diff --git a/DEPS b/DEPS
index 3359e24..d8ae335d 100644
--- a/DEPS
+++ b/DEPS
@@ -315,11 +315,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'a0fc6e43095cf506dba365ecdad45be659bb4764',
+  'angle_revision': '94b451811838c540f8ef682ad7da45c6ccf0b450',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '6d0e2d57acf9486b869dc06c6f53a12fe5a55636',
+  'swiftshader_revision': '440133b5d4062caa97de0b005fd695581a41a4bc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -334,7 +334,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:9.20221006.5.1',
+  'fuchsia_version': 'version:10.20221013.0.1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -378,7 +378,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': '4793433248183dd073e608f655204d4acfdc7193',
+  'catapult_revision': 'db91f6cd331aba553d84f25240d2df465fd88a62',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -386,7 +386,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': '16062552bfc4d831d865cb21de170797e75375e3',
+  'devtools_frontend_revision': '33bb29b551b54b0ac67025e8b3e0ce69352c9504',
   # 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.
@@ -422,7 +422,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': '51cc480b6918e82fd73f6024080c7b33fff511ce',
+  'dawn_revision': 'c84d06e8603ce9c4b5c8d86e42e9ec0acf3bd689',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -442,7 +442,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libavif
   # and whatever else without interference from each other.
-  'libavif_revision': 'de7e6c0d98abcd6843c4a9bf4cee731141dca566',
+  'libavif_revision': '3c48152f9a22bd9ae827c9cbaf7f4db3e6387d48',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nearby
   # and whatever else without interference from each other.
@@ -490,7 +490,7 @@
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
-  'libcxx_revision':       '64d36e572d3f9719c5d75011a718f33f11126851',
+  'libcxx_revision':       '9538eadcb333899b5595b289292ce59b90888501',
 
   # GN CIPD package version.
   'gn_version': 'git_revision:b9c6c19be95a3863e02f00f1fe403b2502e345b6',
@@ -818,12 +818,12 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    '02647eb999b2998bfe8f851a8a4a713302a074f3',
+    'd71ee488b3dfc34f836410eaace4f52915ad7872',
     'condition': 'checkout_android and checkout_src_internal and not checkout_clank_via_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + 'b5ad817e0eecb584486d51f769bd91f013d287c4',
+    'url': Var('chromium_git') + '/website.git' + '@' + '7da061134f35c390ac1549a82704a1762f9a5261',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -842,7 +842,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'e7619686aab6b4e438ab51cd3fe03396b2f872c6',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '416a8ce75bcf827e8e99825aac8b4b7c5857fa5b',
       'condition': 'checkout_ios',
   },
 
@@ -912,7 +912,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': 'XEbOH2L8Z6ubx_LPnXmj_Xdltz9g3D9H8GZK39M3ufIC',
+          'version': 'gjjgFT1JcYKD-SV0nFWRTeGr2kufiafn_rvDI-gFW0QC',
         },
       ],
       'dep_type': 'cipd',
@@ -923,7 +923,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': 'ekwGtBO0MwF3UiT2Mrd_s8obssggePxHG4yLRniKIO8C',
+          'version': 'xH8MfShB-S7HYkM3gLOUa916ukoEtDJa-8X1bOwfevsC',
         },
       ],
       'dep_type': 'cipd',
@@ -934,7 +934,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'Kw4UqmzsIh9S81Bme5Nn8PWYRJHQCwkRY244SZR53j8C',
+          'version': 'SWCvrm3LQO_Y0XbcVVs0q2CJOVKn0ImNLJ0WPQDKx5YC',
         },
       ],
       'dep_type': 'cipd',
@@ -1002,7 +1002,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'h7h2tZ_Dqu-O57Bk14oz6B7AaJLu1naK5jGnsQ5vaJQC',
+          'version': '0MVUzH0ad0hBu4MqH3dIKpof2FXNYwequV_wMG4ijcoC',
       },
     ],
     'condition': 'checkout_android',
@@ -1068,7 +1068,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/lint',
-               'version': '-yqfSSiekeQe-1juzudRLkikLNk6_VZyv6tz2_GiDO4C',
+               'version': 'DO1bMH_JFEfZXSkAknIs7AfgNh4IwLtJaeMJTdzfuJwC',
           },
       ],
       'condition': 'checkout_android',
@@ -1217,7 +1217,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' + '@' + '6c507298cc8d99e4f543d18c4ae4fcc8fcdb8158',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '6ebc1b94de0dc73bba385f70ddffab9798fd59e5',
       'condition': 'checkout_chromeos',
   },
 
@@ -1251,7 +1251,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '2a53454633691a7ef92cfd52d836a91704ac7de7',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '4ac9d827b064e9b1847d2cec90ccb954198472d8',
     'condition': 'checkout_src_internal',
   },
 
@@ -1666,7 +1666,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '1ad401d3ddb9383be2f371264a3ad8d2b5f5ab2b',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '280f0b23c5c8b98248cf0ccf3d011c4fd4bb74f5',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1811,7 +1811,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@fc01517a312ec6df8fc3a220426f1cbf456cfd63',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@f310d85385dfddbe1deeb05deda1045593225710',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1848,10 +1848,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'eba1a78f3d741241b0dbee728561b61e9587a686',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '9c402f750efed2504482b9ac8f075c2907e4ca1e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '6c733eed8ebb0274cdd4cc93c0999bd6e1ddae09',
+    Var('webrtc_git') + '/src.git' + '@' + 'fb3bd4a01d7c840dfe7b3efa144c0fbcb6a97fef',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -1921,7 +1921,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ddb421f4d6b1c260d001e0bc44f088d6104725a0',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@73f9ffba35357a86d519287005b767c26e56f004',
     'condition': 'checkout_src_internal',
   },
 
@@ -1962,7 +1962,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'feBy3xsR68fgOa4--x06At_7WOjDwg_7v0Oavzlp8cMC',
+        'version': 'HfCwnAI0440kMmt917E1v9QJdzsNuNVfQQ86ehaVDscC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4134,10 +4134,11 @@
   },
   {
     # Should run after the clang hook. Used on mac, as well as for orderfile
-    # generation on Android.
+    # generation and size tooling on Android. Used by
+    # dump-static-initializers.py on linux.
     'name': 'objdump',
     'pattern': '.',
-    'condition': 'checkout_mac or checkout_android and host_os != "mac"',
+    'condition': 'checkout_linux or checkout_mac or checkout_android and host_os != "mac"',
     'action': ['python3', 'src/tools/clang/scripts/update.py',
                '--package=objdump'],
   },
diff --git a/WATCHLISTS b/WATCHLISTS
index 897c5759..1a36808 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -183,6 +183,9 @@
       'filepath': 'ash/webui/common/'\
                   '|chrome/test/data/webui/chromeos/ash_common/',
     },
+    'ash_wm_desks': {
+      'filepath': 'ash/wm/desks/',
+    },
     'assistive': {
       'filepath': 'ash/ambient/'\
                   '|ash/app_list/views/assistant/'\
@@ -1949,9 +1952,9 @@
       'filepath': 'apitest|unittest|browsertest|uitest|chrome/test/',
     },
     'tether': {
-      'filepath': 'ash/components/tether/'\
-                  '|chrome/browser/ash/tether/'\
+      'filepath': 'chrome/browser/ash/tether/'\
                   '|chrome/browser/ui/ash/network/tether'\
+                  '|chromeos/ash/components/tether/',
     },
     'text_to_speech': {
       'filepath': 'tts'
@@ -2286,6 +2289,8 @@
     'ash_webui_common': ['gavinwill+watch-ash-webui-common@chromium.org',
                          'jimmyxgong+watch-ash-webui-common@chromium.org',
                          'zentaro+watch-ash-webui-common@chromium.org'],
+    'ash_wm_desks': ['dandersson@chromium.org',
+                     'bicioglu@google.com'],
     'assistive': ['croissant-eng+reviews@chromium.org'],
     'audio_service': ['marinaciocea+watch@chromium.org',
                       'olka+watch@chromium.org'],
diff --git a/android_webview/browser/aw_autofill_client.cc b/android_webview/browser/aw_autofill_client.cc
index 98bf07a..cee186e0 100644
--- a/android_webview/browser/aw_autofill_client.cc
+++ b/android_webview/browser/aw_autofill_client.cc
@@ -352,6 +352,13 @@
   NOTIMPLEMENTED();
 }
 
+autofill::FormInteractionsFlowId
+AwAutofillClient::GetCurrentFormInteractionsFlowId() {
+  // Currently not in use here. See `ChromeAutofillClient` for a proper
+  // implementation.
+  return {};
+}
+
 void AwAutofillClient::LoadRiskData(
     base::OnceCallback<void(const std::string&)> callback) {
   NOTIMPLEMENTED();
diff --git a/android_webview/browser/aw_autofill_client.h b/android_webview/browser/aw_autofill_client.h
index adcef9c4..ae74b2a 100644
--- a/android_webview/browser/aw_autofill_client.h
+++ b/android_webview/browser/aw_autofill_client.h
@@ -150,6 +150,7 @@
   bool AreServerCardsSupported() const override;
   void ExecuteCommand(int id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
+  autofill::FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
 
   // RiskDataLoader:
   void LoadRiskData(
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 33519c7..2dc5ced0 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -48,6 +48,7 @@
 #include "base/feature_list.h"
 #include "base/files/scoped_file.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
@@ -1060,6 +1061,17 @@
       features::kWebViewSuppressDifferentOriginSubframeJSDialogs);
 }
 
+void AwContentBrowserClient::OnDisplayInsecureContent(
+    content::WebContents* web_contents) {
+  AwSettings* aw_settings = AwSettings::FromWebContents(web_contents);
+  if (aw_settings) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "Android.WebView.OptionallyBlockableMixedContentLoaded.Mode",
+        aw_settings->GetMixedContentMode(),
+        AwSettings::MixedContentMode::COUNT);
+  }
+}
+
 // static
 void AwContentBrowserClient::DisableCreatingThreadPool() {
   g_should_create_thread_pool = false;
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 73bc8f0..a742975 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -246,6 +246,7 @@
   bool HasErrorPage(int http_status_code) override;
   bool SuppressDifferentOriginSubframeJSDialogs(
       content::BrowserContext* browser_context) override;
+  void OnDisplayInsecureContent(content::WebContents* web_contents) override;
 
   AwFeatureListCreator* aw_feature_list_creator() {
     return aw_feature_list_creator_;
diff --git a/android_webview/browser/aw_settings.cc b/android_webview/browser/aw_settings.cc
index 9471c4b..6d37fd8 100644
--- a/android_webview/browser/aw_settings.cc
+++ b/android_webview/browser/aw_settings.cc
@@ -112,6 +112,10 @@
   return allow_third_party_cookies_;
 }
 
+AwSettings::MixedContentMode AwSettings::GetMixedContentMode() {
+  return mixed_content_mode_;
+}
+
 void AwSettings::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   delete this;
 }
@@ -185,6 +189,7 @@
   UpdateWillSuppressErrorStateLocked(env, obj);
   UpdateCookiePolicyLocked(env, obj);
   UpdateAllowFileAccessLocked(env, obj);
+  UpdateMixedContentModeLocked(env, obj);
 }
 
 void AwSettings::UpdateUserAgentLocked(JNIEnv* env,
@@ -325,6 +330,16 @@
   allow_file_access_ = Java_AwSettings_getAllowFileAccess(env, obj);
 }
 
+void AwSettings::UpdateMixedContentModeLocked(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  if (!web_contents())
+    return;
+
+  mixed_content_mode_ = static_cast<MixedContentMode>(
+      Java_AwSettings_getMixedContentMode(env, obj));
+}
+
 void AwSettings::RenderViewHostChanged(content::RenderViewHost* old_host,
                                        content::RenderViewHost* new_host) {
   DCHECK_EQ(new_host, web_contents()->GetRenderViewHost());
diff --git a/android_webview/browser/aw_settings.h b/android_webview/browser/aw_settings.h
index ec461e6..b86de760 100644
--- a/android_webview/browser/aw_settings.h
+++ b/android_webview/browser/aw_settings.h
@@ -42,6 +42,13 @@
     CONSTANT_WEBVIEW = 2,
   };
 
+  enum MixedContentMode {
+    MIXED_CONTENT_ALWAYS_ALLOW = 0,
+    MIXED_CONTENT_NEVER_ALLOW = 1,
+    MIXED_CONTENT_COMPATIBILITY_MODE = 2,
+    COUNT,
+  };
+
   static AwSettings* FromWebContents(content::WebContents* web_contents);
   static bool GetAllowSniffingFileUrls();
 
@@ -54,6 +61,7 @@
 
   bool GetJavaScriptCanOpenWindowsAutomatically();
   bool GetAllowThirdPartyCookies();
+  MixedContentMode GetMixedContentMode();
 
   // Called from Java. Methods with "Locked" suffix require that the settings
   // access lock is held during their execution.
@@ -93,6 +101,9 @@
   void UpdateAllowFileAccessLocked(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
+  void UpdateMixedContentModeLocked(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
 
   void PopulateWebPreferences(blink::web_pref::WebPreferences* web_prefs);
   bool GetAllowFileAccess();
@@ -130,6 +141,7 @@
   bool allow_third_party_cookies_;
   bool allow_file_access_;
   bool enterprise_authentication_app_link_policy_enabled_;
+  MixedContentMode mixed_content_mode_;
 
   scoped_refptr<AwContentsOriginMatcher> xrw_allowlist_matcher_;
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSettings.java b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
index c8f9ef35..bcbec92 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -1712,6 +1712,7 @@
         }
     }
 
+    @CalledByNative
     public int getMixedContentMode() {
         synchronized (mAwSettingsLock) {
             return mMixedContentMode;
diff --git a/android_webview/test/shell/AndroidManifest.xml b/android_webview/test/shell/AndroidManifest.xml
index 3f376a1..8894c3d 100644
--- a/android_webview/test/shell/AndroidManifest.xml
+++ b/android_webview/test/shell/AndroidManifest.xml
@@ -21,6 +21,13 @@
   <uses-permission android:name="android.permission.GET_ACCOUNTS" />
   <uses-permission android:name="android.permission.USE_CREDENTIALS" />
 
+  <!-- Features related to permissions we request. -->
+  <!-- android.permission.CAMERA -->
+  <uses-feature android:name="android.hardware.camera" android:required="false" />
+  <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
+  <!-- android.permission.RECORD_AUDIO -->
+  <uses-feature android:name="android.hardware.microphone" android:required="false" />
+
   <application android:name="org.chromium.android_webview.shell.AwShellApplication"
       android:label="AwShellApplication"
       android:hardwareAccelerated="true">
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index d085f92..0adc954 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -846,6 +846,7 @@
     "rgb_keyboard/histogram_util.h",
     "rgb_keyboard/rgb_keyboard_manager.cc",
     "rgb_keyboard/rgb_keyboard_manager.h",
+    "rgb_keyboard/rgb_keyboard_manager_observer.h",
     "rgb_keyboard/rgb_keyboard_util.cc",
     "rgb_keyboard/rgb_keyboard_util.h",
     "root_window_controller.cc",
@@ -2713,6 +2714,7 @@
     "frame/caption_buttons/frame_size_button_unittest.cc",
     "frame/default_frame_header_unittest.cc",
     "frame/non_client_frame_view_ash_unittest.cc",
+    "frame_throttler/frame_throttling_controller_unittest.cc",
     "glanceables/glanceables_unittests.cc",
     "glanceables/glanceables_welcome_label_unittest.cc",
     "glanceables/signout_screenshot_handler_unittest.cc",
@@ -2770,6 +2772,7 @@
     "metrics/feature_discovery_duration_reporter_impl_unittest.cc",
     "metrics/histogram_macros_unittest.cc",
     "metrics/login_metrics_recorder_unittest.cc",
+    "metrics/login_unlock_throughput_recorder_unittest.cc",
     "metrics/pointer_metrics_recorder_unittest.cc",
     "metrics/stylus_metrics_recorder_unittest.cc",
     "metrics/task_switch_metrics_recorder_unittest.cc",
@@ -3212,6 +3215,7 @@
     "//chromeos/crosapi/cpp",
     "//chromeos/dbus/power",
     "//chromeos/dbus/power:power_manager_proto",
+    "//chromeos/login/login_state:login_state",
     "//chromeos/services/network_config/public/cpp",
     "//chromeos/services/network_config/public/mojom",
     "//chromeos/strings:strings_grit",
@@ -3242,6 +3246,7 @@
     "//components/ukm:test_support",
     "//components/user_manager",
     "//components/user_manager:test_support",
+    "//components/viz/host",
     "//components/viz/test:test_support",
     "//device/bluetooth",
     "//device/bluetooth:mocks",
diff --git a/ash/accessibility/ui/accessibility_highlight_layer.h b/ash/accessibility/ui/accessibility_highlight_layer.h
index ff3719a2..898a786 100644
--- a/ash/accessibility/ui/accessibility_highlight_layer.h
+++ b/ash/accessibility/ui/accessibility_highlight_layer.h
@@ -33,6 +33,8 @@
 
   std::vector<gfx::Rect> rects_for_test() { return rects_; }
 
+  SkColor color_for_test() { return highlight_color_; }
+
  private:
   // ui::LayerDelegate overrides:
   void OnPaintLayer(const ui::PaintContext& context) override;
diff --git a/ash/app_list/app_list_color_provider_impl.cc b/ash/app_list/app_list_color_provider_impl.cc
index eac643d..baf96e4c 100644
--- a/ash/app_list/app_list_color_provider_impl.cc
+++ b/ash/app_list/app_list_color_provider_impl.cc
@@ -18,7 +18,7 @@
 namespace {
 // Opacity of the light/dark inkdrop.
 constexpr float kLightInkDropOpacity = 0.08f;
-constexpr float kDarkInkDropOpacity = 0.06f;
+constexpr float kDarkInkDropOpacity = 0.12f;
 
 // Helper to check if tablet mode is enabled.
 bool IsTabletModeEnabled() {
diff --git a/ash/app_list/app_list_metrics.cc b/ash/app_list/app_list_metrics.cc
index 2eb303d4..06d0ef6a 100644
--- a/ash/app_list/app_list_metrics.cc
+++ b/ash/app_list/app_list_metrics.cc
@@ -112,16 +112,22 @@
 constexpr char kAppListAppLaunchedHomecherSearch[] =
     "Apps.AppListAppLaunchedV2.HomecherSearch";
 
+// UMA histograms for app list sort reorder.
 constexpr char kClamshellReorderAnimationSmoothnessHistogram[] =
     "Apps.Launcher.ProductivityReorderAnimationSmoothness.ClamshellMode";
 constexpr char kTabletReorderAnimationSmoothnessHistogram[] =
     "Apps.Launcher.ProductivityReorderAnimationSmoothness.TabletMode";
-
 constexpr char kClamshellReorderActionHistogram[] =
     "Apps.Launcher.ProductivityReorderAction.ClamshellMode";
 constexpr char kTabletReorderActionHistogram[] =
     "Apps.Launcher.ProductivityReorderAction.TabletMode";
 
+// UMA histograms for app list drag reorder.
+constexpr char kClamshellDragReorderAnimationSmoothnessHistogram[] =
+    "Apps.Launcher.DragReorderAnimationSmoothness.ClamshellMode";
+constexpr char kTabletDragReorderAnimationSmoothnessHistogram[] =
+    "Apps.Launcher.DragReorderAnimationSmoothness.TabletMode";
+
 // The prefix for all the variants that track how long the app list is kept
 // open by open method. Suffix is decided in `GetAppListOpenMethod`
 constexpr char kAppListOpenTimePrefix[] = "Apps.AppListOpenTime.";
@@ -515,6 +521,16 @@
     base::UmaHistogramEnumeration(kClamshellReorderActionHistogram, new_order);
 }
 
+void ReportItemDragReorderAnimationSmoothness(bool in_tablet, int smoothness) {
+  if (in_tablet) {
+    base::UmaHistogramPercentage(kTabletDragReorderAnimationSmoothnessHistogram,
+                                 smoothness);
+  } else {
+    base::UmaHistogramPercentage(
+        kClamshellDragReorderAnimationSmoothnessHistogram, smoothness);
+  }
+}
+
 void RecordMetricsOnSessionEnd() {
   if (ContinueSectionView::EnableContinueSectionFileRemovalMetrics() &&
       g_continue_file_removals_in_session == 0) {
diff --git a/ash/app_list/app_list_metrics.h b/ash/app_list/app_list_metrics.h
index a7f420c..4ecc6fe 100644
--- a/ash/app_list/app_list_metrics.h
+++ b/ash/app_list/app_list_metrics.h
@@ -15,16 +15,22 @@
 
 class SearchResult;
 
-// UMA histograms that record app list reorder animation smoothness. Exposed
-// in this header because it is needed in tests.
+// UMA histograms that record app list sort reorder animation smoothness.
+// Exposed in this header because it is needed in tests.
 ASH_EXPORT extern const char kClamshellReorderAnimationSmoothnessHistogram[];
 ASH_EXPORT extern const char kTabletReorderAnimationSmoothnessHistogram[];
 
-// UMA histograms that record app list reorder actions. Exposed in this header
-// because it is needed in tests.
+// UMA histograms that record app list sort reorder actions. Exposed in this
+// header because it is needed in tests.
 ASH_EXPORT extern const char kClamshellReorderActionHistogram[];
 ASH_EXPORT extern const char kTabletReorderActionHistogram[];
 
+// UMA histograms that record app list drag reorder animation smoothness.
+// Exposed in this header because it is needed in tests.
+ASH_EXPORT extern const char
+    kClamshellDragReorderAnimationSmoothnessHistogram[];
+ASH_EXPORT extern const char kTabletDragReorderAnimationSmoothnessHistogram[];
+
 // UMA histograms that records the number of files removed per user per session
 // from the launcher continue section. Exposed in this header because it is
 // needed in tests.
@@ -279,6 +285,8 @@
 
 void RecordAppListSortAction(AppListSortOrder new_order, bool in_tablet);
 
+void ReportItemDragReorderAnimationSmoothness(bool in_tablet, int smoothness);
+
 // Invoked when the app list session ends, records metrics of interest during
 // the session.
 void RecordMetricsOnSessionEnd();
diff --git a/ash/app_list/views/app_list_page.cc b/ash/app_list/views/app_list_page.cc
index 55ceb1b..c1a9b93 100644
--- a/ash/app_list/views/app_list_page.cc
+++ b/ash/app_list/views/app_list_page.cc
@@ -59,26 +59,6 @@
   animator.Run(default_offset, layer());
 }
 
-gfx::Rect AppListPage::GetAboveContentsOffscreenBounds(
-    const gfx::Size& size) const {
-  gfx::Rect rect(size);
-  rect.set_y(-rect.height());
-  return rect;
-}
-
-gfx::Rect AppListPage::GetBelowContentsOffscreenBounds(
-    const gfx::Size& size) const {
-  DCHECK(contents_view_);
-  gfx::Rect rect(size);
-  rect.set_y(contents_view_->GetContentsBounds().height());
-  return rect;
-}
-
-gfx::Rect AppListPage::GetFullContentsBounds() const {
-  DCHECK(contents_view_);
-  return contents_view_->GetContentsBounds();
-}
-
 gfx::Rect AppListPage::GetDefaultContentsBounds() const {
   DCHECK(contents_view_);
   return contents_view_->GetContentsBounds();
diff --git a/ash/app_list/views/app_list_page.h b/ash/app_list/views/app_list_page.h
index 9f2e86d..4b1ae881 100644
--- a/ash/app_list/views/app_list_page.h
+++ b/ash/app_list/views/app_list_page.h
@@ -111,18 +111,6 @@
                                 const TransformAnimator& animator,
                                 float default_offset);
 
-  // Returns the area above the contents view, given the desired size of this
-  // page, in the contents view's coordinate space.
-  gfx::Rect GetAboveContentsOffscreenBounds(const gfx::Size& size) const;
-
-  // Returns the area below the contents view, given the desired size of this
-  // page, in the contents view's coordinate space.
-  gfx::Rect GetBelowContentsOffscreenBounds(const gfx::Size& size) const;
-
-  // Returns the entire bounds of the contents view, in the contents view's
-  // coordinate space.
-  gfx::Rect GetFullContentsBounds() const;
-
   // Returns the default bounds of pages inside the contents view, in the
   // contents view's coordinate space. This is the area of the contents view
   // below the search box.
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index dc38ffde..604eaf9 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -39,6 +39,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/cxx17_backports.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/ranges/algorithm.h"
@@ -1332,6 +1333,14 @@
 }
 
 void AppsGridView::AnimateToIdealBounds() {
+  if (layer()->GetCompositor()) {
+    item_reorder_animation_tracker_ =
+        layer()->GetCompositor()->RequestNewThroughputTracker();
+    item_reorder_animation_tracker_->Start(
+        metrics_util::ForSmoothness(base::BindRepeating(
+            &ReportItemDragReorderAnimationSmoothness, IsTabletMode())));
+  }
+
   gfx::Rect visible_bounds(GetVisibleBounds());
   gfx::Point visible_origin = visible_bounds.origin();
   ConvertPointToTarget(this, items_container_, &visible_origin);
@@ -2548,6 +2557,10 @@
 }
 
 void AppsGridView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) {
+  if (item_reorder_animation_tracker_) {
+    item_reorder_animation_tracker_->Stop();
+    item_reorder_animation_tracker_.reset();
+  }
   row_change_animator_->OnBoundsAnimatorDone();
   DestroyLayerItemsIfNotNeeded();
 }
diff --git a/ash/app_list/views/apps_grid_view.h b/ash/app_list/views/apps_grid_view.h
index d26559d..ea56949 100644
--- a/ash/app_list/views/apps_grid_view.h
+++ b/ash/app_list/views/apps_grid_view.h
@@ -1088,6 +1088,11 @@
   // Used to trigger and manage row change animations.
   std::unique_ptr<AppsGridRowChangeAnimator> row_change_animator_;
 
+  // Tracks the animation smoothness of item reorders during drag. Gets
+  // triggered by AnimateToIdealBounds(), which is mainly caused
+  // by app dragging reorders. This does not track reorders due to sort.
+  absl::optional<ui::ThroughputTracker> item_reorder_animation_tracker_;
+
   base::WeakPtrFactory<AppsGridView> weak_factory_{this};
 };
 
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc
index 375581e..b978fa60a 100644
--- a/ash/app_list/views/apps_grid_view_unittest.cc
+++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -53,6 +53,7 @@
 #include "ash/shell.h"
 #include "ash/style/system_shadow.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_util.h"
 #include "ash/utility/haptics_tracking_test_input_controller.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
@@ -68,6 +69,7 @@
 #include "ui/compositor/presentation_time_recorder.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/compositor/test/layer_animation_stopped_waiter.h"
+#include "ui/compositor/test/test_utils.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/keycodes/keyboard_codes_posix.h"
 #include "ui/views/animation/bounds_animator.h"
@@ -5292,5 +5294,62 @@
   }
 }
 
+TEST_P(AppsGridViewClamshellAndTabletTest, ReorderDragAnimationMetrics) {
+  ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+  base::HistogramTester histogram_tester;
+  const int kAppsInGrid = 9;
+  model_->PopulateApps(kAppsInGrid);
+  UpdateLayout();
+
+  // Begin item drag.
+  auto* dragged_item = apps_grid_view_->GetItemViewAt(0);
+  GetEventGenerator()->MoveMouseTo(
+      dragged_item->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->PressLeftButton();
+  dragged_item->FireMouseDragTimerForTest();
+  GetEventGenerator()->MoveMouseBy(10, 10);
+
+  // Wait for layer animations before the drag to trigger drag reorder
+  // animations.
+  for (size_t i = 0; i < apps_grid_view_->view_model()->view_size(); ++i) {
+    auto* view = apps_grid_view_->view_model()->view_at(i);
+    if (view->layer())
+      ui::LayerAnimationStoppedWaiter().Wait(view->layer());
+  }
+
+  ASSERT_TRUE(apps_grid_view_->drag_item());
+  ASSERT_TRUE(apps_grid_view_->IsDragging());
+  ASSERT_EQ(dragged_item->item(), apps_grid_view_->drag_item());
+
+  // Drag item to the last slot
+  const gfx::Point drop_point = apps_grid_view_->GetItemViewAt(kAppsInGrid - 1)
+                                    ->GetIconBoundsInScreen()
+                                    .right_center() +
+                                gfx::Vector2d(100, 10);
+  GetEventGenerator()->MoveMouseTo(drop_point);
+  ASSERT_TRUE(apps_grid_view_->reorder_timer_for_test()->IsRunning());
+  apps_grid_view_->reorder_timer_for_test()->FireNow();
+
+  // Let the animations play out.
+  test_api_->WaitForItemMoveAnimationDone();
+
+  // Release drag.
+  GetEventGenerator()->ReleaseLeftButton();
+
+  // Ensure there is one more frame presented after animation finishes to allow
+  // animation throughput data to be passed from cc to ui.
+  EXPECT_TRUE(ui::WaitForNextFrameToBePresented(
+      apps_grid_view_->GetWidget()->GetCompositor()));
+
+  if (create_as_tablet_mode_) {
+    histogram_tester.ExpectTotalCount(
+        kTabletDragReorderAnimationSmoothnessHistogram, 1);
+  } else {
+    histogram_tester.ExpectTotalCount(
+        kClamshellDragReorderAnimationSmoothnessHistogram, 1);
+  }
+}
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/app_list/views/search_result_list_view_unittest.cc b/ash/app_list/views/search_result_list_view_unittest.cc
index e627c3b..63ab750e 100644
--- a/ash/app_list/views/search_result_list_view_unittest.cc
+++ b/ash/app_list/views/search_result_list_view_unittest.cc
@@ -17,9 +17,11 @@
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/test/test_app_list_color_provider.h"
+#include "ash/style/ash_color_provider.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/test/widget_test.h"
 
@@ -118,6 +120,11 @@
     return answer_card_view_->GetResultViewAt(index);
   }
 
+  views::FlexLayoutView* GetKeyboardShortcutContents(
+      SearchResultView* result_view) {
+    return result_view->get_keyboard_shortcut_container_for_test();
+  }
+
   std::vector<SearchResultView*> GetAssistantResultViews() const {
     std::vector<SearchResultView*> results;
     for (auto* view : unified_view_->search_result_views_) {
@@ -164,6 +171,41 @@
     RunPendingMessages();
   }
 
+  void SetUpKeyboardShortcutResult() {
+    SearchModel::SearchResults* results = GetResults();
+
+    std::unique_ptr<TestSearchResult> result =
+        std::make_unique<TestSearchResult>();
+    result->set_display_type(ash::SearchResultDisplayType::kList);
+    result->SetTitle(u"Copy and Paste");
+    result->set_best_match(true);
+
+    std::vector<SearchResult::TextItem> keyboard_shortcut_text_vector;
+    SearchResult::TextItem shortcut_text_item_1(
+        ash::SearchResultTextItemType::kIconifiedText);
+    shortcut_text_item_1.SetText(u"ctrl");
+    shortcut_text_item_1.SetTextTags({});
+    keyboard_shortcut_text_vector.push_back(shortcut_text_item_1);
+
+    SearchResult::TextItem shortcut_text_item_2(
+        ash::SearchResultTextItemType::kString);
+    shortcut_text_item_2.SetText(u" + ");
+    shortcut_text_item_2.SetTextTags({});
+    keyboard_shortcut_text_vector.push_back(shortcut_text_item_2);
+
+    SearchResult::TextItem shortcut_text_item_3(
+        ash::SearchResultTextItemType::kIconifiedText);
+    shortcut_text_item_3.SetText(u"a");
+    shortcut_text_item_3.SetTextTags({});
+    keyboard_shortcut_text_vector.push_back(shortcut_text_item_3);
+
+    result->SetKeyboardShortcutTextVector(keyboard_shortcut_text_vector);
+    results->Add(std::move(result));
+
+    // Adding results will schedule Update().
+    RunPendingMessages();
+  }
+
   int GetOpenResultCountAndReset(int ranking) {
     EXPECT_GT(view_delegate_.open_search_result_counts().count(ranking), 0u);
     int result = view_delegate_.open_search_result_counts()[ranking];
@@ -208,6 +250,8 @@
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   TestAppListColorProvider color_provider_;  // Needed by AppListView.
+  AshColorProvider
+      ash_color_provider_;  // Needed by SearchResultInlineIconView.
   AppListTestViewDelegate view_delegate_;
   std::unique_ptr<SearchResultListView> unified_view_;
   std::unique_ptr<SearchResultListView> default_view_;
@@ -225,10 +269,23 @@
   // Result 0 has a detail text. Expect that the detail is appended to the
   // accessibility name.
   EXPECT_EQ(u"Result 0, Detail",
-            GetUnifiedResultViewAt(0)->ComputeAccessibleName());
+            GetDefaultResultViewAt(0)->ComputeAccessibleName());
 
   // Result 2 has no detail text.
-  EXPECT_EQ(u"Result 2", GetUnifiedResultViewAt(2)->ComputeAccessibleName());
+  EXPECT_EQ(u"Result 2", GetDefaultResultViewAt(2)->ComputeAccessibleName());
+}
+
+TEST_P(SearchResultListViewTest, KeyboardShortcutResult) {
+  if (!IsProductivityLauncherEnabled())
+    return;
+
+  default_view()->SetBounds(0, 0, kPreferredWidth, 400);
+  SetUpKeyboardShortcutResult();
+
+  EXPECT_EQ(u"Copy and Paste",
+            GetDefaultResultViewAt(0)->ComputeAccessibleName());
+  EXPECT_TRUE(
+      GetKeyboardShortcutContents(GetDefaultResultViewAt(0))->GetVisible());
 }
 
 TEST_P(SearchResultListViewTest, CorrectEnumLength) {
diff --git a/ash/app_list/views/search_result_view.h b/ash/app_list/views/search_result_view.h
index edf9c9c4..35df7ed 100644
--- a/ash/app_list/views/search_result_view.h
+++ b/ash/app_list/views/search_result_view.h
@@ -173,6 +173,10 @@
     multi_line_title_height_ = height;
   }
 
+  views::FlexLayoutView* get_keyboard_shortcut_container_for_test() {
+    return keyboard_shortcut_container_;
+  }
+
   int PreferredHeight() const;
   int PrimaryTextHeight() const;
   int SecondaryTextHeight() const;
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 3fdd157..c53c7bb5 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2222,6 +2222,9 @@
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_A11Y_LABEL_ACTIVATE" desc="Accessibility label used for an unactivated cellular network in quick settings network list that opens the activation flow when clicked.">
         Click to activate <ph name="NETWORK_NAME">$1<ex>Verizon</ex></ph>
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_A11Y_LABEL_SUBTEXT" desc="Accessibility label used for a network in quick settings network list that has a subtext message (e.g. when offline signin is required).">
+        <ph name="NETWORK_NAME">$1<ex>CaptivePortalNetwork</ex></ph>, <ph name="SUBTEXT">$2<ex>Sign in to network</ex></ph>
+      </message>
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_DISCONNECT_BUTTON_A11Y_LABEL" desc="Accessibility label used for a button to disconnect from a network in quick settings network list.">
         Disconnect from <ph name="NETWORK_NAME">$1<ex>Ethernet</ex></ph>
       </message>
@@ -2410,11 +2413,14 @@
         Connected to <ph name="NAME">$1<ex>GoogleGuest</ex></ph>
       </message>
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED_TOOLTIP" desc="The tooltip text used when connected to a network.">
-        Connected to <ph name="NAME">$1<ex>GoogleGuest</ex></ph>, <ph name="STRENGTH">$2<ex>Weak signal.</ex></ph>
+        <ph name="DESC">$1<ex>Connected to GoogleGuest</ex></ph>, <ph name="STRENGTH">$2<ex>Weak signal.</ex></ph>
       </message>
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING" desc="Message for the network tray tooltip and a11y name when activating a network.">
         Activating <ph name="NAME">$1<ex>YBH Cellular</ex></ph>
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_NETWORK_PORTAL" desc="Message for the network tray tooltip and a11y name when connected to a network in a captive portal state.">
+        Connected to <ph name="NAME">$1<ex>GoogleGuest</ex></ph>, <ph name="SUBTEXT">$2<ex>Sign in to network</ex></ph>
+      </message>
 
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_TOGGLE_TOOLTIP" desc="The tooltip text for the button that toggles network enabled/disabled state.">
         Toggle network connection. <ph name="STATE_TEXT">$1<ex>Connected to public wifi</ex></ph>
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED_TOOLTIP.png.sha1
new file mode 100644
index 0000000..7bd920b
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+d741dfe72d2c90c6ea7303db5d1060dfcf4931ed
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_PORTAL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_PORTAL.png.sha1
new file mode 100644
index 0000000..25fcd9e
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_PORTAL.png.sha1
@@ -0,0 +1 @@
+c0f1e085d614307c6fa869550ce4d0e86905ac46
\ No newline at end of file
diff --git a/ash/assistant/assistant_controller_impl.cc b/ash/assistant/assistant_controller_impl.cc
index 553836b..5dab51fa 100644
--- a/ash/assistant/assistant_controller_impl.cc
+++ b/ash/assistant/assistant_controller_impl.cc
@@ -75,13 +75,7 @@
   assistant_ui_controller_.SetAssistant(assistant);
 
   OnAccessibilityStatusChanged();
-
-  bool dark_mode_enabled = false;
-  if (ash::features::IsProductivityLauncherEnabled() ||
-      ash::features::IsDarkLightModeEnabled()) {
-    dark_mode_enabled = DarkLightModeControllerImpl::Get()->IsDarkModeEnabled();
-  }
-  OnColorModeChanged(dark_mode_enabled);
+  OnColorModeChanged(DarkLightModeControllerImpl::Get()->IsDarkModeEnabled());
 
   if (assistant) {
     for (AssistantControllerObserver& observer : observers_)
diff --git a/ash/assistant/model/ui/assistant_card_element.cc b/ash/assistant/model/ui/assistant_card_element.cc
index 9e96d1a8..8cf32d3c 100644
--- a/ash/assistant/model/ui/assistant_card_element.cc
+++ b/ash/assistant/model/ui/assistant_card_element.cc
@@ -33,8 +33,8 @@
   }
 
   void Process() {
-    const int width_dip = card_element_->viewport_width() -
-                          2 * assistant::ui::GetHorizontalMargin();
+    const int width_dip =
+        card_element_->viewport_width() - 2 * assistant::ui::kHorizontalMargin;
 
     // Configure parameters for the card. We want to configure the size as:
     // - width: It should be width_dip.
diff --git a/ash/assistant/test/assistant_ash_test_base.cc b/ash/assistant/test/assistant_ash_test_base.cc
index debd225c..919f168 100644
--- a/ash/assistant/test/assistant_ash_test_base.cc
+++ b/ash/assistant/test/assistant_ash_test_base.cc
@@ -213,14 +213,6 @@
   return test_api_->IsVisible();
 }
 
-views::View* AssistantAshTestBase::main_view() {
-  DCHECK(!features::IsProductivityLauncherEnabled())
-      << "ProductivityLauncher does not have a main_view(). Prefer "
-         "page_view(), which is supported both with and without "
-         "ProductivityLauncher enabled.";
-  return test_api_->main_view();
-}
-
 views::View* AssistantAshTestBase::page_view() {
   return test_api_->page_view();
 }
diff --git a/ash/assistant/test/assistant_ash_test_base.h b/ash/assistant/test/assistant_ash_test_base.h
index 2257a06..d29a3131 100644
--- a/ash/assistant/test/assistant_ash_test_base.h
+++ b/ash/assistant/test/assistant_ash_test_base.h
@@ -99,11 +99,6 @@
   // Return true if the Assistant UI is visible.
   bool IsVisible();
 
-  // Return the actual displayed Assistant main view.
-  // Can only be used after |ShowAssistantUi| has been called.
-  // Only exists for fullscreen launcher.
-  views::View* main_view();
-
   // This is the top-level Assistant specific view.
   // Can only be used after |ShowAssistantUi| has been called.
   // Exists for both bubble launcher and fullscreen launcher.
diff --git a/ash/assistant/ui/assistant_ui_constants.cc b/ash/assistant/ui/assistant_ui_constants.cc
index 92f8d8c6..5c7c3fa7 100644
--- a/ash/assistant/ui/assistant_ui_constants.cc
+++ b/ash/assistant/ui/assistant_ui_constants.cc
@@ -20,17 +20,6 @@
   return *font_list;
 }
 
-int GetHorizontalMargin() {
-  // Expected margin for productivity launcher case is 24. But
-  // AppListBubbleAssistantPage is shifted by 1px, i.e. has 1px margin. See
-  // b/233384263 for details.
-  return features::IsProductivityLauncherEnabled() ? 23 : 32;
-}
-
-int GetHorizontalPadding() {
-  return features::IsProductivityLauncherEnabled() ? 20 : 14;
-}
-
 }  // namespace ui
 }  // namespace assistant
 }  // namespace ash
diff --git a/ash/assistant/ui/assistant_ui_constants.h b/ash/assistant/ui/assistant_ui_constants.h
index d0817fd..563c19a7 100644
--- a/ash/assistant/ui/assistant_ui_constants.h
+++ b/ash/assistant/ui/assistant_ui_constants.h
@@ -31,6 +31,11 @@
 namespace assistant {
 namespace ui {
 
+// Expected launcher margin is 24. But AppListBubbleAssistantPage is shifted by
+// 1px, i.e. has 1px margin. See b/233384263 for details.
+constexpr int kHorizontalMargin = 23;
+constexpr int kHorizontalPadding = 20;
+
 // Window property to instruct the event targeter for the Assistant window to
 // only allow mouse click events to reach the specified |window|. All other
 // events will not be explored by |window|'s subtree for handling.
@@ -44,14 +49,6 @@
 // The maximum number of user sessions in which to show Assistant onboarding.
 constexpr int kOnboardingMaxSessionsShown = 3;
 
-// Returns the horizontal margin in DIPs.
-COMPONENT_EXPORT(ASSISTANT_UI_CONSTANTS)
-int GetHorizontalMargin();
-
-// Returns the horizontal padding in DIPs.
-COMPONENT_EXPORT(ASSISTANT_UI_CONSTANTS)
-int GetHorizontalPadding();
-
 }  // namespace ui
 }  // namespace assistant
 
diff --git a/ash/assistant/ui/base/assistant_button.cc b/ash/assistant/ui/base/assistant_button.cc
index 358df25..7301c2ec 100644
--- a/ash/assistant/ui/base/assistant_button.cc
+++ b/ash/assistant/ui/base/assistant_button.cc
@@ -152,16 +152,10 @@
   views::View::OnThemeChanged();
 
   // Updates inkdrop color and opacity.
-  const bool is_enabled = features::IsProductivityLauncherEnabled();
-  const bool base_color =
-      is_enabled ? GetColorProvider()->GetColor(kColorAshInkDropOpaqueColor)
-                 : SK_ColorBLACK;
-  const float opacity = is_enabled ? StyleUtil::GetInkDropOpacity()
-                                   : StyleUtil::kDarkInkDropOpacity;
-
   auto* ink_drop = views::InkDrop::Get(this);
-  ink_drop->SetBaseColor(base_color);
-  ink_drop->SetVisibleOpacity(opacity);
+  ink_drop->SetBaseColor(
+      GetColorProvider()->GetColor(kColorAshInkDropOpaqueColor));
+  ink_drop->SetVisibleOpacity(StyleUtil::GetInkDropOpacity());
 
   if (!icon_color_type_.has_value() || !icon_description_.has_value())
     return;
diff --git a/ash/assistant/ui/main_stage/assistant_onboarding_view.cc b/ash/assistant/ui/main_stage/assistant_onboarding_view.cc
index a0ee182..0f0528e 100644
--- a/ash/assistant/ui/main_stage/assistant_onboarding_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_onboarding_view.cc
@@ -179,7 +179,7 @@
 void AssistantOnboardingView::InitLayout() {
   SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical,
-      gfx::Insets::VH(0, assistant::ui::GetHorizontalMargin())));
+      gfx::Insets::VH(0, assistant::ui::kHorizontalMargin)));
 
   // Greeting.
   greeting_ = AddChildView(std::make_unique<views::Label>());
diff --git a/ash/assistant/ui/main_stage/assistant_opt_in_view.cc b/ash/assistant/ui/main_stage/assistant_opt_in_view.cc
index cdaa454..fc769f3 100644
--- a/ash/assistant/ui/main_stage/assistant_opt_in_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_opt_in_view.cc
@@ -133,7 +133,7 @@
   layout_manager =
       container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kHorizontal,
-          gfx::Insets::VH(0, assistant::ui::GetHorizontalPadding())));
+          gfx::Insets::VH(0, assistant::ui::kHorizontalPadding)));
 
   layout_manager->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::kCenter);
diff --git a/ash/assistant/ui/main_stage/suggestion_container_view.cc b/ash/assistant/ui/main_stage/suggestion_container_view.cc
index 63d66cf..43922821 100644
--- a/ash/assistant/ui/main_stage/suggestion_container_view.cc
+++ b/ash/assistant/ui/main_stage/suggestion_container_view.cc
@@ -156,7 +156,7 @@
   layout_manager_ =
       content_view()->SetLayoutManager(std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kHorizontal,
-          gfx::Insets::VH(0, assistant::ui::GetHorizontalPadding()),
+          gfx::Insets::VH(0, assistant::ui::kHorizontalPadding),
           /*between_child_spacing=*/kSpacingDip));
 
   layout_manager_->set_cross_axis_alignment(
diff --git a/ash/assistant/ui/main_stage/ui_element_container_view.cc b/ash/assistant/ui/main_stage/ui_element_container_view.cc
index aa4e883..377f07c 100644
--- a/ash/assistant/ui/main_stage/ui_element_container_view.cc
+++ b/ash/assistant/ui/main_stage/ui_element_container_view.cc
@@ -135,7 +135,7 @@
 
 void UiElementContainerView::InitLayout() {
   // Content.
-  const int horizontal_margin = assistant::ui::GetHorizontalMargin();
+  const int horizontal_margin = assistant::ui::kHorizontalMargin;
   content_view()->SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical,
       gfx::Insets::TLBR(0, horizontal_margin, kPaddingBottomDip,
diff --git a/ash/capture_mode/recording_overlay_controller.cc b/ash/capture_mode/recording_overlay_controller.cc
index 63b3f629..a69877b 100644
--- a/ash/capture_mode/recording_overlay_controller.cc
+++ b/ash/capture_mode/recording_overlay_controller.cc
@@ -146,7 +146,7 @@
         // triggered.
         if (event->type() == ui::ET_MOUSE_PRESSED ||
             event->type() == ui::ET_TOUCH_PRESSED) {
-          annotations->CloseBubble();
+          annotations->ClickedOutsideBubble();
         }
       }
     }
diff --git a/ash/components/BUILD.gn b/ash/components/BUILD.gn
index 7d56e94a..6889ea4d 100644
--- a/ash/components/BUILD.gn
+++ b/ash/components/BUILD.gn
@@ -26,7 +26,6 @@
     "//ash/components/fwupd:unit_tests",
     "//ash/components/peripheral_notification:unit_tests",
     "//ash/components/phonehub:unit_tests",
-    "//ash/components/tether:unit_tests",
     "//ash/strings",
     "//base/test:test_support",
     "//mojo/core/embedder",
diff --git a/ash/components/tether/DEPS b/ash/components/tether/DEPS
deleted file mode 100644
index cb48dbe7..0000000
--- a/ash/components/tether/DEPS
+++ /dev/null
@@ -1,6 +0,0 @@
-include_rules = [
-  "+chromeos/login/login_state",
-  "+components/proximity_auth/logging",
-  "+components/session_manager/core",
-  "+components/sync_preferences",
-]
diff --git a/ash/components/tether/DIR_METADATA b/ash/components/tether/DIR_METADATA
deleted file mode 100644
index 4cad27d..0000000
--- a/ash/components/tether/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-mixins: "//ash/components/tether/COMMON_METADATA"
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 5ba449eca..f2b24d8 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1226,11 +1226,10 @@
              "LacrosProfileMigrationForceOff",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enable this to turn on profile migration for non-googlers. Currently the
-// feature is only limited to googlers only.
+// Disable this to turn off profile migration for non-googlers.
 BASE_FEATURE(kLacrosProfileMigrationForAnyUser,
              "LacrosProfileMigrationForAnyUser",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // If enabled, use `MoveMigrator` instead of `CopyMigrator` to migrate data.
 // `MoveMigrator` moves data from ash to lacros instead of copying them.
diff --git a/ash/constants/ash_pref_names.cc b/ash/constants/ash_pref_names.cc
index ce355a58e..a5f61387 100644
--- a/ash/constants/ash_pref_names.cc
+++ b/ash/constants/ash_pref_names.cc
@@ -722,6 +722,10 @@
 // String value corresponding to ash::ShelfAutoHideBehavior (e.g. "Never").
 const char kShelfAutoHideBehavior[] = "auto_hide_behavior";
 const char kShelfAutoHideBehaviorLocal[] = "auto_hide_behavior_local";
+const char kShelfAutoHideTabletModeBehavior[] =
+    "auto_hide_tablet_mode_behavior";
+const char kShelfAutoHideTabletModeBehaviorLocal[] =
+    "auto_hide_tablet_mode_behavior_local";
 
 // Dictionary value that determines when the launcher navigation nudge should
 // show to the users.
diff --git a/ash/constants/ash_pref_names.h b/ash/constants/ash_pref_names.h
index cb3a404..dd68bbc7 100644
--- a/ash/constants/ash_pref_names.h
+++ b/ash/constants/ash_pref_names.h
@@ -331,6 +331,10 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kShelfAlignmentLocal[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kShelfAutoHideBehavior[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kShelfAutoHideBehaviorLocal[];
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const char kShelfAutoHideTabletModeBehavior[];
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const char kShelfAutoHideTabletModeBehaviorLocal[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kShelfLauncherNudge[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kShelfPreferences[];
 
diff --git a/ash/frame_throttler/DEPS b/ash/frame_throttler/DEPS
new file mode 100644
index 0000000..96262ae
--- /dev/null
+++ b/ash/frame_throttler/DEPS
@@ -0,0 +1,6 @@
+specific_include_rules = {
+  ".*test.cc": [
+    "+components/viz/test",
+    "+services/viz/privileged/mojom/compositing",
+  ],
+}
diff --git a/ash/frame_throttler/frame_throttling_controller.cc b/ash/frame_throttler/frame_throttling_controller.cc
index 5ada2d0..757456b 100644
--- a/ash/frame_throttler/frame_throttling_controller.cc
+++ b/ash/frame_throttler/frame_throttling_controller.cc
@@ -12,13 +12,14 @@
 #include "ash/shell.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "base/command_line.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
-#include "ui/compositor/compositor.h"
 
 namespace ash {
 
@@ -85,16 +86,19 @@
 }
 
 FrameThrottlingController::FrameThrottlingController(
-    ui::ContextFactory* context_factory)
-    : context_factory_(context_factory) {
+    viz::HostFrameSinkManager* host_frame_sink_manager)
+    : host_frame_sink_manager_(host_frame_sink_manager) {
+  DCHECK(host_frame_sink_manager_);
+  int default_fps = kDefaultThrottleFps;
   const base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
   if (cl->HasSwitch(switches::kFrameThrottleFps)) {
-    int value;
-    if (base::StringToInt(cl->GetSwitchValueASCII(switches::kFrameThrottleFps),
-                          &value)) {
-      throttled_fps_ = value;
+    if (!base::StringToInt(cl->GetSwitchValueASCII(switches::kFrameThrottleFps),
+                           &default_fps)) {
+      default_fps = kDefaultThrottleFps;
     }
   }
+  default_throttled_frame_interval_ = base::Hertz(default_fps);
+  current_throttled_frame_interval_ = default_throttled_frame_interval_;
 }
 
 FrameThrottlingController::~FrameThrottlingController() {
@@ -102,7 +106,10 @@
 }
 
 void FrameThrottlingController::StartThrottling(
-    const std::vector<aura::Window*>& windows) {
+    const std::vector<aura::Window*>& windows,
+    base::TimeDelta requested_frame_interval) {
+  latest_custom_throttled_frame_interval_ = requested_frame_interval;
+
   if (windows_manually_throttled_)
     EndThrottling();
 
@@ -126,6 +133,7 @@
     ash::AppType type =
         static_cast<ash::AppType>(window->GetProperty(aura::client::kAppType));
     switch (type) {
+      case ash::AppType::NON_APP:
       case ash::AppType::BROWSER:
         CollectFrameSinkIds(
             window, &manually_throttled_candidates_.browser_frame_sink_ids);
@@ -144,25 +152,26 @@
 
   // Throttle browser and lacros windows.
   if (!manually_throttled_candidates_.IsEmpty()) {
+    SetWindowsManuallyThrottled(true);
     UpdateThrottlingOnFrameSinks();
     for (const auto& lacros_candidate :
          manually_throttled_candidates_.lacros_candidates) {
       lacros_candidate.first->SetProperty(ash::kFrameRateThrottleKey, true);
     }
-    windows_manually_throttled_ = true;
   }
 
   // Do not throttle arc if at least one arc window should not be throttled.
   if (!arc_windows.empty() && (arc_windows.size() == all_arc_windows.size())) {
-    StartThrottlingArc(arc_windows);
-    windows_manually_throttled_ = true;
+    SetWindowsManuallyThrottled(true);
+    StartThrottlingArc(arc_windows, GetCurrentThrottledFrameRate());
   }
 }
 
 void FrameThrottlingController::StartThrottlingArc(
-    const std::vector<aura::Window*>& arc_windows) {
+    const std::vector<aura::Window*>& arc_windows,
+    uint8_t throttled_fps) {
   for (auto& arc_observer : arc_observers_) {
-    arc_observer.OnThrottlingStarted(arc_windows, throttled_fps_);
+    arc_observer.OnThrottlingStarted(arc_windows, throttled_fps);
   }
 }
 
@@ -174,14 +183,17 @@
 
 void FrameThrottlingController::EndThrottling() {
   if (windows_manually_throttled_) {
+    SetWindowsManuallyThrottled(false);
     ResetThrottleCandidates(&manually_throttled_candidates_);
     UpdateThrottlingOnFrameSinks();
     EndThrottlingArc();
-
-    windows_manually_throttled_ = false;
   }
 }
 
+uint8_t FrameThrottlingController::GetCurrentThrottledFrameRate() const {
+  return base::ClampRound(current_throttled_frame_interval_.ToHz());
+}
+
 void FrameThrottlingController::OnCompositingFrameSinksToThrottleUpdated(
     const aura::WindowTreeHost* window_tree_host,
     const base::flat_set<viz::FrameSinkId>& ids) {
@@ -268,8 +280,33 @@
 }
 
 void FrameThrottlingController::UpdateThrottlingOnFrameSinks() {
-  context_factory_->GetHostFrameSinkManager()->Throttle(
-      GetFrameSinkIdsToThrottle(), base::Hertz(throttled_fps_));
+  SetCurrentThrottledFrameInterval();
+  host_frame_sink_manager_->Throttle(GetFrameSinkIdsToThrottle(),
+                                     current_throttled_frame_interval_);
+}
+
+void FrameThrottlingController::SetWindowsManuallyThrottled(
+    bool windows_manually_throttled) {
+  windows_manually_throttled_ = windows_manually_throttled;
+  // The current frame interval is partially dictated by
+  // |windows_manually_throttled_|, so it may have changed.
+  SetCurrentThrottledFrameInterval();
+}
+
+void FrameThrottlingController::SetCurrentThrottledFrameInterval() {
+  // Implements the criteria described above StartThrottling() in the header.
+  bool use_latest_custom_throttled_frame_interval =
+      windows_manually_throttled_ &&
+      latest_custom_throttled_frame_interval_.is_positive() &&
+      (!HasCompositingBasedThrottling() ||
+       latest_custom_throttled_frame_interval_ <=
+           default_throttled_frame_interval_);
+  current_throttled_frame_interval_ =
+      use_latest_custom_throttled_frame_interval
+          ? latest_custom_throttled_frame_interval_
+          : default_throttled_frame_interval_;
+  DVLOG(1) << "Throttled frame interval set to "
+           << current_throttled_frame_interval_;
 }
 
 void FrameThrottlingController::AddArcObserver(
@@ -333,4 +370,12 @@
     CollectLacrosCandidates(child, candidates, lacros_window);
 }
 
+bool FrameThrottlingController::HasCompositingBasedThrottling() const {
+  for (const auto& [_, candidates] : host_to_candidates_map_) {
+    if (!candidates.IsEmpty())
+      return true;
+  }
+  return false;
+}
+
 }  // namespace ash
diff --git a/ash/frame_throttler/frame_throttling_controller.h b/ash/frame_throttler/frame_throttling_controller.h
index d1808ae..6b2d798 100644
--- a/ash/frame_throttler/frame_throttling_controller.h
+++ b/ash/frame_throttler/frame_throttling_controller.h
@@ -23,9 +23,9 @@
 class Window;
 }
 
-namespace ui {
-class ContextFactory;
-}
+namespace viz {
+class HostFrameSinkManager;
+}  // namespace viz
 
 namespace ash {
 
@@ -51,7 +51,8 @@
     : public aura::WindowTreeHostObserver,
       public aura::WindowObserver {
  public:
-  explicit FrameThrottlingController(ui::ContextFactory* context_factory);
+  explicit FrameThrottlingController(
+      viz::HostFrameSinkManager* host_frame_sink_manager);
   FrameThrottlingController(const FrameThrottlingController&) = delete;
   FrameThrottlingController& operator=(const FrameThrottlingController&) =
       delete;
@@ -67,9 +68,35 @@
 
   void OnWindowTreeHostCreated(aura::WindowTreeHost* host);
 
-  // Starts to throttle the framerate of |windows|.
-  void StartThrottling(const std::vector<aura::Window*>& windows);
-  // Ends throttling of all throttled windows.
+  // Starts to throttle the frame rate of |windows| at the custom
+  // |requested_frame_interval|. The |requested_frame_interval| is used unless
+  // the controller is actively throttling other windows not specified via
+  // StartThrottling() at a frame rate higher than the one requested here.
+  //
+  // Examples:
+  // Case 1: Controller is throttling a window specified via
+  //         OnCompositingFrameSinksToThrottleUpdated() at 20 fps, and
+  //         StartThrottling(<new window>, 30fps) is called. Both windows
+  //         will be throttled at 30 fps.
+  // Case 2: Controller is throttling a window specified via
+  //         OnCompositingFrameSinksToThrottleUpdated() at 20 fps, and
+  //         StartThrottling(<new window>, 15fps) is called. Both windows
+  //         will be throttled at 20 fps.
+  // Case 3: Controller is not throttling any windows, and
+  //         StartThrottling(<new window>, 15fps) is called. The new window
+  //         will be throttled at 15 fps.
+  //
+  // The higher frame rate is always picked to ensure all UIs are smooth enough,
+  // even if it comes at the cost of more power consumption.
+  //
+  // If the |requested_frame_interval| is zero, the default throttled frame rate
+  // is used internally.
+  void StartThrottling(
+      const std::vector<aura::Window*>& windows,
+      base::TimeDelta requested_frame_interval = base::TimeDelta());
+
+  // Ends throttling of all windows specified via StartThrottling(). The
+  // throttled frame rate for any remaining windows returns to the default.
   void EndThrottling();
 
   std::vector<viz::FrameSinkId> GetFrameSinkIdsToThrottle() const;
@@ -78,10 +105,21 @@
   void RemoveArcObserver(FrameThrottlingObserver* observer);
   bool HasArcObserver(FrameThrottlingObserver* observer);
 
-  uint8_t throttled_fps() const { return throttled_fps_; }
+  // The current frame interval being used. Note this applies to all windows
+  // that the controller is currently throttling. The viz service does not allow
+  // for multiple simultaneous frame rates.
+  base::TimeDelta current_throttled_frame_interval() const {
+    return current_throttled_frame_interval_;
+  }
+
+  // Returns 1 / current_throttled_frame_interval() rounded to the nearest
+  // integer. Note if the frame interval is very large, this may legitimately
+  // return 0 fps.
+  uint8_t GetCurrentThrottledFrameRate() const;
 
  private:
-  void StartThrottlingArc(const std::vector<aura::Window*>& windows);
+  void StartThrottlingArc(const std::vector<aura::Window*>& windows,
+                          uint8_t throttled_fps);
   void EndThrottlingArc();
 
   // Collect the lacros window in the given |window|. This function recursively
@@ -107,10 +145,15 @@
       aura::Window* lacros_window);
 
   void UpdateThrottlingOnFrameSinks();
+  void SetWindowsManuallyThrottled(bool windows_manually_throttled);
+  void SetCurrentThrottledFrameInterval();
+  // Whether there are any windows to throttle besides the ones specified via
+  // StartThrottling().
+  bool HasCompositingBasedThrottling() const;
 
   void ResetThrottleCandidates(ThrottleCandidates* candidates);
 
-  ui::ContextFactory* context_factory_ = nullptr;
+  viz::HostFrameSinkManager* const host_frame_sink_manager_;
   base::ObserverList<FrameThrottlingObserver> observers_;
   base::ObserverList<FrameThrottlingObserver> arc_observers_;
 
@@ -127,8 +170,16 @@
   // when UI is not in such modes.
   ThrottleCandidates manually_throttled_candidates_;
 
-  // The fps used for throttling.
-  uint8_t throttled_fps_ = kDefaultThrottleFps;
+  // The default frame interval that should be used when a custom interval is
+  // not requested via StartThrottling(). This value is effectively immutable.
+  base::TimeDelta default_throttled_frame_interval_;
+  // The current frame interval used for throttling. Changes according to which
+  // windows are throttled and what frame rates were requested by the caller.
+  base::TimeDelta current_throttled_frame_interval_;
+  // The latest |requested_frame_interval| provided in StartThrottling().
+  // May be zero if one was not requested.
+  base::TimeDelta latest_custom_throttled_frame_interval_;
+
   bool windows_manually_throttled_ = false;
 };
 
diff --git a/ash/frame_throttler/frame_throttling_controller_unittest.cc b/ash/frame_throttler/frame_throttling_controller_unittest.cc
new file mode 100644
index 0000000..f8af31d8
--- /dev/null
+++ b/ash/frame_throttler/frame_throttling_controller_unittest.cc
@@ -0,0 +1,189 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/frame_throttler/frame_throttling_controller.h"
+
+#include <utility>
+#include <vector>
+
+#include "ash/constants/app_types.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_helper.h"
+#include "base/callback.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/host/host_frame_sink_manager.h"
+#include "components/viz/test/test_frame_sink_manager.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ash {
+namespace {
+
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::testing::UnorderedElementsAre;
+
+class FakeFrameSinkManagerImpl : public viz::TestFrameSinkManagerImpl {
+ public:
+  FakeFrameSinkManagerImpl() = default;
+  FakeFrameSinkManagerImpl(const FakeFrameSinkManagerImpl&) = delete;
+  FakeFrameSinkManagerImpl& operator=(const FakeFrameSinkManagerImpl&) = delete;
+  ~FakeFrameSinkManagerImpl() override = default;
+
+  // mojom::FrameSinkManager implementation:
+  void Throttle(const std::vector<viz::FrameSinkId>& ids,
+                base::TimeDelta interval) override {
+    throttled_interval_ = interval;
+    throttled_frame_sink_ids_ = ids;
+  }
+
+  base::TimeDelta throttled_interval() const { return throttled_interval_; }
+  const std::vector<viz::FrameSinkId>& throttled_frame_sink_ids() const {
+    return throttled_frame_sink_ids_;
+  }
+
+ private:
+  base::TimeDelta throttled_interval_;
+  std::vector<viz::FrameSinkId> throttled_frame_sink_ids_;
+};
+
+class FrameThrottlingControllerTest : public AshTestBase {
+ protected:
+  FrameThrottlingControllerTest() : controller_(&host_frame_sink_manager_) {
+    mojo::PendingRemote<viz::mojom::FrameSinkManager> frame_sink_manager;
+    mojo::PendingReceiver<viz::mojom::FrameSinkManager>
+        frame_sink_manager_receiver =
+            frame_sink_manager.InitWithNewPipeAndPassReceiver();
+    mojo::PendingRemote<viz::mojom::FrameSinkManagerClient>
+        frame_sink_manager_client;
+    mojo::PendingReceiver<viz::mojom::FrameSinkManagerClient>
+        frame_sink_manager_client_receiver =
+            frame_sink_manager_client.InitWithNewPipeAndPassReceiver();
+
+    host_frame_sink_manager_.BindAndSetManager(
+        std::move(frame_sink_manager_client_receiver),
+        task_environment()->GetMainThreadTaskRunner(),
+        std::move(frame_sink_manager));
+    frame_sink_manager_impl_.BindReceiver(
+        std::move(frame_sink_manager_receiver),
+        std::move(frame_sink_manager_client));
+  }
+
+  void SetUp() override {
+    AshTestBase::SetUp();
+    controller_.OnWindowTreeHostCreated(ash_test_helper()->GetHost());
+  }
+
+  std::unique_ptr<aura::Window> CreateTestBrowserWindow(
+      const viz::FrameSinkId frame_sink_id) {
+    std::unique_ptr<aura::Window> browser_window =
+        CreateAppWindow(gfx::Rect(100, 100), AppType::BROWSER);
+    browser_window->SetEmbedFrameSinkId(frame_sink_id);
+    return browser_window;
+  }
+
+  FakeFrameSinkManagerImpl frame_sink_manager_impl_;
+  viz::HostFrameSinkManager host_frame_sink_manager_;
+  FrameThrottlingController controller_;
+};
+
+TEST_F(FrameThrottlingControllerTest, ManualThrottling) {
+  std::unique_ptr<aura::Window> window_1 = CreateTestWindow();
+  window_1->SetEmbedFrameSinkId({1, 1});
+  std::unique_ptr<aura::Window> window_2 = CreateTestWindow();
+  window_2->SetEmbedFrameSinkId({2, 2});
+
+  // 10 Hz is lower than the default, but there are no other windows actively
+  // being throttled, so 10 Hz should be used.
+  controller_.StartThrottling({window_1.get(), window_2.get()},
+                              base::Hertz(10));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_interval(),
+              Eq(base::Hertz(10)));
+  EXPECT_THAT(
+      frame_sink_manager_impl_.throttled_frame_sink_ids(),
+      UnorderedElementsAre(viz::FrameSinkId({1, 1}), viz::FrameSinkId({2, 2})));
+
+  controller_.StartThrottling({window_1.get()});
+  base::RunLoop().RunUntilIdle();
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_interval(),
+              Eq(base::Hertz(kDefaultThrottleFps)));
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_frame_sink_ids(),
+              UnorderedElementsAre(viz::FrameSinkId({1, 1})));
+
+  controller_.EndThrottling();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_frame_sink_ids(), IsEmpty());
+}
+
+TEST_F(FrameThrottlingControllerTest, CompositingBasedThrottling) {
+  constexpr viz::FrameSinkId kBrowserWindowFrameSinkId = {99, 99};
+
+  std::unique_ptr<aura::Window> browser_window =
+      CreateTestBrowserWindow(kBrowserWindowFrameSinkId);
+
+  controller_.OnCompositingFrameSinksToThrottleUpdated(
+      ash_test_helper()->GetHost(), {kBrowserWindowFrameSinkId});
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_interval(),
+              Eq(base::Hertz(kDefaultThrottleFps)));
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_frame_sink_ids(),
+              UnorderedElementsAre(kBrowserWindowFrameSinkId));
+}
+
+TEST_F(FrameThrottlingControllerTest, ManualAndCompositingBasedThrottling) {
+  constexpr viz::FrameSinkId kBrowserWindowFrameSinkId = {99, 99};
+  constexpr viz::FrameSinkId kManualWindowFrameSinkId = {100, 100};
+
+  std::unique_ptr<aura::Window> browser_window =
+      CreateTestBrowserWindow(kBrowserWindowFrameSinkId);
+
+  controller_.OnCompositingFrameSinksToThrottleUpdated(
+      ash_test_helper()->GetHost(), {kBrowserWindowFrameSinkId});
+  base::RunLoop().RunUntilIdle();
+
+  std::unique_ptr<aura::Window> manual_window = CreateTestWindow();
+  manual_window->SetEmbedFrameSinkId(kManualWindowFrameSinkId);
+
+  // 10 Hz is lower than the default frame rate, so it should be rejected.
+  controller_.StartThrottling({manual_window.get()}, base::Hertz(10));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_interval(),
+              Eq(base::Hertz(kDefaultThrottleFps)));
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_frame_sink_ids(),
+              UnorderedElementsAre(kBrowserWindowFrameSinkId,
+                                   kManualWindowFrameSinkId));
+
+  // 30 Hz is higher than the default frame rate, so it should be respected.
+  controller_.StartThrottling({manual_window.get()}, base::Hertz(30));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_interval(),
+              Eq(base::Hertz(30)));
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_frame_sink_ids(),
+              UnorderedElementsAre(kBrowserWindowFrameSinkId,
+                                   kManualWindowFrameSinkId));
+
+  // The frame rate should return to default after manual window is removed.
+  controller_.EndThrottling();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_interval(),
+              Eq(base::Hertz(kDefaultThrottleFps)));
+  EXPECT_THAT(frame_sink_manager_impl_.throttled_frame_sink_ids(),
+              UnorderedElementsAre(kBrowserWindowFrameSinkId));
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 3722df741..280b111 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -260,7 +260,7 @@
   // views::Label:
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
     node_data->role = ax::mojom::Role::kStaticText;
-    node_data->SetName(accessible_name_);
+    node_data->SetNameChecked(accessible_name_);
   }
 
   // views::Label:
diff --git a/ash/metrics/login_unlock_throughput_recorder.cc b/ash/metrics/login_unlock_throughput_recorder.cc
index 76b25081..28520c2 100644
--- a/ash/metrics/login_unlock_throughput_recorder.cc
+++ b/ash/metrics/login_unlock_throughput_recorder.cc
@@ -5,20 +5,67 @@
 #include "ash/metrics/login_unlock_throughput_recorder.h"
 
 #include "ash/public/cpp/metrics_util.h"
+#include "ash/public/cpp/shelf_model.h"
 #include "ash/session/session_controller_impl.h"
+#include "ash/shelf/shelf_view.h"
 #include "ash/shell.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/bind.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "chromeos/metrics/login_event_recorder.h"
+#include "components/app_constants/constants.h"
+#include "components/app_restore/window_properties.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/layer.h"
 #include "ui/compositor/total_animation_throughput_reporter.h"
+#include "ui/views/animation/bounds_animator.h"
+#include "ui/views/animation/bounds_animator_observer.h"
 
 namespace ash {
 namespace {
 
+// A class used to wait for animations.
+class AnimationObserver : public views::BoundsAnimatorObserver {
+ public:
+  AnimationObserver(ShelfView* shelf_view, base::OnceClosure& on_animation_end)
+      : shelf_view_(shelf_view),
+        on_animation_end_(std::move(on_animation_end)) {}
+
+  AnimationObserver(const AnimationObserver&) = delete;
+  AnimationObserver& operator=(const AnimationObserver&) = delete;
+
+  ~AnimationObserver() override = default;
+
+  // ShelfViewObserver overrides:
+  void OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) override {}
+  void OnBoundsAnimatorDone(views::BoundsAnimator* animator) override {
+    shelf_view_->RemoveAnimationObserver(this);
+    RunCallbackAndDestroy();
+  }
+
+  void StartObserving() {
+    if (shelf_view_->IsAnimating()) {
+      shelf_view_->AddAnimationObserver(this);
+      return;
+    }
+    RunCallbackAndDestroy();
+  }
+
+ private:
+  void RunCallbackAndDestroy() {
+    std::move(on_animation_end_).Run();
+    delete this;
+  }
+
+  base::raw_ptr<ShelfView> shelf_view_;
+  base::OnceClosure on_animation_end_;
+};
+
 std::string GetDeviceModeSuffix() {
   return Shell::Get()->tablet_mode_controller()->InTabletMode()
              ? "TabletMode"
@@ -57,6 +104,7 @@
     LOG(WARNING) << "Zero frames expected in login animation throughput data";
     return;
   }
+
   chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
       "LoginAnimationEnd",
       /*send_to_uma=*/false,
@@ -76,6 +124,14 @@
                 "Ash.UnlockAnimation.Jank.", "Ash.UnlockAnimation.Duration.");
 }
 
+void OnRestoredWindowPresentationFeedbackReceived(
+    int restore_window_id,
+    const gfx::PresentationFeedback& feedback) {
+  LoginUnlockThroughputRecorder* throughput_recorder =
+      Shell::Get()->login_unlock_throughput_recorder();
+  throughput_recorder->OnRestoredWindowPresented(restore_window_id);
+}
+
 }  // namespace
 
 LoginUnlockThroughputRecorder::LoginUnlockThroughputRecorder() {
@@ -98,24 +154,160 @@
     new ui::TotalAnimationThroughputReporter(
         primary_root->GetHost()->compositor(),
         base::BindOnce(&ReportUnlock, base::TimeTicks::Now()),
-        /*self_destruct=*/true);
+        /*should_delete=*/true);
   }
 }
 
 void LoginUnlockThroughputRecorder::LoggedInStateChanged() {
   auto* login_state = chromeos::LoginState::Get();
   auto logged_in_user = login_state->GetLoggedInUserType();
-  if (login_state->IsUserLoggedIn() &&
-      (logged_in_user == chromeos::LoginState::LOGGED_IN_USER_OWNER ||
-       logged_in_user == chromeos::LoginState::LOGGED_IN_USER_REGULAR)) {
-    ui_recorder_.OnUserLoggedIn();
-    auto* primary_root = Shell::GetPrimaryRootWindow();
-    new ui::TotalAnimationThroughputReporter(
-        primary_root->GetHost()->compositor(),
-        base::BindOnce(&LoginUnlockThroughputRecorder::OnLoginAnimationFinish,
-                       weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()),
-        /*self_destruct=*/true);
+
+  if (user_logged_in_)
+    return;
+
+  if (!login_state->IsUserLoggedIn())
+    return;
+
+  if (logged_in_user != chromeos::LoginState::LOGGED_IN_USER_OWNER &&
+      logged_in_user != chromeos::LoginState::LOGGED_IN_USER_REGULAR) {
+    return;
   }
+
+  user_logged_in_ = true;
+  ui_recorder_.OnUserLoggedIn();
+  auto* primary_root = Shell::GetPrimaryRootWindow();
+  primary_user_logged_in_ = base::TimeTicks::Now();
+  auto* rec = new ui::TotalAnimationThroughputReporter(
+      primary_root->GetHost()->compositor(),
+      base::BindOnce(&LoginUnlockThroughputRecorder::OnLoginAnimationFinish,
+                     weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()),
+      /*should_delete=*/true);
+  login_animation_throughput_reporter_ = rec->GetWeakPtr();
+  DCHECK(!scoped_throughput_reporter_blocker_);
+  // Login animation metrics should not be reported until all shelf icons
+  // were loaded.
+  scoped_throughput_reporter_blocker_ =
+      login_animation_throughput_reporter_->NewScopedBlocker();
+}
+
+void LoginUnlockThroughputRecorder::AddScheduledRestoreWindow(
+    int restore_window_id,
+    const std::string& app_id,
+    RestoreWindowType window_type) {
+  switch (window_type) {
+    case LoginUnlockThroughputRecorder::kBrowser:
+      DCHECK(restore_window_id);
+      if (app_id.empty() || app_id == app_constants::kLacrosAppId)
+        windows_to_restore_.insert(restore_window_id);
+
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void LoginUnlockThroughputRecorder::OnRestoredWindowCreated(
+    int restore_window_id) {
+  auto it = windows_to_restore_.find(restore_window_id);
+  if (it == windows_to_restore_.end())
+    return;
+  windows_to_restore_.erase(it);
+  if (windows_to_restore_.empty() && !primary_user_logged_in_.is_null()) {
+    const base::TimeDelta duration_ms =
+        base::TimeTicks::Now() - primary_user_logged_in_;
+    UMA_HISTOGRAM_CUSTOM_TIMES(
+        "Ash.LoginSessionRestore.AllBrowserWindowsCreated", duration_ms,
+        base::Milliseconds(1), base::Seconds(100), 100);
+  }
+  restore_windows_not_shown_.insert(restore_window_id);
+}
+
+void LoginUnlockThroughputRecorder::OnBeforeRestoredWindowShown(
+    int restore_window_id,
+    ui::Compositor* compositor) {
+  auto it = restore_windows_not_shown_.find(restore_window_id);
+  if (it == restore_windows_not_shown_.end())
+    return;
+
+  restore_windows_not_shown_.erase(it);
+  if (windows_to_restore_.empty() && restore_windows_not_shown_.empty() &&
+      !primary_user_logged_in_.is_null()) {
+    const base::TimeDelta duration_ms =
+        base::TimeTicks::Now() - primary_user_logged_in_;
+    UMA_HISTOGRAM_CUSTOM_TIMES("Ash.LoginSessionRestore.AllBrowserWindowsShown",
+                               duration_ms, base::Milliseconds(1),
+                               base::Seconds(100), 100);
+  }
+
+  if (!compositor)
+    return;
+
+  restore_windows_presentation_time_requested_.insert(restore_window_id);
+  compositor->RequestPresentationTimeForNextFrame(base::BindOnce(
+      &OnRestoredWindowPresentationFeedbackReceived, restore_window_id));
+}
+
+void LoginUnlockThroughputRecorder::OnRestoredWindowPresented(
+    int restore_window_id) {
+  auto it =
+      restore_windows_presentation_time_requested_.find(restore_window_id);
+  if (it == restore_windows_presentation_time_requested_.end())
+    return;
+
+  restore_windows_presentation_time_requested_.erase(it);
+  if (windows_to_restore_.empty() && restore_windows_not_shown_.empty() &&
+      restore_windows_presentation_time_requested_.empty() &&
+      !primary_user_logged_in_.is_null()) {
+    const base::TimeDelta duration_ms =
+        base::TimeTicks::Now() - primary_user_logged_in_;
+    UMA_HISTOGRAM_CUSTOM_TIMES(
+        "Ash.LoginSessionRestore.AllBrowserWindowsPresented", duration_ms,
+        base::Milliseconds(1), base::Seconds(100), 100);
+  }
+  restore_windows_presented_.insert(restore_window_id);
+}
+
+void LoginUnlockThroughputRecorder::InitShelfIconList(const ShelfModel* model) {
+  shelf_initialized_ = true;
+
+  // Copy shelf icons to the expected list.
+  for (int index = 0; index < model->item_count(); ++index) {
+    const ShelfID& id = model->items()[index].id;
+    const ShelfItem& item = model->items()[index];
+    if (item.image.isNull())
+      expected_shelf_icons_.insert(id);
+  }
+
+  if (expected_shelf_icons_.empty())
+    OnAllExpectedShelfIconsLoaded();
+}
+
+void LoginUnlockThroughputRecorder::UpdateShelfIconList(
+    const ShelfModel* model) {
+  if (!shelf_initialized_)
+    return;
+
+  // Remove IDs that have icons loaded or were already deleted.
+  base::flat_set<ShelfID> expected_ids_without_icons;
+
+  for (int index = 0; index < model->item_count(); ++index) {
+    const ShelfItem& item = model->items()[index];
+    const ShelfID& id = item.id;
+    if (!expected_shelf_icons_.contains(id))
+      continue;
+
+    if (item.image.isNull())
+      expected_ids_without_icons.insert(id);
+  }
+  expected_shelf_icons_ = expected_ids_without_icons;
+
+  if (expected_shelf_icons_.empty())
+    OnAllExpectedShelfIconsLoaded();
+}
+
+void LoginUnlockThroughputRecorder::
+    ResetScopedThroughputReporterBlockerForTesting() {
+  scoped_throughput_reporter_blocker_.reset();
 }
 
 void LoginUnlockThroughputRecorder::OnLoginAnimationFinish(
@@ -125,4 +317,43 @@
   ReportLogin(start, data);
 }
 
+void LoginUnlockThroughputRecorder::SetShelfViewIfNotSet(
+    ShelfView* shelf_view) {
+  if (!shelf_view_)
+    shelf_view_ = shelf_view;
+}
+
+void LoginUnlockThroughputRecorder::ScheduleWaitForShelfAnimationEnd() {
+  DCHECK(shelf_view_);
+  if (!shelf_view_)
+    return;
+
+  base::OnceCallback on_animation_end = base::BindOnce(
+      [](base::TimeTicks primary_user_logged_in) {
+        const base::TimeDelta duration_ms =
+            base::TimeTicks::Now() - primary_user_logged_in;
+        UMA_HISTOGRAM_CUSTOM_TIMES(
+            "Ash.LoginSessionRestore.ShelfLoginAnimationEnd", duration_ms,
+            base::Milliseconds(1), base::Seconds(100), 100);
+      },
+      primary_user_logged_in_);
+
+  (new AnimationObserver(shelf_view_, on_animation_end))->StartObserving();
+}
+
+void LoginUnlockThroughputRecorder::OnAllExpectedShelfIconsLoaded() {
+  if (shelf_icons_loaded_)
+    return;
+
+  scoped_throughput_reporter_blocker_.reset();
+
+  shelf_icons_loaded_ = true;
+  const base::TimeDelta duration_ms =
+      base::TimeTicks::Now() - primary_user_logged_in_;
+  UMA_HISTOGRAM_CUSTOM_TIMES("Ash.LoginSessionRestore.AllShelfIconsLoaded",
+                             duration_ms, base::Milliseconds(1),
+                             base::Seconds(100), 100);
+  ScheduleWaitForShelfAnimationEnd();
+}
+
 }  // namespace ash
diff --git a/ash/metrics/login_unlock_throughput_recorder.h b/ash/metrics/login_unlock_throughput_recorder.h
index 55f5bbc..8c1dd7e9 100644
--- a/ash/metrics/login_unlock_throughput_recorder.h
+++ b/ash/metrics/login_unlock_throughput_recorder.h
@@ -5,20 +5,38 @@
 #ifndef ASH_METRICS_LOGIN_UNLOCK_THROUGHPUT_RECORDER_H_
 #define ASH_METRICS_LOGIN_UNLOCK_THROUGHPUT_RECORDER_H_
 
+#include <string>
+
 #include "ash/ash_export.h"
 #include "ash/metrics/ui_throughput_recorder.h"
 #include "ash/public/cpp/session/session_observer.h"
+#include "ash/public/cpp/shelf_types.h"
+#include "base/containers/flat_set.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "cc/metrics/frame_sequence_metrics.h"
 #include "chromeos/login/login_state/login_state.h"
+#include "ui/compositor/total_animation_throughput_reporter.h"
+
+namespace ui {
+class Compositor;
+}
 
 namespace ash {
 
+class ShelfModel;
+class ShelfView;
+
 class ASH_EXPORT LoginUnlockThroughputRecorder
     : public SessionObserver,
       public chromeos::LoginState::Observer {
  public:
+  enum RestoreWindowType {
+    kBrowser,
+    kArc,
+  };
+
   LoginUnlockThroughputRecorder();
   LoginUnlockThroughputRecorder(const LoginUnlockThroughputRecorder&) = delete;
   LoginUnlockThroughputRecorder& operator=(
@@ -31,12 +49,85 @@
   // chromeos::LoginState::Observer:
   void LoggedInStateChanged() override;
 
+  // Adds "restore_window_id" to the list of potentially restored windows.
+  // See
+  // https://source.chromium.org/chromium/chromium/src/+/main:ui/views/widget/widget.h;l=404-415.
+  void AddScheduledRestoreWindow(int restore_window_id,
+                                 const std::string& app_id,
+                                 RestoreWindowType window_type);
+
+  // This is called when restored window was created.
+  void OnRestoredWindowCreated(int restore_window_id);
+
+  // This is called before window is shown to request presentation feedback.
+  void OnBeforeRestoredWindowShown(int restore_window_id,
+                                   ui::Compositor* compositor);
+
+  // This is called when restored window was presented.
+  void OnRestoredWindowPresented(int restore_window_id);
+
+  // This is called when the list of shelf icons is initialized.
+  void InitShelfIconList(const ShelfModel* model);
+
+  // This is called when the list of shelf icons is updated.
+  void UpdateShelfIconList(const ShelfModel* model);
+
+  // Remembers ShelfView pointer to watch for shelf animation finish.
+  void SetShelfViewIfNotSet(ShelfView* shelf_view);
+
+  void ResetScopedThroughputReporterBlockerForTesting();
+
+  const ui::TotalAnimationThroughputReporter*
+  login_animation_throughput_reporter() const {
+    return login_animation_throughput_reporter_.get();
+  }
+
  private:
   void OnLoginAnimationFinish(
       base::TimeTicks start,
       const cc::FrameSequenceMetrics::CustomReportData& data);
 
+  void ScheduleWaitForShelfAnimationEnd();
+
+  void OnAllExpectedShelfIconsLoaded();
+
   UiThroughputRecorder ui_recorder_;
+
+  // Set of window IDs ("restore_window_id") that could be restored but
+  // for which windows have not been created yet.
+  base::flat_set<int> windows_to_restore_;
+
+  // Set of window IDs ("restore_window_id") that were created as a part of the
+  // session restore but not yet shown.
+  base::flat_set<int> restore_windows_not_shown_;
+
+  // Set of window IDs ("restore_window_id") that were shown and presentation
+  // time was requested.
+  base::flat_set<int> restore_windows_presentation_time_requested_;
+
+  // Set of window IDs ("restore_window_id") for which presentation time
+  // was received.
+  base::flat_set<int> restore_windows_presented_;
+
+  base::TimeTicks primary_user_logged_in_;
+
+  base::raw_ptr<ShelfView> shelf_view_ = nullptr;
+
+  bool shelf_initialized_ = false;
+
+  bool shelf_icons_loaded_ = false;
+
+  bool user_logged_in_ = false;
+
+  base::WeakPtr<ui::TotalAnimationThroughputReporter>
+      login_animation_throughput_reporter_;
+
+  std::unique_ptr<
+      ui::TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker>
+      scoped_throughput_reporter_blocker_;
+
+  base::flat_set<ShelfID> expected_shelf_icons_;
+
   base::WeakPtrFactory<LoginUnlockThroughputRecorder> weak_ptr_factory_{this};
 };
 
diff --git a/ash/metrics/login_unlock_throughput_recorder_unittest.cc b/ash/metrics/login_unlock_throughput_recorder_unittest.cc
new file mode 100644
index 0000000..9051400
--- /dev/null
+++ b/ash/metrics/login_unlock_throughput_recorder_unittest.cc
@@ -0,0 +1,542 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/metrics/login_unlock_throughput_recorder.h"
+
+#include <memory>
+#include <string>
+
+#include "ash/login/ui/login_test_base.h"
+#include "ash/metrics/user_metrics_recorder.h"
+#include "ash/public/cpp/shelf_item_delegate.h"
+#include "ash/public/cpp/shelf_model.h"
+#include "ash/session/test_session_controller_client.h"
+#include "ash/shell.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "base/run_loop.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "chromeos/login/login_state/login_state.h"
+#include "components/app_constants/constants.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/compositor/test/draw_waiter_for_test.h"
+#include "ui/gfx/image/image_unittest_util.h"
+
+namespace ash {
+namespace {
+
+constexpr char kAshLoginAnimationDurationTabletMode[] =
+    "Ash.LoginAnimation.Duration.TabletMode";
+constexpr char kAshLoginAnimationDurationClamshellMode[] =
+    "Ash.LoginAnimation.Duration.ClamshellMode";
+constexpr char kAshUnlockAnimationDurationTabletMode[] =
+    "Ash.UnlockAnimation.Duration.TabletMode";
+constexpr char kAshUnlockAnimationDurationClamshellMode[] =
+    "Ash.UnlockAnimation.Duration.ClamshellMode";
+
+// A test shelf item delegate that simulates an activated window when a shelf
+// item is selected.
+class TestShelfItemDelegate : public ShelfItemDelegate {
+ public:
+  explicit TestShelfItemDelegate(const ShelfID& shelf_id)
+      : ShelfItemDelegate(shelf_id) {}
+
+  // ShelfItemDelegate:
+  void ItemSelected(std::unique_ptr<ui::Event> event,
+                    int64_t display_id,
+                    ash::ShelfLaunchSource source,
+                    ItemSelectedCallback callback,
+                    const ItemFilterPredicate& filter_predicate) override {
+    std::move(callback).Run(SHELF_ACTION_WINDOW_ACTIVATED, {});
+  }
+  void ExecuteCommand(bool from_context_menu,
+                      int64_t command_id,
+                      int32_t event_flags,
+                      int64_t display_id) override {}
+  void Close() override {}
+};
+
+class TestShelfModel : public ShelfModel {
+ public:
+  TestShelfModel() = default;
+  TestShelfModel(const TestShelfModel&) = delete;
+  TestShelfModel& operator=(const TestShelfModel&) = delete;
+
+  ~TestShelfModel() = default;
+
+  void InitializeIconList(const std::vector<int>& ids) {
+    while (!items().empty())
+      RemoveItemAt(0);
+
+    for (int n : ids) {
+      ShelfItem item;
+      item.id = ShelfID(base::StringPrintf("item%d", n));
+      item.type = TYPE_PINNED_APP;
+      Add(item, std::make_unique<TestShelfItemDelegate>(item.id));
+    }
+  }
+
+  void SetIconsLoadedFor(const std::vector<int>& ids) {
+    for (int n : ids) {
+      const ShelfID id(base::StringPrintf("item%d", n));
+      int index = ItemIndexByID(id);
+      // Expect item exists.
+      ASSERT_GE(index, 0);
+
+      ShelfItem item = items()[index];
+      item.image = gfx::test::CreateImageSkia(/*width=*/10, /*height=*/10);
+
+      Set(index, item);
+    }
+  }
+};
+
+class TestObserver final : public ui::CompositorAnimationObserver {
+ public:
+  explicit TestObserver(ui::Compositor* compositor) : compositor_(compositor) {
+    compositor_->AddAnimationObserver(this);
+  }
+  TestObserver(const TestObserver&) = delete;
+  TestObserver& operator=(const TestObserver&) = delete;
+  ~TestObserver() override = default;
+
+  // ui::CompositorAnimationObserver:
+  void OnAnimationStep(base::TimeTicks timestamp) override {
+    ++count_;
+    if (count_ < 3)
+      compositor_->ScheduleFullRedraw();
+    else
+      compositor_->RemoveAnimationObserver(this);
+  }
+
+  void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
+
+ private:
+  int count_ = 0;
+  const base::raw_ptr<ui::Compositor> compositor_;
+};
+
+class BeginMainFrameWaiter : public ui::CompositorObserver {
+ public:
+  explicit BeginMainFrameWaiter(ui::Compositor* compositor)
+      : compositor_(compositor) {
+    compositor->AddObserver(this);
+  }
+
+  ~BeginMainFrameWaiter() override { compositor_->RemoveObserver(this); }
+
+  // ui::CompositorObserver
+  void OnDidBeginMainFrame(ui::Compositor* compositor) override {
+    DCHECK_EQ(compositor_, compositor);
+    done_ = true;
+    if (run_loop_)
+      run_loop_->Quit();
+  }
+
+  void Wait() {
+    if (done_)
+      return;
+
+    run_loop_ = std::make_unique<base::RunLoop>(
+        base::RunLoop::Type::kNestableTasksAllowed);
+    run_loop_->Run();
+    run_loop_.reset();
+  }
+
+ private:
+  const base::raw_ptr<ui::Compositor> compositor_;
+  bool done_ = false;
+  std::unique_ptr<base::RunLoop> run_loop_;
+};
+
+class FirstNonAnimatedFrameStartedWaiter : public ui::CompositorObserver {
+ public:
+  explicit FirstNonAnimatedFrameStartedWaiter(ui::Compositor* compositor)
+      : compositor_(compositor) {
+    compositor->AddObserver(this);
+  }
+
+  ~FirstNonAnimatedFrameStartedWaiter() override {
+    compositor_->RemoveObserver(this);
+  }
+
+  // ui::CompositorObserver
+  void OnFirstNonAnimatedFrameStarted(ui::Compositor* compositor) override {
+    DCHECK_EQ(compositor_, compositor);
+    done_ = true;
+    if (run_loop_)
+      run_loop_->Quit();
+  }
+
+  void Wait() {
+    if (done_)
+      return;
+
+    run_loop_ = std::make_unique<base::RunLoop>(
+        base::RunLoop::Type::kNestableTasksAllowed);
+    run_loop_->Run();
+    run_loop_.reset();
+  }
+
+ private:
+  ui::Compositor* compositor_;
+  bool done_ = false;
+  std::unique_ptr<base::RunLoop> run_loop_;
+};
+
+void GiveItSomeTime(base::TimeDelta delta) {
+  // Due to the |frames_to_terminate_tracker|=3 constant in
+  // FrameSequenceTracker::ReportSubmitFrame we need to continue generating
+  // frames to receive feedback.
+  base::RepeatingTimer begin_main_frame_scheduler(
+      FROM_HERE, base::Milliseconds(16), base::BindRepeating([]() {
+        auto* compositor =
+            Shell::GetPrimaryRootWindow()->GetHost()->compositor();
+        compositor->ScheduleFullRedraw();
+      }));
+  begin_main_frame_scheduler.Reset();
+
+  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  auto* compositor = Shell::GetPrimaryRootWindow()->GetHost()->compositor();
+  compositor->ScheduleFullRedraw();
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), delta);
+  run_loop.Run();
+}
+
+class MetricsWaiter {
+ public:
+  MetricsWaiter(base::HistogramTester* histogram_tester,
+                std::string metrics_name)
+      : histogram_tester_(histogram_tester), metrics_name_(metrics_name) {}
+
+  MetricsWaiter(const MetricsWaiter&) = delete;
+  MetricsWaiter& operator=(const MetricsWaiter&) = delete;
+
+  ~MetricsWaiter() = default;
+
+  void Wait() {
+    while (histogram_tester_->GetTotalSum(metrics_name_) == 0) {
+      GiveItSomeTime(base::Milliseconds(16));
+    }
+  }
+
+ private:
+  base::raw_ptr<base::HistogramTester> histogram_tester_;
+  const std::string metrics_name_;
+};
+
+}  // namespace
+
+// Test fixture for the LoginUnlockThroughputRecorder class.
+class LoginUnlockThroughputRecorderTestBase
+    : public LoginTestBase,
+      public testing::WithParamInterface<bool> {
+ public:
+  LoginUnlockThroughputRecorderTestBase() = default;
+
+  LoginUnlockThroughputRecorderTestBase(
+      const LoginUnlockThroughputRecorderTestBase&) = delete;
+  LoginUnlockThroughputRecorderTestBase& operator=(
+      const LoginUnlockThroughputRecorderTestBase&) = delete;
+
+  ~LoginUnlockThroughputRecorderTestBase() override = default;
+
+  // LoginTestBase:
+  void SetUp() override {
+    LoginTestBase::SetUp();
+    histogram_tester_ = std::make_unique<base::HistogramTester>();
+  }
+
+  void LoginOwner() {
+    CreateUserSessions(1);
+    LoginState::Get()->SetLoggedInState(
+        LoginState::LOGGED_IN_ACTIVE,
+        chromeos::LoginState::LOGGED_IN_USER_OWNER);
+  }
+
+  void LockScreenAndAnimate() {
+    GetSessionControllerClient()->LockScreen();
+    RunSimpleAnimation();
+  }
+
+  void UnlockScreenAndAnimate() {
+    GetSessionControllerClient()->UnlockScreen();
+    RunSimpleAnimation();
+  }
+
+  void AddScheduledRestoreBrowserWindows(const std::vector<int>& ids,
+                                         bool is_lacros) {
+    for (int n : ids) {
+      throughput_recorder()->AddScheduledRestoreWindow(
+          n, is_lacros ? app_constants::kLacrosAppId : "",
+          LoginUnlockThroughputRecorder::kBrowser);
+    }
+  }
+
+  void AddScheduledRestoreNonBrowserWindows(const std::vector<int>& ids) {
+    for (int n : ids) {
+      throughput_recorder()->AddScheduledRestoreWindow(
+          n, base::StringPrintf("some_app%d", n),
+          LoginUnlockThroughputRecorder::kBrowser);
+    }
+  }
+
+  void RestoredWindowsCreated(const std::vector<int>& ids) {
+    for (int n : ids) {
+      throughput_recorder()->OnRestoredWindowCreated(n);
+    }
+  }
+
+  void RestoredWindowsShown(const std::vector<int>& ids) {
+    ui::Compositor* compositor =
+        Shell::GetPrimaryRootWindow()->GetHost()->compositor();
+    for (int n : ids) {
+      throughput_recorder()->OnBeforeRestoredWindowShown(n, compositor);
+    }
+  }
+
+  void RestoredWindowsPresented(const std::vector<int>& ids) {
+    for (int n : ids) {
+      throughput_recorder()->OnRestoredWindowPresented(n);
+    }
+  }
+
+ protected:
+  void RunSimpleAnimation() {
+    ui::Compositor* compositor =
+        Shell::GetPrimaryRootWindow()->GetHost()->compositor();
+    TestObserver observer(compositor);
+    BeginMainFrameWaiter(compositor).Wait();
+    FirstNonAnimatedFrameStartedWaiter(compositor).Wait();
+    ui::DrawWaiterForTest::WaitForCompositingEnded(compositor);
+  }
+
+  void EnableTabletMode(bool enable) {
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
+  }
+
+  LoginUnlockThroughputRecorder* throughput_recorder() {
+    return Shell::Get()->login_unlock_throughput_recorder();
+  }
+
+  bool IsThroughputRecorderBlocked() {
+    return throughput_recorder()
+        ->login_animation_throughput_reporter()
+        ->IsBlocked();
+  }
+
+  // Used to verify recorded data.
+  std::unique_ptr<base::HistogramTester> histogram_tester_;
+};
+
+using LoginUnlockThroughputRecorderLoginAnimationTest =
+    LoginUnlockThroughputRecorderTestBase;
+
+// Boolean parameter controls tablet mode.
+INSTANTIATE_TEST_SUITE_P(All,
+                         LoginUnlockThroughputRecorderLoginAnimationTest,
+                         testing::Bool());
+
+// Verifies that login animation metrics are reported correctly ignoring shelf
+// initialization.
+TEST_P(LoginUnlockThroughputRecorderLoginAnimationTest,
+       ReportLoginAnimationOnly) {
+  EnableTabletMode(GetParam());
+  const std::string metrics_name =
+      GetParam() ? kAshLoginAnimationDurationTabletMode
+                 : kAshLoginAnimationDurationClamshellMode;
+
+  LoginOwner();
+  RunSimpleAnimation();
+  GiveItSomeTime(base::Milliseconds(100));
+
+  // Should not report login histogram until shelf is initialized.
+  EXPECT_EQ(histogram_tester_.get()->GetTotalSum(metrics_name), 0);
+
+  // In this test case we ignore the shelf initialization. Pretend that it
+  // was done.
+  throughput_recorder()->ResetScopedThroughputReporterBlockerForTesting();
+  RunSimpleAnimation();
+
+  MetricsWaiter(histogram_tester_.get(),
+                GetParam() ? kAshLoginAnimationDurationTabletMode
+                           : kAshLoginAnimationDurationClamshellMode)
+      .Wait();
+}
+
+// Verifies that login animation metrics are reported correctly after shelf is
+// initialized.
+TEST_P(LoginUnlockThroughputRecorderLoginAnimationTest,
+       ReportLoginWithShelfInitialization) {
+  EnableTabletMode(GetParam());
+  const std::string metrics_name =
+      GetParam() ? kAshLoginAnimationDurationTabletMode
+                 : kAshLoginAnimationDurationClamshellMode;
+
+  LoginOwner();
+  GiveItSomeTime(base::Milliseconds(100));
+
+  // Should not report login histogram until shelf is initialized.
+  EXPECT_EQ(histogram_tester_.get()->GetTotalSum(metrics_name), 0);
+
+  TestShelfModel model;
+  model.InitializeIconList({1, 2, 3, 4, 5, 6});
+
+  // None of the expected shelf items have icons loaded.
+  throughput_recorder()->InitShelfIconList(&model);
+
+  RunSimpleAnimation();
+  GiveItSomeTime(base::Milliseconds(100));
+  EXPECT_TRUE(IsThroughputRecorderBlocked());
+
+  model.SetIconsLoadedFor({1, 2, 3});
+  throughput_recorder()->UpdateShelfIconList(&model);
+  EXPECT_TRUE(IsThroughputRecorderBlocked());
+
+  // Remove last shelf button.
+  model.InitializeIconList({1, 2, 3, 4, 5});
+  model.SetIconsLoadedFor({1, 2, 3});
+  throughput_recorder()->UpdateShelfIconList(&model);
+  EXPECT_TRUE(IsThroughputRecorderBlocked());
+
+  // Add extra buttons.
+  model.InitializeIconList({4, 5, 6, 7, 8, 9});
+  model.SetIconsLoadedFor({7, 8, 9});
+  // Only 4 and 5 are not loaded yet.
+  throughput_recorder()->UpdateShelfIconList(&model);
+  EXPECT_TRUE(IsThroughputRecorderBlocked());
+
+  model.SetIconsLoadedFor({4, 5});
+  // All buttons should have icons.
+  throughput_recorder()->UpdateShelfIconList(&model);
+  // All loaded icons should trigger login histograms.
+  EXPECT_FALSE(IsThroughputRecorderBlocked());
+  EXPECT_GT(histogram_tester_.get()->GetTotalSum(
+                "Ash.LoginSessionRestore.AllShelfIconsLoaded"),
+            0);
+
+  GiveItSomeTime(base::Milliseconds(100));
+  // Should not report login histogram until login animation starts.
+  EXPECT_EQ(histogram_tester_.get()->GetTotalSum(metrics_name), 0);
+  // Shelf metrics should be already reported. Did not specifically start shelf
+  // animations, but it should be reported immediately when there are no shelf
+  // animation.
+  EXPECT_GT(histogram_tester_.get()->GetTotalSum(
+                "Ash.LoginSessionRestore.ShelfLoginAnimationEnd"),
+            0);
+
+  // Start login animation. It should trigger metrics reporting.
+  RunSimpleAnimation();
+  MetricsWaiter(histogram_tester_.get(), metrics_name).Wait();
+}
+
+TEST_P(LoginUnlockThroughputRecorderLoginAnimationTest, ReportUnlock) {
+  LoginOwner();
+
+  EnableTabletMode(GetParam());
+
+  LockScreenAndAnimate();
+  UnlockScreenAndAnimate();
+
+  MetricsWaiter(histogram_tester_.get(),
+                GetParam() ? kAshUnlockAnimationDurationTabletMode
+                           : kAshUnlockAnimationDurationClamshellMode)
+      .Wait();
+}
+
+using LoginUnlockThroughputRecorderWindowRestoreTest =
+    LoginUnlockThroughputRecorderTestBase;
+
+// Boolean parameter controls lacros mode.
+INSTANTIATE_TEST_SUITE_P(All,
+                         LoginUnlockThroughputRecorderWindowRestoreTest,
+                         testing::Bool());
+
+// Verifies that window restore metrics are reported correctly.
+TEST_P(LoginUnlockThroughputRecorderWindowRestoreTest,
+       ReportWindowRestoreMetrics) {
+  const bool is_lacros = GetParam();
+
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
+
+  LoginOwner();
+  GiveItSomeTime(base::Milliseconds(100));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
+
+  AddScheduledRestoreBrowserWindows({1, 2, 3, 4, 5, 6}, is_lacros);
+  AddScheduledRestoreNonBrowserWindows({7, 8, 9, 10, 11, 12});
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
+
+  // The unexpected windows do not trigger the metrics.
+  RestoredWindowsCreated({21, 22, 23, 24, 25, 26});
+  RestoredWindowsShown({21, 22, 23, 24, 25, 26});
+  RestoredWindowsPresented({21, 22, 23, 24, 25, 26});
+  GiveItSomeTime(base::Milliseconds(100));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
+
+  // Window must go through all of the expected steps
+  // (Created->Shown->Presented). The non-created windows do not trigger
+  // metrics.
+  RestoredWindowsShown({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
+  RestoredWindowsPresented({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
+  GiveItSomeTime(base::Milliseconds(100));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
+
+  // Only wait for the expected browser windows: expected window 1 is missing.
+  RestoredWindowsCreated({2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
+  RestoredWindowsShown({2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
+  RestoredWindowsPresented({2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
+  GiveItSomeTime(base::Milliseconds(100));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
+
+  // Last window created.
+  RestoredWindowsCreated({1});
+  EXPECT_TRUE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
+  GiveItSomeTime(base::Milliseconds(100));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
+  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
+
+  RestoredWindowsShown({1});
+  EXPECT_TRUE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
+
+  RestoredWindowsPresented({1});
+  EXPECT_TRUE(histogram_tester_.get()->GetTotalSum(
+      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
+}
+
+}  // namespace ash
diff --git a/ash/projector/projector_annotation_tray.cc b/ash/projector/projector_annotation_tray.cc
index 0bf5efec..d73175e6 100644
--- a/ash/projector/projector_annotation_tray.cc
+++ b/ash/projector/projector_annotation_tray.cc
@@ -60,13 +60,13 @@
 enum ProjectorTool { kToolNone, kToolPen };
 
 ProjectorTool GetCurrentTool() {
-  auto* projector_controller = Shell::Get()->projector_controller();
-  // ProjectorController may not be available yet as the ProjectorAnnotationTray
+  auto* controller = Shell::Get()->projector_controller();
+  // ProjctorController may not be available yet as the ProjectorAnnotationTray
   // is created before it.
-  if (!projector_controller)
+  if (!controller)
     return kToolNone;
 
-  if (projector_controller->IsAnnotatorEnabled())
+  if (controller->IsAnnotatorEnabled())
     return kToolPen;
   return kToolNone;
 }
@@ -100,21 +100,6 @@
       image_view_(
           tray_container()->AddChildView(std::make_unique<views::ImageView>())),
       pen_view_(nullptr) {
-  SetPressedCallback(base::BindRepeating(
-      [](ProjectorAnnotationTray* projector_annotation_tray,
-         const ui::Event& event) {
-        if ((event.IsMouseEvent() &&
-             event.AsMouseEvent()->IsRightMouseButton()) ||
-            (event.IsGestureEvent() &&
-             event.AsGestureEvent()->details().type() ==
-                 ui::ET_GESTURE_LONG_PRESS)) {
-          projector_annotation_tray->ShowBubble();
-          return;
-        }
-
-        projector_annotation_tray->ToggleAnnotator();
-      },
-      base::Unretained(this)));
   image_view_->SetTooltipText(GetTooltip());
   image_view_->SetHorizontalAlignment(views::ImageView::Alignment::kCenter);
   image_view_->SetVerticalAlignment(views::ImageView::Alignment::kCenter);
@@ -126,6 +111,30 @@
 
 ProjectorAnnotationTray::~ProjectorAnnotationTray() = default;
 
+bool ProjectorAnnotationTray::PerformAction(const ui::Event& event) {
+  ToggleAnnotator();
+  return true;
+}
+
+void ProjectorAnnotationTray::OnMouseEvent(ui::MouseEvent* event) {
+  if (event->type() != ui::ET_MOUSE_PRESSED) {
+    return;
+  }
+  if (event->IsRightMouseButton()) {
+    ShowBubble();
+  } else if (event->IsLeftMouseButton()) {
+    ToggleAnnotator();
+  }
+}
+
+void ProjectorAnnotationTray::OnGestureEvent(ui::GestureEvent* event) {
+  if (event->details().type() == ui::ET_GESTURE_LONG_PRESS) {
+    ShowBubble();
+  } else if (event->details().type() == ui::ET_GESTURE_TAP) {
+    ToggleAnnotator();
+  }
+}
+
 void ProjectorAnnotationTray::ClickedOutsideBubble() {
   CloseBubble();
 }
@@ -279,18 +288,18 @@
 }
 
 void ProjectorAnnotationTray::EnableAnnotatorWithPenColor() {
-  auto* projector_controller = Shell::Get()->projector_controller();
-  DCHECK(projector_controller);
+  auto* controller = Shell::Get()->projector_controller();
+  DCHECK(controller);
   AnnotatorTool tool;
   tool.color = current_pen_color_;
-  projector_controller->SetAnnotatorTool(tool);
-  projector_controller->EnableAnnotatorTool();
+  controller->SetAnnotatorTool(tool);
+  controller->EnableAnnotatorTool();
 }
 
 void ProjectorAnnotationTray::DeactivateActiveTool() {
-  auto* projector_controller = Shell::Get()->projector_controller();
-  DCHECK(projector_controller);
-  projector_controller->ResetTools();
+  auto* controller = Shell::Get()->projector_controller();
+  DCHECK(controller);
+  controller->ResetTools();
 }
 
 void ProjectorAnnotationTray::UpdateIcon() {
diff --git a/ash/projector/projector_annotation_tray.h b/ash/projector/projector_annotation_tray.h
index f831d73..e11414e 100644
--- a/ash/projector/projector_annotation_tray.h
+++ b/ash/projector/projector_annotation_tray.h
@@ -5,24 +5,15 @@
 #ifndef ASH_PROJECTOR_PROJECTOR_ANNOTATION_TRAY_H_
 #define ASH_PROJECTOR_PROJECTOR_ANNOTATION_TRAY_H_
 
-#include <string>
-
 #include "ash/public/cpp/session/session_observer.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/system/tray/tray_background_view.h"
 #include "ash/system/tray/view_click_listener.h"
 #include "base/scoped_observation.h"
 
-namespace views {
-class ImageView;
-class Widget;
-}  // namespace views
-
 namespace ash {
 
 class HoverHighlightView;
-class Shelf;
-class TrayBubbleView;
 class TrayBubbleWrapper;
 
 // Pen colors.
@@ -43,6 +34,7 @@
   ~ProjectorAnnotationTray() override;
 
   // TrayBackgroundView:
+  bool PerformAction(const ui::Event& event) override;
   void ClickedOutsideBubble() override;
   std::u16string GetAccessibleNameForTray() override;
   void HandleLocaleChange() override;
@@ -51,6 +43,8 @@
   void ShowBubble() override;
   TrayBubbleView* GetBubbleView() override;
   views::Widget* GetBubbleWidget() const override;
+  void OnMouseEvent(ui::MouseEvent* event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
   void OnThemeChanged() override;
 
   // SessionObserver:
diff --git a/ash/public/cpp/app_list/app_list_config_provider_unittest.cc b/ash/public/cpp/app_list/app_list_config_provider_unittest.cc
index 9e54d7c..706fb7b 100644
--- a/ash/public/cpp/app_list/app_list_config_provider_unittest.cc
+++ b/ash/public/cpp/app_list/app_list_config_provider_unittest.cc
@@ -163,10 +163,6 @@
 
 // Tests GetConfigForType behavior.
 TEST_F(AppListConfigProviderTest, ConfigGetters) {
-  // The configs tested here are only used by ProductivityLauncher.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kProductivityLauncher);
-
   std::vector<AppListConfigType> test_cases = {AppListConfigType::kRegular,
                                                AppListConfigType::kDense};
   std::set<AppListConfigType> created_types;
@@ -206,60 +202,9 @@
   }
 }
 
-// Tests GetConfigForType behavior for pre-productivity launcher configs.
-TEST_F(AppListConfigProviderTest, LegacyConfigGetters) {
-  // The configs tested here are not used by ProductivityLauncher. This test
-  // can be deleted when ProductivityLauncher is the default.
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(features::kProductivityLauncher);
-
-  std::vector<AppListConfigType> test_cases = {AppListConfigType::kSmall,
-                                               AppListConfigType::kMedium,
-                                               AppListConfigType::kLarge};
-  std::set<AppListConfigType> created_types;
-  for (const auto& config_type : test_cases) {
-    SCOPED_TRACE(static_cast<int>(config_type));
-
-    // Calling GetConfigForType with false |can_create| will not create a new
-    // config.
-    EXPECT_FALSE(AppListConfigProvider::Get().GetConfigForType(
-        config_type, false /*can_create*/));
-    EXPECT_EQ(std::vector<AppListConfigType>(),
-              registry_observer_.created_types());
-
-    // Calling GetConfigForType with true |can_create| will create a new config
-    // (if not previously created), and it will notify observers a config was
-    // created.
-    const AppListConfig* config = AppListConfigProvider::Get().GetConfigForType(
-        config_type, true /*can_create*/);
-    ASSERT_TRUE(config);
-    created_types.insert(config_type);
-    EXPECT_EQ(config_type, config->type());
-    const std::vector<AppListConfigType> expected_created_types = {config_type};
-    EXPECT_EQ(expected_created_types, registry_observer_.created_types());
-
-    // Subsequent calls to GetConfigForType will return previously created
-    // config, and will not notify observers of config creation.
-    EXPECT_EQ(config, AppListConfigProvider::Get().GetConfigForType(config_type,
-                                                                    false));
-    EXPECT_EQ(config,
-              AppListConfigProvider::Get().GetConfigForType(config_type, true));
-    EXPECT_EQ(expected_created_types, registry_observer_.created_types());
-
-    EXPECT_EQ(created_types,
-              AppListConfigProvider::Get().GetAvailableConfigTypes());
-
-    registry_observer_.ClearCreatedTypes();
-  }
-}
-
 // Tests calling CreateForFullscreenAppList creates the appropriate app list
 // configuration depending on display size.
 TEST_F(AppListConfigProviderTest, CreateConfigByDisplayWorkArea) {
-  // The configs tested here are only used by ProductivityLauncher.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kProductivityLauncher);
-
   // NOTE: The `available_size` are arbitrary values large enough so the
   // returned app list config does not get scaled down (i.e. large enough so
   // they can fit an apps grid with default sized-items).
@@ -319,80 +264,10 @@
   }
 }
 
-// Tests calling CreateForFullscreenAppList creates the appropriate app list
-// configuration depending on display size with productivity launcher disabled.
-TEST_F(AppListConfigProviderTest, CreateLegacyConfigByDisplayWorkArea) {
-  // The configs tested here are not used by ProductivityLauncher. This test
-  // can be deleted when ProductivityLauncher is the default.
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(features::kProductivityLauncher);
-
-  // NOTE: The `available_size` are arbitrary values large enough so the
-  // returned app list config does not get scaled down (i.e. large enough so
-  // they can fit an apps grid with default sized-items).
-  const struct TestCase {
-    gfx::Size work_area_size;
-    gfx::Size available_size;
-    AppListConfigType config_type;
-  } test_cases[] = {
-      {gfx::Size(900, 500), gfx::Size(788, 321), AppListConfigType::kSmall},
-      {gfx::Size(500, 900), gfx::Size(388, 704), AppListConfigType::kSmall},
-      {gfx::Size(960, 600), gfx::Size(848, 412), AppListConfigType::kMedium},
-      {gfx::Size(1100, 700), gfx::Size(988, 504), AppListConfigType::kMedium},
-      {gfx::Size(600, 960), gfx::Size(488, 764), AppListConfigType::kMedium},
-      {gfx::Size(700, 1100), gfx::Size(588, 904), AppListConfigType::kMedium},
-      {gfx::Size(1200, 768), gfx::Size(1088, 572), AppListConfigType::kLarge},
-      {gfx::Size(768, 1200), gfx::Size(656, 1004), AppListConfigType::kLarge}};
-
-  for (const auto& test_case : test_cases) {
-    SCOPED_TRACE(::testing::Message()
-                 << "Size: " << test_case.work_area_size.ToString()
-                 << ", expected config type: "
-                 << static_cast<int>(test_case.config_type));
-
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            test_case.work_area_size,
-            GetPreferredGridRowsForWorkArea(test_case.work_area_size),
-            GetPreferredGridColumnsForWorkArea(test_case.work_area_size),
-            test_case.available_size, nullptr);
-
-    ASSERT_TRUE(config.get());
-    EXPECT_EQ(test_case.config_type, config->type());
-    EXPECT_EQ(1, config->scale_x());
-    EXPECT_EQ(1, config->scale_y());
-    SanityCheckGridTileDimensions(config.get(), 0);
-
-    // Verify that AppListConfigProvider now provides the created config type.
-    EXPECT_TRUE(AppListConfigProvider::Get().GetConfigForType(
-        test_case.config_type, false));
-
-    // NOTE: While a specific config might be expected in more than one test
-    // case, it should only get reported as created once - given that the
-    // observed created types are not cleared for |registry_observer_| between
-    // test cases, the "observed" count for |test_case.config_type| should
-    // always be 1.
-    EXPECT_EQ(1, base::STLCount(registry_observer_.created_types(),
-                                test_case.config_type));
-
-    // Verify CreateForAppListWidget returns nullptr if the created config would
-    // be the same as |config|.
-    EXPECT_FALSE(AppListConfigProvider::Get().CreateForFullscreenAppList(
-        test_case.work_area_size,
-        GetPreferredGridRowsForWorkArea(test_case.work_area_size),
-        GetPreferredGridColumnsForWorkArea(test_case.work_area_size),
-        test_case.available_size, config.get()));
-  }
-}
-
 // Tests whether CreateForAppListWidget returns a new config depending on the
 // value of the old config passed to the method.
 TEST_F(AppListConfigProviderTest,
        CreateConfigByDisplayWorkAreaWithNonNullConfig) {
-  // The configs tested here are only used by ProductivityLauncher.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kProductivityLauncher);
-
   // Create initial configuration.
   gfx::Size work_area(1200, 768);
   gfx::Size available_size(1088, 572);
@@ -425,53 +300,8 @@
   EXPECT_EQ(AppListConfigType::kDense, updated_config->type());
 }
 
-// Tests whether CreateForAppListWidget returns a new config depending on the
-// value of the old config passed to the method.
-TEST_F(AppListConfigProviderTest,
-       CreateLegacyConfigByDisplayWorkAreaWithNonNullConfig) {
-  // The configs tested here are not used by ProductivityLauncher. This test
-  // can be deleted when ProductivityLauncher is the default.
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(features::kProductivityLauncher);
-
-  // Create initial configuration.
-  gfx::Size work_area(1200, 768);
-  gfx::Size available_size(1088, 572);
-  std::unique_ptr<AppListConfig> config =
-      AppListConfigProvider::Get().CreateForFullscreenAppList(
-          work_area, GetPreferredGridRowsForWorkArea(work_area),
-          GetPreferredGridColumnsForWorkArea(work_area), available_size,
-          nullptr);
-  ASSERT_TRUE(config);
-  EXPECT_EQ(AppListConfigType::kLarge, config->type());
-
-  // Verify CreateForAppListWidget returns nullptr if the created config would
-  // be the same as `config`.
-  work_area = gfx::Size(768, 1200);
-  available_size = gfx::Size(656, 1004);
-  EXPECT_FALSE(AppListConfigProvider::Get().CreateForFullscreenAppList(
-      work_area, GetPreferredGridRowsForWorkArea(work_area),
-      GetPreferredGridColumnsForWorkArea(work_area), available_size,
-      config.get()));
-
-  // Create different config.
-  work_area = gfx::Size(960, 600);
-  available_size = gfx::Size(848, 412);
-  std::unique_ptr<AppListConfig> updated_config =
-      AppListConfigProvider::Get().CreateForFullscreenAppList(
-          work_area, GetPreferredGridRowsForWorkArea(work_area),
-          GetPreferredGridColumnsForWorkArea(work_area), available_size,
-          config.get());
-  ASSERT_TRUE(updated_config);
-  EXPECT_EQ(AppListConfigType::kMedium, updated_config->type());
-}
-
 TEST_F(AppListConfigProviderTest,
        CreateScaledConfigByDisplayWorkAreaRegularLandscape) {
-  // The configs tested here are only used by ProductivityLauncher.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kProductivityLauncher);
-
   // The available grid size fits the grid - created config is not scaled.
   const gfx::Size work_area(1200, 768);
   const gfx::Size initial_available_size(1088, 572);
@@ -533,10 +363,6 @@
 
 TEST_F(AppListConfigProviderTest,
        CreateScaledConfigByDisplayWorkAreaDenseLandscape) {
-  // The configs tested here are only used by ProductivityLauncher.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kProductivityLauncher);
-
   // The available grid size fits the grid - created config is not scaled.
   const gfx::Size work_area(960, 600);
   const gfx::Size initial_available_size(848, 412);
@@ -596,202 +422,7 @@
 }
 
 TEST_F(AppListConfigProviderTest,
-       CreateScaledConfigByDisplayWorkAreaLargeLandscape) {
-  // The configs tested here are not used by ProductivityLauncher. This test
-  // can be deleted when ProductivityLauncher is the default.
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(features::kProductivityLauncher);
-
-  // The available grid size fits the grid - created config is not scaled.
-  const gfx::Size work_area(1200, 768);
-  const gfx::Size initial_available_size(1088, 572);
-  const int preferred_rows = GetPreferredGridRowsForWorkArea(work_area);
-  const int preferred_columns = GetPreferredGridColumnsForWorkArea(work_area);
-  std::unique_ptr<AppListConfig> base_config =
-      AppListConfigProvider::Get().CreateForFullscreenAppList(
-          work_area, preferred_rows, preferred_columns, initial_available_size,
-          nullptr);
-
-  ASSERT_TRUE(base_config.get());
-  ASSERT_EQ(AppListConfigType::kLarge, base_config->type());
-  ASSERT_EQ(1, base_config->scale_x());
-  ASSERT_EQ(1, base_config->scale_y());
-
-  const int kMinGridWidth = base_config->grid_tile_width() * preferred_columns;
-  const int kMinGridHeight = base_config->grid_tile_height() * preferred_rows;
-
-  {
-    SCOPED_TRACE("Horizontal scaling");
-
-    // Reduce available width so the grid scales down horizontally.
-    const gfx::Size available_size(480, initial_available_size.height());
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 480.0f / kMinGridWidth, 1);
-  }
-
-  {
-    SCOPED_TRACE("Vertical scaling");
-
-    // Reduce available height so the grid scales down vertically.
-    const gfx::Size available_size(initial_available_size.width(), 400);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 1, 400.0f / kMinGridHeight);
-  }
-
-  {
-    SCOPED_TRACE("Horizontal and vertical scaling");
-
-    // Reduce both available width and height so the grid scales down
-    // horizontally and vertically.
-    const gfx::Size available_size(480, 400);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 480.0f / kMinGridWidth,
-                       400.0f / kMinGridHeight);
-  }
-}
-
-TEST_F(AppListConfigProviderTest,
-       CreateScaledConfigByDisplayWorkAreaMediumLandscape) {
-  // The configs tested here are not used by ProductivityLauncher. This test
-  // can be deleted when ProductivityLauncher is the default.
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(features::kProductivityLauncher);
-
-  // The available grid size fits the grid - created config is not scaled.
-  const gfx::Size work_area(960, 600);
-  const gfx::Size initial_available_size(848, 412);
-  const int preferred_rows = GetPreferredGridRowsForWorkArea(work_area);
-  const int preferred_columns = GetPreferredGridColumnsForWorkArea(work_area);
-  std::unique_ptr<AppListConfig> base_config =
-      AppListConfigProvider::Get().CreateForFullscreenAppList(
-          work_area, preferred_rows, preferred_columns, initial_available_size,
-          nullptr);
-  ASSERT_TRUE(base_config.get());
-  ASSERT_EQ(AppListConfigType::kMedium, base_config->type());
-  ASSERT_EQ(1, base_config->scale_x());
-  ASSERT_EQ(1, base_config->scale_y());
-
-  const int kMinGridWidth = base_config->grid_tile_width() * preferred_columns;
-  const int kMinGridHeight = base_config->grid_tile_height() * preferred_rows;
-
-  {
-    SCOPED_TRACE("Horizontal scaling");
-
-    // Reduce available width so the grid scales down horizontally.
-    const gfx::Size available_size(400, initial_available_size.height());
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 400.0f / kMinGridWidth, 1);
-  }
-
-  {
-    SCOPED_TRACE("Vertical scaling");
-
-    // Reduce available height so the grid scales down vertically.
-    const gfx::Size available_size(initial_available_size.width(), 300);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 1, 300.0f / kMinGridHeight);
-  }
-
-  {
-    SCOPED_TRACE("Horizontal and vertical scaling");
-
-    // Reduce both available width height so the grid scales down horizontally
-    // and vertically.
-    const gfx::Size available_size(400, 300);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 400.0f / kMinGridWidth,
-                       300.0f / kMinGridHeight);
-  }
-}
-
-TEST_F(AppListConfigProviderTest,
-       CreateScaledConfigByDisplayWorkAreaSmallLandscape) {
-  // The configs tested here are not used by ProductivityLauncher. This test
-  // can be deleted when ProductivityLauncher is the default.
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(features::kProductivityLauncher);
-
-  // The available grid size fits the grid - created config is not scaled.
-  const gfx::Size work_area(900, 500);
-  const gfx::Size initial_available_size(788, 321);
-  const int preferred_rows = GetPreferredGridRowsForWorkArea(work_area);
-  const int preferred_columns = GetPreferredGridColumnsForWorkArea(work_area);
-  std::unique_ptr<AppListConfig> base_config =
-      AppListConfigProvider::Get().CreateForFullscreenAppList(
-          work_area, preferred_rows, preferred_columns, initial_available_size,
-          nullptr);
-
-  ASSERT_TRUE(base_config.get());
-  ASSERT_EQ(AppListConfigType::kSmall, base_config->type());
-  ASSERT_EQ(1, base_config->scale_x());
-  ASSERT_EQ(1, base_config->scale_y());
-
-  const int kMinGridWidth = base_config->grid_tile_width() * preferred_columns;
-  const int kMinGridHeight = base_config->grid_tile_height() * preferred_rows;
-
-  {
-    SCOPED_TRACE("Horizontal scaling");
-
-    // Reduce available width so the grid scales down horizontally.
-    const gfx::Size available_size(340, initial_available_size.height());
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 340.0f / kMinGridWidth, 1);
-  }
-
-  {
-    SCOPED_TRACE("Vertical scaling");
-
-    // Reduce available height so the grid scales down vertically.
-    const gfx::Size available_size(initial_available_size.width(), 260);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 1, 260.0f / kMinGridHeight);
-  }
-
-  {
-    SCOPED_TRACE("Horizontal and vertical scaling");
-
-    // Reduce both available width height so the grid scales down horizontally
-    // and vertically.
-    const gfx::Size available_size(340, 260);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 340.0f / kMinGridWidth,
-                       260.0f / kMinGridHeight);
-  }
-}
-
-TEST_F(AppListConfigProviderTest,
        CreateScaledConfigByDisplayWorkAreaRegularPortrait) {
-  // The configs tested here are only used by ProductivityLauncher.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kProductivityLauncher);
-
   // The available grid size fits the grid - created config is not scaled.
   const gfx::Size work_area(768, 1200);
   const gfx::Size initial_available_size(656, 1004);
@@ -853,10 +484,6 @@
 
 TEST_F(AppListConfigProviderTest,
        CreateScaledConfigByDisplayWorkAreaDensePortrait) {
-  // The configs tested here are only used by ProductivityLauncher.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kProductivityLauncher);
-
   // The available grid size fits the grid - created config is not scaled.
   const gfx::Size work_area(600, 960);
   const gfx::Size initial_available_size(488, 764);
@@ -916,196 +543,4 @@
   }
 }
 
-TEST_F(AppListConfigProviderTest,
-       CreateScaledConfigByDisplayWorkAreaLargePortrait) {
-  // The configs tested here are not used by ProductivityLauncher. This test
-  // can be deleted when ProductivityLauncher is the default.
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(features::kProductivityLauncher);
-
-  // The available grid size fits the grid - created config is not scaled.
-  const gfx::Size work_area(768, 1200);
-  const gfx::Size initial_available_size(656, 1004);
-  const int preferred_rows = GetPreferredGridRowsForWorkArea(work_area);
-  const int preferred_columns = GetPreferredGridColumnsForWorkArea(work_area);
-  std::unique_ptr<AppListConfig> base_config =
-      AppListConfigProvider::Get().CreateForFullscreenAppList(
-          work_area, preferred_rows, preferred_columns, initial_available_size,
-          nullptr);
-
-  ASSERT_TRUE(base_config.get());
-  ASSERT_EQ(AppListConfigType::kLarge, base_config->type());
-  ASSERT_EQ(1, base_config->scale_x());
-  ASSERT_EQ(1, base_config->scale_y());
-
-  const int kMinGridWidth = base_config->grid_tile_width() * preferred_columns;
-  const int kMinGridHeight = base_config->grid_tile_height() * preferred_rows;
-
-  {
-    SCOPED_TRACE("Horizontal scaling");
-
-    // Reduce available width so the grid scales down horizontally.
-    const gfx::Size available_size(440, initial_available_size.height());
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 440.0f / kMinGridWidth, 1);
-  }
-
-  {
-    SCOPED_TRACE("Vertical scaling");
-
-    // Reduce available height so the grid scales down vertically.
-    const gfx::Size available_size(initial_available_size.width(), 532);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 1, 532.0f / kMinGridHeight);
-  }
-
-  {
-    SCOPED_TRACE("Horizontal and vertical scaling");
-
-    // Reduce both available width height so the grid scales down horizontally
-    // and vertically.
-    const gfx::Size available_size(440, 532);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 440.0f / kMinGridWidth,
-                       532.0f / kMinGridHeight);
-  }
-}
-
-TEST_F(AppListConfigProviderTest,
-       CreateScaledConfigByDisplayWorkAreaMediumPortrait) {
-  // The configs tested here are not used by ProductivityLauncher. This test
-  // can be deleted when ProductivityLauncher is the default.
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(features::kProductivityLauncher);
-
-  // The available grid size fits the grid - created config is not scaled.
-  const gfx::Size work_area(600, 960);
-  const gfx::Size initial_available_size(488, 764);
-  const int preferred_rows = GetPreferredGridRowsForWorkArea(work_area);
-  const int preferred_columns = GetPreferredGridColumnsForWorkArea(work_area);
-  std::unique_ptr<AppListConfig> base_config =
-      AppListConfigProvider::Get().CreateForFullscreenAppList(
-          work_area, preferred_rows, preferred_columns, initial_available_size,
-          nullptr);
-
-  ASSERT_TRUE(base_config.get());
-  ASSERT_EQ(AppListConfigType::kMedium, base_config->type());
-  ASSERT_EQ(1, base_config->scale_x());
-  ASSERT_EQ(1, base_config->scale_y());
-
-  const int kMinGridWidth = base_config->grid_tile_width() * preferred_columns;
-  const int kMinGridHeight = base_config->grid_tile_height() * preferred_rows;
-
-  {
-    SCOPED_TRACE("Horizontal scaling");
-
-    // Reduce available width so the grid scales down horizontally.
-    const gfx::Size available_size(300, initial_available_size.height());
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 300.0f / kMinGridWidth, 1);
-  }
-
-  {
-    SCOPED_TRACE("Vertical scaling");
-
-    // Reduce available height so the grid scales down vertically.
-    const gfx::Size available_size(initial_available_size.width(), 360);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 1, 360.0f / kMinGridHeight);
-  }
-
-  {
-    SCOPED_TRACE("Horizontal and vertical scaling");
-
-    // Reduce both available width height so the grid scales down horizontally
-    // and vertically.
-    const gfx::Size available_size(300, 360);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 300.0f / kMinGridWidth,
-                       360.0f / kMinGridHeight);
-  }
-}
-
-TEST_F(AppListConfigProviderTest,
-       CreateScaledConfigByDisplayWorkAreaSmallPortrait) {
-  // The configs tested here are not used by ProductivityLauncher. This test
-  // can be deleted when ProductivityLauncher is the default.
-  base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(features::kProductivityLauncher);
-
-  // The available grid size fits the grid - created config is not scaled.
-  const gfx::Size work_area(500, 900);
-  const gfx::Size initial_available_size(388, 704);
-  const int preferred_rows = GetPreferredGridRowsForWorkArea(work_area);
-  const int preferred_columns = GetPreferredGridColumnsForWorkArea(work_area);
-  std::unique_ptr<AppListConfig> base_config =
-      AppListConfigProvider::Get().CreateForFullscreenAppList(
-          work_area, preferred_rows, preferred_columns, initial_available_size,
-          nullptr);
-
-  ASSERT_TRUE(base_config.get());
-  ASSERT_EQ(AppListConfigType::kSmall, base_config->type());
-  ASSERT_EQ(1, base_config->scale_x());
-  ASSERT_EQ(1, base_config->scale_y());
-
-  const int kMinGridWidth = base_config->grid_tile_width() * preferred_columns;
-  const int kMinGridHeight = base_config->grid_tile_height() * preferred_rows;
-
-  {
-    SCOPED_TRACE("Horizontal scaling");
-
-    // Reduce available width so the grid scales down horizontally.
-    const gfx::Size available_size(240, initial_available_size.height());
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 240.0f / kMinGridWidth, 1);
-  }
-
-  {
-    SCOPED_TRACE("Vertical scaling");
-
-    // Reduce available height so the grid scales down vertically.
-    const gfx::Size available_size(initial_available_size.width(), 300);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 1, 300.0f / kMinGridHeight);
-  }
-
-  {
-    SCOPED_TRACE("Horizontal and vertical scaling");
-
-    // Reduce both available width height so the grid scales down horizontally
-    // and vertically.
-    const gfx::Size available_size(240, 300);
-    std::unique_ptr<AppListConfig> config =
-        AppListConfigProvider::Get().CreateForFullscreenAppList(
-            work_area, preferred_rows, preferred_columns, available_size,
-            nullptr);
-    VerifyScaledConfig(*base_config, config.get(), 240.0f / kMinGridWidth,
-                       300.0f / kMinGridHeight);
-  }
-}
-
 }  // namespace ash
diff --git a/ash/public/cpp/shelf_prefs.cc b/ash/public/cpp/shelf_prefs.cc
index 025dab3..b42f4012 100644
--- a/ash/public/cpp/shelf_prefs.cc
+++ b/ash/public/cpp/shelf_prefs.cc
@@ -6,7 +6,10 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
+#include "ash/public/cpp/tablet_mode.h"
+#include "base/feature_list.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "components/prefs/pref_service.h"
@@ -84,33 +87,6 @@
   return default_string ? *default_string : std::string();
 }
 
-// Sets the preference value for the display with the given |display_id|.
-void SetPerDisplayPref(PrefService* prefs,
-                       int64_t display_id,
-                       const char* pref_key,
-                       const std::string& value) {
-  if (display_id == display::kInvalidDisplayId)
-    return;
-
-  // Avoid ScopedDictPrefUpdate's notifications for read but unmodified prefs.
-  const base::Value::Dict& current_shelf_prefs =
-      prefs->GetDict(prefs::kShelfPreferences);
-  std::string display_key = base::NumberToString(display_id);
-  const base::Value::Dict* current_display_prefs =
-      current_shelf_prefs.FindDict(display_key);
-  if (current_display_prefs) {
-    const std::string* current_value =
-        current_display_prefs->FindStringByDottedPath(pref_key);
-    if (current_value && *current_value == value)
-      return;
-  }
-
-  ScopedDictPrefUpdate update(prefs, prefs::kShelfPreferences);
-  base::Value::Dict& shelf_prefs = update.Get();
-  base::Value::Dict* display_prefs_weak = shelf_prefs.EnsureDict(display_key);
-  display_prefs_weak->Set(pref_key, value);
-}
-
 ShelfAlignment AlignmentFromPref(const std::string& value) {
   if (value == kShelfAlignmentLeft)
     return ShelfAlignment::kLeft;
@@ -165,14 +141,51 @@
 
 }  // namespace
 
+void SetPerDisplayShelfPref(PrefService* prefs,
+                            int64_t display_id,
+                            const char* pref_key,
+                            const std::string& value) {
+  if (display_id == display::kInvalidDisplayId)
+    return;
+
+  // Avoid ScopedDictPrefUpdate's notifications for read but unmodified prefs.
+  const base::Value::Dict& current_shelf_prefs =
+      prefs->GetDict(prefs::kShelfPreferences);
+  std::string display_key = base::NumberToString(display_id);
+  const base::Value::Dict* current_display_prefs =
+      current_shelf_prefs.FindDict(display_key);
+  if (current_display_prefs) {
+    const std::string* current_value =
+        current_display_prefs->FindStringByDottedPath(pref_key);
+    if (current_value && *current_value == value)
+      return;
+  }
+
+  ScopedDictPrefUpdate update(prefs, prefs::kShelfPreferences);
+  base::Value::Dict& shelf_prefs = update.Get();
+  base::Value::Dict* display_prefs_weak = shelf_prefs.EnsureDict(display_key);
+  display_prefs_weak->Set(pref_key, value);
+}
+
 ShelfAutoHideBehavior GetShelfAutoHideBehaviorPref(PrefService* prefs,
                                                    int64_t display_id) {
   DCHECK_NE(display_id, display::kInvalidDisplayId);
 
+  if (!base::FeatureList::IsEnabled(features::kShelfAutoHideSeparation)) {
+    // See comment in |kShelfAlignment| as to why we consider two prefs.
+    return AutoHideBehaviorFromPref(
+        GetPerDisplayPref(prefs, display_id, prefs::kShelfAutoHideBehaviorLocal,
+                          prefs::kShelfAutoHideBehavior));
+  }
+
+  const bool is_in_tablet_mode = TabletMode::Get()->InTabletMode();
   // See comment in |kShelfAlignment| as to why we consider two prefs.
-  return AutoHideBehaviorFromPref(
-      GetPerDisplayPref(prefs, display_id, prefs::kShelfAutoHideBehaviorLocal,
-                        prefs::kShelfAutoHideBehavior));
+  return AutoHideBehaviorFromPref(GetPerDisplayPref(
+      prefs, display_id,
+      is_in_tablet_mode ? prefs::kShelfAutoHideTabletModeBehaviorLocal
+                        : prefs::kShelfAutoHideBehaviorLocal,
+      is_in_tablet_mode ? prefs::kShelfAutoHideTabletModeBehavior
+                        : prefs::kShelfAutoHideBehavior));
 }
 
 void SetShelfAutoHideBehaviorPref(PrefService* prefs,
@@ -184,11 +197,32 @@
   if (!value)
     return;
 
-  SetPerDisplayPref(prefs, display_id, prefs::kShelfAutoHideBehavior, value);
+  if (!base::FeatureList::IsEnabled(features::kShelfAutoHideSeparation)) {
+    SetPerDisplayShelfPref(prefs, display_id, prefs::kShelfAutoHideBehavior,
+                           value);
+    if (display_id == display::Screen::GetScreen()->GetPrimaryDisplay().id()) {
+      // See comment in |kShelfAlignment| about why we have two prefs here.
+      prefs->SetString(prefs::kShelfAutoHideBehaviorLocal, value);
+      prefs->SetString(prefs::kShelfAutoHideBehavior, value);
+    }
+    return;
+  }
+
+  const bool is_in_tablet_mode = TabletMode::Get()->InTabletMode();
+  SetPerDisplayShelfPref(prefs, display_id,
+                         is_in_tablet_mode
+                             ? prefs::kShelfAutoHideTabletModeBehavior
+                             : prefs::kShelfAutoHideBehavior,
+                         value);
   if (display_id == display::Screen::GetScreen()->GetPrimaryDisplay().id()) {
     // See comment in |kShelfAlignment| about why we have two prefs here.
-    prefs->SetString(prefs::kShelfAutoHideBehaviorLocal, value);
-    prefs->SetString(prefs::kShelfAutoHideBehavior, value);
+    prefs->SetString(is_in_tablet_mode
+                         ? prefs::kShelfAutoHideTabletModeBehaviorLocal
+                         : prefs::kShelfAutoHideBehaviorLocal,
+                     value);
+    prefs->SetString(is_in_tablet_mode ? prefs::kShelfAutoHideTabletModeBehavior
+                                       : prefs::kShelfAutoHideBehavior,
+                     value);
   }
 }
 
@@ -209,7 +243,7 @@
   if (!value)
     return;
 
-  SetPerDisplayPref(prefs, display_id, prefs::kShelfAlignment, value);
+  SetPerDisplayShelfPref(prefs, display_id, prefs::kShelfAlignment, value);
   if (display_id == display::Screen::GetScreen()->GetPrimaryDisplay().id()) {
     // See comment in |kShelfAlignment| as to why we consider two prefs.
     prefs->SetString(prefs::kShelfAlignmentLocal, value);
diff --git a/ash/public/cpp/shelf_prefs.h b/ash/public/cpp/shelf_prefs.h
index 730eac2..280797d8 100644
--- a/ash/public/cpp/shelf_prefs.h
+++ b/ash/public/cpp/shelf_prefs.h
@@ -21,6 +21,12 @@
 ASH_PUBLIC_EXPORT extern const char kShelfAlignmentLeft[];
 ASH_PUBLIC_EXPORT extern const char kShelfAlignmentRight[];
 
+// Sets the shelf preference value for the display with the given |display_id|.
+ASH_PUBLIC_EXPORT void SetPerDisplayShelfPref(PrefService* prefs,
+                                              int64_t display_id,
+                                              const char* pref_key,
+                                              const std::string& value);
+
 // Get the shelf auto hide behavior preference for a particular display.
 ASH_PUBLIC_EXPORT ShelfAutoHideBehavior
 GetShelfAutoHideBehaviorPref(PrefService* prefs, int64_t display_id);
diff --git a/ash/public/cpp/test/test_system_tray_client.cc b/ash/public/cpp/test/test_system_tray_client.cc
index 54659b4..a4d17bc 100644
--- a/ash/public/cpp/test/test_system_tray_client.cc
+++ b/ash/public/cpp/test/test_system_tray_client.cc
@@ -122,9 +122,13 @@
   show_calendar_event_count_++;
 }
 
-void TestSystemTrayClient::ShowChannelInfoAdditionalDetails() {}
+void TestSystemTrayClient::ShowChannelInfoAdditionalDetails() {
+  ++show_channel_info_additional_details_count_;
+}
 
-void TestSystemTrayClient::ShowChannelInfoGiveFeedback() {}
+void TestSystemTrayClient::ShowChannelInfoGiveFeedback() {
+  ++show_channel_info_give_feedback_count_;
+}
 
 bool TestSystemTrayClient::IsUserFeedbackEnabled() {
   return user_feedback_enabled_;
diff --git a/ash/public/cpp/test/test_system_tray_client.h b/ash/public/cpp/test/test_system_tray_client.h
index 0938320..88bd6c1 100644
--- a/ash/public/cpp/test/test_system_tray_client.h
+++ b/ash/public/cpp/test/test_system_tray_client.h
@@ -122,6 +122,14 @@
     return last_network_settings_network_id_;
   }
 
+  int show_channel_info_additional_details_count() const {
+    return show_channel_info_additional_details_count_;
+  }
+
+  int show_channel_info_give_feedback_count() const {
+    return show_channel_info_give_feedback_count_;
+  }
+
   void set_user_feedback_enabled(bool user_feedback_enabled) {
     user_feedback_enabled_ = user_feedback_enabled;
   }
@@ -142,6 +150,8 @@
   std::string last_bluetooth_settings_device_id_;
   std::string last_network_settings_network_id_;
   std::string last_network_type_;
+  int show_channel_info_additional_details_count_ = 0;
+  int show_channel_info_give_feedback_count_ = 0;
   bool user_feedback_enabled_ = false;
 };
 
diff --git a/ash/quick_pair/common/fast_pair/fast_pair_metrics.cc b/ash/quick_pair/common/fast_pair/fast_pair_metrics.cc
index 55979294..826a998 100644
--- a/ash/quick_pair/common/fast_pair/fast_pair_metrics.cc
+++ b/ash/quick_pair/common/fast_pair/fast_pair_metrics.cc
@@ -17,6 +17,55 @@
 const char kInvalidUUIDString[] = "Invalid UUID";
 const char kSocketNotListeningString[] = "Socket is not listening.";
 
+// Top 10 Popular peripherals and first party devices. These device
+// model names should be kept in sync with the FastPairTrackedModelID
+// enum in src/tools/metrics/histograms/enums.xml.
+const char kPopularPeripheral_JBLLIVE300TWS_ModelId[] = "718FA4";
+const char kPopularPeripheral_JBLLIVE300TWS_Name[] = "JBLLIVE300TWS";
+const char kPopularPeripheral_JBLLIVE400BT_ModelId[] = "F0020B";
+const char kPopularPeripheral_JBLLIVE400BT_Name[] = "JBLLIVE400BT";
+const char kPopularPeripheral_JBLTUNE125TWS_ModelId[] = "FF1B63";
+const char kPopularPeripheral_JBLTUNE125TWS_Name[] = "JBLTUNE125TWS";
+const char kPopularPeripheral_JBLTUNE225TWS_ModelId[] = "5C0C84";
+const char kPopularPeripheral_JBLTUNE225TWS_Name[] = "JBLTUNE225TWS";
+const char kPopularPeripheral_OnePlusBudsZ_ModelId[] = "A41C91";
+const char kPopularPeripheral_OnePlusBudsZ_Name[] = "OnePlusBudsZ";
+const char kPopularPeripheral_PixelBuds_ModelId[] = "060000";
+const char kPopularPeripheral_PixelBuds_Name[] = "PixelBuds";
+const char kPopularPeripheral_PixelBudsASeries_ModelId[] = "718C17";
+const char kPopularPeripheral_PixelBudsASeries_Name[] = "PixelBudsASeries";
+const char kPopularPeripheral_PixelBudsPro_ModelId[] = "F2020E";
+const char kPopularPeripheral_PixelBudsPro_Name[] = "PixelBudsPro";
+const char kPopularPeripheral_RealmeBudsAir2_ModelId[] = "BA5D56";
+const char kPopularPeripheral_RealmeBudsAir2_Name[] = "RealmeBudsAir2";
+const char kPopularPeripheral_SonyWF1000XM3_ModelId[] = "38C95C";
+const char kPopularPeripheral_SonyWF1000XM3_Name[] = "SonyWF1000XM3";
+const char kPopularPeripheral_Other_Name[] = "Other";
+
+const std::string GetFastPairTrackedModelId(const std::string& model_id) {
+  if (model_id == kPopularPeripheral_JBLLIVE300TWS_ModelId)
+    return kPopularPeripheral_JBLLIVE300TWS_Name;
+  if (model_id == kPopularPeripheral_JBLLIVE400BT_ModelId)
+    return kPopularPeripheral_JBLLIVE400BT_Name;
+  if (model_id == kPopularPeripheral_JBLTUNE125TWS_ModelId)
+    return kPopularPeripheral_JBLTUNE125TWS_Name;
+  if (model_id == kPopularPeripheral_JBLTUNE225TWS_ModelId)
+    return kPopularPeripheral_JBLTUNE225TWS_Name;
+  if (model_id == kPopularPeripheral_OnePlusBudsZ_ModelId)
+    return kPopularPeripheral_OnePlusBudsZ_Name;
+  if (model_id == kPopularPeripheral_PixelBuds_ModelId)
+    return kPopularPeripheral_PixelBuds_Name;
+  if (model_id == kPopularPeripheral_PixelBudsASeries_ModelId)
+    return kPopularPeripheral_PixelBudsASeries_Name;
+  if (model_id == kPopularPeripheral_PixelBudsPro_ModelId)
+    return kPopularPeripheral_PixelBudsPro_Name;
+  if (model_id == kPopularPeripheral_RealmeBudsAir2_ModelId)
+    return kPopularPeripheral_RealmeBudsAir2_Name;
+  if (model_id == kPopularPeripheral_SonyWF1000XM3_ModelId)
+    return kPopularPeripheral_SonyWF1000XM3_Name;
+  return kPopularPeripheral_Other_Name;
+}
+
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused. This enum should be kept in sync
 // with the BluetoothConnectToServiceError enum in
@@ -203,6 +252,33 @@
 const char kSavedDevicesCount[] =
     "Bluetooth.ChromeOS.FastPair.SavedDevices.DeviceCount";
 
+const std::string GetEngagementFlowInitialModelIdMetric(
+    const ash::quick_pair::Device& device) {
+  return std::string(kEngagementFlowInitialMetric) + "." +
+         GetFastPairTrackedModelId(device.metadata_id);
+}
+
+const std::string GetEngagementFlowSubsequentModelIdMetric(
+    const ash::quick_pair::Device& device) {
+  return std::string(kEngagementFlowSubsequentMetric) + "." +
+         GetFastPairTrackedModelId(device.metadata_id);
+}
+
+const std::string GetRetroactiveEngagementFlowModelIdMetric(
+    const ash::quick_pair::Device& device) {
+  return std::string(kRetroactiveEngagementFlowMetric) + "." +
+         GetFastPairTrackedModelId(device.metadata_id);
+}
+
+// The retroactive engagement flow doesn't record retroactive successes
+// properly due to b/240581398, so we use the account key write metric
+// to record metrics split by model ID.
+const std::string GetAccountKeyWriteResultRetroactiveModelIdMetric(
+    const ash::quick_pair::Device& device) {
+  return std::string(kFastPairAccountKeyWriteResultRetroactiveMetric) + "." +
+         GetFastPairTrackedModelId(device.metadata_id);
+}
+
 }  // namespace
 
 namespace ash {
@@ -214,12 +290,18 @@
     case Protocol::kFastPairInitial:
       base::UmaHistogramSparse(kEngagementFlowInitialMetric,
                                static_cast<int>(event));
+      // Also record engagement flow metrics split per tracked model ID.
+      base::UmaHistogramSparse(GetEngagementFlowInitialModelIdMetric(device),
+                               static_cast<int>(event));
       break;
     case Protocol::kFastPairRetroactive:
       break;
     case Protocol::kFastPairSubsequent:
       base::UmaHistogramSparse(kEngagementFlowSubsequentMetric,
                                static_cast<int>(event));
+      // Also record engagement flow metrics split per tracked model ID.
+      base::UmaHistogramSparse(GetEngagementFlowSubsequentModelIdMetric(device),
+                               static_cast<int>(event));
       break;
   }
 }
@@ -252,6 +334,10 @@
     case Protocol::kFastPairRetroactive:
       base::UmaHistogramSparse(kRetroactiveEngagementFlowMetric,
                                static_cast<int>(event));
+      // Also record engagement flow metrics split per tracked model ID.
+      base::UmaHistogramSparse(
+          GetRetroactiveEngagementFlowModelIdMetric(device),
+          static_cast<int>(event));
       break;
   }
 }
@@ -335,6 +421,9 @@
     case Protocol::kFastPairRetroactive:
       base::UmaHistogramBoolean(kFastPairAccountKeyWriteResultRetroactiveMetric,
                                 success);
+      // Also record engagement flow metrics split per tracked model ID.
+      base::UmaHistogramBoolean(
+          GetAccountKeyWriteResultRetroactiveModelIdMetric(device), success);
       break;
     case Protocol::kFastPairSubsequent:
       base::UmaHistogramBoolean(kFastPairAccountKeyWriteResultSubsequentMetric,
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 8ff57af..7925b9b 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -252,6 +252,7 @@
     "privacy_indicators_microphone.icon",
     "privacy_indicators_screen_share.icon",
     "privacy_screen.icon",
+    "quick_settings_back.icon",
     "remove_outline.icon",
     "reorder.icon",
     "reorder_nudge_dark_clamshell.icon",
diff --git a/ash/resources/vector_icons/quick_settings_back.icon b/ash/resources/vector_icons/quick_settings_back.icon
new file mode 100644
index 0000000..bff50ee
--- /dev/null
+++ b/ash/resources/vector_icons/quick_settings_back.icon
@@ -0,0 +1,13 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 14, 5.41f,
+LINE_TO, 9.06f, 10,
+LINE_TO, 14, 14.59f,
+LINE_TO, 12.48f, 16,
+LINE_TO, 6, 10,
+LINE_TO, 12.48f, 4,
+LINE_TO, 14, 5.41f,
+CLOSE
diff --git a/ash/rgb_keyboard/rgb_keyboard_manager.cc b/ash/rgb_keyboard/rgb_keyboard_manager.cc
index fca33f18..9e261eac3ce 100644
--- a/ash/rgb_keyboard/rgb_keyboard_manager.cc
+++ b/ash/rgb_keyboard/rgb_keyboard_manager.cc
@@ -10,6 +10,7 @@
 #include "ash/constants/ash_features.h"
 #include "ash/ime/ime_controller_impl.h"
 #include "ash/rgb_keyboard/histogram_util.h"
+#include "ash/rgb_keyboard/rgb_keyboard_manager_observer.h"
 #include "ash/rgb_keyboard/rgb_keyboard_util.h"
 #include "base/check.h"
 #include "base/check_op.h"
@@ -117,6 +118,14 @@
   return g_instance;
 }
 
+void RgbKeyboardManager::AddObserver(RgbKeyboardManagerObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void RgbKeyboardManager::RemoveObserver(RgbKeyboardManagerObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void RgbKeyboardManager::OnCapabilityUpdatedForTesting(
     rgbkbd::RgbKeyboardCapabilities capability) {
   capabilities_ = capability;
@@ -138,6 +147,9 @@
 
   if (IsRgbKeyboardSupported())
     InitializeRgbKeyboard();
+
+  for (auto& observer : observers_)
+    observer.OnRgbKeyboardSupportedChanged(IsRgbKeyboardSupported());
 }
 
 void RgbKeyboardManager::InitializeRgbKeyboard() {
diff --git a/ash/rgb_keyboard/rgb_keyboard_manager.h b/ash/rgb_keyboard/rgb_keyboard_manager.h
index d419a69..3ac027ef 100644
--- a/ash/rgb_keyboard/rgb_keyboard_manager.h
+++ b/ash/rgb_keyboard/rgb_keyboard_manager.h
@@ -16,6 +16,8 @@
 
 namespace ash {
 
+class RgbKeyboardManagerObserver;
+
 // RgbKeyboardManager is singleton class that provides clients access to
 // RGB keyboard-related API's. Clients should interact with this class instead
 // of the rgbkbd DBus client.
@@ -41,6 +43,10 @@
     return capabilities_ != rgbkbd::RgbKeyboardCapabilities::kNone;
   }
 
+  // Add and remove observers.
+  void AddObserver(RgbKeyboardManagerObserver* observer);
+  void RemoveObserver(RgbKeyboardManagerObserver* observer);
+
  private:
   // Enum to track the background mode sent to rgbkbd
   enum class BackgroundType {
@@ -76,6 +82,8 @@
   SkColor background_color_;
   BackgroundType background_type_ = BackgroundType::kNone;
 
+  base::ObserverList<RgbKeyboardManagerObserver> observers_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<RgbKeyboardManager> weak_ptr_factory_{this};
diff --git a/ash/rgb_keyboard/rgb_keyboard_manager_observer.h b/ash/rgb_keyboard/rgb_keyboard_manager_observer.h
new file mode 100644
index 0000000..2eb2ef8
--- /dev/null
+++ b/ash/rgb_keyboard/rgb_keyboard_manager_observer.h
@@ -0,0 +1,26 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_RGB_KEYBOARD_RGB_KEYBOARD_MANAGER_OBSERVER_H_
+#define ASH_RGB_KEYBOARD_RGB_KEYBOARD_MANAGER_OBSERVER_H_
+
+#include "ash/ash_export.h"
+#include "base/observer_list_types.h"
+
+namespace ash {
+
+// Used to listen for rgb_keyboard_manager changes.
+class ASH_EXPORT RgbKeyboardManagerObserver : public base::CheckedObserver {
+ public:
+  // Invoked when rgb keyboard support is determined. Called only once after
+  // fetching rgb capabilities.
+  virtual void OnRgbKeyboardSupportedChanged(bool supported) {}
+
+ protected:
+  ~RgbKeyboardManagerObserver() override = default;
+};
+
+}  // namespace ash
+
+#endif  // ASH_RGB_KEYBOARD_RGB_KEYBOARD_MANAGER_OBSERVER_H_
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index 18df6440f..5ddea72 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -10,6 +10,7 @@
 #include "ash/app_list/app_list_controller_impl.h"
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_switches.h"
+#include "ash/metrics/login_unlock_throughput_recorder.h"
 #include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/public/cpp/shelf_item_delegate.h"
 #include "ash/public/cpp/shelf_model.h"
@@ -18,6 +19,7 @@
 #include "ash/root_window_controller.h"
 #include "ash/shelf/hotseat_widget.h"
 #include "ash/shelf/login_shelf_widget.h"
+#include "ash/shelf/scrollable_shelf_view.h"
 #include "ash/shelf/shelf_controller.h"
 #include "ash/shelf/shelf_focus_cycler.h"
 #include "ash/shelf/shelf_layout_manager.h"
@@ -406,6 +408,8 @@
   hotseat_transition_metrics_reporter_ =
       std::make_unique<HotseatWidgetAnimationMetricsReporter>(
           HotseatWidgetAnimationMetricsReporter::HotseatElementType::kWidget);
+  Shell::Get()->login_unlock_throughput_recorder()->SetShelfViewIfNotSet(
+      hotseat_widget_->scrollable_shelf_view()->shelf_view());
 }
 
 void Shelf::CreateStatusAreaWidget(aura::Window* shelf_container) {
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc
index e2ec3ff..4188282 100644
--- a/ash/shelf/shelf_controller.cc
+++ b/ash/shelf/shelf_controller.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "ash/public/cpp/message_center/arc_notification_constants.h"
 #include "ash/public/cpp/shelf_item_delegate.h"
@@ -18,6 +19,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -134,6 +136,13 @@
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   registry->RegisterStringPref(prefs::kShelfAutoHideBehaviorLocal,
                                std::string());
+  if (base::FeatureList::IsEnabled(features::kShelfAutoHideSeparation)) {
+    registry->RegisterStringPref(
+        prefs::kShelfAutoHideTabletModeBehavior, kShelfAutoHideBehaviorNever,
+        user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
+    registry->RegisterStringPref(prefs::kShelfAutoHideTabletModeBehaviorLocal,
+                                 std::string());
+  }
   registry->RegisterStringPref(
       prefs::kShelfAlignment, kShelfAlignmentBottom,
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
@@ -163,6 +172,11 @@
                               base::BindRepeating(&SetShelfAlignmentFromPrefs));
   pref_change_registrar_->Add(prefs::kShelfAutoHideBehaviorLocal,
                               base::BindRepeating(&SetShelfAutoHideFromPrefs));
+  if (base::FeatureList::IsEnabled(features::kShelfAutoHideSeparation)) {
+    pref_change_registrar_->Add(
+        prefs::kShelfAutoHideTabletModeBehaviorLocal,
+        base::BindRepeating(&SetShelfAutoHideFromPrefs));
+  }
   pref_change_registrar_->Add(prefs::kShelfPreferences,
                               base::BindRepeating(&SetShelfBehaviorsFromPrefs));
 
@@ -194,8 +208,12 @@
   if (Shell::Get()->session_controller()->IsRunningInAppMode())
     return;
 
-  // Force the shelf to be visible and to be bottom aligned in tablet mode; the
-  // prefs are restored on exit.
+  if (base::FeatureList::IsEnabled(features::kShelfAutoHideSeparation)) {
+    SetShelfAutoHideFromPrefs();
+  }
+
+  // Force the shelf to be bottom aligned in tablet mode; the prefs are restored
+  // on exit.
   for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
     if (Shelf* shelf = GetShelfForDisplay(display.id())) {
       // Only animate into tablet mode if the shelf alignment will not change.
diff --git a/ash/shelf/shelf_controller_unittest.cc b/ash/shelf/shelf_controller_unittest.cc
index f42e4223..341a45a 100644
--- a/ash/shelf/shelf_controller_unittest.cc
+++ b/ash/shelf/shelf_controller_unittest.cc
@@ -24,6 +24,7 @@
 #include "ash/wm/window_util.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "components/account_id/account_id.h"
 #include "components/prefs/pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -123,33 +124,91 @@
   EXPECT_FALSE(controller->model()->items()[index].has_notification);
 }
 
-class ShelfControllerPrefsTest : public AshTestBase {
+class ShelfControllerPrefsTest
+    : public AshTestBase,
+      public testing::WithParamInterface<
+          /*is_shelf_auto_hide_separation_enabled*/ bool> {
  public:
-  ShelfControllerPrefsTest() = default;
+  ShelfControllerPrefsTest()
+      : is_shelf_auto_hide_separation_enabled_(GetParam()) {
+    scoped_feature_list_.InitWithFeatureState(
+        features::kShelfAutoHideSeparation,
+        is_shelf_auto_hide_separation_enabled_);
+  }
 
   ShelfControllerPrefsTest(const ShelfControllerPrefsTest&) = delete;
   ShelfControllerPrefsTest& operator=(const ShelfControllerPrefsTest&) = delete;
 
   ~ShelfControllerPrefsTest() override = default;
+
+  void SetAutoHideBehaviorPrefForMode(PrefService* prefs,
+                                      int64_t display_id,
+                                      const std::string& value,
+                                      bool tablet_mode) {
+    SetPerDisplayShelfPref(prefs, display_id,
+                           tablet_mode ? prefs::kShelfAutoHideTabletModeBehavior
+                                       : prefs::kShelfAutoHideBehavior,
+                           value);
+    prefs->SetString(tablet_mode ? prefs::kShelfAutoHideTabletModeBehaviorLocal
+                                 : prefs::kShelfAutoHideBehaviorLocal,
+                     value);
+    prefs->SetString(tablet_mode ? prefs::kShelfAutoHideTabletModeBehavior
+                                 : prefs::kShelfAutoHideBehavior,
+                     value);
+  }
+
+  bool is_shelf_auto_hide_separation_enabled() {
+    return is_shelf_auto_hide_separation_enabled_;
+  }
+
+ private:
+  const bool is_shelf_auto_hide_separation_enabled_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
+INSTANTIATE_TEST_SUITE_P(ShelfAutoHideSeparation,
+                         ShelfControllerPrefsTest,
+                         testing::Bool());
+
+// Ensure relevant shelf preferences have been registsered.
+TEST_P(ShelfControllerPrefsTest, PrefsAreRegistered) {
+  PrefService* prefs =
+      Shell::Get()->session_controller()->GetLastActiveUserPrefService();
+  EXPECT_TRUE(prefs->FindPreference(prefs::kShelfAutoHideBehavior));
+  EXPECT_TRUE(prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal));
+  EXPECT_TRUE(prefs->FindPreference(prefs::kShelfAlignment));
+  EXPECT_TRUE(prefs->FindPreference(prefs::kShelfAlignmentLocal));
+  EXPECT_TRUE(prefs->FindPreference(prefs::kShelfPreferences));
+  if (is_shelf_auto_hide_separation_enabled()) {
+    EXPECT_TRUE(prefs->FindPreference(prefs::kShelfAutoHideTabletModeBehavior));
+    EXPECT_TRUE(
+        prefs->FindPreference(prefs::kShelfAutoHideTabletModeBehaviorLocal));
+  }
+}
+
 // Ensure shelf settings are updated on preference changes.
-TEST_F(ShelfControllerPrefsTest, ShelfRespectsPrefs) {
+TEST_P(ShelfControllerPrefsTest, ShelfRespectsPrefs) {
   Shelf* shelf = GetPrimaryShelf();
   EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
-  EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
-
   PrefService* prefs =
       Shell::Get()->session_controller()->GetLastActiveUserPrefService();
   prefs->SetString(prefs::kShelfAlignmentLocal, "Left");
-  prefs->SetString(prefs::kShelfAutoHideBehaviorLocal, "Always");
-
   EXPECT_EQ(ShelfAlignment::kLeft, shelf->alignment());
-  EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+
+  if (is_shelf_auto_hide_separation_enabled()) {
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+    EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+    prefs->SetString(prefs::kShelfAutoHideTabletModeBehaviorLocal, "Always");
+    EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  } else {
+    EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+    prefs->SetString(prefs::kShelfAutoHideBehaviorLocal, "Always");
+    EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  }
 }
 
 // Ensure shelf settings are updated on per-display preference changes.
-TEST_F(ShelfControllerPrefsTest, ShelfRespectsPerDisplayPrefs) {
+TEST_P(ShelfControllerPrefsTest, ShelfRespectsPerDisplayPrefs) {
   UpdateDisplay("1024x768,800x600");
   base::RunLoop().RunUntilIdle();
   const int64_t id1 = GetPrimaryDisplay().id();
@@ -177,7 +236,7 @@
 
 // Ensures that pre-Unified Mode per-display shelf settings don't prevent us
 // from changing the shelf settings in unified mode.
-TEST_F(ShelfControllerPrefsTest, ShelfRespectsPerDisplayPrefsUnified) {
+TEST_P(ShelfControllerPrefsTest, ShelfRespectsPerDisplayPrefsUnified) {
   UpdateDisplay("1024x768,800x600");
 
   // Before enabling Unified Mode, set the shelf alignment for one of the two
@@ -215,7 +274,7 @@
 
 // Ensure shelf settings are correct after display swap at login screen, see
 // crbug.com/748291
-TEST_F(ShelfControllerPrefsTest,
+TEST_P(ShelfControllerPrefsTest,
        ShelfSettingsValidAfterDisplaySwapAtLoginScreen) {
   // Simulate adding an external display at the lock screen.
   GetSessionControllerClient()->RequestLockScreen();
@@ -293,7 +352,7 @@
 
 // Test display swap while logged in, which was causing a crash (see
 // crbug.com/1022852)
-TEST_F(ShelfControllerPrefsTest,
+TEST_P(ShelfControllerPrefsTest,
        ShelfSettingsValidAfterDisplaySwapWhileLoggedIn) {
   // Simulate adding an external display at the lock screen.
   GetSessionControllerClient()->RequestLockScreen();
@@ -328,7 +387,9 @@
             GetShelfForDisplay(external_display_id)->auto_hide_behavior());
 }
 
-TEST_F(ShelfControllerPrefsTest, ShelfSettingsInTabletMode) {
+// Tests shelf settings behavior when switching between clamshell mode and
+// tablet mode.
+TEST_P(ShelfControllerPrefsTest, ShelfSettingsBetweenClamshellAndTabletMode) {
   Shelf* shelf = GetPrimaryShelf();
   PrefService* prefs =
       Shell::Get()->session_controller()->GetLastActiveUserPrefService();
@@ -338,30 +399,136 @@
   ASSERT_EQ(ShelfAlignment::kLeft, shelf->alignment());
   ASSERT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
 
-  // Verify after entering tablet mode, the shelf alignment is bottom and the
-  // auto hide behavior has not changed.
+  // Verify after entering tablet mode, the shelf alignment is bottom.
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
-  EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  // If shelf-auto-hide-separation is enabled then the auto hide behavior should
+  // be never (the default value) because this is the first time that tablet
+  // mode is entered. If shelf-auto-hide-separation is not enabled then the auto
+  // hide behvaior should be whatever value it was before entering tablet mode.
+  if (is_shelf_auto_hide_separation_enabled()) {
+    EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+  } else {
+    EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  }
 
   // Verify that screen rotation does not change alignment or auto-hide.
   display_manager()->SetDisplayRotation(
       display::Screen::GetScreen()->GetPrimaryDisplay().id(),
       display::Display::ROTATE_90, display::Display::RotationSource::ACTIVE);
   EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
-  EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  if (is_shelf_auto_hide_separation_enabled()) {
+    EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+  } else {
+    EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  }
 
   // Verify after exiting tablet mode, the shelf alignment and auto hide
   // behavior get their stored pref values.
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(ShelfAlignment::kLeft, shelf->alignment());
   EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+
+  // Change the clamshell-mode auto hide setting and then switch to tablet mode.
+  SetShelfAutoHideBehaviorPref(prefs, GetPrimaryDisplay().id(),
+                               ShelfAutoHideBehavior::kNever);
+  ASSERT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  // If shelf-auto-hide-separation is enabled then the auto hide behavior should
+  // be whatever it was previously in tablet mode (never, in this case);
+  // otherwise, it should follow the clamshell-mode behavior (still never, in
+  // this case).
+  EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+
+  // Change the tablet-mode auto hide setting and then switch to clamshell mode.
+  SetShelfAutoHideBehaviorPref(prefs, GetPrimaryDisplay().id(),
+                               ShelfAutoHideBehavior::kAlways);
+  ASSERT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
+  // If shelf-auto-hide-separation is enabled then the auto hide behavior should
+  // be whatever it was previously in clamshell mode (never, in this case);
+  // otherwise it should follow the tablet-mode behavior (always, in this case).
+  if (is_shelf_auto_hide_separation_enabled()) {
+    EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+  } else {
+    EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  }
 }
 
-using ShelfControllerAppModeTest = NoSessionAshTestBase;
+using ShelfControllerPrefsWithSeparationTest = ShelfControllerPrefsTest;
+
+INSTANTIATE_TEST_SUITE_P(ShelfAutoHideSeparation,
+                         ShelfControllerPrefsWithSeparationTest,
+                         testing::Values(true));
+
+// Tests shelf auto hide behavior when changing tablet mode settings while in
+// clamshell mode, and vice versa. Note that this test only makes sense when
+// shelf-auto-hide-separation is enabled because there is no distinction between
+// "clamshell-mode auto hide pref" vs. "tablet-mode auto hide pref" when
+// shelf-auto-hide-separation is not enabled.
+TEST_P(ShelfControllerPrefsWithSeparationTest,
+       ShelfSettingsChangedInAnotherMode) {
+  Shelf* shelf = GetPrimaryShelf();
+  PrefService* prefs =
+      Shell::Get()->session_controller()->GetLastActiveUserPrefService();
+
+  // Ensure the auto hide behavior is "Always" in both clamshell and tablet
+  // mode. Then switch to tablet mode, and change the clamshell-mode auto hide
+  // behavior. This should not affect the tablet-mode auto hide behavior.
+  SetShelfAutoHideBehaviorPref(prefs, GetPrimaryDisplay().id(),
+                               ShelfAutoHideBehavior::kAlways);
+  ASSERT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  SetShelfAutoHideBehaviorPref(prefs, GetPrimaryDisplay().id(),
+                               ShelfAutoHideBehavior::kAlways);
+  ASSERT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+  const auto display_id = GetPrimaryDisplay().id();
+  SetAutoHideBehaviorPrefForMode(prefs, display_id, "Never",
+                                 /*tablet_mode*/ false);
+  EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
+
+  // Ensure the auto hide behavior is "Never" in both clamshell and tablet
+  // mode. Then switch to clamshell mode, and change the tablet-mode auto hide
+  // behavior. This should not affect the clamshell-mode auto hide behavior.
+  SetShelfAutoHideBehaviorPref(prefs, display_id,
+                               ShelfAutoHideBehavior::kNever);
+  ASSERT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
+  ASSERT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+  SetAutoHideBehaviorPrefForMode(prefs, display_id, "Always",
+                                 /*tablet_mode*/ true);
+  EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
+}
+
+class ShelfControllerAppModeTest
+    : public NoSessionAshTestBase,
+      public testing::WithParamInterface<
+          /*is_shelf_auto_hide_separation_enabled*/ bool> {
+ public:
+  ShelfControllerAppModeTest()
+      : is_shelf_auto_hide_separation_enabled_(GetParam()) {
+    scoped_feature_list_.InitWithFeatureState(
+        features::kShelfAutoHideSeparation,
+        is_shelf_auto_hide_separation_enabled_);
+  }
+
+  ShelfControllerAppModeTest(const ShelfControllerAppModeTest&) = delete;
+  ShelfControllerAppModeTest& operator=(const ShelfControllerAppModeTest&) =
+      delete;
+
+  ~ShelfControllerAppModeTest() override = default;
+
+ private:
+  const bool is_shelf_auto_hide_separation_enabled_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(ShelfAutoHideSeparation,
+                         ShelfControllerAppModeTest,
+                         testing::Bool());
 
 // Tests that shelf auto hide behavior is always hidden in app mode.
-TEST_F(ShelfControllerAppModeTest, AutoHideBehavior) {
+TEST_P(ShelfControllerAppModeTest, AutoHideBehavior) {
   SimulateKioskMode(user_manager::USER_TYPE_KIOSK_APP);
 
   Shelf* shelf = GetPrimaryShelf();
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 18a18ba..164c40e 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -2966,7 +2966,8 @@
   if (!IsWindowDragInProgress())
     return;
 
-  DCHECK_EQ(drag_status_, kDragInProgress);
+  DCHECK(drag_status_ == kDragInProgress ||
+         drag_status_ == kDragCancelInProgress);
   shelf_widget_->GetDragHandle()->SetWindowDragFromShelfInProgress(false);
   window_drag_controller_->CancelDrag();
 }
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index aed2772..696ab55 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -1985,6 +1985,15 @@
   return drag_icon_proxy_->GetBoundsInScreen();
 }
 
+void ShelfView::AddAnimationObserver(views::BoundsAnimatorObserver* observer) {
+  bounds_animator_->AddObserver(observer);
+}
+
+void ShelfView::RemoveAnimationObserver(
+    views::BoundsAnimatorObserver* observer) {
+  bounds_animator_->RemoveObserver(observer);
+}
+
 void ShelfView::AnnounceShelfAutohideBehavior() {
   std::u16string announcement;
   switch (shelf_->auto_hide_behavior()) {
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index 3cdf669..c75b823 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -326,6 +326,9 @@
     return current_ghost_view_index_;
   }
 
+  void AddAnimationObserver(views::BoundsAnimatorObserver* observer);
+  void RemoveAnimationObserver(views::BoundsAnimatorObserver* observer);
+
  private:
   friend class ShelfViewTestAPI;
 
diff --git a/ash/shell.cc b/ash/shell.cc
index 65f1e7a7..86648006 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -1090,8 +1090,9 @@
   wallpaper_controller_ = WallpaperControllerImpl::Create(local_state_);
 
   if (features::IsRgbKeyboardEnabled()) {
-    // Initialized after |wallpaper_controller_| because we will need to observe
-    // when the extracted wallpaper color changes.
+    // Initialized after |rgb_keyboard_manager_| to observe the state of rgb
+    // keyboard and |wallpaper_controller_| because we will need to observe when
+    // the extracted wallpaper color changes.
     keyboard_backlight_color_controller_ =
         std::make_unique<KeyboardBacklightColorController>();
   }
@@ -1166,8 +1167,8 @@
 
   screen_position_controller_ = std::make_unique<ScreenPositionController>();
 
-  frame_throttling_controller_ =
-      std::make_unique<FrameThrottlingController>(context_factory);
+  frame_throttling_controller_ = std::make_unique<FrameThrottlingController>(
+      context_factory->GetHostFrameSinkManager());
 
   if (features::IsTabClusterUIEnabled())
     tab_cluster_ui_controller_ = std::make_unique<TabClusterUIController>();
diff --git a/ash/shell.h b/ash/shell.h
index fd54b4bf..51dfdb29 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -738,6 +738,10 @@
   void NotifyShelfAlignmentChanged(aura::Window* root_window,
                                    ShelfAlignment old_alignment);
 
+  LoginUnlockThroughputRecorder* login_unlock_throughput_recorder() {
+    return login_unlock_throughput_recorder_.get();
+  }
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ExtendedDesktopTest, TestCursor);
   FRIEND_TEST_ALL_PREFIXES(WindowManagerTest, MouseEventCursors);
diff --git a/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc b/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
index 5deb212b..d0b97a9 100644
--- a/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
+++ b/ash/shortcut_viewer/views/keyboard_shortcut_item_view.cc
@@ -212,7 +212,7 @@
       base::i18n::IsRTL() ? gfx::ALIGN_LEFT : gfx::ALIGN_RIGHT);
   DCHECK_EQ(replacement_strings.size(), offsets.size());
   // TODO(wutao): make this reliable.
-  // If the replacement string is "+ ", it indicates to insert a seperator view.
+  // If the replacement string is "+ ", it indicates to insert a separator view.
   const std::u16string separator_string = u"+ ";
   for (size_t i = 0; i < offsets.size(); ++i) {
     views::StyledLabel::RangeStyleInfo style_info;
diff --git a/ash/style/ash_color_mixer.cc b/ash/style/ash_color_mixer.cc
index 0bb2cd3c..d94b034 100644
--- a/ash/style/ash_color_mixer.cc
+++ b/ash/style/ash_color_mixer.cc
@@ -145,8 +145,7 @@
   mixer[kColorAshTextColorPositive] = {cros_tokens::kColorPositive};
   mixer[kColorAshTextColorURL] = {cros_tokens::kColorProminent};
   mixer[kColorAshIconColorPrimary] = {kColorAshTextColorPrimary};
-  // TODO(skau): Figure out if this should be kColorSecondary instead.
-  mixer[kColorAshIconColorSecondary] = {cros_tokens::kColorDisabledDark};
+  mixer[kColorAshIconColorSecondary] = {cros_tokens::kColorSecondary};
   mixer[kColorAshIconColorAlert] = {kColorAshTextColorAlert};
   mixer[kColorAshIconColorWarning] = {kColorAshTextColorWarning};
   mixer[kColorAshIconColorPositive] = {kColorAshTextColorPositive};
diff --git a/ash/style/ash_color_provider_unittest.cc b/ash/style/ash_color_provider_unittest.cc
index ee16192..5e4ff59 100644
--- a/ash/style/ash_color_provider_unittest.cc
+++ b/ash/style/ash_color_provider_unittest.cc
@@ -267,7 +267,7 @@
           SkColorSetRGB(0x20, 0x21, 0x24)},
          {ColorMode::kLight,
           ColorProvider::ContentLayerType::kIconColorSecondary,
-          SkColorSetRGB(0x9A, 0xA0, 0xA6)},
+          SkColorSetRGB(0x5F, 0x63, 0x68)},
          {ColorMode::kLight, ColorProvider::ContentLayerType::kIconColorAlert,
           SkColorSetRGB(0xD9, 0x30, 0x25)},
          {ColorMode::kLight, ColorProvider::ContentLayerType::kIconColorWarning,
@@ -402,7 +402,7 @@
           SkColorSetRGB(0xE8, 0xEA, 0xED)},
          {ColorMode::kDark,
           ColorProvider::ContentLayerType::kIconColorSecondary,
-          SkColorSetRGB(0x9A, 0xA0, 0xA6)},
+          SkColorSetRGB(0xBD, 0xC1, 0xC6)},
          {ColorMode::kDark, ColorProvider::ContentLayerType::kIconColorAlert,
           SkColorSetRGB(0xF2, 0x8B, 0x82)},
          {ColorMode::kDark, ColorProvider::ContentLayerType::kIconColorWarning,
diff --git a/ash/style/dark_light_mode_controller_impl.cc b/ash/style/dark_light_mode_controller_impl.cc
index 6b448d12..82f2b8e 100644
--- a/ash/style/dark_light_mode_controller_impl.cc
+++ b/ash/style/dark_light_mode_controller_impl.cc
@@ -21,8 +21,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/known_user.h"
 #include "ui/chromeos/styles/cros_styles.h"
-#include "ui/gfx/color_analysis.h"
-#include "ui/gfx/color_utils.h"
 
 namespace ash {
 
diff --git a/ash/system/channel_indicator/channel_indicator_quick_settings_view.cc b/ash/system/channel_indicator/channel_indicator_quick_settings_view.cc
index ea1ee56..9909921 100644
--- a/ash/system/channel_indicator/channel_indicator_quick_settings_view.cc
+++ b/ash/system/channel_indicator/channel_indicator_quick_settings_view.cc
@@ -6,24 +6,29 @@
 
 #include <algorithm>
 
+#include "ash/constants/ash_features.h"
 #include "ash/constants/quick_settings_catalogs.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/public/cpp/system_tray_client.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "ash/style/ash_color_provider.h"
 #include "ash/style/icon_button.h"
+#include "ash/style/style_util.h"
 #include "ash/system/channel_indicator/channel_indicator_utils.h"
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/unified/quick_settings_metrics_util.h"
 #include "base/i18n/rtl.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkScalar.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/gfx/geometry/rrect_f.h"
 #include "ui/gfx/geometry/skia_conversions.h"
+#include "ui/gfx/text_constants.h"
 #include "ui/views/animation/ink_drop.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/label_button.h"
@@ -36,6 +41,7 @@
 namespace {
 
 constexpr int kVersionButtonHeight = 24;
+constexpr int kVersionButtonRevampHeight = 32;
 constexpr int kVersionButtonImageLabelSpacing = 8;
 
 constexpr int kVersionButtonMarginVertical = 3;
@@ -93,6 +99,10 @@
 constexpr int kSubmitFeedbackButtonWidth = 30;
 constexpr int kSubmitFeedbackButtonIconSize = 16;
 
+constexpr int kSubmitFeedbackButtonRevampHeight = 32;
+constexpr int kSubmitFeedbackButtonRevampWidth = 40;
+constexpr int kSubmitFeedbackButtonRevampIconSize = 18;
+
 // Corners for the `SubmitFeedbackButton` contents.
 constexpr SkScalar kSubmitFeedbackButtonCorners[] = {
     kSubmitFeedbackButtonSmallCornerRadius,
@@ -118,6 +128,32 @@
     kSubmitFeedbackButtonLargeCornerRadius);
 
 constexpr int kButtonSpacing = 2;
+constexpr int kButtonSpacingRevamp = 6;
+
+// Returns an array of `SkScalar` used to generate the rounded rect that's
+// painted for the button, the same regardless of RTL/LTR but may be different
+// if `VersionButton` is "standalone" vs. "partnered" with a
+// `SubmitFeedbackButton`.
+const SkScalar (&GetVersionButtonContentCorners(
+    bool allow_user_feedback))[kNumVersionButtonCornerRadii] {
+  return allow_user_feedback ? kPartneredVersionButtonCorners
+                             : kStandaloneVersionButtonCorners;
+}
+
+// Returns a `gfx::RoundedCornersF` used to generate the highlight path and ink
+// drop, will be different depending on RTL/LTR.
+const gfx::RoundedCornersF& GetVersionButtonInkDropCorners(
+    bool allow_user_feedback) {
+  return allow_user_feedback ? base::i18n::IsRTL()
+                                   ? kPartneredVersionButtonInkDropCornersRToL
+                                   : kPartneredVersionButtonInkDropCornersLToR
+                             : kStandaloneVersionButtonInkDropCorners;
+}
+
+const gfx::RoundedCornersF& GetSubmitFeedbackButtonInkDropCorners() {
+  return base::i18n::IsRTL() ? kSubmitFeedbackButtonInkDropCornersRToL
+                             : kSubmitFeedbackButtonInkDropCornersLToR;
+}
 
 // A `HighlightPathGenerator` that uses caller-supplied rounded rect corners.
 class VIEWS_EXPORT RoundedCornerHighlightPathGenerator
@@ -149,20 +185,21 @@
       view, std::make_unique<RoundedCornerHighlightPathGenerator>(corners));
 }
 
+SkColor GetInkDropBaseColor(version_info::Channel channel) {
+  if (features::IsQsRevampEnabled()) {
+    const std::pair<SkColor, float> base_color_and_opacity =
+        AshColorProvider::Get()->GetInkDropBaseColorAndOpacity();
+    return base_color_and_opacity.first;
+  }
+  return channel_indicator_utils::GetBgColor(channel);
+}
+
 // VersionButton is a base class that provides a styled button, for devices on a
 // non-stable release track, that has a label for the channel and ChromeOS
 // version.
 class VersionButton : public views::LabelButton {
  public:
-  // `content_corners` - an array of `SkScalar` used to generate the rounded
-  // rect that's painted for the button, the same regardless of RTL/LTR but may
-  // be different if `VersionButton` is "standalone" vs. "partnered" with a
-  // `SubmitFeedbackButton`.
-  // `highlight_corners` - a `gfx::RoundedCornersF` used to generate the
-  // highlight path and ink drop, will be different depending on RTL/LTR.
-  VersionButton(version_info::Channel channel,
-                const SkScalar (&content_corners)[kNumVersionButtonCornerRadii],
-                const gfx::RoundedCornersF& highlight_corners)
+  VersionButton(version_info::Channel channel, bool allow_user_feedback)
       : LabelButton(
             base::BindRepeating([](const ui::Event& event) {
               quick_settings_metrics_util::RecordQsButtonActivated(
@@ -176,16 +213,29 @@
         channel_(channel) {
     SetID(VIEW_ID_QS_VERSION_BUTTON);
     SetFlipCanvasOnPaintForRTLUI(true);
+    const auto& content_corners =
+        GetVersionButtonContentCorners(allow_user_feedback);
     std::copy(content_corners, content_corners + kNumVersionButtonCornerRadii,
               content_corners_);
-    SetBorder(views::CreateEmptyBorder(gfx::Insets::VH(
-        kVersionButtonMarginVertical, kVersionButtonMarginHorizontal)));
-    SetImageLabelSpacing(kVersionButtonImageLabelSpacing);
-    SetMinSize(gfx::Size(0, kVersionButtonHeight));
+    if (features::IsQsRevampEnabled()) {
+      if (allow_user_feedback) {
+        // Visually center the label by adding an empty border on the left side
+        // that is the same width as the feedback button.
+        SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(
+            0, kButtonSpacingRevamp + kSubmitFeedbackButtonRevampWidth, 0, 0)));
+      }
+      SetHorizontalAlignment(gfx::ALIGN_CENTER);
+      SetMinSize(gfx::Size(0, kVersionButtonRevampHeight));
+    } else {
+      SetBorder(views::CreateEmptyBorder(gfx::Insets::VH(
+          kVersionButtonMarginVertical, kVersionButtonMarginHorizontal)));
+      SetImageLabelSpacing(kVersionButtonImageLabelSpacing);
+      SetMinSize(gfx::Size(0, kVersionButtonHeight));
+    }
     views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON);
-    views::InkDrop::Get(this)->SetBaseColor(
-        channel_indicator_utils::GetBgColor(channel_));
-    InstallRoundedCornerHighlightPathGenerator(this, highlight_corners);
+    views::InkDrop::Get(this)->SetBaseColor(GetInkDropBaseColor(channel_));
+    InstallRoundedCornerHighlightPathGenerator(
+        this, GetVersionButtonInkDropCorners(allow_user_feedback));
   }
   VersionButton(const VersionButton&) = delete;
   VersionButton& operator=(const VersionButton&) = delete;
@@ -194,8 +244,14 @@
   // views::LabelButton:
   void PaintButtonContents(gfx::Canvas* canvas) override {
     cc::PaintFlags flags;
-    flags.setColor(channel_indicator_utils::GetBgColor(channel_));
-    flags.setStyle(cc::PaintFlags::kFill_Style);
+    if (features::IsQsRevampEnabled()) {
+      flags.setColor(AshColorProvider::Get()->GetContentLayerColor(
+          ColorProvider::ContentLayerType::kSeparatorColor));
+      flags.setStyle(cc::PaintFlags::kStroke_Style);
+    } else {
+      flags.setColor(channel_indicator_utils::GetBgColor(channel_));
+      flags.setStyle(cc::PaintFlags::kFill_Style);
+    }
     flags.setAntiAlias(true);
     canvas->DrawPath(
         SkPath().addRoundRect(gfx::RectToSkRect(GetLocalBounds()),
@@ -210,9 +266,16 @@
 
  private:
   void SetBackgroundAndFont() {
-    label()->SetFontList(
-        gfx::FontList().DeriveWithWeight(gfx::Font::Weight::MEDIUM));
-    SetEnabledTextColors(channel_indicator_utils::GetFgColor(channel_));
+    if (features::IsQsRevampEnabled()) {
+      // TODO(b/252873172): Revisit font style and color. For now use the
+      // default size (which is obviously too small).
+      SetEnabledTextColors(AshColorProvider::Get()->GetContentLayerColor(
+          ColorProvider::ContentLayerType::kTextColorSecondary));
+    } else {
+      label()->SetFontList(
+          gfx::FontList().DeriveWithWeight(gfx::Font::Weight::MEDIUM));
+      SetEnabledTextColors(channel_indicator_utils::GetFgColor(channel_));
+    }
   }
 
   // The channel itself, BETA, DEV, or CANARY.
@@ -242,7 +305,9 @@
                          ->client()
                          ->ShowChannelInfoGiveFeedback();
                    }),
-                   IconButton::Type::kSmall,
+                   features::IsQsRevampEnabled()
+                       ? IconButton::Type::kSmallFloating
+                       : IconButton::Type::kSmall,
                    &kRequestFeedbackIcon,
                    IDS_ASH_STATUS_TRAY_REPORT_FEEDBACK),
         channel_(channel) {
@@ -252,15 +317,24 @@
     SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(
         kSubmitFeedbackButtonMarginTop, kSubmitFeedbackButtonMarginLeft,
         kSubmitFeedbackButtonMarginBottom, kSubmitFeedbackButtonMarginRight)));
-    SetIconColor(channel_indicator_utils::GetFgColor(channel_));
-    SetIconSize(kSubmitFeedbackButtonIconSize);
-    SetBackgroundColor(channel_indicator_utils::GetBgColor(channel_));
-    SetPreferredSize(
-        gfx::Size(kSubmitFeedbackButtonWidth, kSubmitFeedbackButtonHeight));
+    if (features::IsQsRevampEnabled()) {
+      SetIconSize(kSubmitFeedbackButtonRevampIconSize);
+      SetPreferredSize(gfx::Size(kSubmitFeedbackButtonRevampWidth,
+                                 kSubmitFeedbackButtonRevampHeight));
+      // Enable ink drop on hover.
+      StyleUtil::SetUpInkDropForButton(this, gfx::Insets(),
+                                       /*highlight_on_hover=*/true,
+                                       /*highlight_on_focus=*/false,
+                                       GetInkDropBaseColor(channel_));
+    } else {
+      SetIconSize(kSubmitFeedbackButtonIconSize);
+      SetPreferredSize(
+          gfx::Size(kSubmitFeedbackButtonWidth, kSubmitFeedbackButtonHeight));
+    }
+    // Icon colors are set in OnThemeChanged().
 
     views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON);
-    views::InkDrop::Get(this)->SetBaseColor(
-        channel_indicator_utils::GetBgColor(channel_));
+    views::InkDrop::Get(this)->SetBaseColor(GetInkDropBaseColor(channel_));
     InstallRoundedCornerHighlightPathGenerator(this, highlight_corners);
   }
   SubmitFeedbackButton(const SubmitFeedbackButton&) = delete;
@@ -270,8 +344,14 @@
   // views::LabelButton:
   void PaintButtonContents(gfx::Canvas* canvas) override {
     cc::PaintFlags flags;
-    flags.setColor(channel_indicator_utils::GetBgColor(channel_));
-    flags.setStyle(cc::PaintFlags::kFill_Style);
+    if (features::IsQsRevampEnabled()) {
+      flags.setColor(AshColorProvider::Get()->GetContentLayerColor(
+          ColorProvider::ContentLayerType::kSeparatorColor));
+      flags.setStyle(cc::PaintFlags::kStroke_Style);
+    } else {
+      flags.setColor(channel_indicator_utils::GetBgColor(channel_));
+      flags.setStyle(cc::PaintFlags::kFill_Style);
+    }
     flags.setAntiAlias(true);
     canvas->DrawPath(
         SkPath().addRoundRect(gfx::RectToSkRect(GetLocalBounds()),
@@ -281,7 +361,14 @@
   }
 
   void OnThemeChanged() override {
-    SetIconColor(channel_indicator_utils::GetFgColor(channel_));
+    if (features::IsQsRevampEnabled()) {
+      // TODO(b/252873172): Revisit icon color.
+      SetIconColor(AshColorProvider::Get()->GetContentLayerColor(
+          ColorProvider::ContentLayerType::kIconColorSecondary));
+    } else {
+      SetIconColor(channel_indicator_utils::GetFgColor(channel_));
+      SetBackgroundColor(channel_indicator_utils::GetBgColor(channel_));
+    }
     IconButton::OnThemeChanged();
   }
 
@@ -293,25 +380,6 @@
   SkScalar content_corners_[kNumVersionButtonCornerRadii];
 };
 
-const SkScalar (&GetVersionButtonContentCorners(
-    bool allow_user_feedback))[kNumVersionButtonCornerRadii] {
-  return allow_user_feedback ? kPartneredVersionButtonCorners
-                             : kStandaloneVersionButtonCorners;
-}
-
-const gfx::RoundedCornersF& GetVersionButtonInkDropCorners(
-    bool allow_user_feedback) {
-  return allow_user_feedback ? base::i18n::IsRTL()
-                                   ? kPartneredVersionButtonInkDropCornersRToL
-                                   : kPartneredVersionButtonInkDropCornersLToR
-                             : kStandaloneVersionButtonInkDropCorners;
-}
-
-const gfx::RoundedCornersF& GetSubmitFeedbackButtonInkDropCorners() {
-  return base::i18n::IsRTL() ? kSubmitFeedbackButtonInkDropCornersRToL
-                             : kSubmitFeedbackButtonInkDropCornersLToR;
-}
-
 }  // namespace
 
 ChannelIndicatorQuickSettingsView::ChannelIndicatorQuickSettingsView(
@@ -326,11 +394,19 @@
 
   layout->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::kCenter);
-  layout->set_between_child_spacing(kButtonSpacing);
+  if (features::IsQsRevampEnabled()) {
+    layout->set_between_child_spacing(kButtonSpacingRevamp);
+  } else {
+    layout->set_between_child_spacing(kButtonSpacing);
+  }
 
-  version_button_ = AddChildView(std::make_unique<VersionButton>(
-      channel, GetVersionButtonContentCorners(allow_user_feedback),
-      GetVersionButtonInkDropCorners(allow_user_feedback)));
+  version_button_ = AddChildView(
+      std::make_unique<VersionButton>(channel, allow_user_feedback));
+
+  if (features::IsQsRevampEnabled()) {
+    // Stretch version button horizontally.
+    layout->SetFlexForView(version_button_, 1);
+  }
 
   if (allow_user_feedback) {
     feedback_button_ = AddChildView(std::make_unique<SubmitFeedbackButton>(
@@ -339,13 +415,4 @@
   }
 }
 
-bool ChannelIndicatorQuickSettingsView::IsVersionButtonVisibleForTesting() {
-  return version_button_ && version_button_->GetVisible();
-}
-
-bool ChannelIndicatorQuickSettingsView::
-    IsSubmitFeedbackButtonVisibleForTesting() {
-  return feedback_button_ && feedback_button_->GetVisible();
-}
-
 }  // namespace ash
diff --git a/ash/system/channel_indicator/channel_indicator_quick_settings_view.h b/ash/system/channel_indicator/channel_indicator_quick_settings_view.h
index e5f95a6..380c28c 100644
--- a/ash/system/channel_indicator/channel_indicator_quick_settings_view.h
+++ b/ash/system/channel_indicator/channel_indicator_quick_settings_view.h
@@ -23,9 +23,8 @@
       const ChannelIndicatorQuickSettingsView&) = delete;
   ~ChannelIndicatorQuickSettingsView() override = default;
 
-  // Introspection methods for unit tests.
-  bool IsVersionButtonVisibleForTesting();
-  bool IsSubmitFeedbackButtonVisibleForTesting();
+  views::View* version_button_for_test() { return version_button_; }
+  views::View* feedback_button_for_test() { return feedback_button_; }
 
  private:
   // Refs maintained for unit test introspection methods.
diff --git a/ash/system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc b/ash/system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc
index 63f61b6..e1ff049f 100644
--- a/ash/system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc
+++ b/ash/system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc
@@ -4,18 +4,27 @@
 
 #include "ash/system/channel_indicator/channel_indicator_quick_settings_view.h"
 
+#include <tuple>
+
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/test/test_system_tray_client.h"
 #include "ash/test/ash_test_base.h"
+#include "base/test/scoped_feature_list.h"
 #include "components/version_info/channel.h"
+#include "ui/views/widget/widget.h"
 
 namespace ash {
 
+// Parameterized by feature QsRevamp and whether user feedback is enabled.
 class ChannelIndicatorQuickSettingsViewTest
     : public AshTestBase,
-      public testing::WithParamInterface<bool> {
+      public testing::WithParamInterface<std::tuple<bool, bool>> {
  public:
-  ChannelIndicatorQuickSettingsViewTest() = default;
+  ChannelIndicatorQuickSettingsViewTest() {
+    // Param 0 is whether QsRevamp is enabled.
+    feature_list_.InitWithFeatureState(features::kQsRevamp,
+                                       std::get<0>(GetParam()));
+  }
   ChannelIndicatorQuickSettingsViewTest(
       const ChannelIndicatorQuickSettingsViewTest&) = delete;
   ChannelIndicatorQuickSettingsViewTest& operator=(
@@ -26,43 +35,75 @@
   void SetUp() override {
     AshTestBase::SetUp();
 
-    // Param is whether user feedback is allowed.
+    // Param 1 is whether user feedback is allowed.
     system_tray_client_ = GetSystemTrayClient();
-    system_tray_client_->set_user_feedback_enabled(GetParam());
+    system_tray_client_->set_user_feedback_enabled(std::get<1>(GetParam()));
 
     // Instantiate view.
-    view_ = std::make_unique<ChannelIndicatorQuickSettingsView>(
+    auto view = std::make_unique<ChannelIndicatorQuickSettingsView>(
         version_info::Channel::BETA,
         system_tray_client_->IsUserFeedbackEnabled());
+    view_ = view.get();
+
+    // Place the view in a large views::Widget so the buttons are clickable.
+    widget_ = CreateFramelessTestWidget();
+    widget_->SetFullscreen(true);
+    widget_->SetContentsView(std::move(view));
+  }
+
+  void TearDown() override {
+    widget_.reset();
+    AshTestBase::TearDown();
   }
 
   bool IsFeedbackShown() {
     return system_tray_client_->IsUserFeedbackEnabled();
   }
 
-  ChannelIndicatorQuickSettingsView* view() { return view_.get(); }
+  ChannelIndicatorQuickSettingsView* view() { return view_; }
 
  private:
-  TestSystemTrayClient* system_tray_client_;
-  std::unique_ptr<ChannelIndicatorQuickSettingsView> view_;
+  base::test::ScopedFeatureList feature_list_;
+  TestSystemTrayClient* system_tray_client_ = nullptr;
+  std::unique_ptr<views::Widget> widget_;
+  ChannelIndicatorQuickSettingsView* view_ = nullptr;
 };
 
 // Run the `Visible` test below for each value of version_info::Channel.
 INSTANTIATE_TEST_SUITE_P(ChannelValues,
                          ChannelIndicatorQuickSettingsViewTest,
-                         ::testing::Bool());
+                         ::testing::Combine(::testing::Bool(),
+                                            ::testing::Bool()));
 
 TEST_P(ChannelIndicatorQuickSettingsViewTest, Visible) {
   // View exists.
   EXPECT_TRUE(view());
 
   // Version button is always visible.
-  EXPECT_TRUE(view()->IsVersionButtonVisibleForTesting());
+  ASSERT_TRUE(view()->version_button_for_test());
+  EXPECT_TRUE(view()->version_button_for_test()->GetVisible());
 
   // Feedback button is visible if `SystemTrayClient` says the user preference
   // is set that allows user feedback.
-  EXPECT_EQ(view()->IsSubmitFeedbackButtonVisibleForTesting(),
-            IsFeedbackShown());
+  views::View* feedback_button = view()->feedback_button_for_test();
+  if (IsFeedbackShown()) {
+    ASSERT_TRUE(feedback_button);
+    EXPECT_TRUE(feedback_button->GetVisible());
+  } else {
+    ASSERT_FALSE(feedback_button);
+  }
+}
+
+TEST_P(ChannelIndicatorQuickSettingsViewTest, ClickOnButtons) {
+  TestSystemTrayClient* client = GetSystemTrayClient();
+
+  LeftClickOn(view()->version_button_for_test());
+  EXPECT_EQ(1, client->show_channel_info_additional_details_count());
+
+  if (IsFeedbackShown()) {
+    LeftClickOn(view()->feedback_button_for_test());
+    EXPECT_EQ(1, client->show_channel_info_give_feedback_count());
+  }
 }
 
 }  // namespace ash
diff --git a/ash/system/ime_menu/ime_menu_tray_unittest.cc b/ash/system/ime_menu/ime_menu_tray_unittest.cc
index c3d17adb..c392b2e 100644
--- a/ash/system/ime_menu/ime_menu_tray_unittest.cc
+++ b/ash/system/ime_menu/ime_menu_tray_unittest.cc
@@ -144,7 +144,7 @@
     ui::TextInputMethod::InputContext input_context(
         input_type, ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_FLAG_NONE,
         ui::TextInputClient::FOCUS_REASON_OTHER,
-        false /* should_do_learning */);
+        ui::PersonalizationMode::kDisabled);
     ui::IMEBridge::Get()->SetCurrentInputContext(input_context);
   }
 
diff --git a/ash/system/keyboard_brightness/keyboard_backlight_color_controller.cc b/ash/system/keyboard_brightness/keyboard_backlight_color_controller.cc
index 1ff11af5..a85185d7 100644
--- a/ash/system/keyboard_brightness/keyboard_backlight_color_controller.cc
+++ b/ash/system/keyboard_brightness/keyboard_backlight_color_controller.cc
@@ -46,10 +46,12 @@
 KeyboardBacklightColorController::KeyboardBacklightColorController()
     : keyboard_backlight_color_nudge_controller_(
           std::make_unique<KeyboardBacklightColorNudgeController>()) {
-  wallpaper_controller_observation_.Observe(WallpaperController::Get());
+  Shell::Get()->rgb_keyboard_manager()->AddObserver(this);
 }
 
-KeyboardBacklightColorController::~KeyboardBacklightColorController() = default;
+KeyboardBacklightColorController::~KeyboardBacklightColorController() {
+  Shell::Get()->rgb_keyboard_manager()->RemoveObserver(this);
+}
 
 // static
 void KeyboardBacklightColorController::RegisterProfilePrefs(
@@ -73,16 +75,24 @@
   if (account_id.empty())
     return personalization_app::mojom::BacklightColor::kWallpaper;
   auto* pref_service = GetUserPrefService(account_id);
-  if (!pref_service) {
-    // TODO(b/238463679): Migrate to local state pref. There may be a timing
-    // issue that results in null pref service. Defaults to |kWallpaper| when
-    // that happens.
-    return personalization_app::mojom::BacklightColor::kWallpaper;
-  }
+  DCHECK(pref_service);
   return static_cast<personalization_app::mojom::BacklightColor>(
       pref_service->GetInteger(prefs::kPersonalizationKeyboardBacklightColor));
 }
 
+void KeyboardBacklightColorController::OnRgbKeyboardSupportedChanged(
+    bool supported) {
+  if (supported) {
+    if (!session_observer_.IsObserving())
+      session_observer_.Observe(Shell::Get()->session_controller());
+    if (!wallpaper_controller_observation_.IsObserving())
+      wallpaper_controller_observation_.Observe(WallpaperController::Get());
+  } else {
+    session_observer_.Reset();
+    wallpaper_controller_observation_.Reset();
+  }
+}
+
 void KeyboardBacklightColorController::OnSessionStateChanged(
     session_manager::SessionState state) {
   // If we are in OOBE, we should set the backlight to a default of white.
diff --git a/ash/system/keyboard_brightness/keyboard_backlight_color_controller.h b/ash/system/keyboard_brightness/keyboard_backlight_color_controller.h
index 8e5b888d..7c3039b 100644
--- a/ash/system/keyboard_brightness/keyboard_backlight_color_controller.h
+++ b/ash/system/keyboard_brightness/keyboard_backlight_color_controller.h
@@ -9,6 +9,9 @@
 #include "ash/public/cpp/session/session_observer.h"
 #include "ash/public/cpp/wallpaper/wallpaper_controller.h"
 #include "ash/public/cpp/wallpaper/wallpaper_controller_observer.h"
+#include "ash/rgb_keyboard/rgb_keyboard_manager.h"
+#include "ash/rgb_keyboard/rgb_keyboard_manager_observer.h"
+#include "ash/session/session_controller_impl.h"
 #include "ash/webui/personalization_app/mojom/personalization_app.mojom-shared.h"
 #include "base/scoped_observation.h"
 #include "components/session_manager/session_manager_types.h"
@@ -22,7 +25,8 @@
 
 // Controller to manage keyboard backlight colors.
 class ASH_EXPORT KeyboardBacklightColorController
-    : public SessionObserver,
+    : public RgbKeyboardManagerObserver,
+      public SessionObserver,
       public WallpaperControllerObserver {
  public:
   KeyboardBacklightColorController();
@@ -45,6 +49,9 @@
   personalization_app::mojom::BacklightColor GetBacklightColor(
       const AccountId& account_id);
 
+  // RgbKeyboardManagerObserver:
+  void OnRgbKeyboardSupportedChanged(bool supported) override;
+
   // SessionObserver:
   void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
   void OnSessionStateChanged(session_manager::SessionState state) override;
@@ -71,7 +78,8 @@
 
   SkColor displayed_color_for_testing_ = SK_ColorTRANSPARENT;
 
-  ScopedSessionObserver scoped_session_observer_{this};
+  base::ScopedObservation<SessionControllerImpl, SessionObserver>
+      session_observer_{this};
 
   base::ScopedObservation<WallpaperController, WallpaperControllerObserver>
       wallpaper_controller_observation_{this};
diff --git a/ash/system/keyboard_brightness/keyboard_backlight_color_controller_unittest.cc b/ash/system/keyboard_brightness/keyboard_backlight_color_controller_unittest.cc
index 724448ab..21a909c 100644
--- a/ash/system/keyboard_brightness/keyboard_backlight_color_controller_unittest.cc
+++ b/ash/system/keyboard_brightness/keyboard_backlight_color_controller_unittest.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "ash/system/keyboard_brightness/keyboard_backlight_color_controller.h"
+
+#include <memory>
+
 #include "ash/constants/ash_features.h"
 #include "ash/rgb_keyboard/rgb_keyboard_util.h"
 #include "ash/shell.h"
@@ -80,10 +83,16 @@
   void SetUp() override {
     AshTestBase::SetUp();
 
-    controller_ = Shell::Get()->keyboard_backlight_color_controller();
+    controller_ = std::make_unique<KeyboardBacklightColorController>();
+    controller_->OnRgbKeyboardSupportedChanged(true);
     wallpaper_controller_ = Shell::Get()->wallpaper_controller();
   }
 
+  void TearDown() override {
+    controller_.reset();
+    AshTestBase::TearDown();
+  }
+
  protected:
   const base::HistogramTester& histogram_tester() const {
     return histogram_tester_;
@@ -97,7 +106,7 @@
     controller_->displayed_color_for_testing_ = SK_ColorTRANSPARENT;
   }
 
-  KeyboardBacklightColorController* controller_ = nullptr;
+  std::unique_ptr<KeyboardBacklightColorController> controller_;
   WallpaperControllerImpl* wallpaper_controller_ = nullptr;
 
  private:
diff --git a/ash/system/keyboard_brightness/keyboard_backlight_color_nudge_controller_unittest.cc b/ash/system/keyboard_brightness/keyboard_backlight_color_nudge_controller_unittest.cc
index 7d6fbce..b1f8525c 100644
--- a/ash/system/keyboard_brightness/keyboard_backlight_color_nudge_controller_unittest.cc
+++ b/ash/system/keyboard_brightness/keyboard_backlight_color_nudge_controller_unittest.cc
@@ -7,7 +7,6 @@
 #include "ash/controls/contextual_tooltip.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
-#include "ash/system/keyboard_brightness/keyboard_backlight_color_controller.h"
 #include "ash/test/ash_test_base.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
@@ -36,18 +35,7 @@
 
   ~KeyboardBacklightColorNudgeControllerTest() override = default;
 
-  // testing::Test:
-  void SetUp() override {
-    AshTestBase::SetUp();
-
-    controller_ = Shell::Get()
-                      ->keyboard_backlight_color_controller()
-                      ->keyboard_backlight_color_nudge_controller();
-  }
-
  protected:
-  KeyboardBacklightColorNudgeController* controller_ = nullptr;
-
   PrefService* pref_service() {
     return Shell::Get()->session_controller()->GetActivePrefService();
   }
@@ -58,6 +46,8 @@
         contextual_tooltip::TooltipType::kKeyboardBacklightColor, nullptr);
   }
 
+  KeyboardBacklightColorNudgeController controller_;
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
@@ -69,7 +59,7 @@
 
   SimulateUserLogin(account_id_1);
   EXPECT_TRUE(can_show_nudge());
-  controller_->MaybeShowEducationNudge(&anchor_view);
+  controller_.MaybeShowEducationNudge(&anchor_view);
 
   EXPECT_FALSE(can_show_nudge());
 
@@ -83,7 +73,7 @@
   SimulateUserLogin(account_id_1);
   EXPECT_TRUE(can_show_nudge());
 
-  controller_->SetUserPerformedAction();
+  controller_.SetUserPerformedAction();
 
   EXPECT_FALSE(can_show_nudge());
 
diff --git a/ash/system/message_center/message_center_style.h b/ash/system/message_center/message_center_style.h
index 133b734..86e14b5 100644
--- a/ash/system/message_center/message_center_style.h
+++ b/ash/system/message_center/message_center_style.h
@@ -20,7 +20,7 @@
 // TODO(crbug.com/1309551): Get the colors from AshColorProvider once
 // notification supports dark/light mode.
 constexpr SkColor kCountLabelColor = gfx::kGoogleGrey900;
-constexpr SkColor kSeperatorColor = SkColorSetA(SK_ColorBLACK, 0x24);  // 14%
+constexpr SkColor kSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x24);  // 14%
 constexpr SkColor kNotificationBackgroundColor = SK_ColorWHITE;
 constexpr SkColor kUnifiedMenuButtonColorActive =
     SkColorSetRGB(0x25, 0x81, 0xDF);
diff --git a/ash/system/message_center/stacked_notification_bar.cc b/ash/system/message_center/stacked_notification_bar.cc
index 4f777d1..6e37f1e0 100644
--- a/ash/system/message_center/stacked_notification_bar.cc
+++ b/ash/system/message_center/stacked_notification_bar.cc
@@ -530,7 +530,7 @@
     canvas->DrawSharpLine(
         gfx::PointF(bounds.bottom_left() - gfx::Vector2d(0, 1)),
         gfx::PointF(bounds.bottom_right() - gfx::Vector2d(0, 1)),
-        message_center_style::kSeperatorColor);
+        message_center_style::kSeparatorColor);
   }
 }
 
diff --git a/ash/system/message_center/unified_message_center_bubble.cc b/ash/system/message_center/unified_message_center_bubble.cc
index 172f84c5..1c68d3d 100644
--- a/ash/system/message_center/unified_message_center_bubble.cc
+++ b/ash/system/message_center/unified_message_center_bubble.cc
@@ -58,7 +58,7 @@
 
     // Draw a solid rounded rect as the inner border.
     cc::PaintFlags flags;
-    flags.setColor(message_center_style::kSeperatorColor);
+    flags.setColor(message_center_style::kSeparatorColor);
     flags.setStyle(cc::PaintFlags::kStroke_Style);
     flags.setStrokeWidth(canvas->image_scale());
     flags.setAntiAlias(true);
diff --git a/ash/system/message_center/unified_message_list_view.cc b/ash/system/message_center/unified_message_list_view.cc
index 3406c17..258d838 100644
--- a/ash/system/message_center/unified_message_list_view.cc
+++ b/ash/system/message_center/unified_message_list_view.cc
@@ -137,7 +137,7 @@
                     : views::CreateSolidSidedBorder(
                           gfx::Insets::TLBR(
                               0, 0, kUnifiedNotificationSeparatorThickness, 0),
-                          message_center_style::kSeperatorColor));
+                          message_center_style::kSeparatorColor));
     }
 
     const int message_center_notification_corner_radius =
diff --git a/ash/system/network/active_network_icon.cc b/ash/system/network/active_network_icon.cc
index 232cfe4..e23c264 100644
--- a/ash/system/network/active_network_icon.cc
+++ b/ash/system/network/active_network_icon.cc
@@ -10,6 +10,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/network/network_icon.h"
+#include "ash/system/network/network_utils.h"
 #include "ash/system/network/tray_network_state_model.h"
 #include "ash/system/tray/tray_constants.h"
 #include "base/bind.h"
@@ -88,8 +89,14 @@
       *tooltip = activating_string;
   } else if (network && chromeos::network_config::StateIsConnected(
                             network->connection_state)) {
-    std::u16string connected_string = l10n_util::GetStringFUTF16(
-        IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, network_name);
+    std::u16string connected_string;
+    if (auto portal_subtext = GetPortalStateSubtext(network->portal_state)) {
+      connected_string = l10n_util::GetStringFUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_PORTAL, network_name, *portal_subtext);
+    } else {
+      connected_string = l10n_util::GetStringFUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, network_name);
+    }
     std::u16string signal_strength_string;
     if (chromeos::network_config::NetworkTypeMatchesType(
             network->type, NetworkType::kWireless)) {
@@ -123,7 +130,7 @@
                      ? connected_string
                      : l10n_util::GetStringFUTF16(
                            IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED_TOOLTIP,
-                           network_name, signal_strength_string);
+                           connected_string, signal_strength_string);
     }
   } else if (network &&
              network->connection_state == ConnectionStateType::kConnecting) {
diff --git a/ash/system/network/active_network_icon_unittest.cc b/ash/system/network/active_network_icon_unittest.cc
index 2e153db4..942a9792 100644
--- a/ash/system/network/active_network_icon_unittest.cc
+++ b/ash/system/network/active_network_icon_unittest.cc
@@ -190,9 +190,11 @@
   EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED,
                                        kCellularNetworkGuid16),
             name);
+  std::u16string connected_string = l10n_util::GetStringFUTF16(
+      IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, kCellularNetworkGuid16);
   EXPECT_EQ(
       l10n_util::GetStringFUTF16(
-          IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED_TOOLTIP, kCellularNetworkGuid16,
+          IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED_TOOLTIP, connected_string,
           l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_SIGNAL_STRONG)),
       tooltip);
 }
diff --git a/ash/system/network/network_list_network_item_view.cc b/ash/system/network/network_list_network_item_view.cc
index b5e3e74..3e80a91c 100644
--- a/ash/system/network/network_list_network_item_view.cc
+++ b/ash/system/network/network_list_network_item_view.cc
@@ -14,8 +14,10 @@
 #include "ash/style/ash_color_provider.h"
 #include "ash/style/color_util.h"
 #include "ash/system/model/system_tray_model.h"
+#include "ash/system/network/active_network_icon.h"
 #include "ash/system/network/network_icon.h"
 #include "ash/system/network/network_icon_animation.h"
+#include "ash/system/network/network_utils.h"
 #include "ash/system/network/tray_network_state_model.h"
 #include "ash/system/power/power_status.h"
 #include "ash/system/tray/hover_highlight_view.h"
@@ -25,6 +27,7 @@
 #include "base/i18n/number_formatting.h"
 #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/gfx/image/image_skia.h"
@@ -353,30 +356,16 @@
     return;
   }
 
-  if (!ash::features::IsCaptivePortalUI2022Enabled()) {
-    SetupConnectedScrollListItem(this);
-    return;
+  if (ash::features::IsCaptivePortalUI2022Enabled()) {
+    absl::optional<std::u16string> portal_subtext =
+        GetPortalStateSubtext(network_properties()->portal_state);
+    if (portal_subtext) {
+      SetWarningSubText(this, *portal_subtext);
+      return;
+    }
   }
 
-  switch (network_properties()->portal_state) {
-    // Portal state is portal or proxy auth, setup signin subtext.
-    case PortalState::kPortal:
-    case PortalState::kProxyAuthRequired:
-      SetWarningSubText(this, l10n_util::GetStringUTF16(
-                                  IDS_ASH_STATUS_TRAY_NETWORK_STATUS_SIGNIN));
-      return;
-    // Portal state is portal-suspected or no internet, setup no internet
-    // subtext.
-    case PortalState::kPortalSuspected:
-    case PortalState::kNoInternet:
-      SetWarningSubText(
-          this, l10n_util::GetStringUTF16(
-                    IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED_NO_INTERNET));
-      return;
-    default:
-      SetupConnectedScrollListItem(this);
-      return;
-  }
+  SetupConnectedScrollListItem(this);
 }
 
 void NetworkListNetworkItemView::UpdateDisabledTextColor() {
@@ -426,6 +415,13 @@
 
 std::u16string NetworkListNetworkItemView::GenerateAccessibilityLabel(
     const std::u16string& label) {
+  absl::optional<std::u16string> portal_subtext =
+      GetPortalStateSubtext(network_properties()->portal_state);
+  if (portal_subtext) {
+    return l10n_util::GetStringFUTF16(
+        IDS_ASH_STATUS_TRAY_NETWORK_A11Y_LABEL_SUBTEXT, label, *portal_subtext);
+  }
+
   if (IsNetworkConnectable(network_properties())) {
     return l10n_util::GetStringFUTF16(
         IDS_ASH_STATUS_TRAY_NETWORK_A11Y_LABEL_CONNECT, label);
@@ -449,8 +445,14 @@
   std::u16string connection_status;
 
   if (StateIsConnected(network_properties()->connection_state)) {
-    connection_status =
-        l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
+    absl::optional<std::u16string> portal_subtext =
+        GetPortalStateSubtext(network_properties()->portal_state);
+    if (portal_subtext) {
+      connection_status = *portal_subtext;
+    } else {
+      connection_status = l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
+    }
   } else if (network_properties()->connection_state ==
              ConnectionStateType::kConnecting) {
     connection_status = l10n_util::GetStringUTF16(
@@ -586,4 +588,4 @@
 BEGIN_METADATA(NetworkListNetworkItemView, NetworkListItemView)
 END_METADATA
 
-}  // namespace ash
\ No newline at end of file
+}  // namespace ash
diff --git a/ash/system/network/network_list_network_item_view_unittest.cc b/ash/system/network/network_list_network_item_view_unittest.cc
index c87ff15..d8c56722 100644
--- a/ash/system/network/network_list_network_item_view_unittest.cc
+++ b/ash/system/network/network_list_network_item_view_unittest.cc
@@ -107,6 +107,10 @@
     return {OncSource::kDevicePolicy, OncSource::kNone};
   }
 
+  std::vector<PortalState> GetPortalStates() {
+    return {PortalState::kPortal, PortalState::kNoInternet};
+  }
+
   const NetworkListItemView* LastClickedNetworkListItem() {
     return fake_network_detailed_network_view_
         ->last_clicked_network_list_item();
@@ -125,7 +129,7 @@
   }
 
   void AssertA11yDescription(NetworkStatePropertiesPtr& network_properties,
-                             const std::u16string& description) {
+                             const std::u16string& expected_description) {
     ui::AXNodeData node_data;
     UpdateViewForNetwork(network_properties);
     network_list_network_item_view()
@@ -133,7 +137,7 @@
         .GetAccessibleNodeData(&node_data);
     std::string a11ydescription =
         node_data.GetStringAttribute(ax::mojom::StringAttribute::kDescription);
-    EXPECT_EQ(base::UTF8ToUTF16(a11ydescription), description);
+    EXPECT_EQ(base::UTF8ToUTF16(a11ydescription), expected_description);
   }
 
   void NetworkIconChanged() {
@@ -757,6 +761,111 @@
   }
 }
 
+TEST_F(NetworkListNetworkItemViewTest, HasExpectedDescriptionForWiFiWithFlag) {
+  feature_list_.Reset();
+  feature_list_.InitWithFeatures(
+      /*enabled_features=*/{features::kCaptivePortalUI2022,
+                            features::kQuickSettingsNetworkRevamp},
+      /*disabled_features=*/{});
+
+  SecurityType security_types[2] = {SecurityType::kNone, SecurityType::kWepPsk};
+
+  NetworkStatePropertiesPtr wifi_network = CreateStandaloneNetworkProperties(
+      kWiFiName, NetworkType::kWiFi, ConnectionStateType::kConnected);
+
+  for (const auto& security : security_types) {
+    wifi_network->type_state->get_wifi()->security = security;
+    const std::u16string security_label = l10n_util::GetStringUTF16(
+        security == SecurityType::kWepPsk
+            ? IDS_ASH_STATUS_TRAY_NETWORK_STATUS_SECURED
+            : IDS_ASH_STATUS_TRAY_NETWORK_STATUS_UNSECURED);
+
+    for (const auto& connection : GetConnectionStateTypes()) {
+      wifi_network->connection_state = connection;
+      wifi_network->portal_state = PortalState::kUnknown;  // default
+      std::u16string connection_status;
+      int desc_id;
+      for (const auto& policy : GetPolicies()) {
+        wifi_network->source = policy;
+        // Set desc_id for portal, online, connecting
+        switch (policy) {
+          case OncSource::kDevicePolicy:
+            desc_id =
+                IDS_ASH_STATUS_TRAY_WIFI_NETWORK_A11Y_DESC_MANAGED_WITH_CONNECTION_STATUS;
+            break;
+          case OncSource::kNone:
+            desc_id =
+                IDS_ASH_STATUS_TRAY_WIFI_NETWORK_A11Y_DESC_WITH_CONNECTION_STATUS;
+            break;
+          default:
+            NOTREACHED();
+        }
+        switch (connection) {
+          case ConnectionStateType::kPortal: {
+            for (const auto& portal_state : GetPortalStates()) {
+              wifi_network->portal_state = portal_state;
+              switch (portal_state) {
+                case PortalState::kPortal:
+                  connection_status = l10n_util::GetStringUTF16(
+                      IDS_ASH_STATUS_TRAY_NETWORK_STATUS_SIGNIN);
+                  break;
+                case PortalState::kNoInternet:
+                  connection_status = l10n_util::GetStringUTF16(
+                      IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED_NO_INTERNET);
+                  break;
+                default:
+                  NOTREACHED();
+              }
+              AssertA11yDescription(
+                  wifi_network, l10n_util::GetStringFUTF16(
+                                    desc_id, security_label, connection_status,
+                                    base::FormatPercent(kSignalStrength)));
+            }
+            break;
+          }
+          case ConnectionStateType::kConnected:
+            [[fallthrough]];
+          case ConnectionStateType::kOnline: {
+            connection_status = l10n_util::GetStringUTF16(
+                IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED);
+            AssertA11yDescription(
+                wifi_network, l10n_util::GetStringFUTF16(
+                                  desc_id, security_label, connection_status,
+                                  base::FormatPercent(kSignalStrength)));
+            break;
+          }
+          case ConnectionStateType::kConnecting: {
+            connection_status = l10n_util::GetStringUTF16(
+                IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING);
+            AssertA11yDescription(
+                wifi_network, l10n_util::GetStringFUTF16(
+                                  desc_id, security_label, connection_status,
+                                  base::FormatPercent(kSignalStrength)));
+            break;
+          }
+          case ConnectionStateType::kNotConnected: {
+            switch (policy) {
+              case OncSource::kDevicePolicy:
+                desc_id = IDS_ASH_STATUS_TRAY_WIFI_NETWORK_A11Y_DESC_MANAGED;
+                break;
+              case OncSource::kNone:
+                desc_id = IDS_ASH_STATUS_TRAY_WIFI_NETWORK_A11Y_DESC;
+                break;
+              default:
+                NOTREACHED();
+            }
+            AssertA11yDescription(wifi_network,
+                                  l10n_util::GetStringFUTF16(
+                                      desc_id, security_label,
+                                      base::FormatPercent(kSignalStrength)));
+            break;
+          }
+        }
+      }
+    }
+  }
+}
+
 TEST_F(NetworkListNetworkItemViewTest, NetworkIconAnimating) {
   NetworkStatePropertiesPtr wifi_network = CreateStandaloneNetworkProperties(
       kWiFiName, NetworkType::kWiFi, ConnectionStateType::kConnecting);
diff --git a/ash/system/network/network_list_view_controller_impl.cc b/ash/system/network/network_list_view_controller_impl.cc
index 862c0e0..005ce2f 100644
--- a/ash/system/network/network_list_view_controller_impl.cc
+++ b/ash/system/network/network_list_view_controller_impl.cc
@@ -354,10 +354,10 @@
 
   if (separator_view == &wifi_separator_view_) {
     separator->SetID(
-        static_cast<int>(NetworkListViewControllerViewChildId::kWifiSeperator));
+        static_cast<int>(NetworkListViewControllerViewChildId::kWifiSeparator));
   } else if (separator_view == &mobile_separator_view_) {
     separator->SetID(static_cast<int>(
-        NetworkListViewControllerViewChildId::kMobileSeperator));
+        NetworkListViewControllerViewChildId::kMobileSeparator));
   } else {
     NOTREACHED();
   }
diff --git a/ash/system/network/network_list_view_controller_impl.h b/ash/system/network/network_list_view_controller_impl.h
index d3ef55b..837cc70d 100644
--- a/ash/system/network/network_list_view_controller_impl.h
+++ b/ash/system/network/network_list_view_controller_impl.h
@@ -58,10 +58,10 @@
   enum class NetworkListViewControllerViewChildId {
     kConnectionWarning = 11,
     kConnectionWarningLabel = 12,
-    kMobileSeperator = 13,
+    kMobileSeparator = 13,
     kMobileStatusMessage = 14,
     kMobileSectionHeader = 15,
-    kWifiSeperator = 16,
+    kWifiSeparator = 16,
     kWifiSectionHeader = 17,
     kWifiStatusMessage = 18,
   };
diff --git a/ash/system/network/network_list_view_controller_unittest.cc b/ash/system/network/network_list_view_controller_unittest.cc
index 33eb867a..0172688 100644
--- a/ash/system/network/network_list_view_controller_unittest.cc
+++ b/ash/system/network/network_list_view_controller_unittest.cc
@@ -240,7 +240,7 @@
   views::Separator* GetMobileSeparator() {
     return FindViewById<views::Separator*>(
         NetworkListViewControllerImpl::NetworkListViewControllerViewChildId::
-            kMobileSeperator);
+            kMobileSeparator);
   }
 
   FakeNetworkListWifiHeaderView* GetWifiSubHeader() {
@@ -252,7 +252,7 @@
   views::Separator* GetWifiSeparator() {
     return FindViewById<views::Separator*>(
         NetworkListViewControllerImpl::NetworkListViewControllerViewChildId::
-            kWifiSeperator);
+            kWifiSeparator);
   }
 
   TrayInfoLabel* GetMobileStatusMessage() {
diff --git a/ash/system/network/network_utils.cc b/ash/system/network/network_utils.cc
index bde80dd6..998eb6e 100644
--- a/ash/system/network/network_utils.cc
+++ b/ash/system/network/network_utils.cc
@@ -4,8 +4,11 @@
 
 #include "ash/system/network/network_utils.h"
 
+#include "ash/constants/ash_features.h"
+#include "ash/strings/grit/ash_strings.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/strcat.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace ash {
 
@@ -54,4 +57,30 @@
       new_state);
 }
 
-}  // namespace ash
\ No newline at end of file
+absl::optional<std::u16string> GetPortalStateSubtext(
+    const chromeos::network_config::mojom::PortalState& portal_state) {
+  if (!ash::features::IsCaptivePortalUI2022Enabled()) {
+    return absl::nullopt;
+  }
+  using chromeos::network_config::mojom::PortalState;
+  switch (portal_state) {
+    case PortalState::kUnknown:
+      [[fallthrough]];
+    case PortalState::kOnline:
+      return absl::nullopt;
+    case PortalState::kPortalSuspected:
+      [[fallthrough]];
+    case PortalState::kNoInternet:
+      // Use 'no internet' for portal suspected and no internet states.
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED_NO_INTERNET);
+    case PortalState::kPortal:
+      [[fallthrough]];
+    case PortalState::kProxyAuthRequired:
+      // Use 'signin to network' for portal and proxy auth required states.
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_NETWORK_STATUS_SIGNIN);
+  }
+}
+
+}  // namespace ash
diff --git a/ash/system/network/network_utils.h b/ash/system/network/network_utils.h
index 8e638bdad..8d8c795 100644
--- a/ash/system/network/network_utils.h
+++ b/ash/system/network/network_utils.h
@@ -7,6 +7,7 @@
 
 #include "ash/ash_export.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace ash {
 
@@ -40,6 +41,11 @@
     chromeos::network_config::mojom::NetworkType network_type,
     bool new_state);
 
+// Returns the subtext to display for a connected network in a portal state.
+// This is used in the network menu, the tooltip, and for a11y.
+ASH_EXPORT absl::optional<std::u16string> GetPortalStateSubtext(
+    const chromeos::network_config::mojom::PortalState& portal_state);
+
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_NETWORK_NETWORK_UTILS_H_
\ No newline at end of file
+#endif  // ASH_SYSTEM_NETWORK_NETWORK_UTILS_H_
diff --git a/ash/system/privacy/privacy_indicators_tray_item_view_unittest.cc b/ash/system/privacy/privacy_indicators_tray_item_view_unittest.cc
index a764c13..cbde258 100644
--- a/ash/system/privacy/privacy_indicators_tray_item_view_unittest.cc
+++ b/ash/system/privacy/privacy_indicators_tray_item_view_unittest.cc
@@ -399,7 +399,7 @@
             privacy_indicators_view()->GetPreferredSize().height());
 }
 
-TEST_F(PrivacyIndicatorsTrayItemViewTest, StateChangeDuringAnimation) {
+TEST_F(PrivacyIndicatorsTrayItemViewTest, DISABLED_StateChangeDuringAnimation) {
   SetViewVisibleWithAnimation();
   double progress = 0.5;
 
@@ -431,6 +431,10 @@
   privacy_indicators_view()->UpdateScreenShareStatus(
       /*is_screen_sharing=*/false);
   EXPECT_FALSE(privacy_indicators_view()->GetVisible());
+
+  // Clean up.
+  longer_side_shrink_animation()->End();
+  shorter_side_shrink_animation()->End();
 }
 
 TEST_F(PrivacyIndicatorsTrayItemViewTest, MultipleAppsAccess) {
diff --git a/ash/system/tray/detailed_view_delegate.cc b/ash/system/tray/detailed_view_delegate.cc
index 4c976893..f6e0dcd 100644
--- a/ash/system/tray/detailed_view_delegate.cc
+++ b/ash/system/tray/detailed_view_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/tray/detailed_view_delegate.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
@@ -28,6 +29,8 @@
 
 namespace {
 
+constexpr int kQsItemBetweenSpacing = 8;
+
 void ConfigureTitleTriView(TriView* tri_view, TriView::Container container) {
   std::unique_ptr<views::BoxLayout> layout;
 
@@ -39,7 +42,9 @@
                                    : 0;
       layout = std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kHorizontal,
-          gfx::Insets::TLBR(0, left_padding, 0, 0), kUnifiedTopShortcutSpacing);
+          gfx::Insets::TLBR(0, left_padding, 0, 0),
+          features::IsQsRevampEnabled() ? kQsItemBetweenSpacing
+                                        : kUnifiedTopShortcutSpacing);
       layout->set_main_axis_alignment(
           views::BoxLayout::MainAxisAlignment::kCenter);
       layout->set_cross_axis_alignment(
@@ -53,6 +58,11 @@
           views::BoxLayout::Orientation::kVertical);
       layout->set_main_axis_alignment(
           views::BoxLayout::MainAxisAlignment::kCenter);
+      if (features::IsQsRevampEnabled()) {
+        layout->set_cross_axis_alignment(
+            views::BoxLayout::CrossAxisAlignment::kCenter);
+        break;
+      }
       layout->set_cross_axis_alignment(
           views::BoxLayout::CrossAxisAlignment::kStretch);
       break;
@@ -63,27 +73,6 @@
                        gfx::Size(0, kUnifiedDetailedViewTitleRowHeight));
 }
 
-class BackButton : public IconButton {
- public:
-  BackButton(views::Button::PressedCallback callback)
-      : IconButton(std::move(callback),
-                   IconButton::Type::kSmallFloating,
-                   &kUnifiedMenuExpandIcon,
-                   IDS_ASH_STATUS_TRAY_PREVIOUS_MENU) {}
-  BackButton(const BackButton&) = delete;
-  BackButton& operator=(const BackButton&) = delete;
-  ~BackButton() override = default;
-
-  // Use the same icon as CollapseButton with rotation.
-  void PaintButtonContents(gfx::Canvas* canvas) override {
-    gfx::ScopedCanvas scoped(canvas);
-    canvas->Translate(gfx::Vector2d(size().width() / 2, size().height() / 2));
-    canvas->sk_canvas()->rotate(-90);
-    gfx::ImageSkia image = GetImageToPaint();
-    canvas->DrawImageInt(image, -image.width() / 2, -image.height() / 2);
-  }
-};
-
 }  // namespace
 
 DetailedViewDelegate::DetailedViewDelegate(
@@ -171,9 +160,15 @@
   return item;
 }
 
+// TODO(b/253091169): Refactor the following creating buttons methods to return
+// unique pointers.
 views::Button* DetailedViewDelegate::CreateBackButton(
     views::Button::PressedCallback callback) {
-  return new BackButton(std::move(callback));
+  return new IconButton(
+      std::move(callback),
+      features::IsQsRevampEnabled() ? IconButton::Type::kSmall
+                                    : IconButton::Type::kSmallFloating,
+      &kQuickSettingsBackIcon, IDS_ASH_STATUS_TRAY_PREVIOUS_MENU);
 }
 
 views::Button* DetailedViewDelegate::CreateInfoButton(
diff --git a/ash/system/tray/tray_detailed_view.cc b/ash/system/tray/tray_detailed_view.cc
index 43056bd..3aa9b18 100644
--- a/ash/system/tray/tray_detailed_view.cc
+++ b/ash/system/tray/tray_detailed_view.cc
@@ -77,6 +77,12 @@
   }
 
   void PaintChildren(const views::PaintInfo& paint_info) override {
+    // No sticky header and no shadow for the revamped view.
+    if (features::IsQsRevampEnabled()) {
+      views::View::PaintChildren(paint_info);
+      return;
+    }
+
     int sticky_header_height = 0;
     for (const auto& header : headers_) {
       // Sticky header is at the top.
@@ -125,6 +131,11 @@
 
   void Layout() override {
     views::View::Layout();
+
+    // No sticky headers for the revamped view.
+    if (features::IsQsRevampEnabled())
+      return;
+
     headers_.clear();
     for (auto* child : children()) {
       if (child->GetID() == VIEW_ID_STICKY_HEADER)
@@ -278,6 +289,9 @@
       views::BoxLayout::Orientation::kVertical));
   SetBackground(views::CreateSolidBackground(
       delegate_->GetBackgroundColor().value_or(SK_ColorTRANSPARENT)));
+
+  if (features::IsQsRevampEnabled())
+    IgnoreSeparator();
 }
 
 TrayDetailedView::~TrayDetailedView() = default;
@@ -314,6 +328,28 @@
   }
 
   CreateExtraTitleRowButtons();
+
+  if (!features::IsQsRevampEnabled()) {
+    Layout();
+    return;
+  }
+  // Makes the `tri_view_`'s `START` and `END`container have the same width,
+  // so the header text will be in the center of the `QuickSettingsView`
+  // horizontally.
+  auto* start_view =
+      tri_view_->children()[static_cast<size_t>(TriView::Container::START)];
+  auto* end_view =
+      tri_view_->children()[static_cast<size_t>(TriView::Container::END)];
+  int start_width = start_view->GetPreferredSize().width();
+  int end_width = end_view->GetPreferredSize().width();
+  if (start_width < end_width) {
+    start_view->SetBorder(views::CreateEmptyBorder(
+        gfx::Insets::TLBR(0, 0, 0, end_width - start_width)));
+  } else {
+    end_view->SetBorder(views::CreateEmptyBorder(
+        gfx::Insets::TLBR(0, start_width - end_width, 0, 0)));
+  }
+
   Layout();
 }
 
diff --git a/ash/system/tray/tray_item_view.cc b/ash/system/tray/tray_item_view.cc
index 2891688..b23ed7d 100644
--- a/ash/system/tray/tray_item_view.cc
+++ b/ash/system/tray/tray_item_view.cc
@@ -65,7 +65,7 @@
     return Label::GetAccessibleNodeData(node_data);
 
   node_data->role = ax::mojom::Role::kStaticText;
-  node_data->SetName(custom_accessible_name_);
+  node_data->SetNameChecked(custom_accessible_name_);
 }
 
 TrayItemView::TrayItemView(Shelf* shelf)
diff --git a/ash/system/unified/buttons.cc b/ash/system/unified/buttons.cc
index 2f22d75..c28669c2 100644
--- a/ash/system/unified/buttons.cc
+++ b/ash/system/unified/buttons.cc
@@ -7,18 +7,29 @@
 #include "ash/constants/ash_features.h"
 #include "ash/constants/quick_settings_catalogs.h"
 #include "ash/public/cpp/ash_view_ids.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/system/model/enterprise_domain_model.h"
+#include "ash/system/model/system_tray_model.h"
 #include "ash/system/power/power_status.h"
+#include "ash/system/supervised/supervised_icon_string.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/unified/quick_settings_metrics_util.h"
 #include "ash/system/unified/unified_system_tray_controller.h"
 #include "base/functional/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chromeos/strings/grit/chromeos_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/chromeos/devicetype_utils.h"
 #include "ui/compositor/layer.h"
+#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/animation/ink_drop.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/image_view.h"
@@ -42,6 +53,14 @@
   label->GetViewAccessibility().OverrideIsIgnored(true);
 }
 
+// Shows enterprise managed device information.
+void ShowEnterpriseInfo(UnifiedSystemTrayController* controller,
+                        const ui::Event& event) {
+  quick_settings_metrics_util::RecordQsButtonActivated(
+      QsButtonCatalogName::kManagedButton);
+  controller->HandleEnterpriseInfoAction();
+}
+
 }  // namespace
 
 BatteryInfoViewBase::BatteryInfoViewBase(
@@ -90,10 +109,10 @@
       views::BoxLayout::Orientation::kHorizontal));
 
   percentage_ = AddChildView(std::make_unique<views::Label>());
-  auto seperator = std::make_unique<views::Label>();
-  seperator->SetText(
+  auto separator = std::make_unique<views::Label>();
+  separator->SetText(
       l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_STATUS_SEPARATOR));
-  separator_view_ = AddChildView(std::move(seperator));
+  separator_view_ = AddChildView(std::move(separator));
   status_ = AddChildView(std::make_unique<views::Label>());
   Update();
 }
@@ -196,4 +215,144 @@
 BEGIN_METADATA(BatteryIconView, BatteryInfoViewBase)
 END_METADATA
 
+////////////////////////////////////////////////////////////////////////////////
+
+ManagedStateView::ManagedStateView(PressedCallback callback,
+                                   int label_id,
+                                   const gfx::VectorIcon& icon)
+    : Button(std::move(callback)), icon_(icon) {
+  auto* layout_manager = SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
+      kUnifiedSystemInfoSpacing));
+
+  label_ = AddChildView(std::make_unique<views::Label>());
+  label_->SetAutoColorReadabilityEnabled(false);
+  label_->SetSubpixelRenderingEnabled(false);
+  label_->SetText(l10n_util::GetStringUTF16(label_id));
+
+  image_ = AddChildView(std::make_unique<views::ImageView>());
+  image_->SetPreferredSize(
+      gfx::Size(kUnifiedSystemInfoHeight, kUnifiedSystemInfoHeight));
+
+  // Shrink the label if needed so the icon fits.
+  layout_manager->SetFlexForView(label_, 1);
+
+  SetInstallFocusRingOnFocus(true);
+  views::FocusRing::Get(this)->SetColorId(ui::kColorAshFocusRing);
+  views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF);
+}
+
+views::View* ManagedStateView::GetTooltipHandlerForPoint(
+    const gfx::Point& point) {
+  // Tooltip events should be handled by this top-level view.
+  return HitTestPoint(point) ? this : nullptr;
+}
+
+void ManagedStateView::OnThemeChanged() {
+  views::Button::OnThemeChanged();
+  label_->SetEnabledColor(GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kTextColorSecondary));
+  image_->SetImage(gfx::CreateVectorIcon(
+      icon_, GetContentLayerColor(
+                 AshColorProvider::ContentLayerType::kIconColorSecondary)));
+}
+
+BEGIN_METADATA(ManagedStateView, views::Button)
+END_METADATA
+
+////////////////////////////////////////////////////////////////////////////////
+
+EnterpriseManagedView::EnterpriseManagedView(
+    UnifiedSystemTrayController* controller)
+    : ManagedStateView(base::BindRepeating(&ShowEnterpriseInfo,
+                                           base::Unretained(controller)),
+                       IDS_ASH_ENTERPRISE_DEVICE_MANAGED_SHORT,
+                       kUnifiedMenuManagedIcon) {
+  DCHECK(Shell::Get());
+  SetID(VIEW_ID_QS_MANAGED_BUTTON);
+  Shell::Get()->system_tray_model()->enterprise_domain()->AddObserver(this);
+  Shell::Get()->session_controller()->AddObserver(this);
+  Update();
+}
+
+EnterpriseManagedView::~EnterpriseManagedView() {
+  Shell::Get()->system_tray_model()->enterprise_domain()->RemoveObserver(this);
+  Shell::Get()->session_controller()->RemoveObserver(this);
+}
+
+void EnterpriseManagedView::OnDeviceEnterpriseInfoChanged() {
+  Update();
+}
+
+void EnterpriseManagedView::OnEnterpriseAccountDomainChanged() {
+  Update();
+}
+
+void EnterpriseManagedView::OnLoginStatusChanged(LoginStatus status) {
+  Update();
+}
+
+void EnterpriseManagedView::Update() {
+  EnterpriseDomainModel* model =
+      Shell::Get()->system_tray_model()->enterprise_domain();
+  SessionControllerImpl* session_controller =
+      Shell::Get()->session_controller();
+  std::string enterprise_domain_manager = model->enterprise_domain_manager();
+  std::string account_domain_manager = model->account_domain_manager();
+
+  bool visible = session_controller->ShouldDisplayManagedUI() ||
+                 model->active_directory_managed() ||
+                 !enterprise_domain_manager.empty() ||
+                 !account_domain_manager.empty();
+  SetVisible(visible);
+
+  if (!visible)
+    return;
+
+  // Display both device and user management if the feature is enabled.
+  std::u16string managed_string;
+  if (enterprise_domain_manager.empty() && account_domain_manager.empty()) {
+    managed_string = l10n_util::GetStringFUTF16(
+        IDS_ASH_ENTERPRISE_DEVICE_MANAGED, ui::GetChromeOSDeviceName());
+  } else if (!enterprise_domain_manager.empty() &&
+             !account_domain_manager.empty() &&
+             enterprise_domain_manager != account_domain_manager) {
+    managed_string =
+        l10n_util::GetStringFUTF16(IDS_ASH_SHORT_MANAGED_BY_MULTIPLE,
+                                   base::UTF8ToUTF16(enterprise_domain_manager),
+                                   base::UTF8ToUTF16(account_domain_manager));
+  } else {
+    std::u16string display_domain_manager =
+        enterprise_domain_manager.empty()
+            ? base::UTF8ToUTF16(account_domain_manager)
+            : base::UTF8ToUTF16(enterprise_domain_manager);
+    managed_string = l10n_util::GetStringFUTF16(IDS_ASH_SHORT_MANAGED_BY,
+                                                display_domain_manager);
+  }
+  SetTooltipText(managed_string);
+}
+
+BEGIN_METADATA(EnterpriseManagedView, ManagedStateView)
+END_METADATA
+
+////////////////////////////////////////////////////////////////////////////////
+
+SupervisedUserView::SupervisedUserView()
+    : ManagedStateView(PressedCallback(),
+                       IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL,
+                       GetSupervisedUserIcon()) {
+  bool visible = Shell::Get()->session_controller()->IsUserChild();
+  SetVisible(visible);
+  if (visible)
+    SetTooltipText(GetSupervisedUserMessage());
+
+  // TODO(crbug/1026821) Add SupervisedUserView::ButtonPress() overload
+  // to show a similar ui to enterprise managed accounts. Disable button
+  // state for now.
+  SetState(ButtonState::STATE_DISABLED);
+}
+
+BEGIN_METADATA(SupervisedUserView, ManagedStateView)
+END_METADATA
+
 }  // namespace ash
diff --git a/ash/system/unified/buttons.h b/ash/system/unified/buttons.h
index 4280e56..79769ec 100644
--- a/ash/system/unified/buttons.h
+++ b/ash/system/unified/buttons.h
@@ -5,6 +5,8 @@
 #ifndef ASH_SYSTEM_UNIFIED_BUTTONS_H_
 #define ASH_SYSTEM_UNIFIED_BUTTONS_H_
 
+#include "ash/public/cpp/session/session_observer.h"
+#include "ash/system/enterprise/enterprise_domain_observer.h"
 #include "ash/system/power/power_status.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/button/button.h"
@@ -106,6 +108,69 @@
   views::Label* percentage_ = nullptr;
   views::ImageView* battery_image_ = nullptr;
 };
+
+// A base class of the views showing device management state.
+class ManagedStateView : public views::Button {
+ public:
+  METADATA_HEADER(ManagedStateView);
+
+  ManagedStateView(const ManagedStateView&) = delete;
+  ManagedStateView& operator=(const ManagedStateView&) = delete;
+  ~ManagedStateView() override = default;
+
+ protected:
+  ManagedStateView(PressedCallback callback,
+                   int label_id,
+                   const gfx::VectorIcon& icon);
+
+ private:
+  // views::Button:
+  views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
+  void OnThemeChanged() override;
+
+  // Owned by views hierarchy.
+  views::Label* label_ = nullptr;
+  views::ImageView* image_ = nullptr;
+
+  const gfx::VectorIcon& icon_;
+};
+
+// A view that shows whether the device is enterprise managed or not. It updates
+// by observing EnterpriseDomainModel.
+class EnterpriseManagedView : public ManagedStateView,
+                              public EnterpriseDomainObserver,
+                              public SessionObserver {
+ public:
+  METADATA_HEADER(EnterpriseManagedView);
+
+  explicit EnterpriseManagedView(UnifiedSystemTrayController* controller);
+  EnterpriseManagedView(const EnterpriseManagedView&) = delete;
+  EnterpriseManagedView& operator=(const EnterpriseManagedView&) = delete;
+  ~EnterpriseManagedView() override;
+
+ private:
+  // EnterpriseDomainObserver:
+  void OnDeviceEnterpriseInfoChanged() override;
+  void OnEnterpriseAccountDomainChanged() override;
+
+  // SessionObserver:
+  void OnLoginStatusChanged(LoginStatus status) override;
+
+  // Updates the view visibility and displayed string.
+  void Update();
+};
+
+// A view that shows whether the user is supervised or a child.
+class SupervisedUserView : public ManagedStateView {
+ public:
+  METADATA_HEADER(SupervisedUserView);
+
+  SupervisedUserView();
+  SupervisedUserView(const SupervisedUserView&) = delete;
+  SupervisedUserView& operator=(const SupervisedUserView&) = delete;
+  ~SupervisedUserView() override = default;
+};
+
 }  // namespace ash
 
 #endif  // ASH_SYSTEM_UNIFIED_BUTTONS_H_
diff --git a/ash/system/unified/quick_settings_header.cc b/ash/system/unified/quick_settings_header.cc
index 2d28556..1ac9e39 100644
--- a/ash/system/unified/quick_settings_header.cc
+++ b/ash/system/unified/quick_settings_header.cc
@@ -7,14 +7,24 @@
 #include <memory>
 
 #include "ash/constants/ash_features.h"
-#include "ash/style/pill_button.h"
+#include "ash/public/cpp/system_tray_client.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
+#include "ash/shell_delegate.h"
+#include "ash/system/channel_indicator/channel_indicator_quick_settings_view.h"
+#include "ash/system/channel_indicator/channel_indicator_utils.h"
+#include "ash/system/model/system_tray_model.h"
+#include "components/session_manager/session_manager_types.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/views/layout/box_layout.h"
 
 namespace ash {
 namespace {
 
-constexpr gfx::Insets kQuickSettingsHeaderPadding(16);
+// The bottom padding is 0 so this view is flush with the feature tiles.
+constexpr auto kHeaderPadding = gfx::Insets::TLBR(16, 16, 0, 16);
+
+constexpr int kBetweenChildSpacing = 8;
 
 }  // namespace
 
@@ -22,17 +32,36 @@
   DCHECK(features::IsQsRevampEnabled());
 
   auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kVertical, kQuickSettingsHeaderPadding));
+      views::BoxLayout::Orientation::kVertical, kHeaderPadding,
+      kBetweenChildSpacing));
   layout->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::kStretch);
 
-  // TODO(b/251724754): Remove this temporary placeholder.
-  placeholder_ = AddChildView(std::make_unique<PillButton>(
-      PillButton::PressedCallback(), u"Placeholder"));
+  // If the release track is not "stable" then show the channel indicator UI.
+  auto channel = Shell::Get()->shell_delegate()->GetChannel();
+  if (channel_indicator_utils::IsDisplayableChannel(channel) &&
+      Shell::Get()->session_controller()->GetSessionState() ==
+          session_manager::SessionState::ACTIVE) {
+    channel_view_ =
+        AddChildView(std::make_unique<ChannelIndicatorQuickSettingsView>(
+            channel, Shell::Get()
+                         ->system_tray_model()
+                         ->client()
+                         ->IsUserFeedbackEnabled()));
+  }
+
+  UpdateVisibility();
 }
 
 QuickSettingsHeader::~QuickSettingsHeader() = default;
 
+void QuickSettingsHeader::UpdateVisibility() {
+  // TODO(b/251724754): Update condition when enterprise management view is
+  // added.
+  bool should_show = !!channel_view_;
+  SetVisible(should_show);
+}
+
 BEGIN_METADATA(QuickSettingsHeader, views::View)
 END_METADATA
 
diff --git a/ash/system/unified/quick_settings_header.h b/ash/system/unified/quick_settings_header.h
index 9634f2b5..00adaca2 100644
--- a/ash/system/unified/quick_settings_header.h
+++ b/ash/system/unified/quick_settings_header.h
@@ -10,10 +10,11 @@
 
 namespace ash {
 
-class PillButton;
+class ChannelIndicatorQuickSettingsView;
 
 // The header view shown at the top of the `QuickSettingsView`. Contains an
-// optional "Managed by" button and an optional release channel indicator.
+// optional "Managed by" button and an optional release channel indicator. Sets
+// itself invisible when its child views do not need to be shown.
 class ASH_EXPORT QuickSettingsHeader : public views::View {
  public:
   METADATA_HEADER(QuickSettingsHeader);
@@ -23,9 +24,16 @@
   QuickSettingsHeader& operator=(const QuickSettingsHeader&) = delete;
   ~QuickSettingsHeader() override;
 
+  ChannelIndicatorQuickSettingsView* channel_view_for_test() {
+    return channel_view_;
+  }
+
  private:
-  // TODO(b/251724754): Remove this temporary placeholder.
-  PillButton* placeholder_ = nullptr;
+  // Updates visibility for this view. When it has no children it sets itself
+  // invisible so it does not consume any space.
+  void UpdateVisibility();
+
+  ChannelIndicatorQuickSettingsView* channel_view_ = nullptr;
 };
 
 }  // namespace ash
diff --git a/ash/system/unified/quick_settings_header_unittest.cc b/ash/system/unified/quick_settings_header_unittest.cc
index 87cbea7..91c689e0 100644
--- a/ash/system/unified/quick_settings_header_unittest.cc
+++ b/ash/system/unified/quick_settings_header_unittest.cc
@@ -8,22 +8,60 @@
 
 #include "ash/constants/ash_features.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test_shell_delegate.h"
 #include "base/test/scoped_feature_list.h"
+#include "components/version_info/channel.h"
 
 namespace ash {
 
-class QuickSettingsHeaderTest : public AshTestBase {
+class QuickSettingsHeaderTest : public NoSessionAshTestBase {
  public:
   QuickSettingsHeaderTest() {
     feature_list_.InitAndEnableFeature(features::kQsRevamp);
   }
 
+  // AshTestBase:
+  void SetUp() override {
+    // Install a test delegate to allow overriding channel version.
+    auto delegate = std::make_unique<TestShellDelegate>();
+    test_shell_delegate_ = delegate.get();
+    AshTestBase::SetUp(std::move(delegate));
+  }
+
   base::test::ScopedFeatureList feature_list_;
+  TestShellDelegate* test_shell_delegate_ = nullptr;
 };
 
-TEST_F(QuickSettingsHeaderTest, Construction) {
+TEST_F(QuickSettingsHeaderTest, HiddenByDefaultBeforeLogin) {
   QuickSettingsHeader header;
-  // No crash.
+
+  // By default, channel view is not created.
+  EXPECT_FALSE(header.channel_view_for_test());
+
+  // Since no views are created, the header is hidden.
+  EXPECT_FALSE(header.GetVisible());
+}
+
+TEST_F(QuickSettingsHeaderTest, DoesNotShowChannelViewBeforeLogin) {
+  test_shell_delegate_->set_channel(version_info::Channel::BETA);
+
+  QuickSettingsHeader header;
+
+  EXPECT_FALSE(header.channel_view_for_test());
+  EXPECT_FALSE(header.GetVisible());
+}
+
+TEST_F(QuickSettingsHeaderTest, ShowsChannelViewAfterLogin) {
+  test_shell_delegate_->set_channel(version_info::Channel::BETA);
+  SimulateUserLogin("user@gmail.com");
+
+  QuickSettingsHeader header;
+
+  // Channel view is created.
+  EXPECT_TRUE(header.channel_view_for_test());
+
+  // Header is shown.
+  EXPECT_TRUE(header.GetVisible());
 }
 
 }  // namespace ash
diff --git a/ash/system/unified/top_shortcuts_view.cc b/ash/system/unified/top_shortcuts_view.cc
index aeac37f..0d2210e 100644
--- a/ash/system/unified/top_shortcuts_view.cc
+++ b/ash/system/unified/top_shortcuts_view.cc
@@ -62,48 +62,6 @@
   ~UserAvatarButton() override = default;
 };
 
-auto avatar_button_lambda = [](UnifiedSystemTrayController* controller,
-                               const ui::Event& event) {
-  quick_settings_metrics_util::RecordQsButtonActivated(
-      QsButtonCatalogName::kAvatarButton);
-  controller->ShowUserChooserView();
-};
-
-auto sign_out_button_lambda = [](UnifiedSystemTrayController* controller,
-                                 const ui::Event& event) {
-  quick_settings_metrics_util::RecordQsButtonActivated(
-      QsButtonCatalogName::kSignOutButton);
-  controller->HandleSignOutAction();
-};
-
-auto power_button_lambda = [](UnifiedSystemTrayController* controller,
-                              const ui::Event& event) {
-  quick_settings_metrics_util::RecordQsButtonActivated(
-      QsButtonCatalogName::kPowerButton);
-  controller->HandlePowerAction();
-};
-
-auto lock_button_lambda = [](UnifiedSystemTrayController* controller,
-                             const ui::Event& event) {
-  quick_settings_metrics_util::RecordQsButtonActivated(
-      QsButtonCatalogName::kLockButton);
-  controller->HandleLockAction();
-};
-
-auto settings_button_lambda = [](UnifiedSystemTrayController* controller,
-                                 const ui::Event& event) {
-  quick_settings_metrics_util::RecordQsButtonActivated(
-      QsButtonCatalogName::kSettingsButton);
-  controller->HandleSettingsAction();
-};
-
-auto collapse_button_lambda = [](UnifiedSystemTrayController* controller,
-                                 const ui::Event& event) {
-  quick_settings_metrics_util::RecordQsButtonActivated(
-      QsButtonCatalogName::kCollapseButton);
-  controller->ToggleExpanded();
-};
-
 }  // namespace
 
 TopShortcutButtonContainer::TopShortcutButtonContainer() = default;
@@ -226,15 +184,25 @@
   if (!is_on_login_screen) {
     user_avatar_button_ = button_container->AddUserAvatarButton(
         std::make_unique<UserAvatarButton>(base::BindRepeating(
-            avatar_button_lambda, base::Unretained(controller))));
+            [](UnifiedSystemTrayController* controller) {
+              quick_settings_metrics_util::RecordQsButtonActivated(
+                  QsButtonCatalogName::kAvatarButton);
+              controller->ShowUserChooserView();
+            },
+            base::Unretained(controller))));
     user_avatar_button_->SetEnabled(
         UserChooserDetailedViewController::IsUserChooserEnabled());
     user_avatar_button_->SetID(VIEW_ID_QS_USER_AVATAR_BUTTON);
 
     sign_out_button_ =
         button_container->AddSignOutButton(std::make_unique<PillButton>(
-            base::BindRepeating(sign_out_button_lambda,
-                                base::Unretained(controller)),
+            base::BindRepeating(
+                [](UnifiedSystemTrayController* controller) {
+                  quick_settings_metrics_util::RecordQsButtonActivated(
+                      QsButtonCatalogName::kSignOutButton);
+                  controller->HandleSignOutAction();
+                },
+                base::Unretained(controller)),
             user::GetLocalizedSignOutStringForStatus(
                 Shell::Get()->session_controller()->login_status(),
                 /*multiline=*/false),
@@ -244,14 +212,26 @@
   }
   bool reboot = shell->shutdown_controller()->reboot_on_shutdown();
   power_button_ = button_container->AddChildView(std::make_unique<IconButton>(
-      base::BindRepeating(power_button_lambda, base::Unretained(controller)),
+      base::BindRepeating(
+          [](UnifiedSystemTrayController* controller) {
+            quick_settings_metrics_util::RecordQsButtonActivated(
+                QsButtonCatalogName::kPowerButton);
+            controller->HandlePowerAction();
+          },
+          base::Unretained(controller)),
       IconButton::Type::kSmall, &kUnifiedMenuPowerIcon,
       reboot ? IDS_ASH_STATUS_TRAY_REBOOT : IDS_ASH_STATUS_TRAY_SHUTDOWN));
   power_button_->SetID(VIEW_ID_QS_POWER_BUTTON);
 
   if (can_show_settings && can_lock_screen) {
     lock_button_ = button_container->AddChildView(std::make_unique<IconButton>(
-        base::BindRepeating(lock_button_lambda, base::Unretained(controller)),
+        base::BindRepeating(
+            [](UnifiedSystemTrayController* controller) {
+              quick_settings_metrics_util::RecordQsButtonActivated(
+                  QsButtonCatalogName::kLockButton);
+              controller->HandleLockAction();
+            },
+            base::Unretained(controller)),
         IconButton::Type::kSmall, &kUnifiedMenuLockIcon,
         IDS_ASH_STATUS_TRAY_LOCK));
     lock_button_->SetID(VIEW_ID_QS_LOCK_BUTTON);
@@ -260,8 +240,13 @@
   if (can_show_settings) {
     settings_button_ =
         button_container->AddChildView(std::make_unique<IconButton>(
-            base::BindRepeating(settings_button_lambda,
-                                base::Unretained(controller)),
+            base::BindRepeating(
+                [](UnifiedSystemTrayController* controller) {
+                  quick_settings_metrics_util::RecordQsButtonActivated(
+                      QsButtonCatalogName::kSettingsButton);
+                  controller->HandleSettingsAction();
+                },
+                base::Unretained(controller)),
             IconButton::Type::kSmall, &vector_icons::kSettingsOutlineIcon,
             IDS_ASH_STATUS_TRAY_SETTINGS));
     settings_button_->SetID(VIEW_ID_QS_SETTINGS_BUTTON);
@@ -286,7 +271,12 @@
   auto collapse_button_container = std::make_unique<views::View>();
   collapse_button_ = collapse_button_container->AddChildView(
       std::make_unique<CollapseButton>(base::BindRepeating(
-          collapse_button_lambda, base::Unretained(controller))));
+          [](UnifiedSystemTrayController* controller) {
+            quick_settings_metrics_util::RecordQsButtonActivated(
+                QsButtonCatalogName::kCollapseButton);
+            controller->ToggleExpanded();
+          },
+          base::Unretained(controller))));
   collapse_button_->SetID(VIEW_ID_QS_COLLAPSE_BUTTON);
   const gfx::Size collapse_button_size = collapse_button_->GetPreferredSize();
   collapse_button_container->SetPreferredSize(
diff --git a/ash/system/unified/unified_system_info_view.cc b/ash/system/unified/unified_system_info_view.cc
index 158f7a5..2620ee4 100644
--- a/ash/system/unified/unified_system_info_view.cc
+++ b/ash/system/unified/unified_system_info_view.cc
@@ -7,9 +7,7 @@
 #include "ash/constants/ash_features.h"
 #include "ash/constants/quick_settings_catalogs.h"
 #include "ash/public/cpp/ash_view_ids.h"
-#include "ash/public/cpp/session/session_observer.h"
 #include "ash/public/cpp/system_tray_client.h"
-#include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
@@ -17,14 +15,11 @@
 #include "ash/style/ash_color_provider.h"
 #include "ash/system/channel_indicator/channel_indicator_quick_settings_view.h"
 #include "ash/system/channel_indicator/channel_indicator_utils.h"
-#include "ash/system/enterprise/enterprise_domain_observer.h"
 #include "ash/system/model/clock_model.h"
 #include "ash/system/model/clock_observer.h"
-#include "ash/system/model/enterprise_domain_model.h"
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/power/adaptive_charging_controller.h"
 #include "ash/system/power/power_status.h"
-#include "ash/system/supervised/supervised_icon_string.h"
 #include "ash/system/time/calendar_metrics.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/tray/tray_popup_utils.h"
@@ -33,20 +28,15 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/i18n/time_formatting.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
-#include "chromeos/strings/grit/chromeos_strings.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/chromeos/devicetype_utils.h"
 #include "ui/color/color_id.h"
-#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/animation/ink_drop.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/focus_ring.h"
-#include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/separator.h"
 #include "ui/views/layout/box_layout.h"
@@ -191,204 +181,6 @@
   Update();
 }
 
-// A base class of the views showing device management state.
-class ManagedStateView : public views::Button {
- public:
-  ManagedStateView(const ManagedStateView&) = delete;
-  ManagedStateView& operator=(const ManagedStateView&) = delete;
-
-  ~ManagedStateView() override = default;
-
-  // views::Button:
-  views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
-  const char* GetClassName() const override { return "ManagedStateView"; }
-  void OnThemeChanged() override;
-
- protected:
-  ManagedStateView(PressedCallback callback,
-                   int label_id,
-                   const gfx::VectorIcon& icon);
-
- private:
-  views::Label* label_ = nullptr;
-  views::ImageView* image_ = nullptr;
-  const gfx::VectorIcon& icon_;
-};
-
-views::View* ManagedStateView::GetTooltipHandlerForPoint(
-    const gfx::Point& point) {
-  // Tooltip events should be handled by this top-level view.
-  return HitTestPoint(point) ? this : nullptr;
-}
-
-void ManagedStateView::OnThemeChanged() {
-  views::Button::OnThemeChanged();
-  auto* color_provider = AshColorProvider::Get();
-  label_->SetEnabledColor(color_provider->GetContentLayerColor(
-      ContentLayerType::kTextColorSecondary));
-  image_->SetImage(
-      gfx::CreateVectorIcon(icon_, color_provider->GetContentLayerColor(
-                                       ContentLayerType::kIconColorSecondary)));
-}
-
-ManagedStateView::ManagedStateView(PressedCallback callback,
-                                   int label_id,
-                                   const gfx::VectorIcon& icon)
-    : Button(std::move(callback)), icon_(icon) {
-  auto* layout_manager = SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
-      kUnifiedSystemInfoSpacing));
-
-  label_ = AddChildView(std::make_unique<views::Label>());
-  label_->SetAutoColorReadabilityEnabled(false);
-  label_->SetSubpixelRenderingEnabled(false);
-  label_->SetText(l10n_util::GetStringUTF16(label_id));
-
-  image_ = AddChildView(std::make_unique<views::ImageView>());
-  image_->SetPreferredSize(
-      gfx::Size(kUnifiedSystemInfoHeight, kUnifiedSystemInfoHeight));
-
-  // Shrink the label if needed so the icon fits.
-  layout_manager->SetFlexForView(label_, 1);
-
-  SetInstallFocusRingOnFocus(true);
-  views::FocusRing::Get(this)->SetColorId(ui::kColorAshFocusRing);
-  views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF);
-}
-
-// A view that shows whether the device is enterprise managed or not. It updates
-// by observing EnterpriseDomainModel.
-class EnterpriseManagedView : public ManagedStateView,
-                              public EnterpriseDomainObserver,
-                              public SessionObserver {
- public:
-  explicit EnterpriseManagedView(UnifiedSystemTrayController* controller);
-
-  EnterpriseManagedView(const EnterpriseManagedView&) = delete;
-  EnterpriseManagedView& operator=(const EnterpriseManagedView&) = delete;
-
-  ~EnterpriseManagedView() override;
-
-  // EnterpriseDomainObserver:
-  void OnDeviceEnterpriseInfoChanged() override;
-  void OnEnterpriseAccountDomainChanged() override;
-
-  // SessionObserver:
-  void OnLoginStatusChanged(LoginStatus status) override;
-
-  // views::Button:
-  const char* GetClassName() const override { return "EnterpriseManagedView"; }
-
- private:
-  void Update();
-};
-
-auto managed_button_lambda = [](UnifiedSystemTrayController* controller,
-                                const ui::Event& event) {
-  quick_settings_metrics_util::RecordQsButtonActivated(
-      QsButtonCatalogName::kManagedButton);
-  controller->HandleEnterpriseInfoAction();
-};
-
-EnterpriseManagedView::EnterpriseManagedView(
-    UnifiedSystemTrayController* controller)
-    : ManagedStateView(base::BindRepeating(managed_button_lambda,
-                                           base::Unretained(controller)),
-                       IDS_ASH_ENTERPRISE_DEVICE_MANAGED_SHORT,
-                       kUnifiedMenuManagedIcon) {
-  DCHECK(Shell::Get());
-  SetID(VIEW_ID_QS_MANAGED_BUTTON);
-  Shell::Get()->system_tray_model()->enterprise_domain()->AddObserver(this);
-  Shell::Get()->session_controller()->AddObserver(this);
-  Update();
-}
-
-EnterpriseManagedView::~EnterpriseManagedView() {
-  Shell::Get()->system_tray_model()->enterprise_domain()->RemoveObserver(this);
-  Shell::Get()->session_controller()->RemoveObserver(this);
-}
-
-void EnterpriseManagedView::OnDeviceEnterpriseInfoChanged() {
-  Update();
-}
-
-void EnterpriseManagedView::OnEnterpriseAccountDomainChanged() {
-  Update();
-}
-
-void EnterpriseManagedView::OnLoginStatusChanged(LoginStatus status) {
-  Update();
-}
-
-void EnterpriseManagedView::Update() {
-  EnterpriseDomainModel* model =
-      Shell::Get()->system_tray_model()->enterprise_domain();
-  SessionControllerImpl* session_controller =
-      Shell::Get()->session_controller();
-  std::string enterprise_domain_manager = model->enterprise_domain_manager();
-  std::string account_domain_manager = model->account_domain_manager();
-
-  bool visible = session_controller->ShouldDisplayManagedUI() ||
-                 model->active_directory_managed() ||
-                 !enterprise_domain_manager.empty() ||
-                 !account_domain_manager.empty();
-  SetVisible(visible);
-
-  if (!visible)
-    return;
-
-  // Display both device and user management if the feature is enabled.
-  std::u16string managed_string;
-  if (enterprise_domain_manager.empty() && account_domain_manager.empty()) {
-    managed_string = l10n_util::GetStringFUTF16(
-        IDS_ASH_ENTERPRISE_DEVICE_MANAGED, ui::GetChromeOSDeviceName());
-  } else if (!enterprise_domain_manager.empty() &&
-             !account_domain_manager.empty() &&
-             enterprise_domain_manager != account_domain_manager) {
-    managed_string =
-        l10n_util::GetStringFUTF16(IDS_ASH_SHORT_MANAGED_BY_MULTIPLE,
-                                   base::UTF8ToUTF16(enterprise_domain_manager),
-                                   base::UTF8ToUTF16(account_domain_manager));
-  } else {
-    std::u16string display_domain_manager =
-        enterprise_domain_manager.empty()
-            ? base::UTF8ToUTF16(account_domain_manager)
-            : base::UTF8ToUTF16(enterprise_domain_manager);
-    managed_string = l10n_util::GetStringFUTF16(IDS_ASH_SHORT_MANAGED_BY,
-                                                display_domain_manager);
-  }
-  SetTooltipText(managed_string);
-}
-
-// A view that shows whether the user is supervised or a child.
-class SupervisedUserView : public ManagedStateView {
- public:
-  SupervisedUserView();
-
-  SupervisedUserView(const SupervisedUserView&) = delete;
-  SupervisedUserView& operator=(const SupervisedUserView&) = delete;
-
-  ~SupervisedUserView() override = default;
-
-  // views::Button:
-  const char* GetClassName() const override { return "SupervisedUserView"; }
-};
-
-SupervisedUserView::SupervisedUserView()
-    : ManagedStateView(PressedCallback(),
-                       IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL,
-                       GetSupervisedUserIcon()) {
-  bool visible = Shell::Get()->session_controller()->IsUserChild();
-  SetVisible(visible);
-  if (visible)
-    SetTooltipText(GetSupervisedUserMessage());
-
-  // TODO(crbug/1026821) Add SupervisedUserView::ButtonPress() overload
-  // to show a similar ui to enterprise managed accounts. Disable button
-  // state for now.
-  SetState(ButtonState::STATE_DISABLED);
-}
-
 }  // namespace
 
 // A view that contains date, battery status, and whether the device
diff --git a/ash/webui/common/resources/BUILD.gn b/ash/webui/common/resources/BUILD.gn
index bdc7ad0a..3246600a 100644
--- a/ash/webui/common/resources/BUILD.gn
+++ b/ash/webui/common/resources/BUILD.gn
@@ -107,6 +107,7 @@
   "cr_picture/webcam_utils.js",
   "cr_policy_indicator_behavior.js",
   "cr_scrollable_behavior.js",
+  "event_tracker.js",
   "focus_row_js.js",
   "focus_row_behavior.js",
   "focus_without_ink_js.js",
@@ -278,6 +279,7 @@
   "cr_picture/icons.html.js",
   "cr_picture/png.js",
   "cr_picture/webcam_utils.js",
+  "event_tracker.js",
   "focus_row_js.js",
   "focus_without_ink_js.js",
   "keyboard_shortcut_list_js.js",
@@ -400,6 +402,7 @@
 js_type_check("closure_compile_local") {
   is_polymer3 = true
   deps = [
+    ":event_tracker",
     ":fake_method_resolver",
     ":fake_observables",
     ":focus_row_behavior",
@@ -432,6 +435,9 @@
   ]
 }
 
+js_library("event_tracker") {
+}
+
 js_library("fake_observables") {
   deps = [ "//ui/webui/resources/js:cr.m" ]
 }
@@ -442,8 +448,8 @@
 
 js_library("focus_row_js") {
   deps = [
+    ":event_tracker",
     "//ui/webui/resources/js:assert",
-    "//ui/webui/resources/js:event_tracker",
     "//ui/webui/resources/js:util",
   ]
 }
diff --git a/ash/webui/common/resources/event_tracker.js b/ash/webui/common/resources/event_tracker.js
new file mode 100644
index 0000000..df43f7a6e
--- /dev/null
+++ b/ash/webui/common/resources/event_tracker.js
@@ -0,0 +1,94 @@
+// Copyright 2011 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview EventTracker is a simple class that manages the addition and
+ * removal of DOM event listeners. In particular, it keeps track of all
+ * listeners that have been added and makes it easy to remove some or all of
+ * them without requiring all the information again. This is particularly handy
+ * when the listener is a generated function such as a lambda or the result of
+ * calling Function.bind.
+ * Note: This file is deprecated in favor of the TypeScript version at
+ * ui/webui/resources/js/event_tracker.ts. The TypeScript version should be used
+ * in all TypeScript code, and can also be used by JavaScript code that is not
+ * typechecked with closure compiler.
+ */
+
+export class EventTracker {
+  /**
+   * Create an EventTracker to track a set of events.
+   * EventTracker instances are typically tied 1:1 with other objects or
+   * DOM elements whose listeners should be removed when the object is
+   * disposed or the corresponding elements are removed from the DOM.
+   */
+  constructor() {
+    /**
+     * @type {Array<EventTrackerEntry>}
+     * @private
+     */
+    this.listeners_ = [];
+  }
+
+  /**
+   * Add an event listener - replacement for EventTarget.addEventListener.
+   * @param {!EventTarget} target The DOM target to add a listener to.
+   * @param {string} eventType The type of event to subscribe to.
+   * @param {EventListener|Function} listener The listener to add.
+   * @param {boolean=} capture Whether to invoke during the capture phase.
+   */
+  add(target, eventType, listener, capture = false) {
+    const h = {
+      target: target,
+      eventType: eventType,
+      listener: listener,
+      capture: capture,
+    };
+    this.listeners_.push(h);
+    target.addEventListener(eventType, listener, capture);
+  }
+
+  /**
+   * Remove any specified event listeners added with this EventTracker.
+   * @param {!EventTarget} target The DOM target to remove a listener from.
+   * @param {?string} eventType The type of event to remove.
+   */
+  remove(target, eventType) {
+    this.listeners_ = this.listeners_.filter(listener => {
+      if (listener.target === target &&
+          (!eventType || (listener.eventType === eventType))) {
+        EventTracker.removeEventListener(listener);
+        return false;
+      }
+      return true;
+    });
+  }
+
+  /** Remove all event listeners added with this EventTracker. */
+  removeAll() {
+    this.listeners_.forEach(
+        listener => EventTracker.removeEventListener(listener));
+    this.listeners_ = [];
+  }
+
+  /**
+   * Remove a single event listener given it's tracking entry. It's up to the
+   * caller to ensure the entry is removed from listeners_.
+   * @param {EventTrackerEntry} entry The entry describing the listener to
+   * remove.
+   */
+  static removeEventListener(entry) {
+    entry.target.removeEventListener(
+        entry.eventType, entry.listener, entry.capture);
+  }
+}
+
+/**
+ * The type of the internal tracking entry.
+ * @typedef {{target: !EventTarget,
+ *            eventType: string,
+ *            listener: (EventListener|Function),
+ *            capture: boolean}}
+ */
+let EventTrackerEntry;
+
diff --git a/ash/webui/common/resources/focus_row_js.js b/ash/webui/common/resources/focus_row_js.js
index e831488..ebe2706 100644
--- a/ash/webui/common/resources/focus_row_js.js
+++ b/ash/webui/common/resources/focus_row_js.js
@@ -8,7 +8,7 @@
 
 // clang-format off
 import {assert, assertInstanceof} from 'chrome://resources/js/assert.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.js';
+import {EventTracker} from './event_tracker.js';
 import {hasKeyModifiers, isRTL} from 'chrome://resources/js/util.js';
 // clang-format on
 
diff --git a/ash/webui/diagnostics_ui/resources/drawing_provider.ts b/ash/webui/diagnostics_ui/resources/drawing_provider.ts
index 304d984..83b752e 100644
--- a/ash/webui/diagnostics_ui/resources/drawing_provider.ts
+++ b/ash/webui/diagnostics_ui/resources/drawing_provider.ts
@@ -20,11 +20,26 @@
  * touchpad tester to draw on screen.
  */
 interface DrawingProvider {
-  // For touchscreen tester to draw a trail on screen.
+  /**
+   * For touchscreen tester to draw a trail on screen. A trail is connected by
+   * multiple lines. This function essentially draws a line by connecting two
+   * points.
+   * @param x0 The x coordinate of the first point.
+   * @param y0 The y coordinate of the first point.
+   * @param x1 The x coordinate of the second point.
+   * @param y1 The y coordinate of the second point.
+   * @param pressure The pressure of the touch to indicate the opacity of the
+   *     trail.
+   */
   drawTrail(x0: number, y0: number, x1: number, y1: number, pressure: number):
       void;
 
-  // For touchscreen tester to draw a trial mark on screen.
+  /**
+   * For touchscreen tester to draw a trail starting or ending mark on screen.
+   * A mark is essentially a circle on screen.
+   * @param x The x coordinate of the circle center.
+   * @param y The y coordinate of the circle center.
+   */
   drawTrailMark(x: number, y: number): void;
 }
 
diff --git a/ash/webui/os_feedback_ui/resources/file_attachment.html b/ash/webui/os_feedback_ui/resources/file_attachment.html
index 256f218..a92269d 100644
--- a/ash/webui/os_feedback_ui/resources/file_attachment.html
+++ b/ash/webui/os_feedback_ui/resources/file_attachment.html
@@ -56,13 +56,6 @@
     width: 0;
   }
 
-  #selectedFileImage {
-    display: block;
-    height: auto;
-    transition: all 250ms ease;
-    width: 68px;
-  }
-
   #selectedFileImage:hover {
     opacity: 0.7;
   }
@@ -105,7 +98,7 @@
   #selectedFileImage {
     border-radius: 0 4px 4px 0;
     display: block;
-    height: 48px;
+    height: 46px;
     transition: all 250ms ease;
     width: 68px;
   }
diff --git a/ash/webui/os_feedback_ui/resources/share_data_page.html b/ash/webui/os_feedback_ui/resources/share_data_page.html
index 2fa46227..0af1bbb5 100644
--- a/ash/webui/os_feedback_ui/resources/share_data_page.html
+++ b/ash/webui/os_feedback_ui/resources/share_data_page.html
@@ -67,7 +67,7 @@
   #screenshotImage {
     border-radius: 0 4px 4px 0;
     display: block;
-    height: 48px;
+    height: 46px;
     transition: all 250ms ease;
     width: 68px;
   }
diff --git a/ash/webui/personalization_app/resources/BUILD.gn b/ash/webui/personalization_app/resources/BUILD.gn
index 1468275..6a6d63c 100644
--- a/ash/webui/personalization_app/resources/BUILD.gn
+++ b/ash/webui/personalization_app/resources/BUILD.gn
@@ -88,6 +88,7 @@
   "js/personalization_theme_element.ts",
   "js/personalization_toast_element.ts",
   "js/personalization_breadcrumb_element.ts",
+  "js/theme/theme_header_element.ts",
   "js/user/avatar_camera_element.ts",
   "js/user/avatar_list_element.ts",
   "js/user/user_preview_element.ts",
@@ -204,6 +205,7 @@
   deps = [
     "//third_party/polymer/v3_0:library",
     "//ui/webui/resources:library",
+    "//ui/webui/resources/cr_components/color_change_listener:build_ts",
     "//ui/webui/resources/mojo:library",
   ]
 
diff --git a/ash/webui/personalization_app/resources/js/personalization_app.ts b/ash/webui/personalization_app/resources/js/personalization_app.ts
index 204090c..e117cbe 100644
--- a/ash/webui/personalization_app/resources/js/personalization_app.ts
+++ b/ash/webui/personalization_app/resources/js/personalization_app.ts
@@ -28,6 +28,7 @@
 import './personalization_breadcrumb_element.js';
 import './personalization_main_element.js';
 import './personalization_theme_element.js';
+import './theme/theme_header_element.js';
 import './user/avatar_camera_element.js';
 import './user/avatar_list_element.js';
 import './user/user_preview_element.js';
@@ -78,6 +79,7 @@
 export {PersonalizationToastElement} from './personalization_toast_element.js';
 export {setDarkModeEnabledAction, SetDarkModeEnabledAction, ThemeActionName, ThemeActions} from './theme/theme_actions.js';
 export {setThemeProviderForTesting} from './theme/theme_interface_provider.js';
+export {ThemeHeader} from './theme/theme_header_element.js';
 export {ThemeObserver} from './theme/theme_observer.js';
 export {AvatarCamera, AvatarCameraMode} from './user/avatar_camera_element.js';
 export {AvatarList} from './user/avatar_list_element.js';
diff --git a/ash/webui/personalization_app/resources/js/personalization_theme_element.html b/ash/webui/personalization_app/resources/js/personalization_theme_element.html
index a5fc9b9..a7c811dc 100644
--- a/ash/webui/personalization_app/resources/js/personalization_theme_element.html
+++ b/ash/webui/personalization_app/resources/js/personalization_theme_element.html
@@ -42,9 +42,14 @@
   }
 </style>
 <div id="container">
-  <div id="themeLabel">
-    <h2>$i18n{themeLabel}</h2>
-  </div>
+  <template is="dom-if" if="[[!isJellyEnabled_]]">
+    <div id="themeLabel">
+      <h2>$i18n{themeLabel}</h2>
+    </div>
+  </template>
+  <template is="dom-if" if="[[isJellyEnabled_]]">
+    <theme-header></theme-header>
+  </template>
   <iron-a11y-keys id="keys" keys="left right" on-keys-pressed="onKeysPress_">
   </iron-a11y-keys>
   <iron-selector id="selector" selected="0"
diff --git a/ash/webui/personalization_app/resources/js/personalization_theme_element.ts b/ash/webui/personalization_app/resources/js/personalization_theme_element.ts
index e327c16..f53a28da 100644
--- a/ash/webui/personalization_app/resources/js/personalization_theme_element.ts
+++ b/ash/webui/personalization_app/resources/js/personalization_theme_element.ts
@@ -15,6 +15,7 @@
 import '../css/cros_button_style.css.js';
 
 import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {IronA11yKeysElement} from 'chrome://resources/polymer/v3_0/iron-a11y-keys/iron-a11y-keys.js';
 import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
 
@@ -52,6 +53,10 @@
         type: Boolean,
         value: null,
       },
+      isJellyEnabled_: {
+        type: Boolean,
+        value: loadTimeData.getBoolean('isJellyEnabled'),
+      },
 
       /** The button currently highlighted by keyboard navigation. */
       selectedButton_: {
diff --git a/ash/webui/personalization_app/resources/js/theme/theme_header_element.html b/ash/webui/personalization_app/resources/js/theme/theme_header_element.html
new file mode 100644
index 0000000..138d5e8e
--- /dev/null
+++ b/ash/webui/personalization_app/resources/js/theme/theme_header_element.html
@@ -0,0 +1,30 @@
+<style include="common">
+  :host {
+    color: var(--cros-text-color-primary);
+    font: var(--personalization-app-label-font);
+  }
+
+  #theme-header {
+    align-items: center;
+    display: flex;
+    margin-bottom: 16px;
+  }
+
+  #theme-title {
+    flex-grow: 1;
+  }
+
+  #dynamic-color-toggle-description {
+    font-weight: var(--cros-body-1-font-weight);
+    margin-inline-end: 12px;
+  }
+</style>
+<div id="theme-header">
+  <!-- TODO(b/253089237): Add the final translated text. -->
+  <div id="theme-title">[temp]Theme color</div>
+  <!-- TODO(b/253089237): Add the final translated text. -->
+  <div id="dynamic-color-toggle-description">[temp]Auto</div>
+  <!-- TODO(b/253089237): Add the translated aria label. -->
+  <cr-toggle id="dynamic-color-toggle" checked="{{checked}}">
+  </cr-toggle>
+</div>
diff --git a/ash/webui/personalization_app/resources/js/theme/theme_header_element.ts b/ash/webui/personalization_app/resources/js/theme/theme_header_element.ts
new file mode 100644
index 0000000..3d98aa8
--- /dev/null
+++ b/ash/webui/personalization_app/resources/js/theme/theme_header_element.ts
@@ -0,0 +1,39 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview This component displays the theme header and a toggle button.
+ */
+
+import '../../css/common.css.js';
+import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js';
+
+import {WithPersonalizationStore} from '../personalization_store.js';
+
+import {getTemplate} from './theme_header_element.html.js';
+
+export class ThemeHeader extends WithPersonalizationStore {
+  static get is() {
+    return 'theme-header';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      checked: {
+        type: Boolean,
+        value: true,
+        notify: true,
+        reflectToAttribute: true,
+      },
+    };
+  }
+
+  checked: boolean;
+}
+
+customElements.define(ThemeHeader.is, ThemeHeader);
diff --git a/ash/webui/print_management/resources/.eslintrc.js b/ash/webui/print_management/resources/.eslintrc.js
new file mode 100644
index 0000000..bcb22a6c
--- /dev/null
+++ b/ash/webui/print_management/resources/.eslintrc.js
@@ -0,0 +1,35 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Disable clang-format because it produces odd formatting.
+// clang-format off
+module.exports = {
+  'parserOptions': {
+    'project': ['./tsconfig_base.json'],
+  },
+  'rules': {
+    '@typescript-eslint/explicit-function-return-type': ['error'],
+  },
+  'overrides': [{
+    'files': ['**/*.ts'],
+    'parser':
+      '../../../../third_party/node/node_modules/@typescript-eslint/parser',
+    'parserOptions': {
+      tsconfigRootDir: __dirname,
+    },
+    'plugins': ['@typescript-eslint'],
+    'rules': {
+      '@typescript-eslint/naming-convention':
+        ['error',
+          {
+            selector: ['classMethod', 'classProperty'],
+            format: ['camelCase'],
+            modifiers: ['private'],
+            trailingUnderscore: 'forbid',
+          },
+        ],
+    },
+  }],
+};
+// clang-format on
\ No newline at end of file
diff --git a/ash/webui/print_management/resources/mojo_interface_provider.ts b/ash/webui/print_management/resources/mojo_interface_provider.ts
index ca934b00..258ef49 100644
--- a/ash/webui/print_management/resources/mojo_interface_provider.ts
+++ b/ash/webui/print_management/resources/mojo_interface_provider.ts
@@ -7,7 +7,7 @@
 let metadataProvider: PrintingMetadataProviderInterface|null = null;
 
 export function setMetadataProviderForTesting(
-    testProvider: PrintingMetadataProviderInterface) {
+    testProvider: PrintingMetadataProviderInterface): void {
   metadataProvider = testProvider;
 }
 
diff --git a/ash/webui/print_management/resources/print_job_clear_history_dialog.html b/ash/webui/print_management/resources/print_job_clear_history_dialog.html
index ff180748..9927e41 100644
--- a/ash/webui/print_management/resources/print_job_clear_history_dialog.html
+++ b/ash/webui/print_management/resources/print_job_clear_history_dialog.html
@@ -39,11 +39,11 @@
     </div>
   </div>
   <div slot="button-container">
-    <cr-button id="cancelButton" on-click="onCancelButtonClick_">
+    <cr-button id="cancelButton" on-click="onCancelButtonClick">
       [[i18n('cancelButtonLabel')]]
     </cr-button>
-    <cr-button class="action-button" on-click="onClearButtonClick_"
-        disabled="[[shouldDisableClearButton_]]">
+    <cr-button class="action-button" on-click="onClearButtonClick"
+        disabled="[[shouldDisableClearButton]]">
       [[i18n('clearButtonLabel')]]
     </cr-button>
   </div>
diff --git a/ash/webui/print_management/resources/print_job_clear_history_dialog.ts b/ash/webui/print_management/resources/print_job_clear_history_dialog.ts
index 92191e7..89029e1d 100644
--- a/ash/webui/print_management/resources/print_job_clear_history_dialog.ts
+++ b/ash/webui/print_management/resources/print_job_clear_history_dialog.ts
@@ -8,6 +8,7 @@
 
 import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
+import {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getMetadataProvider} from './mojo_interface_provider.js';
@@ -27,43 +28,43 @@
 
 class PrintJobClearHistoryDialogElement extends
     PrintJobClearHistoryDialogElementBase {
-  static get is() {
+  static get is(): string {
     return 'print-job-clear-history-dialog';
   }
 
-  static get template() {
+  static get template(): HTMLTemplateElement {
     return getTemplate();
   }
 
-  static get properties() {
+  static get properties(): PolymerElementProperties {
     return {
-      shouldDisableClearButton_: {
+      shouldDisableClearButton: {
         type: Boolean,
         value: false,
       },
     };
   }
 
-  private shouldDisableClearButton_: boolean;
-  private mojoInterfaceProvider_ = getMetadataProvider();
+  private shouldDisableClearButton: boolean;
+  private mojoInterfaceProvider = getMetadataProvider();
 
-  override connectedCallback() {
+  override connectedCallback(): void {
     super.connectedCallback();
 
     this.$.clearDialog.showModal();
   }
 
-  private onCancelButtonClick_() {
+  private onCancelButtonClick(): void {
     this.$.clearDialog.close();
   }
 
-  private onClearButtonClick_() {
-    this.shouldDisableClearButton_ = true;
-    this.mojoInterfaceProvider_.deleteAllPrintJobs().then(
-        this.onClearedHistory_.bind(this));
+  private onClearButtonClick(): void {
+    this.shouldDisableClearButton = true;
+    this.mojoInterfaceProvider.deleteAllPrintJobs().then(
+        this.onClearedHistory.bind(this));
   }
 
-  private onClearedHistory_(clearedHistoryResult: {success: boolean}) {
+  private onClearedHistory(clearedHistoryResult: {success: boolean}): void {
     if (clearedHistoryResult.success) {
       this.dispatchEvent(new CustomEvent(
           'all-history-cleared', {bubbles: true, composed: true}));
diff --git a/ash/webui/print_management/resources/print_job_entry.html b/ash/webui/print_management/resources/print_job_entry.html
index 487b4b5..f5551c5 100644
--- a/ash/webui/print_management/resources/print_job_entry.html
+++ b/ash/webui/print_management/resources/print_job_entry.html
@@ -60,65 +60,65 @@
 <div id="rowWrapper" focus-row-container>
   <!-- TODO(crbug/1073693): Update the a11y based on expert guidance -->
   <div class="list-item flex-center"
-      aria-label$="[[jobEntryAriaLabel_]]">
-    <iron-icon id="fileIcon" class$="[[fileIconClass_]]" icon="[[fileIcon_]]"
+      aria-label$="[[jobEntryAriaLabel]]">
+    <iron-icon id="fileIcon" class$="[[fileIconClass]]" icon="[[fileIcon]]"
         alt="">
     </iron-icon>
     <div id="jobTitle" class="file-name-column overflow-ellipsis"
         aria-hidden="true">
-      [[jobTitle_]]
+      [[jobTitle]]
     </div>
     <div id="printerName"
         class="printer-name-column overflow-ellipsis padded-left"
         aria-hidden="true">
-      [[printerName_]]
+      [[printerName]]
     </div>
     <div id="creationTime" class="date-column overflow-ellipsis padded-left"
         aria-hidden="true">
-      [[creationTime_]]
+      [[creationTime]]
     </div>
 
-    <template is="dom-if" if="[[isCompletedPrintJob_(jobEntry)]]" restamp>
+    <template is="dom-if" if="[[isCompletedPrintJob(jobEntry)]]" restamp>
       <div id="completionStatus"
           class="status-column overflow-ellipsis padded-left"
           focus-row-control
           focus-type="completedStatus"
           aria-hidden="true">
-        [[completionStatus_]]
+        [[completionStatus]]
       </div>
     </template>
 
-    <template is="dom-if" if="[[!isCompletedPrintJob_(jobEntry)]]" restamp>
+    <template is="dom-if" if="[[!isCompletedPrintJob(jobEntry)]]" restamp>
         <iron-media-query query="(min-width: 768px)"
-            query-matches="{{showFullOngoingStatus_}}">
+            query-matches="{{showFullOngoingStatus}}">
         </iron-media-query>
         <div id="activeStatusContainer"
             class="status-column padded-left flex-center">
           <!-- Non-error printing status -->
-          <template is="dom-if" if="[[!ongoingErrorStatus_]]" restamp>
-            <template is="dom-if" if="[[showFullOngoingStatus_]]">
+          <template is="dom-if" if="[[!ongoingErrorStatus]]" restamp>
+            <template is="dom-if" if="[[showFullOngoingStatus]]">
               <div id="numericalProgress" aria-hidden="true">
-                [[readableProgress_]]
+                [[readableProgress]]
               </div>
               <paper-progress
-                  value="[[computePrintPagesProgress_(
+                  value="[[computePrintPagesProgress(
                       jobEntry.activePrintJobInfo.printedPages,
                       jobEntry.numberOfPages)]]"
                   aria-hidden="true">
               </paper-progress>
             </template>
-            <div class="collapsed-status" hidden="[[showFullOngoingStatus_]]"
+            <div class="collapsed-status" hidden="[[showFullOngoingStatus]]"
                 aria-hidden="true">
               [[i18n('collapsedPrintingText')]]
             </div>
           </template>
           <!-- Error printing status -->
-          <template is="dom-if" if="[[ongoingErrorStatus_]]" restamp>
+          <template is="dom-if" if="[[ongoingErrorStatus]]" restamp>
             <div id="ongoingError" class="overflow-ellipsis" aria-hidden="true"
-                hidden="[[!showFullOngoingStatus_]]">
-              [[ongoingErrorStatus_]]
+                hidden="[[!showFullOngoingStatus]]">
+              [[ongoingErrorStatus]]
             </div>
-            <div hidden="[[showFullOngoingStatus_]]" aria-hidden="true">
+            <div hidden="[[showFullOngoingStatus]]" aria-hidden="true">
               [[i18n('stoppedGeneric')]]
             </div>
           </template>
@@ -127,7 +127,7 @@
               focus-row-control
               focus-type="cancelPrintJob"
               aria-hidden="true"
-            on-click="onCancelPrintJobClicked_">
+            on-click="onCancelPrintJobClicked">
           </cr-icon-button>
         </div>
     </template>
diff --git a/ash/webui/print_management/resources/print_job_entry.ts b/ash/webui/print_management/resources/print_job_entry.ts
index 3b1e010..e725121e 100644
--- a/ash/webui/print_management/resources/print_job_entry.ts
+++ b/ash/webui/print_management/resources/print_job_entry.ts
@@ -13,13 +13,14 @@
 import './print_management_shared.css.js';
 import './strings.m.js';
 
+import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {assert, assertNotReached} from 'chrome://resources/js/assert.js';
 import {FocusRowMixin} from 'chrome://resources/js/focus_row_mixin.js';
-import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {String16} from 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-webui.js';
 import {Time} from 'chrome://resources/mojo/mojo/public/mojom/base/time.mojom-webui.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
+import {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getMetadataProvider} from './mojo_interface_provider.js';
@@ -152,44 +153,44 @@
 const PrintJobEntryElementBase = FocusRowMixin(I18nMixin(PolymerElement));
 
 export class PrintJobEntryElement extends PrintJobEntryElementBase {
-  static get is() {
+  static get is(): string {
     return 'print-job-entry';
   }
 
-  static get template() {
+  static get template(): HTMLTemplateElement {
     return getTemplate();
   }
 
-  static get properties() {
+  static get properties(): PolymerElementProperties {
     return {
       jobEntry: {
         type: Object,
       },
 
-      jobTitle_: {
+      jobTitle: {
         type: String,
-        computed: 'decodeString16_(jobEntry.title)',
+        computed: 'decodeString16(jobEntry.title)',
       },
 
-      printerName_: {
+      printerName: {
         type: String,
-        computed: 'decodeString16_(jobEntry.printerName)',
+        computed: 'decodeString16(jobEntry.printerName)',
       },
 
-      creationTime_: {
+      creationTime: {
         type: String,
-        computed: 'computeDate_(jobEntry.creationTime)',
+        computed: 'computeDate(jobEntry.creationTime)',
       },
 
-      completionStatus_: {
+      completionStatus: {
         type: String,
-        computed: 'computeCompletionStatus_(jobEntry.completedInfo)',
+        computed: 'computeCompletionStatus(jobEntry.completedInfo)',
       },
 
       // Empty if there is no ongoing error.
-      ongoingErrorStatus_: {
+      ongoingErrorStatus: {
         type: String,
-        computed: 'getOngoingErrorStatus_(jobEntry.printerErrorCode)',
+        computed: 'getOngoingErrorStatus(jobEntry.printerErrorCode)',
       },
 
       /**
@@ -197,72 +198,72 @@
        * of pages to be printed. E.g. 5/7 (5 pages printed / 7 total pages to
        * print).
        */
-      readableProgress_: {
+      readableProgress: {
         type: String,
-        computed: 'computeReadableProgress_(jobEntry.activePrintJobInfo)',
+        computed: 'computeReadableProgress(jobEntry.activePrintJobInfo)',
       },
 
-      jobEntryAriaLabel_: {
+      jobEntryAriaLabel: {
         type: String,
-        computed: 'getJobEntryAriaLabel_(jobEntry, jobTitle_, printerName_, ' +
-            'creationTime_, completionStatus_, ' +
+        computed: 'getJobEntryAriaLabel(jobEntry, jobTitle, printerName, ' +
+            'creationTime, completionStatus, ' +
             'jobEntry.activePrintJobinfo.printedPages, jobEntry.numberOfPages)',
       },
 
       // This is only updated by media queries from window width changes.
-      showFullOngoingStatus_: Boolean,
+      showFullOngoingStatus: Boolean,
 
-      fileIcon_: {
+      fileIcon: {
         type: String,
-        computed: 'computeFileIcon_(jobTitle_)',
+        computed: 'computeFileIcon(jobTitle)',
       },
 
-      fileIconClass_: {
+      fileIconClass: {
         type: String,
-        computed: 'computeFileIconClass_(fileIcon_)',
+        computed: 'computeFileIconClass(fileIcon)',
       },
 
     };
   }
 
   jobEntry: PrintJobInfo;
-  private mojoInterfaceProvider_: PrintingMetadataProviderInterface;
-  private jobTitle_: string;
-  private printerName_: string;
-  private creationTime_: string;
-  private completionStatus_: string;
-  private ongoingErrorStatus_: string;
-  private readableProgress_: string;
-  private jobEntryAriaLabel_: string;
-  private showFullOngoingStatus_: boolean;
-  private fileIcon_: string;
-  private fileIconClass_: string;
+  private mojoInterfaceProvider: PrintingMetadataProviderInterface;
+  private jobTitle: string;
+  private printerName: string;
+  private creationTime: string;
+  private completionStatus: string;
+  private ongoingErrorStatus: string;
+  private readableProgress: string;
+  private jobEntryAriaLabel: string;
+  private showFullOngoingStatus: boolean;
+  private fileIcon: string;
+  private fileIconClass: string;
 
-  static get observers() {
+  static get observers(): string[] {
     return [
-      'printJobEntryDataChanged_(jobTitle_, printerName_, creationTime_, ' +
-          'completionStatus_)',
+      'printJobEntryDataChanged(jobTitle, printerName, creationTime, ' +
+          'completionStatus)',
     ];
   }
 
   constructor() {
     super();
 
-    this.mojoInterfaceProvider_ = getMetadataProvider();
+    this.mojoInterfaceProvider = getMetadataProvider();
 
-    this.addEventListener('click', () => this.onClick_());
+    this.addEventListener('click', () => this.onClick());
   }
 
   // Return private property this.fileIconClass for usage in browser tests.
   getFileIconClass(): string {
-    return this.fileIconClass_;
+    return this.fileIconClass;
   }
 
   /**
    * Check if any elements with the class "overflow-ellipsis" needs to
    * add/remove the title attribute.
    */
-  private printJobEntryDataChanged_() {
+  private printJobEntryDataChanged(): void {
     if (!this.shadowRoot) {
       return;
     }
@@ -281,7 +282,7 @@
         });
   }
 
-  private onClick_() {
+  private onClick(): void {
     if (!this.shadowRoot) {
       return;
     }
@@ -289,7 +290,7 @@
     // Since the status or cancel button has the focus-row-control attribute,
     // this will trigger the iron-list focus behavior and highlight the entire
     // entry.
-    if (this.isCompletedPrintJob_()) {
+    if (this.isCompletedPrintJob()) {
       this.shadowRoot.querySelector<HTMLElement>('#completionStatus')?.focus();
       return;
     }
@@ -301,22 +302,22 @@
         ?.focus();
   }
 
-  override connectedCallback() {
+  override connectedCallback(): void {
     super.connectedCallback();
 
     IronA11yAnnouncer.requestAvailability();
   }
 
-  private computeCompletionStatus_(): string {
+  private computeCompletionStatus(): string {
     if (!this.jobEntry.completedInfo) {
       return '';
     }
 
-    return this.convertStatusToString_(
+    return this.convertStatusToString(
         this.jobEntry.completedInfo.completionStatus);
   }
 
-  private computeReadableProgress_(): string {
+  private computeReadableProgress(): string {
     if (!this.jobEntry.activePrintJobInfo) {
       return '';
     }
@@ -327,26 +328,26 @@
         this.jobEntry.numberOfPages.toString());
   }
 
-  private onCancelPrintJobClicked_() {
-    this.mojoInterfaceProvider_.cancelPrintJob(this.jobEntry.id)
-        .then((() => this.onPrintJobCanceled_()));
+  private onCancelPrintJobClicked(): void {
+    this.mojoInterfaceProvider.cancelPrintJob(this.jobEntry.id)
+        .then((() => this.onPrintJobCanceled()));
   }
 
-  private onPrintJobCanceled_() {
+  private onPrintJobCanceled(): void {
     // TODO(crbug/1093527): Handle error case in which attempted cancellation
     // failed. Need to discuss with UX on error states.
     this.dispatchEvent(new CustomEvent('iron-announce', {
       bubbles: true,
       composed: true,
       detail:
-          {text: loadTimeData.getStringF('cancelledPrintJob', this.jobTitle_)},
+          {text: loadTimeData.getStringF('cancelledPrintJob', this.jobTitle)},
     }));
     this.dispatchEvent(new CustomEvent(
         'remove-print-job',
         {bubbles: true, composed: true, detail: this.jobEntry.id}));
   }
 
-  private decodeString16_(arr: String16): string {
+  private decodeString16(arr: String16): string {
     return arr.data.map(ch => String.fromCodePoint(ch)).join('');
   }
 
@@ -354,7 +355,7 @@
    * Converts mojo time to JS time. Returns "Today" if |mojoTime| is at the
    * current day.
    */
-  private computeDate_(mojoTime: Time): string {
+  private computeDate(mojoTime: Time): string {
     const jsDate = convertMojoTimeToJS(mojoTime);
     // Date() is constructed with the current time in UTC. If the Date() matches
     // |jsDate|'s date, display the 12hour time of the current date.
@@ -368,11 +369,11 @@
         {month: 'short', day: 'numeric', year: 'numeric'});
   }
 
-  private convertStatusToString_(mojoCompletionStatus:
-                                     PrintJobCompletionStatus): string {
+  private convertStatusToString(mojoCompletionStatus: PrintJobCompletionStatus):
+      string {
     switch (mojoCompletionStatus) {
       case PrintJobCompletionStatus.kFailed:
-        return this.getFailedStatusString_(this.jobEntry.printerErrorCode);
+        return this.getFailedStatusString(this.jobEntry.printerErrorCode);
       case PrintJobCompletionStatus.kCanceled:
         return loadTimeData.getString('completionStatusCanceled');
       case PrintJobCompletionStatus.kPrinted:
@@ -387,38 +388,38 @@
    * Returns true if the job entry is a completed print job.
    * Returns false otherwise.
    */
-  private isCompletedPrintJob_(): boolean {
+  private isCompletedPrintJob(): boolean {
     return !!this.jobEntry.completedInfo && !this.jobEntry.activePrintJobInfo;
   }
 
-  private getJobEntryAriaLabel_(): string {
+  private getJobEntryAriaLabel(): string {
     if (!this.jobEntry || this.jobEntry.numberOfPages === undefined ||
-        this.printerName_ === undefined || this.jobTitle_ === undefined ||
-        !this.creationTime_) {
+        this.printerName === undefined || this.jobTitle === undefined ||
+        !this.creationTime) {
       return '';
     }
 
-    // |completionStatus_| and |jobEntry.activePrintJobInfo| are mutually
+    // |completionStatus| and |jobEntry.activePrintJobInfo| are mutually
     // exclusive and one of which has to be non-null. Assert that if
-    // |completionStatus_| is non-null that |jobEntry.activePrintJobInfo| is
+    // |completionStatus| is non-null that |jobEntry.activePrintJobInfo| is
     // null and vice-versa.
     assert(
-        this.completionStatus_ ? !this.jobEntry.activePrintJobInfo :
-                                 this.jobEntry.activePrintJobInfo);
+        this.completionStatus ? !this.jobEntry.activePrintJobInfo :
+                                this.jobEntry.activePrintJobInfo);
 
-    if (this.isCompletedPrintJob_()) {
+    if (this.isCompletedPrintJob()) {
       return loadTimeData.getStringF(
-          'completePrintJobLabel', this.jobTitle_, this.printerName_,
-          this.creationTime_, this.completionStatus_);
+          'completePrintJobLabel', this.jobTitle, this.printerName,
+          this.creationTime, this.completionStatus);
     }
-    if (this.ongoingErrorStatus_) {
+    if (this.ongoingErrorStatus) {
       return loadTimeData.getStringF(
-          'stoppedOngoingPrintJobLabel', this.jobTitle_, this.printerName_,
-          this.creationTime_, this.ongoingErrorStatus_);
+          'stoppedOngoingPrintJobLabel', this.jobTitle, this.printerName,
+          this.creationTime, this.ongoingErrorStatus);
     }
     return loadTimeData.getStringF(
-        'ongoingPrintJobLabel', this.jobTitle_, this.printerName_,
-        this.creationTime_,
+        'ongoingPrintJobLabel', this.jobTitle, this.printerName,
+        this.creationTime,
         this.jobEntry.activePrintJobInfo ?
             this.jobEntry.activePrintJobInfo.printedPages.toString() :
             '',
@@ -429,7 +430,7 @@
    * Returns the percentage, out of 100, of the pages printed versus total
    * number of pages.
    */
-  private computePrintPagesProgress_(
+  private computePrintPagesProgress(
       printedPages: number,
       totalPages: number,
       ): number {
@@ -445,15 +446,15 @@
    * This is a best effort approach, as we are only given the file name and
    * not necessarily its extension.
    */
-  private computeFileIcon_(): string {
-    const fileExtension = getFileExtensionIconName(this.jobTitle_);
+  private computeFileIcon(): string {
+    const fileExtension = getFileExtensionIconName(this.jobTitle);
     // It's valid for a file to have '.' in its name and not be its extension.
     // If this is the case and we don't have a non-generic file icon, attempt to
     // see if this is a Google file.
     if (fileExtension && fileExtension !== GENERIC_FILE_EXTENSION_ICON) {
       return fileExtension;
     }
-    const gfileExtension = getGFileIconName(this.jobTitle_);
+    const gfileExtension = getGFileIconName(this.jobTitle);
     if (gfileExtension) {
       return gfileExtension;
     }
@@ -464,12 +465,12 @@
   /**
    * Uses file-icon SVG id to determine correct class to apply for file icon.
    */
-  private computeFileIconClass_(): string {
-    const iconClass = ICON_CLASS_MAP.get(this.fileIcon_);
+  private computeFileIconClass(): string {
+    const iconClass = ICON_CLASS_MAP.get(this.fileIcon);
     return `flex-center ${iconClass}`;
   }
 
-  private getFailedStatusString_(
+  private getFailedStatusString(
       mojoPrinterErrorCode: PrinterErrorCode,
       ): string {
     switch (mojoPrinterErrorCode) {
@@ -503,10 +504,10 @@
     }
   }
 
-  private getOngoingErrorStatus_(
+  private getOngoingErrorStatus(
       mojoPrinterErrorCode: PrinterErrorCode,
       ): string {
-    if (this.isCompletedPrintJob_()) {
+    if (this.isCompletedPrintJob()) {
       return '';
     }
 
diff --git a/ash/webui/print_management/resources/print_management.html b/ash/webui/print_management/resources/print_management.html
index e1c717a..c75cf24e 100644
--- a/ash/webui/print_management/resources/print_management.html
+++ b/ash/webui/print_management/resources/print_management.html
@@ -97,22 +97,22 @@
   <div id="headerContainer">
     <h1 id="printJobTitle">[[i18n('printJobTitle')]]</h1>
     <div id="clearAllContainer">
-      <template is="dom-if" if="[[!deletePrintJobHistoryAllowedByPolicy_]]">
+      <template is="dom-if" if="[[!deletePrintJobHistoryAllowedByPolicy]]">
         <cr-policy-indicator id="policyIcon" indicator-type="userPolicy">
         </cr-policy-indicator>
       </template>
-      <cr-button id="clearAllButton" on-click="onClearHistoryClicked_"
-          disabled="[[shouldDisableClearAllButton_]]"
-          hidden="[[!showClearAllButton_]]">
+      <cr-button id="clearAllButton" on-click="onClearHistoryClicked"
+          disabled="[[shouldDisableClearAllButton]]"
+          hidden="[[!showClearAllButton]]">
         <iron-icon id="deleteIcon" icon="print-management:delete"></iron-icon>
         [[i18n('clearAllHistoryLabel')]]
       </cr-button>
     </div>
   </div>
 
-  <template is="dom-if" if="[[showClearAllDialog_]]" restamp>
+  <template is="dom-if" if="[[showClearAllDialog]]" restamp>
     <print-job-clear-history-dialog id="clearHistoryDialog"
-        on-close="onClearHistoryDialogClosed_">
+        on-close="onClearHistoryDialogClosed">
     </print-job-clear-history-dialog>
   </template>
 
@@ -137,42 +137,42 @@
     </div>
   </div>
 
-  <template is="dom-if" if="[[ongoingPrintJobs_.length]]" restamp>
-    <iron-list id="ongoingList" items="[[ongoingPrintJobs_]]" role="grid">
+  <template is="dom-if" if="[[ongoingPrintJobs.length]]" restamp>
+    <iron-list id="ongoingList" items="[[ongoingPrintJobs]]" role="grid">
       <template>
         <print-job-entry job-entry="[[item]]" tabindex$="[[tabIndex]]"
-            last-focused="{{lastFocused_}}" list-blurred="{{listBlurred_}}"
+            last-focused="{{lastFocused}}" list-blurred="{{listBlurred}}"
             focus-row-index="[[index]]" iron-list-tab-index="[[tabIndex]]">
         </print-job-entry>
       </template>
     </iron-list>
   </template>
 
-  <div id="ongoingEmptyState" hidden="[[ongoingPrintJobs_.length]]">
+  <div id="ongoingEmptyState" hidden="[[ongoingPrintJobs.length]]">
     [[i18n('noPrintJobInProgress')]]
   </div>
 
-  <template is="dom-if" if="[[printJobs_.length]]" restamp>
+  <template is="dom-if" if="[[printJobs.length]]" restamp>
     <div id="historyHeaderContainer" class="column-headers flex-center">
-      <div aria-label$="[[printJobHistoryExpirationPeriod_]]">
+      <div aria-label$="[[printJobHistoryExpirationPeriod]]">
         [[i18n('historyHeader')]]
       </div>
       <iron-icon id="infoIcon" icon="cr:info-outline" aria-hidden="true"
-          hidden="[[isPolicyControlled_]]">
+          hidden="[[isPolicyControlled]]">
       </iron-icon>
       <iron-icon id="enterpriseIcon" icon="print-management:enterprise-icon"
-          aria-hidden="true" hidden="[[!isPolicyControlled_]]">
+          aria-hidden="true" hidden="[[!isPolicyControlled]]">
       </iron-icon>
-      <paper-tooltip for="[[activeHistoryInfoIcon_]]" fit-to-visible-bounds
+      <paper-tooltip for="[[activeHistoryInfoIcon]]" fit-to-visible-bounds
           aria-hidden="true">
-        [[printJobHistoryExpirationPeriod_]]
+        [[printJobHistoryExpirationPeriod]]
       </paper-tooltip>
     </div>
 
-    <iron-list id="entryList" items="[[printJobs_]]" role="grid">
+    <iron-list id="entryList" items="[[printJobs]]" role="grid">
       <template>
         <print-job-entry job-entry="[[item]]" tabindex$="[[tabIndex]]"
-            last-focused="{{lastFocused_}}" list-blurred="{{listBlurred_}}"
+            last-focused="{{lastFocused}}" list-blurred="{{listBlurred}}"
             focus-row-index="[[index]]" iron-list-tab-index="[[tabIndex]]">
         </print-job-entry>
       </template>
diff --git a/ash/webui/print_management/resources/print_management.ts b/ash/webui/print_management/resources/print_management.ts
index 3c0b78f1..fd72c9f1 100644
--- a/ash/webui/print_management/resources/print_management.ts
+++ b/ash/webui/print_management/resources/print_management.ts
@@ -16,9 +16,10 @@
 import './strings.m.js';
 
 import {IronIconElement} from '//resources/polymer/v3_0/iron-icon/iron-icon.js';
-import {assert} from 'chrome://resources/js/assert.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
+import {assert} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getMetadataProvider} from './mojo_interface_provider.js';
@@ -62,176 +63,176 @@
 
 export class PrintManagementElement extends PrintManagementElementBase
     implements PrintJobsObserverInterface {
-  static get is() {
+  static get is(): string {
     return 'print-management';
   }
 
-  static get template() {
+  static get template(): HTMLTemplateElement {
     return getTemplate();
   }
 
-  static get properties() {
+  static get properties(): PolymerElementProperties {
     return {
-      printJobs_: {
+      printJobs: {
         type: Array,
         value: () => [],
       },
 
-      printJobHistoryExpirationPeriod_: {
+      printJobHistoryExpirationPeriod: {
         type: String,
         value: '',
       },
 
-      activeHistoryInfoIcon_: {
+      activeHistoryInfoIcon: {
         type: String,
         value: '',
       },
 
-      isPolicyControlled_: {
+      isPolicyControlled: {
         type: Boolean,
         value: false,
       },
 
-      ongoingPrintJobs_: {
+      ongoingPrintJobs: {
         type: Array,
         value: () => [],
       },
 
       // Used by FocusRowBehavior to track the last focused element on a row.
-      lastFocused_: Object,
+      lastFocused: Object,
 
       // Used by FocusRowBehavior to track if the list has been blurred.
-      listBlurred_: Boolean,
+      listBlurred: Boolean,
 
-      showClearAllButton_: {
+      showClearAllButton: {
         type: Boolean,
         value: false,
         reflectToAttribute: true,
       },
 
-      showClearAllDialog_: {
+      showClearAllDialog: {
         type: Boolean,
         value: false,
       },
 
-      deletePrintJobHistoryAllowedByPolicy_: {
+      deletePrintJobHistoryAllowedByPolicy: {
         type: Boolean,
         value: true,
       },
 
-      shouldDisableClearAllButton_: {
+      shouldDisableClearAllButton: {
         type: Boolean,
-        computed: 'computeShouldDisableClearAllButton_(printJobs_,' +
-            'deletePrintJobHistoryAllowedByPolicy_)',
+        computed: 'computeShouldDisableClearAllButton(printJobs,' +
+            'deletePrintJobHistoryAllowedByPolicy)',
       },
 
       /**
        * Receiver responsible for observing print job updates notification
        * events.
        */
-      printJobsObserverReceiver_: {type: Object},
+      printJobsObserverReceiver: {type: Object},
     };
   }
 
-  static get observers() {
-    return ['onClearAllButtonUpdated_(shouldDisableClearAllButton_)'];
+  static get observers(): string[] {
+    return ['onClearAllButtonUpdated(shouldDisableClearAllButton)'];
   }
 
   constructor() {
     super();
 
-    this.mojoInterfaceProvider_ = getMetadataProvider();
+    this.mojoInterfaceProvider = getMetadataProvider();
 
     window.CrPolicyStrings = {
       controlledSettingPolicy:
           loadTimeData.getString('clearAllPrintJobPolicyIndicatorToolTip'),
     };
 
-    this.addEventListener('all-history-cleared', () => this.getPrintJobs_());
-    this.addEventListener('remove-print-job', (e) => this.removePrintJob_(e));
+    this.addEventListener('all-history-cleared', () => this.getPrintJobs());
+    this.addEventListener('remove-print-job', (e) => this.removePrintJob(e));
   }
 
-  private mojoInterfaceProvider_: PrintingMetadataProviderInterface;
-  private isPolicyControlled_: boolean;
-  private printJobs_: PrintJobInfo[];
-  private printJobHistoryExpirationPeriod_: string;
-  private activeHistoryInfoIcon_: string;
-  private ongoingPrintJobs_: PrintJobInfo[];
-  private lastFocused_: Element;
-  private listBlurred_: boolean;
-  private showClearAllButton_: boolean;
-  private showClearAllDialog_: boolean;
-  private deletePrintJobHistoryAllowedByPolicy_: boolean;
-  private shouldDisableClearAllButton_: boolean;
-  private printJobsObserverReceiver_: PrintJobsObserverReceiver;
+  private mojoInterfaceProvider: PrintingMetadataProviderInterface;
+  private isPolicyControlled: boolean;
+  private printJobs: PrintJobInfo[];
+  private printJobHistoryExpirationPeriod: string;
+  private activeHistoryInfoIcon: string;
+  private ongoingPrintJobs: PrintJobInfo[];
+  private lastFocused: Element;
+  private listBlurred: boolean;
+  private showClearAllButton: boolean;
+  private showClearAllDialog: boolean;
+  private deletePrintJobHistoryAllowedByPolicy: boolean;
+  private shouldDisableClearAllButton: boolean;
+  private printJobsObserverReceiver: PrintJobsObserverReceiver;
 
-  override connectedCallback() {
+  override connectedCallback(): void {
     super.connectedCallback();
 
-    this.getPrintJobHistoryExpirationPeriod_();
-    this.startObservingPrintJobs_();
-    this.fetchDeletePrintJobHistoryPolicy_();
+    this.getPrintJobHistoryExpirationPeriod();
+    this.startObservingPrintJobs();
+    this.fetchDeletePrintJobHistoryPolicy();
   }
 
-  override disconnectedCallback() {
+  override disconnectedCallback(): void {
     super.disconnectedCallback();
 
-    this.printJobsObserverReceiver_.$.close();
+    this.printJobsObserverReceiver.$.close();
   }
 
-  private startObservingPrintJobs_() {
-    this.printJobsObserverReceiver_ = new PrintJobsObserverReceiver((this));
-    this.mojoInterfaceProvider_
+  private startObservingPrintJobs(): void {
+    this.printJobsObserverReceiver = new PrintJobsObserverReceiver((this));
+    this.mojoInterfaceProvider
         .observePrintJobs(
-            this.printJobsObserverReceiver_.$.bindNewPipeAndPassRemote())
+            this.printJobsObserverReceiver.$.bindNewPipeAndPassRemote())
         .then(() => {
-          this.getPrintJobs_();
+          this.getPrintJobs();
         });
   }
 
-  private fetchDeletePrintJobHistoryPolicy_() {
-    this.mojoInterfaceProvider_.getDeletePrintJobHistoryAllowedByPolicy().then(
+  private fetchDeletePrintJobHistoryPolicy(): void {
+    this.mojoInterfaceProvider.getDeletePrintJobHistoryAllowedByPolicy().then(
         (param) => {
-          this.onGetDeletePrintHistoryPolicy_(param);
+          this.onGetDeletePrintHistoryPolicy(param);
         });
   }
 
-  private onGetDeletePrintHistoryPolicy_(responseParam:
-                                             {isAllowedByPolicy: boolean}) {
-    this.showClearAllButton_ = true;
-    this.deletePrintJobHistoryAllowedByPolicy_ =
-        responseParam.isAllowedByPolicy;
+  private onGetDeletePrintHistoryPolicy(responseParam: {
+    isAllowedByPolicy: boolean,
+  }): void {
+    this.showClearAllButton = true;
+    this.deletePrintJobHistoryAllowedByPolicy = responseParam.isAllowedByPolicy;
   }
 
-  onAllPrintJobsDeleted() {
-    this.getPrintJobs_();
+  onAllPrintJobsDeleted(): void {
+    this.getPrintJobs();
   }
 
-  onPrintJobUpdate(job: PrintJobInfo) {
+  onPrintJobUpdate(job: PrintJobInfo): void {
     // Only update ongoing print jobs.
     assert(job.activePrintJobInfo);
 
     // Check if |job| is an existing ongoing print job and requires an update
     // or if |job| is a new ongoing print job.
-    const idx = this.getIndexOfOngoingPrintJob_(job.id);
+    const idx = this.getIndexOfOngoingPrintJob(job.id);
     if (idx !== -1) {
       // Replace the existing ongoing print job with its updated entry.
-      this.splice('ongoingPrintJobs_', idx, 1, job);
+      this.splice('ongoingPrintJobs', idx, 1, job);
     } else {
       // New ongoing print jobs are appended to the ongoing print
       // jobs list.
-      this.push('ongoingPrintJobs_', job);
+      this.push('ongoingPrintJobs', job);
     }
 
     if (job.activePrintJobInfo?.activeState ===
         ActivePrintJobState.kDocumentDone) {
       // This print job is now completed, next step is to update the history
       // list with the recently stored print job.
-      this.getPrintJobs_();
+      this.getPrintJobs();
     }
   }
 
-  private onPrintJobsReceived_(jobs: {printJobs: PrintJobInfo[]}) {
+  private onPrintJobsReceived(jobs: {printJobs: PrintJobInfo[]}): void {
     // TODO(crbug/1073690): Update this when BigInt is supported for
     // updateList().
     const ongoingList = [];
@@ -246,19 +247,19 @@
     }
 
     // Sort the print jobs in chronological order.
-    this.ongoingPrintJobs_ = ongoingList.sort(comparePrintJobsChronologically);
-    this.printJobs_ = historyList.sort(comparePrintJobsReverseChronologically);
+    this.ongoingPrintJobs = ongoingList.sort(comparePrintJobsChronologically);
+    this.printJobs = historyList.sort(comparePrintJobsReverseChronologically);
   }
 
-  private getPrintJobs_() {
-    this.mojoInterfaceProvider_.getPrintJobs().then(
-        this.onPrintJobsReceived_.bind(this));
+  private getPrintJobs(): void {
+    this.mojoInterfaceProvider.getPrintJobs().then(
+        this.onPrintJobsReceived.bind(this));
   }
 
-  private onPrintJobHistoryExpirationPeriodReceived_(printJobPolicyInfo: {
+  private onPrintJobHistoryExpirationPeriodReceived(printJobPolicyInfo: {
     expirationPeriodInDays: number,
     isFromPolicy: boolean,
-  }) {
+  }): void {
     const expirationPeriod = printJobPolicyInfo.expirationPeriodInDays;
     // If print jobs are not persisted, we can return early since the tooltip
     // section won't be shown.
@@ -266,63 +267,62 @@
       return;
     }
 
-    this.isPolicyControlled_ = printJobPolicyInfo.isFromPolicy;
-    this.activeHistoryInfoIcon_ =
-        this.isPolicyControlled_ ? 'enterpriseIcon' : 'infoIcon';
+    this.isPolicyControlled = printJobPolicyInfo.isFromPolicy;
+    this.activeHistoryInfoIcon =
+        this.isPolicyControlled ? 'enterpriseIcon' : 'infoIcon';
 
     switch (expirationPeriod) {
       case METADATA_STORED_INDEFINITELY:
-        this.printJobHistoryExpirationPeriod_ =
+        this.printJobHistoryExpirationPeriod =
             loadTimeData.getString('printJobHistoryIndefinitePeriod');
         break;
       case METADATA_STORED_FOR_ONE_DAY:
-        this.printJobHistoryExpirationPeriod_ =
+        this.printJobHistoryExpirationPeriod =
             loadTimeData.getString('printJobHistorySingleDay');
         break;
       default:
-        this.printJobHistoryExpirationPeriod_ = loadTimeData.getStringF(
+        this.printJobHistoryExpirationPeriod = loadTimeData.getStringF(
             'printJobHistoryExpirationPeriod',
             expirationPeriod,
         );
     }
   }
 
-  private getPrintJobHistoryExpirationPeriod_() {
-    this.mojoInterfaceProvider_.getPrintJobHistoryExpirationPeriod().then(
-        this.onPrintJobHistoryExpirationPeriodReceived_.bind(this));
+  private getPrintJobHistoryExpirationPeriod(): void {
+    this.mojoInterfaceProvider.getPrintJobHistoryExpirationPeriod().then(
+        this.onPrintJobHistoryExpirationPeriodReceived.bind(this));
   }
 
-  private removePrintJob_(e: RemovePrintJobEvent) {
-    const idx = this.getIndexOfOngoingPrintJob_(e.detail);
+  private removePrintJob(e: RemovePrintJobEvent): void {
+    const idx = this.getIndexOfOngoingPrintJob(e.detail);
     if (idx !== -1) {
-      this.splice('ongoingPrintJobs_', idx, 1);
+      this.splice('ongoingPrintJobs', idx, 1);
     }
   }
 
-  private onClearHistoryClicked_() {
-    this.showClearAllDialog_ = true;
+  private onClearHistoryClicked(): void {
+    this.showClearAllDialog = true;
   }
 
-  private onClearHistoryDialogClosed_() {
-    this.showClearAllDialog_ = false;
+  private onClearHistoryDialogClosed(): void {
+    this.showClearAllDialog = false;
   }
 
-  private getIndexOfOngoingPrintJob_(expectedId: string): number {
-    return this.ongoingPrintJobs_.findIndex(
+  private getIndexOfOngoingPrintJob(expectedId: string): number {
+    return this.ongoingPrintJobs.findIndex(
         arrJob => arrJob.id === expectedId,
     );
   }
 
-  private computeShouldDisableClearAllButton_(): boolean {
-    return !this.deletePrintJobHistoryAllowedByPolicy_ ||
-        !this.printJobs_.length;
+  private computeShouldDisableClearAllButton(): boolean {
+    return !this.deletePrintJobHistoryAllowedByPolicy || !this.printJobs.length;
   }
 
-  private onClearAllButtonUpdated_() {
+  private onClearAllButtonUpdated(): void {
     this.$.deleteIcon.classList.toggle(
-        'delete-enabled', !this.shouldDisableClearAllButton_);
+        'delete-enabled', !this.shouldDisableClearAllButton);
     this.$.deleteIcon.classList.toggle(
-        'delete-disabled', this.shouldDisableClearAllButton_);
+        'delete-disabled', this.shouldDisableClearAllButton);
   }
 }
 
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
index 5545657..4a48460 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
@@ -4,14 +4,35 @@
 
 #include "ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h"
 
+#include <vector>
+
 #include "ash/accelerators/ash_accelerator_configuration.h"
 #include "ash/shell.h"
 #include "ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom.h"
+#include "base/containers/flat_map.h"
+#include "mojo/public/cpp/bindings/clone_traits.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
 
 namespace ash {
+
+namespace {
+
+mojom::AcceleratorInfoPtr AcceleratorInfoToMojom(
+    const AcceleratorInfo& accelerator) {
+  mojom::AcceleratorInfoPtr info_mojom = mojom::AcceleratorInfo::New();
+  info_mojom->accelerator = accelerator.accelerator;
+  info_mojom->key_display = accelerator.key_display;
+  info_mojom->type = accelerator.type;
+  info_mojom->state = accelerator.state;
+  info_mojom->locked = accelerator.locked;
+
+  return info_mojom;
+}
+
+}  // namespace
+
 namespace shortcut_ui {
 
 AcceleratorConfigurationProvider::AcceleratorConfigurationProvider()
@@ -39,6 +60,29 @@
   std::move(callback).Run(/*is_mutable=*/true);
 }
 
+void AcceleratorConfigurationProvider::GetAccelerators(
+    GetAcceleratorsCallback callback) {
+  AcceleratorConfigurationMap accelerator_config;
+
+  base::flat_map<AcceleratorActionId, std::vector<mojom::AcceleratorInfoPtr>>
+      accelerators_mojom;
+  // TODO(jimmyxgong): Currently only handling Ash case, need to also include
+  // other accelerator sources.
+  for (const auto& [id, accelerators] : ash_accelerator_mapping_) {
+    std::vector<mojom::AcceleratorInfoPtr> infos_mojom;
+    infos_mojom.reserve(accelerators.size());
+    for (const auto& accelerator : accelerators) {
+      infos_mojom.push_back(AcceleratorInfoToMojom(accelerator));
+    }
+    accelerators_mojom.emplace(id, std::move(infos_mojom));
+  }
+
+  accelerator_config.emplace(mojom::AcceleratorSource::kAsh,
+                             std::move(accelerators_mojom));
+
+  std::move(callback).Run(std::move(accelerator_config));
+}
+
 void AcceleratorConfigurationProvider::BindInterface(
     mojo::PendingReceiver<
         shortcut_customization::mojom::AcceleratorConfigurationProvider>
@@ -50,8 +94,6 @@
     mojom::AcceleratorSource source,
     const std::map<AcceleratorActionId, std::vector<AcceleratorInfo>>&
         mapping) {
-  // TODO(jimmyxgong): Remove `ash_accelerator_mapping_` and instead fire the
-  // Mojo event with the mapping.
   ash_accelerator_mapping_ = mapping;
 }
 
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h
index 6f22b21..5c5b9c1 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h
@@ -19,6 +19,11 @@
 class AcceleratorConfigurationProvider
     : shortcut_customization::mojom::AcceleratorConfigurationProvider {
  public:
+  using AcceleratorConfigurationMap =
+      base::flat_map<mojom::AcceleratorSource,
+                     base::flat_map<AcceleratorActionId,
+                                    std::vector<mojom::AcceleratorInfoPtr>>>;
+
   AcceleratorConfigurationProvider();
   AcceleratorConfigurationProvider(const AcceleratorConfigurationProvider&) =
       delete;
@@ -29,6 +34,7 @@
   // shortcut_customization::mojom::AcceleratorConfigurationProvider:
   void IsMutable(ash::mojom::AcceleratorSource source,
                  IsMutableCallback callback) override;
+  void GetAccelerators(GetAcceleratorsCallback callback) override;
 
   void BindInterface(
       mojo::PendingReceiver<
@@ -43,7 +49,6 @@
       const std::map<AcceleratorActionId, std::vector<AcceleratorInfo>>&
           mapping);
 
-  // TODO(jimmyxgong): Remove this when Mojo is implemented.
   std::map<AcceleratorActionId, std::vector<AcceleratorInfo>>
       ash_accelerator_mapping_;
 
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
index 26ea344..3adf0f33 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
@@ -45,7 +45,7 @@
 }
 
 void ExpectAllAcceleratorsEqual(
-    const base::span<const ash::AcceleratorData> expected,
+    const base::span<const ash::AcceleratorData>& expected,
     const std::vector<ash::AcceleratorInfo>& actual) {
   EXPECT_EQ(std::size(expected), actual.size());
 
@@ -61,6 +61,24 @@
   }
 }
 
+void ExpectMojomAcceleratorsEqual(
+    ash::mojom::AcceleratorSource source,
+    const base::span<const ash::AcceleratorData>& expected,
+    ash::shortcut_ui::AcceleratorConfigurationProvider::
+        AcceleratorConfigurationMap actual_config) {
+  // Flatten the map into a vector of `AcceleratorInfo`'s and verify it against
+  // the expected data.
+  std::vector<AcceleratorInfo> actual_infos;
+  for (const auto& iter : actual_config[source]) {
+    for (const auto& mojo_info : iter.second) {
+      AcceleratorInfo accelerator(mojo_info->type, mojo_info->accelerator,
+                                  mojo_info->key_display, mojo_info->locked);
+      actual_infos.push_back(std::move(accelerator));
+    }
+  }
+  ExpectAllAcceleratorsEqual(expected, actual_infos);
+}
+
 }  // namespace
 
 namespace shortcut_ui {
@@ -96,6 +114,13 @@
     return accelerators;
   }
 
+  void GetAshConfigAndExpectEquals(
+      const base::span<const ash::AcceleratorData>& expected) {
+    provider_->GetAccelerators(base::BindOnce(&ExpectMojomAcceleratorsEqual,
+                                              mojom::AcceleratorSource::kAsh,
+                                              expected));
+  }
+
   std::unique_ptr<AcceleratorConfigurationProvider> provider_;
 };
 
@@ -147,6 +172,23 @@
   ExpectAllAcceleratorsEqual(updated_test_data, GetAshAccelerators());
 }
 
+TEST_F(AcceleratorConfigurationProviderTest, GetAcceleratorConfigAsh) {
+  const AcceleratorData test_data[] = {
+      {/**trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
+       CYCLE_FORWARD_MRU},
+      {/**trigger_on_press=*/true, ui::VKEY_TAB,
+       ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
+      {/**trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN,
+       SHOW_TASK_MANAGER},
+  };
+  Shell::Get()->ash_accelerator_configuration()->Initialize(test_data);
+  base::RunLoop().RunUntilIdle();
+  ExpectAllAcceleratorsEqual(test_data, GetAshAccelerators());
+
+  GetAshConfigAndExpectEquals(test_data);
+  base::RunLoop().RunUntilIdle();
+}
+
 }  // namespace shortcut_ui
 
 }  // namespace ash
diff --git a/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom b/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom
index 729a482..9dad65b 100644
--- a/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom
+++ b/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom
@@ -14,4 +14,12 @@
 interface AcceleratorConfigurationProvider {
   // Whether the source is mutable and shortcuts can be changed.
   IsMutable(ash.mojom.AcceleratorSource source) => (bool is_mutable);
+
+  // Get the accelerator mappings for all sources. This is formatted as
+  // AcceleratorSource -> map<AcceleratorActionId, Array<AcceleratorInfo>>.
+  // Note that an accelerator action can have multiple accelerators associated
+  // with it.
+  GetAccelerators() =>
+      (map<ash.mojom.AcceleratorSource,
+       map<uint32, array<ash.mojom.AcceleratorInfo>>> config);
 };
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index 6a47920..f54a767 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -3195,11 +3195,6 @@
 }
 
 TEST_P(DesksTest, MiniViewsTouchGestures) {
-  // TODO(crbug.com/1361138): Figure out how to accommodate the context menu in
-  // CloseAll.
-  base::test::ScopedFeatureList desks_close_all_disabler;
-  desks_close_all_disabler.InitAndDisableFeature(features::kDesksCloseAll);
-
   auto* controller = DesksController::Get();
   NewDesk();
   NewDesk();
@@ -3216,16 +3211,36 @@
   auto* desk_2_mini_view = desks_bar_view->mini_views()[1];
   auto* desk_3_mini_view = desks_bar_view->mini_views()[2];
 
-  // Long gesture tapping on one mini_view shows its desk action interface, and
-  // hides those of other mini_views.
+  // Long gesture tapping on one desk preview shows its desk action interface,
+  // and hides those of other mini views.
   auto* event_generator = GetEventGenerator();
-  LongGestureTap(desk_1_mini_view->GetBoundsInScreen().CenterPoint(),
-                 event_generator);
+  const gfx::Point desk_1_preview_center =
+      desk_1_mini_view->desk_preview()->GetBoundsInScreen().CenterPoint();
+  const gfx::Point desk_2_preview_center =
+      desk_2_mini_view->desk_preview()->GetBoundsInScreen().CenterPoint();
+
+  LongGestureTap(desk_1_preview_center, event_generator);
+
+  // If the `kDesksCloseAll` feature is enabled, the context menu appears on the
+  // first long press and after the user taps away the buttons will show. So in
+  // that case we need to tap away and wait for the context menu to disappear
+  // before checking whether the desk action interfaces are visible.
+  if (features::IsDesksCloseAllEnabled()) {
+    event_generator->GestureTapDownAndUp(desk_1_preview_center);
+    base::RunLoop().RunUntilIdle();
+  }
+
   EXPECT_TRUE(GetDeskActionVisibilityForMiniView(desk_1_mini_view));
   EXPECT_FALSE(GetDeskActionVisibilityForMiniView(desk_2_mini_view));
   EXPECT_FALSE(GetDeskActionVisibilityForMiniView(desk_3_mini_view));
-  LongGestureTap(desk_2_mini_view->GetBoundsInScreen().CenterPoint(),
-                 event_generator);
+
+  LongGestureTap(desk_2_preview_center, event_generator);
+
+  if (features::IsDesksCloseAllEnabled()) {
+    event_generator->GestureTapDownAndUp(desk_2_preview_center);
+    base::RunLoop().RunUntilIdle();
+  }
+
   EXPECT_FALSE(GetDeskActionVisibilityForMiniView(desk_1_mini_view));
   EXPECT_TRUE(GetDeskActionVisibilityForMiniView(desk_2_mini_view));
   EXPECT_FALSE(GetDeskActionVisibilityForMiniView(desk_3_mini_view));
@@ -5611,11 +5626,6 @@
 }
 
 TEST_P(DesksTest, ReorderDesksByGesture) {
-  // TODO(crbug.com/1361138): Figure out how to accommodate the context menu in
-  // CloseAll.
-  base::test::ScopedFeatureList desks_close_all_disabler;
-  desks_close_all_disabler.InitAndDisableFeature(features::kDesksCloseAll);
-
   auto* desks_controller = DesksController::Get();
 
   EnterOverview();
@@ -5656,6 +5666,16 @@
 
   event_generator->ReleaseTouch();
 
+  // If the `kDesksCloseAll` feature is enabled, the context menu appears on a
+  // long press on the desk preview. In order to drag the desk again, we first
+  // need to get rid of the context menu by tapping and waiting for the menu to
+  // disappear.
+  if (features::IsDesksCloseAllEnabled()) {
+    event_generator->GestureTapDownAndUp(
+        mini_view_1->desk_preview()->GetBoundsInScreen().CenterPoint());
+    base::RunLoop().RunUntilIdle();
+  }
+
   // Reorder the second desk
   LongTapOnDeskPreview(mini_view_1, event_generator);
   EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
@@ -5663,6 +5683,13 @@
   // Swap the positions of the second desk and the third desk.
   gfx::Point desk_center_2 =
       mini_view_2->GetPreviewBoundsInScreen().CenterPoint();
+
+  // If `kDesksCloseAll` is enabled, we need to drag the mouse a bit after
+  // long-tapping the desk preview to start the closing of the context menu
+  // before rearranging the desk.
+  if (features::IsDesksCloseAllEnabled())
+    event_generator->MoveTouchBy(10, 0);
+
   event_generator->MoveTouch(desk_center_2);
 
   // Now, the desks order should be [0, 2, 1]:
@@ -5768,11 +5795,6 @@
 
 // Test reordering desks in RTL mode.
 TEST_P(DesksTest, ReorderDesksInRTLMode) {
-  // TODO(crbug.com/1361138): Figure out how to accommodate the context menu in
-  // CloseAll.
-  base::test::ScopedFeatureList desks_close_all_disabler;
-  desks_close_all_disabler.InitAndDisableFeature(features::kDesksCloseAll);
-
   // Turn on RTL mode.
   const bool default_rtl = base::i18n::IsRTL();
   base::i18n::SetRTLForTesting(true);
@@ -5834,6 +5856,13 @@
 
   gfx::Point desk_center_0 =
       mini_view_0->GetPreviewBoundsInScreen().CenterPoint();
+
+  // If `kDesksCloseAll` is enabled, we need to drag the mouse a bit after
+  // long-tapping the desk preview to start the closing of the context menu
+  // before rearranging the desk.
+  if (features::IsDesksCloseAllEnabled())
+    event_generator->MoveTouchBy(-10, 0);
+
   event_generator->MoveTouch(desk_center_0);
 
   // Now, the desks order should be [1, 0, 2]:
diff --git a/ash/wm/overview/overview_controller_unittest.cc b/ash/wm/overview/overview_controller_unittest.cc
index 3bb9eff..db7c30b 100644
--- a/ash/wm/overview/overview_controller_unittest.cc
+++ b/ash/wm/overview/overview_controller_unittest.cc
@@ -792,9 +792,10 @@
     arc_windows[i] = created_windows[i + browser_window_count].get();
   }
 
-  EXPECT_CALL(observer, OnThrottlingStarted(
-                            testing::UnorderedElementsAreArray(arc_windows),
-                            frame_throttling_controller->throttled_fps()));
+  EXPECT_CALL(observer,
+              OnThrottlingStarted(
+                  testing::UnorderedElementsAreArray(arc_windows),
+                  frame_throttling_controller->GetCurrentThrottledFrameRate()));
   EnterOverview();
   EXPECT_THAT(frame_throttling_controller->GetFrameSinkIdsToThrottle(),
               ::testing::UnorderedElementsAreArray(ids));
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 86ee605..ee0e6a80 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -3409,7 +3409,6 @@
   testing::NiceMock<MockFrameThrottlingObserver> observer;
   FrameThrottlingController* frame_throttling_controller =
       Shell::Get()->frame_throttling_controller();
-  uint8_t throttled_fps = frame_throttling_controller->throttled_fps();
   frame_throttling_controller->AddArcObserver(&observer);
 
   const int window_count = 5;
@@ -3425,9 +3424,10 @@
   std::vector<aura::Window*> windows_to_throttle(window_count, nullptr);
   std::transform(windows.begin(), windows.end(), windows_to_throttle.begin(),
                  [](std::unique_ptr<aura::Window>& w) { return w.get(); });
-  EXPECT_CALL(observer, OnThrottlingStarted(testing::UnorderedElementsAreArray(
-                                                windows_to_throttle),
-                                            throttled_fps));
+  EXPECT_CALL(observer,
+              OnThrottlingStarted(
+                  testing::UnorderedElementsAreArray(windows_to_throttle),
+                  frame_throttling_controller->GetCurrentThrottledFrameRate()));
   ToggleOverview();
 
   // Add a new window to overview.
@@ -3437,9 +3437,10 @@
                           static_cast<int>(AppType::ARC_APP));
   windows_to_throttle.push_back(new_window.get());
   EXPECT_CALL(observer, OnThrottlingEnded());
-  EXPECT_CALL(observer, OnThrottlingStarted(testing::UnorderedElementsAreArray(
-                                                windows_to_throttle),
-                                            throttled_fps));
+  EXPECT_CALL(observer,
+              OnThrottlingStarted(
+                  testing::UnorderedElementsAreArray(windows_to_throttle),
+                  frame_throttling_controller->GetCurrentThrottledFrameRate()));
   OverviewGrid* grid = GetOverviewSession()->grid_list()[0].get();
   grid->AppendItem(new_window.get(), /*reposition=*/false, /*animate=*/false,
                    /*use_spawn_animation=*/false);
diff --git a/ash/wm/overview/scoped_overview_hide_windows.cc b/ash/wm/overview/scoped_overview_hide_windows.cc
index 2eef8f9..b8bc893d 100644
--- a/ash/wm/overview/scoped_overview_hide_windows.cc
+++ b/ash/wm/overview/scoped_overview_hide_windows.cc
@@ -70,6 +70,11 @@
   if (!visible)
     return;
 
+  // If it's not one of the registered windows, then it must be a child of the
+  // registered windows. Early return in this case.
+  if (!HasWindow(window))
+    return;
+
   // It's expected that windows hidden in overview, unless they are forcefully
   // hidden should not be shown while in overview.
   if (!force_hidden_)
diff --git a/base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java b/base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java
index 53ddf212..5b31cf45 100644
--- a/base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java
+++ b/base/android/java/src/org/chromium/base/NativeLibraryLoadedStatus.java
@@ -29,7 +29,9 @@
         boolean nativeMethodsReady = isMainDex ? sProvider.areMainDexNativeMethodsReady()
                                                : sProvider.areNativeMethodsReady();
         if (!nativeMethodsReady) {
-            throw new JniException("Native method called before the native library was ready.");
+            throw new JniException(String.format(
+                    "Native method called before the native library was ready (isMainDex=%b).",
+                    isMainDex));
         }
     }
 
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
index 5663a7a..a844376 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -34,7 +34,6 @@
 import org.chromium.base.metrics.UmaRecorderHolder;
 import org.chromium.build.BuildConfig;
 import org.chromium.build.NativeLibraries;
-import org.chromium.build.annotations.CheckDiscard;
 import org.chromium.build.annotations.MainDex;
 
 import java.lang.annotation.Retention;
@@ -86,6 +85,9 @@
 
     private static boolean sBrowserStartupBlockedForTesting;
 
+    // Helps mInitializedForTesting and mLoadStateForTesting to be removed by R8.
+    private static boolean sEnableStateForTesting;
+
     // One-way switch becomes true when the libraries are initialized (by calling
     // LibraryLoaderJni.get().libraryLoaded, which forwards to LibraryLoaded(...) in
     // library_loader_hooks.cc). Note that this member should remain a one-way switch, since it
@@ -108,6 +110,14 @@
     }
     private volatile @LoadState int mLoadState;
 
+    // Tracks mLoadState, but can be reset to NOT_LOADED between tests to ensure that each test that
+    // requires native explicitly loads it.
+    private @LoadState int mLoadStateForTesting;
+
+    // Tracks mInitialized, but can be reset to false between tests to ensure that each test that
+    // requires native explicitly loads it.
+    private boolean mInitializedForTesting;
+
     // Whether to use the Chromium linker vs. the system linker.
     // Avoids locking: should be initialized very early.
     private boolean mUseChromiumLinker = NativeLibraries.sUseLinker;
@@ -423,7 +433,22 @@
 
     @VisibleForTesting
     protected LibraryLoader() {
-        if (DEBUG) logLinkersUsed();
+        if (DEBUG) {
+            logLinkersUsed();
+        }
+        if (BuildConfig.ENABLE_ASSERTS) {
+            NativeLibraryLoadedStatus.setProvider(new NativeLibraryLoadedStatusProvider() {
+                @Override
+                public boolean areMainDexNativeMethodsReady() {
+                    return isMainDexLoaded();
+                }
+
+                @Override
+                public boolean areNativeMethodsReady() {
+                    return isLoaded();
+                }
+            });
+        }
     }
 
     /**
@@ -553,23 +578,6 @@
         }
     }
 
-    @CheckDiscard("")
-    public void enableJniChecks() {
-        if (!BuildConfig.ENABLE_ASSERTS) return;
-
-        NativeLibraryLoadedStatus.setProvider(new NativeLibraryLoadedStatusProvider() {
-            @Override
-            public boolean areMainDexNativeMethodsReady() {
-                return mLoadState >= LoadState.MAIN_DEX_LOADED;
-            }
-
-            @Override
-            public boolean areNativeMethodsReady() {
-                return isInitialized();
-            }
-        });
-    }
-
     /**
      * Return if library is already loaded successfully by the zygote.
      */
@@ -650,7 +658,13 @@
     @Deprecated
     @VisibleForTesting
     public boolean isLoaded() {
-        return mLoadState == LoadState.LOADED;
+        return mLoadState == LoadState.LOADED
+                && (!sEnableStateForTesting || mLoadStateForTesting == LoadState.LOADED);
+    }
+
+    private boolean isMainDexLoaded() {
+        return mLoadState >= LoadState.MAIN_DEX_LOADED
+                && (!sEnableStateForTesting || mLoadStateForTesting >= LoadState.MAIN_DEX_LOADED);
     }
 
     /**
@@ -661,7 +675,7 @@
      */
     @Deprecated
     public boolean isInitialized() {
-        return mInitialized && isLoaded();
+        return mInitialized && isLoaded() && (!sEnableStateForTesting || mInitializedForTesting);
     }
 
     /**
@@ -674,6 +688,15 @@
     }
 
     /**
+     * Causes LibraryLoader to pretend that native libraries have not yet been initialized.
+     */
+    public void resetForTesting() {
+        mLoadStateForTesting = LoadState.NOT_LOADED;
+        mInitializedForTesting = false;
+        sEnableStateForTesting = true;
+    }
+
+    /**
      * Override kept for callers that need to load from a different app context. Do not use unless
      * specifically required to load from another context that is not the current process's app
      * context.
@@ -832,7 +855,12 @@
     @GuardedBy("mLock")
     @VisibleForTesting
     protected void loadMainDexAlreadyLocked(ApplicationInfo appInfo, boolean inZygote) {
-        if (mLoadState >= LoadState.MAIN_DEX_LOADED) return;
+        if (mLoadState >= LoadState.MAIN_DEX_LOADED) {
+            if (sEnableStateForTesting && mLoadStateForTesting == LoadState.NOT_LOADED) {
+                mLoadStateForTesting = LoadState.MAIN_DEX_LOADED;
+            }
+            return;
+        }
         try (TraceEvent te = TraceEvent.scoped("LibraryLoader.loadMainDexAlreadyLocked")) {
             assert !mInitialized;
             assert mLibraryProcessType != LibraryProcessType.PROCESS_UNINITIALIZED || inZygote;
@@ -853,10 +881,15 @@
             }
 
             long loadTimeMs = uptimeTimer.getElapsedMillis();
-            getMediator().recordLoadTimeHistogram(loadTimeMs);
-            getMediator().recordLoadThreadTimeHistogram(threadTimeTimer.getElapsedMillis());
+
             if (DEBUG) Log.i(TAG, "Time to load native libraries: %d ms", loadTimeMs);
             mLoadState = LoadState.MAIN_DEX_LOADED;
+            if (sEnableStateForTesting) {
+                mLoadStateForTesting = LoadState.MAIN_DEX_LOADED;
+            }
+
+            getMediator().recordLoadTimeHistogram(loadTimeMs);
+            getMediator().recordLoadThreadTimeHistogram(threadTimeTimer.getElapsedMillis());
         } catch (UnsatisfiedLinkError e) {
             throw new ProcessInitException(LoaderErrors.NATIVE_LIBRARY_LOAD_FAILED, e);
         }
@@ -864,7 +897,12 @@
 
     @VisibleForTesting
     protected void loadNonMainDex() {
-        if (mLoadState == LoadState.LOADED) return;
+        if (mLoadState == LoadState.LOADED) {
+            if (sEnableStateForTesting) {
+                mLoadStateForTesting = LoadState.LOADED;
+            }
+            return;
+        }
         synchronized (mNonMainDexLock) {
             assert mLoadState != LoadState.NOT_LOADED;
             if (mLoadState == LoadState.LOADED) return;
@@ -874,6 +912,9 @@
                     LibraryLoaderJni.get().registerNonMainDexJni();
                 }
                 mLoadState = LoadState.LOADED;
+                if (sEnableStateForTesting) {
+                    mLoadStateForTesting = LoadState.LOADED;
+                }
             }
         }
     }
@@ -932,7 +973,7 @@
     // switch the Java CommandLine will delegate all calls the native CommandLine).
     @GuardedBy("mLock")
     private void ensureCommandLineSwitchedAlreadyLocked() {
-        assert mLoadState >= LoadState.MAIN_DEX_LOADED;
+        assert isMainDexLoaded();
         if (mCommandLineSwitched) {
             return;
         }
@@ -952,7 +993,12 @@
     // Invoke base::android::LibraryLoaded in library_loader_hooks.cc
     @GuardedBy("mLock")
     private void initializeAlreadyLocked() {
-        if (mInitialized) return;
+        if (mInitialized) {
+            if (sEnableStateForTesting) {
+                mInitializedForTesting = true;
+            }
+            return;
+        }
         assert mLibraryProcessType != LibraryProcessType.PROCESS_UNINITIALIZED;
 
         if (mLibraryProcessType == LibraryProcessType.PROCESS_BROWSER) {
@@ -995,6 +1041,9 @@
         // Note that this flag can be accessed asynchronously, so any initialization
         // must be performed before.
         mInitialized = true;
+        if (sEnableStateForTesting) {
+            mInitializedForTesting = true;
+        }
     }
 
     /**
@@ -1045,6 +1094,10 @@
         LibraryLoader self = getInstance();
         self.mLoadState = LoadState.LOADED;
         self.mInitialized = true;
+        if (sEnableStateForTesting) {
+            self.mInitializedForTesting = true;
+            self.mLoadStateForTesting = LoadState.LOADED;
+        }
     }
 
     public static void setBrowserProcessStartupBlockedForTesting() {
diff --git a/base/android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java b/base/android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java
index 903e704..f1175da 100644
--- a/base/android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java
+++ b/base/android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java
@@ -19,7 +19,9 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.RequiresRestart;
 import org.chromium.build.BuildConfig;
 import org.chromium.build.annotations.MainDex;
 
@@ -31,19 +33,26 @@
 @RunWith(BaseJUnit4ClassRunner.class)
 @JNINamespace("base")
 @MainDex
+@Batch(Batch.UNIT_TESTS)
 public class EarlyNativeTest {
+    private boolean mWasInitialized;
     private CallbackHelper mLoadMainDexStarted;
     private CallbackHelper mEnsureMainDexInitializedFinished;
 
     @Before
     public void setUp() {
+        mWasInitialized = LibraryLoader.getInstance().isInitialized();
+        LibraryLoader.getInstance().resetForTesting();
         mLoadMainDexStarted = new CallbackHelper();
         mEnsureMainDexInitializedFinished = new CallbackHelper();
     }
 
     @After
     public void tearDown() {
-        NativeLibraryLoadedStatus.setProvider(null);
+        // Restore the simulated library state (due to the resetForTesting() call).
+        if (mWasInitialized) {
+            LibraryLoader.getInstance().ensureInitialized();
+        }
     }
 
     private class TestLibraryLoader extends LibraryLoader {
@@ -84,12 +93,17 @@
 
         LibraryLoader.getInstance().ensureInitialized();
         Assert.assertTrue(LibraryLoader.getInstance().isInitialized());
+
+        // Test resetForTesting().
+        LibraryLoader.getInstance().resetForTesting();
+        Assert.assertFalse(LibraryLoader.getInstance().isInitialized());
+        LibraryLoader.getInstance().ensureInitialized();
+        Assert.assertTrue(LibraryLoader.getInstance().isInitialized());
     }
 
     private void doTestFullInitializationDoesntBlockMainDexInitialization(final boolean initialize)
             throws Exception {
         final TestLibraryLoader loader = new TestLibraryLoader();
-        loader.enableJniChecks();
         loader.setLibraryProcessType(LibraryProcessType.PROCESS_BROWSER);
         final Thread t1 = new Thread(() -> {
             if (initialize) {
@@ -113,12 +127,14 @@
 
     @Test
     @SmallTest
+    @RequiresRestart("Uses custom LibraryLoader")
     public void testFullInitializationDoesntBlockMainDexInitialization() throws Exception {
         doTestFullInitializationDoesntBlockMainDexInitialization(true);
     }
 
     @Test
     @SmallTest
+    @RequiresRestart("Uses custom LibraryLoader")
     public void testLoadDoesntBlockMainDexInitialization() throws Exception {
         doTestFullInitializationDoesntBlockMainDexInitialization(false);
     }
@@ -129,8 +145,6 @@
         // Test is a no-op if DCHECK isn't on.
         if (!BuildConfig.ENABLE_ASSERTS) return;
 
-        LibraryLoader.getInstance().enableJniChecks();
-
         Assert.assertFalse(
                 NativeLibraryLoadedStatus.getProviderForTesting().areMainDexNativeMethodsReady());
         Assert.assertFalse(
@@ -155,8 +169,6 @@
         // Test is a no-op if dcheck isn't on.
         if (!BuildConfig.ENABLE_ASSERTS) return;
 
-        LibraryLoader.getInstance().enableJniChecks();
-
         try {
             EarlyNativeTestJni.get().isCommandLineInitialized();
             Assert.fail("Using JNI before the library is loaded should throw an exception.");
diff --git a/base/fuchsia/scheduler.h b/base/fuchsia/scheduler.h
index cfd06cb..9f20ba82 100644
--- a/base/fuchsia/scheduler.h
+++ b/base/fuchsia/scheduler.h
@@ -15,7 +15,7 @@
 // this constants.
 constexpr TimeDelta kAudioSchedulingPeriod = Milliseconds(10);
 
-// Reserve 30% of one CPU core for audio threads.
+// Request 30% max CPU deadline utilization for an audio thread.
 // TODO(crbug.com/1174811): A different value may need to be used for WebAudio
 // threads (see media::FuchsiaAudioOutputDevice). A higher capacity may need to
 // be allocated in that case.
@@ -26,7 +26,7 @@
 // this constants.
 constexpr TimeDelta kDisplaySchedulingPeriod = Seconds(1) / 60;
 
-// Reserve 50% of one CPU core for display threads.
+// Request 50% max CPU deadline utilization for a display thread.
 // TODO(crbug.com/1181421): Currently DISPLAY priority is not enabled for any
 // thread on Fuchsia. The value below will need to be fine-tuned when it's
 // enabled.
diff --git a/base/memory/raw_ref.h b/base/memory/raw_ref.h
index 0c8afdf..96f3688 100644
--- a/base/memory/raw_ref.h
+++ b/base/memory/raw_ref.h
@@ -122,6 +122,11 @@
       p.inner_ = nullptr;
   }
 
+  static ALWAYS_INLINE raw_ref from_ptr(T* ptr) noexcept {
+    CHECK(ptr);
+    return raw_ref(*ptr);
+  }
+
   // Upcast assignment
   template <class U, class = std::enable_if_t<std::is_convertible_v<U&, T&>>>
   ALWAYS_INLINE raw_ref& operator=(const raw_ref<U, RawPtrType>& p) noexcept {
diff --git a/base/memory/raw_ref_unittest.cc b/base/memory/raw_ref_unittest.cc
index e34bf86..4adc2eb 100644
--- a/base/memory/raw_ref_unittest.cc
+++ b/base/memory/raw_ref_unittest.cc
@@ -349,6 +349,16 @@
       { [[maybe_unused]] auto r2 = raw_ref<BaseClass>(std::move(r)); });
 }
 
+TEST(RawRef, FromPtr) {
+  int i = 42;
+  auto ref = raw_ref<int>::from_ptr(&i);
+  EXPECT_EQ(&i, &*ref);
+}
+
+TEST(RawRefDeathTest, FromPtrWithNullptr) {
+  EXPECT_CHECK_DEATH({ raw_ref<int>::from_ptr(nullptr); });
+}
+
 TEST(RawRef, CopyAssignUpCast) {
   {
     auto s = SubClass();
diff --git a/base/threading/platform_thread_fuchsia.cc b/base/threading/platform_thread_fuchsia.cc
index 88fe8af..ccc0754 100644
--- a/base/threading/platform_thread_fuchsia.cc
+++ b/base/threading/platform_thread_fuchsia.cc
@@ -8,6 +8,8 @@
 #include <sched.h>
 #include <zircon/syscalls.h>
 
+#include <mutex>
+
 #include <fuchsia/media/cpp/fidl.h>
 #include <lib/fdio/directory.h>
 #include <lib/sys/cpp/component_context.h>
@@ -26,15 +28,26 @@
 
 fuchsia::media::ProfileProviderSyncPtr ConnectProfileProvider() {
   fuchsia::media::ProfileProviderSyncPtr profile_provider;
-  base::ComponentContextForProcess()->svc()->Connect(
+  const zx_status_t status = base::ComponentContextForProcess()->svc()->Connect(
       profile_provider.NewRequest());
+  if (status != ZX_OK) {
+    ZX_LOG(ERROR, status)
+        << "Failed to connect to ProfileProvider! Is "
+           "fuchsia.media.ProfileProvider in the component sandbox?";
+  }
   return profile_provider;
 }
 
-void ScheduleAsMediaThread(StringPiece name, TimeDelta period, float capacity) {
-  DCHECK(!period.is_zero());
-  DCHECK_GT(capacity, 0.0);
-  DCHECK_LT(capacity, 1.0);
+// Sets the current thread to the given scheduling role, optionally including
+// hints about the workload period and max CPU runtime (capacity * period) in
+// that period.
+// TODO(crbug.com/1365682): Migrate to the new fuchsia.scheduler.ProfileProvider
+// API when available.
+void SetThreadRole(StringPiece role_name,
+                   TimeDelta period = {},
+                   float capacity = 0.0f) {
+  DCHECK_GE(capacity, 0.0);
+  DCHECK_LE(capacity, 1.0);
 
   static const base::NoDestructor<fuchsia::media::ProfileProviderSyncPtr>
       profile_provider(ConnectProfileProvider());
@@ -44,17 +57,12 @@
       zx::thread::self()->duplicate(ZX_RIGHT_SAME_RIGHTS, &dup_thread);
   ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
 
+  std::string role_selector{role_name};
   int64_t out_period, out_capacity;
-  status = (*profile_provider)
-               ->RegisterHandlerWithCapacity(
-                   std::move(dup_thread), std::string(name),
-                   period.ToZxDuration(), capacity, &out_period, &out_capacity);
-
-  if (status != ZX_OK) {
-    ZX_LOG(WARNING, status)
-        << "Failed to register a realtime thread. Is "
-           "fuchsia.media.ProfileProvider in the component sandbox?";
-  }
+  (*profile_provider)
+      ->RegisterHandlerWithCapacity(std::move(dup_thread), role_selector,
+                                    period.ToZxDuration(), capacity,
+                                    &out_period, &out_capacity);
 }
 
 }  // namespace
@@ -87,21 +95,32 @@
 void SetCurrentThreadTypeImpl(ThreadType thread_type,
                               MessagePumpType pump_type_hint) {
   switch (thread_type) {
-    case ThreadType::kBackground:
-    case ThreadType::kResourceEfficient:
     case ThreadType::kDefault:
+      SetThreadRole("chromium.base.threading.default");
+
+      break;
+
+    case ThreadType::kBackground:
+      SetThreadRole("chromium.base.threading.background");
+      break;
+
+    case ThreadType::kResourceEfficient:
+      SetThreadRole("chromium.base.threading.resource-efficient");
+      break;
+
     case ThreadType::kCompositing:
+      SetThreadRole("chromium.base.threading.compositing",
+                    kDisplaySchedulingPeriod, kDisplaySchedulingCapacity);
       break;
 
     case ThreadType::kDisplayCritical:
-      ScheduleAsMediaThread("chromium.base.threading.display",
-                            kDisplaySchedulingPeriod,
-                            kDisplaySchedulingCapacity);
+      SetThreadRole("chromium.base.threading.display", kDisplaySchedulingPeriod,
+                    kDisplaySchedulingCapacity);
       break;
 
     case ThreadType::kRealtimeAudio:
-      ScheduleAsMediaThread("chromium.base.threading.realtime-audio",
-                            kAudioSchedulingPeriod, kAudioSchedulingCapacity);
+      SetThreadRole("chromium.base.threading.realtime-audio",
+                    kAudioSchedulingPeriod, kAudioSchedulingCapacity);
       break;
   }
 }
diff --git a/build/android/gyp/assert_static_initializers.py b/build/android/gyp/assert_static_initializers.py
index 225c75e3..4d4e3f3 100755
--- a/build/android/gyp/assert_static_initializers.py
+++ b/build/android/gyp/assert_static_initializers.py
@@ -41,24 +41,14 @@
                     'Your output directory is likely stale.')
 
 
-def _GetStaticInitializers(so_path, tool_prefix):
-  output = subprocess.check_output(
-      [_DUMP_STATIC_INITIALIZERS_PATH, '-d', so_path, '-t', tool_prefix],
-      encoding='utf-8')
-  summary = re.search(r'Found \d+ static initializers in (\d+) files.', output)
-  return output.splitlines()[:-1], int(summary.group(1))
-
-
-def _PrintDumpSIsCount(apk_so_name, unzipped_so, out_dir, tool_prefix):
+def _DumpStaticInitializers(apk_so_name, unzipped_so, out_dir, tool_prefix):
   lib_name = os.path.basename(apk_so_name).replace('crazy.', '')
   so_with_symbols_path = os.path.join(out_dir, 'lib.unstripped', lib_name)
   if not os.path.exists(so_with_symbols_path):
     raise Exception('Unstripped .so not found. Looked here: %s' %
                     so_with_symbols_path)
   _VerifyLibBuildIdsMatch(tool_prefix, unzipped_so, so_with_symbols_path)
-  sis, _ = _GetStaticInitializers(so_with_symbols_path, tool_prefix)
-  for si in sis:
-    print(si)
+  subprocess.check_call([_DUMP_STATIC_INITIALIZERS_PATH, so_with_symbols_path])
 
 
 def _ReadInitArray(so_path, tool_prefix, expect_no_initializers):
@@ -126,10 +116,7 @@
         si_count += _CountStaticInitializers(temp.name, tool_prefix,
                                              expect_no_initializers)
         if dump_sis:
-          # Print count and list of SIs reported by dump-static-initializers.py.
-          # Doesn't work well on all archs (particularly arm), which is why
-          # the readelf method is used for tracking SI counts.
-          _PrintDumpSIsCount(f.filename, temp.name, out_dir, tool_prefix)
+          _DumpStaticInitializers(f.filename, temp.name, out_dir, tool_prefix)
   return si_count
 
 
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index cd9b186..f272b18 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -738,6 +738,12 @@
     ldflags += [ "-Wl,--no-rosegment" ]
   }
 
+  # TODO(crbug.com/1374347): Cleanup undefined symbol errors caught by 
+  # --no-undefined-version.
+  if (use_lld && !is_win && !is_mac && !is_ios) {
+    ldflags += [ "-Wl,--undefined-version" ]
+  }
+
   # LLD does call-graph-sorted binary layout by default when profile data is
   # present. On Android this increases binary size due to more thinks for long
   # jumps. Turn it off by default and enable selectively for targets where it's
diff --git a/build/fuchsia/cipd/BUILD.gn b/build/fuchsia/cipd/BUILD.gn
index 12b6dd73..e04fc877 100644
--- a/build/fuchsia/cipd/BUILD.gn
+++ b/build/fuchsia/cipd/BUILD.gn
@@ -338,7 +338,7 @@
 build_id_dir(_web_engine_build_ids_target) {
   testonly = true  # Some of the archives contain test packages.
   output_path = _web_engine_debug_symbols_outdir
-  deps = [ ":web_engine_archives_with_symbols" ]
+  deps = [ ":web_engine_archives_with_tests" ]
 }
 
 fuchsia_cipd_package(_web_engine_debug_symbols_archive_name) {
@@ -396,7 +396,7 @@
 }
 
 # Used by both the main group as well as :debug_symbols.
-group("web_engine_archives_with_symbols") {
+group("web_engine_archives_with_tests") {
   testonly = true  # tests and web_engine_shell are testonly.
   deps = [
     ":tests${_archive_suffix}",
@@ -405,16 +405,17 @@
   ]
 }
 
-# TODO(zijiehe): Revisit the naming in this file.
-# E.g. web_engine_archives_with_symbols and web_engine_debug_symbols look
-# similar and it's unclear if the previous one covers the later one from only
-# the name.
+# TODO(zijiehe): Rename to "cipd_yaml" when possible.
+# This target only creates yaml files and related archives for cipd rather
+# than executing the cipd instance to upload them.
+# Currently it's named as "cipd" to match the folder name which introduces
+# confusions.
 group("cipd") {
   testonly = true  # Some archives are testonly.
   deps = [
     ":chrome${_archive_suffix}",
     ":chrome_debug_symbols",
-    ":web_engine_archives_with_symbols",
+    ":web_engine_archives_with_tests",
 
     # Symbols are not uploaded for the following.
     ":chromedriver${_archive_suffix}",
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index 7a145d73..1542969 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-9.20221011.3.1
+10.20221013.1.1
diff --git a/build/fuchsia/test/ffx_integration.py b/build/fuchsia/test/ffx_integration.py
index 44dbd51..9ec0b54a 100644
--- a/build/fuchsia/test/ffx_integration.py
+++ b/build/fuchsia/test/ffx_integration.py
@@ -90,6 +90,10 @@
                  with_network: bool,
                  logs_dir: Optional[str] = None) -> None:
         if product_bundle:
+
+            # TODO(fxb/111222): Remove when SDK images' names align with ffx's.
+            if product_bundle == 'workstation_eng.qemu-x64-release':
+                product_bundle = 'workstation_eng.qemu-x64'
             self._product_bundle = product_bundle
         else:
             target_cpu = get_host_arch()
diff --git a/build/fuchsia/test/start_emulator.py b/build/fuchsia/test/start_emulator.py
index 71b4373e..9c96d66 100755
--- a/build/fuchsia/test/start_emulator.py
+++ b/build/fuchsia/test/start_emulator.py
@@ -18,6 +18,10 @@
     """Register emulator specific arguments."""
     femu_args = parser.add_argument_group('emulator',
                                           'emulator startup arguments.')
+    femu_args.add_argument('--custom-image',
+                           dest='product_bundle',
+                           help='Backwards compatible flag that specifies an '
+                           'image used for booting up the emulator.')
     if enable_graphics:
         femu_args.add_argument('--disable-graphics',
                                action='store_false',
diff --git a/build/sanitizers/sanitizer_options.cc b/build/sanitizers/sanitizer_options.cc
index 93d3ea1..b2ee020 100644
--- a/build/sanitizers/sanitizer_options.cc
+++ b/build/sanitizers/sanitizer_options.cc
@@ -41,25 +41,19 @@
 //   symbolize=1 - enable in-process symbolization.
 //   external_symbolizer_path=... - provides the path to llvm-symbolizer
 //     relative to the main executable
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) | BUILDFLAG(IS_APPLE)
 const char kAsanDefaultOptions[] =
     "strip_path_prefix=/../../ fast_unwind_on_fatal=1 "
     "detect_stack_use_after_return=1 symbolize=1 detect_leaks=0 "
     "external_symbolizer_path=%d/../../third_party/llvm-build/Release+Asserts/"
     "bin/llvm-symbolizer";
-
-#elif BUILDFLAG(IS_APPLE)
-const char* kAsanDefaultOptions =
-    "strip_path_prefix=/../../ fast_unwind_on_fatal=1 "
-    "detect_stack_use_after_return=1 ";
-
 #elif BUILDFLAG(IS_WIN)
 const char* kAsanDefaultOptions =
     "strip_path_prefix=\\..\\..\\ fast_unwind_on_fatal=1 "
     "detect_stack_use_after_return=1 symbolize=1 "
     "external_symbolizer_path=%d/../../third_party/"
     "llvm-build/Release+Asserts/bin/llvm-symbolizer.exe";
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE)
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE) || \
     BUILDFLAG(IS_WIN)
@@ -123,12 +117,8 @@
 //     relative to the main executable
 const char kMsanDefaultOptions[] =
     "strip_path_prefix=/../../ "
-
-#if !BUILDFLAG(IS_APPLE)
     "external_symbolizer_path=%d/../../third_party/llvm-build/Release+Asserts/"
-    "bin/llvm-symbolizer"
-#endif
-    ;
+    "bin/llvm-symbolizer";
 
 SANITIZER_HOOK_ATTRIBUTE const char *__msan_default_options() {
   return kMsanDefaultOptions;
@@ -153,7 +143,7 @@
 const char kLsanDefaultOptions[] =
     "strip_path_prefix=/../../ use_poisoned=1 "
 
-#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
     "external_symbolizer_path=%d/../../third_party/llvm-build/Release+Asserts/"
     "bin/llvm-symbolizer "
 #endif
@@ -189,12 +179,8 @@
 //   print_stacktrace=1 - print the stacktrace when UBSan reports an error.
 const char kUbsanDefaultOptions[] =
     "print_stacktrace=1 strip_path_prefix=/../../ "
-
-#if !BUILDFLAG(IS_APPLE)
     "external_symbolizer_path=%d/../../third_party/llvm-build/Release+Asserts/"
-    "bin/llvm-symbolizer"
-#endif
-    ;
+    "bin/llvm-symbolizer";
 
 SANITIZER_HOOK_ATTRIBUTE const char* __ubsan_default_options() {
   return kUbsanDefaultOptions;
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni
index 8e0ad585..33ce489 100644
--- a/buildtools/deps_revisions.gni
+++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@
 declare_args() {
   # Used to cause full rebuilds on libc++ rolls. This should be kept in sync
   # with the libcxx_revision vars in //DEPS.
-  libcxx_revision = "64d36e572d3f9719c5d75011a718f33f11126851"
+  libcxx_revision = "9538eadcb333899b5595b289292ce59b90888501"
 }
diff --git a/cc/document_transition/document_transition_request.cc b/cc/document_transition/document_transition_request.cc
index 02d04d0..1bf2845 100644
--- a/cc/document_transition/document_transition_request.cc
+++ b/cc/document_transition/document_transition_request.cc
@@ -25,8 +25,6 @@
   switch (type) {
     case viz::CompositorFrameTransitionDirective::Type::kSave:
       return "kSave";
-    case viz::CompositorFrameTransitionDirective::Type::kAnimate:
-      return "kAnimate";
     case viz::CompositorFrameTransitionDirective::Type::kAnimateRenderer:
       return "kAnimateRenderer";
     case viz::CompositorFrameTransitionDirective::Type::kRelease:
@@ -113,10 +111,8 @@
   }
 
   // TODO(vmpstr): Clean up the directive parameters.
-  return viz::CompositorFrameTransitionDirective(
-      sequence_id_, type_,
-      viz::CompositorFrameTransitionDirective::Effect::kNone,
-      std::move(shared_elements));
+  return viz::CompositorFrameTransitionDirective(sequence_id_, type_,
+                                                 std::move(shared_elements));
 }
 
 std::string DocumentTransitionRequest::ToString() const {
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index d1e462da..46732cf 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -58,6 +58,7 @@
   "java/src/org/chromium/chrome/browser/about_settings/AboutSettingsBridge.java",
   "java/src/org/chromium/chrome/browser/about_settings/HyperlinkPreference.java",
   "java/src/org/chromium/chrome/browser/about_settings/LegalInformationSettings.java",
+  "java/src/org/chromium/chrome/browser/accessibility/AccessibilityTabHelper.java",
   "java/src/org/chromium/chrome/browser/accessibility/settings/ChromeAccessibilitySettingsDelegate.java",
   "java/src/org/chromium/chrome/browser/accessibility_tab_switcher/AccessibilityTabModelAdapter.java",
   "java/src/org/chromium/chrome/browser/accessibility_tab_switcher/AccessibilityTabModelListItem.java",
@@ -995,6 +996,9 @@
   "java/src/org/chromium/chrome/browser/searchwidget/SearchType.java",
   "java/src/org/chromium/chrome/browser/searchwidget/SearchWidgetProvider.java",
   "java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionController.java",
+  "java/src/org/chromium/chrome/browser/segmentation_platform/PriceTrackingActionProvider.java",
+  "java/src/org/chromium/chrome/browser/segmentation_platform/ReaderModeActionProvider.java",
+  "java/src/org/chromium/chrome/browser/segmentation_platform/SignalAccumulator.java",
   "java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerServiceImpl.java",
   "java/src/org/chromium/chrome/browser/services/gcm/GCMBackgroundServiceImpl.java",
   "java/src/org/chromium/chrome/browser/services/gcm/GCMBackgroundTask.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index b320343..1dafa18 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -1,5 +1,8 @@
 chrome_junit_test_java_sources = [
   "java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerTest.java",
+  "java/src/org/chromium/chrome/browser/segmentation_platform/PriceTrackingActionProviderTest.java",
+  "java/src/org/chromium/chrome/browser/segmentation_platform/ReaderModeActionProviderTest.java",
+  "java/src/org/chromium/chrome/browser/segmentation_platform/SignalAccumulatorTest.java",
   "java/src/org/chromium/chrome/browser/tab/TabFaviconTest.java",
   "junit/src/org/chromium/chrome/browser/AppIndexingUtilTest.java",
   "junit/src/org/chromium/chrome/browser/BackPressHelperUnitTest.java",
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java
index e0e0bce..2dc3bb9c 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java
@@ -42,7 +42,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ClientSettingsProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ClientSettingsProto.IntegrationTestSettings;
@@ -106,7 +106,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "see crbug.com/1207665")
+    @DisabledTest(message = "see crbug.com/1207665")
     public void testBottomSheetHasRestrictedFixedHeight() throws Exception {
         ArrayList<ActionProto> list = new ArrayList<>();
 
@@ -178,7 +178,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1254423")
+    @DisabledTest(message = "https://crbug.com/1254423")
     public void testBottomSheetListensToAccessibilityChanges() throws Exception {
         ArrayList<ActionProto> list = new ArrayList<>();
 
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
index e049abf6..0bfe11db 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
@@ -42,7 +42,6 @@
 
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipProto;
@@ -267,7 +266,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1237330")
+    @DisabledTest(message = "https://crbug.com/1237330")
     public void switchingTabsRestoresBottomSheetState() {
         ArrayList<ActionProto> listA = new ArrayList<>();
         listA.add(ActionProto.newBuilder()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
index 4a52f951..a46184a 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
@@ -66,7 +66,6 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
@@ -699,7 +698,7 @@
      */
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1183594")
+    @DisabledTest(message = "https://crbug.com/1183594")
     public void testExternalAddExpiredCreditCard() throws Exception {
         // Add address for card.
         String profileId = mHelper.addDummyProfile("John Doe", "johndoe@google.com");
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java
index 7e2a20b..00b9cf8 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java
@@ -49,7 +49,6 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.Empty;
@@ -165,7 +164,7 @@
     @EnableFeatures(AssistantFeatures.AUTOFILL_ASSISTANT_PROACTIVE_HELP_NAME)
     @DisableIf.
     Build(message = "See https://crbug.com/1199849", sdk_is_greater_than = VERSION_CODES.O_MR1)
-    @FlakyTest(message = "crbug.com/1199416")
+    @DisabledTest(message = "crbug.com/1199416")
     public void setReturningUserFlag() {
         TriggerScriptProto.Builder firstTimeTriggerScript =
                 TriggerScriptProto.newBuilder()
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryIntegrationTest.java
index 7feb410..2d327e1 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryIntegrationTest.java
@@ -39,7 +39,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisableIf;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.ChromeWindow;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -179,7 +179,7 @@
      */
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/984489")
+    @DisabledTest(message = "https://crbug.com/984489")
     public void testSwitchFieldsRescrollsKeyboardAccessory() throws TimeoutException {
         loadTestPage(FakeKeyboard::new);
         mHelper.clickNodeAndShowKeyboard("EMAIL_ADDRESS", 8);
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java
index acdcbc1..23d06ad 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java
+++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java
@@ -48,9 +48,9 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -198,7 +198,7 @@
     @Feature({"StartSurface", "TabGroup"})
     @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS})
     @EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID})
-    @FlakyTest(message = "https://crbug.com/1232695")
+    @DisabledTest(message = "https://crbug.com/1232695")
     public void testCreateTabWithinTabGroup() throws Exception {
         // Create tab state files for a group with two tabs.
         TabUiTestHelper.finishActivity(mActivityTestRule.getActivity());
@@ -263,7 +263,7 @@
     @Test
     @LargeTest
     @Feature({"StartSurface"})
-    @FlakyTest(message = "https://crbug.com/1295839")
+    @DisabledTest(message = "https://crbug.com/1295839")
     @CommandLineFlags.
     Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS + "/show_tabs_in_mru_order/true"})
     public void test_CarouselTabSwitcherShowTabsInMRUOrder() {
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutPerfTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutPerfTest.java
index f0e6d6b..ba1586fd 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutPerfTest.java
+++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutPerfTest.java
@@ -37,7 +37,6 @@
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.EnormousTest;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
@@ -186,7 +185,7 @@
 
     @Test
     @EnormousTest
-    @FlakyTest(message = "https://crbug.com/1045938")
+    @DisabledTest(message = "https://crbug.com/1045938")
     @CommandLineFlags.Add({BASE_PARAMS})
     public void testTabToGridFromLiveTabWith10TabsWithoutThumbnail() throws InterruptedException {
         // Note that most of the tabs won't have thumbnails.
@@ -352,7 +351,7 @@
     @Test
     @EnormousTest
     @CommandLineFlags.Add({BASE_PARAMS})
-    @FlakyTest(message = "https://crbug.com/1225926")
+    @DisabledTest(message = "https://crbug.com/1225926")
     public void testGridToTabToOtherLive() throws InterruptedException, TimeoutException {
         prepareTabs(2, mUrl);
         reportGridToTabPerf(true, false, "Grid-to-Tab to other live tab");
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutTest.java
index e015e39..a2945cfd 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutTest.java
+++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutTest.java
@@ -86,7 +86,6 @@
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -452,7 +451,7 @@
     @MediumTest
     @EnableFeatures({ChromeFeatureList.TAB_TO_GTS_ANIMATION + "<Study"})
     @CommandLineFlags.Add({BASE_PARAMS})
-    @FlakyTest(message = "crbug.com/1130830")
+    @DisabledTest(message = "crbug.com/1130830")
     public void testTabToGridFromNtp() throws InterruptedException {
         prepareTabs(2, 0, NTP_URL);
         testTabToGrid(NTP_URL);
@@ -698,7 +697,7 @@
     @MediumTest
     @EnableFeatures({ChromeFeatureList.TAB_TO_GTS_ANIMATION + "<Study"})
     @CommandLineFlags.Add({BASE_PARAMS + "/soft-cleanup-delay/2000/cleanup-delay/10000"})
-    @FlakyTest(message = "crbug.com/1130830")
+    @DisabledTest(message = "crbug.com/1130830")
     public void testInvisibleTabsDontFetchWarm() throws InterruptedException {
         // Get the GTS in the warm state.
         prepareTabs(2, 0, NTP_URL);
@@ -723,7 +722,7 @@
     @MediumTest
     @EnableFeatures({ChromeFeatureList.TAB_TO_GTS_ANIMATION + "<Study"})
     @CommandLineFlags.Add({BASE_PARAMS + "/cleanup-delay/10000"})
-    @FlakyTest(message = "crbug.com/1130830")
+    @DisabledTest(message = "crbug.com/1130830")
     public void testInvisibleTabsDontFetchSoft() throws InterruptedException {
         // Get the GTS in the soft cleaned up state.
         prepareTabs(2, 0, NTP_URL);
@@ -1484,7 +1483,7 @@
     @MediumTest
     @EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID})
     @DisableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION)
-    @FlakyTest(message = "crbug.com/1096997")
+    @DisabledTest(message = "crbug.com/1096997")
     public void testTabGroupManualSelection() throws InterruptedException {
         ChromeTabbedActivity cta = mActivityTestRule.getActivity();
         TabSelectionEditorTestingRobot robot = new TabSelectionEditorTestingRobot();
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceTrackingDialogTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceTrackingDialogTest.java
index c117c09..4c2958e 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceTrackingDialogTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceTrackingDialogTest.java
@@ -47,7 +47,6 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -243,7 +242,7 @@
     @MediumTest
     @Feature({"RenderTest"})
     @CommandLineFlags.Add({BASE_PARAMS + "/enable_price_notification/true"})
-    @FlakyTest(message = "https://crbug.com/1233364")
+    @DisabledTest(message = "https://crbug.com/1233364")
     public void testRenderPriceTrackingDialog_Landscape() throws IOException {
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
 
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
index 3cdadd5..b7242e2c 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
@@ -93,7 +93,6 @@
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
@@ -836,7 +835,7 @@
     @MediumTest
     @Feature({"RenderTest"})
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
-    @FlakyTest(message = "https://crbug.com/1139475")
+    @DisabledTest(message = "https://crbug.com/1139475")
     public void testRenderDialog_3Tabs_Portrait(boolean nightModeEnabled) throws Exception {
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
         prepareTabsWithThumbnail(mActivityTestRule, 3, 0, "about:blank");
@@ -856,7 +855,7 @@
     @Test
     @MediumTest
     @Feature({"RenderTest"})
-    @FlakyTest(message = "https://crbug.com/1110099")
+    @DisabledTest(message = "https://crbug.com/1110099")
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
     public void testRenderDialog_3Tabs_Landscape(boolean nightModeEnabled) throws Exception {
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinderTest.java
index e9e6f5c..d7e42cbc 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinderTest.java
@@ -32,7 +32,7 @@
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisableIf;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -166,7 +166,7 @@
     @Test
     @MediumTest
     @Features.EnableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION)
-    @FlakyTest(message = "https://crbug.com/1182554")
+    @DisabledTest(message = "https://crbug.com/1182554")
     public void testHidesWithAnimation() {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mContainerModel.set(
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
index d0ff9f0..e39635d 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
@@ -64,8 +64,8 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.RequiresRestart;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -334,7 +334,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1237368")
+    @DisabledTest(message = "https://crbug.com/1237368")
     public void testToolbarGroupButton() {
         prepareBlankTab(2, false);
         List<Tab> tabs = getTabsInCurrentTabModel();
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 86a8b56a..ff03416f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1742,7 +1742,7 @@
                 /* appMenuBlocker= */ this, this::supportsAppMenu, this::supportsFindInPage,
                 getTabCreatorManagerSupplier(), getFullscreenManager(),
                 getCompositorViewHolderSupplier(), getTabContentManagerSupplier(),
-                this::getSnackbarManager, getActivityType(), this::shouldShowOverviewPageOnStart,
+                this::getSnackbarManager, getActivityType(), this::isInOverviewMode,
                 this::isWarmOnResume,
                 /* appMenuDelegate= */ this,
                 /* statusBarColorProvider= */ this, new ObservableSupplierImpl<>(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/accessibility/AccessibilityTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/accessibility/AccessibilityTabHelper.java
new file mode 100644
index 0000000..f2fa5cde
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/accessibility/AccessibilityTabHelper.java
@@ -0,0 +1,83 @@
+// Copyright 2022 The Chromium Authors
+// 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.accessibility;
+
+import org.chromium.base.UserData;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContentsAccessibility;
+import org.chromium.ui.base.WindowAndroid;
+
+/**
+ *  Helper class that wraps accessibility state information for {Tab}.
+ */
+public class AccessibilityTabHelper extends EmptyTabObserver implements UserData {
+    public static final Class<AccessibilityTabHelper> USER_DATA_KEY = AccessibilityTabHelper.class;
+
+    private final Tab mTab;
+    private WebContents mWebContents;
+
+    /**
+     * Creates an instance of {AccessibilityTabHelper} for the given tab.
+     * @param tab Tab to observe.
+     */
+    public static void createForTab(Tab tab) {
+        tab.getUserDataHost().setUserData(USER_DATA_KEY, new AccessibilityTabHelper(tab));
+    }
+
+    /**
+     * Constructs a new {AccessibilityTabHelper} object for the given tab.
+     * @param tab Tab to observe.
+     */
+    private AccessibilityTabHelper(Tab tab) {
+        mTab = tab;
+        mTab.addObserver(this);
+        mWebContents = tab.getWebContents();
+        if (mWebContents != null) updateWebContentsAccessibilityStateForTab(tab);
+    }
+
+    /**
+     * Communicate accessibility state information for this embedder to the
+     * {WebContentsAccessibility} object for the given tab. These values are used to determine
+     * which accessibility features are enabled for the associated {WebContents}; which is dependent
+     * on both user device settings, and the embedder of this Tab.
+     * @param tab Tab to update state for.
+     */
+    private void updateWebContentsAccessibilityStateForTab(Tab tab) {
+        assert tab.getWebContents() != null;
+        WebContentsAccessibility wcax =
+                WebContentsAccessibility.fromWebContents(tab.getWebContents());
+
+        // For browser tabs, we want to set accessibility focus to the page when it loads. This
+        // is not the default behavior for embedded web views.
+        wcax.setShouldFocusOnPageLoad(true);
+
+        // Enable image descriptions feature normally, but not for Chrome Custom Tabs.
+        wcax.setIsImageDescriptionsCandidate(!tab.isCustomTab());
+    }
+
+    @Override
+    public void onActivityAttachmentChanged(Tab tab, WindowAndroid window) {
+        // When the activity attachment changes, we communicate the current accessibility state
+        // since the attachment change could be part of switching embedders (e.g. CCT to Chrome).
+        if (tab.getWebContents() != null) updateWebContentsAccessibilityStateForTab(tab);
+    }
+
+    @Override
+    public void onContentChanged(Tab tab) {
+        // When the content changes, if the current |mWebContents| is different than the given Tab's
+        // we communicate state for the new web contents (e.g. web contents was changed at runtime).
+        if (mWebContents == tab.getWebContents()) return;
+
+        if (tab.getWebContents() != null) updateWebContentsAccessibilityStateForTab(tab);
+        mWebContents = tab.getWebContents();
+    }
+
+    @Override
+    public void destroy() {
+        mTab.removeObserver(this);
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/feed/feedmanagement/FeedManagementActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/feed/feedmanagement/FeedManagementActivity.java
index 75abe71..5dc4146 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/feed/feedmanagement/FeedManagementActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/feed/feedmanagement/FeedManagementActivity.java
@@ -7,6 +7,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.view.MenuItem;
+
+import androidx.appcompat.widget.Toolbar;
 
 import org.chromium.base.Log;
 import org.chromium.chrome.browser.SnackbarActivity;
@@ -39,6 +42,22 @@
         FeedManagementCoordinator coordinator =
                 new FeedManagementCoordinator(this, this, this, streamKind);
         setContentView(coordinator.getView());
+
+        // Set up the toolbar and back button.
+        Toolbar toolbar = (Toolbar) findViewById(org.chromium.chrome.browser.feed.R.id.action_bar);
+        setSupportActionBar(toolbar);
+        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                finish();
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
     }
 
     // FollowManagementLauncher method.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/feed/followmanagement/FollowManagementActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/feed/followmanagement/FollowManagementActivity.java
index 79758c0..f3ea30bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/feed/followmanagement/FollowManagementActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/feed/followmanagement/FollowManagementActivity.java
@@ -5,6 +5,9 @@
 package org.chromium.chrome.browser.app.feed.followmanagement;
 
 import android.os.Bundle;
+import android.view.MenuItem;
+
+import androidx.appcompat.widget.Toolbar;
 
 import org.chromium.base.Log;
 import org.chromium.chrome.browser.SnackbarActivity;
@@ -23,5 +26,21 @@
 
         FollowManagementCoordinator coordinator = new FollowManagementCoordinator(this);
         setContentView(coordinator.getView());
+
+        // Set up the toolbar and back button.
+        Toolbar toolbar = (Toolbar) findViewById(org.chromium.chrome.browser.feed.R.id.action_bar);
+        setSupportActionBar(toolbar);
+        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                finish();
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
index 6d9e03e..d4b0518 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
@@ -161,7 +161,6 @@
         ResourceBundle.setAvailablePakLocales(ProductConfig.LOCALES);
         LibraryLoader.getInstance().setLinkerImplementation(
                 ProductConfig.USE_CHROMIUM_LINKER, ProductConfig.USE_MODERN_LINKER);
-        LibraryLoader.getInstance().enableJniChecks();
 
         if (!isBrowserProcess) {
             EarlyTraceEvent.earlyEnableInChildWithoutCommandLine();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
index 5539f03..c3442a0e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
@@ -23,6 +23,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.app.bookmarks.BookmarkActivity;
 import org.chromium.chrome.browser.commerce.ShoppingFeatures;
+import org.chromium.chrome.browser.commerce.ShoppingServiceFactory;
 import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksReader;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.subscriptions.CommerceSubscriptionsServiceFactory;
@@ -212,6 +213,8 @@
                     new CommerceSubscriptionsServiceFactory()
                             .getForLastUsedProfile()
                             .getSubscriptionsManager());
+            ShoppingServiceFactory.getForProfile(Profile.getLastUsedRegularProfile())
+                    .scheduleSavedProductUpdate();
         }
 
         @SuppressWarnings("unchecked")
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRow.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRow.java
index cf4d5ba..2fceb2b9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRow.java
@@ -32,7 +32,6 @@
 import org.chromium.components.power_bookmarks.PowerBookmarkMeta;
 import org.chromium.components.power_bookmarks.ProductPrice;
 
-import java.util.Arrays;
 import java.util.Locale;
 
 /** A row view that shows shopping info in the bookmarks UI. */
@@ -88,23 +87,6 @@
                 meta != null && meta.getShoppingSpecifics().getIsPriceTracked();
         initPriceTrackingUI(meta.getLeadImage().getUrl(), mIsPriceTrackingEnabled,
                 originalPrice.getAmountMicros(), originalPrice.getAmountMicros());
-        // Request an updated price then push updates to the UI.
-        mBookmarkModel.getUpdatedProductPrices(
-                Arrays.asList(bookmarkId), (id, url, updatedPrice) -> {
-                    if (!mBookmarkId.equals(id)
-                            || !originalPrice.getCurrencyCode().equals(
-                                    updatedPrice.getCurrencyCode())) {
-                        return;
-                    }
-
-                    if (updatedPrice.getAmountMicros() > originalPrice.getAmountMicros()) {
-                        PowerBookmarkUtils.updatePriceForBookmarkId(
-                                mBookmarkModel, bookmarkId, updatedPrice);
-                    }
-
-                    setPriceInfoChip(
-                            originalPrice.getAmountMicros(), updatedPrice.getAmountMicros());
-                });
         return bookmarkItem;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
index 049251b..83fc007b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
@@ -512,8 +512,12 @@
                 mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
             }
         } else {
-            height = initialHeightInPortraitMode();
-            mStatus = HeightStatus.INITIAL_HEIGHT;
+            if (mStatus == HeightStatus.INITIAL_HEIGHT) {
+                height = initialHeightInPortraitMode();
+            } else if (mStatus == HeightStatus.TOP) {
+                height = mDisplayHeight - maxExpandedY;
+            }
+
             if (!mWindowAboveNavbar) {
                 mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionController.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionController.java
index dff37d3..1d262c576 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionController.java
@@ -4,12 +4,16 @@
 
 package org.chromium.chrome.browser.segmentation_platform;
 
+import android.os.Handler;
+import android.os.Looper;
+
+import androidx.annotation.VisibleForTesting;
+
 import org.chromium.base.Callback;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.bookmarks.BookmarkModel;
-import org.chromium.chrome.browser.bookmarks.PowerBookmarkUtils;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.CurrentTabObserver;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
@@ -18,24 +22,41 @@
 import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures;
 import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures.AdaptiveToolbarButtonVariant;
 import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarStatePredictor;
-import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.components.commerce.core.ShoppingService;
 import org.chromium.components.segmentation_platform.SegmentSelectionResult;
 import org.chromium.url.GURL;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Central class for contextual page actions bridging between UI and backend. Registers itself with
  * segmentation platform for on-demand model execution on page load triggers. Provides updated
  * button data to the toolbar when asked for it.
  */
 public class ContextualPageActionController {
+    /**
+     * The interface to be implemented by the individual feature backends to provide signals
+     * necessary for the controller in an uniform manner.
+     */
+    public interface ActionProvider {
+        /**
+         * Called during a page load to fetch the relevant signals from the action provider.
+         * @param tab The current tab for which the action would be shown.
+         * @param signalAccumulator An accumulator into which the provider would populate relevant
+         *         signals.
+         */
+        void getAction(Tab tab, SignalAccumulator signalAccumulator);
+    }
+
     private final ObservableSupplier<Profile> mProfileSupplier;
-    private final ObservableSupplier<Tab> mTabSupplier;
-    private final Supplier<ShoppingService> mShoppingServiceSupplier;
-    private final Supplier<BookmarkModel> mBookmarkModelSupplier;
+    private ObservableSupplier<Tab> mTabSupplier;
     private final AdaptiveToolbarButtonController mAdaptiveToolbarButtonController;
     private CurrentTabObserver mCurrentTabObserver;
 
+    // The action provider backends.
+    protected final List<ActionProvider> mActionProviders = new ArrayList<>();
+
     /**
      * Constructor.
      * @param profileSupplier The supplier for current profile.
@@ -50,8 +71,6 @@
             Supplier<BookmarkModel> bookmarkModelSupplier) {
         mProfileSupplier = profileSupplier;
         mTabSupplier = tabSupplier;
-        mShoppingServiceSupplier = shoppingServiceSupplier;
-        mBookmarkModelSupplier = bookmarkModelSupplier;
         mAdaptiveToolbarButtonController = adaptiveToolbarButtonController;
         profileSupplier.addObserver(profile -> {
             if (profile.isOffTheRecord()) return;
@@ -71,9 +90,24 @@
                     if (tab != null) maybeShowContextualPageAction();
                 }
             }, this::activeTabChanged);
+
+            initActionProviders(shoppingServiceSupplier, bookmarkModelSupplier);
         });
     }
 
+    @VisibleForTesting
+    protected void initActionProviders(Supplier<ShoppingService> shoppingServiceSupplier,
+            Supplier<BookmarkModel> bookmarkModelSupplier) {
+        mActionProviders.clear();
+        if (AdaptiveToolbarFeatures.isPriceTrackingPageActionEnabled()) {
+            mActionProviders.add(new PriceTrackingActionProvider(
+                    shoppingServiceSupplier, bookmarkModelSupplier));
+        }
+        if (AdaptiveToolbarFeatures.isReaderModePageActionEnabled()) {
+            mActionProviders.add(new ReaderModeActionProvider());
+        }
+    }
+
     /** Called on destroy. */
     public void destroy() {
         if (mCurrentTabObserver != null) mCurrentTabObserver.destroy();
@@ -88,34 +122,28 @@
     }
 
     private void maybeShowContextualPageAction() {
-        Tab tab = mTabSupplier.get();
-        if (tab == null || tab.isIncognito() || tab.isDestroyed()) {
+        Tab tab = getValidActiveTab();
+        if (tab == null) {
             // On incognito tabs revert back to static action.
-            mAdaptiveToolbarButtonController.showDynamicAction(
-                    AdaptiveToolbarButtonVariant.UNKNOWN);
+            showDynamicAction(AdaptiveToolbarButtonVariant.UNKNOWN);
             return;
         }
         collectSignals(tab);
     }
 
     private void collectSignals(Tab tab) {
-        final BookmarkModel bookmarkModel = mBookmarkModelSupplier.get();
-        bookmarkModel.finishLoadingBookmarkModel(() -> {
-            BookmarkId bookmarkId = bookmarkModel.getUserBookmarkIdForTab(tab);
-            boolean isAlreadyPriceTracked =
-                    PowerBookmarkUtils.isBookmarkPriceTracked(bookmarkModel, bookmarkId);
-            if (isAlreadyPriceTracked) {
-                findBestAction(tab, /*canTrackPrice=*/false);
-            } else {
-                mShoppingServiceSupplier.get().getProductInfoForUrl(tab.getUrl(), (url, info) -> {
-                    boolean canTrackPrice = info != null;
-                    findBestAction(tab, canTrackPrice);
-                });
-            }
-        });
+        if (mActionProviders.isEmpty()) return;
+        final SignalAccumulator signalAccumulator =
+                new SignalAccumulator(new Handler(Looper.getMainLooper()), tab, mActionProviders);
+        signalAccumulator.getSignals(() -> findBestAction(signalAccumulator));
     }
 
-    private void findBestAction(Tab tab, boolean canTrackPrice) {
+    private void findBestAction(SignalAccumulator signalAccumulator) {
+        Tab tab = getValidActiveTab();
+        if (tab == null) return;
+        // TODO(crbug/1373905): Remove this after segmentation integration for reader mode.
+        boolean canTrackPrice =
+                signalAccumulator.hasPriceTracking() || signalAccumulator.hasReaderMode();
         ContextualPageActionControllerJni.get().computeContextualPageAction(
                 mProfileSupplier.get(), tab.getUrl(), canTrackPrice, result -> {
                     if (tab.isDestroyed()) return;
@@ -125,13 +153,31 @@
                     if (!isSameTab) return;
 
                     if (!AdaptiveToolbarFeatures.isContextualPageActionUiEnabled()) return;
-                    mAdaptiveToolbarButtonController.showDynamicAction(
-                            AdaptiveToolbarStatePredictor
-                                    .getAdaptiveToolbarButtonVariantFromSegmentId(
-                                            result.selectedSegment));
+                    int action = AdaptiveToolbarStatePredictor
+                                         .getAdaptiveToolbarButtonVariantFromSegmentId(
+                                                 result.selectedSegment);
+                    // TODO(crbug/1373905): Remove this after segmentation integration for reader
+                    // mode.
+                    if (signalAccumulator.hasReaderMode()) {
+                        action = AdaptiveToolbarButtonVariant.READER_MODE;
+                    }
+                    showDynamicAction(action);
                 });
     }
 
+    private void showDynamicAction(@AdaptiveToolbarButtonVariant int action) {
+        // TODO(crbug/1373891): Add logic to inform reader mode backend.
+        mAdaptiveToolbarButtonController.showDynamicAction(action);
+    }
+
+    /** @return The active regular tab. Null for incognito. */
+    private Tab getValidActiveTab() {
+        if (mProfileSupplier == null || mProfileSupplier.get().isOffTheRecord()) return null;
+        Tab tab = mTabSupplier.get();
+        if (tab == null || tab.isIncognito() || tab.isDestroyed()) return null;
+        return tab;
+    }
+
     @NativeMethods
     interface Natives {
         void computeContextualPageAction(Profile profile, GURL url, boolean canTrackPrice,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerTest.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerTest.java
index 6259496..269cb97f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerTest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerTest.java
@@ -7,7 +7,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -30,6 +29,7 @@
 import org.chromium.base.FeatureList;
 import org.chromium.base.FeatureList.TestValues;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Features;
 import org.chromium.base.test.util.Features.EnableFeatures;
@@ -42,10 +42,6 @@
 import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarButtonController;
 import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures.AdaptiveToolbarButtonVariant;
 import org.chromium.components.commerce.core.ShoppingService;
-import org.chromium.components.commerce.core.ShoppingService.ProductInfo;
-import org.chromium.components.commerce.core.ShoppingService.ProductInfoCallback;
-import org.chromium.components.power_bookmarks.PowerBookmarkMeta;
-import org.chromium.components.power_bookmarks.ShoppingSpecifics;
 import org.chromium.components.segmentation_platform.SegmentSelectionResult;
 import org.chromium.components.segmentation_platform.proto.SegmentationProto.SegmentId;
 
@@ -80,14 +76,6 @@
     @Rule
     public TestRule mProcessor = new Features.JUnitProcessor();
 
-    ContextualPageActionController mContextualPageActionController;
-
-    @Mock
-    private ShoppingService mShoppingService;
-
-    @Mock
-    private BookmarkModel mBookmarkModel;
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -98,45 +86,24 @@
         mJniMocker.mock(ContextualPageActionControllerJni.TEST_HOOKS, mMockControllerJni);
         doReturn(mMockConfiguration).when(mMockResources).getConfiguration();
         doReturn(true).when(mMockActivityLifecycleDispatcher).isNativeInitializationFinished();
-
-        setPriceTrackingBackendResult(false);
-
-        // Setup bookmark model expectations.
-        Mockito.doAnswer(invocation -> {
-                   Runnable runnable = invocation.getArgument(0);
-                   runnable.run();
-                   return null;
-               })
-                .when(mBookmarkModel)
-                .finishLoadingBookmarkModel(any());
-        setPageAlreadyPriceTracked(false);
-    }
-
-    private void setPriceTrackingBackendResult(boolean hasProductInfo) {
-        ProductInfo testProductInfo = new ProductInfo(null, null, 0, 0, null, 0, null);
-        Mockito.doAnswer(invocation -> {
-                   ProductInfoCallback callback = invocation.getArgument(1);
-                   callback.onResult(
-                           invocation.getArgument(0), hasProductInfo ? testProductInfo : null);
-                   return null;
-               })
-                .when(mShoppingService)
-                .getProductInfoForUrl(any(), any());
-    }
-
-    private void setPageAlreadyPriceTracked(boolean alreadyPriceTracked) {
-        when(mBookmarkModel.getUserBookmarkIdForTab(any())).thenReturn(null);
-        PowerBookmarkMeta.Builder builder = PowerBookmarkMeta.newBuilder();
-        builder.setShoppingSpecifics(
-                ShoppingSpecifics.newBuilder().setIsPriceTracked(alreadyPriceTracked).build());
-        when(mBookmarkModel.getPowerBookmarkMeta(any())).thenReturn(builder.build());
     }
 
     private ContextualPageActionController createContextualPageActionController() {
         ContextualPageActionController contextualPageActionController =
                 new ContextualPageActionController(mProfileSupplier, mTabSupplier,
-                        mMockAdaptiveToolbarController,
-                        () -> mShoppingService, () -> mBookmarkModel);
+                        mMockAdaptiveToolbarController, null, null) {
+                    @Override
+                    protected void initActionProviders(
+                            Supplier<ShoppingService> shoppingServiceSupplier,
+                            Supplier<BookmarkModel> bookmarkModelSupplier) {
+                        mActionProviders.add((tab, signalAccumulator) -> {
+                            // Supply all signals and notify controller.
+                            signalAccumulator.setHasReaderMode(true);
+                            signalAccumulator.setHasPriceTracking(true);
+                            signalAccumulator.notifySignalAvailable();
+                        });
+                    }
+                };
 
         mProfileSupplier.set(mMockProfile);
 
@@ -189,40 +156,6 @@
     }
 
     @Test
-    public void alreadyPriceTrackedPagesWillBeSkipped() {
-        mMockConfiguration.screenWidthDp = 450;
-        setPageAlreadyPriceTracked(true);
-        setPriceTrackingBackendResult(true);
-        setMockSegmentationResult(
-                SegmentId.OPTIMIZATION_TARGET_CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING);
-
-        ContextualPageActionController contextualPageActionController =
-                createContextualPageActionController();
-
-        mTabSupplier.set(mMockTab);
-
-        verify(mMockControllerJni).computeContextualPageAction(any(), any(), eq(false), any());
-    }
-
-    @Test
-    public void priceTrackingActionShownSuccessfully() {
-        mMockConfiguration.screenWidthDp = 450;
-        setPageAlreadyPriceTracked(true);
-        setPriceTrackingBackendResult(true);
-        setMockSegmentationResult(
-                SegmentId.OPTIMIZATION_TARGET_CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING);
-
-        ContextualPageActionController contextualPageActionController =
-                createContextualPageActionController();
-
-        mTabSupplier.set(mMockTab);
-
-        verify(mMockControllerJni).computeContextualPageAction(any(), any(), eq(false), any());
-        verify(mMockAdaptiveToolbarController)
-                .showDynamicAction(AdaptiveToolbarButtonVariant.PRICE_TRACKING);
-    }
-
-    @Test
     public void buttonNotShownWhenUiDisabled() {
         mMockConfiguration.screenWidthDp = 450;
         setMockSegmentationResult(
@@ -238,7 +171,6 @@
 
         ContextualPageActionController contextualPageActionController =
                 createContextualPageActionController();
-
         mTabSupplier.set(mMockTab);
 
         verify(mMockAdaptiveToolbarController, never()).showDynamicAction(anyInt());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/PriceTrackingActionProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/PriceTrackingActionProvider.java
new file mode 100644
index 0000000..de8a44e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/PriceTrackingActionProvider.java
@@ -0,0 +1,45 @@
+// Copyright 2022 The Chromium Authors
+// 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.segmentation_platform;
+
+import org.chromium.base.supplier.Supplier;
+import org.chromium.chrome.browser.bookmarks.BookmarkModel;
+import org.chromium.chrome.browser.bookmarks.PowerBookmarkUtils;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.components.bookmarks.BookmarkId;
+import org.chromium.components.commerce.core.ShoppingService;
+
+/** Provides price tracking signal for showing contextual page action for a given tab. */
+public class PriceTrackingActionProvider implements ContextualPageActionController.ActionProvider {
+    private final Supplier<ShoppingService> mShoppingServiceSupplier;
+    private final Supplier<BookmarkModel> mBookmarkModelSupplier;
+
+    /** Constructor. */
+    public PriceTrackingActionProvider(Supplier<ShoppingService> shoppingServiceSupplier,
+            Supplier<BookmarkModel> bookmarkModelSupplier) {
+        mShoppingServiceSupplier = shoppingServiceSupplier;
+        mBookmarkModelSupplier = bookmarkModelSupplier;
+    }
+
+    @Override
+    public void getAction(Tab tab, SignalAccumulator signalAccumulator) {
+        final BookmarkModel bookmarkModel = mBookmarkModelSupplier.get();
+        bookmarkModel.finishLoadingBookmarkModel(() -> {
+            BookmarkId bookmarkId = bookmarkModel.getUserBookmarkIdForTab(tab);
+            boolean isAlreadyPriceTracked =
+                    PowerBookmarkUtils.isBookmarkPriceTracked(bookmarkModel, bookmarkId);
+            if (isAlreadyPriceTracked) {
+                signalAccumulator.setHasPriceTracking(false);
+                signalAccumulator.notifySignalAvailable();
+            } else {
+                mShoppingServiceSupplier.get().getProductInfoForUrl(tab.getUrl(), (url, info) -> {
+                    boolean canTrackPrice = info != null;
+                    signalAccumulator.setHasPriceTracking(canTrackPrice);
+                    signalAccumulator.notifySignalAvailable();
+                });
+            }
+        });
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/PriceTrackingActionProviderTest.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/PriceTrackingActionProviderTest.java
new file mode 100644
index 0000000..7f05c09
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/PriceTrackingActionProviderTest.java
@@ -0,0 +1,111 @@
+// Copyright 2022 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.segmentation_platform;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.bookmarks.BookmarkModel;
+import org.chromium.chrome.browser.segmentation_platform.ContextualPageActionController.ActionProvider;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.components.commerce.core.ShoppingService;
+import org.chromium.components.commerce.core.ShoppingService.ProductInfo;
+import org.chromium.components.commerce.core.ShoppingService.ProductInfoCallback;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link PriceTrackingActionProvider}
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class PriceTrackingActionProviderTest {
+    @Mock
+    private Tab mMockTab;
+
+    @Mock
+    private ShoppingService mShoppingService;
+
+    @Mock
+    private BookmarkModel mBookmarkModel;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        setBookmarkModelReady();
+    }
+
+    private void setBookmarkModelReady() {
+        // Setup bookmark model expectations.
+        Mockito.doAnswer(invocation -> {
+                   Runnable runnable = invocation.getArgument(0);
+                   runnable.run();
+                   return null;
+               })
+                .when(mBookmarkModel)
+                .finishLoadingBookmarkModel(any());
+    }
+
+    private void setPriceTrackingBackendResult(boolean hasProductInfo) {
+        ProductInfo testProductInfo = new ProductInfo(null, null, 0, 0, null, 0, null);
+        Mockito.doAnswer(invocation -> {
+                   ProductInfoCallback callback = invocation.getArgument(1);
+                   callback.onResult(
+                           invocation.getArgument(0), hasProductInfo ? testProductInfo : null);
+                   return null;
+               })
+                .when(mShoppingService)
+                .getProductInfoForUrl(any(), any());
+    }
+
+    private void setPageAlreadyPriceTracked(boolean alreadyPriceTracked) {
+        when(mBookmarkModel.getUserBookmarkIdForTab(any())).thenReturn(null);
+        org.chromium.components.power_bookmarks.PowerBookmarkMeta.Builder builder =
+                org.chromium.components.power_bookmarks.PowerBookmarkMeta.newBuilder();
+        builder.setShoppingSpecifics(
+                org.chromium.components.power_bookmarks.ShoppingSpecifics.newBuilder()
+                        .setIsPriceTracked(alreadyPriceTracked)
+                        .build());
+        when(mBookmarkModel.getPowerBookmarkMeta(any())).thenReturn(builder.build());
+    }
+
+    @Test
+    public void priceTrackingActionShownSuccessfully() {
+        List<ActionProvider> providers = new ArrayList<>();
+        PriceTrackingActionProvider provider =
+                new PriceTrackingActionProvider(() -> mShoppingService, () -> mBookmarkModel);
+        providers.add(provider);
+        SignalAccumulator accumulator = new SignalAccumulator(new Handler(), mMockTab, providers);
+        setPriceTrackingBackendResult(true);
+        provider.getAction(mMockTab, accumulator);
+        Assert.assertTrue(accumulator.hasPriceTracking());
+    }
+
+    @Test
+    public void priceTrackingNotShownForAlreadyPriceTrackedPages() {
+        List<ActionProvider> providers = new ArrayList<>();
+        PriceTrackingActionProvider provider =
+                new PriceTrackingActionProvider(() -> mShoppingService, () -> mBookmarkModel);
+        providers.add(provider);
+        SignalAccumulator accumulator = new SignalAccumulator(new Handler(), mMockTab, providers);
+        setPageAlreadyPriceTracked(true);
+        setPriceTrackingBackendResult(true);
+        provider.getAction(mMockTab, accumulator);
+        Assert.assertFalse(accumulator.hasPriceTracking());
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ReaderModeActionProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ReaderModeActionProvider.java
new file mode 100644
index 0000000..cd3d274
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ReaderModeActionProvider.java
@@ -0,0 +1,61 @@
+// Copyright 2022 The Chromium Authors
+// 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.segmentation_platform;
+
+import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
+import org.chromium.chrome.browser.dom_distiller.TabDistillabilityProvider;
+import org.chromium.chrome.browser.dom_distiller.TabDistillabilityProvider.DistillabilityObserver;
+import org.chromium.chrome.browser.tab.Tab;
+
+/** Provides reader mode signal for showing contextual page action for a given tab. */
+public class ReaderModeActionProvider implements ContextualPageActionController.ActionProvider {
+    @Override
+    public void getAction(Tab tab, SignalAccumulator signalAccumulator) {
+        final TabDistillabilityProvider tabDistillabilityProvider =
+                TabDistillabilityProvider.get(tab);
+        if (tabDistillabilityProvider.isDistillabilityDetermined()) {
+            notifyActionAvailable(tabDistillabilityProvider.isDistillable(),
+                    tabDistillabilityProvider.isMobileOptimized(), tab, signalAccumulator);
+            return;
+        }
+
+        // Distillability score isn't available yet. Start observing the provider.
+        final TabDistillabilityProvider.DistillabilityObserver distillabilityObserver =
+                new DistillabilityObserver() {
+                    @Override
+                    public void onIsPageDistillableResult(Tab tab, boolean isDistillable,
+                            boolean isLast, boolean isMobileOptimized) {
+                        notifyActionAvailable(
+                                isDistillable, isMobileOptimized, tab, signalAccumulator);
+                        tabDistillabilityProvider.removeObserver(this);
+                    }
+                };
+        tabDistillabilityProvider.addObserver(distillabilityObserver);
+    }
+
+    private void notifyActionAvailable(boolean isDistillable, boolean isMobileOptimized, Tab tab,
+            SignalAccumulator signalAccumulator) {
+        // TODO(shaktisahu): Can we merge these into a single method call?
+        signalAccumulator.setHasReaderMode(isDistillable && !isFilteredOut(tab, isMobileOptimized));
+        signalAccumulator.notifySignalAvailable();
+    }
+
+    private boolean isFilteredOut(Tab tab, boolean isMobileOptimized) {
+        // Test if the user is requesting the desktop site. Ignore this if distiller is set to
+        // ALWAYS_TRUE.
+        boolean usingRequestDesktopSite = tab.getWebContents() != null
+                && tab.getWebContents().getNavigationController().getUseDesktopUserAgent()
+                && !DomDistillerTabUtils.isHeuristicAlwaysTrue();
+
+        if (usingRequestDesktopSite) return true;
+
+        if (isMobileOptimized && DomDistillerTabUtils.shouldExcludeMobileFriendly(tab)) {
+            return true;
+        }
+
+        // TODO(crbug/1373891): Add rate limiting logic for muted sites.
+        return false;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ReaderModeActionProviderTest.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ReaderModeActionProviderTest.java
new file mode 100644
index 0000000..4fadb326
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ReaderModeActionProviderTest.java
@@ -0,0 +1,68 @@
+// Copyright 2022 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.segmentation_platform;
+
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.UserDataHost;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
+import org.chromium.chrome.browser.dom_distiller.TabDistillabilityProvider;
+import org.chromium.chrome.browser.segmentation_platform.ContextualPageActionController.ActionProvider;
+import org.chromium.chrome.browser.tab.Tab;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Unit tests for {@link ReaderModeActionProvider}
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ReaderModeActionProviderTest {
+    @Mock
+    private Tab mMockTab;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        initializeReaderModeBackend();
+    }
+
+    private void initializeReaderModeBackend() {
+        UserDataHost userDataHost = new UserDataHost();
+        when(mMockTab.getUserDataHost()).thenReturn(userDataHost);
+        TabDistillabilityProvider.createForTab(mMockTab);
+        DomDistillerTabUtils.setExcludeMobileFriendlyForTesting(true);
+    }
+
+    private void setReaderModeBackendSignal(boolean isDistillable) {
+        TabDistillabilityProvider tabDistillabilityProvider =
+                TabDistillabilityProvider.get(mMockTab);
+        tabDistillabilityProvider.onIsPageDistillableResult(isDistillable, true, false);
+    }
+
+    @Test
+    public void testIsDistillableInvokesCallback() throws TimeoutException {
+        List<ActionProvider> providers = new ArrayList<>();
+        ReaderModeActionProvider provider = new ReaderModeActionProvider();
+        providers.add(provider);
+        SignalAccumulator accumulator = new SignalAccumulator(new Handler(), mMockTab, providers);
+        setReaderModeBackendSignal(true);
+        provider.getAction(mMockTab, accumulator);
+        Assert.assertTrue(accumulator.hasReaderMode());
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/SignalAccumulator.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/SignalAccumulator.java
new file mode 100644
index 0000000..0233e78d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/SignalAccumulator.java
@@ -0,0 +1,112 @@
+// Copyright 2022 The Chromium Authors
+// 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.segmentation_platform;
+
+import android.os.Handler;
+
+import org.chromium.chrome.browser.segmentation_platform.ContextualPageActionController.ActionProvider;
+import org.chromium.chrome.browser.tab.Tab;
+
+import java.util.List;
+
+/**
+ * Convenient wrapper to keep track of the feature backend results and trigger the next step after
+ * all the feature backends have responded or a time out has happened.
+ */
+public class SignalAccumulator {
+    private static final long ACTION_PROVIDER_TIMEOUT_MS = 100;
+
+    // List of signals to query. Modify hasAllSignals() when adding signals to this list.
+    // TODO(crbug/1373895): Introduce a key set and directly populate InputContext.
+    private Boolean mHasPriceTracking;
+    private Boolean mHasReaderMode;
+
+    // Whether the backends didn't respond within the time limit. Any further response from the
+    // backends will be ignored.
+    private boolean mHasTimedOut;
+
+    // Whether the results from the backends have already been used for computing the action to
+    // show.
+    private boolean mIsInValid;
+
+    // The callback to be invoked at the end of getting all the signals or time out. After it is
+    // run, the accumulator becomes invalid.
+    private Runnable mCompletionCallback;
+
+    private final List<ActionProvider> mActionProviders;
+    private final Tab mTab;
+    private final Handler mHandler;
+
+    /**
+     * Constructor.
+     * @param handler A handler for posting task.
+     * @param tab The given tab.
+     * @param actionProviders List of action providers to get signals from.
+     */
+    public SignalAccumulator(Handler handler, Tab tab, List<ActionProvider> actionProviders) {
+        mHandler = handler;
+        mTab = tab;
+        mActionProviders = actionProviders;
+    }
+
+    /**
+     * Called to start getting signals from the respective action providers. The callback will be
+     * invoked at the end of signal collection or timeout.
+     */
+    public void getSignals(Runnable callback) {
+        mCompletionCallback = callback;
+        for (ActionProvider actionProvider : mActionProviders) {
+            actionProvider.getAction(mTab, this);
+        }
+        mHandler.postDelayed(() -> {
+            mHasTimedOut = true;
+            proceedToNextStepIfReady();
+        }, ACTION_PROVIDER_TIMEOUT_MS);
+    }
+
+    /**
+     * Called to notify that one of the backends is ready and the controller can proceed to next
+     * step if it has all the signals.
+     */
+    public void notifySignalAvailable() {
+        proceedToNextStepIfReady();
+    }
+
+    /**
+     * @return Whether the page is price tracking eligible. Default is false.
+     */
+    public Boolean hasPriceTracking() {
+        return mHasPriceTracking == null ? false : mHasPriceTracking;
+    }
+
+    /** Called to set whether the page can be price tracked. */
+    public void setHasPriceTracking(Boolean hasPriceTracking) {
+        mHasPriceTracking = hasPriceTracking;
+    }
+
+    /** @return Whether the page is reader mode eligible. Default is false. */
+    public Boolean hasReaderMode() {
+        return mHasReaderMode == null ? false : mHasReaderMode;
+    }
+
+    /** Called to set whether the page can be viewed in reader mode. */
+    public void setHasReaderMode(Boolean hasReaderMode) {
+        mHasReaderMode = hasReaderMode;
+    }
+
+    /**
+     * Central method invoked whenever a backend responds or time out happens.
+     */
+    private void proceedToNextStepIfReady() {
+        boolean isReady = mHasTimedOut || hasAllSignals();
+        if (!isReady || mIsInValid) return;
+        mIsInValid = true;
+        mCompletionCallback.run();
+    }
+
+    private boolean hasAllSignals() {
+        return mHasPriceTracking != null && mHasReaderMode != null;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/SignalAccumulatorTest.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/SignalAccumulatorTest.java
new file mode 100644
index 0000000..9e4bced
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/SignalAccumulatorTest.java
@@ -0,0 +1,82 @@
+// Copyright 2022 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.segmentation_platform;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+
+import android.os.Handler;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.chrome.browser.segmentation_platform.ContextualPageActionController.ActionProvider;
+import org.chromium.chrome.browser.tab.Tab;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Unit tests for {@link SignalAccumulator}
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class SignalAccumulatorTest {
+    @Mock
+    private Tab mMockTab;
+
+    @Mock
+    private Handler mHandler;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        Mockito.doAnswer(invocation -> {
+                   Runnable runnable = invocation.getArgument(0);
+                   runnable.run();
+                   return null;
+               })
+                .when(mHandler)
+                .postDelayed(any(), anyLong());
+    }
+
+    @Test
+    public void testAllSignalsBeforeTimeout() throws TimeoutException {
+        List<ActionProvider> actionProviders = new ArrayList<>();
+        ActionProvider dummyProvider = (tab, accumulator) -> {
+            accumulator.setHasPriceTracking(true);
+            accumulator.setHasReaderMode(false);
+        };
+        actionProviders.add(dummyProvider);
+        final CallbackHelper callbackHelper = new CallbackHelper();
+        int callCount = callbackHelper.getCallCount();
+        SignalAccumulator accumulator = new SignalAccumulator(mHandler, mMockTab, actionProviders);
+        accumulator.getSignals(() -> callbackHelper.notifyCalled());
+        callbackHelper.waitForCallback(callCount);
+        Assert.assertTrue(accumulator.hasPriceTracking());
+        Assert.assertFalse(accumulator.hasReaderMode());
+    }
+
+    @Test
+    public void testTimeoutBeforeAllSignals() throws TimeoutException {
+        final CallbackHelper callbackHelper = new CallbackHelper();
+        int callCount = callbackHelper.getCallCount();
+        SignalAccumulator accumulator =
+                new SignalAccumulator(mHandler, mMockTab, new ArrayList<ActionProvider>());
+        accumulator.getSignals(() -> callbackHelper.notifyCalled());
+        callbackHelper.waitForCallback(callCount);
+        Assert.assertFalse(accumulator.hasPriceTracking());
+        Assert.assertFalse(accumulator.hasReaderMode());
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
index 5a0347c..907fdf7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -7,6 +7,7 @@
   "+chrome/android/java/src/org/chromium/chrome/browser/ActivityUtils.java",
   "+chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java",
   "+chrome/android/java/src/org/chromium/chrome/browser/TabHidingType.java",
+  "+chrome/android/java/src/org/chromium/chrome/browser/accessibility/AccessibilityTabHelper.java",
   "+chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java",
   "+chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java",
   "+chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabHelpers.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabHelpers.java
index df10aa5..af220c335 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabHelpers.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabHelpers.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.tab;
 
 import org.chromium.chrome.browser.SwipeRefreshHandler;
+import org.chromium.chrome.browser.accessibility.AccessibilityTabHelper;
 import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantTabHelper;
 import org.chromium.chrome.browser.complex_tasks.TaskTabHelper;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchTabHelper;
@@ -39,6 +40,7 @@
         if (ReaderModeManager.isEnabled()) ReaderModeManager.createForTab(tab);
         AutofillAssistantTabHelper.createForTab(tab);
         PasswordCheckUkmRecorder.createForTab(tab);
+        AccessibilityTabHelper.createForTab(tab);
 
         // The following will start prefetching data for the price drops feature, so
         // we should only do it if the user is eligible for the feature (e.g. has sync enabled).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
index 24388e7d..7ccc08d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
@@ -34,7 +34,6 @@
 import org.chromium.content_public.browser.LifecycleState;
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.WebContents;
-import org.chromium.content_public.browser.WebContentsAccessibility;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.net.NetError;
 import org.chromium.ui.mojom.VirtualKeyboardMode;
@@ -106,14 +105,6 @@
     public void initWebContents(WebContents webContents) {
         mObserver = new Observer(webContents);
 
-        // For browser tabs, we want to set accessibility focus to the page when it loads. This
-        // is not the default behavior for embedded web views.
-        WebContentsAccessibility.fromWebContents(webContents).setShouldFocusOnPageLoad(true);
-
-        // Enable image descriptions feature normally, but not for Chrome Custom Tabs.
-        WebContentsAccessibility.fromWebContents(webContents)
-                .setIsImageDescriptionsCandidate(!mTab.isCustomTab());
-
         for (Callback<WebContents> callback : mInitObservers) callback.onResult(webContents);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtil.java
index ffcd944..d328ef7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtil.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtil.java
@@ -160,10 +160,11 @@
      * @return true if past threshold, false if not past threshold or experiment cannot be loaded.
      */
     public static boolean shouldShowTabSwitcher(final long lastBackgroundedTimeMillis) {
-        long tabSwitcherAfterMillis =
-                CachedFeatureFlags.isEnabled(ChromeFeatureList.START_SURFACE_RETURN_TIME)
-                ? getReturnTimeFromSegmentation()
-                : TAB_SWITCHER_ON_RETURN_MS.getValue();
+        long tabSwitcherAfterMillis = TAB_SWITCHER_ON_RETURN_MS.getValue();
+        if (CachedFeatureFlags.isEnabled(ChromeFeatureList.START_SURFACE_RETURN_TIME)
+                && TAB_SWITCHER_ON_RETURN_MS.getValue() != 0) {
+            tabSwitcherAfterMillis = getReturnTimeFromSegmentation();
+        }
 
         if (lastBackgroundedTimeMillis == -1) {
             // No last background timestamp set, use control behavior unless "immediate" was set.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 3c39d25..34073ec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -699,16 +699,17 @@
             mLocationBar = locationBarCoordinator;
         }
 
-        if (mLocationBar.getOmniboxStub() != null) {
-            mLocationBar.getOmniboxStub().addUrlFocusChangeListener(this);
-        }
         Runnable clickDelegate = () -> setUrlBarFocus(false, OmniboxFocusReason.UNFOCUS);
         View scrimTarget = mCompositorViewHolder;
         mLocationBarFocusHandler = new LocationBarFocusScrimHandler(scrimCoordinator,
                 new TabObscuringCallback(tabObscuringHandler), /* context= */ activity,
                 mLocationBarModel, clickDelegate, scrimTarget);
-        if (mLocationBar.getOmniboxStub() != null) {
-            mLocationBar.getOmniboxStub().addUrlFocusChangeListener(mLocationBarFocusHandler);
+
+        var omnibox = mLocationBar.getOmniboxStub();
+        if (omnibox != null) {
+            omnibox.addUrlFocusChangeListener(this);
+            omnibox.addUrlFocusChangeListener(mStatusBarColorController);
+            omnibox.addUrlFocusChangeListener(mLocationBarFocusHandler);
         }
 
         mProgressBarCoordinator = new LoadProgressCoordinator(
@@ -748,7 +749,7 @@
              * reduce server pressure.
              */
             private void maybeTriggerCacheRefreshForZeroSuggest(GURL url) {
-                if (url != null && UrlUtilities.isNTPUrl(url)) {
+                if (url != null) {
                     mLocationBarModel.notifyZeroSuggestRefresh();
                 }
             }
@@ -1475,6 +1476,13 @@
     public void destroy() {
         mIsDestroyed = true;
 
+        var omnibox = mLocationBar.getOmniboxStub();
+        if (omnibox != null) {
+            omnibox.removeUrlFocusChangeListener(this);
+            omnibox.removeUrlFocusChangeListener(mStatusBarColorController);
+            omnibox.removeUrlFocusChangeListener(mLocationBarFocusHandler);
+        }
+
         VrModuleProvider.unregisterVrModeObserver(mVrModeObserver);
 
         if (mInitializedWithNative) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
index cc73252f..ed5f603 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -1110,7 +1110,7 @@
                     mActivity, mActivityLifecycleDispatcher, mProfileSupplier);
             PriceTrackingButtonController priceTrackingButtonController =
                     new PriceTrackingButtonController(mActivityTabProvider,
-                            mModalDialogManagerSupplier.get(),
+                            mModalDialogManagerSupplier.get(), getBottomSheetController(),
                             AppCompatResources.getDrawable(
                                     mActivity, R.drawable.price_tracking_disabled),
                             mTabBookmarkerSupplier);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
index 4118b17..4b21503 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
@@ -26,6 +26,8 @@
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.DestroyObserver;
 import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.omnibox.OmniboxFeatures;
+import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
 import org.chromium.chrome.browser.status_indicator.StatusIndicatorCoordinator;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabSelectionType;
@@ -45,7 +47,7 @@
  */
 public class StatusBarColorController
         implements DestroyObserver, TopToolbarCoordinator.UrlExpansionObserver,
-                   StatusIndicatorCoordinator.StatusIndicatorObserver {
+                   StatusIndicatorCoordinator.StatusIndicatorObserver, UrlFocusChangeListener {
     public static final @ColorInt int UNDEFINED_STATUS_BAR_COLOR = Color.TRANSPARENT;
     public static final @ColorInt int DEFAULT_STATUS_BAR_COLOR = Color.argb(0x01, 0, 0, 0);
 
@@ -79,6 +81,7 @@
     private final @ColorInt int mIncognitoPrimaryBgColor;
     private final @ColorInt int mStandardDefaultThemeColor;
     private final @ColorInt int mIncognitoDefaultThemeColor;
+    private final @ColorInt int mActiveOmniboxDefaultColor;
 
     private @Nullable TabModelSelector mTabModelSelector;
     private CallbackController mCallbackController = new CallbackController();
@@ -86,6 +89,7 @@
     private @Nullable Tab mCurrentTab;
     private boolean mIsInOverviewMode;
     private boolean mIsIncognito;
+    private boolean mIsOmniboxFocused;
 
     private @ColorInt int mScrimColor;
     private float mStatusBarScrimFraction;
@@ -120,8 +124,14 @@
         mIncognitoPrimaryBgColor = ChromeColors.getPrimaryBackgroundColor(context, true);
         mStandardDefaultThemeColor = ChromeColors.getDefaultThemeColor(context, false);
         mIncognitoDefaultThemeColor = ChromeColors.getDefaultThemeColor(context, true);
-
         mStatusIndicatorColor = UNDEFINED_STATUS_BAR_COLOR;
+        if (OmniboxFeatures.shouldShowModernizeVisualUpdate(context)
+                && OmniboxFeatures.shouldShowActiveColorOnOmnibox()) {
+            mActiveOmniboxDefaultColor = ChromeColors.getSurfaceColor(
+                    context, R.dimen.omnibox_suggestion_dropdown_bg_elevation);
+        } else {
+            mActiveOmniboxDefaultColor = mStandardDefaultThemeColor;
+        }
 
         mStatusBarColorTabObserver = new ActivityTabProvider.ActivityTabTabObserver(tabProvider) {
             @Override
@@ -244,6 +254,12 @@
         updateStatusBarColor();
     }
 
+    @Override
+    public void onUrlFocusChange(boolean hasFocus) {
+        mIsOmniboxFocused = hasFocus;
+        updateStatusBarColor();
+    }
+
     /**
      * Update the scrim amount on the status bar.
      * @param fraction The scrim fraction in range [0, 1].
@@ -300,6 +316,10 @@
         // StatusBarColorProvider.
         if (mIsTablet) return Color.BLACK;
 
+        // When Omnibox gains focus, we want to clear the status bar theme color.
+        // The theme should be restored when Omnibox focus clears.
+        if (mIsOmniboxFocused) return calculateDefaultStatusBarColor();
+
         // Return status bar color in overview mode.
         if (mIsInOverviewMode) {
             if (shouldDarkenStatusBarColor()) return Color.BLACK;
@@ -332,6 +352,9 @@
         if (shouldDarkenStatusBarColor()) {
             return Color.BLACK;
         }
+        if (mIsOmniboxFocused) {
+            return mIsIncognito ? mIncognitoPrimaryBgColor : mActiveOmniboxDefaultColor;
+        }
         return mIsIncognito ? mIncognitoDefaultThemeColor : mStandardDefaultThemeColor;
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
index 63aedceb..862b16db 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
@@ -21,8 +21,8 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
@@ -114,7 +114,7 @@
      * @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
      */
     @Test
-    @FlakyTest(message = "http://crbug.com/172473")
+    @DisabledTest(message = "http://crbug.com/172473")
     public void testHideSelectionOnPhoneTabSwiping() throws Exception {
         mActivityTestRule.startMainActivityOnBlankPage();
         // Setup
@@ -170,7 +170,7 @@
     @MediumTest
     @Feature({"TabContents"})
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
-    @FlakyTest(message = "http://crbug.com/967128")
+    @DisabledTest(message = "http://crbug.com/967128")
     public void testHideSelectionOnPhoneTabSwitcher() throws Exception {
         mActivityTestRule.startMainActivityOnBlankPage();
         // Setup
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
index 441ce2d..b842915 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -29,7 +29,6 @@
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
@@ -511,7 +510,7 @@
 
     @Test
     @DisableIf.Build(hardware_is = "sprout", message = "fails on android-one: crbug.com/540723")
-    @FlakyTest(message = "https://crbug.com/1269027")
+    @DisabledTest(message = "https://crbug.com/1269027")
     @MediumTest
     @Feature({"Navigation"})
     public void testWindowOpenUrlSpoof() throws Exception {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java
index ae395d0..c920298 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java
@@ -26,8 +26,8 @@
 
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.app.ChromeActivity;
@@ -193,7 +193,7 @@
     @Test
     @MediumTest
     @Feature({"SmartClip"})
-    @FlakyTest(message = "https://crbug.com/853816")
+    @DisabledTest(message = "https://crbug.com/853816")
     public void testSmartClipDataCallback() throws TimeoutException {
         final float dpi = Coordinates.createFor(mWebContents).getDeviceScaleFactor();
         final Rect bounds = DOMUtils.getNodeBounds(mWebContents, "simple_text");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
index 877ab17a..21182ec 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
@@ -34,7 +34,6 @@
 import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -340,7 +339,7 @@
     @Test
     @MediumTest
     @Feature({"autofill"})
-    @FlakyTest(message = "crbug.com/1075791")
+    @DisabledTest(message = "crbug.com/1075791")
     public void testNotLoggingInvalidOption() throws TimeoutException {
         loadAndFillForm(INVALID_OPTION, "o");
         final String profileFullName = FIRST_NAME + " " + LAST_NAME;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 9771137d..dbdeeec9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -93,7 +93,6 @@
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.AppHooks;
@@ -1180,7 +1179,7 @@
     /** Same as above, but the hidden tab matching should not ignore the fragment. */
     @Test
     @SmallTest
-    @FlakyTest(message = "https://crbug.com/1237331")
+    @DisabledTest(message = "https://crbug.com/1237331")
     @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     public void testHiddenTabAndChangingFragmentDontIgnoreFragments() throws Exception {
         startHiddenTabAndChangeFragment(false, true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrarTest.java
index 18c9cf3..419083e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrarTest.java
@@ -16,7 +16,7 @@
 
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
 import org.chromium.chrome.browser.customtabs.CustomTabsIntentTestUtils;
@@ -64,7 +64,7 @@
      */
     @Test
     @MediumTest
-    @FlakyTest(message = "crbug.com/1269017")
+    @DisabledTest(message = "crbug.com/1269017")
     public void testObserveActiveTab() throws Throwable {
         EmbeddedTestServer testServer = mCustomTabActivityTestRule.getTestServer();
         final String windowOpenUrl =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/AutoDownloadsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/AutoDownloadsTest.java
index 59a2042..03c5f99 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/AutoDownloadsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/AutoDownloadsTest.java
@@ -20,8 +20,8 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.download.DownloadTestRule.CustomMainActivityStart;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -70,7 +70,7 @@
     @Test
     @MediumTest
     @Feature({"AutoDownloads"})
-    @FlakyTest(message = "https://crbug.com/1108800")
+    @DisabledTest(message = "https://crbug.com/1108800")
     public void testAutoDownloadsDialog() throws Exception {
         try (CloseableOnMainThread ignored = CloseableOnMainThread.StrictMode.allowDiskWrites()) {
             ArrayList<DirectoryOption> dirOptions = new ArrayList<>();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
index 27b07fb14..8f6c1bba 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
@@ -28,7 +28,6 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.download.DownloadTestRule.CustomMainActivityStart;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -222,7 +221,7 @@
     @Test
     @MediumTest
     @Feature({"Downloads"})
-    @FlakyTest(message = "https://crbug.com/1287296")
+    @DisabledTest(message = "https://crbug.com/1287296")
     public void testHttpGetDownload() throws Exception {
         mDownloadTestRule.loadUrl(mTestServer.getURL(TEST_DOWNLOAD_DIRECTORY + "get.html"));
         waitForFocus();
@@ -237,7 +236,7 @@
     @Test
     @MediumTest
     @Feature({"Downloads"})
-    @FlakyTest(message = "https://crbug.com/1287296")
+    @DisabledTest(message = "https://crbug.com/1287296")
     public void testHttpPostDownload() throws Exception {
         mDownloadTestRule.loadUrl(mTestServer.getURL(TEST_DOWNLOAD_DIRECTORY + "post.html"));
         waitForFocus();
@@ -287,7 +286,7 @@
     @Test
     @MediumTest
     @Feature({"Downloads"})
-    @FlakyTest(message = "https://crbug.com/1287296")
+    @DisabledTest(message = "https://crbug.com/1287296")
     public void testUrlEscaping() throws Exception {
         mDownloadTestRule.loadUrl(mTestServer.getURL(TEST_DOWNLOAD_DIRECTORY + "urlescaping.html"));
         waitForFocus();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
index f8bed3c..18b71a4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.fullscreen;
 
 // (http://crbug/642336)
+
 import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE;
 
 import android.graphics.Point;
@@ -35,7 +36,6 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
@@ -620,7 +620,7 @@
     @Test
     @LargeTest
     @Feature({"Fullscreen"})
-    @FlakyTest(message = "https://crbug.com/1099447")
+    @DisabledTest(message = "https://crbug.com/1099447")
     public void testControlsShownOnUnresponsiveRendererUponExitingTabSwitcherMode()
             throws Exception {
         FullscreenManagerTestUtils.disableBrowserOverrides();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/hardware_acceleration/ToastHWATest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/hardware_acceleration/ToastHWATest.java
index 915c51f..a8fdfa8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/hardware_acceleration/ToastHWATest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/hardware_acceleration/ToastHWATest.java
@@ -25,7 +25,6 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.download.DownloadTestRule;
@@ -85,7 +84,7 @@
     @Test
     @SmallTest
     @CommandLineFlags.Add(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)
-    @FlakyTest(message = "crbug.com/668217")
+    @DisabledTest(message = "crbug.com/668217")
     public void testNoRenderThread() {
         Utils.assertNoRenderThread();
     }
@@ -117,7 +116,7 @@
     @Test
     @SmallTest
     @CommandLineFlags.Add(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)
-    @FlakyTest(message = "crbug.com/668217")
+    @DisabledTest(message = "crbug.com/668217")
     public void testOpenedInBackgroundToast() throws Exception {
         mDownloadTestRule.loadUrl(mTestServer.getURL(URL_PATH));
         mDownloadTestRule.assertWaitForPageScaleFactorMatch(0.5f);
@@ -136,7 +135,7 @@
     @Test
     @SmallTest
     @CommandLineFlags.Add(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)
-    @FlakyTest(message = "crbug.com/668217")
+    @DisabledTest(message = "crbug.com/668217")
     public void testToastNoAcceleration() throws Exception {
         // Toasts created on low-end devices shouldn't be HW accelerated.
         Assert.assertFalse(isToastAcceleratedWithContext(mDownloadTestRule.getActivity()));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java
index cfe02895..42ff5d04 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java
@@ -25,8 +25,8 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.homepage.settings.HomepageMetricsEnums.HomepageLocationType;
@@ -99,7 +99,7 @@
     @Test
     @MediumTest
     @Feature({"Homepage"})
-    @FlakyTest(message = "crbug.com/1133544")
+    @DisabledTest(message = "crbug.com/1133544")
     public void testStartUpPage() {
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoPermissionLeakageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoPermissionLeakageTest.java
index 42a98a66..04ebf007 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoPermissionLeakageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoPermissionLeakageTest.java
@@ -35,7 +35,6 @@
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.IncognitoCustomTabActivityTestRule;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -142,7 +141,7 @@
     @Test
     @LargeTest
     @UseMethodParameter(RegularAndIncognito.class)
-    @FlakyTest(message = "https://crbug.com/1103488")
+    @DisabledTest(message = "https://crbug.com/1103488")
     public void testAllowPermissionDoNotLeakBetweenRegularAndIncognito(
             String activityType1, String activityType2) throws Exception {
         ActivityType activity1 = ActivityType.valueOf(activityType1);
@@ -252,7 +251,7 @@
     @Test
     @LargeTest
     @UseMethodParameter(TestParams.IncognitoToRegular.class)
-    @FlakyTest(message = "https://crbug.com/1103488")
+    @DisabledTest(message = "https://crbug.com/1103488")
     public void testBlockPermissionDoNotLeakFromIncognitoToRegular(
             String incognitoActivityType, String regularActivityType) throws Exception {
         ActivityType incognitoActivity = ActivityType.valueOf(incognitoActivityType);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
index 69aedfd0..888178d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
@@ -23,8 +23,8 @@
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.WebContentsFactory;
@@ -230,7 +230,7 @@
     @Test
     @MediumTest
     @Feature({"Browser", "Main"})
-    @FlakyTest(message = "https://crbug.com/1269025")
+    @DisabledTest(message = "https://crbug.com/1269025")
     public void testInfoBarForPopUp() throws TimeoutException, ExecutionException {
         sActivityTestRule.loadUrl(sTestServer.getURL(POPUP_PAGE));
         mListener.addInfoBarAnimationFinished("InfoBar not added");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java
index 7f93a6f..61b99f1f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java
@@ -29,7 +29,6 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -129,7 +128,7 @@
      */
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1237639")
+    @DisabledTest(message = "https://crbug.com/1237639")
     @Feature({"Browser", "Main"})
     public void testBeforeUnloadDialogWithNoHistory() throws TimeoutException, ExecutionException {
         ChromeTabbedActivity activity = sActivityTestRule.getActivity();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java
index 6f70214..1dd1192e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java
@@ -22,7 +22,6 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -96,7 +95,7 @@
     @Test
     @MediumTest
     @MinAndroidSdkLevel(Build.VERSION_CODES.O)
-    @FlakyTest(message = "https://crbug.com/1211930/#c10")
+    @DisabledTest(message = "https://crbug.com/1211930/#c10")
     public void testEnterPip() throws Throwable {
         enterFullscreen();
         triggerAutoPiPAndWait();
@@ -106,7 +105,7 @@
     @Test
     @MediumTest
     @MinAndroidSdkLevel(Build.VERSION_CODES.O)
-    @FlakyTest(message = "https://crbug.com/1211930/#c10")
+    @DisabledTest(message = "https://crbug.com/1211930/#c10")
     public void testExitPipOnNavigation() throws Throwable {
         testExitOn(()
                            -> JavaScriptUtils.executeJavaScript(getWebContents(),
@@ -177,7 +176,7 @@
     @Test
     @MediumTest
     @MinAndroidSdkLevel(Build.VERSION_CODES.O)
-    @FlakyTest(message = "https://crbug.com/1211930/#c10")
+    @DisabledTest(message = "https://crbug.com/1211930/#c10")
     public void testNoExitOnIframeNavigation() throws Throwable {
         // Add a TabObserver so we know when the iFrame navigation has occurred before we check that
         // we are still in PiP.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/MediaSessionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/MediaSessionTest.java
index fac935c..3e19b92 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/MediaSessionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/MediaSessionTest.java
@@ -20,7 +20,7 @@
 
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.ntp.NewTabPage;
@@ -58,7 +58,7 @@
 
     @Test
     @SmallTest
-    @FlakyTest(message = "https://crbug.com/1315419")
+    @DisabledTest(message = "https://crbug.com/1315419")
     public void testPauseOnHeadsetUnplug() throws IllegalArgumentException, TimeoutException {
         mActivityTestRule.startMainActivityWithURL(mTestServer.getURL(TEST_PATH));
         Tab tab = mActivityTestRule.getActivity().getActivityTab();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
index 0c54d81..bbbe82b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -54,7 +54,6 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -350,7 +349,7 @@
     @SmallTest
     @Feature({"NewTabPage", "FeedNewTabPage"})
     @ParameterAnnotations.UseMethodParameter(MVTParams.class)
-    @FlakyTest(message = "crbug.com/1036500")
+    @DisabledTest(message = "crbug.com/1036500")
     public void testRemoveMostVisitedItem(boolean isScrollableMVTEnabled)
             throws ExecutionException {
         Assert.assertNotNull(mMvTilesLayout);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
index 0faa326..a68f446 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
@@ -37,7 +37,7 @@
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.CriteriaNotSatisfiedException;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -294,7 +294,7 @@
     @MediumTest
     @MinAndroidSdkLevel(Build.VERSION_CODES.N)
     @CommandLineFlags.Add(ChromeSwitches.DISABLE_TAB_MERGING_FOR_TESTING)
-    @FlakyTest(message = "https://crbug.com/1291136")
+    @DisabledTest(message = "https://crbug.com/1291136")
     public void testSwitchToTabSuggestionWhenIncognitoTabOnTop() throws InterruptedException {
         mTestServer = EmbeddedTestServer.createAndStartHTTPSServer(
                 InstrumentationRegistry.getInstrumentation().getContext(),
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/portals/PortalsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/portals/PortalsTest.java
index 51d62c57..d9c38e8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/portals/PortalsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/portals/PortalsTest.java
@@ -36,7 +36,6 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.app.ChromeActivity;
@@ -628,7 +627,7 @@
     @LargeTest
     @Feature({"Portals"})
     @MinAndroidSdkLevel(Build.VERSION_CODES.M)
-    @FlakyTest(message = "https://crbug.com/1184291")
+    @DisabledTest(message = "https://crbug.com/1184291")
     public void testMediaNotificationDisappearsAfterActivation() throws Exception {
         String mainUrl =
                 mTestServer.getURL("/chrome/test/data/android/portals/media-notification.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineSettingsTest.java
index 3e3e2595..bd9177a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineSettingsTest.java
@@ -19,8 +19,8 @@
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisableIf;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.settings.MainSettings;
@@ -131,7 +131,7 @@
     @Test
     @SmallTest
     @Feature({"Preferences"})
-    @FlakyTest(message = "crbug.com/540706")
+    @DisabledTest(message = "crbug.com/540706")
     @DisableIf.Build(hardware_is = "sprout", message = "fails on android-one: crbug.com/540706")
     public void testSearchEnginePreferenceHttp() throws Exception {
         ensureTemplateUrlServiceLoaded();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
index 3a442a8..65073d2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
@@ -47,7 +47,6 @@
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.FileProviderHelper;
@@ -474,7 +473,7 @@
 
     @Test
     @SmallTest
-    @FlakyTest(message = "crbug.com/1133547")
+    @DisabledTest(message = "crbug.com/1133547")
     public void testRealPromoDialogInterruption() throws Exception {
         // Start the Activity.  It should pause when the promo dialog appears.
         mTestDelegate.shouldShowRealSearchDialog = true;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java
index 52806e1..8ef9798 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java
@@ -25,7 +25,6 @@
 import org.chromium.base.test.util.CriteriaHelper;
 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.UserActionTester;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -77,7 +76,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1205346")
+    @DisabledTest(message = "https://crbug.com/1205346")
     public void signinWhenPrimaryAccountIsRenamedToAKnownAccount() {
         mActivityTestRule.startMainActivityOnBlankPage();
         mSigninTestRule.addAccountAndWaitForSeeding("the.second.account@gmail.com");
@@ -97,7 +96,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1205346")
+    @DisabledTest(message = "https://crbug.com/1205346")
     public void signoutWhenPrimaryAccountIsRenamedToAnUnknownAccount() {
         mActivityTestRule.startMainActivityOnBlankPage();
         mSigninTestRule.addAccountAndWaitForSeeding("the.second.account@gmail.com");
@@ -118,7 +117,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1205346")
+    @DisabledTest(message = "https://crbug.com/1205346")
     public void signoutWhenPrimaryAccountIsRemoved() {
         mActivityTestRule.startMainActivityOnBlankPage();
         mSigninTestRule.addAccountAndWaitForSeeding("the.second.account@gmail.com");
@@ -136,7 +135,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1205346")
+    @DisabledTest(message = "https://crbug.com/1205346")
     public void signoutWhenPrimaryAccountWithoutSyncConsentIsRemoved() {
         mActivityTestRule.startMainActivityOnBlankPage();
         mSigninTestRule.addAccountAndWaitForSeeding("the.second.account@gmail.com");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
index 75ddcb3..8929e27 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
@@ -35,7 +35,6 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -309,7 +308,7 @@
 
     @Test
     @SmallTest
-    @FlakyTest(message = "crbug.com/988622")
+    @DisabledTest(message = "crbug.com/988622")
     @Feature({"Sync"})
     public void testPaymentsIntegrationCheckboxEnablesPaymentsIntegration() {
         mSyncTestRule.setUpAccountAndEnableSyncForTesting();
@@ -455,7 +454,7 @@
     @Test
     @SmallTest
     @Feature({"Sync"})
-    @FlakyTest(message = "https://crbug.com/1188548")
+    @DisabledTest(message = "https://crbug.com/1188548")
     public void testPassphraseCreation() {
         mSyncTestRule.setUpAccountAndEnableSyncForTesting();
         final ManageSyncSettings fragment = startManageSyncPreferences();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/UndoIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/UndoIntegrationTest.java
index e929760..b636848 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/UndoIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/UndoIntegrationTest.java
@@ -18,7 +18,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -67,7 +67,7 @@
      * @throws TimeoutException
      */
     @Test
-    @FlakyTest(message = "https://crbug.com/679480")
+    @DisabledTest(message = "https://crbug.com/679480")
     @LargeTest
     @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     public void testAddNewContentsFromClosingTab() throws TimeoutException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarIntegrationTest.java
index 8d701125..c1b751c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarIntegrationTest.java
@@ -16,8 +16,8 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -63,7 +63,7 @@
     @Test
     @Feature({"Android-Progress-Bar"})
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1269029")
+    @DisabledTest(message = "https://crbug.com/1269029")
     public void testProgressBarTraversesScreenOnce() throws TimeoutException {
         EmbeddedTestServer testServer =
                 EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java
index 20b4f48b8..229878e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java
@@ -24,8 +24,8 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.app.ChromeActivity;
@@ -117,7 +117,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1230091")
+    @DisabledTest(message = "https://crbug.com/1230091")
     public void testNTPNavigatesToErrorPageOnDisconnectedNetwork() {
         EmbeddedTestServer testServer =
                 EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java
index 43afce4..5536fa8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java
@@ -32,7 +32,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.FeatureList;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.app.ChromeActivity;
@@ -143,7 +143,7 @@
     @Test
     @MediumTest
     @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
-    @FlakyTest(message = "https://crbug.com/1142979")
+    @DisabledTest(message = "https://crbug.com/1142979")
     public void testTabSwitcherButtonIph() throws InterruptedException {
         when(mTracker.shouldTriggerHelpUI(FeatureConstants.TAB_SWITCHER_BUTTON_FEATURE))
                 .thenReturn(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java
index f72038c..aca9cf8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java
@@ -37,6 +37,7 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
+import org.chromium.chrome.test.util.OmniboxTestUtils;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.ThemeTestUtils;
 import org.chromium.components.browser_ui.styles.ChromeColors;
@@ -197,6 +198,32 @@
                 initialColor, statusBarColor.get().intValue());
     }
 
+    /**
+     * Test that the theme color is cleared when the Omnibox gains focus.
+     */
+    @Test
+    @LargeTest
+    @Feature({"StatusBar"})
+    @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP_MR1)
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE}) // Status bar is always black on tablets
+    public void testBrandColorIgnoredWhenOmniboxIsFocused() throws Exception {
+        ChromeTabbedActivity activity = sActivityTestRule.getActivity();
+        final int expectedDefaultStandardColor =
+                defaultColorFallbackToBlack(ChromeColors.getDefaultThemeColor(activity, false));
+
+        String pageWithBrandColorUrl = sActivityTestRule.getTestServer().getURL(
+                "/chrome/test/data/android/theme_color_test.html");
+        sActivityTestRule.loadUrl(pageWithBrandColorUrl);
+        ThemeTestUtils.waitForThemeColor(activity, Color.RED);
+        waitForStatusBarColor(activity, Color.RED);
+
+        var omniboxUtils = new OmniboxTestUtils(activity);
+        omniboxUtils.requestFocus();
+        waitForStatusBarColor(activity, expectedDefaultStandardColor);
+        omniboxUtils.clearFocus();
+        waitForStatusBarColor(activity, Color.RED);
+    }
+
     private int defaultColorFallbackToBlack(int color) {
         return (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? Color.BLACK : color;
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
index 2246843..f98a882 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
@@ -37,7 +37,6 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -232,7 +231,7 @@
     @MediumTest
     @CommandLineFlags.Add({"enable-features=WebXR"})
     @Restriction(RESTRICTION_TYPE_SVR)
-    @FlakyTest(message = "crbug.com/1229236")
+    @DisabledTest(message = "crbug.com/1229236")
     public void testControlsVisibleAfterExitingVr_WebXr() throws InterruptedException {
         controlsVisibleAfterExitingVrImpl("generic_webxr_page", mWebXrVrTestFramework);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenCurrentPageVerifierTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenCurrentPageVerifierTest.java
index 0dcb108..a77028ab2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenCurrentPageVerifierTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenCurrentPageVerifierTest.java
@@ -19,8 +19,8 @@
 
 import org.chromium.base.CommandLine;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.browserservices.intents.WebappConstants;
 import org.chromium.chrome.browser.browserservices.ui.controller.CurrentPageVerifier.VerificationStatus;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -71,7 +71,7 @@
     @Test
     @LargeTest
     @Feature({"Webapps"})
-    @FlakyTest(message = "http://crbug.com/1283235")
+    @DisabledTest(message = "http://crbug.com/1283235")
     public void testInScope() {
         String page = "https://foo.com/chrome/test/data/android/customtabs/cct_header.html";
         String otherPageInScope = "https://foo.com/chrome/test/data/android/simple.html";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
index 353fc73..36cdfb2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
@@ -18,7 +18,6 @@
 
 import androidx.test.filters.LargeTest;
 
-import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -31,7 +30,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.flags.ActivityType;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -133,7 +132,7 @@
     @Test
     @LargeTest
     @Feature({"Webapps"})
-    @FlakyTest(message = "https://crbug.com/1112352")
+    @DisabledTest(message = "https://crbug.com/1112352")
     public void testShare() throws TimeoutException {
         final String sharedSubject = "Fun tea parties";
         final String sharedText = "Boston";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/launchpad/LaunchpadPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/launchpad/LaunchpadPageTest.java
index be2cdc48..0c5bb326 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/launchpad/LaunchpadPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/launchpad/LaunchpadPageTest.java
@@ -35,7 +35,6 @@
 
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.settings.SettingsActivity;
@@ -138,7 +137,7 @@
 
     @Test
     @MediumTest
-    @FlakyTest(message = "https://crbug.com/1271233")
+    @DisabledTest(message = "https://crbug.com/1271233")
     public void testManagementMenuAppPermissions() {
         LaunchpadTestUtils.setPermissionDefaults(LaunchpadTestUtils.APP_URL_2);
         openLaunchpadPage();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
index 4a9128d..00c3ce8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
@@ -26,8 +26,8 @@
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -297,7 +297,7 @@
     }
 
     @Test
-    @FlakyTest(message = "https://crbug.com/837809")
+    @DisabledTest(message = "https://crbug.com/837809")
     @MediumTest
     @Feature({"BottomSheetController"})
     public void testSwitchTabsMultipleTimes() throws TimeoutException {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
index 522be505..3668cb4 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
@@ -577,7 +577,7 @@
     }
 
     @Test
-    public void rotateToLandescapeUnresizable() {
+    public void rotateToLandscapeUnresizable() {
         PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800);
         PartialCustomTabHandleStrategy handleStrategy = strategy.createHandleStrategyForTesting();
 
@@ -587,7 +587,7 @@
     }
 
     @Test
-    public void rotateToLandescapeHideCustomNavbar() {
+    public void rotateToLandscapeHideCustomNavbar() {
         // Custom navigation bar is drawn only on 'Fixed Window'-type implementation.
         if (mWindowAboveNavbar) return;
 
@@ -601,6 +601,24 @@
     }
 
     @Test
+    public void rotateToLandscapeAndBackTestHeight() {
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800);
+        PartialCustomTabHandleStrategy handleStrategy = strategy.createHandleStrategyForTesting();
+        mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        strategy.onConfigurationChanged(mConfiguration);
+        mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT;
+        strategy.onConfigurationChanged((mConfiguration));
+        assertTabIsAtInitialPos(mAttributeResults.get(0));
+
+        assertTabIsFullHeight(dragTab(handleStrategy, 1500, 1000, 500));
+        mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        strategy.onConfigurationChanged(mConfiguration);
+        mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT;
+        strategy.onConfigurationChanged(mConfiguration);
+        assertTabIsFullHeight(mAttributeResults.get(mAttributeResults.size()-1));
+    }
+
+    @Test
     public void showDragHandleOnPortraitMode() {
         PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800);
         verify(mDragBar).setVisibility(View.VISIBLE);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtilUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtilUnitTest.java
index e359168..21d9ede 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtilUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tasks/ReturnToChromeUtilUnitTest.java
@@ -204,6 +204,7 @@
         TAB_SWITCHER_ON_RETURN_MS.setForTesting(0);
         Assert.assertEquals(0, TAB_SWITCHER_ON_RETURN_MS.getValue());
         Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(-1));
+        Assert.assertTrue(ReturnToChromeUtil.shouldShowTabSwitcher(System.currentTimeMillis() - 1));
 
         // If immediate return is enabled by {@link ChromeFeatureList.START_SURFACE_RETURN_TIME},
         // returns true:
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index a05636c9..7224741 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-108.0.5355.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-108.0.5355.0_rc-r2-merged.afdo.bz2
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index b48bb86..09c0377 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4065,6 +4065,12 @@
   <message name="IDS_CONSOLIDATED_CONSENT_BACKUP_OPT_IN_LEARN_MORE_LINK" desc="Learn more about backup opt in">
     Learn more about backing up your apps
   </message>
+  <message name="IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN_TITLE" desc="Title for the message in the consolidated consent screen to opt-in for setting up recovery.">
+    Enable data recovery service.
+  </message>
+  <message name="IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN" desc="Message in the consolidated consent screen to opt-in for setting up recovery.">
+    If you forget your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> password, you can still restore your local data. You'll need to sign in to your Google Account or use account recovery.
+  </message>
   <message name="IDS_CONSOLIDATED_CONSENT_LOCATION_OPT_IN_TITLE" desc="Title for the message in the consolidated consent screen to opt-in for location services.">
     Use location for Android apps and services.
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN.png.sha1
new file mode 100644
index 0000000..9436a76
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN.png.sha1
@@ -0,0 +1 @@
+8db7f4574f2ac207cb8ed38099ba337f743f8921
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN_TITLE.png.sha1
new file mode 100644
index 0000000..9436a76
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN_TITLE.png.sha1
@@ -0,0 +1 @@
+8db7f4574f2ac207cb8ed38099ba337f743f8921
\ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 9041160..b95cc2c 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -113,6 +113,11 @@
       Show a quick highlight on the focused object
     </message>
   </if>
+  <if expr="chromeos_lacros">
+    <message name="IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES" desc="In the settings tab, the title of a link that opens a screen allowing the user to change accessibility features.">
+      Manage accessibility features
+    </message>
+  </if>
 
   <!-- Appearance Page -->
   <message name="IDS_SETTINGS_APPEARANCE" desc="Name of the settings page which displays appearance preferences.">
@@ -3363,33 +3368,6 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_GROUP_DELETE" desc="The clear storage button label, used to delete storage data for a group of sites.">
     Clear data
   </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_HEADER" desc="A header for the list of showing all cookies and site data.">
-    All cookies and site data
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_LINK" desc="Label for link showing all cookies and site data.">
-    See all cookies and site data
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE" desc="Label for the button to delete a single site cookie.">
-    Remove
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_ALL" desc="Label for the button to delete all cookies for a site.">
-    Remove All
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_ALL_SHOWN" desc="Label for the button to delete all visible cookies for a site.">
-    Remove All Shown
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_ALL_THIRD_PARTY" desc="Label for the subpage button to open a confirmation dialog to remove all cookies available in third-party contexts.">
-    Remove Third-Party Cookies
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIE_REMOVE_DIALOG_TITLE" desc="Title of the dialog that warns about deleting third-party cookie data.">
-    Clear third-party cookies
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIE_REMOVE_CONFIRMATION" desc="Text for the dialog that warns about deleting third-party cookie data.">
-    This will delete all cookies and site data available in third-party contexts. Do you want to continue?
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_CLEAR_THIRD_PARTY_COOKIES" desc="Label for the confirmation dialog button to delete all cookies and site data for third-party contexts.">
-    Clear third-party cookies
-  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIES_EXCEPTION_LABEL" desc="Label for site exceptions that affect third party cookies.">
     Including third-party cookies on this site
   </message>
@@ -3445,12 +3423,6 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_CLEAR_DISPLAYED_STORAGE_SIGN_OUT" desc="Text for the dialog that warns about being signed out when clearing storage used by displayed sites.">
     You'll be signed out of displayed sites, including in open tabs
   </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_DIALOG_TITLE" desc="Title of the dialog that warns about deleting all site data.">
-    Clear site data
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_SUBPAGE" desc="A label for cookie subpage, stating which site we're showing data for.">
-    <ph name="SITE">$1<ex>www.example.com</ex></ph> locally stored data
-  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_SITE_RESET_CONFIRMATION" desc="Text for the dialog that warns about resetting all permissions for a site.">
     Reset site permissions for <ph name="SITE">$1<ex>www.example.com</ex></ph>?
   </message>
@@ -3502,15 +3474,6 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_APPS" desc="Text for the dialog that warns about installed apps losing offline data when clearing all storage data for the site group.">
     Offline data in installed apps will also be cleared
   </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_ORIGIN_DELETE_CONFIRMATION" desc="Text for the dialog that warns about clearing all storage data for an origin.">
-    This will clear all data and cookies stored by <ph name="ORIGIN_NAME">$1<ex>www.example.com</ex></ph>
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_ORIGIN_DELETE_CONFIRMATION_INSTALLED" desc="Text for the dialog that warns about clearing all storage data for an origin that has one or more installed apps.">
-    This will clear all data and cookies stored by <ph name="ORIGIN_NAME">$1<ex>www.example.com</ex></ph> and its installed apps
-  </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_MULTIPLE" desc="Text for the dialog that warns about deleting all site data.">
-    This will delete any data stored on your device for all the sites shown. Do you want to continue?
-  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_REMOVE_SITE_ORIGIN_DIALOG_TITLE" desc="Title of the confirmation dialog when a user selects to remove a specific origin">
     Clear site data and permissions for <ph name="SITE_NAME">$1<ex>www.example.com</ex></ph>?
   </message>
@@ -3547,18 +3510,12 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_SITE" desc="Label for the trashcan button to delete all cookies and site data for a specific site (ex: all the cookies set on google.com).">
     Remove <ph name="SITE">$1<ex>google.com</ex></ph>
   </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIES_CLEAR_ALL" desc="Text for the button that clears all site data.">
-    Clear all
-  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_SITE_RESET_ALL" desc="Text for the button that resets the site's permissions back to the defaults.">
     Reset
   </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_SITE_CLEAR_STORAGE" desc="Text for the button that clears the storage used by a site, excluding cookies.">
     Clear
   </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_COOKIE_SEARCH" desc="A placeholder label shown inside the Cookie Data filter textbox as a hint that the user can enter a substring to search for.">
-    Search cookies
-  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_HANDLER_IS_DEFAULT" desc="A label showing that a certain handler for a given protocol is the default.">
     Default
   </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES.png.sha1
new file mode 100644
index 0000000..021fc6e
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES.png.sha1
@@ -0,0 +1 @@
+053712f25f12c7ae0050d264ca12cf9c7769103c
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b2ba0534..2e93f3f 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1573,6 +1573,18 @@
         {"10 suggestions if 2 or fewer URLs", kOmniboxDynamicMaxAutocomplete102,
          std::size(kOmniboxDynamicMaxAutocomplete102), nullptr}};
 
+const FeatureEntry::FeatureParam kOmniboxUniformRowHeight36[] = {
+    {"OmniboxUniformRowHeight", "36"}};
+const FeatureEntry::FeatureParam kOmniboxUniformRowHeight40[] = {
+    {"OmniboxUniformRowHeight", "40"}};
+
+const FeatureEntry::FeatureVariation kOmniboxSuggestionHeightVariations[] = {
+    {"36 px height for all omnibox suggestions", kOmniboxUniformRowHeight36,
+     std::size(kOmniboxUniformRowHeight36), nullptr},
+    {"40 px height for all omnibox suggestions", kOmniboxUniformRowHeight40,
+     std::size(kOmniboxUniformRowHeight40), nullptr},
+};
+
 const FeatureEntry::FeatureParam
     kOrganicRepeatableQueriesCappedWithHighPrivilege[] = {
         {"MaxNumRepeatableQueries", "4"},
@@ -5749,6 +5761,13 @@
      flag_descriptions::kOmniboxShortBookmarkSuggestionsDescription, kOsAll,
      FEATURE_VALUE_TYPE(omnibox::kShortBookmarkSuggestions)},
 
+    {"omnibox-uniform-suggestion-height",
+     flag_descriptions::kOmniboxSimplifiedUiUniformRowHeightName,
+     flag_descriptions::kOmniboxSimplifiedUiUniformRowHeightDescription, kOsAll,
+     FEATURE_WITH_PARAMS_VALUE_TYPE(omnibox::kUniformRowHeight,
+                                    kOmniboxSuggestionHeightVariations,
+                                    "Uniform Omnibox Suggest Heights")},
+
     {"optimization-guide-debug-logs",
      flag_descriptions::kOptimizationGuideDebugLogsName,
      flag_descriptions::kOptimizationGuideDebugLogsDescription, kOsAll,
@@ -7003,6 +7022,14 @@
      flag_descriptions::kAccessibilityServiceDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kAccessibilityService)},
 
+    {"enable-accessibility-select-to-speak-hover-text-improvements",
+     flag_descriptions::kAccessibilitySelectToSpeakHoverTextImprovementsName,
+     flag_descriptions::
+         kAccessibilitySelectToSpeakHoverTextImprovementsDescription,
+     kOsCrOS,
+     FEATURE_VALUE_TYPE(
+         features::kAccessibilitySelectToSpeakHoverTextImprovements)},
+
     {"enable-accessibility-select-to-speak-page-migration",
      flag_descriptions::kAccessibilitySelectToSpeakPageMigrationName,
      flag_descriptions::kAccessibilitySelectToSpeakPageMigrationDescription,
@@ -7877,11 +7904,6 @@
      FEATURE_VALUE_TYPE(chrome::android::kIncognitoReauthenticationForAndroid)},
 #endif
 
-    {"consolidated-site-storage-controls",
-     flag_descriptions::kConsolidatedSiteStorageControlsName,
-     flag_descriptions::kConsolidatedSiteStorageControlsDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(features::kConsolidatedSiteStorageControls)},
-
 #if BUILDFLAG(IS_ANDROID)
     {"enable-surface-control", flag_descriptions::kAndroidSurfaceControlName,
      flag_descriptions::kAndroidSurfaceControlDescription, kOsAndroid,
@@ -8352,6 +8374,11 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(features::kFedCm,
                                     kFedCmFeatureVariations,
                                     "FedCmFeatureVariations")},
+
+    {"fedcm-metrics-endpoint", flag_descriptions::kFedCmMetricsEndpointName,
+     flag_descriptions::kFedCmMetricsEndpointDescription, kOsAll,
+     FEATURE_VALUE_TYPE(features::kFedCmMetricsEndpoint)},
+
     {"fedcm-multi-idp", flag_descriptions::kFedCmMultiIdpName,
      flag_descriptions::kFedCmMultiIdpDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kFedCmMultipleIdentityProviders)},
diff --git a/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_api.cc b/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_api.cc
index 367cf304..f7ce3759 100644
--- a/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_api.cc
+++ b/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_api.cc
@@ -42,6 +42,8 @@
 
 }  // namespace
 
+using enterprise_remote_apps::RemoteAppsPosition;
+
 EnterpriseRemoteAppsAddFolderFunction::EnterpriseRemoteAppsAddFolderFunction() =
     default;
 
@@ -165,4 +167,47 @@
   Respond(WithArguments());
 }
 
+EnterpriseRemoteAppsSortLauncherFunction::
+    EnterpriseRemoteAppsSortLauncherFunction() = default;
+
+EnterpriseRemoteAppsSortLauncherFunction::
+    ~EnterpriseRemoteAppsSortLauncherFunction() = default;
+
+ExtensionFunction::ResponseAction
+EnterpriseRemoteAppsSortLauncherFunction::Run() {
+  auto parameters =
+      api::enterprise_remote_apps::SortLauncher::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(parameters);
+
+  chromeos::remote_apps::mojom::RemoteApps* remote_apps_api =
+      GetEnterpriseRemoteAppsApi(browser_context());
+  if (remote_apps_api == nullptr)
+    return RespondNow(Error("Remote apps not supported in this session"));
+
+  switch (parameters->options.position) {
+    case RemoteAppsPosition::REMOTE_APPS_POSITION_REMOTE_APPS_FIRST: {
+      auto callback = base::BindOnce(
+          &EnterpriseRemoteAppsSortLauncherFunction::OnResult, this);
+      remote_apps_api->SortLauncherWithRemoteAppsFirst(std::move(callback));
+      break;
+    }
+    default: {
+      return RespondNow(Error("Remote apps sort position not valid."));
+    }
+  }
+
+  // `did_respond()` needed here as the `SortLauncher()` can be sync or async.
+  return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void EnterpriseRemoteAppsSortLauncherFunction::OnResult(
+    const absl::optional<std::string>& error) {
+  if (error) {
+    Respond(Error(*error));
+    return;
+  }
+
+  Respond(WithArguments());
+}
+
 }  // namespace chrome_apps::api
diff --git a/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_api.h b/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_api.h
index 48940c4..d60c035 100644
--- a/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_api.h
+++ b/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_api.h
@@ -76,6 +76,28 @@
   void OnResult(const absl::optional<std::string>& error);
 };
 
+class EnterpriseRemoteAppsSortLauncherFunction : public ExtensionFunction {
+ public:
+  EnterpriseRemoteAppsSortLauncherFunction();
+
+  EnterpriseRemoteAppsSortLauncherFunction(
+      const EnterpriseRemoteAppsSortLauncherFunction&) = delete;
+
+  EnterpriseRemoteAppsSortLauncherFunction& operator=(
+      const EnterpriseRemoteAppsSortLauncherFunction&) = delete;
+
+  DECLARE_EXTENSION_FUNCTION("enterprise.remoteApps.sortLauncher",
+                             ENTERPRISE_REMOTEAPPS_SORTLAUNCHER)
+
+ protected:
+  ~EnterpriseRemoteAppsSortLauncherFunction() override;
+
+  // ExtensionFunction:
+  ResponseAction Run() override;
+
+  void OnResult(const absl::optional<std::string>& error);
+};
+
 }  // namespace chrome_apps::api
 
 #endif  // CHROME_BROWSER_APPS_PLATFORM_APPS_API_ENTERPRISE_REMOTE_APPS_ENTERPRISE_REMOTE_APPS_API_H_
diff --git a/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_apitest.cc b/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_apitest.cc
index 34a898e..1d3250f1 100644
--- a/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_apitest.cc
+++ b/chrome/browser/apps/platform_apps/api/enterprise_remote_apps/enterprise_remote_apps_apitest.cc
@@ -59,6 +59,7 @@
 constexpr char kId1[] = "Id 1";
 constexpr char kId2[] = "Id 2";
 constexpr char kId3[] = "Id 3";
+constexpr char kId4[] = "Id 4";
 
 }  // namespace
 
@@ -95,6 +96,10 @@
 
     SetUpDeviceLocalAccountPolicy();
     ash::SessionStateWaiter(session_manager::SessionState::ACTIVE).Wait();
+
+    user_manager::User* user =
+        user_manager::UserManager::Get()->GetActiveUser();
+    profile_ = ash::ProfileHelper::Get()->GetProfileByUser(user);
   }
 
   // TODO(b/239145899): Refactor to not use MGS setup any more.
@@ -112,36 +117,40 @@
     RefreshDevicePolicy();
   }
 
+  std::string LoadExtension(base::FilePath extension_path,
+                            base::FilePath pem_path = base::FilePath()) {
+    extensions::ChromeTestExtensionLoader loader(profile_);
+    loader.set_location(extensions::mojom::ManifestLocation::kExternalPolicy);
+    loader.set_pack_extension(true);
+    if (!pem_path.empty())
+      loader.set_pem_path(pem_path);
+
+    // When |set_pack_extension_| is true, the |loader| first packs and then
+    // loads the extension. The packing step creates a _metadata folder which
+    // causes an install warning when loading.
+    loader.set_ignore_manifest_warnings(true);
+    return loader.LoadExtension(extension_path)->id();
+  }
+
   void LoadExtensionAndRunTest(const std::string& test_name) {
     config_.SetKey("customArg", base::Value(test_name));
     extensions::TestGetConfigFunction::set_test_config_state(&config_);
 
+    std::unique_ptr<ash::FakeIdGenerator> id_generator =
+        std::make_unique<ash::FakeIdGenerator>(
+            std::vector<std::string>{kId1, kId2, kId3, kId4});
+    ash::RemoteAppsManagerFactory::GetForProfile(profile_)
+        ->GetModelForTesting()
+        ->SetIdGeneratorForTesting(std::move(id_generator));
+
     base::FilePath test_dir_path;
     base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir_path);
     base::FilePath extension_path = test_dir_path.AppendASCII(GetParam());
     base::FilePath pem_path =
         test_dir_path.AppendASCII(kExtensionPemRelativePath);
 
-    user_manager::User* user =
-        user_manager::UserManager::Get()->GetActiveUser();
-    Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
-
-    std::unique_ptr<ash::FakeIdGenerator> id_generator =
-        std::make_unique<ash::FakeIdGenerator>(
-            std::vector<std::string>{kId1, kId2, kId3});
-    ash::RemoteAppsManagerFactory::GetForProfile(profile)
-        ->GetModelForTesting()
-        ->SetIdGeneratorForTesting(std::move(id_generator));
-
-    extensions::ChromeTestExtensionLoader loader(profile);
-    loader.set_location(extensions::mojom::ManifestLocation::kExternalPolicy);
-    loader.set_pack_extension(true);
-    loader.set_pem_path(pem_path);
-    // When |set_pack_extension_| is true, the |loader| first packs and then
-    // loads the extension. The packing step creates a _metadata folder which
-    // causes an install warning when loading.
-    loader.set_ignore_manifest_warnings(true);
-    ASSERT_TRUE(loader.LoadExtension(extension_path));
+    std::string extension_id = LoadExtension(extension_path, pem_path);
+    ASSERT_FALSE(extension_id.empty());
   }
 
   ash::AppListItem* GetAppListItem(const std::string& id) {
@@ -175,6 +184,7 @@
   }
 
  private:
+  Profile* profile_;
   base::DictionaryValue config_;
   ash::EmbeddedPolicyTestServerMixin policy_test_server_mixin_{&mixin_host_};
 };
@@ -287,6 +297,75 @@
   ASSERT_TRUE(catcher.GetNextResult());
 }
 
+// Adds remote and native items and tests that the final order, after calling
+// chrome.enterprise.remoteApps.sortLauncher(), is remote apps first, in
+// alphabetical, case insensitive order, followed by native apps in
+// alphabetical, case insensitive order.
+IN_PROC_BROWSER_TEST_P(RemoteAppsApitest, SortLauncher) {
+  if (GetParam() != kApiExtensionRelativePath)
+    GTEST_SKIP() << "The sortLauncher API method is not available in Mojo API";
+
+  base::FilePath test_dir_path;
+  base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir_path);
+  test_dir_path = test_dir_path.AppendASCII("extensions");
+
+  extensions::ResultCatcher catcher;
+  ExtensionTestMessageListener listener("Ready to sort",
+                                        ReplyBehavior::kWillReply);
+  listener.set_extension_id(kExtensionId);
+  LoadExtensionAndRunTest("AddRemoteItemsForSort");
+  ASSERT_TRUE(listener.WaitUntilSatisfied());
+
+  std::string app1_id =
+      LoadExtension(test_dir_path.AppendASCII("app1"));  // Test App 1
+  ASSERT_FALSE(app1_id.empty());
+  std::string app2_id =
+      LoadExtension(test_dir_path.AppendASCII("app2"));  // Test App 2
+  ASSERT_FALSE(app2_id.empty());
+  std::string app4_id =
+      LoadExtension(test_dir_path.AppendASCII("app4"));  // Test App 4
+  ASSERT_FALSE(app4_id.empty());
+
+  // Apps and folders are not ordered. Native and remote apps are added to the
+  // front (last app added is now first).
+  // Current order: `Test App 4` (native), `Test App 2` (native), `Test App 1`
+  // (native), `Test App 6 Folder` (remote), `Test App 7` (remote), `test app 5`
+  // (remote).
+  int app1_index = GetAppListItemIndex(app1_id);  // Test App 1 (native)
+  int app2_index = GetAppListItemIndex(app2_id);  // Test App 2 (native)
+  int app4_index = GetAppListItemIndex(app4_id);  // Test App 4 (native)
+  int id1_index = GetAppListItemIndex(kId1);      // test app 5 (remote)
+  int id2_index = GetAppListItemIndex(kId2);      // Test App 7 (remote)
+  int id3_index = GetAppListItemIndex(kId3);      // Test App 6 Folder (remote)
+  EXPECT_LT(app4_index, app2_index);              // Test App 4 < Test App 2
+  EXPECT_LT(app2_index, app1_index);              // Test App 2 < Test App 1
+  EXPECT_LT(app1_index, id3_index);  // Test App 1 < Test App 6 Folder
+  EXPECT_LT(id3_index, id2_index);   // Test App 6 Folder < Test App 7
+  EXPECT_LT(id2_index, id1_index);   // Test App 7 < test app 5
+
+  // Call chrome.enterprise.remoteApps.sortLauncher().
+  listener.Reply("");
+  ASSERT_TRUE(catcher.GetNextResult());
+
+  // Verifies that remote apps sorting moves all remote items (apps and folders)
+  // to the front, in alphabetical, case insensitive order, followed by native
+  // items also in alphabetical, case insensitive order.
+  // Sorted order: `test app 5` (remote), `Test App 6 Folder` (remote),
+  // `Test App 7` (remote), `App Test 1` (native), `Test App 2` (native),
+  // `Test App 4` (native).
+  app1_index = GetAppListItemIndex(app1_id);  // Test App 1 (native)
+  app2_index = GetAppListItemIndex(app2_id);  // Test App 2 (native)
+  app4_index = GetAppListItemIndex(app4_id);  // Test App 4 (native)
+  id1_index = GetAppListItemIndex(kId1);      // test app 5 (remote)
+  id2_index = GetAppListItemIndex(kId2);      // Test App 7 (remote)
+  id3_index = GetAppListItemIndex(kId3);      // Test App 6 Folder (remote)
+  EXPECT_LT(id1_index, id3_index);            // test app 5 < Test App 6 Folder
+  EXPECT_LT(id3_index, id2_index);            // Test App 6 Folder  < Test App 7
+  EXPECT_LT(id2_index, app1_index);           // Test App 7 < Test App 1
+  EXPECT_LT(app1_index, app2_index);          // Test App 1 < Test App 2
+  EXPECT_LT(app2_index, app4_index);          // Test App 2 < Test App 4
+}
+
 INSTANTIATE_TEST_SUITE_P(,
                          RemoteAppsApitest,
                          testing::Values(kApiExtensionRelativePath,
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 869719c4..337832a 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -3044,7 +3044,6 @@
     "//ash/components/arc/session:connection_holder",
     "//ash/components/phonehub",
     "//ash/components/phonehub/proto",
-    "//ash/components/tether",
     "//ash/constants",
     "//ash/public/cpp",
     "//ash/public/cpp/external_arc",
@@ -3177,6 +3176,7 @@
     "//chromeos/ash/components/scanning",
     "//chromeos/ash/components/settings",
     "//chromeos/ash/components/smbfs",
+    "//chromeos/ash/components/tether",
     "//chromeos/ash/components/timezone",
     "//chromeos/ash/components/trash_service/public/cpp",
     "//chromeos/ash/services/cros_healthd/public/cpp",
diff --git a/chrome/browser/ash/accessibility/accessibility_manager.cc b/chrome/browser/ash/accessibility/accessibility_manager.cc
index cb40395..05b6e5d 100644
--- a/chrome/browser/ash/accessibility/accessibility_manager.cc
+++ b/chrome/browser/ash/accessibility/accessibility_manager.cc
@@ -1999,6 +1999,8 @@
     SkColor color) {
   AccessibilityFocusRingController::Get()->SetHighlights(rects_in_screen,
                                                          color);
+  if (highlights_observer_for_test_ && rects_in_screen.size())
+    highlights_observer_for_test_.Run();
 }
 
 void AccessibilityManager::HideHighlights() {
@@ -2081,6 +2083,11 @@
   focus_ring_observer_for_test_ = observer;
 }
 
+void AccessibilityManager::SetHighlightsObserverForTest(
+    base::RepeatingCallback<void()> observer) {
+  highlights_observer_for_test_ = observer;
+}
+
 void AccessibilityManager::SetSelectToSpeakStateObserverForTest(
     base::RepeatingCallback<void()> observer) {
   select_to_speak_state_observer_for_test_ = observer;
diff --git a/chrome/browser/ash/accessibility/accessibility_manager.h b/chrome/browser/ash/accessibility/accessibility_manager.h
index 080d0a3..3178a45 100644
--- a/chrome/browser/ash/accessibility/accessibility_manager.h
+++ b/chrome/browser/ash/accessibility/accessibility_manager.h
@@ -383,6 +383,8 @@
   static void SetBrailleControllerForTest(
       extensions::api::braille_display_private::BrailleController* controller);
   void SetFocusRingObserverForTest(base::RepeatingCallback<void()> observer);
+  // Runs when highlights are set or updated, but not when they are removed.
+  void SetHighlightsObserverForTest(base::RepeatingCallback<void()> observer);
   void SetSelectToSpeakStateObserverForTest(
       base::RepeatingCallback<void()> observer);
   void SetCaretBoundsObserverForTest(
@@ -611,6 +613,7 @@
   bool ignore_dictation_locale_pref_change_ = false;
 
   base::RepeatingCallback<void()> focus_ring_observer_for_test_;
+  base::RepeatingCallback<void()> highlights_observer_for_test_;
   base::RepeatingCallback<void()> select_to_speak_state_observer_for_test_;
   base::RepeatingCallback<void(const gfx::Rect&)>
       caret_bounds_observer_for_test_;
diff --git a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc
index bdd2019ea..f785197 100644
--- a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc
+++ b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc
@@ -7,6 +7,7 @@
 
 #include "ash/accessibility/ui/accessibility_focus_ring_controller_impl.h"
 #include "ash/accessibility/ui/accessibility_focus_ring_layer.h"
+#include "ash/accessibility/ui/accessibility_highlight_layer.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/public/cpp/system_tray_test_api.h"
 #include "ash/public/cpp/test/shell_test_api.h"
@@ -32,11 +33,13 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_host_test_helper.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/browser/process_manager.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/accessibility/accessibility_features.h"
 #include "ui/accessibility/accessibility_switches.h"
 #include "ui/compositor/layer.h"
@@ -54,13 +57,19 @@
   SelectToSpeakTest& operator=(const SelectToSpeakTest&) = delete;
 
   void OnFocusRingChanged() {
-    if (loop_runner_) {
+    if (loop_runner_ && loop_runner_->running()) {
       loop_runner_->Quit();
     }
   }
 
+  void OnHighlightsAdded() {
+    if (highlights_runner_ && highlights_runner_->running()) {
+      highlights_runner_->Quit();
+    }
+  }
+
   void SetSelectToSpeakState() {
-    if (tray_loop_runner_) {
+    if (tray_loop_runner_ && tray_loop_runner_->running()) {
       tray_loop_runner_->Quit();
     }
   }
@@ -121,8 +130,21 @@
     generator_->ReleaseKey(ui::VKEY_LWIN, 0 /* flags */);
   }
 
+  void PrepareToWaitForHighlightAdded() {
+    highlights_runner_ = std::make_unique<base::RunLoop>();
+    base::RepeatingCallback<void()> callback = base::BindRepeating(
+        &SelectToSpeakTest::OnHighlightsAdded, GetWeakPtr());
+    AccessibilityManager::Get()->SetHighlightsObserverForTest(callback);
+  }
+
+  void WaitForHighlightAdded() {
+    DCHECK(highlights_runner_);
+    highlights_runner_->Run();
+    highlights_runner_ = nullptr;
+  }
+
   void PrepareToWaitForSelectToSpeakStatusChanged() {
-    tray_loop_runner_ = new content::MessageLoopRunner();
+    tray_loop_runner_ = std::make_unique<base::RunLoop>();
   }
 
   // Blocks until the select-to-speak tray status is changed.
@@ -138,7 +160,7 @@
   }
 
   void PrepareToWaitForFocusRingChanged() {
-    loop_runner_ = new content::MessageLoopRunner();
+    loop_runner_ = std::make_unique<base::RunLoop>();
   }
 
   // Blocks until the focus ring is changed.
@@ -169,8 +191,9 @@
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
-  scoped_refptr<content::MessageLoopRunner> loop_runner_;
-  scoped_refptr<content::MessageLoopRunner> tray_loop_runner_;
+  std::unique_ptr<base::RunLoop> loop_runner_;
+  std::unique_ptr<base::RunLoop> highlights_runner_;
+  std::unique_ptr<base::RunLoop> tray_loop_runner_;
   base::WeakPtrFactory<SelectToSpeakTest> weak_ptr_factory_{this};
 };
 
@@ -342,6 +365,28 @@
   sm_.Replay();
 }
 
+IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, SetsWordHighlights) {
+  AccessibilityFocusRingControllerImpl* controller =
+      Shell::Get()->accessibility_focus_ring_controller();
+  EXPECT_FALSE(controller->highlight_layer_for_testing());
+  PrepareToWaitForHighlightAdded();
+  ActivateSelectToSpeakInWindowBounds(
+      "data:text/html;charset=utf-8,<p>Highlight me");
+  sm_.ExpectSpeechPattern("*Highlight me*");
+  sm_.Replay();
+
+  // Some highlighting should have occurred. OK to do this after speech as
+  // Select to Speak refreshes the UI intermittently.
+  WaitForHighlightAdded();
+
+  // Check the highlight exists and the color is as expected.
+  AccessibilityHighlightLayer* highlight_layer =
+      controller->highlight_layer_for_testing();
+  EXPECT_TRUE(highlight_layer);
+  EXPECT_EQ(1u, highlight_layer->rects_for_test().size());
+  EXPECT_EQ(SkColorSetRGB(94, 155, 255), highlight_layer->color_for_test());
+}
+
 // Flaky on ChromeOS MSAN bots: https://crbug.com/1227368
 #if defined(MEMORY_SANITIZER)
 #define MAYBE_SmoothlyReadsAcrossMultipleLines DISABLED_SmoothlyReadsAcrossMultipleLines
diff --git a/chrome/browser/ash/accessibility/speech_monitor.cc b/chrome/browser/ash/accessibility/speech_monitor.cc
index 663c22b4..86e67dc 100644
--- a/chrome/browser/ash/accessibility/speech_monitor.cc
+++ b/chrome/browser/ash/accessibility/speech_monitor.cc
@@ -49,7 +49,9 @@
          "empty string in a test, that's probably not the correct way to "
          "achieve stopping speech. If it is unintended, it indicates a deeper "
          "underlying issue.";
-
+  content::TtsController::GetInstance()->OnTtsEvent(
+      utterance_id, content::TTS_EVENT_START, 0,
+      static_cast<int>(utterance.size()), std::string());
   content::TtsController::GetInstance()->OnTtsEvent(
       utterance_id, content::TTS_EVENT_END, static_cast<int>(utterance.size()),
       0, std::string());
diff --git a/chrome/browser/ash/app_restore/full_restore_app_launch_handler.cc b/chrome/browser/ash/app_restore/full_restore_app_launch_handler.cc
index 7e67100..2616970 100644
--- a/chrome/browser/ash/app_restore/full_restore_app_launch_handler.cc
+++ b/chrome/browser/ash/app_restore/full_restore_app_launch_handler.cc
@@ -8,6 +8,8 @@
 #include <utility>
 
 #include "ash/constants/ash_switches.h"
+#include "ash/metrics/login_unlock_throughput_recorder.h"
+#include "ash/shell.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram_functions.h"
@@ -449,6 +451,10 @@
     return;
   }
 
+  LoginUnlockThroughputRecorder* throughput_recorder =
+      Shell::HasInstance() ? Shell::Get()->login_unlock_throughput_recorder()
+                           : nullptr;
+
   int arc_app_count = 0;
   int other_app_count = 0;
   for (const auto& it : restore_data()->app_id_to_launch_list()) {
@@ -460,6 +466,12 @@
       continue;
     }
 
+    if (throughput_recorder) {
+      for (const auto& window : it.second) {
+        throughput_recorder->AddScheduledRestoreWindow(
+            window.first, it.first, LoginUnlockThroughputRecorder::kBrowser);
+      }
+    }
     ++other_app_count;
   }
   VLOG(1) << "There is restore data: Browser("
diff --git a/chrome/browser/ash/arc/input_method_manager/arc_input_method_manager_service_unittest.cc b/chrome/browser/ash/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
index 86b20eb..7da0591 100644
--- a/chrome/browser/ash/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
+++ b/chrome/browser/ash/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
@@ -943,7 +943,8 @@
   // Set up mock input context.
   const ui::TextInputMethod::InputContext test_context{
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT, 0 /* flags */,
-      ui::TextInputClient::FOCUS_REASON_MOUSE, true /* should_do_learning */};
+      ui::TextInputClient::FOCUS_REASON_MOUSE,
+      ui::PersonalizationMode::kEnabled};
   ui::MockInputMethod mock_input_method(nullptr);
   TestIMEInputContextHandler test_context_handler(&mock_input_method);
   ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
@@ -1039,7 +1040,8 @@
   // Set up mock input context.
   const ui::TextInputMethod::InputContext test_context{
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT, 0 /* flags */,
-      ui::TextInputClient::FOCUS_REASON_MOUSE, true /* should_do_learning */};
+      ui::TextInputClient::FOCUS_REASON_MOUSE,
+      ui::PersonalizationMode::kEnabled};
   ui::MockInputMethod mock_input_method(nullptr);
   TestIMEInputContextHandler test_context_handler(&mock_input_method);
   ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
@@ -1104,7 +1106,8 @@
   // Set up mock input context.
   const ui::TextInputMethod::InputContext test_context{
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT, 0 /* flags */,
-      ui::TextInputClient::FOCUS_REASON_MOUSE, true /* should_do_learning */};
+      ui::TextInputClient::FOCUS_REASON_MOUSE,
+      ui::PersonalizationMode::kEnabled};
   ui::MockInputMethod mock_input_method(nullptr);
   TestIMEInputContextHandler test_context_handler(&mock_input_method);
   ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
diff --git a/chrome/browser/ash/arc/input_method_manager/input_connection_impl_unittest.cc b/chrome/browser/ash/arc/input_method_manager/input_connection_impl_unittest.cc
index 15f7585..734d89d9 100644
--- a/chrome/browser/ash/arc/input_method_manager/input_connection_impl_unittest.cc
+++ b/chrome/browser/ash/arc/input_method_manager/input_connection_impl_unittest.cc
@@ -188,7 +188,8 @@
   ui::TextInputMethod::InputContext context() {
     return ui::TextInputMethod::InputContext{
         ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT, 0 /* flags */,
-        ui::TextInputClient::FOCUS_REASON_MOUSE, true /* should_do_learning */};
+        ui::TextInputClient::FOCUS_REASON_MOUSE,
+        ui::PersonalizationMode::kEnabled};
   }
 
   void SetUp() override {
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator.h b/chrome/browser/ash/crosapi/browser_data_migrator.h
index 5ca07189..2a796bf 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator.h
+++ b/chrome/browser/ash/crosapi/browser_data_migrator.h
@@ -209,6 +209,10 @@
                            MaybeRestartToMigrateWithMigrationStep);
   FRIEND_TEST_ALL_PREFIXES(BrowserDataMigratorRestartTest,
                            MaybeRestartToMigrateMoveAfterCopy);
+  FRIEND_TEST_ALL_PREFIXES(BrowserDataMigratorRestartTest,
+                           LacrosProfileMigrationForAnyUserDisabled);
+  FRIEND_TEST_ALL_PREFIXES(BrowserDataMigratorRestartTest,
+                           LacrosProfileMigrationForAnyUserDisabledForGoogler);
 
   // The common implementation of `MaybeRestartToMigrate` and
   // `MaybeRestartToMigrateWithDiskCheck`.
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_browsertest.cc b/chrome/browser/ash/crosapi/browser_data_migrator_browsertest.cc
index 61c26a1..7f4fc8e 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_browsertest.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_browsertest.cc
@@ -132,10 +132,7 @@
   ~BrowserDataMigratorCopyMigrateOnSignIn() override = default;
 
   void SetUp() override {
-    feature_list_.InitWithFeatures(
-        {ash::features::kLacrosSupport,
-         ash::features::kLacrosProfileMigrationForAnyUser},
-        {});
+    feature_list_.InitWithFeatures({ash::features::kLacrosSupport}, {});
 
     BrowserDataMigratorOnSignIn::SetUp();
   }
@@ -193,16 +190,6 @@
   BrowserDataMigratorMoveMigrateOnSignInByPolicy& operator=(
       BrowserDataMigratorMoveMigrateOnSignInByPolicy&) = delete;
   ~BrowserDataMigratorMoveMigrateOnSignInByPolicy() override = default;
-
-  void SetUp() override {
-    feature_list_.InitWithFeatures(
-        {ash::features::kLacrosProfileMigrationForAnyUser}, {});
-
-    BrowserDataMigratorOnSignIn::SetUp();
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
 };
 
 // Enabling LacrosOnly by policy should trigger move migration during signin.
@@ -236,8 +223,7 @@
   void SetUp() override {
     feature_list_.InitWithFeatures(
         {ash::features::kLacrosSupport, ash::features::kLacrosPrimary,
-         ash::features::kLacrosOnly,
-         ash::features::kLacrosProfileMigrationForAnyUser},
+         ash::features::kLacrosOnly},
         {});
 
     BrowserDataMigratorOnSignIn::SetUp();
@@ -376,8 +362,7 @@
   void SetUp() override {
     feature_list_.InitWithFeatures(
         {ash::features::kLacrosSupport, ash::features::kLacrosPrimary,
-         ash::features::kLacrosOnly,
-         ash::features::kLacrosProfileMigrationForAnyUser},
+         ash::features::kLacrosOnly},
         {});
 
     BrowserDataMigratorRestartInSession::SetUp();
@@ -409,13 +394,6 @@
   ~BrowserDataMigratorMoveMigrateOnRestartInSessionByPolicy() override =
       default;
 
-  void SetUp() override {
-    feature_list_.InitAndEnableFeature(
-        ash::features::kLacrosProfileMigrationForAnyUser);
-
-    BrowserDataMigratorRestartInSession::SetUp();
-  }
-
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitchASCII(
         crosapi::browser_util::kLacrosAvailabilityPolicySwitch,
@@ -479,10 +457,7 @@
   ~BrowserDataMigratorForKiosk() override = default;
 
   void SetUp() override {
-    feature_list_.InitWithFeatures(
-        {ash::features::kLacrosSupport,
-         ash::features::kLacrosProfileMigrationForAnyUser},
-        {});
+    feature_list_.InitWithFeatures({ash::features::kLacrosSupport}, {});
 
     KioskBaseTest::SetUp();
   }
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
index 01e5cdb5..44b37f6 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
@@ -449,8 +449,6 @@
   {
     // If Lacros is not enabled, migration should not run.
     base::test::ScopedFeatureList feature_list;
-    feature_list.InitWithFeatures(
-        {ash::features::kLacrosProfileMigrationForAnyUser}, {});
     EXPECT_EQ(crosapi::browser_util::GetMigrationMode(
                   user, crosapi::browser_util::PolicyInitState::kAfterInit),
               crosapi::browser_util::MigrationMode::kCopy);
@@ -462,10 +460,7 @@
   {
     // If Lacros is enabled, migration should run.
     base::test::ScopedFeatureList feature_list;
-    feature_list.InitWithFeatures(
-        {ash::features::kLacrosSupport,
-         ash::features::kLacrosProfileMigrationForAnyUser},
-        {});
+    feature_list.InitWithFeatures({ash::features::kLacrosSupport}, {});
     EXPECT_EQ(crosapi::browser_util::GetMigrationMode(
                   user, crosapi::browser_util::PolicyInitState::kAfterInit),
               crosapi::browser_util::MigrationMode::kCopy);
@@ -481,10 +476,7 @@
   {
     // If migration is marked as completed, migration should not run.
     base::test::ScopedFeatureList feature_list;
-    feature_list.InitWithFeatures(
-        {ash::features::kLacrosSupport,
-         ash::features::kLacrosProfileMigrationForAnyUser},
-        {});
+    feature_list.InitWithFeatures({ash::features::kLacrosSupport}, {});
     EXPECT_EQ(crosapi::browser_util::GetMigrationMode(
                   user, crosapi::browser_util::PolicyInitState::kAfterInit),
               crosapi::browser_util::MigrationMode::kCopy);
@@ -502,8 +494,7 @@
     base::test::ScopedFeatureList feature_list;
     feature_list.InitWithFeatures(
         {ash::features::kLacrosSupport, ash::features::kLacrosPrimary,
-         ash::features::kLacrosOnly,
-         ash::features::kLacrosProfileMigrationForAnyUser},
+         ash::features::kLacrosOnly},
         {});
     EXPECT_EQ(crosapi::browser_util::GetMigrationMode(
                   user, crosapi::browser_util::PolicyInitState::kAfterInit),
@@ -524,8 +515,7 @@
     base::test::ScopedFeatureList feature_list;
     feature_list.InitWithFeatures(
         {ash::features::kLacrosSupport, ash::features::kLacrosPrimary,
-         ash::features::kLacrosOnly,
-         ash::features::kLacrosProfileMigrationForAnyUser},
+         ash::features::kLacrosOnly},
         {});
     EXPECT_EQ(crosapi::browser_util::GetMigrationMode(
                   user, crosapi::browser_util::PolicyInitState::kAfterInit),
@@ -535,4 +525,59 @@
         crosapi::browser_util::PolicyInitState::kAfterInit));
   }
 }
+
+TEST_F(BrowserDataMigratorRestartTest,
+       LacrosProfileMigrationForAnyUserDisabled) {
+  AddRegularUser("user@gmail.com");
+  const user_manager::User* const user =
+      ash::ProfileHelper::Get()->GetUserByProfile(testing_profile());
+
+  crosapi::browser_util::RecordDataVer(
+      local_state(), user->username_hash(),
+      base::Version(
+          base::StringPiece(crosapi::browser_util::kRequiredDataVersion)));
+  {
+    // If Lacros is enabled, migration should run.
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitWithFeatures({ash::features::kLacrosSupport}, {});
+    EXPECT_TRUE(BrowserDataMigratorImpl::MaybeRestartToMigrateInternal(
+        user->GetAccountId(), user->username_hash(),
+        crosapi::browser_util::PolicyInitState::kAfterInit));
+  }
+
+  {
+    // If Lacros is enabled but `kLacrosProfileMigrationForAnyUser` is disabled,
+    // migration should not run.
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitWithFeatures(
+        {}, {ash::features::kLacrosProfileMigrationForAnyUser});
+    EXPECT_FALSE(BrowserDataMigratorImpl::MaybeRestartToMigrateInternal(
+        user->GetAccountId(), user->username_hash(),
+        crosapi::browser_util::PolicyInitState::kAfterInit));
+  }
+}
+
+TEST_F(BrowserDataMigratorRestartTest,
+       LacrosProfileMigrationForAnyUserDisabledForGoogler) {
+  AddRegularUser("user@google.com");
+  const user_manager::User* const user =
+      ash::ProfileHelper::Get()->GetUserByProfile(testing_profile());
+
+  crosapi::browser_util::RecordDataVer(
+      local_state(), user->username_hash(),
+      base::Version(
+          base::StringPiece(crosapi::browser_util::kRequiredDataVersion)));
+  {
+    // If Lacros is enabled, migration should run even if
+    // `kLacrosProfileMigrationForAnyUser` is disabled for Googlers.
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitWithFeatures(
+        {ash::features::kLacrosSupport},
+        {ash::features::kLacrosProfileMigrationForAnyUser});
+    EXPECT_TRUE(BrowserDataMigratorImpl::MaybeRestartToMigrateInternal(
+        user->GetAccountId(), user->username_hash(),
+        crosapi::browser_util::PolicyInitState::kAfterInit));
+  }
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc
index a631d0fe..115f43d 100644
--- a/chrome/browser/ash/crosapi/browser_util.cc
+++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -405,9 +405,10 @@
     return false;
   }
 
-  //  Currently we turn on profile migration only for Googlers.
-  //  `kLacrosProfileMigrationForAnyUser` can be enabled to allow testing with
-  //  non-googler accounts.
+  // Now `kLacrosProfileMigrationForAnyUser` is enabled by default thus the
+  // following condition is false only when the account is not an internal
+  // google account (@google.com account) and the user has disabled
+  // `kLacrosProfileMigrationForAnyUser`.
   if (gaia::IsGoogleInternalAccountEmail(account_id.GetUserEmail()) ||
       base::FeatureList::IsEnabled(
           ash::features::kLacrosProfileMigrationForAnyUser))
diff --git a/chrome/browser/ash/crosapi/test/network_change_ash_browsertest.cc b/chrome/browser/ash/crosapi/test/network_change_ash_browsertest.cc
deleted file mode 100644
index eedf2c8e..0000000
--- a/chrome/browser/ash/crosapi/test/network_change_ash_browsertest.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/run_loop.h"
-#include "chrome/browser/ash/crosapi/crosapi_ash.h"
-#include "chrome/browser/ash/crosapi/crosapi_manager.h"
-#include "chrome/browser/ash/crosapi/network_change_ash.h"
-#include "chrome/browser/ash/network_change_manager_client.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chromeos/crosapi/mojom/network_change.mojom.h"
-#include "content/public/test/browser_test.h"
-
-namespace crosapi {
-namespace {
-
-class MockNerworkChangeObserver : public mojom::NetworkChangeObserver {
- public:
-  MOCK_METHOD(void,
-              OnNetworkChanged,
-              (bool dns_changed,
-               bool ip_address_changed,
-               bool connection_type_changed,
-               mojom::ConnectionType new_connection_type,
-               bool connection_subtype_changed,
-               mojom::ConnectionSubtype new_connection_subtype),
-              (override));
-};
-
-class NetworkChangeCrosapiTest : public InProcessBrowserTest {
- protected:
-  testing::NiceMock<MockNerworkChangeObserver> observer;
-  mojo::Receiver<mojom::NetworkChangeObserver> receiver{&observer};
-};
-
-IN_PROC_BROWSER_TEST_F(NetworkChangeCrosapiTest, OnNetworkChanged) {
-  base::RunLoop run_loop;
-
-  // When AddObserver() is called, OnNetworkChange() should also be called to
-  // initialize network setup.
-  EXPECT_CALL(observer,
-              OnNetworkChanged(
-                  /*dns_changed=*/false, /*ip_address_changed=*/false,
-                  /*connection_type_changed=*/true,
-                  mojom::ConnectionType(
-                      net::NetworkChangeNotifier::CONNECTION_ETHERNET),
-                  /*connection_subtype_changed=*/true,
-                  mojom::ConnectionSubtype(
-                      net::NetworkChangeNotifier::SUBTYPE_UNKNOWN)))
-      .WillOnce([&] { run_loop.Quit(); });
-  CrosapiManager::Get()->crosapi_ash()->network_change_ash()->AddObserver(
-      receiver.BindNewPipeAndPassRemote());
-  run_loop.Run();
-
-  EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&observer));
-
-  // When the network connection changes, OnNetworkChange() should be called.
-  // TODO(crbug.com/1356920): Replace SuspendDone() by test crosapi at the time
-  // we implement isolation test.
-  EXPECT_CALL(
-      observer,
-      OnNetworkChanged(
-          /*dns_changed=*/false, /*ip_address_changed=*/true,
-          /*connection_type_changed=*/false,
-          mojom::ConnectionType(net::NetworkChangeNotifier::CONNECTION_UNKNOWN),
-          /*connection_subtype_changed=*/false,
-          mojom::ConnectionSubtype(net::NetworkChangeNotifier::SUBTYPE_NONE)));
-  ash::NetworkChangeManagerClient::GetInstance()->SuspendDone(
-      base::TimeDelta());
-}
-
-}  // namespace
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/test/network_change_ash_crosapitest.cc b/chrome/browser/ash/crosapi/test/network_change_ash_crosapitest.cc
new file mode 100644
index 0000000..fc29beca
--- /dev/null
+++ b/chrome/browser/ash/crosapi/test/network_change_ash_crosapitest.cc
@@ -0,0 +1,132 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/run_loop.h"
+#include "chrome/browser/ash/crosapi/test/crosapi_test_base.h"
+#include "chromeos/crosapi/mojom/crosapi.mojom.h"
+#include "chromeos/crosapi/mojom/network_change.mojom.h"
+#include "chromeos/crosapi/mojom/test_controller.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "net/base/network_change_notifier.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::_;
+using testing::AnyNumber;
+
+namespace crosapi {
+namespace {
+
+constexpr char kWifiServicePath[] = "/service/wifi1";
+constexpr char kEthServicePath[] = "/service/eth1";
+
+class MockNetworkChangeObserver : public mojom::NetworkChangeObserver {
+ public:
+  // This mock is for catching the input given via crosapi, but not for
+  // modifying the crosapi behavior.
+  MOCK_METHOD(void,
+              OnNetworkChanged,
+              (bool dns_changed,
+               bool ip_address_changed,
+               bool connection_type_changed,
+               mojom::ConnectionType new_connection_type,
+               bool connection_subtype_changed,
+               mojom::ConnectionSubtype new_connection_subtype),
+              (override));
+};
+
+class NetworkChangeCrosapiTest : public CrosapiTestBase {
+ protected:
+  void SetUp() override {
+    CrosapiTestBase::SetUp();
+
+    network_change_ = BindCrosapiInterface(&mojom::Crosapi::BindNetworkChange);
+    test_controller_ =
+        BindCrosapiInterface(&mojom::Crosapi::BindTestController);
+  }
+
+  mojo::Remote<mojom::NetworkChange> network_change_;
+  mojo::Remote<mojom::TestController> test_controller_;
+
+  MockNetworkChangeObserver observer_;
+  mojo::Receiver<mojom::NetworkChangeObserver> receiver_{&observer_};
+};
+
+TEST_F(NetworkChangeCrosapiTest, OnNetworkChanged) {
+  base::RunLoop run_loop;
+  // When NetworkChange::AddObserver() is called,
+  // NetworkChangeObserver::OnNetworkChange() should also be called to
+  // initialize network setup.
+  EXPECT_CALL(observer_,
+              OnNetworkChanged(
+                  /*dns_changed=*/false, /*ip_address_changed=*/false,
+                  /*connection_type_changed=*/true,
+                  mojom::ConnectionType(
+                      net::NetworkChangeNotifier::CONNECTION_ETHERNET),
+                  /*connection_subtype_changed=*/true,
+                  mojom::ConnectionSubtype(
+                      net::NetworkChangeNotifier::SUBTYPE_UNKNOWN)))
+      .WillOnce([&] { run_loop.Quit(); });
+  network_change_->AddObserver(receiver_.BindNewPipeAndPassRemote());
+  run_loop.Run();
+
+  EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&observer_));
+
+  {
+    testing::InSequence sequence;
+
+    base::RunLoop run_loop2;
+    // Ignore OnNetworkChange() calls and only check the last result which
+    // overrides all results passed before. The first called
+    // DisconnectFromNetwork() causes a few network chaneges for some reason.
+    // TODO(crbug.com/1374276): Modify network change crosapi specification.
+    EXPECT_CALL(observer_, OnNetworkChanged(_, _, _, _, _, _))
+        .Times(AnyNumber());
+    // Check if eventually disconnected from Ethernet and connected to Wifi.
+    EXPECT_CALL(observer_, OnNetworkChanged(
+                               /*dns_changed=*/true,
+                               /*ip_address_changed=*/true,
+                               /*connection_type_changed=*/true,
+                               mojom::ConnectionType::CONNECTION_WIFI,
+                               /*connection_subtype_changed=*/true,
+                               mojom::ConnectionSubtype::SUBTYPE_UNKNOWN))
+        .WillOnce([&] { run_loop2.Quit(); });
+
+    test_controller_->DisconnectFromNetwork(kEthServicePath);
+    run_loop2.Run();
+  }
+  EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&observer_));
+
+  base::RunLoop run_loop3;
+  // Check if disconnected from Wifi and not connected to anything.
+  EXPECT_CALL(observer_, OnNetworkChanged(
+                             /*dns_changed=*/true,
+                             /*ip_address_changed=*/true,
+                             /*connection_type_changed=*/true,
+                             mojom::ConnectionType::CONNECTION_NONE,
+                             /*connection_subtype_changed=*/true,
+                             mojom::ConnectionSubtype::SUBTYPE_NONE))
+      .WillOnce([&] { run_loop3.Quit(); });
+
+  test_controller_->DisconnectFromNetwork(kWifiServicePath);
+  run_loop3.Run();
+
+  EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&observer_));
+
+  base::RunLoop run_loop4;
+  // Check if connected to Ethernet.
+  EXPECT_CALL(observer_, OnNetworkChanged(
+                             /*dns_changed=*/true,
+                             /*ip_address_changed=*/true,
+                             /*connection_type_changed=*/true,
+                             mojom::ConnectionType::CONNECTION_ETHERNET,
+                             /*connection_subtype_changed=*/true,
+                             mojom::ConnectionSubtype::SUBTYPE_UNKNOWN))
+      .WillOnce([&] { run_loop4.Quit(); });
+
+  test_controller_->ConnectToNetwork(kEthServicePath);
+  run_loop4.Run();
+}
+
+}  // namespace
+}  // namespace crosapi
diff --git a/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc b/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc
index 99e86a0d..f308029 100644
--- a/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc
+++ b/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc
@@ -427,11 +427,6 @@
         continue;
       }
 
-      if (engine.engine_id == "vkd_hi_inscript" &&
-          !base::FeatureList::IsEnabled(features::kHindiInscriptLayout)) {
-        continue;
-      }
-
       component_ime.engines.push_back(engine);
     }
     out_imes->push_back(component_ime);
diff --git a/chrome/browser/ash/input_method/input_method_engine_browsertests.cc b/chrome/browser/ash/input_method/input_method_engine_browsertests.cc
index f9cc57f..e8ca9ecb 100644
--- a/chrome/browser/ash/input_method/input_method_engine_browsertests.cc
+++ b/chrome/browser/ash/input_method/input_method_engine_browsertests.cc
@@ -82,7 +82,7 @@
     return ui::TextInputMethod::InputContext(
         type, ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_FLAG_NONE,
         ui::TextInputClient::FOCUS_REASON_OTHER,
-        false /* should_do_learning */);
+        ui::PersonalizationMode::kDisabled);
   }
 
  protected:
@@ -1426,7 +1426,7 @@
   ExtensionTestMessageListener focus_listener(
       "onFocus:text:true:true:true:true");
   auto context = CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_TEXT);
-  context.should_do_learning = true;
+  context.personalization_mode = ui::PersonalizationMode::kEnabled;
   engine_handler->FocusIn(context);
   ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
   ASSERT_TRUE(focus_listener.was_satisfied());
diff --git a/chrome/browser/ash/input_method/input_method_engine_unittest.cc b/chrome/browser/ash/input_method/input_method_engine_unittest.cc
index beb781b..2c6a170 100644
--- a/chrome/browser/ash/input_method/input_method_engine_unittest.cc
+++ b/chrome/browser/ash/input_method/input_method_engine_unittest.cc
@@ -172,7 +172,7 @@
     ui::TextInputMethod::InputContext input_context(
         input_type, ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_FLAG_NONE,
         ui::TextInputClient::FOCUS_REASON_OTHER,
-        false /* should_do_learning */);
+        ui::PersonalizationMode::kDisabled);
     engine_->FocusIn(input_context);
     ui::IMEBridge::Get()->SetCurrentInputContext(input_context);
   }
diff --git a/chrome/browser/ash/input_method/input_method_syncer.cc b/chrome/browser/ash/input_method/input_method_syncer.cc
index ca2a8262..2101ff4e 100644
--- a/chrome/browser/ash/input_method/input_method_syncer.cc
+++ b/chrome/browser/ash/input_method/input_method_syncer.cc
@@ -291,7 +291,8 @@
 void InputMethodSyncer::OnPreferenceChanged(const std::string& pref_name) {
   DCHECK(pref_name == language::prefs::kPreferredLanguages ||
          pref_name == prefs::kLanguagePreloadEngines ||
-         pref_name == prefs::kLanguageEnabledImes);
+         pref_name == prefs::kLanguageEnabledImes ||
+         pref_name == prefs::kHindiInscriptLayoutEnabled);
 
   if (merging_ || prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods))
     return;
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
index 3430b69..24cf00bc 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
+++ b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
@@ -468,6 +468,16 @@
   }
 }
 
+mojom::PersonalizationMode GetPersonalizationMode(
+    ui::PersonalizationMode mode) {
+  switch (mode) {
+    case ui::PersonalizationMode::kEnabled:
+      return mojom::PersonalizationMode::kEnabled;
+    case ui::PersonalizationMode::kDisabled:
+      return mojom::PersonalizationMode::kDisabled;
+  }
+}
+
 mojom::InputFieldInfoPtr CreateInputFieldInfo(
     const std::string& engine_id,
     const ui::TextInputMethod::InputContext& context,
@@ -488,8 +498,7 @@
   return mojom::InputFieldInfo::New(
       TextInputTypeToMojoType(context.type),
       AutocorrectFlagsToMojoType(context.flags),
-      context.should_do_learning ? mojom::PersonalizationMode::kEnabled
-                                 : mojom::PersonalizationMode::kDisabled,
+      GetPersonalizationMode(context.personalization_mode),
       GetTextPredictionMode(engine_id, input_field_context, prefs));
 }
 
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc b/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc
index 5aac331..20debcd 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc
+++ b/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc
@@ -459,7 +459,7 @@
   ui::TextInputMethod::InputContext input_context(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true);
+      ui::PersonalizationMode::kEnabled);
   engine.Enable(kEngineIdUs);
   engine.FlushForTesting();  // ensure input_method connected.
   engine.FocusIn(input_context);
@@ -508,7 +508,7 @@
   ui::TextInputMethod::InputContext input_context(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true);
+      ui::PersonalizationMode::kEnabled);
   engine.Enable(kEngineIdUs);
   engine.FlushForTesting();  // ensure input_method connected.
   engine.FocusIn(input_context);
@@ -533,7 +533,7 @@
   ui::TextInputMethod::InputContext input_context(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true);
+      ui::PersonalizationMode::kEnabled);
   engine.Enable(kEngineIdPinyin);
   engine.FlushForTesting();  // ensure input_method is connected.
   engine.FocusIn(input_context);
@@ -587,7 +587,7 @@
   ui::TextInputMethod::InputContext input_context(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true);
+      ui::PersonalizationMode::kEnabled);
   engine.Enable(kEngineIdUs);
   engine.FlushForTesting();  // ensure input_method is connected.
   engine.FocusIn(input_context);
@@ -638,7 +638,7 @@
   ui::TextInputMethod::InputContext input_context(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true);
+      ui::PersonalizationMode::kEnabled);
   engine.Enable(kEngineIdUs);
   engine.FlushForTesting();  // ensure input_method is connected.
   engine.FocusIn(input_context);
@@ -669,7 +669,7 @@
   ui::TextInputMethod::InputContext input_context(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true);
+      ui::PersonalizationMode::kEnabled);
   engine.Enable(kEngineIdUs);
   engine.FlushForTesting();  // ensure input_method is connected.
   engine.FocusIn(input_context);
@@ -725,7 +725,7 @@
   engine.FocusIn(ui::TextInputMethod::InputContext(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true));
+      ui::PersonalizationMode::kEnabled));
   // Each character in "你好" is one UTF-16 code unit.
   engine.SetSurroundingText(u"你好",
                             /*cursor_pos=*/2,
@@ -780,7 +780,7 @@
   engine.FocusIn(ui::TextInputMethod::InputContext(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true));
+      ui::PersonalizationMode::kEnabled));
 
   // Quote ("VKEY_OEM_7") + A is a dead key combination.
   engine.ProcessKeyEvent(
@@ -845,7 +845,7 @@
   engine.FocusIn(ui::TextInputMethod::InputContext(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true));
+      ui::PersonalizationMode::kEnabled));
 
   // Enter and Backspace are named keys with Unicode representation.
   engine.ProcessKeyEvent(
@@ -896,7 +896,7 @@
   engine.FocusIn(ui::TextInputMethod::InputContext(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true));
+      ui::PersonalizationMode::kEnabled));
 
   // Help is a named DOM key, but is not used by IMEs.
   engine.ProcessKeyEvent({ui::ET_KEY_PRESSED, ui::VKEY_HELP, ui::DomCode::HELP,
@@ -961,7 +961,7 @@
   ui::TextInputMethod::InputContext input_context(
       ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
       ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
-      /*should_do_learning=*/true);
+      ui::PersonalizationMode::kEnabled);
   engine.Enable(kEngineIdUs);
   engine.FlushForTesting();
 
diff --git a/chrome/browser/ash/login/saml/fake_saml_idp_mixin.cc b/chrome/browser/ash/login/saml/fake_saml_idp_mixin.cc
index 1ebcbeee..a9d9725 100644
--- a/chrome/browser/ash/login/saml/fake_saml_idp_mixin.cc
+++ b/chrome/browser/ash/login/saml/fake_saml_idp_mixin.cc
@@ -8,6 +8,8 @@
 #include "base/containers/contains.h"
 #include "base/containers/span.h"
 #include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
@@ -174,6 +176,10 @@
   return challenge_response_.has_value();
 }
 
+bool FakeSamlIdpMixin::IsLastChallengeResponseError() const {
+  return error_challenge_response_.has_value();
+}
+
 int FakeSamlIdpMixin::GetChallengeResponseCount() const {
   return challenge_response_count_;
 }
@@ -342,8 +348,17 @@
   auto http_response = std::make_unique<BasicHttpResponse>();
   http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
   http_response->AddCustomHeader("Location", redirect_url.spec());
+
+  // Device Trust only supports V2 challenges, which are formatted as a JSON
+  // object with only one "challenge" property (containing the value from V1).
+  // TODO(b:253427534): Update code to handle V1 challenges.
+  base::Value::Dict challenge_value;
+  challenge_value.Set("challenge", GetTpmChallengeBase64());
+  std::string challenge_json_value;
+  EXPECT_TRUE(base::JSONWriter::Write(challenge_value, &challenge_json_value));
+
   http_response->AddCustomHeader(kSamlVerifiedAccessChallengeHeader,
-                                 GetTpmChallengeBase64());
+                                 challenge_json_value);
   return http_response;
 }
 
@@ -389,12 +404,33 @@
 
 void FakeSamlIdpMixin::SaveChallengeResponse(const std::string& response) {
   EXPECT_EQ(challenge_response_, absl::nullopt);
-  challenge_response_ = response;
+  auto parsed_value = base::JSONReader::Read(
+      response, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS);
+
+  if (!parsed_value || !parsed_value->is_dict()) {
+    // Most likely given a V1, no need to try parsing the values out.
+    challenge_response_ = response;
+    return;
+  }
+
+  const std::string* challenge_response_string =
+      parsed_value->GetDict().FindString("challengeResponse");
+  const std::string* error_string = parsed_value->GetDict().FindString("error");
+
+  // Only one of those values should be set.
+  EXPECT_NE(!!challenge_response_string, !!error_string);
   challenge_response_count_++;
+
+  if (challenge_response_string) {
+    challenge_response_ = response;
+  } else {
+    error_challenge_response_ = response;
+  }
 }
 
 void FakeSamlIdpMixin::ClearChallengeResponse() {
   challenge_response_.reset();
+  error_challenge_response_.reset();
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ash/login/saml/fake_saml_idp_mixin.h b/chrome/browser/ash/login/saml/fake_saml_idp_mixin.h
index 4a7e7e77..151239b 100644
--- a/chrome/browser/ash/login/saml/fake_saml_idp_mixin.h
+++ b/chrome/browser/ash/login/saml/fake_saml_idp_mixin.h
@@ -42,10 +42,15 @@
   void SetRequireHttpBasicAuth(bool require_http_basic_auth);
   void SetSamlResponseFile(const std::string& xml_file);
   bool DeviceTrustHeaderRecieved() const;
-  bool IsLastChallengeResponseExists() const;
   int GetChallengeResponseCount() const;
   void AssertChallengeResponseMatchesTpmResponse() const;
 
+  // Returns true if a successful challenge response was captured.
+  bool IsLastChallengeResponseExists() const;
+
+  // Returns true if a failed challenge response was captured.
+  bool IsLastChallengeResponseError() const;
+
   std::string GetIdpHost() const;
   std::string GetIdpDomain() const;
   GURL GetSamlPageUrl() const;
@@ -118,6 +123,7 @@
   bool device_trust_header_recieved_ = false;
   int challenge_response_count_ = 0;
   absl::optional<std::string> challenge_response_;
+  absl::optional<std::string> error_challenge_response_;
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ash/login/saml/saml_browsertest.cc b/chrome/browser/ash/login/saml/saml_browsertest.cc
index 3cd4e75..a7087cc 100644
--- a/chrome/browser/ash/login/saml/saml_browsertest.cc
+++ b/chrome/browser/ash/login/saml/saml_browsertest.cc
@@ -2107,10 +2107,11 @@
 
   ASSERT_EQ(fake_saml_idp()->GetChallengeResponseCount(), 1);
 
+  // TODO(b:253427534): Handle VA V1 challenges cases for Device Trust.
   histogram_tester_.ExpectBucketCount(
       kDeviceTrustAttestationFunnelStep,
       enterprise_connectors::DTAttestationFunnelStep::kChallengeResponseSent,
-      1);
+      0);
 }
 
 IN_PROC_BROWSER_TEST_F(SAMLDeviceAttestationEnrolledTest, TimeoutError) {
diff --git a/chrome/browser/ash/login/screens/consolidated_consent_screen.cc b/chrome/browser/ash/login/screens/consolidated_consent_screen.cc
index 369607e..55aa012 100644
--- a/chrome/browser/ash/login/screens/consolidated_consent_screen.cc
+++ b/chrome/browser/ash/login/screens/consolidated_consent_screen.cc
@@ -184,6 +184,12 @@
   // URL for Chrome and ChromeOS additional terms of service, the URL should
   // include the locale.
   data.Set("crosEulaUrl", GetCrosEulaOnlineUrl());
+  // Option that controls if Recovery factor opt-in should be shown for the
+  // user.
+  data.Set("showRecoveryOption", context()->ask_about_recovery_consent);
+  // Default value for recovery opt toggle.
+  data.Set("recoveryOptionDefault", context()->ask_about_recovery_consent);
+
   view_->Show(std::move(data));
 }
 
@@ -196,12 +202,14 @@
   if (action_id == kBackDemoButtonClicked) {
     exit_callback_.Run(Result::BACK_DEMO);
   } else if (action_id == kAcceptButtonClicked) {
-    CHECK_EQ(args.size(), 5u);
+    CHECK_EQ(args.size(), 6u);
     const bool enable_usage = args[1].GetBool();
     const bool enable_backup = args[2].GetBool();
     const bool enable_location = args[3].GetBool();
     const std::string& tos_content = args[4].GetString();
-    OnAccept(enable_usage, enable_backup, enable_location, tos_content);
+    const bool enable_recovery = args[5].GetBool();
+    OnAccept(enable_usage, enable_backup, enable_location, tos_content,
+             enable_recovery);
   } else {
     BaseScreen::OnUserAction(args);
   }
@@ -382,9 +390,12 @@
 void ConsolidatedConsentScreen::OnAccept(bool enable_stats_usage,
                                          bool enable_backup_restore,
                                          bool enable_location_services,
-                                         const std::string& tos_content) {
+                                         const std::string& tos_content,
+                                         bool enable_recovery) {
   ReportUsageOptIn(enable_stats_usage);
 
+  context()->recovery_factor_opted_in = enable_recovery;
+
   if (arc::IsArcDemoModeSetupFlow() ||
       !arc::IsArcTermsOfServiceOobeNegotiationNeeded()) {
     for (auto& observer : observer_list_)
diff --git a/chrome/browser/ash/login/screens/consolidated_consent_screen.h b/chrome/browser/ash/login/screens/consolidated_consent_screen.h
index aa9544c..f881c33 100644
--- a/chrome/browser/ash/login/screens/consolidated_consent_screen.h
+++ b/chrome/browser/ash/login/screens/consolidated_consent_screen.h
@@ -70,7 +70,8 @@
   void OnAccept(bool enable_stats_usage,
                 bool enable_backup_restore,
                 bool enable_location_services,
-                const std::string& tos_content);
+                const std::string& tos_content,
+                bool enable_recovery);
 
   // arc::ArcOptInPreferenceHandlerObserver:
   void OnMetricsModeChanged(bool enabled, bool managed) override;
diff --git a/chrome/browser/ash/login/screens/consolidated_consent_screen_browsertest.cc b/chrome/browser/ash/login/screens/consolidated_consent_screen_browsertest.cc
index 0619d77..fa6d68f 100644
--- a/chrome/browser/ash/login/screens/consolidated_consent_screen_browsertest.cc
+++ b/chrome/browser/ash/login/screens/consolidated_consent_screen_browsertest.cc
@@ -83,6 +83,8 @@
 const test::UIPath kBackupLearnMorePopUpClose = {
     kConsolidatedConsentId, "backupLearnMorePopUp", "closeButton"};
 
+const test::UIPath kRecovery = {kConsolidatedConsentId, "recovery"};
+
 const test::UIPath kLocation = {kConsolidatedConsentId, "location"};
 const test::UIPath kLocationToggle = {kConsolidatedConsentId, "locationOptIn"};
 const test::UIPath kLocationLearnMoreLink = {kConsolidatedConsentId,
@@ -270,6 +272,7 @@
   test::OobeJS().ExpectVisiblePath(kUsageStats);
   test::OobeJS().ExpectEnabledPath(kUsageStatsToggle);
   test::OobeJS().ExpectHiddenPath(kBackup);
+  test::OobeJS().ExpectHiddenPath(kRecovery);
   test::OobeJS().ExpectHiddenPath(kLocation);
   test::OobeJS().ExpectHiddenPath(kFooter);
 }
@@ -379,8 +382,9 @@
   FakeArcTosMixin fake_arc_tos_{&mixin_host_, embedded_test_server()};
 };
 
-// For regular users with ARC enavled, all opt-ins are visible and the toggles
-// are enabled.
+// For regular users with ARC enabled, all ARC opt-ins are visible and the
+// toggles are enabled. Recovery service availability would depend on feature
+// flag.
 IN_PROC_BROWSER_TEST_F(ConsolidatedConsentScreenArcEnabledTest,
                        OptinsVisiblity) {
   LoginAsRegularUser();
@@ -391,6 +395,7 @@
   test::OobeJS().ExpectEnabledPath(kUsageStatsToggle);
   test::OobeJS().ExpectVisiblePath(kBackup);
   test::OobeJS().ExpectEnabledPath(kBackupToggle);
+  test::OobeJS().ExpectHiddenPath(kRecovery);
   test::OobeJS().ExpectVisiblePath(kLocation);
   test::OobeJS().ExpectEnabledPath(kLocationToggle);
 
diff --git a/chrome/browser/ash/login/users/avatar/user_image_loader.cc b/chrome/browser/ash/login/users/avatar/user_image_loader.cc
index 685a637..c8bec3e7 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_loader.cc
+++ b/chrome/browser/ash/login/users/avatar/user_image_loader.cc
@@ -16,14 +16,25 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/task_runner_util.h"
+#include "base/task/thread_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/ash/login/helper.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/ash/image_downloader_impl.h"
 #include "components/user_manager/user_image/user_image.h"
+#include "ipc/ipc_channel.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+#include "services/data_decoder/public/cpp/decode_image.h"
+#include "services/data_decoder/public/mojom/image_decoder.mojom.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"
 #include "skia/ext/image_operations.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/encode/SkWebpEncoder.h"
 #include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/codec/webp_codec.h"
 #include "ui/gfx/skbitmap_operations.h"
 #include "url/gurl.h"
 
@@ -31,6 +42,9 @@
 namespace user_image_loader {
 namespace {
 
+constexpr int64_t kMaxImageSizeInBytes =
+    static_cast<int64_t>(IPC::Channel::kMaximumMessageSize);
+
 // Contains attributes we need to know about each image we decode.
 struct ImageInfo {
   ImageInfo(const base::FilePath& file_path,
@@ -236,11 +250,112 @@
   ImageDecoder::StartWithOptions(image_request, *data, codec, false);
 }
 
-void OnImageDownloaded(LoadedCallback loaded_cb,
-                       const gfx::ImageSkia& image_skia) {
-  std::move(loaded_cb).Run(user_manager::UserImage::CreateAndEncode(
-      image_skia,
-      user_manager::UserImage::ChooseImageFormat(*image_skia.bitmap())));
+void OnAnimationDecoded(
+    LoadedCallback loaded_cb,
+    std::vector<data_decoder::mojom::AnimationFramePtr> mojo_frames) {
+  auto frame_size = mojo_frames.size();
+  if (!frame_size) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(loaded_cb),
+                                  std::make_unique<user_manager::UserImage>()));
+    return;
+  }
+
+  // Re-encode static image as PNG and send to requester.
+  if (frame_size == 1) {
+    base::ThreadPool::PostTaskAndReplyWithResult(
+        FROM_HERE,
+        base::BindOnce(
+            [](const SkBitmap& bitmap) {
+              auto encoded = base::MakeRefCounted<base::RefCountedBytes>();
+              if (!gfx::PNGCodec::EncodeBGRASkBitmap(
+                      bitmap, /*discard_transparency=*/false,
+                      &encoded->data())) {
+                return std::make_unique<user_manager::UserImage>();
+              }
+
+              auto image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+              image_skia.MakeThreadSafe();
+
+              auto user_image = std::make_unique<user_manager::UserImage>(
+                  image_skia, encoded, user_manager::UserImage::FORMAT_PNG);
+              user_image->MarkAsSafe();
+
+              return user_image;
+            },
+            mojo_frames[0]->bitmap),
+        std::move(loaded_cb));
+    return;
+  }
+
+  // The image is animated, re-encode as WebP animated image and send to
+  // requester.
+  std::vector<gfx::WebpCodec::Frame> frames;
+  for (auto& mojo_frame : mojo_frames) {
+    gfx::WebpCodec::Frame frame;
+    frame.bitmap = mojo_frame->bitmap;
+    frame.duration = mojo_frame->duration.InMilliseconds();
+    frames.push_back(frame);
+  }
+
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      base::BindOnce(
+          [](const std::vector<gfx::WebpCodec::Frame>& frames) {
+            SkWebpEncoder::Options options;
+            options.fCompression = SkWebpEncoder::Compression::kLossless;
+            // Lower quality under kLossless compression means compress faster
+            // into larger files.
+            options.fQuality = 0;
+
+            auto encoded = gfx::WebpCodec::EncodeAnimated(frames, options);
+            if (!encoded.has_value()) {
+              return std::make_unique<user_manager::UserImage>();
+            }
+
+            auto image_skia =
+                gfx::ImageSkia::CreateFrom1xBitmap(frames[0].bitmap);
+            image_skia.MakeThreadSafe();
+
+            auto bytes =
+                base::MakeRefCounted<base::RefCountedBytes>(encoded.value());
+
+            auto user_image = std::make_unique<user_manager::UserImage>(
+                image_skia, bytes, user_manager::UserImage::FORMAT_WEBP);
+            user_image->MarkAsSafe();
+
+            return user_image;
+          },
+          std::move(frames)),
+      std::move(loaded_cb));
+}
+
+void DecodeAnimation(LoadedCallback loaded_cb, base::StringPiece data) {
+  if (data.empty()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(loaded_cb),
+                                  std::make_unique<user_manager::UserImage>()));
+    return;
+  }
+
+  base::span<const uint8_t> bytes = base::make_span(
+      reinterpret_cast<const uint8_t*>(data.data()), data.size());
+
+  data_decoder::DecodeAnimationIsolated(
+      bytes, /*shrink_to_fit=*/true, kMaxImageSizeInBytes,
+      base::BindOnce(&OnAnimationDecoded, std::move(loaded_cb)));
+}
+
+void OnImageDownloaded(std::unique_ptr<network::SimpleURLLoader> loader,
+                       LoadedCallback loaded_cb,
+                       std::unique_ptr<std::string> body) {
+  if (loader->NetError() != net::OK || !body) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(loaded_cb),
+                                  std::make_unique<user_manager::UserImage>()));
+    return;
+  }
+  DecodeAnimation(std::move(loaded_cb), *body);
 }
 
 }  // namespace
@@ -272,16 +387,30 @@
               background_task_runner, data.get(), true /* data_is_ready */);
 }
 
+void StartWithDataAnimated(base::StringPiece data, LoadedCallback loaded_cb) {
+  DecodeAnimation(std::move(loaded_cb), data);
+}
+
+void StartWithFilePathAnimated(const base::FilePath& file_path,
+                               LoadedCallback loaded_cb) {
+  base::ThreadTaskRunnerHandle::Get()->PostTaskAndReplyWithResult(
+      FROM_HERE,
+      base::BindOnce(
+          [](const base::FilePath& file_path) {
+            std::string data;
+            if (!base::ReadFileToString(file_path, &data)) {
+              return std::string();
+            }
+            return data;
+          },
+          file_path),
+      base::BindOnce(&DecodeAnimation, std::move(loaded_cb)));
+}
+
 // Used to load user images from GURL, specifically in the case of
 // retrieving images from the cloud.
-void StartWithGURL(const GURL& default_image_url, LoadedCallback loaded_cb) {
-  if (!ash::ImageDownloader::Get()) {
-    LOG(ERROR) << "Could not retrieve image downloader for user image";
-    return;
-  }
-
-  ash::ImageDownloader::DownloadCallback download_callback =
-      base::BindOnce(&OnImageDownloaded, std::move(loaded_cb));
+void StartWithGURLAnimated(const GURL& default_image_url,
+                           LoadedCallback loaded_cb) {
   constexpr net::NetworkTrafficAnnotationTag kNetworkTrafficAnnotationTag =
       net::DefineNetworkTrafficAnnotation("user_image_downloader", R"(
             semantics: {
@@ -303,9 +432,25 @@
               policy_exception_justification: "Not implemented."
             })");
 
-  ash::ImageDownloader::Get()->Download(default_image_url,
-                                        kNetworkTrafficAnnotationTag,
-                                        std::move(download_callback));
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = default_image_url;
+  request->credentials_mode = network::mojom::CredentialsMode::kOmit;
+
+  auto loader = network::SimpleURLLoader::Create(std::move(request),
+                                                 kNetworkTrafficAnnotationTag);
+  loader->SetRetryOptions(
+      /*max_retries=*/5,
+      network::SimpleURLLoader::RetryMode::RETRY_ON_5XX |
+          network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE |
+          network::SimpleURLLoader::RETRY_ON_NAME_NOT_RESOLVED);
+
+  auto* loader_ptr = loader.get();
+  loader_ptr->DownloadToString(
+      g_browser_process->shared_url_loader_factory().get(),
+      base::BindOnce(&OnImageDownloaded, std::move(loader),
+                     std::move(loaded_cb)),
+      network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
 }
+
 }  // namespace user_image_loader
 }  // namespace ash
diff --git a/chrome/browser/ash/login/users/avatar/user_image_loader.h b/chrome/browser/ash/login/users/avatar/user_image_loader.h
index a288e24..9a717f9 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_loader.h
+++ b/chrome/browser/ash/login/users/avatar/user_image_loader.h
@@ -50,10 +50,20 @@
     int pixels_per_side,
     LoadedCallback loaded_cb);
 
-// Loads the default image fetched from `default_image_url` and calls
-// `loaded_cb` with the resulting UserImage (which may be empty in case of
-// error).
-void StartWithGURL(const GURL& default_image_url, LoadedCallback loaded_cb);
+// Loads user image from provided |data| bytes. If the image is animated, encode
+// with WebP encoder, otherwise encode with PNG encoder.
+void StartWithDataAnimated(base::StringPiece data, LoadedCallback loaded_cb);
+
+// Loads user image from |file_path|. If the image is animated, encode with WebP
+// encoder, otherwise encode with PNG encoder.
+// TODO(b/251083485): Add support for external image from file.
+void StartWithFilePathAnimated(const base::FilePath& file_path,
+                               LoadedCallback loaded_cb);
+
+// Loads the default image fetched from |default_image_url|. If the image is
+// animated, encode with WebP encoder, otherwise encode with PNG encoder.
+void StartWithGURLAnimated(const GURL& default_image_url,
+                           LoadedCallback loaded_cb);
 
 }  // namespace user_image_loader
 }  // namespace ash
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
index a503cf2..d45bb8d 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
@@ -104,6 +104,8 @@
       return ".jpg";
     case user_manager::UserImage::FORMAT_PNG:
       return ".png";
+    case user_manager::UserImage::FORMAT_WEBP:
+      return ".webp";
     default:
       NOTREACHED() << "Invalid format: " << image_format;
       return ".jpg";
@@ -288,16 +290,13 @@
           !base::DirectoryExists(image_path_)) {
         // Will refactor to remove this redundant call after the feature flag
         // IsAvatarsCloudMigrationEnabled is no longer needed.
-        user_image_loader::StartWithFilePath(
-            parent_->background_task_runner_, image_path_,
-            ChooseCodecFromPath(image_path_),
-            0,  // Do not crop.
-            base::BindOnce(&Job::OnLoadImageDone, weak_factory_.GetWeakPtr(),
-                           false));
+        user_image_loader::StartWithFilePathAnimated(
+            image_path_, base::BindOnce(&Job::OnLoadImageDone,
+                                        weak_factory_.GetWeakPtr(), false));
       } else {
         // Fetch the default image from cloud before caching it.
         image_url_ = default_user_image::GetDefaultImageUrl(image_index_);
-        user_image_loader::StartWithGURL(
+        user_image_loader::StartWithGURLAnimated(
             image_url_, base::BindOnce(&Job::OnLoadImageDone,
                                        weak_factory_.GetWeakPtr(), true));
       }
@@ -312,6 +311,7 @@
       // images to cloud.
       UpdateUserAndSaveImage(std::move(user_image));
     }
+
   } else if (image_index_ == user_manager::User::USER_IMAGE_EXTERNAL ||
              image_index_ == user_manager::User::USER_IMAGE_PROFILE) {
     // Load the user image from a file referenced by `image_path`. This happens
@@ -341,7 +341,7 @@
   if (ash::features::IsAvatarsCloudMigrationEnabled()) {
     // Fetch the default image from cloud before caching it.
     image_url_ = default_user_image::GetDefaultImageUrl(image_index_);
-    user_image_loader::StartWithGURL(
+    user_image_loader::StartWithGURLAnimated(
         image_url_, base::BindOnce(&Job::OnLoadImageDone,
                                    weak_factory_.GetWeakPtr(), true));
   } else {
diff --git a/chrome/browser/ash/login/wizard_context.h b/chrome/browser/ash/login/wizard_context.h
index 3450459..4e83431 100644
--- a/chrome/browser/ash/login/wizard_context.h
+++ b/chrome/browser/ash/login/wizard_context.h
@@ -97,6 +97,14 @@
   EnrollmentPreference enrollment_preference_ =
       WizardContext::EnrollmentPreference::kEnterprise;
 
+  // Controls if user should be asked about recovery factor setup
+  // on the consolidated consent screen.
+  bool ask_about_recovery_consent = false;
+
+  // User's choice about using recovery factor. Filled by
+  // consolidated consent screen, used by auth_factors_setup screen.
+  bool recovery_factor_opted_in = false;
+
   // Authorization data that is required by PinSetup screen to add PIN as
   // another possible auth factor. Can be empty (if PIN is not supported).
   // In future will be replaced by AuthSession.
diff --git a/chrome/browser/ash/preferences.cc b/chrome/browser/ash/preferences.cc
index 6735707b..a39a9cc 100644
--- a/chrome/browser/ash/preferences.cc
+++ b/chrome/browser/ash/preferences.cc
@@ -397,6 +397,7 @@
       ::prefs::kCaptivePortalAuthenticationIgnoresProxy, true);
 
   registry->RegisterBooleanPref(::prefs::kLanguageImeMenuActivated, false);
+  registry->RegisterBooleanPref(::prefs::kHindiInscriptLayoutEnabled, false);
 
   // TODO(b/227674947): Eventually delete this after Sign in with Smart Lock has
   // been removed and enough time has elapsed for users to be notified.
diff --git a/chrome/browser/ash/remote_apps/remote_apps_impl.cc b/chrome/browser/ash/remote_apps/remote_apps_impl.cc
index 3014a2bb..fdd4803 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_impl.cc
+++ b/chrome/browser/ash/remote_apps/remote_apps_impl.cc
@@ -134,6 +134,12 @@
   }
 }
 
+void RemoteAppsImpl::SortLauncherWithRemoteAppsFirst(
+    SortLauncherWithRemoteAppsFirstCallback callback) {
+  manager_->SortLauncherWithRemoteAppsFirst();
+  std::move(callback).Run(absl::nullopt);
+}
+
 void RemoteAppsImpl::OnAppLaunched(const std::string& source_id,
                                    const std::string& app_id) {
   // Dispatch events to broadcast observers.
diff --git a/chrome/browser/ash/remote_apps/remote_apps_impl.h b/chrome/browser/ash/remote_apps/remote_apps_impl.h
index d1b6331..6de48944 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_impl.h
+++ b/chrome/browser/ash/remote_apps/remote_apps_impl.h
@@ -67,6 +67,8 @@
               AddAppCallback callback) override;
   void DeleteApp(const std::string& app_id,
                  DeleteAppCallback callback) override;
+  void SortLauncherWithRemoteAppsFirst(
+      SortLauncherWithRemoteAppsFirstCallback callback) override;
 
   void OnAppLaunched(const std::string& source_id, const std::string& app_id);
 
diff --git a/chrome/browser/ash/remote_apps/remote_apps_manager.cc b/chrome/browser/ash/remote_apps/remote_apps_manager.cc
index 0459919..a02c1dc 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_manager.cc
+++ b/chrome/browser/ash/remote_apps/remote_apps_manager.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_util.h"
 #include "chrome/browser/ui/app_list/chrome_app_list_item.h"
+#include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h"
 #include "chrome/common/apps/platform_apps/api/enterprise_remote_apps.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/services/app_service/public/cpp/menu.h"
@@ -249,6 +250,11 @@
   return RemoteAppsError::kNone;
 }
 
+void RemoteAppsManager::SortLauncherWithRemoteAppsFirst() {
+  static_cast<ChromeAppListModelUpdater*>(model_updater_)
+      ->RequestAppListSort(AppListSortOrder::kAlphabeticalEphemeralAppFirst);
+}
+
 std::string RemoteAppsManager::AddFolder(const std::string& folder_name,
                                          bool add_to_front) {
   const RemoteAppsModel::FolderInfo& folder_info =
diff --git a/chrome/browser/ash/remote_apps/remote_apps_manager.h b/chrome/browser/ash/remote_apps/remote_apps_manager.h
index c8bfd89..f6d99acd 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_manager.h
+++ b/chrome/browser/ash/remote_apps/remote_apps_manager.h
@@ -124,6 +124,10 @@
   // Deleting a non-existent app will result in an error.
   RemoteAppsError DeleteApp(const std::string& id);
 
+  // Sorts the launcher items with the custom kAlphabeticalEphemeralAppFirst
+  // sort order which moves the remote apps to the front of the launcher.
+  void SortLauncherWithRemoteAppsFirst();
+
   // Adds a folder with |folder_name|. Note that empty folders are not shown in
   // the launcher. Returns the ID for the added folder. If |add_to_front| is
   // true, the folder will be added to the front of the app item list.
diff --git a/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc b/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc
index 2715c758..0906725 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc
+++ b/chrome/browser/ash/remote_apps/remote_apps_manager_browsertest.cc
@@ -16,6 +16,7 @@
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/test/app_list_test_api.h"
 #include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
 #include "base/barrier_closure.h"
 #include "base/callback.h"
 #include "base/callback_forward.h"
@@ -35,6 +36,7 @@
 #include "chrome/browser/ash/remote_apps/id_generator.h"
 #include "chrome/browser/ash/remote_apps/remote_apps_manager_factory.h"
 #include "chrome/browser/ash/remote_apps/remote_apps_model.h"
+#include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
@@ -191,6 +193,9 @@
     user_manager::User* user =
         user_manager::UserManager::Get()->GetActiveUser();
     profile_ = ProfileHelper::Get()->GetProfileByUser(user);
+    app_list_syncable_service_ =
+        app_list::AppListSyncableServiceFactory::GetForProfile(profile_);
+    app_list_model_updater_ = app_list_syncable_service_->GetModelUpdater();
     manager_ = RemoteAppsManagerFactory::GetForProfile(profile_);
     std::unique_ptr<FakeIdGenerator> id_generator =
         std::make_unique<FakeIdGenerator>(
@@ -293,7 +298,42 @@
     EXPECT_TRUE(client->GetAppListWindow());
   }
 
+  std::string LoadExtension(const base::FilePath& extension_path) {
+    extensions::ChromeTestExtensionLoader loader(profile_);
+    loader.set_location(extensions::mojom::ManifestLocation::kExternalPolicy);
+    loader.set_pack_extension(true);
+    // When |set_pack_extension_| is true, the |loader| first packs and then
+    // loads the extension. The packing step creates a _metadata folder which
+    // causes an install warning when loading.
+    loader.set_ignore_manifest_warnings(true);
+    return loader.LoadExtension(extension_path)->id();
+  }
+
+  // Returns a list of app ids following the ordinal increasing order.
+  std::vector<std::string> GetAppIdsInOrdinalOrder(
+      const std::vector<std::string>& ids) {
+    std::vector<std::string> copy_ids(ids);
+    std::sort(
+        copy_ids.begin(), copy_ids.end(),
+        [&](const std::string& id1, const std::string& id2) {
+          return app_list_model_updater_->FindItem(id1)->position().LessThan(
+              app_list_model_updater_->FindItem(id2)->position());
+        });
+    return copy_ids;
+  }
+
+  void OnReorderAnimationDone(base::OnceClosure closure,
+                              bool aborted,
+                              AppListGridAnimationStatus status) {
+    EXPECT_FALSE(aborted);
+    EXPECT_EQ(AppListGridAnimationStatus::kReorderFadeIn, status);
+    std::move(closure).Run();
+  }
+
  protected:
+  app_list::AppListSyncableService* app_list_syncable_service_;
+  AppListModelUpdater* app_list_model_updater_;
+  ash::AppListTestApi app_list_test_api_;
   RemoteAppsManager* manager_ = nullptr;
   MockImageDownloader* image_downloader_ = nullptr;
   Profile* profile_ = nullptr;
@@ -356,17 +396,16 @@
 
   // App's icon is placeholder.
   // TODO(https://crbug.com/1345682): add a pixel diff test for this scenario.
-  ash::AppListTestApi app_list_test_api;
-  CheckIconsEqual(
-      future.Get()->uncompressed,
-      app_list_test_api.GetTopLevelItemViewFromId(kId1)->icon_image_for_test());
+  CheckIconsEqual(future.Get()->uncompressed,
+                  app_list_test_api_.GetTopLevelItemViewFromId(kId1)
+                      ->icon_image_for_test());
   CheckIconsEqual(future.Get()->uncompressed, item->GetDefaultIcon());
 
   // App list color sorting should still work for placeholder icons.
   ui::test::EventGenerator event_generator(ash::Shell::GetPrimaryRootWindow());
   ash::AppListTestApi::ReorderAnimationEndState actual_state;
 
-  app_list_test_api.ReorderByMouseClickAtToplevelAppsGridMenu(
+  app_list_test_api_.ReorderByMouseClickAtToplevelAppsGridMenu(
       ash::AppListSortOrder::kColor,
       ash::AppListTestApi::MenuType::kAppListNonFolderItemMenu,
       &event_generator,
@@ -657,11 +696,9 @@
 // the added remote app items are marked as ephemeral and are not synced to
 // local storage or uploaded to sync data.
 IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest, RemoteAppsNotSynced) {
-  app_list::AppListSyncableService* app_list_syncable_service =
-      app_list::AppListSyncableServiceFactory::GetForProfile(profile_);
   std::unique_ptr<syncer::FakeSyncChangeProcessor> sync_processor =
       std::make_unique<syncer::FakeSyncChangeProcessor>();
-  app_list_syncable_service->MergeDataAndStartSyncing(
+  app_list_syncable_service_->MergeDataAndStartSyncing(
       syncer::APP_LIST, {},
       std::unique_ptr<syncer::SyncChangeProcessor>(
           new syncer::SyncChangeProcessorWrapperForTest(sync_processor.get())),
@@ -695,14 +732,10 @@
 // that the added remote folder items are marked as ephemeral and are not synced
 // to local storage or uploaded to sync data.
 IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest, RemoteFoldersNotSynced) {
-  app_list::AppListSyncableService* app_list_syncable_service =
-      app_list::AppListSyncableServiceFactory::GetForProfile(profile_);
   std::unique_ptr<syncer::FakeSyncChangeProcessor> sync_processor =
       std::make_unique<syncer::FakeSyncChangeProcessor>();
-  AppListModelUpdater* app_list_model_updater =
-      app_list_syncable_service->GetModelUpdater();
-  app_list_model_updater->SetActive(true);
-  app_list_syncable_service->MergeDataAndStartSyncing(
+  app_list_model_updater_->SetActive(true);
+  app_list_syncable_service_->MergeDataAndStartSyncing(
       syncer::APP_LIST, {},
       std::unique_ptr<syncer::SyncChangeProcessor>(
           new syncer::SyncChangeProcessorWrapperForTest(sync_processor.get())),
@@ -734,4 +767,74 @@
     EXPECT_NE(item_id, kId1);
   }
 }
+
+// Tests that the kAlphabeticalEphemeralAppFirst sort order moves the remote
+// apps and folders to the front of the launcher, before all native items.
+IN_PROC_BROWSER_TEST_F(RemoteAppsManagerBrowsertest,
+                       SortLauncherWithRemoteAppsFirst) {
+  // Show launcher UI so that app icons are loaded.
+  ShowLauncherAppsGrid(/*wait_for_opening_animation=*/true);
+
+  base::FilePath test_dir_path;
+  base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir_path);
+  test_dir_path = test_dir_path.AppendASCII("extensions");
+
+  // Adds 2 remote apps.
+  // Make one app name lower case to test case insensitive.
+  std::string remote_app1_id =
+      AddApp(kExtensionId1, "test app 5", std::string(), GURL(),
+             /*add_to_front=*/true);
+  std::string remote_app2_id =
+      AddApp(kExtensionId1, "Test App 7", std::string(), GURL(),
+             /*add_to_front=*/true);
+
+  // Adds remote folder with one remote app inside.
+  std::string remote_folder_id =
+      manager_->AddFolder("Test App 6 Folder", /*add_to_front=*/true);
+  AddApp(kExtensionId1, "Test App 8", remote_folder_id, GURL(),
+         /*add_to_front=*/true);
+
+  // Adds 3 native apps.
+  std::string app1_id =
+      LoadExtension(test_dir_path.AppendASCII("app1"));  // Test App 1
+  ASSERT_FALSE(app1_id.empty());
+  std::string app2_id =
+      LoadExtension(test_dir_path.AppendASCII("app2"));  // Test App 2
+  ASSERT_FALSE(app2_id.empty());
+  std::string app3_id =
+      LoadExtension(test_dir_path.AppendASCII("app4"));  // Test App 4
+  ASSERT_FALSE(app3_id.empty());
+
+  // Moves 2 native apps to a native folder.
+  const std::string native_folder_id =
+      app_list_test_api_.CreateFolderWithApps({app2_id, app3_id});
+  ash::AppListItem* folder_item = GetAppListItem(native_folder_id);
+  auto folder_metadata = folder_item->CloneMetadata();
+  folder_metadata->name = "Test App 2 Folder";
+  folder_item->SetMetadata(std::move(folder_metadata));
+
+  // Current order: `Test App 2 Folder` (native), `Test App 1` (native),
+  // `Test App 6 Folder` (remote), `Test App 7` (remote), `test app 5` (remote).
+  const std::vector<std::string> ids({app1_id, native_folder_id, remote_app1_id,
+                                      remote_app2_id, remote_folder_id});
+  EXPECT_EQ(
+      GetAppIdsInOrdinalOrder(ids),
+      std::vector<std::string>({native_folder_id, app1_id, remote_folder_id,
+                                remote_app2_id, remote_app1_id}));
+
+  base::RunLoop run_loop;
+  app_list_test_api_.AddReorderAnimationCallback(
+      base::BindRepeating(&RemoteAppsManagerBrowsertest::OnReorderAnimationDone,
+                          base::Unretained(this), run_loop.QuitClosure()));
+
+  manager_->SortLauncherWithRemoteAppsFirst();
+  run_loop.Run();
+
+  // Sorted order: `test app 5` (remote), `Test App 6 Folder` (remote),
+  // `Test App 7` (remote), `Test App 1` (native), `Test App 2 Folder` (native).
+  EXPECT_EQ(
+      GetAppIdsInOrdinalOrder(ids),
+      std::vector<std::string>({remote_app1_id, remote_folder_id,
+                                remote_app2_id, app1_id, native_folder_id}));
+}
 }  // namespace ash
diff --git a/chrome/browser/ash/tether/DIR_METADATA b/chrome/browser/ash/tether/DIR_METADATA
index 4cad27d..9af97369 100644
--- a/chrome/browser/ash/tether/DIR_METADATA
+++ b/chrome/browser/ash/tether/DIR_METADATA
@@ -1 +1 @@
-mixins: "//ash/components/tether/COMMON_METADATA"
+mixins: "//chromeos/ash/components/tether/COMMON_METADATA"
diff --git a/chrome/browser/ash/tether/OWNERS b/chrome/browser/ash/tether/OWNERS
index 6473a0b4..4f92e27 100644
--- a/chrome/browser/ash/tether/OWNERS
+++ b/chrome/browser/ash/tether/OWNERS
@@ -1 +1 @@
-file://ash/components/tether/OWNERS
+file://chromeos/ash/components/tether/OWNERS
diff --git a/chrome/browser/ash/tether/tether_service.cc b/chrome/browser/ash/tether/tether_service.cc
index b6209226..4e23ade 100644
--- a/chrome/browser/ash/tether/tether_service.cc
+++ b/chrome/browser/ash/tether/tether_service.cc
@@ -4,10 +4,6 @@
 
 #include "chrome/browser/ash/tether/tether_service.h"
 
-#include "ash/components/tether/gms_core_notifications_state_tracker_impl.h"
-#include "ash/components/tether/tether_component.h"
-#include "ash/components/tether/tether_component_impl.h"
-#include "ash/components/tether/tether_host_fetcher_impl.h"
 #include "ash/services/multidevice_setup/public/cpp/prefs.h"
 #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
@@ -23,6 +19,10 @@
 #include "chromeos/ash/components/network/device_state.h"
 #include "chromeos/ash/components/network/network_connect.h"
 #include "chromeos/ash/components/network/network_type_pattern.h"
+#include "chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.h"
+#include "chromeos/ash/components/tether/tether_component.h"
+#include "chromeos/ash/components/tether/tether_component_impl.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher_impl.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
diff --git a/chrome/browser/ash/tether/tether_service.h b/chrome/browser/ash/tether/tether_service.h
index d5df15e9..a0dbceac 100644
--- a/chrome/browser/ash/tether/tether_service.h
+++ b/chrome/browser/ash/tether/tether_service.h
@@ -7,8 +7,6 @@
 
 #include <memory>
 
-#include "ash/components/tether/tether_component.h"
-#include "ash/components/tether/tether_host_fetcher.h"
 #include "ash/services/device_sync/public/cpp/device_sync_client.h"
 #include "ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h"
 #include "base/gtest_prod_util.h"
@@ -17,6 +15,8 @@
 #include "base/timer/timer.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_handler_observer.h"
+#include "chromeos/ash/components/tether/tether_component.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "device/bluetooth/bluetooth_adapter.h"
diff --git a/chrome/browser/ash/tether/tether_service_unittest.cc b/chrome/browser/ash/tether/tether_service_unittest.cc
index 5f25b8d..a03388f 100644
--- a/chrome/browser/ash/tether/tether_service_unittest.cc
+++ b/chrome/browser/ash/tether/tether_service_unittest.cc
@@ -6,11 +6,6 @@
 
 #include <memory>
 
-#include "ash/components/tether/fake_notification_presenter.h"
-#include "ash/components/tether/fake_tether_component.h"
-#include "ash/components/tether/fake_tether_host_fetcher.h"
-#include "ash/components/tether/tether_component_impl.h"
-#include "ash/components/tether/tether_host_fetcher_impl.h"
 #include "ash/constants/ash_features.h"
 #include "ash/services/device_sync/cryptauth_device_manager.h"
 #include "ash/services/device_sync/cryptauth_enroller.h"
@@ -49,6 +44,11 @@
 #include "chromeos/ash/components/network/network_handler_test_helper.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_type_pattern.h"
+#include "chromeos/ash/components/tether/fake_notification_presenter.h"
+#include "chromeos/ash/components/tether/fake_tether_component.h"
+#include "chromeos/ash/components/tether/fake_tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/tether_component_impl.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher_impl.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/dbus/power_manager/suspend.pb.h"
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl.cc
index 7fd2f2b..0471da7 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl.cc
@@ -24,15 +24,6 @@
 
 namespace ash::personalization_app {
 
-namespace {
-KeyboardBacklightColorController* GetKeyboardBacklightColorController() {
-  auto* keyboard_backlight_color_controller =
-      ash::Shell::Get()->keyboard_backlight_color_controller();
-  DCHECK(keyboard_backlight_color_controller);
-  return keyboard_backlight_color_controller;
-}
-}  // namespace
-
 PersonalizationAppKeyboardBacklightProviderImpl::
     PersonalizationAppKeyboardBacklightProviderImpl(content::WebUI* web_ui)
     : profile_(Profile::FromWebUI(web_ui)) {}
@@ -101,6 +92,23 @@
 }
 
 void PersonalizationAppKeyboardBacklightProviderImpl::
+    SetKeyboardBacklightColorControllerForTesting(
+        KeyboardBacklightColorController* controller) {
+  keyboard_backlight_color_controller_for_testing_ = controller;
+}
+
+KeyboardBacklightColorController*
+PersonalizationAppKeyboardBacklightProviderImpl::
+    GetKeyboardBacklightColorController() {
+  if (keyboard_backlight_color_controller_for_testing_)
+    return keyboard_backlight_color_controller_for_testing_;
+  auto* keyboard_backlight_color_controller =
+      ash::Shell::Get()->keyboard_backlight_color_controller();
+  DCHECK(keyboard_backlight_color_controller);
+  return keyboard_backlight_color_controller;
+}
+
+void PersonalizationAppKeyboardBacklightProviderImpl::
     NotifyBacklightColorChanged() {
   DCHECK(keyboard_backlight_observer_remote_.is_bound());
   keyboard_backlight_observer_remote_->OnBacklightColorChanged(
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl.h b/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl.h
index 05db719..fd047ac 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl.h
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl.h
@@ -7,6 +7,7 @@
 
 #include "ash/public/cpp/wallpaper/wallpaper_controller.h"
 #include "ash/public/cpp/wallpaper/wallpaper_controller_observer.h"
+#include "ash/system/keyboard_brightness/keyboard_backlight_color_controller.h"
 #include "ash/webui/personalization_app/mojom/personalization_app.mojom.h"
 #include "ash/webui/personalization_app/personalization_app_keyboard_backlight_provider.h"
 #include "base/scoped_observation.h"
@@ -52,13 +53,23 @@
   // WallpaperControllerObserver:
   void OnWallpaperColorsChanged() override;
 
+  // Tests can provide the controller in case it is not initialized in
+  // ash::Shell.
+  void SetKeyboardBacklightColorControllerForTesting(
+      KeyboardBacklightColorController* controller);
+
  private:
+  KeyboardBacklightColorController* GetKeyboardBacklightColorController();
+
   // Notify webUI the current state of backlight color.
   void NotifyBacklightColorChanged();
 
   // Pointer to profile of user that opened personalization SWA. Not owned.
   raw_ptr<Profile> const profile_ = nullptr;
 
+  raw_ptr<KeyboardBacklightColorController>
+      keyboard_backlight_color_controller_for_testing_;
+
   mojo::Receiver<mojom::KeyboardBacklightProvider> keyboard_backlight_receiver_{
       this};
 
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl_unittest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl_unittest.cc
index 6100e52..19a837e 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl_unittest.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl_unittest.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/ash/web_applications/personalization_app/personalization_app_keyboard_backlight_provider_impl.h"
 
+#include <memory>
+
 #include "ash/constants/ash_features.h"
+#include "ash/system/keyboard_brightness/keyboard_backlight_color_controller.h"
 #include "ash/webui/personalization_app/mojom/personalization_app.mojom.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
@@ -101,11 +104,17 @@
     keyboard_backlight_provider_ =
         std::make_unique<PersonalizationAppKeyboardBacklightProviderImpl>(
             &web_ui_);
+    keyboard_backlight_color_controller_ =
+        std::make_unique<KeyboardBacklightColorController>();
+    keyboard_backlight_color_controller_->OnRgbKeyboardSupportedChanged(true);
+    keyboard_backlight_provider_->SetKeyboardBacklightColorControllerForTesting(
+        keyboard_backlight_color_controller_.get());
     keyboard_backlight_provider_->BindInterface(
         keyboard_backlight_provider_remote_.BindNewPipeAndPassReceiver());
   }
 
   void TearDown() override {
+    keyboard_backlight_color_controller_.reset();
     keyboard_backlight_provider_.reset();
     ChromeAshTestBase::TearDown();
   }
@@ -148,6 +157,8 @@
   content::TestWebUI web_ui_;
   std::unique_ptr<content::WebContents> web_contents_;
   TestingProfile* profile_;
+  std::unique_ptr<KeyboardBacklightColorController>
+      keyboard_backlight_color_controller_;
   mojo::Remote<ash::personalization_app::mojom::KeyboardBacklightProvider>
       keyboard_backlight_provider_remote_;
   std::unique_ptr<PersonalizationAppKeyboardBacklightProviderImpl>
diff --git a/chrome/browser/ash/web_applications/terminal_source.cc b/chrome/browser/ash/web_applications/terminal_source.cc
index ca881353..7358ab5 100644
--- a/chrome/browser/ash/web_applications/terminal_source.cc
+++ b/chrome/browser/ash/web_applications/terminal_source.cc
@@ -203,14 +203,7 @@
   if (ssh_allowed_) {
     switch (directive) {
       case network::mojom::CSPDirectiveName::ConnectSrc:
-        // TODO(b/247580345): Allow connect to any relay / proxy.
-        // First test this behind flag.
-        if (base::FeatureList::IsEnabled(chromeos::features::kTerminalDev)) {
-          return "connect-src *;";
-        }
-        return "connect-src 'self' "
-               "https://*.corp.google.com:* wss://*.corp.google.com:* "
-               "https://*.r.ext.google.com:* wss://*.r.ext.google.com:*;";
+        return "connect-src *;";
       case network::mojom::CSPDirectiveName::FrameAncestors:
         return "frame-ancestors 'self';";
       case network::mojom::CSPDirectiveName::FrameSrc:
diff --git a/chrome/browser/banners/app_banner_manager_browsertest.cc b/chrome/browser/banners/app_banner_manager_browsertest.cc
index eb54136..f5e6bab 100644
--- a/chrome/browser/banners/app_banner_manager_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_browsertest.cc
@@ -143,7 +143,8 @@
   void UpdateState(AppBannerManager::State state) override {
     AppBannerManager::UpdateState(state);
     if (state == AppBannerManager::State::PENDING_ENGAGEMENT ||
-        state == AppBannerManager::State::PENDING_PROMPT) {
+        state == AppBannerManager::State::PENDING_PROMPT_CANCELED ||
+        state == AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED) {
       if (on_done_)
         base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                       std::move(on_done_));
@@ -263,7 +264,8 @@
     // Generally the manager will be in the complete state, however some test
     // cases navigate the page, causing the state to go back to INACTIVE.
     EXPECT_TRUE(manager->state() == State::COMPLETE ||
-                manager->state() == State::PENDING_PROMPT ||
+                manager->state() == State::PENDING_PROMPT_CANCELED ||
+                manager->state() == State::PENDING_PROMPT_NOT_CANCELED ||
                 manager->state() == State::PENDING_WORKER ||
                 manager->state() == State::INACTIVE);
 
@@ -360,7 +362,8 @@
                           browser()->tab_strip_model()->GetActiveWebContents(),
                           "addManifestLinkTag()"));
                     }),
-                    false, AppBannerManager::State::PENDING_PROMPT);
+                    false,
+                    AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED);
   histograms.ExpectTotalCount(kInstallableStatusCodeHistogram, 0);
 }
 
@@ -372,7 +375,8 @@
       browser(), manager.get(),
       embedded_test_server()->GetURL("/banners/manifest_test_page.html"),
       absl::nullopt);
-  EXPECT_EQ(manager->state(), AppBannerManager::State::PENDING_PROMPT);
+  EXPECT_EQ(manager->state(),
+            AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED);
 
   // Dynamically remove the manifest.
   base::HistogramTester histograms;
@@ -398,7 +402,8 @@
       browser(), manager.get(),
       embedded_test_server()->GetURL("/banners/manifest_test_page.html"),
       absl::nullopt);
-  EXPECT_EQ(manager->state(), AppBannerManager::State::PENDING_PROMPT);
+  EXPECT_EQ(manager->state(),
+            AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED);
 
   // Dynamically change the manifest, which results in a
   // Stop(RENDERER_CANCELLED), and a restart of the pipeline.
@@ -419,14 +424,16 @@
   }
   // The pipeline should either have completed, or it is scheduled in the
   // background. Wait for the next prompt request if so.
-  if (manager->state() != AppBannerManager::State::PENDING_PROMPT) {
+  if (manager->state() !=
+      AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED) {
     base::HistogramTester histograms;
     base::RunLoop run_loop;
     manager->PrepareDone(run_loop.QuitClosure());
     run_loop.Run();
     histograms.ExpectTotalCount(kInstallableStatusCodeHistogram, 0);
   }
-  EXPECT_EQ(manager->state(), AppBannerManager::State::PENDING_PROMPT);
+  EXPECT_EQ(manager->state(),
+            AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED);
 }
 
 IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, NoManifest) {
@@ -500,7 +507,7 @@
   // Navigate and expect the manager to end up waiting for prompt to be called.
   TriggerBannerFlowWithNavigation(browser(), manager.get(), test_url,
                                   false /* expected_will_show */,
-                                  State::PENDING_PROMPT);
+                                  State::PENDING_PROMPT_NOT_CANCELED);
 
   // Navigate and expect Stop() to be called.
   TriggerBannerFlowWithNavigation(browser(), manager.get(), GURL("about:blank"),
@@ -528,7 +535,7 @@
   // called.
   TriggerBannerFlowWithNavigation(browser(), manager.get(), test_url,
                                   false /* expected_will_show */,
-                                  State::PENDING_PROMPT);
+                                  State::PENDING_PROMPT_CANCELED);
 
   // Navigate to about:blank and expect Stop() to be called.
   TriggerBannerFlowWithNavigation(browser(), manager.get(), GURL("about:blank"),
@@ -554,7 +561,7 @@
   // Navigate to page and get the pipeline started.
   TriggerBannerFlowWithNavigation(browser(), manager.get(), test_url,
                                   false /* expected_will_show */,
-                                  State::PENDING_PROMPT);
+                                  State::PENDING_PROMPT_NOT_CANCELED);
 
   // Now let the page call prompt with a gesture. The banner should be shown.
   TriggerBannerFlow(
@@ -594,7 +601,7 @@
                      base::Unretained(service),
                      browser()->tab_strip_model()->GetActiveWebContents(),
                      ui::PageTransition::PAGE_TRANSITION_TYPED),
-      false /* expected_will_show */, State::PENDING_PROMPT);
+      false /* expected_will_show */, State::PENDING_PROMPT_NOT_CANCELED);
 
   // Trigger prompt() and expect the banner to be shown.
   TriggerBannerFlow(
@@ -621,7 +628,7 @@
   // Navigate to page and get the pipeline started.
   TriggerBannerFlowWithNavigation(browser(), manager.get(), test_url,
                                   false /* expected_will_show */,
-                                  State::PENDING_PROMPT);
+                                  State::PENDING_PROMPT_NOT_CANCELED);
 
   // Call prompt to show the banner.
   TriggerBannerFlow(
@@ -708,7 +715,7 @@
   // called.
   TriggerBannerFlowWithNavigation(browser(), manager.get(), test_url,
                                   false /* expected_will_show */,
-                                  State::PENDING_PROMPT);
+                                  State::PENDING_PROMPT_NOT_CANCELED);
 
   // Navigate to about:blank and expect it to be terminated because the previous
   // URL is still pending.
@@ -762,8 +769,7 @@
   }
 
   void SetupFeaturesAndParameters() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
 
     for (const auto& [feature, params] : enabled_features_with_params_) {
       enabled_features.emplace_back(*feature, params);
@@ -823,9 +829,10 @@
   // Triggering flow to first URL with a pending prompt.
   TriggerBannerFlowWithNavigation(browser(), manager.get(), GetBannerURL(),
                                   /*expected_will_show=*/false,
-                                  State::PENDING_PROMPT);
+                                  State::PENDING_PROMPT_NOT_CANCELED);
   content::RenderFrameHostWrapper rfh_a(current_frame_host());
-  EXPECT_EQ(manager->state(), AppBannerManager::State::PENDING_PROMPT);
+  EXPECT_EQ(manager->state(),
+            AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED);
   histograms.ExpectTotalCount(kInstallableStatusCodeHistogram, 0);
 
   // Navigating to 2nd installable URL while PENDING_PROMPT will trigger
@@ -939,7 +946,8 @@
   // still successfully get to the PENDING_PROMPT state of the pipeline, as it
   // should retry the call to GetData on the InstallableManager.
   RunBannerTest(browser(), manager.get(), test_url, MANIFEST_URL_CHANGED);
-  EXPECT_EQ(manager->state(), AppBannerManager::State::PENDING_PROMPT);
+  EXPECT_EQ(manager->state(),
+            AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED);
 
   {
     base::HistogramTester histograms;
@@ -1121,7 +1129,8 @@
       browser(), manager.get(),
       embedded_test_server()->GetURL("/banners/manifest_test_page.html"),
       absl::nullopt);
-  EXPECT_EQ(manager->state(), AppBannerManager::State::PENDING_PROMPT);
+  EXPECT_EQ(manager->state(),
+            AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED);
   EXPECT_EQ(manager->GetInstallableWebAppCheckResultForTesting(),
             AppBannerManager::InstallableWebAppCheckResult::kYes_Promotable);
 }
@@ -1213,7 +1222,6 @@
         manager->GetInstallableWebAppCheckResultForTesting(),
         AppBannerManager::InstallableWebAppCheckResult::kYes_ByUserRequest);
   }
-  EXPECT_EQ(manager->GetAppName(), u"Manifest test app");
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
index 9d994c6..8852908 100644
--- a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
@@ -99,7 +99,7 @@
     ASSERT_TRUE(ui_test_utils::NavigateToURL(
         browser(), GetBannerURLWithAction("stash_event")));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   {
@@ -134,7 +134,7 @@
     ASSERT_TRUE(ui_test_utils::NavigateToURL(
         browser(), GetBannerURLWithAction("verify_appinstalled_stash_event")));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   {
@@ -187,7 +187,7 @@
     ASSERT_TRUE(ui_test_utils::NavigateToURL(
         browser(), GetBannerURLWithAction("stash_event")));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   {
@@ -232,7 +232,7 @@
         browser(), GetBannerURLWithManifestAndQuery("/banners/minimal-ui.json",
                                                     "action", "stash_event")));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   // Install the app via the menu instead of the banner.
@@ -263,7 +263,7 @@
         browser(), GetBannerURLWithManifestAndQuery("/banners/fullscreen.json",
                                                     "action", "stash_event")));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   // Install the app via the menu instead of the banner.
@@ -299,7 +299,7 @@
 
     ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetBannerURL()));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   EXPECT_EQ(AppBannerManager::InstallableWebAppCheckResult::kYes_Promotable,
@@ -343,7 +343,7 @@
 
     ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetBannerURL()));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   EXPECT_EQ(AppBannerManager::InstallableWebAppCheckResult::kYes_Promotable,
@@ -368,7 +368,7 @@
                        "/banners/manifest_display_override.json", "action",
                        "stash_event")));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   // Install the app via the menu instead of the banner.
@@ -400,7 +400,7 @@
             "/banners/manifest_display_override_display_is_browser.json",
             "action", "stash_event")));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   {
@@ -442,7 +442,7 @@
 
     ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetBannerURL()));
     run_loop.Run();
-    EXPECT_EQ(State::PENDING_PROMPT, manager->state());
+    EXPECT_EQ(State::PENDING_PROMPT_NOT_CANCELED, manager->state());
   }
 
   EXPECT_EQ(AppBannerManager::InstallableWebAppCheckResult::kYes_Promotable,
diff --git a/chrome/browser/banners/test_app_banner_manager_desktop.cc b/chrome/browser/banners/test_app_banner_manager_desktop.cc
index 607c9b2..f6bca445 100644
--- a/chrome/browser/banners/test_app_banner_manager_desktop.cc
+++ b/chrome/browser/banners/test_app_banner_manager_desktop.cc
@@ -151,7 +151,8 @@
   AppBannerManager::UpdateState(state);
 
   if (state == AppBannerManager::State::PENDING_ENGAGEMENT ||
-      state == AppBannerManager::State::PENDING_PROMPT ||
+      state == AppBannerManager::State::PENDING_PROMPT_CANCELED ||
+      state == AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED ||
       state == AppBannerManager::State::COMPLETE) {
     OnFinished();
   }
diff --git a/chrome/browser/cart/cart_handler_unittest.cc b/chrome/browser/cart/cart_handler_unittest.cc
index fd27f90..bab56ad 100644
--- a/chrome/browser/cart/cart_handler_unittest.cc
+++ b/chrome/browser/cart/cart_handler_unittest.cc
@@ -691,8 +691,7 @@
 class CartHandlerNtpModuleDiscountConsentV2Test : public CartHandlerTest {
  public:
   CartHandlerNtpModuleDiscountConsentV2Test() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     base::FieldTrialParams consent_v2_params, cart_params;
     cart_params["NtpChromeCartModuleAbandonedCartDiscountParam"] = "true";
     cart_params["partner-merchant-pattern"] = "(foo.com)";
diff --git a/chrome/browser/cart/cart_service_unittest.cc b/chrome/browser/cart/cart_service_unittest.cc
index cc64a0b..9bfaf56 100644
--- a/chrome/browser/cart/cart_service_unittest.cc
+++ b/chrome/browser/cart/cart_service_unittest.cc
@@ -1397,8 +1397,7 @@
   // Features need to be initialized before CartServiceTest::SetUp runs, in
   // order to avoid tsan data race error on FeatureList.
   CartServiceDiscountTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     base::FieldTrialParams cart_params, coupon_params;
     cart_params[ntp_features::kNtpChromeCartModuleAbandonedCartDiscountParam] =
         "true";
@@ -1875,8 +1874,7 @@
   // Features need to be initialized before CartServiceTest::SetUp runs, in
   // order to avoid tsan data race error on FeatureList.
   CartServiceMerchantWideDiscountTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     base::FieldTrialParams cart_params, merchant_wide_params;
     cart_params[ntp_features::kNtpChromeCartModuleAbandonedCartDiscountParam] =
         "true";
@@ -2338,8 +2336,7 @@
   // Features need to be initialized before CartServiceTest::SetUp runs, in
   // order to avoid tsan data race error on FeatureList.
   CartServiceDiscountConsentV2Test() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     base::FieldTrialParams consent_v2_params, cart_params;
     cart_params[ntp_features::kNtpChromeCartModuleAbandonedCartDiscountParam] =
         "true";
diff --git a/chrome/browser/cart/fetch_discount_worker_browsertest.cc b/chrome/browser/cart/fetch_discount_worker_browsertest.cc
index f27995e..02fdb509 100644
--- a/chrome/browser/cart/fetch_discount_worker_browsertest.cc
+++ b/chrome/browser/cart/fetch_discount_worker_browsertest.cc
@@ -215,8 +215,7 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
 
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     base::FieldTrialParams cart_params, coupon_params;
     cart_params[ntp_features::kNtpChromeCartModuleAbandonedCartDiscountParam] =
         "true";
@@ -373,8 +372,7 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
 
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     base::FieldTrialParams cart_params, coupon_params;
     cart_params[ntp_features::kNtpChromeCartModuleAbandonedCartDiscountParam] =
         "true";
diff --git a/chrome/browser/cart/fetch_discount_worker_unittest.cc b/chrome/browser/cart/fetch_discount_worker_unittest.cc
index 4c03a82..bf55caa6 100644
--- a/chrome/browser/cart/fetch_discount_worker_unittest.cc
+++ b/chrome/browser/cart/fetch_discount_worker_unittest.cc
@@ -455,8 +455,7 @@
 class FetchDiscountWorkerTest : public FetchDiscountWorkerTestBase {
  public:
   FetchDiscountWorkerTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     base::FieldTrialParams cart_params, coupon_params;
     cart_params["NtpChromeCartModuleAbandonedCartDiscountParam"] = "true";
     cart_params["discount-fetch-delay"] = "6h";
@@ -734,8 +733,7 @@
   // Features need to be initialized before #SetUp runs, in
   // order to avoid tsan data race error on FeatureList.
   FetchMerchantWideDiscountWorkerTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     base::FieldTrialParams merchant_wide_params;
     merchant_wide_params[commerce::kReadyToFetchMerchantWidePromotionParam] =
         "true";
@@ -808,8 +806,7 @@
   // Features need to be initialized before #SetUp runs, in
   // order to avoid tsan data race error on FeatureList.
   FetchMerchantWideDiscountWorkerDisableFetchTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     base::FieldTrialParams merchant_wide_params;
     merchant_wide_params[commerce::kReadyToFetchMerchantWidePromotionParam] =
         "false";
diff --git a/chrome/browser/chrome_back_forward_cache_browsertest.cc b/chrome/browser/chrome_back_forward_cache_browsertest.cc
index 0ab7c86..3cd6ae6 100644
--- a/chrome/browser/chrome_back_forward_cache_browsertest.cc
+++ b/chrome/browser/chrome_back_forward_cache_browsertest.cc
@@ -106,8 +106,7 @@
   }
 
   void SetupFeaturesAndParameters() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
 
     for (const auto& [feature, params] : features_with_params_) {
       enabled_features.emplace_back(*feature, params);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 6ee1cb7..3038bbd2 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -6035,24 +6035,6 @@
                                  chrome::kChromeUIHelpHost);
   }
 
-  if (base::FeatureList::IsEnabled(
-          features::kConsolidatedSiteStorageControls)) {
-    // Replace deprecated Site Data page URL with the All Sites page, which
-    // contains storage controls for sites.
-    if (url->SchemeIs(content::kChromeUIScheme) &&
-        url->host() == chrome::kChromeUISettingsHost) {
-      if (url->path() == chrome::kChromeUISiteDataDeprecatedPath) {
-        *url = ReplaceURLHostAndPath(*url, chrome::kChromeUISettingsHost,
-                                     chrome::kChromeUIAllSitesPath);
-        UMA_HISTOGRAM_BOOLEAN("Settings.AllSites.DeprecatedRedirect", true);
-      } else if (url->path() == chrome::kChromeUIAllSitesPath) {
-        // Log un-redirected navigations to the page as well to provide context
-        // for the raw number of redirects.
-        UMA_HISTOGRAM_BOOLEAN("Settings.AllSites.DeprecatedRedirect", false);
-      }
-    }
-  }
-
 #if BUILDFLAG(IS_WIN)
   // TODO(crbug.com/1003960): Remove when issue is resolved.
   if (url->SchemeIs(content::kChromeUIScheme) &&
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 3f162e6..bf2b8f5 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -17,7 +17,6 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/gtest_util.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "build/build_config.h"
@@ -504,33 +503,6 @@
                                                              &profile_));
 }
 
-TEST_F(ChromeContentBrowserClientTest, RedirectSiteDataURL) {
-  base::test::ScopedFeatureList feature_list(
-      features::kConsolidatedSiteStorageControls);
-
-  TestChromeContentBrowserClient test_content_browser_client;
-  base::HistogramTester histogram_tester;
-  const std::string histogram_name = "Settings.AllSites.DeprecatedRedirect";
-
-  GURL settings_url = GURL(chrome::kChromeUISettingsURL);
-  settings_url = net::AppendQueryParameter(settings_url, "foo", "bar");
-
-  GURL::Replacements replacements;
-  replacements.SetPathStr(chrome::kChromeUISiteDataDeprecatedPath);
-  GURL site_data_url = settings_url.ReplaceComponents(replacements);
-
-  replacements.SetPathStr(chrome::kChromeUIAllSitesPath);
-  GURL all_sites_url = settings_url.ReplaceComponents(replacements);
-
-  test_content_browser_client.HandleWebUI(&site_data_url, &profile_);
-  EXPECT_EQ(all_sites_url, site_data_url);
-  histogram_tester.ExpectUniqueSample(histogram_name, true, 1);
-
-  test_content_browser_client.HandleWebUI(&all_sites_url, &profile_);
-  histogram_tester.ExpectBucketCount(histogram_name, false, 1);
-  histogram_tester.ExpectTotalCount(histogram_name, 2);
-}
-
 #if BUILDFLAG(IS_CHROMEOS)
 class ChromeContentSettingsRedirectTest
     : public ChromeContentBrowserClientTest {
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index e592310b..62d74fb 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -2606,11 +2606,10 @@
   SiteIsolationForCOOPBrowserTest()
       : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
     // Enable COOP isolation with a max of 3 stored sites.
-    const std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        kEnabledFeatures = {
-            {::features::kSiteIsolationForCrossOriginOpenerPolicy,
-             {{"stored_sites_max_size", base::NumberToString(3)},
-              {"should_persist_across_restarts", "true"}}}};
+    const std::vector<base::test::FeatureRefAndParams> kEnabledFeatures = {
+        {::features::kSiteIsolationForCrossOriginOpenerPolicy,
+         {{"stored_sites_max_size", base::NumberToString(3)},
+          {"should_persist_across_restarts", "true"}}}};
     // Disable full site isolation so we can observe effects of COOP isolation.
     const std::vector<base::test::FeatureRef> kDisabledFeatures = {
         features::kSitePerProcess};
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 73d5606..00928c6 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -81,7 +81,6 @@
     "//ash/components/peripheral_notification",
     "//ash/components/phonehub",
     "//ash/components/phonehub/proto",
-    "//ash/components/tether",
     "//ash/constants",
     "//ash/keyboard/ui",
     "//ash/public/cpp",
@@ -319,6 +318,7 @@
     "//chromeos/ash/components/smbfs/mojom",
     "//chromeos/ash/components/string_matching",
     "//chromeos/ash/components/sync_wifi",
+    "//chromeos/ash/components/tether",
     "//chromeos/ash/components/timezone",
     "//chromeos/ash/components/tpm",
     "//chromeos/ash/components/tpm:buildflags",
@@ -2038,7 +2038,6 @@
     "//ash/components/arc:arc_test_support",
     "//ash/components/arc:notification_test_support",
     "//ash/components/phonehub:test_support",
-    "//ash/components/tether:test_support",
     "//ash/constants",
     "//ash/public/cpp",
     "//ash/public/cpp:test_support",
@@ -2111,6 +2110,7 @@
     "//chromeos/ash/components/scanning",
     "//chromeos/ash/components/settings",
     "//chromeos/ash/components/sync_wifi:test_support",
+    "//chromeos/ash/components/tether:test_support",
     "//chromeos/ash/components/tpm",
     "//chromeos/ash/services/nearby/public/cpp:test_support",
     "//chromeos/ash/services/nearby/public/mojom",
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
index c23720f..fa94453 100644
--- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
@@ -394,6 +394,13 @@
       << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(FileSystemProviderServiceWorkerApiTest, GetMetadata) {
+  ASSERT_TRUE(RunExtensionTest(
+      "file_system_provider/service_worker/get_metadata",
+      {.extension_url = "test.html"}, {.load_as_component = true}))
+      << message_;
+}
+
 IN_PROC_BROWSER_TEST_F(FileSystemProviderServiceWorkerApiTest, MoveEntry) {
   ASSERT_TRUE(RunExtensionTest("file_system_provider/service_worker/move_entry",
                                {.extension_url = "test.html"},
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate.cc b/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate.cc
index e6423520..bd594e7 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate.cc
@@ -14,6 +14,28 @@
 #include "storage/browser/file_system/file_system_url.h"
 
 namespace policy {
+namespace {
+
+void CopySourceInformation(storage::FileSystemURL source,
+                           storage::FileSystemURL destination) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  DlpRulesManager* rules_manager;
+  rules_manager = DlpRulesManagerFactory::GetForPrimaryProfile();
+  if (!rules_manager) {
+    return;
+  }
+  DlpFilesController* controller = rules_manager->GetDlpFilesController();
+  if (!controller) {
+    return;
+  }
+  controller->CopySourceInformation(source, destination);
+#else
+  NOTREACHED();
+#endif
+}
+
+}  // namespace
 
 DlpCopyOrMoveHookDelegate::DlpCopyOrMoveHookDelegate(bool isComposite)
     : CopyOrMoveHookDelegate(isComposite) {}
@@ -39,31 +61,7 @@
     const storage::FileSystemURL& destination_url) {
   content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE,
-      base::BindOnce(&DlpCopyOrMoveHookDelegate::CopySourceInformation,
-                     base::Unretained(this), source_url, destination_url));
-}
-
-void DlpCopyOrMoveHookDelegate::CopySourceInformation(
-    storage::FileSystemURL source,
-    storage::FileSystemURL destination) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  DlpRulesManager* rules_manager = GetRulesManager();
-  if (!rules_manager) {
-    return;
-  }
-  DlpFilesController* controller = rules_manager->GetDlpFilesController();
-  if (!controller) {
-    return;
-  }
-  controller->CopySourceInformation(source, destination);
-#else
-  NOTREACHED();
-#endif
-}
-
-DlpRulesManager* DlpCopyOrMoveHookDelegate::GetRulesManager() {
-  return DlpRulesManagerFactory::GetForPrimaryProfile();
+      base::BindOnce(&CopySourceInformation, source_url, destination_url));
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate.h b/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate.h
index 989b0c7..a3139f5 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_COPY_OR_MOVE_HOOK_DELEGATE_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_COPY_OR_MOVE_HOOK_DELEGATE_H_
 
-#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
 #include "storage/browser/file_system/copy_or_move_hook_delegate.h"
 #include "storage/browser/file_system/file_system_url.h"
 
@@ -28,11 +27,6 @@
  private:
   void OnSuccess(const storage::FileSystemURL& source_url,
                  const storage::FileSystemURL& destination_url);
-
-  void CopySourceInformation(storage::FileSystemURL source,
-                             storage::FileSystemURL destination);
-
-  virtual DlpRulesManager* GetRulesManager();
 };
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate_unittest.cc b/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate_unittest.cc
index cc6ca92..1d9b541 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate_unittest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate_unittest.cc
@@ -4,21 +4,39 @@
 
 #include "chrome/browser/chromeos/policy/dlp/dlp_copy_or_move_hook_delegate.h"
 
+#include <memory>
+
 #include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/test/bind.h"
 #include "base/test/task_environment.h"
-#include "chrome/browser/ash/policy/dlp/dlp_files_controller.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
+#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h"
 #include "chrome/browser/chromeos/policy/dlp/mock_dlp_rules_manager.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/user_manager/scoped_user_manager.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_task_environment.h"
+#include "storage/browser/file_system/file_system_url.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 
+#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
+#include "chrome/browser/ash/policy/dlp/dlp_files_controller.h"
+
 namespace policy {
+namespace {
+
+constexpr char kEmailId[] = "test@example.com";
+constexpr char kGaiaId[] = "12345";
+
+}  // namespace
 
 class MockController : public DlpFilesController {
  public:
@@ -31,76 +49,143 @@
               (override));
 };
 
-class MockHook : public DlpCopyOrMoveHookDelegate {
- public:
-  explicit MockHook(DlpRulesManager* manager) : manager_(manager) {}
-  DlpRulesManager* GetRulesManager() override { return manager_; }
-  DlpRulesManager* manager_;
-};
-
 class DlpCopyOrMoveHookDelegateTest : public testing::Test {
+ public:
+  void SetUp() override {
+    scoped_manager = std::make_unique<MockDlpRulesManager>();
+    manager_ = scoped_manager.get();
+  }
+
  protected:
   content::BrowserTaskEnvironment task_environment_{
       content::BrowserTaskEnvironment::ThreadPoolExecutionMode::QUEUED};
-  MockDlpRulesManager manager_;
-  MockController controller_{manager_};
-  MockHook hook_{&manager_};
+  MockDlpRulesManager* manager_;
+  std::unique_ptr<DlpCopyOrMoveHookDelegate> hook_{
+      std::make_unique<DlpCopyOrMoveHookDelegate>()};
   const storage::FileSystemURL source =
       storage::FileSystemURL::CreateForTest(GURL("source"));
   const storage::FileSystemURL destination =
       storage::FileSystemURL::CreateForTest(GURL("destination"));
+  std::unique_ptr<MockDlpRulesManager> scoped_manager;
 };
 
-TEST_F(DlpCopyOrMoveHookDelegateTest, OnEndCopy) {
-  EXPECT_CALL(manager_, GetDlpFilesController)
-      .WillOnce(testing::Return(&controller_));
-  EXPECT_CALL(controller_, CopySourceInformation)
-      .WillOnce([this](const storage::FileSystemURL src,
-                       const storage::FileSystemURL dest) {
-        EXPECT_EQ(source, src);
-        EXPECT_EQ(destination, dest);
-      });
-  auto task_runner = content::GetIOThreadTaskRunner({});
-  task_runner->PostTask(
-      FROM_HERE, base::BindOnce(&DlpCopyOrMoveHookDelegate::OnEndCopy,
-                                base::Unretained(&hook_), source, destination));
-  task_environment_.RunUntilIdle();
-}
-
-TEST_F(DlpCopyOrMoveHookDelegateTest, OnEndMove) {
-  EXPECT_CALL(manager_, GetDlpFilesController)
-      .WillOnce(testing::Return(&controller_));
-  EXPECT_CALL(controller_, CopySourceInformation)
-      .WillOnce([this](const storage::FileSystemURL src,
-                       const storage::FileSystemURL dest) {
-        EXPECT_EQ(source, src);
-        EXPECT_EQ(destination, dest);
-      });
-  auto task_runner = content::GetIOThreadTaskRunner({});
-  task_runner->PostTask(
-      FROM_HERE, base::BindOnce(&DlpCopyOrMoveHookDelegate::OnEndMove,
-                                base::Unretained(&hook_), source, destination));
-  task_environment_.RunUntilIdle();
-}
-
 TEST_F(DlpCopyOrMoveHookDelegateTest, OnEndCopyNoManager) {
-  hook_.manager_ = nullptr;
-  EXPECT_CALL(manager_, GetDlpFilesController).Times(0);
+  EXPECT_CALL(*manager_, GetDlpFilesController).Times(0);
   auto task_runner = content::GetIOThreadTaskRunner({});
   task_runner->PostTask(
-      FROM_HERE, base::BindOnce(&DlpCopyOrMoveHookDelegate::OnEndCopy,
-                                base::Unretained(&hook_), source, destination));
+      FROM_HERE,
+      base::BindOnce(&DlpCopyOrMoveHookDelegate::OnEndCopy,
+                     base::Unretained(hook_.get()), source, destination));
   task_environment_.RunUntilIdle();
 }
 
-TEST_F(DlpCopyOrMoveHookDelegateTest, OnEndCopyNoController) {
-  EXPECT_CALL(manager_, GetDlpFilesController)
-      .WillOnce(testing::Return(nullptr));
-  EXPECT_CALL(controller_, CopySourceInformation).Times(0);
+class DlpCopyOrMoveHookDelegateTestWithProfile
+    : public DlpCopyOrMoveHookDelegateTest {
+ public:
+  void SetUp() override {
+    profile_ = std::make_unique<TestingProfile>();
+    AccountId account_id = AccountId::FromUserEmailGaiaId(kEmailId, kGaiaId);
+    profile_->SetIsNewProfile(true);
+    user_manager::User* user =
+        user_manager_->AddUserWithAffiliationAndTypeAndProfile(
+            account_id, /*is_affiliated=*/false,
+            user_manager::USER_TYPE_REGULAR, profile_.get());
+    user_manager_->UserLoggedIn(account_id, user->username_hash(),
+                                /*browser_restart=*/false,
+                                /*is_child=*/false);
+    user_manager_->SimulateUserProfileLoad(account_id);
+
+    policy::DlpRulesManagerFactory::GetInstance()->SetTestingFactory(
+        profile_.get(),
+        base::BindRepeating(
+            &DlpCopyOrMoveHookDelegateTestWithProfile::SetDlpRulesManager,
+            base::Unretained(this)));
+    ASSERT_TRUE(policy::DlpRulesManagerFactory::GetForPrimaryProfile());
+  }
+
+  std::unique_ptr<KeyedService> SetDlpRulesManager(
+      content::BrowserContext* context) {
+    auto dlp_rules_manager = std::make_unique<MockDlpRulesManager>();
+    manager_ = dlp_rules_manager.get();
+    controller_ = std::make_unique<MockController>(*dlp_rules_manager);
+    return dlp_rules_manager;
+  }
+
+ protected:
+  std::unique_ptr<TestingProfile> profile_;
+  ash::FakeChromeUserManager* user_manager_{new ash::FakeChromeUserManager()};
+  std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_{
+      std::make_unique<user_manager::ScopedUserManager>(
+          base::WrapUnique(user_manager_))};
+  std::unique_ptr<MockController> controller_;
+  MockDlpRulesManager* manager_;
+};
+
+TEST_F(DlpCopyOrMoveHookDelegateTestWithProfile, OnEndCopy) {
+  EXPECT_CALL(*manager_, GetDlpFilesController)
+      .WillOnce(testing::Return(controller_.get()));
+  EXPECT_CALL(*controller_, CopySourceInformation)
+      .WillOnce([this](const storage::FileSystemURL src,
+                       const storage::FileSystemURL dest) {
+        EXPECT_EQ(source, src);
+        EXPECT_EQ(destination, dest);
+      });
   auto task_runner = content::GetIOThreadTaskRunner({});
   task_runner->PostTask(
-      FROM_HERE, base::BindOnce(&DlpCopyOrMoveHookDelegate::OnEndCopy,
-                                base::Unretained(&hook_), source, destination));
+      FROM_HERE,
+      base::BindOnce(&DlpCopyOrMoveHookDelegate::OnEndCopy,
+                     base::Unretained(hook_.get()), source, destination));
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(DlpCopyOrMoveHookDelegateTestWithProfile, OnEndCopyDelete) {
+  EXPECT_CALL(*manager_, GetDlpFilesController)
+      .WillOnce(testing::Return(controller_.get()));
+  EXPECT_CALL(*controller_, CopySourceInformation)
+      .WillOnce([this](const storage::FileSystemURL src,
+                       const storage::FileSystemURL dest) {
+        EXPECT_EQ(source, src);
+        EXPECT_EQ(destination, dest);
+      });
+  auto task_runner = content::GetIOThreadTaskRunner({});
+  task_runner->PostTask(FROM_HERE,
+                        base::BindOnce(
+                            [](std::unique_ptr<DlpCopyOrMoveHookDelegate> hook,
+                               const storage::FileSystemURL& source,
+                               const storage::FileSystemURL& destination) {
+                              hook->OnEndCopy(source, destination);
+                              hook.reset();
+                            },
+                            std::move(hook_), source, destination));
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(DlpCopyOrMoveHookDelegateTestWithProfile, OnEndMove) {
+  EXPECT_CALL(*manager_, GetDlpFilesController)
+      .WillOnce(testing::Return(controller_.get()));
+  EXPECT_CALL(*controller_, CopySourceInformation)
+      .WillOnce([this](const storage::FileSystemURL src,
+                       const storage::FileSystemURL dest) {
+        EXPECT_EQ(source, src);
+        EXPECT_EQ(destination, dest);
+      });
+  auto task_runner = content::GetIOThreadTaskRunner({});
+  task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&DlpCopyOrMoveHookDelegate::OnEndMove,
+                     base::Unretained(hook_.get()), source, destination));
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(DlpCopyOrMoveHookDelegateTestWithProfile, OnEndCopyNoController) {
+  EXPECT_CALL(*manager_, GetDlpFilesController)
+      .WillOnce(testing::Return(nullptr));
+  EXPECT_CALL(*controller_, CopySourceInformation).Times(0);
+  auto task_runner = content::GetIOThreadTaskRunner({});
+  task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&DlpCopyOrMoveHookDelegate::OnEndCopy,
+                     base::Unretained(hook_.get()), source, destination));
   task_environment_.RunUntilIdle();
 }
 
diff --git a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonController.java b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonController.java
index 6a98fbbe..95f7747 100644
--- a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonController.java
+++ b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonController.java
@@ -21,6 +21,10 @@
 import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures;
 import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures.AdaptiveToolbarButtonVariant;
 import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
+import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
@@ -30,16 +34,28 @@
  */
 public class PriceTrackingButtonController extends BaseButtonDataProvider {
     private final Supplier<TabBookmarker> mTabBookmarkerSupplier;
+    private final BottomSheetController mBottomSheetController;
+    private final BottomSheetObserver mBottomSheetObserver;
 
     /** Constructor. */
     public PriceTrackingButtonController(ObservableSupplier<Tab> tabSupplier,
-            ModalDialogManager modalDialogManager, Drawable buttonDrawable,
-            Supplier<TabBookmarker> tabBookmarkerSupplier) {
+            ModalDialogManager modalDialogManager, BottomSheetController bottomSheetController,
+            Drawable buttonDrawable, Supplier<TabBookmarker> tabBookmarkerSupplier) {
         super(tabSupplier, modalDialogManager, buttonDrawable,
                 R.string.enable_price_tracking_menu_item,
                 /*supportsTinting=*/true, /*iphCommandBuilder*/ null,
                 AdaptiveToolbarButtonVariant.PRICE_TRACKING);
         mTabBookmarkerSupplier = tabBookmarkerSupplier;
+        mBottomSheetController = bottomSheetController;
+
+        mBottomSheetObserver = new EmptyBottomSheetObserver() {
+            @Override
+            public void onSheetStateChanged(int newState, int reason) {
+                mButtonData.setEnabled(newState == SheetState.HIDDEN);
+                notifyObservers(mButtonData.canShow());
+            }
+        };
+        mBottomSheetController.addObserver(mBottomSheetObserver);
     }
 
     @Override
diff --git a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonControllerUnitTest.java b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonControllerUnitTest.java
new file mode 100644
index 0000000..aff052f
--- /dev/null
+++ b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonControllerUnitTest.java
@@ -0,0 +1,184 @@
+// Copyright 2022 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.price_tracking;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.FeatureList;
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.Supplier;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.bookmarks.TabBookmarker;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.toolbar.ButtonData;
+import org.chromium.chrome.browser.toolbar.ButtonDataProvider;
+import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
+import org.chromium.ui.modaldialog.ModalDialogManager;
+
+/**
+ * Unit test for {@link PriceTrackingButtonController}.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+@Features.EnableFeatures({ChromeFeatureList.CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING,
+        ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2})
+public class PriceTrackingButtonControllerUnitTest {
+    @Rule
+    public TestRule mFeaturesProcessor = new Features.JUnitProcessor();
+
+    private Activity mActivity;
+    @Mock
+    private Tab mMockTab;
+    @Mock
+    private ObservableSupplier<Tab> mMockTabSupplier;
+    @Mock
+    private Supplier<TabBookmarker> mMockTabBookmarkerSupplier;
+    @Mock
+    private TabBookmarker mMockTabBookmarker;
+    @Mock
+    private BottomSheetController mMockBottomSheetController;
+    @Mock
+    private ModalDialogManager mMockModalDialogManager;
+    @Captor
+    private ArgumentCaptor<BottomSheetObserver> mBottomSheetObserverCaptor;
+
+    @Before
+    public void setUp() {
+        mActivity = Robolectric.setupActivity(Activity.class);
+        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+
+        MockitoAnnotations.initMocks(this);
+
+        when(mMockTab.getContext()).thenReturn(mActivity);
+        when(mMockTabSupplier.get()).thenReturn(mMockTab);
+        when(mMockTabBookmarkerSupplier.get()).thenReturn(mMockTabBookmarker);
+    }
+
+    @Test
+    public void testButtonData_QuietVariation() {
+        PriceTrackingButtonController priceTrackingButtonController =
+                new PriceTrackingButtonController(mMockTabSupplier, mMockModalDialogManager,
+                        mMockBottomSheetController, mock(Drawable.class),
+                        mMockTabBookmarkerSupplier);
+        ButtonData buttonData = priceTrackingButtonController.get(mMockTab);
+
+        // Quiet variation uses an IPHCommandBuilder to highlight the action.
+        Assert.assertNotNull(buttonData.getButtonSpec().getIPHCommandBuilder());
+        Assert.assertEquals(
+                Resources.ID_NULL, buttonData.getButtonSpec().getActionChipLabelResId());
+    }
+
+    @Test
+    public void testButtonData_ActionChipVariation() {
+        FeatureList.TestValues testValues = new FeatureList.TestValues();
+        testValues.addFeatureFlagOverride(ChromeFeatureList.CONTEXTUAL_PAGE_ACTIONS, true);
+        testValues.addFieldTrialParamOverride(
+                ChromeFeatureList.CONTEXTUAL_PAGE_ACTIONS, "action_chip", "true");
+        testValues.addFeatureFlagOverride(
+                ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2, true);
+        FeatureList.setTestValues(testValues);
+
+        PriceTrackingButtonController priceTrackingButtonController =
+                new PriceTrackingButtonController(mMockTabSupplier, mMockModalDialogManager,
+                        mMockBottomSheetController, mock(Drawable.class),
+                        mMockTabBookmarkerSupplier);
+        ButtonData buttonData = priceTrackingButtonController.get(mMockTab);
+
+        // Action chip variation sets a string resource as action chip label. IPH is not used.
+        Assert.assertNull(buttonData.getButtonSpec().getIPHCommandBuilder());
+        Assert.assertNotEquals(
+                Resources.ID_NULL, buttonData.getButtonSpec().getActionChipLabelResId());
+    }
+
+    @Test
+    public void testPriceTrackingButtonClick() {
+        PriceTrackingButtonController priceTrackingButtonController =
+                new PriceTrackingButtonController(mMockTabSupplier, mMockModalDialogManager,
+                        mMockBottomSheetController, mock(Drawable.class),
+                        mMockTabBookmarkerSupplier);
+        ButtonData buttonData = priceTrackingButtonController.get(mMockTab);
+
+        buttonData.getButtonSpec().getOnClickListener().onClick(null);
+
+        verify(mMockTabBookmarker).startOrModifyPriceTracking(mMockTab);
+    }
+
+    @Test
+    public void testPriceTrackingButton_IsDisabledWhenBottomSheetAppears() {
+        PriceTrackingButtonController priceTrackingButtonController =
+                new PriceTrackingButtonController(mMockTabSupplier, mMockModalDialogManager,
+                        mMockBottomSheetController, mock(Drawable.class),
+                        mMockTabBookmarkerSupplier);
+        ButtonDataProvider.ButtonDataObserver buttonDataObserver =
+                Mockito.mock(ButtonDataProvider.ButtonDataObserver.class);
+        priceTrackingButtonController.addObserver(buttonDataObserver);
+        ButtonData buttonData = priceTrackingButtonController.get(mMockTab);
+
+        // The controller should have registered an observer to listen to bottom sheet events.
+        verify(mMockBottomSheetController).addObserver(mBottomSheetObserverCaptor.capture());
+
+        mBottomSheetObserverCaptor.getValue().onSheetStateChanged(
+                SheetState.FULL, StateChangeReason.NONE);
+
+        Assert.assertFalse(buttonData.isEnabled());
+        verify(buttonDataObserver).buttonDataChanged(true);
+    }
+
+    @Test
+    public void testPriceTrackingButton_IsReenabledWhenBottomSheetDismissed() {
+        PriceTrackingButtonController priceTrackingButtonController =
+                new PriceTrackingButtonController(mMockTabSupplier, mMockModalDialogManager,
+                        mMockBottomSheetController, mock(Drawable.class),
+                        mMockTabBookmarkerSupplier);
+
+        ButtonDataProvider.ButtonDataObserver buttonDataObserver =
+                Mockito.mock(ButtonDataProvider.ButtonDataObserver.class);
+        priceTrackingButtonController.addObserver(buttonDataObserver);
+        ButtonData buttonData = priceTrackingButtonController.get(mMockTab);
+
+        // The controller should have registered an observer to listen to bottom sheet events.
+        verify(mMockBottomSheetController).addObserver(mBottomSheetObserverCaptor.capture());
+
+        // Show bottom sheet to disable button.
+        mBottomSheetObserverCaptor.getValue().onSheetStateChanged(
+                SheetState.FULL, StateChangeReason.NONE);
+
+        // Close the bottom sheet, button should be enabled again.
+        mBottomSheetObserverCaptor.getValue().onSheetStateChanged(
+                SheetState.HIDDEN, StateChangeReason.NONE);
+
+        // After the bottom sheet is closed the button should be enabled.
+        Assert.assertTrue(buttonData.isEnabled());
+        // We should have notified of changes twice (when disabled and when enabled again).
+        verify(buttonDataObserver, times(2)).buttonDataChanged(true);
+    }
+}
diff --git a/chrome/browser/commerce/price_tracking/android/test_java_sources.gni b/chrome/browser/commerce/price_tracking/android/test_java_sources.gni
index f54d7a7..665fa0f1 100644
--- a/chrome/browser/commerce/price_tracking/android/test_java_sources.gni
+++ b/chrome/browser/commerce/price_tracking/android/test_java_sources.gni
@@ -9,5 +9,6 @@
 
 price_tracking_junit_test_java_sources = [
   "//chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotifierUnitTest.java",
+  "//chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonControllerUnitTest.java",
   "//chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingNotificationBridgeUnitTest.java",
 ]
diff --git a/chrome/browser/component_updater/file_type_policies_component_installer_unittest.cc b/chrome/browser/component_updater/file_type_policies_component_installer_unittest.cc
index 3bb1ddd..6391c515e 100644
--- a/chrome/browser/component_updater/file_type_policies_component_installer_unittest.cc
+++ b/chrome/browser/component_updater/file_type_policies_component_installer_unittest.cc
@@ -25,7 +25,7 @@
   // Feature enabled
   {
     base::test::ScopedFeatureList feature_list;
-    base::test::ScopedFeatureList::FeatureAndParams feature_params(
+    base::test::FeatureRefAndParams feature_params(
         safe_browsing::kFileTypePoliciesTag, {{"policy_omaha_tag", "46"}});
     feature_list.InitWithFeaturesAndParameters({feature_params}, {});
 
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
index 41a2e97..552e13c9 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
@@ -118,25 +118,6 @@
   return &enabled;
 }
 
-ContentAnalysisAcknowledgement::FinalAction GetFinalAction(
-    FinalContentAnalysisResult final_result) {
-  auto final_action = ContentAnalysisAcknowledgement::ALLOW;
-  switch (final_result) {
-    case FinalContentAnalysisResult::FAILURE:
-    case FinalContentAnalysisResult::LARGE_FILES:
-    case FinalContentAnalysisResult::ENCRYPTED_FILES:
-      final_action = ContentAnalysisAcknowledgement::BLOCK;
-      break;
-    case FinalContentAnalysisResult::WARNING:
-      final_action = ContentAnalysisAcknowledgement::WARN;
-      break;
-    case FinalContentAnalysisResult::SUCCESS:
-      break;
-  }
-
-  return final_action;
-}
-
 }  // namespace
 
 ContentAnalysisDelegate::Data::Data() = default;
@@ -368,7 +349,7 @@
     enterprise_connectors::ContentAnalysisResponse response) {
   // Remember to send an ack for this response.
   if (result == safe_browsing::BinaryUploadService::Result::SUCCESS)
-    request_tokens_.push_back(response.request_token());
+    final_actions_[response.request_token()] = GetAckFinalAction(response);
 
   int64_t content_size = 0;
   for (const std::string& entry : data_.text)
@@ -409,7 +390,7 @@
 void ContentAnalysisDelegate::FilesRequestCallback(
     std::vector<RequestHandlerResult> results) {
   // Remember to send acks for any responses.
-  files_request_handler_->AppendRequestTokensTo(&request_tokens_);
+  files_request_handler_->AppendFinalActionsTo(&final_actions_);
 
   // No reporting here, because the MultiFileRequestHandler does that.
   DCHECK_EQ(results.size(), result_.paths_results.size());
@@ -452,7 +433,7 @@
     enterprise_connectors::ContentAnalysisResponse response) {
   // Remember to send an ack for this response.
   if (result == safe_browsing::BinaryUploadService::Result::SUCCESS)
-    request_tokens_.push_back(response.request_token());
+    final_actions_[response.request_token()] = GetAckFinalAction(response);
 
   RecordDeepScanMetrics(access_point_,
                         base::TimeTicks::Now() - upload_start_time_,
@@ -667,15 +648,12 @@
   if (!upload_service)
     return;
 
-  // Calculate final action applied to all requests.
-  auto final_action = GetFinalAction(final_result_);
-
-  for (auto& token : request_tokens_) {
+  for (const auto& token_and_action : final_actions_) {
     auto ack = std::make_unique<safe_browsing::BinaryUploadService::Ack>(
         data_.settings.cloud_or_local_settings);
-    ack->set_request_token(token);
+    ack->set_request_token(token_and_action.first);
     ack->set_status(ContentAnalysisAcknowledgement::SUCCESS);
-    ack->set_final_action(final_action);
+    ack->set_final_action(token_and_action.second);
     upload_service->MaybeAcknowledge(std::move(ack));
   }
 }
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
index 6839ed7b..f3e08b2 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
@@ -352,9 +352,10 @@
   // Always nullptr for non-file content scanning.
   std::unique_ptr<FilesRequestHandler> files_request_handler_;
 
-  // The request tokens of all the requests that make up the user action
-  // represented by this ContentAnalysisDelegate instance.
-  std::vector<std::string> request_tokens_;
+  // A mapping of request tokens to ack final actions for all requests that make
+  // up the user action represented by this ContentAnalysisDelegate.
+  std::map<std::string, ContentAnalysisAcknowledgement::FinalAction>
+      final_actions_;
 
   base::TimeTicks upload_start_time_;
 
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc
index d128493..5ccdb4eb 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc
@@ -87,9 +87,10 @@
   }
 
   void SetExpectedFinalAction(
+      const std::string& request_token,
       enterprise_connectors::ContentAnalysisAcknowledgement::FinalAction
           final_action) {
-    final_action_ = final_action;
+    request_tokens_to_final_actions_[request_token] = final_action;
   }
 
   void SetShouldAutomaticallyAuthorize(bool authorize) {
@@ -101,10 +102,13 @@
 
  private:
   void MaybeAcknowledge(std::unique_ptr<Ack> ack) override {
-    EXPECT_EQ(final_action_, ack->ack().final_action());
+    EXPECT_TRUE(ack);
 
     ++ack_count_;
-    ASSERT_TRUE(base::Contains(requests_tokens_, ack->ack().request_token()));
+    ASSERT_TRUE(base::Contains(request_tokens_to_final_actions_,
+                               ack->ack().request_token()));
+    ASSERT_EQ(ack->ack().final_action(),
+              request_tokens_to_final_actions_.at(ack->ack().request_token()));
   }
 
   void UploadForDeepScanning(std::unique_ptr<Request> request) override {
@@ -124,13 +128,10 @@
           ASSERT_FALSE(file.empty());
           ASSERT_TRUE(prepared_file_results_.count(file));
           ASSERT_TRUE(prepared_file_responses_.count(file));
-          requests_tokens_.push_back(
-              prepared_file_responses_[file].request_token());
           request->FinishRequest(prepared_file_results_[file],
                                  prepared_file_responses_[file]);
           break;
         case AnalysisConnector::BULK_DATA_ENTRY:
-          requests_tokens_.push_back(prepared_text_response_.request_token());
           request->FinishRequest(prepared_text_result_,
                                  prepared_text_response_);
           break;
@@ -163,12 +164,11 @@
   std::map<std::string, BinaryUploadService::Result> prepared_file_results_;
   std::map<std::string, ContentAnalysisResponse> prepared_file_responses_;
 
-  std::vector<std::string> requests_tokens_;
   int requests_count_ = 0;
   int ack_count_ = 0;
   bool should_automatically_authorize_ = false;
-  ContentAnalysisAcknowledgement::FinalAction final_action_ =
-      ContentAnalysisAcknowledgement::ACTION_UNSPECIFIED;
+  std::map<std::string, ContentAnalysisAcknowledgement::FinalAction>
+      request_tokens_to_final_actions_;
 };
 
 FakeBinaryUploadService* FakeBinaryUploadServiceStorage() {
@@ -449,11 +449,13 @@
   FakeBinaryUploadServiceStorage()->SetResponseForFile(
       created_file_paths()[0].AsUTF8Unsafe(),
       BinaryUploadService::Result::SUCCESS, ok_response);
+  FakeBinaryUploadServiceStorage()->SetExpectedFinalAction(
+      kScanId1, ContentAnalysisAcknowledgement::ALLOW);
   FakeBinaryUploadServiceStorage()->SetResponseForFile(
       created_file_paths()[1].AsUTF8Unsafe(),
       BinaryUploadService::Result::SUCCESS, bad_response);
   FakeBinaryUploadServiceStorage()->SetExpectedFinalAction(
-      ContentAnalysisAcknowledgement::BLOCK);
+      kScanId2, ContentAnalysisAcknowledgement::BLOCK);
 
   bool called = false;
   base::RunLoop run_loop;
@@ -518,7 +520,7 @@
   FakeBinaryUploadServiceStorage()->SetResponseForText(
       BinaryUploadService::Result::SUCCESS, response);
   FakeBinaryUploadServiceStorage()->SetExpectedFinalAction(
-      ContentAnalysisAcknowledgement::BLOCK);
+      kScanId1, ContentAnalysisAcknowledgement::BLOCK);
 
   // The DLP verdict means an event should be reported. The content size is
   // equal to the length of the concatenated texts (2 * 100 * 'a').
@@ -987,7 +989,7 @@
       created_file_paths()[0].AsUTF8Unsafe(),
       BinaryUploadService::Result::SUCCESS, response);
   FakeBinaryUploadServiceStorage()->SetExpectedFinalAction(
-      ContentAnalysisAcknowledgement::BLOCK);
+      kScanId1, ContentAnalysisAcknowledgement::BLOCK);
   validator.ExpectDangerousDeepScanningResultAndSensitiveDataEvent(
       /*url*/ "about:blank",
       /*filename*/ "foo.doc",
diff --git a/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc b/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc
index 631f185..06d8ac4 100644
--- a/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc
+++ b/chrome/browser/enterprise/connectors/analysis/files_request_handler.cc
@@ -260,8 +260,10 @@
     safe_browsing::BinaryUploadService::Result upload_result,
     enterprise_connectors::ContentAnalysisResponse response) {
   // Remember to send an ack for this response.
-  if (upload_result == safe_browsing::BinaryUploadService::Result::SUCCESS)
-    request_tokens_.push_back(response.request_token());
+  if (upload_result == safe_browsing::BinaryUploadService::Result::SUCCESS) {
+    request_tokens_to_ack_final_actions_[response.request_token()] =
+        GetAckFinalAction(response);
+  }
 
   DCHECK_EQ(results_.size(), paths_.size());
   if (upload_result ==
diff --git a/chrome/browser/enterprise/connectors/analysis/files_request_handler_unittest.cc b/chrome/browser/enterprise/connectors/analysis/files_request_handler_unittest.cc
index b636f72..301bac4 100644
--- a/chrome/browser/enterprise/connectors/analysis/files_request_handler_unittest.cc
+++ b/chrome/browser/enterprise/connectors/analysis/files_request_handler_unittest.cc
@@ -235,10 +235,11 @@
     RunUntilDone();
 
     EXPECT_GE(paths.size(),
-              fake_files_request_handler_->GetRequestTokensForTesting().size());
-    for (auto& token :
-         fake_files_request_handler_->GetRequestTokensForTesting()) {
-      EXPECT_FALSE(token.empty());
+              fake_files_request_handler_->request_tokens_to_ack_final_actions()
+                  .size());
+    for (const auto& token_and_action :
+         fake_files_request_handler_->request_tokens_to_ack_final_actions()) {
+      EXPECT_FALSE(token_and_action.first.empty());
     }
   }
 
diff --git a/chrome/browser/enterprise/connectors/analysis/request_handler_base.cc b/chrome/browser/enterprise/connectors/analysis/request_handler_base.cc
index 3419f34..d4e58790 100644
--- a/chrome/browser/enterprise/connectors/analysis/request_handler_base.cc
+++ b/chrome/browser/enterprise/connectors/analysis/request_handler_base.cc
@@ -34,12 +34,15 @@
   return UploadDataImpl();
 }
 
-void RequestHandlerBase::AppendRequestTokensTo(
-    std::vector<std::string>* request_tokens) {
-  request_tokens->reserve(request_tokens->size() + request_tokens_.size());
-  std::move(std::begin(request_tokens_), std::end(request_tokens_),
-            std::back_inserter(*request_tokens));
-  request_tokens_.clear();
+void RequestHandlerBase::AppendFinalActionsTo(
+    std::map<std::string, ContentAnalysisAcknowledgement::FinalAction>*
+        final_actions) {
+  DCHECK(final_actions);
+  final_actions->insert(
+      std::make_move_iterator(request_tokens_to_ack_final_actions_.begin()),
+      std::make_move_iterator(request_tokens_to_ack_final_actions_.end()));
+
+  request_tokens_to_ack_final_actions_.clear();
 }
 
 void RequestHandlerBase::PrepareRequest(
diff --git a/chrome/browser/enterprise/connectors/analysis/request_handler_base.h b/chrome/browser/enterprise/connectors/analysis/request_handler_base.h
index 76424eb..f54199a 100644
--- a/chrome/browser/enterprise/connectors/analysis/request_handler_base.h
+++ b/chrome/browser/enterprise/connectors/analysis/request_handler_base.h
@@ -45,9 +45,11 @@
   // the background and false if there is nothing to do.
   bool UploadData();
 
-  // Moves the tokens of all file requests being handled to the end of the
-  // given vector.
-  void AppendRequestTokensTo(std::vector<std::string>* request_tokens);
+  // Moves the tokens-actions mapping of all file requests being handled to the
+  // given map.
+  void AppendFinalActionsTo(
+      std::map<std::string, ContentAnalysisAcknowledgement::FinalAction>*
+          final_actions);
 
   // This method is called after a user has bypassed a scanning warning and is
   // expected to send one or more reports corresponding to the data that was
@@ -55,11 +57,12 @@
   virtual void ReportWarningBypass(
       absl::optional<std::u16string> user_justification) = 0;
 
-  // After All file requests have been processed, this call can be used to
-  // retrieve any request tokens stored internally.  There should one for
-  // each successful request and they must all be non-empty.
-  const std::vector<std::string>& GetRequestTokensForTesting() const {
-    return request_tokens_;
+  // After all file requests have been processed, this call can be used to
+  // retrieve any final actions stored internally.  There should one for
+  // each successful request.
+  const std::map<std::string, ContentAnalysisAcknowledgement::FinalAction>&
+  request_tokens_to_ack_final_actions() const {
+    return request_tokens_to_ack_final_actions_;
   }
 
  private:
@@ -87,9 +90,10 @@
   uint64_t user_action_requests_count_;
   safe_browsing::DeepScanAccessPoint access_point_;
 
-  // The request tokens of all the requests that make up the user action
-  // represented by this ContentAnalysisDelegate instance.
-  std::vector<std::string> request_tokens_;
+  // A mapping of request tokens (corresponding to one user action) to their Ack
+  // final action.
+  std::map<std::string, ContentAnalysisAcknowledgement::FinalAction>
+      request_tokens_to_ack_final_actions_;
 
   base::TimeTicks upload_start_time_;
 };
diff --git a/chrome/browser/enterprise/connectors/common.cc b/chrome/browser/enterprise/connectors/common.cc
index bcc2f02..15efc28 100644
--- a/chrome/browser/enterprise/connectors/common.cc
+++ b/chrome/browser/enterprise/connectors/common.cc
@@ -42,6 +42,20 @@
   }
 }
 
+ContentAnalysisAcknowledgement::FinalAction RuleActionToAckAction(
+    TriggeredRule::Action action) {
+  switch (action) {
+    case TriggeredRule::ACTION_UNSPECIFIED:
+      return ContentAnalysisAcknowledgement::ACTION_UNSPECIFIED;
+    case TriggeredRule::REPORT_ONLY:
+      return ContentAnalysisAcknowledgement::REPORT_ONLY;
+    case TriggeredRule::WARN:
+      return ContentAnalysisAcknowledgement::WARN;
+    case TriggeredRule::BLOCK:
+      return ContentAnalysisAcknowledgement::BLOCK;
+  }
+}
+
 }  // namespace
 
 bool ResultShouldAllowDataUse(
@@ -118,6 +132,24 @@
                             : safe_browsing::EventResult::BLOCKED);
 }
 
+ContentAnalysisAcknowledgement::FinalAction GetAckFinalAction(
+    const ContentAnalysisResponse& response) {
+  auto final_action = ContentAnalysisAcknowledgement::ALLOW;
+  for (const auto& result : response.results()) {
+    if (!result.has_status() ||
+        result.status() != ContentAnalysisResponse::Result::SUCCESS) {
+      continue;
+    }
+
+    for (const auto& rule : result.triggered_rules()) {
+      final_action = GetHighestPrecedenceAction(
+          final_action, RuleActionToAckAction(rule.action()));
+    }
+  }
+
+  return final_action;
+}
+
 ReportingSettings::ReportingSettings() = default;
 ReportingSettings::ReportingSettings(GURL url,
                                      const std::string& dm_token,
@@ -246,6 +278,37 @@
   return TriggeredRule::ACTION_UNSPECIFIED;
 }
 
+ContentAnalysisAcknowledgement::FinalAction GetHighestPrecedenceAction(
+    const ContentAnalysisAcknowledgement::FinalAction& action_1,
+    const ContentAnalysisAcknowledgement::FinalAction& action_2) {
+  // Don't use the enum's int values to determine precedence since that
+  // may introduce bugs for new actions later.
+  //
+  // The current precedence is BLOCK > WARN > REPORT_ONLY > ALLOW > UNSPECIFIED
+  if (action_1 == ContentAnalysisAcknowledgement::BLOCK ||
+      action_2 == ContentAnalysisAcknowledgement::BLOCK) {
+    return ContentAnalysisAcknowledgement::BLOCK;
+  }
+  if (action_1 == ContentAnalysisAcknowledgement::WARN ||
+      action_2 == ContentAnalysisAcknowledgement::WARN) {
+    return ContentAnalysisAcknowledgement::WARN;
+  }
+  if (action_1 == ContentAnalysisAcknowledgement::REPORT_ONLY ||
+      action_2 == ContentAnalysisAcknowledgement::REPORT_ONLY) {
+    return ContentAnalysisAcknowledgement::REPORT_ONLY;
+  }
+  if (action_1 == ContentAnalysisAcknowledgement::ALLOW ||
+      action_2 == ContentAnalysisAcknowledgement::ALLOW) {
+    return ContentAnalysisAcknowledgement::ALLOW;
+  }
+  if (action_1 == ContentAnalysisAcknowledgement::ACTION_UNSPECIFIED ||
+      action_2 == ContentAnalysisAcknowledgement::ACTION_UNSPECIFIED) {
+    return ContentAnalysisAcknowledgement::ACTION_UNSPECIFIED;
+  }
+  NOTREACHED();
+  return ContentAnalysisAcknowledgement::ACTION_UNSPECIFIED;
+}
+
 FileMetadata::FileMetadata(const std::string& filename,
                            const std::string& sha256,
                            const std::string& mime_type,
diff --git a/chrome/browser/enterprise/connectors/common.h b/chrome/browser/enterprise/connectors/common.h
index 21630387..7d2d0900 100644
--- a/chrome/browser/enterprise/connectors/common.h
+++ b/chrome/browser/enterprise/connectors/common.h
@@ -142,6 +142,9 @@
 TriggeredRule::Action GetHighestPrecedenceAction(
     const TriggeredRule::Action& action_1,
     const TriggeredRule::Action& action_2);
+ContentAnalysisAcknowledgement::FinalAction GetHighestPrecedenceAction(
+    const ContentAnalysisAcknowledgement::FinalAction& action_1,
+    const ContentAnalysisAcknowledgement::FinalAction& action_2);
 
 // Struct used to persist metadata about a file in base::SupportsUserData
 // through ScanResult.
@@ -223,6 +226,11 @@
     bool allowed_by_scan_result,
     bool should_warn);
 
+// Calculates the ContentAnalysisAcknowledgement::FinalAction for an action
+// based on the response it got from scanning.
+ContentAnalysisAcknowledgement::FinalAction GetAckFinalAction(
+    const ContentAnalysisResponse& response);
+
 // User data to persist a save package's final callback allowing/denying
 // completion. This is used since the callback can be called either when
 // scanning completes on a block/allow verdict, when the user cancels the scan,
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_service.h b/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_service.h
index be6d3d4..0076872 100644
--- a/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_service.h
+++ b/chrome/browser/enterprise/connectors/device_trust/attestation/common/attestation_service.h
@@ -25,12 +25,13 @@
 
   virtual ~AttestationService() = default;
 
-  // If the `serialized_signed_challenge` comes from Verified Access
-  // builds a proper response including the `signals` and returns it via
-  // the given `callback`. If the challenge does not come from VA, runs
-  // `callback` with an empty string.
+  // Uses the `challenge` that comes from Verified Access to build a proper
+  // response including the `signals` and signature representing the device
+  // identity, and returns it via the given `callback`. If the challenge does
+  // not come from VA, runs `callback` with an empty string.
+  // `challenge` represents a serialized SignedData proto.
   virtual void BuildChallengeResponseForVAChallenge(
-      const std::string& serialized_signed_challenge,
+      const std::string& challenge,
       base::Value::Dict signals,
       AttestationCallback callback) = 0;
 };
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation/desktop/desktop_attestation_service.cc b/chrome/browser/enterprise/connectors/device_trust/attestation/desktop/desktop_attestation_service.cc
index 439308b..3a32e15 100644
--- a/chrome/browser/enterprise/connectors/device_trust/attestation/desktop/desktop_attestation_service.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/attestation/desktop/desktop_attestation_service.cc
@@ -117,19 +117,19 @@
 // - Encode encrypted data,
 // - Reply to callback.
 void DesktopAttestationService::BuildChallengeResponseForVAChallenge(
-    const std::string& serialized_signed_challenge,
+    const std::string& challenge,
     base::Value::Dict signals,
     AttestationCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   key_manager_->ExportPublicKeyAsync(
       base::BindOnce(&DesktopAttestationService::OnPublicKeyExported,
-                     weak_factory_.GetWeakPtr(), serialized_signed_challenge,
-                     std::move(signals), std::move(callback)));
+                     weak_factory_.GetWeakPtr(), challenge, std::move(signals),
+                     std::move(callback)));
 }
 
 void DesktopAttestationService::OnPublicKeyExported(
-    const std::string& serialized_signed_challenge,
+    const std::string& challenge,
     base::Value::Dict signals,
     AttestationCallback callback,
     absl::optional<std::string> exported_key) {
@@ -143,8 +143,7 @@
   }
 
   SignedData signed_data;
-  if (serialized_signed_challenge.empty() ||
-      !signed_data.ParseFromString(serialized_signed_challenge)) {
+  if (challenge.empty() || !signed_data.ParseFromString(challenge)) {
     // Challenge is not properly formatted, so mark the device as untrusted (no
     // challenge response).
     std::move(callback).Run(
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation/desktop/desktop_attestation_service.h b/chrome/browser/enterprise/connectors/device_trust/attestation/desktop/desktop_attestation_service.h
index 69a5af0..2acc8da 100644
--- a/chrome/browser/enterprise/connectors/device_trust/attestation/desktop/desktop_attestation_service.h
+++ b/chrome/browser/enterprise/connectors/device_trust/attestation/desktop/desktop_attestation_service.h
@@ -37,7 +37,7 @@
 
   // AttestationService:
   void BuildChallengeResponseForVAChallenge(
-      const std::string& serialized_signed_challenge,
+      const std::string& challenge,
       base::Value::Dict signals,
       AttestationCallback callback) override;
 
diff --git a/chrome/browser/enterprise/connectors/device_trust/common/BUILD.gn b/chrome/browser/enterprise/connectors/device_trust/common/BUILD.gn
index f184120..ea96160 100644
--- a/chrome/browser/enterprise/connectors/device_trust/common/BUILD.gn
+++ b/chrome/browser/enterprise/connectors/device_trust/common/BUILD.gn
@@ -5,10 +5,15 @@
 import("//build/config/chromeos/ui_mode.gni")
 
 source_set("common") {
-  sources = [ "metrics_utils.cc" ]
+  sources = [
+    "common_types.cc",
+    "device_trust_constants.cc",
+    "metrics_utils.cc",
+  ]
 
   public = [
     "common_types.h",
+    "device_trust_constants.h",
     "metrics_utils.h",
   ]
 
diff --git a/chrome/browser/enterprise/connectors/device_trust/common/common_types.cc b/chrome/browser/enterprise/connectors/device_trust/common/common_types.cc
new file mode 100644
index 0000000..458de73
--- /dev/null
+++ b/chrome/browser/enterprise/connectors/device_trust/common/common_types.cc
@@ -0,0 +1,53 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/enterprise/connectors/device_trust/common/common_types.h"
+
+#include "base/notreached.h"
+#include "chrome/browser/enterprise/connectors/device_trust/common/device_trust_constants.h"
+
+namespace enterprise_connectors {
+
+const std::string AttestationResultToString(DTAttestationResult result) {
+  switch (result) {
+    case DTAttestationResult::kMissingCoreSignals:
+      return errors::kMissingCoreSignals;
+    case DTAttestationResult::kMissingSigningKey:
+      return errors::kMissingSigningKey;
+    case DTAttestationResult::kBadChallengeFormat:
+      return errors::kBadChallengeFormat;
+    case DTAttestationResult::kBadChallengeSource:
+      return errors::kBadChallengeSource;
+    case DTAttestationResult::kFailedToSerializeKeyInfo:
+      return errors::kFailedToSerializeKeyInfo;
+    case DTAttestationResult::kFailedToGenerateResponse:
+      return errors::kFailedToGenerateResponse;
+    case DTAttestationResult::kFailedToSignResponse:
+      return errors::kFailedToSignResponse;
+    case DTAttestationResult::kFailedToSerializeResponse:
+      return errors::kFailedToSerializeResponse;
+    case DTAttestationResult::kEmptySerializedResponse:
+      return errors::kEmptySerializedResponse;
+    case DTAttestationResult::kFailedToSerializeSignals:
+      return errors::kFailedToSerializeSignals;
+    case DTAttestationResult::kSuccess:
+      NOTREACHED();
+      return std::string();
+  }
+}
+
+const std::string DeviceTrustErrorToString(DeviceTrustError error) {
+  switch (error) {
+    case DeviceTrustError::kUnknown:
+      return errors::kUnknown;
+    case DeviceTrustError::kTimeout:
+      return errors::kTimeout;
+    case DeviceTrustError::kFailedToParseChallenge:
+      return errors::kFailedToParseChallenge;
+    case DeviceTrustError::kFailedToCreateResponse:
+      return errors::kFailedToCreateResponse;
+  }
+}
+
+}  // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/common/common_types.h b/chrome/browser/enterprise/connectors/device_trust/common/common_types.h
index 9d6b7084a..7feece6 100644
--- a/chrome/browser/enterprise/connectors/device_trust/common/common_types.h
+++ b/chrome/browser/enterprise/connectors/device_trust/common/common_types.h
@@ -7,6 +7,8 @@
 
 #include <string>
 
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
 namespace enterprise_connectors {
 
 // Various possible outcomes to the attestation step in the overarching Device
@@ -28,11 +30,37 @@
   kMaxValue = kFailedToSerializeSignals,
 };
 
+// Enum representing all possible errors that may cause the generation of a
+// challenge response to fail as part of the device identity attestation flow.
+enum class DeviceTrustError {
+  kUnknown = 0,
+  kTimeout,
+  kFailedToParseChallenge,
+  kFailedToCreateResponse
+};
+
+// Used to convert an error `result` to a string. This function will return an
+// empty string if `result` represents `kSuccess`.
+const std::string AttestationResultToString(DTAttestationResult result);
+
+// Used to convert `error` to a string representation.
+const std::string DeviceTrustErrorToString(DeviceTrustError error);
+
+// Response payload for the inline flow's attestation step, where the challenge
+// response is created and signed.
 struct AttestationResponse {
   std::string challenge_response{};
   DTAttestationResult result_code{};
 };
 
+// Top-level response payload to a request for a challenge response as part of
+// a device identity attestation request.
+struct DeviceTrustResponse {
+  std::string challenge_response{};
+  absl::optional<DeviceTrustError> error = absl::nullopt;
+  absl::optional<DTAttestationResult> attestation_result = absl::nullopt;
+};
+
 }  // namespace enterprise_connectors
 
 #endif  // CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_COMMON_COMMON_TYPES_H_
diff --git a/chrome/browser/enterprise/connectors/device_trust/common/device_trust_constants.cc b/chrome/browser/enterprise/connectors/device_trust/common/device_trust_constants.cc
new file mode 100644
index 0000000..10215fceb6
--- /dev/null
+++ b/chrome/browser/enterprise/connectors/device_trust/common/device_trust_constants.cc
@@ -0,0 +1,25 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/enterprise/connectors/device_trust/common/device_trust_constants.h"
+
+namespace enterprise_connectors::errors {
+
+const char kMissingCoreSignals[] = "missing_core_signals";
+const char kMissingSigningKey[] = "missing_signing_key";
+const char kBadChallengeFormat[] = "bad_challenge_format";
+const char kBadChallengeSource[] = "bad_challenge_source";
+const char kFailedToSerializeKeyInfo[] = "failed_to_serialize_keyinfo";
+const char kFailedToGenerateResponse[] = "failed_to_generate_response";
+const char kFailedToSignResponse[] = "failed_to_sign_response";
+const char kFailedToSerializeResponse[] = "failed_to_serialize_response";
+const char kEmptySerializedResponse[] = "empty_response";
+const char kFailedToSerializeSignals[] = "failed_to_serialize_signals";
+
+const char kUnknown[] = "unknown";
+const char kTimeout[] = "timeout";
+const char kFailedToParseChallenge[] = "failed_to_parse_challenge";
+const char kFailedToCreateResponse[] = "failed_to_create_response";
+
+}  // namespace enterprise_connectors::errors
diff --git a/chrome/browser/enterprise/connectors/device_trust/common/device_trust_constants.h b/chrome/browser/enterprise/connectors/device_trust/common/device_trust_constants.h
new file mode 100644
index 0000000..75495b48
--- /dev/null
+++ b/chrome/browser/enterprise/connectors/device_trust/common/device_trust_constants.h
@@ -0,0 +1,28 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_COMMON_DEVICE_TRUST_CONSTANTS_H_
+#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_COMMON_DEVICE_TRUST_CONSTANTS_H_
+
+namespace enterprise_connectors::errors {
+
+extern const char kMissingCoreSignals[];
+extern const char kMissingSigningKey[];
+extern const char kBadChallengeFormat[];
+extern const char kBadChallengeSource[];
+extern const char kFailedToSerializeKeyInfo[];
+extern const char kFailedToGenerateResponse[];
+extern const char kFailedToSignResponse[];
+extern const char kFailedToSerializeResponse[];
+extern const char kEmptySerializedResponse[];
+extern const char kFailedToSerializeSignals[];
+
+extern const char kUnknown[];
+extern const char kTimeout[];
+extern const char kFailedToParseChallenge[];
+extern const char kFailedToCreateResponse[];
+
+}  // namespace enterprise_connectors::errors
+
+#endif  // CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_COMMON_DEVICE_TRUST_CONSTANTS_H_
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc
index 1b6778b7..ed0a517 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc
@@ -428,34 +428,39 @@
       initial_attestation_request_->headers.find(kDeviceTrustHeader)->second,
       kDeviceTrustHeaderValue);
 
-  EXPECT_EQ(use_v2_header(), challenge_response_request_.has_value());
+  // Response header should always be set, even in error cases (i.e.
+  // use_v2_header is false).
+  EXPECT_TRUE(challenge_response_request_.has_value());
 
   ExpectFunnelStep(DTAttestationFunnelStep::kAttestationFlowStarted);
   ExpectFunnelStep(DTAttestationFunnelStep::kChallengeReceived);
-  ExpectFunnelStep(DTAttestationFunnelStep::kSignalsCollected);
+
+  EXPECT_EQ(challenge_response_request_->GetURL().path(),
+            GetRedirectLocationUrl().path());
+  const std::string& challenge_response =
+      challenge_response_request_->headers.find(kVerifiedAccessResponseHeader)
+          ->second;
 
   if (use_v2_header()) {
-    EXPECT_EQ(challenge_response_request_->GetURL().path(),
-              GetRedirectLocationUrl().path());
-
     // TODO(crbug.com/1241857): Add challenge-response validation.
-    const std::string& challenge_response =
-        challenge_response_request_->headers
-            .find(kVerifiedAccessResponseHeader)
-            ->second;
     EXPECT_TRUE(!challenge_response.empty());
 
+    ExpectFunnelStep(DTAttestationFunnelStep::kSignalsCollected);
     ExpectFunnelStep(DTAttestationFunnelStep::kChallengeResponseSent);
     histogram_tester_.ExpectUniqueSample(kResultHistogramName,
                                          DTAttestationResult::kSuccess, 1);
     histogram_tester_.ExpectTotalCount(kLatencySuccessHistogramName, 1);
     histogram_tester_.ExpectTotalCount(kLatencyFailureHistogramName, 0);
   } else {
+    static constexpr char kFailedToParseChallengeJsonResponse[] =
+        "{\"error\":\"failed_to_parse_challenge\"}";
+    EXPECT_EQ(challenge_response, kFailedToParseChallengeJsonResponse);
+    histogram_tester_.ExpectBucketCount(
+        kFunnelHistogramName, DTAttestationFunnelStep::kSignalsCollected, 0);
     histogram_tester_.ExpectBucketCount(
         kFunnelHistogramName, DTAttestationFunnelStep::kChallengeResponseSent,
         0);
-    histogram_tester_.ExpectUniqueSample(
-        kResultHistogramName, DTAttestationResult::kBadChallengeFormat, 1);
+    histogram_tester_.ExpectTotalCount(kResultHistogramName, 0);
     histogram_tester_.ExpectTotalCount(kLatencySuccessHistogramName, 0);
     histogram_tester_.ExpectTotalCount(kLatencyFailureHistogramName, 1);
   }
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc
index 0a6fa70..f5901cb4 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc
@@ -46,6 +46,12 @@
   return;
 }
 
+DeviceTrustResponse CreateFailedResponse(DeviceTrustError error) {
+  DeviceTrustResponse response;
+  response.error = error;
+  return response;
+}
+
 }  // namespace
 
 using CollectSignalsCallback = SignalsService::CollectSignalsCallback;
@@ -70,10 +76,11 @@
   return connector_ && connector_->IsConnectorEnabled();
 }
 
-void DeviceTrustService::BuildChallengeResponse(const std::string& challenge,
-                                                AttestationCallback callback) {
+void DeviceTrustService::BuildChallengeResponse(
+    const std::string& serialized_challenge,
+    DeviceTrustCallback callback) {
   ParseJsonChallenge(
-      challenge,
+      serialized_challenge,
       base::BindOnce(&DeviceTrustService::OnChallengeParsed,
                      weak_factory_.GetWeakPtr(), std::move(callback)));
 }
@@ -83,41 +90,55 @@
 }
 
 void DeviceTrustService::ParseJsonChallenge(
-    const std::string& challenge,
+    const std::string& serialized_challenge,
     ParseJsonChallengeCallback callback) {
-  data_decoder_.ParseJson(challenge,
+  data_decoder_.ParseJson(serialized_challenge,
                           base::BindOnce(&OnJsonParsed, std::move(callback)));
 }
 
-void DeviceTrustService::OnChallengeParsed(
-    AttestationCallback callback,
-    const std::string& serialized_signed_challenge) {
+void DeviceTrustService::OnChallengeParsed(DeviceTrustCallback callback,
+                                           const std::string& challenge) {
+  if (challenge.empty()) {
+    // Failed to parse the challenge, fail early.
+    std::move(callback).Run(
+        CreateFailedResponse(DeviceTrustError::kFailedToParseChallenge));
+    return;
+  }
+
   GetSignals(base::BindOnce(&DeviceTrustService::OnSignalsCollected,
-                            weak_factory_.GetWeakPtr(),
-                            serialized_signed_challenge, std::move(callback)));
+                            weak_factory_.GetWeakPtr(), challenge,
+                            std::move(callback)));
 }
 
 void DeviceTrustService::GetSignals(CollectSignalsCallback callback) {
   return signals_service_->CollectSignals(std::move(callback));
 }
 
-void DeviceTrustService::OnSignalsCollected(
-    const std::string& serialized_signed_challenge,
-    AttestationCallback callback,
-    base::Value::Dict signals) {
+void DeviceTrustService::OnSignalsCollected(const std::string& challenge,
+                                            DeviceTrustCallback callback,
+                                            base::Value::Dict signals) {
   LogAttestationFunnelStep(DTAttestationFunnelStep::kSignalsCollected);
 
   attestation_service_->BuildChallengeResponseForVAChallenge(
-      serialized_signed_challenge, std::move(signals),
+      challenge, std::move(signals),
       base::BindOnce(&DeviceTrustService::OnAttestationResponseReceived,
                      weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void DeviceTrustService::OnAttestationResponseReceived(
-    AttestationCallback callback,
-    const AttestationResponse& response) {
-  LogAttestationResult(response.result_code);
-  std::move(callback).Run(response.challenge_response);
+    DeviceTrustCallback callback,
+    const AttestationResponse& attestation_response) {
+  LogAttestationResult(attestation_response.result_code);
+
+  DeviceTrustResponse dt_response{};
+  dt_response.challenge_response = attestation_response.challenge_response;
+  dt_response.attestation_result = attestation_response.result_code;
+
+  if (attestation_response.result_code != DTAttestationResult::kSuccess) {
+    dt_response.error = DeviceTrustError::kFailedToCreateResponse;
+  }
+
+  std::move(callback).Run(dt_response);
 }
 
 }  // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h
index 7547f4a..5c652381 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h
@@ -21,6 +21,7 @@
 struct AttestationResponse;
 class AttestationService;
 class DeviceTrustConnectorService;
+struct DeviceTrustResponse;
 class SignalsService;
 
 // Main service used to drive device trust connector scenarios. It is currently
@@ -28,7 +29,8 @@
 // Access during an attestation flow.
 class DeviceTrustService : public KeyedService {
  public:
-  using AttestationCallback = base::OnceCallback<void(const std::string&)>;
+  using DeviceTrustCallback =
+      base::OnceCallback<void(const DeviceTrustResponse&)>;
 
   // Callback used by the data_decoder to get the parsed json result.
   using ParseJsonChallengeCallback =
@@ -47,9 +49,12 @@
   // any task sequence.
   virtual bool IsEnabled() const;
 
-  // Starts flow that actually builds a response.
-  virtual void BuildChallengeResponse(const std::string& challenge,
-                                      AttestationCallback callback);
+  // Uses the challenge stored in `serialized_challenge` to generate a
+  // challenge-response containing device signals and a device identity
+  // signature to be used in an attestation flow. Returns the challenge response
+  // asynchronously via `callback`.
+  virtual void BuildChallengeResponse(const std::string& serialized_challenge,
+                                      DeviceTrustCallback callback);
 
   // Returns whether the Device Trust connector watches navigations to the given
   // `url` or not.
@@ -58,8 +63,8 @@
   // Collects device trust signals and returns them via `callback`.
   void GetSignals(base::OnceCallback<void(base::Value::Dict)> callback);
 
-  // Parses the `challenge` response and returns it via a `callback`.
-  void ParseJsonChallenge(const std::string& challenge,
+  // Parses the `serialized_challenge` and returns its value via `callback`.
+  void ParseJsonChallenge(const std::string& serialized_challenge,
                           ParseJsonChallengeCallback callback);
 
  protected:
@@ -67,13 +72,14 @@
   DeviceTrustService();
 
  private:
-  void OnChallengeParsed(AttestationCallback callback,
-                         const std::string& serialized_signed_challenge);
+  void OnChallengeParsed(DeviceTrustCallback callback,
+                         const std::string& challenge);
   void OnSignalsCollected(const std::string& challenge,
-                          AttestationCallback callback,
+                          DeviceTrustCallback callback,
                           base::Value::Dict signals);
-  void OnAttestationResponseReceived(AttestationCallback callback,
-                                     const AttestationResponse& response);
+  void OnAttestationResponseReceived(
+      DeviceTrustCallback callback,
+      const AttestationResponse& attestation_response);
 
   std::unique_ptr<AttestationService> attestation_service_;
   std::unique_ptr<SignalsService> signals_service_;
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc
index a828ca3..8522fc7 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc
@@ -10,11 +10,10 @@
 #include "base/base64.h"
 #include "base/json/json_reader.h"
 #include "base/memory/raw_ptr.h"
-#include "base/run_loop.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"
+#include "base/test/test_future.h"
 #include "base/values.h"
 #include "chrome/browser/enterprise/connectors/device_trust/attestation/common/mock_attestation_service.h"
 #include "chrome/browser/enterprise/connectors/device_trust/common/common_types.h"
@@ -83,7 +82,6 @@
 
 using test::MockAttestationService;
 using test::MockSignalsService;
-using AttestationCallback = DeviceTrustService::AttestationCallback;
 
 class DeviceTrustServiceTest
     : public testing::Test,
@@ -179,12 +177,16 @@
         std::move(callback).Run({challenge, result_code});
       }));
 
-  base::RunLoop run_loop;
+  base::test::TestFuture<const DeviceTrustResponse&> future;
   device_trust_service->BuildChallengeResponse(
       kJsonChallenge,
-      /*callback=*/base::BindLambdaForTesting(
-          [&run_loop](const std::string& response) { run_loop.Quit(); }));
-  run_loop.Run();
+      /*callback=*/future.GetCallback());
+
+  const DeviceTrustResponse& dt_response = future.Get();
+  EXPECT_FALSE(dt_response.challenge_response.empty());
+  EXPECT_FALSE(dt_response.error);
+  ASSERT_TRUE(dt_response.attestation_result);
+  EXPECT_EQ(dt_response.attestation_result.value(), result_code);
 
   histogram_tester_.ExpectUniqueSample(kResultHistogramName, result_code, 1);
 }
diff --git a/chrome/browser/enterprise/connectors/device_trust/mock_device_trust_service.h b/chrome/browser/enterprise/connectors/device_trust/mock_device_trust_service.h
index 6a70b9e..fe6b56f 100644
--- a/chrome/browser/enterprise/connectors/device_trust/mock_device_trust_service.h
+++ b/chrome/browser/enterprise/connectors/device_trust/mock_device_trust_service.h
@@ -19,7 +19,7 @@
   MOCK_METHOD(bool, IsEnabled, (), (const, override));
   MOCK_METHOD(void,
               BuildChallengeResponse,
-              (const std::string&, AttestationCallback),
+              (const std::string&, DeviceTrustCallback),
               (override));
   MOCK_METHOD(bool, Watches, (const GURL&), (const, override));
 };
diff --git a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.cc b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.cc
index 48ec4c5..08780a2 100644
--- a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.cc
@@ -4,9 +4,12 @@
 
 #include "chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h"
 
+#include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
+#include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/enterprise/connectors/connectors_prefs.h"
+#include "chrome/browser/enterprise/connectors/device_trust/common/common_types.h"
 #include "chrome/browser/enterprise/connectors/device_trust/common/metrics_utils.h"
 #include "chrome/browser/enterprise/connectors/device_trust/device_trust_features.h"
 #include "chrome/browser/enterprise/connectors/device_trust/device_trust_service.h"
@@ -24,24 +27,49 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+namespace enterprise_connectors {
+
+using DeviceTrustCallback = DeviceTrustService::DeviceTrustCallback;
+
 namespace {
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-enterprise_connectors::DTOrigin GetAttestationFlowOrigin(
-    content::BrowserContext* context) {
-  if (context->IsOffTheRecord() && ash::ProfileHelper::IsSigninProfile(
-                                       Profile::FromBrowserContext(context))) {
-    return enterprise_connectors::DTOrigin::kLoginScreen;
+constexpr char kErrorPropertyName[] = "error";
+constexpr char kSpecificErrorCodePropertyName[] = "code";
+
+const std::string CreateErrorJsonString(
+    const DeviceTrustResponse& dt_response) {
+  DCHECK(dt_response.error);
+  base::Value::Dict error_response;
+  error_response.Set(kErrorPropertyName,
+                     DeviceTrustErrorToString(dt_response.error.value()));
+
+  if (dt_response.attestation_result &&
+      dt_response.attestation_result.value() != DTAttestationResult::kSuccess) {
+    error_response.Set(
+        kSpecificErrorCodePropertyName,
+        AttestationResultToString(dt_response.attestation_result.value()));
   }
 
-  return enterprise_connectors::DTOrigin::kInSession;
+  std::string out_json;
+  if (!base::JSONWriter::Write(error_response, &out_json)) {
+    return "{\"error\":\"failed_to_serialize_error\"}";
+  }
+  return out_json;
+}
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+DTOrigin GetAttestationFlowOrigin(content::BrowserContext* context) {
+  if (context->IsOffTheRecord() && ash::ProfileHelper::IsSigninProfile(
+                                       Profile::FromBrowserContext(context))) {
+    return DTOrigin::kLoginScreen;
+  }
+
+  return DTOrigin::kInSession;
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace
 
-namespace enterprise_connectors {
-
 // Const headers used in the handshake flow.
 constexpr char kDeviceTrustHeader[] = "X-Device-Trust";
 constexpr char kDeviceTrustHeaderValue[] = "VerifiedAccess";
@@ -133,7 +161,7 @@
       // Create callback for `ReplyChallengeResponseAndResume` which will
       // be called after the challenge response is created. With this
       // we can defer the navigation to unblock the main thread.
-      AttestationCallback resume_navigation_callback = base::BindOnce(
+      DeviceTrustCallback resume_navigation_callback = base::BindOnce(
           &DeviceTrustNavigationThrottle::ReplyChallengeResponseAndResume,
           weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now());
 
@@ -149,7 +177,7 @@
           base::BindOnce(
               [](base::WeakPtr<DeviceTrustNavigationThrottle> throttler,
                  const std::string& challenge,
-                 AttestationCallback resume_navigation_callback) {
+                 DeviceTrustCallback resume_navigation_callback) {
                 if (throttler) {
                   throttler->device_trust_service_->BuildChallengeResponse(
                       challenge, std::move(resume_navigation_callback));
@@ -165,14 +193,28 @@
 
 void DeviceTrustNavigationThrottle::ReplyChallengeResponseAndResume(
     base::TimeTicks start_time,
-    const std::string& challenge_response) {
-  LogAttestationResponseLatency(start_time,
-                                /*success=*/!challenge_response.empty());
+    const DeviceTrustResponse& dt_response) {
+  // Make a copy to allow mutations.
+  auto copied_dt_response = dt_response;
 
-  if (!challenge_response.empty()) {
+  if (copied_dt_response.challenge_response.empty() &&
+      !copied_dt_response.error) {
+    // An empty `challenge_response` value must be treated as a failure. If
+    // `error` isn't set, then default-set it to unknown.
+    copied_dt_response.error = DeviceTrustError::kUnknown;
+  }
+
+  LogAttestationResponseLatency(start_time,
+                                /*success=*/!copied_dt_response.error);
+
+  if (copied_dt_response.error) {
+    navigation_handle()->SetRequestHeader(
+        kVerifiedAccessResponseHeader,
+        CreateErrorJsonString(copied_dt_response));
+  } else {
     LogAttestationFunnelStep(DTAttestationFunnelStep::kChallengeResponseSent);
-    navigation_handle()->SetRequestHeader(kVerifiedAccessResponseHeader,
-                                          challenge_response);
+    navigation_handle()->SetRequestHeader(
+        kVerifiedAccessResponseHeader, copied_dt_response.challenge_response);
   }
 
   Resume();
diff --git a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h
index 13887bc7..5f296a9 100644
--- a/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h
+++ b/chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h
@@ -14,6 +14,7 @@
 namespace enterprise_connectors {
 
 class DeviceTrustService;
+struct DeviceTrustResponse;
 
 // DeviceTrustNavigationThrottle provides a simple way to start a handshake
 // between Chrome and an origin based on a list of trusted URLs set in the
@@ -32,8 +33,6 @@
   static std::unique_ptr<DeviceTrustNavigationThrottle> MaybeCreateThrottleFor(
       content::NavigationHandle* navigation_handle);
 
-  using AttestationCallback = base::OnceCallback<void(const std::string&)>;
-
   DeviceTrustNavigationThrottle(DeviceTrustService* device_trust_service,
                                 content::NavigationHandle* navigation_handle);
 
@@ -53,11 +52,13 @@
   // Not owned.
   const raw_ptr<DeviceTrustService> device_trust_service_;
 
-  // Set `challege_response` into the header
+  // Resumes the navigation by setting a value into the header
   // `X-Verified-Access-Challenge-Response` of the redirection request to the
-  // IdP and resume the navigation.
+  // IdP and resume the navigation. That value is determined by the properties
+  // of `dt_response` which, when in success cases, contains a valid response
+  // string. `start_time` is used to measure the latency of the end-to-end flow.
   void ReplyChallengeResponseAndResume(base::TimeTicks start_time,
-                                       const std::string& challenge_response);
+                                       const DeviceTrustResponse& dt_response);
 
   base::WeakPtrFactory<DeviceTrustNavigationThrottle> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index a4a83b34..2201567 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -215,6 +215,18 @@
   return base::UTF16ToUTF8(std::u16string(1, ch));
 }
 
+// TODO(b/247441188): Change the input extension JS API to use
+// PersonalizationMode instead of a bool.
+bool ConvertPersonalizationMode(
+    const ui::TextInputMethod::InputContext& context) {
+  switch (context.personalization_mode) {
+    case ui::PersonalizationMode::kEnabled:
+      return true;
+    case ui::PersonalizationMode::kDisabled:
+      return false;
+  }
+}
+
 InputMethodEngine* GetEngineIfActive(Profile* profile,
                                      const std::string& extension_id,
                                      std::string* error) {
@@ -480,7 +492,8 @@
           ConvertInputContextSpellCheck(context.flags);
       private_api_input_context.has_been_password =
           ConvertHasBeenPassword(context);
-      private_api_input_context.should_do_learning = context.should_do_learning;
+      private_api_input_context.should_do_learning =
+          ConvertPersonalizationMode(context);
       private_api_input_context.focus_reason =
           input_method_private::ParseFocusReason(
               ConvertInputContextFocusReason(context));
@@ -509,7 +522,8 @@
           ConvertInputContextAutoCapitalizePublic(context.flags);
       public_api_input_context.spell_check =
           ConvertInputContextSpellCheck(context.flags);
-      public_api_input_context.should_do_learning = context.should_do_learning;
+      public_api_input_context.should_do_learning =
+          ConvertPersonalizationMode(context);
 
       auto args(input_ime::OnFocus::Create(public_api_input_context));
       DispatchEventToExtension(extensions::events::INPUT_IME_ON_FOCUS,
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
index 5bbd575..519c454 100644
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
@@ -695,6 +695,7 @@
 // descriptors. Used for languageSettingsPrivate.getInputMethodLists().
 void PopulateInputMethodListFromDescriptors(
     const InputMethodDescriptors& descriptors,
+    const PrefService* prefs,
     std::vector<language_settings_private::InputMethod>* input_methods) {
   InputMethodManager* manager = InputMethodManager::Get();
   InputMethodUtil* util = manager->GetInputMethodUtil();
@@ -719,6 +720,14 @@
       input_map(l10n_util::StringComparator<std::u16string>(collator.get()));
 
   for (const auto& descriptor : descriptors) {
+    if (base::EndsWith(descriptor.id(), "vkd_hi_inscript")) {
+      bool allow_hindi_inscript =
+          base::FeatureList::IsEnabled(
+              chromeos::features::kHindiInscriptLayout) ||
+          (prefs && (prefs->GetBoolean(prefs::kHindiInscriptLayoutEnabled)));
+      if (!allow_hindi_inscript)
+        continue;
+    }
     language_settings_private::InputMethod input_method;
     input_method.id = descriptor.id();
     input_method.display_name = util->GetLocalizedDisplayName(descriptor);
@@ -760,6 +769,7 @@
       manager->GetComponentExtensionIMEManager();
   PopulateInputMethodListFromDescriptors(
       component_extension_manager->GetAllIMEAsInputMethodDescriptor(),
+      Profile::FromBrowserContext(browser_context())->GetPrefs(),
       &input_method_lists.component_extension_imes);
 
   scoped_refptr<InputMethodManager::State> ime_state =
@@ -768,7 +778,8 @@
     InputMethodDescriptors ext_ime_descriptors;
     ime_state->GetInputMethodExtensions(&ext_ime_descriptors);
     PopulateInputMethodListFromDescriptors(
-        ext_ime_descriptors, &input_method_lists.third_party_extension_imes);
+        ext_ime_descriptors, nullptr,
+        &input_method_lists.third_party_extension_imes);
   }
 
   return RespondNow(WithArguments(input_method_lists.ToValue()));
diff --git a/chrome/browser/feed/android/BUILD.gn b/chrome/browser/feed/android/BUILD.gn
index 0e96b84..60d17919 100644
--- a/chrome/browser/feed/android/BUILD.gn
+++ b/chrome/browser/feed/android/BUILD.gn
@@ -174,7 +174,6 @@
     "java/res/drawable-v24/header_title_tab_selected_background.xml",
     "java/res/drawable-xhdpi/follow_accelerator_shadow.9.png",
     "java/res/drawable-xxhdpi/follow_accelerator_shadow.9.png",
-    "java/res/drawable/back_arrow.xml",
     "java/res/drawable/back_to_top_arrow.xml",
     "java/res/drawable/crow_icon.xml",
     "java/res/drawable/header_title_section_tab_background.xml",
diff --git a/chrome/browser/feed/android/java/res/drawable/back_arrow.xml b/chrome/browser/feed/android/java/res/drawable/back_arrow.xml
deleted file mode 100644
index 4609c08..0000000
--- a/chrome/browser/feed/android/java/res/drawable/back_arrow.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2022 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24"
-        android:autoMirrored="true">
-  <path
-      android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"
-      android:fillColor="@color/baseline_neutral_700"
-      android:fillType="nonZero"/>
-</vector>
diff --git a/chrome/browser/feed/android/java/res/layout/feed_options_panel.xml b/chrome/browser/feed/android/java/res/layout/feed_options_panel.xml
index 1c50c18..d07d159 100644
--- a/chrome/browser/feed/android/java/res/layout/feed_options_panel.xml
+++ b/chrome/browser/feed/android/java/res/layout/feed_options_panel.xml
@@ -15,17 +15,17 @@
     android:paddingVertical="@dimen/feed_options_vertical_margins"
     android:layout_marginBottom="@dimen/feed_options_vertical_margins"
     android:orientation="vertical"
-    android:visibility="gone"
-    android:importantForAccessibility="no">
+    android:visibility="gone">
     <TextView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         style="@style/TextAppearance.TextAccentMediumThick.Secondary"
         android:text="@string/sort_by"
-        android:paddingVertical="@dimen/feed_options_vertical_margins" />
+        android:paddingVertical="@dimen/feed_options_vertical_margins"
+        android:focusableInTouchMode="true"/>
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:id="@+id/chips_container"
         android:orientation="horizontal" />
-</org.chromium.chrome.browser.feed.sort_ui.FeedOptionsView>
\ No newline at end of file
+</org.chromium.chrome.browser.feed.sort_ui.FeedOptionsView>
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinator.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinator.java
index 3fcf399..85e1428 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinator.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinator.java
@@ -10,7 +10,6 @@
 import android.widget.ListView;
 
 import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
 
 import org.chromium.chrome.browser.feed.R;
 import org.chromium.chrome.browser.feed.StreamKind;
@@ -45,11 +44,6 @@
         ListView listView = (ListView) mView.findViewById(R.id.feed_management_menu);
         listView.setAdapter(adapter);
 
-        // Set up the toolbar and back button.
-        Toolbar toolbar = (Toolbar) mView.findViewById(R.id.action_bar);
-        toolbar.setNavigationIcon(R.drawable.back_arrow);
-        toolbar.setNavigationOnClickListener(this::handleBackArrowClick);
-
         mMediator = new FeedManagementMediator(mActivity, listItems, followManagementLauncher,
                 autoplayManagementLauncher, feedType);
     }
@@ -57,9 +51,4 @@
     public View getView() {
         return mView;
     }
-
-    private void handleBackArrowClick(View view) {
-        // Navigate back.
-        mActivity.finish();
-    }
 }
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinatorTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinatorTest.java
index efbc21e..dfca2ac 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinatorTest.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/feedmanagement/FeedManagementCoordinatorTest.java
@@ -7,10 +7,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.verify;
 
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.appcompat.widget.AppCompatImageButton;
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 
 import org.junit.Before;
@@ -25,7 +21,6 @@
 import org.chromium.chrome.browser.feed.FeedServiceBridge;
 import org.chromium.chrome.browser.feed.FeedServiceBridgeJni;
 import org.chromium.chrome.browser.feed.StreamKind;
-import org.chromium.chrome.browser.feed.test.R;
 import org.chromium.ui.base.TestActivity;
 
 /**
@@ -62,24 +57,4 @@
     public void testConstruction() {
         assertTrue(true);
     }
-
-    @Test
-    public void testBackArrow() {
-        View outerView = mFeedManagementCoordinator.getView();
-        // Send a click to the back arrow.
-        // Note that finding the back arrow view is ugly because it doesn't
-        // have an ID.
-        boolean clicked = false;
-        ViewGroup actionBar = outerView.findViewById(R.id.action_bar);
-        for (int i = 0; i < actionBar.getChildCount(); i++) {
-            try {
-                AppCompatImageButton button = (AppCompatImageButton) actionBar.getChildAt(i);
-                button.performClick();
-                clicked = true;
-            } catch (ClassCastException e) {
-            }
-        }
-
-        assertTrue(clicked);
-    }
 }
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinator.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinator.java
index c35b371..9f6a0faa 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinator.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinator.java
@@ -10,7 +10,6 @@
 import android.widget.LinearLayout;
 
 import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -55,11 +54,6 @@
         recyclerView.setLayoutManager(manager);
         recyclerView.setAdapter(adapter);
 
-        // Set up the toolbar and back button.
-        Toolbar toolbar = mView.findViewById(R.id.action_bar);
-        toolbar.setNavigationIcon(R.drawable.back_arrow);
-        toolbar.setNavigationOnClickListener(this::handleBackArrowClick);
-
         mMediator = new FollowManagementMediator(
                 activity, listItems, new MediatorObserver(), WebFeedFaviconFetcher.createDefault());
     }
@@ -68,11 +62,6 @@
         return mView;
     }
 
-    private void handleBackArrowClick(View view) {
-        // Navigate back.
-        mActivity.finish();
-    }
-
     private class MediatorObserver implements FollowManagementMediator.Observer {
         @Override
         public void networkConnectionError() {
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinatorTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinatorTest.java
index b75fdd9..286f5a43 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinatorTest.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/followmanagement/FollowManagementCoordinatorTest.java
@@ -8,10 +8,6 @@
 import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.verify;
 
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.appcompat.widget.AppCompatImageButton;
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 
 import org.junit.After;
@@ -24,7 +20,6 @@
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
-import org.chromium.chrome.browser.feed.test.R;
 import org.chromium.chrome.browser.feed.webfeed.WebFeedBridge;
 import org.chromium.chrome.browser.feed.webfeed.WebFeedBridgeJni;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -80,24 +75,4 @@
     public void testConstruction() {
         assertTrue(true);
     }
-
-    @Test
-    public void testBackArrow() {
-        View outerView = mFollowManagementCoordinator.getView();
-        // Send a click to the back arrow.
-        // Note that finding the back arrow view is ugly because it doesn't
-        // have an ID.
-        boolean clicked = false;
-        ViewGroup actionBar = (ViewGroup) outerView.findViewById(R.id.action_bar);
-        for (int i = 0; i < actionBar.getChildCount(); i++) {
-            try {
-                AppCompatImageButton button = (AppCompatImageButton) actionBar.getChildAt(i);
-                button.performClick();
-                clicked = true;
-            } catch (ClassCastException e) {
-            }
-        }
-
-        assertTrue(clicked);
-    }
 }
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java
index e814af0..bde3d8bb 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java
@@ -19,6 +19,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 import androidx.core.content.res.ResourcesCompat;
+import androidx.core.view.ViewCompat;
 import androidx.core.widget.ImageViewCompat;
 
 import com.google.android.material.tabs.TabLayout;
@@ -129,6 +130,8 @@
 
     private boolean mTextsEnabled;
     private @Px int mToolbarHeight;
+    // Action ID for accessibility.
+    private int mActionId = -1;
 
     public SectionHeaderView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
@@ -144,19 +147,29 @@
         TabLayout.Tab tab = mTabLayout.getTabAt(index);
 
         ImageView optionsIndicatorView = tab.view.findViewById(R.id.options_indicator);
-        if (optionsIndicatorView == null) return;
+        // Skip setting visibility if indicator isn't visible.
+        if (optionsIndicatorView == null || optionsIndicatorView.getVisibility() != View.VISIBLE) {
+            return;
+        }
+
+        int actionTitleId;
 
         if (isVisible) {
             optionsIndicatorView.setImageDrawable(ResourcesCompat.getDrawable(
                     getResources(), R.drawable.mtrl_ic_arrow_drop_up, getContext().getTheme()));
-            tab.setContentDescription(getTabState(tab).text
-                    + getResources().getString(R.string.feed_options_dropdown_description_close));
+            actionTitleId = R.string.feed_options_dropdown_description_close;
         } else {
             optionsIndicatorView.setImageDrawable(ResourcesCompat.getDrawable(
                     getResources(), R.drawable.mtrl_ic_arrow_drop_down, getContext().getTheme()));
-            tab.setContentDescription(getTabState(tab).text
-                    + getResources().getString(R.string.feed_options_dropdown_description));
+            actionTitleId = R.string.feed_options_dropdown_description;
         }
+
+        ViewCompat.removeAccessibilityAction(tab.view, mActionId);
+        mActionId = ViewCompat.addAccessibilityAction(
+                tab.view, getResources().getString(actionTitleId), (view, arguments) -> {
+                    mTabListener.onTabReselected(tab);
+                    return true;
+                });
     }
 
     @Override
@@ -184,6 +197,9 @@
         mMenuView.addOnLayoutChangeListener(
                 (View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                         int oldRight, int oldBottom) -> adjustMenuTouchDelegate(touchSize));
+
+        // Ensures that the whole header doesn't get focused for a11y.
+        setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
     }
 
     /** Updates header text for this view. */
@@ -262,12 +278,13 @@
         ImageView image = tab.view.findViewById(R.id.options_indicator);
         image.setVisibility(ViewVisibility.toVisibility(visibility));
 
-        // Child a11y aren't included in the tab's readout. Add together if visible.
         if (visibility == ViewVisibility.VISIBLE) {
-            tab.setContentDescription(getTabState(tab).text
-                    + getResources().getString(R.string.feed_options_dropdown_description));
+            tab.view.setClickable(true);
+            // Sets up a11y and ensures indicator is pointing in the right direction.
+            updateDrawable(index, false);
         } else {
-            tab.setContentDescription(getTabState(tab).text);
+            // If not visible, remove the expand/collapse actions.
+            ViewCompat.removeAccessibilityAction(tab.view, mActionId);
         }
     }
 
diff --git a/chrome/browser/first_party_sets/BUILD.gn b/chrome/browser/first_party_sets/BUILD.gn
index ccba188..7dbeb63 100644
--- a/chrome/browser/first_party_sets/BUILD.gn
+++ b/chrome/browser/first_party_sets/BUILD.gn
@@ -21,6 +21,8 @@
     "first_party_sets_policy_service_factory.h",
     "first_party_sets_pref_names.cc",
     "first_party_sets_pref_names.h",
+    "mock_first_party_sets_handler.cc",
+    "mock_first_party_sets_handler.h",
   ]
   deps = [
     "//base",
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
index 1b96d5a8..7488835 100644
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/first_party_sets_handler.h"
 #include "content/public/common/content_features.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
 #include "net/first_party_sets/first_party_sets_context_config.h"
 #include "services/network/public/mojom/first_party_sets_access_delegate.mojom.h"
 
@@ -21,9 +22,11 @@
 namespace {
 
 network::mojom::FirstPartySetsReadyEventPtr MakeReadyEvent(
-    net::FirstPartySetsContextConfig config) {
+    net::FirstPartySetsContextConfig config,
+    net::FirstPartySetsCacheFilter cache_filter) {
   auto ready_event = network::mojom::FirstPartySetsReadyEvent::New();
   ready_event->config = std::move(config);
+  ready_event->cache_filter = std::move(cache_filter);
   return ready_event;
 }
 
@@ -70,7 +73,8 @@
         get_config) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!base::FeatureList::IsEnabled(features::kFirstPartySets)) {
-    OnReadyToNotifyDelegates(net::FirstPartySetsContextConfig());
+    OnReadyToNotifyDelegates(net::FirstPartySetsContextConfig(),
+                             net::FirstPartySetsCacheFilter());
     return;
   }
 
@@ -81,7 +85,8 @@
   // Checks that `profile` isn't a system profile or a guest profile before
   // returning a pointer to the value of the First-Party Sets Overrides policy.
   if (profile->IsSystemProfile() || profile->IsGuestSession()) {
-    OnReadyToNotifyDelegates(net::FirstPartySetsContextConfig());
+    OnReadyToNotifyDelegates(net::FirstPartySetsContextConfig(),
+                             net::FirstPartySetsCacheFilter());
     return;
   }
 
@@ -104,11 +109,12 @@
     mojo::Remote<network::mojom::FirstPartySetsAccessDelegate>
         access_delegate) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (config_.has_value()) {
+  if (config_.has_value() && cache_filter_.has_value()) {
     // Since the list of First-Party Sets is static after initialization and
     // the FirstPartySetsOverrides policy doesn't support dynamic refresh, a
     // profile's `config_` is static as well.
-    access_delegate->NotifyReady(MakeReadyEvent(config_->Clone()));
+    access_delegate->NotifyReady(
+        MakeReadyEvent(config_->Clone(), cache_filter_->Clone()));
   }
   access_delegates_.Add(std::move(access_delegate));
 }
@@ -147,7 +153,8 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!initially_enabled) {
-    OnReadyToNotifyDelegates(std::move(config));
+    OnReadyToNotifyDelegates(std::move(config),
+                             net::FirstPartySetsCacheFilter());
     return;
   }
 
@@ -155,7 +162,8 @@
   if (!profile->IsRegularProfile() || profile->IsGuestSession()) {
     // TODO(https://crbug.com/1348572): regular profiles and guest sessions
     // aren't mutually exclusive on ChromeOS.
-    OnReadyToNotifyDelegates(std::move(config));
+    OnReadyToNotifyDelegates(std::move(config),
+                             net::FirstPartySetsCacheFilter());
     return;
   }
 
@@ -202,12 +210,15 @@
 }
 
 void FirstPartySetsPolicyService::OnReadyToNotifyDelegates(
-    net::FirstPartySetsContextConfig config) {
+    net::FirstPartySetsContextConfig config,
+    net::FirstPartySetsCacheFilter cache_filter) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   config_ = std::move(config);
+  cache_filter_ = std::move(cache_filter);
   first_initialization_complete_for_testing_ = true;
   for (auto& delegate : access_delegates_) {
-    delegate->NotifyReady(MakeReadyEvent(config_.value().Clone()));
+    delegate->NotifyReady(
+        MakeReadyEvent(config_.value().Clone(), cache_filter_.value().Clone()));
   }
 
   if (on_first_init_complete_for_testing_.has_value()) {
@@ -219,6 +230,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   access_delegates_.Clear();
   config_.reset();
+  cache_filter_.reset();
   on_first_init_complete_for_testing_.reset();
   // Note: `first_initialization_complete_for_testing_` is intentionally not
   // reset here.
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.h b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
index d1f86460..93370f8f 100644
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.h
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
@@ -11,7 +11,6 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
-#include "net/first_party_sets/first_party_sets_context_config.h"
 #include "services/network/public/mojom/first_party_sets_access_delegate.mojom.h"
 
 class PrefService;
@@ -21,6 +20,8 @@
 }  // namespace content
 
 namespace net {
+class FirstPartySetsCacheFilter;
+class FirstPartySetsContextConfig;
 class SchemefulSite;
 }  // namespace net
 
@@ -112,7 +113,8 @@
                 get_config);
 
   // Sets the `config_` member and provides it to all delegates via NotifyReady.
-  void OnReadyToNotifyDelegates(net::FirstPartySetsContextConfig config);
+  void OnReadyToNotifyDelegates(net::FirstPartySetsContextConfig config,
+                                net::FirstPartySetsCacheFilter cache_filter);
 
   // Triggers changes that occur once the FirstPartySetsContextConfig for the
   // profile that created this service is retrieved.
@@ -138,6 +140,10 @@
   absl::optional<net::FirstPartySetsContextConfig> config_
       GUARDED_BY_CONTEXT(sequence_checker_);
 
+  // The filter used to bypass cache access in the network for this profile.
+  absl::optional<net::FirstPartySetsCacheFilter> cache_filter_
+      GUARDED_BY_CONTEXT(sequence_checker_);
+
   // Callback used by tests to wait for the ctor's initialization flow to
   // complete.
   absl::optional<base::OnceClosure> on_first_init_complete_for_testing_;
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc
index 2899653..7b5a312 100644
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/first_party_sets/first_party_sets_policy_service.h"
 
+#include "base/callback.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
 #include "chrome/browser/first_party_sets/first_party_sets_policy_service_factory.h"
+#include "chrome/browser/first_party_sets/mock_first_party_sets_handler.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
@@ -29,6 +31,12 @@
   return ExplainMatchResult(testing::Eq(config), arg->config, result_listener);
 }
 
+MATCHER_P2(CarryingConfigAndCacheFilter, config, cache_filter, "") {
+  if (arg.is_null())
+    return false;
+  return arg->config == config && arg->cache_filter == cache_filter;
+}
+
 namespace first_party_sets {
 
 class MockFirstPartySetsAccessDelegate
@@ -76,9 +84,11 @@
   service->AddRemoteAccessDelegate(std::move(mock_delegate_remote_));
 
   net::FirstPartySetsContextConfig config;
+  net::FirstPartySetsCacheFilter cache_filter;
 
   // Ensure NotifyReady is called with the empty config.
-  EXPECT_CALL(mock_delegate, NotifyReady(CarryingConfig(std::ref(config))))
+  EXPECT_CALL(mock_delegate, NotifyReady(CarryingConfigAndCacheFilter(
+                                 std::ref(config), std::ref(cache_filter))))
       .Times(1);
 
   env().RunUntilIdle();
@@ -96,9 +106,11 @@
   service->AddRemoteAccessDelegate(std::move(mock_delegate_remote_));
 
   net::FirstPartySetsContextConfig config;
+  net::FirstPartySetsCacheFilter cache_filter;
 
   // Ensure NotifyReady is called with the empty config.
-  EXPECT_CALL(mock_delegate, NotifyReady(CarryingConfig(std::ref(config))))
+  EXPECT_CALL(mock_delegate, NotifyReady(CarryingConfigAndCacheFilter(
+                                 std::ref(config), std::ref(cache_filter))))
       .Times(1);
 
   env().RunUntilIdle();
@@ -113,9 +125,11 @@
   service->AddRemoteAccessDelegate(std::move(mock_delegate_remote_));
 
   net::FirstPartySetsContextConfig config;
+  net::FirstPartySetsCacheFilter cache_filter;
 
   // Ensure NotifyReady is called with the empty config.
-  EXPECT_CALL(mock_delegate, NotifyReady(CarryingConfig(std::ref(config))))
+  EXPECT_CALL(mock_delegate, NotifyReady(CarryingConfigAndCacheFilter(
+                                 std::ref(config), std::ref(cache_filter))))
       .Times(1);
 
   env().RunUntilIdle();
@@ -420,4 +434,59 @@
   env().RunUntilIdle();
 }
 
+class FirstPartySetsPolicyServiceWithMockHandlerTest
+    : public FirstPartySetsPolicyServiceTest {
+ public:
+  FirstPartySetsPolicyServiceWithMockHandlerTest() = default;
+
+  void SetUp() override {
+    FirstPartySetsPolicyServiceTest::SetUp();
+
+    content::FirstPartySetsHandler::GetInstance()->SetInstanceForTesting(
+        &first_party_sets_handler_);
+  }
+
+  void TearDown() override {
+    FirstPartySetsPolicyServiceTest::TearDown();
+    first_party_sets_handler_.ResetForTesting();
+    content::FirstPartySetsHandler::GetInstance()->SetInstanceForTesting(
+        nullptr);
+  }
+
+  void SetContextConfig(net::FirstPartySetsContextConfig config) {
+    first_party_sets_handler_.SetContextConfig(std::move(config));
+  }
+  void SetCacheFilter(net::FirstPartySetsCacheFilter cache_filter) {
+    first_party_sets_handler_.SetCacheFilter(std::move(cache_filter));
+  }
+
+ private:
+  MockFirstPartySetsHandler first_party_sets_handler_;
+  base::test::ScopedFeatureList features_;
+};
+
+TEST_F(FirstPartySetsPolicyServiceWithMockHandlerTest,
+       NotifiesReadyWithConfigAndCacheFilter) {
+  net::SchemefulSite test_primary(GURL("https://a.test"));
+  net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary,
+                                     absl::nullopt);
+  net::FirstPartySetsContextConfig test_config({{test_primary, {test_entry}}});
+  net::FirstPartySetsCacheFilter test_cache_filter({{test_primary, 1}},
+                                                   /*browser_run_id=*/1);
+  SetContextConfig(test_config.Clone());
+  SetCacheFilter(test_cache_filter.Clone());
+  service()->InitForTesting(
+      [&](PrefService* prefs,
+          base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
+        std::move(callback).Run(test_config.Clone());
+      });
+
+  EXPECT_CALL(mock_delegate,
+              NotifyReady(CarryingConfigAndCacheFilter(
+                  std::ref(test_config), std::ref(test_cache_filter))))
+      .Times(1);
+
+  env().RunUntilIdle();
+}
+
 }  // namespace first_party_sets
diff --git a/chrome/browser/first_party_sets/mock_first_party_sets_handler.cc b/chrome/browser/first_party_sets/mock_first_party_sets_handler.cc
new file mode 100644
index 0000000..2139a94e
--- /dev/null
+++ b/chrome/browser/first_party_sets/mock_first_party_sets_handler.cc
@@ -0,0 +1,76 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/first_party_sets/mock_first_party_sets_handler.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/types/optional_util.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
+#include "net/first_party_sets/first_party_sets_context_config.h"
+#include "net/first_party_sets/global_first_party_sets.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace first_party_sets {
+
+MockFirstPartySetsHandler::MockFirstPartySetsHandler() = default;
+MockFirstPartySetsHandler::~MockFirstPartySetsHandler() = default;
+
+bool MockFirstPartySetsHandler::IsEnabled() const {
+  return true;
+}
+
+void MockFirstPartySetsHandler::SetPublicFirstPartySets(
+    const base::Version& version,
+    base::File sets_file) {}
+
+void MockFirstPartySetsHandler::SetGlobalSetsForTesting(
+    net::GlobalFirstPartySets global_sets) {
+  global_sets_ = std::move(global_sets);
+}
+
+absl::optional<net::FirstPartySetEntry> MockFirstPartySetsHandler::FindEntry(
+    const net::SchemefulSite& site,
+    const net::FirstPartySetsContextConfig& config) const {
+  if (!global_sets_.has_value()) {
+    return absl::nullopt;
+  }
+  return global_sets_->FindEntry(site, config);
+}
+
+void MockFirstPartySetsHandler::GetContextConfigForPolicy(
+    const base::Value::Dict* policy,
+    base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
+  DCHECK(config_.has_value()) << " Need to call SetContextConfig first.";
+  std::move(callback).Run(config_->Clone());
+}
+
+void MockFirstPartySetsHandler::ClearSiteDataOnChangedSetsForContext(
+    base::RepeatingCallback<content::BrowserContext*()> browser_context_getter,
+    const std::string& browser_context_id,
+    net::FirstPartySetsContextConfig context_config,
+    base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                            net::FirstPartySetsCacheFilter)> callback) {
+  DCHECK(config_.has_value()) << " Need to call SetContextConfig first.";
+  DCHECK(cache_filter_.has_value()) << " Need to call SetCacheFilter first.";
+  std::move(callback).Run(config_->Clone(), cache_filter_->Clone());
+}
+
+void MockFirstPartySetsHandler::ResetForTesting() {
+  global_sets_ = absl::nullopt;
+  config_ = absl::nullopt;
+  cache_filter_ = absl::nullopt;
+}
+
+void MockFirstPartySetsHandler::SetContextConfig(
+    net::FirstPartySetsContextConfig config) {
+  config_ = std::move(config);
+}
+void MockFirstPartySetsHandler::SetCacheFilter(
+    net::FirstPartySetsCacheFilter cache_filter) {
+  cache_filter_ = std::move(cache_filter);
+}
+
+}  // namespace first_party_sets
diff --git a/chrome/browser/first_party_sets/mock_first_party_sets_handler.h b/chrome/browser/first_party_sets/mock_first_party_sets_handler.h
new file mode 100644
index 0000000..a452bff
--- /dev/null
+++ b/chrome/browser/first_party_sets/mock_first_party_sets_handler.h
@@ -0,0 +1,72 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_FIRST_PARTY_SETS_MOCK_FIRST_PARTY_SETS_HANDLER_H_
+#define CHROME_BROWSER_FIRST_PARTY_SETS_MOCK_FIRST_PARTY_SETS_HANDLER_H_
+
+#include <string>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "content/public/browser/first_party_sets_handler.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
+#include "net/first_party_sets/first_party_sets_context_config.h"
+#include "net/first_party_sets/global_first_party_sets.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace base {
+class Version;
+class File;
+class Value;
+}  // namespace base
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace first_party_sets {
+
+// Used to create a dummy FirstPartySetsHandler implementation for testing
+// purposes. Enabled by default.
+class MockFirstPartySetsHandler : public content::FirstPartySetsHandler {
+ public:
+  MockFirstPartySetsHandler();
+  ~MockFirstPartySetsHandler() override;
+
+  // FirstPartySetsHandler:
+  bool IsEnabled() const override;
+  void SetPublicFirstPartySets(const base::Version& version,
+                               base::File sets_file) override;
+  void ResetForTesting() override;
+  void SetGlobalSetsForTesting(net::GlobalFirstPartySets global_sets) override;
+  absl::optional<net::FirstPartySetEntry> FindEntry(
+      const net::SchemefulSite& site,
+      const net::FirstPartySetsContextConfig& config) const override;
+  void GetContextConfigForPolicy(
+      const base::Value::Dict* policy,
+      base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback)
+      override;
+  void ClearSiteDataOnChangedSetsForContext(
+      base::RepeatingCallback<content::BrowserContext*()>
+          browser_context_getter,
+      const std::string& browser_context_id,
+      net::FirstPartySetsContextConfig context_config,
+      base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                              net::FirstPartySetsCacheFilter)> callback)
+      override;
+
+  // Helper functions for tests to set up context.
+  void SetContextConfig(net::FirstPartySetsContextConfig config);
+  void SetCacheFilter(net::FirstPartySetsCacheFilter cache_filter);
+
+ private:
+  absl::optional<net::GlobalFirstPartySets> global_sets_;
+  absl::optional<net::FirstPartySetsContextConfig> config_;
+  absl::optional<net::FirstPartySetsCacheFilter> cache_filter_;
+};
+
+}  // namespace first_party_sets
+
+#endif  // CHROME_BROWSER_FIRST_PARTY_SETS_MOCK_FIRST_PARTY_SETS_HANDLER_H_
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 4655c46e..d6df92d 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1680,6 +1680,11 @@
     "expiry_milestone": 110
   },
   {
+    "name": "enable-accessibility-select-to-speak-hover-text-improvements",
+    "owners": [ "josiahk", "//ui/accessibility/OWNERS" ],
+    "expiry_milestone": 130
+  },
+  {
     "name": "enable-accessibility-select-to-speak-page-migration",
     "owners": [ "josiahk", "//ui/accessibility/OWNERS" ],
     "expiry_milestone": 120
@@ -1827,6 +1832,11 @@
     "expiry_milestone":120
   },
   {
+    "name": "enable-check-visibility-on-attention-log-start",
+    "owners": [ "sczs", "tinazwang" ],
+    "expiry_milestone": 120
+  },
+  {
     "name": "enable-chrome-management-page-android",
     "owners": [ "ogastorga", "ftirelo" ],
     "expiry_milestone": 107
@@ -2901,6 +2911,11 @@
     "expiry_milestone": -1
   },
   {
+    "name": "enable-refine-data-source-reload-reporting",
+    "owners": [ "sczs", "tinazwang" ],
+    "expiry_milestone": 120
+  },
+  {
     "name": "enable-region-search-on-pdf-viewer",
     "owners": ["nguyenbryan@google.com"],
     "expiry_milestone": 120
@@ -3587,6 +3602,11 @@
     "expiry_milestone": 120
   },
   {
+    "name": "fedcm-metrics-endpoint",
+    "owners": ["yigu", "web-identity-eng@google.com"],
+    "expiry_milestone": 120
+  },
+  {
     "name": "fedcm-multi-idp",
     "owners": ["npm", "web-identity-eng@google.com"],
     "expiry_milestone": 120
@@ -5223,6 +5243,11 @@
     "expiry_milestone": 110
   },
   {
+    "name": "omnibox-uniform-suggestion-height",
+    "owners": [ "yohanes@google.com", "manukh", "chrome-omnibox-team@google.com"],
+    "expiry_milestone": 110
+  },
+  {
     "name": "omnibox-updated-connection-security-indicators",
     "owners": [ "meacer", "chrome-trusty-transport@google.com" ],
     "expiry_milestone": 110
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 6510f3cb..1fedefc 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -704,11 +704,6 @@
 const char kCommerceHintAndroidDescription[] =
     "Enables commerce hint detection on Android.";
 
-const char kConsolidatedSiteStorageControlsName[] =
-    "Consolidated Site Storage Controls";
-const char kConsolidatedSiteStorageControlsDescription[] =
-    "Enables the consolidated version of Site Storage controls in settings";
-
 const char kConsumerAutoUpdateToggleAllowedName[] =
     "Allow Consumer Auto Update Toggle";
 const char kConsumerAutoUpdateToggleAllowedDescription[] =
@@ -1069,6 +1064,12 @@
     "This option enables Select-to-Speak page migration from extension options "
     "page to a Chrome OS settings page.";
 
+const char kAccessibilitySelectToSpeakHoverTextImprovementsName[] =
+    "Select-to-Speak Hover Text Improvements";
+const char kAccessibilitySelectToSpeakHoverTextImprovementsDescription[] =
+    "This option enables improvements in the text shown when hovering over the "
+    "Select-to-Speak feature icon in the system tray.";
+
 const char kPostQuantumCECPQ2Name[] = "TLS Post-Quantum Confidentiality";
 const char kPostQuantumCECPQ2Description[] =
     "This option enables a post-quantum (i.e. resistent to quantum computers) "
@@ -1512,6 +1513,11 @@
 const char kFedCmDescription[] =
     "Enables JavaScript API to intermediate federated identity requests.";
 
+const char kFedCmMetricsEndpointName[] = "FedCmMetricsEndpoint";
+const char kFedCmMetricsEndpointDescription[] =
+    "Allows the FedCM API to send performance measurement to the metrics "
+    "endpoint on the identity provider side. Requires FedCM to be enabled.";
+
 const char kFedCmMultiIdpName[] = "FedCmMultiIdp";
 const char kFedCmMultiIdpDescription[] =
     "Allows the FedCM API to request multiple identity providers "
@@ -2181,6 +2187,11 @@
     "Changes the maximum number of autocomplete matches displayed in the "
     "Omnibox UI.";
 
+const char kOmniboxSimplifiedUiUniformRowHeightName[] =
+    "Omnibox Suggestion Row Height";
+const char kOmniboxSimplifiedUiUniformRowHeightDescription[] =
+    "Changes the row height of omnibox suggetions.";
+
 const char kOmniboxUpdatedConnectionSecurityIndicatorsName[] =
     "Omnibox Updated connection security indicators";
 const char kOmniboxUpdatedConnectionSecurityIndicatorsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 7700846e..99c5223 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -376,9 +376,6 @@
 extern const char kCommerceHintAndroidName[];
 extern const char kCommerceHintAndroidDescription[];
 
-extern const char kConsolidatedSiteStorageControlsName[];
-extern const char kConsolidatedSiteStorageControlsDescription[];
-
 extern const char kConsumerAutoUpdateToggleAllowedName[];
 extern const char kConsumerAutoUpdateToggleAllowedDescription[];
 
@@ -611,6 +608,9 @@
 extern const char kAccessibilitySelectToSpeakPrefsMigrationName[];
 extern const char kAccessibilitySelectToSpeakPrefsMigrationDescription[];
 
+extern const char kAccessibilitySelectToSpeakHoverTextImprovementsName[];
+extern const char kAccessibilitySelectToSpeakHoverTextImprovementsDescription[];
+
 extern const char kPostQuantumCECPQ2Name[];
 extern const char kPostQuantumCECPQ2Description[];
 
@@ -841,6 +841,9 @@
 extern const char kFedCmName[];
 extern const char kFedCmDescription[];
 
+extern const char kFedCmMetricsEndpointName[];
+extern const char kFedCmMetricsEndpointDescription[];
+
 extern const char kFedCmMultiIdpName[];
 extern const char kFedCmMultiIdpDescription[];
 
@@ -1224,6 +1227,9 @@
 extern const char kOmniboxUIMaxAutocompleteMatchesName[];
 extern const char kOmniboxUIMaxAutocompleteMatchesDescription[];
 
+extern const char kOmniboxSimplifiedUiUniformRowHeightName[];
+extern const char kOmniboxSimplifiedUiUniformRowHeightDescription[];
+
 extern const char kOmniboxUpdatedConnectionSecurityIndicatorsName[];
 extern const char kOmniboxUpdatedConnectionSecurityIndicatorsDescription[];
 
diff --git a/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros.cc b/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros.cc
index 8ee2909..12a90a14 100644
--- a/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros.cc
+++ b/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros.cc
@@ -119,6 +119,17 @@
   ash_remote_apps_remote_->DeleteApp(app_id, std::move(callback));
 }
 
+void RemoteAppsProxyLacros::SortLauncherWithRemoteAppsFirst(
+    SortLauncherWithRemoteAppsFirstCallback callback) {
+  if (!ash_remote_apps_remote_.is_bound() ||
+      !ash_remote_apps_remote_.is_connected()) {
+    std::move(callback).Run(kErrorNoAshRemoteConnected);
+    return;
+  }
+
+  ash_remote_apps_remote_->SortLauncherWithRemoteAppsFirst(std::move(callback));
+}
+
 void RemoteAppsProxyLacros::OnRemoteAppLaunched(const std::string& app_id,
                                                 const std::string& source_id) {
   std::unique_ptr<extensions::Event> event = std::make_unique<
diff --git a/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros.h b/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros.h
index 6ac65bd8..97343da9 100644
--- a/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros.h
+++ b/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros.h
@@ -76,6 +76,8 @@
               AddAppCallback callback) override;
   void DeleteApp(const std::string& app_id,
                  DeleteAppCallback callback) override;
+  void SortLauncherWithRemoteAppsFirst(
+      SortLauncherWithRemoteAppsFirstCallback callback) override;
 
   // remote_apps::mojom::RemoteAppLaunchObserver:
   void OnRemoteAppLaunched(const std::string& app_id,
diff --git a/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros_unittest.cc b/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros_unittest.cc
index 6130e3c..d18ca24 100644
--- a/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros_unittest.cc
+++ b/chrome/browser/lacros/remote_apps/remote_apps_proxy_lacros_unittest.cc
@@ -39,6 +39,8 @@
 using AddFolderCallback = base::OnceCallback<void(AddFolderResultPtr)>;
 using DeleteAppCallback =
     base::OnceCallback<void(const absl::optional<std::string>&)>;
+using SortLauncherWithRemoteAppsFirstCallback =
+    base::OnceCallback<void(const absl::optional<std::string>&)>;
 
 using testing::_;
 
@@ -78,6 +80,10 @@
               DeleteApp,
               (const std::string&, DeleteAppCallback),
               (override));
+  MOCK_METHOD(void,
+              SortLauncherWithRemoteAppsFirst,
+              (SortLauncherWithRemoteAppsFirstCallback),
+              (override));
 
  private:
   mojo::Receiver<RemoteApps> remote_apps_receiver_{this};
@@ -197,6 +203,20 @@
         });
   }
 
+  void SetExpectationForSortLauncherSuccess() {
+    EXPECT_CALL(remote_apps_bridge_, SortLauncherWithRemoteAppsFirst(_))
+        .WillOnce([](SortLauncherWithRemoteAppsFirstCallback callback) {
+          std::move(callback).Run(absl::nullopt);
+        });
+  }
+
+  void SetExpectationForSortLauncherError(const std::string& error) {
+    EXPECT_CALL(remote_apps_bridge_, SortLauncherWithRemoteAppsFirst(_))
+        .WillOnce([error](SortLauncherWithRemoteAppsFirstCallback callback) {
+          std::move(callback).Run(error);
+        });
+  }
+
  protected:
   TestingProfileManager testing_profile_manager_;
   raw_ptr<TestingProfile> testing_profile_ = nullptr;
@@ -339,6 +359,46 @@
   ASSERT_EQ(error, *result);
 }
 
+TEST_F(RemoteAppsProxyLacrosUnittest, SortLauncherWithRemoteAppsFirst) {
+  base::test::TestFuture<absl::optional<std::string>> future;
+
+  testing::StrictMock<MockRemoteAppLaunchObserver> mockObserver;
+  mojo::Remote<chromeos::remote_apps::mojom::RemoteApps> remote;
+  mojo::Receiver<chromeos::remote_apps::mojom::RemoteAppLaunchObserver>
+      observer{&mockObserver};
+  proxy_->BindRemoteAppsAndAppLaunchObserver(
+      kSource, remote.BindNewPipeAndPassReceiver(),
+      observer.BindNewPipeAndPassRemote());
+
+  SetExpectationForSortLauncherSuccess();
+  remote->SortLauncherWithRemoteAppsFirst(
+      future.GetCallback<const absl::optional<std::string>&>());
+
+  ASSERT_FALSE(future.Get());
+}
+
+TEST_F(RemoteAppsProxyLacrosUnittest, SortLauncherWithRemoteAppsFirstError) {
+  std::string error = "error";
+
+  base::test::TestFuture<absl::optional<std::string>> future;
+
+  testing::StrictMock<MockRemoteAppLaunchObserver> mockObserver;
+  mojo::Remote<chromeos::remote_apps::mojom::RemoteApps> remote;
+  mojo::Receiver<chromeos::remote_apps::mojom::RemoteAppLaunchObserver>
+      observer{&mockObserver};
+  proxy_->BindRemoteAppsAndAppLaunchObserver(
+      kSource, remote.BindNewPipeAndPassReceiver(),
+      observer.BindNewPipeAndPassRemote());
+
+  SetExpectationForSortLauncherError(error);
+  remote->SortLauncherWithRemoteAppsFirst(
+      future.GetCallback<const absl::optional<std::string>&>());
+
+  absl::optional<const std::string> result = future.Get();
+  ASSERT_TRUE(result);
+  ASSERT_EQ(error, *result);
+}
+
 // Tests that the `OnRemoteAppLaunched` event is only dispatched to the source
 // which added the app by adding multiple apps from different sources.
 TEST_F(RemoteAppsProxyLacrosUnittest, OnRemoteAppLaunched) {
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
index 2beef83..51e9f15f 100644
--- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
+++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
@@ -234,8 +234,7 @@
       public testing::WithParamInterface<bool> {
  protected:
   void SetUp() override {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     std::vector<base::test::FeatureRef> disabled_features;
 
     enabled_features.emplace_back(features::kSignedHTTPExchange,
diff --git a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
index d2055a0..f83a101 100644
--- a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
@@ -477,8 +477,7 @@
  protected:
   // Features to enable or disable for the test. Must be updated in the test
   // constructor (before SetUpDefaultCommandLine()) to take effect.
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-      enabled_features_;
+  std::vector<base::test::FeatureRefAndParams> enabled_features_;
   std::vector<base::test::FeatureRef> disabled_features_;
   base::test::ScopedFeatureList feature_list_;
 
diff --git a/chrome/browser/media/webrtc/get_display_media_set_browsertest.cc b/chrome/browser/media/webrtc/get_display_media_set_browsertest.cc
index d96b13b..3ece436 100644
--- a/chrome/browser/media/webrtc/get_display_media_set_browsertest.cc
+++ b/chrome/browser/media/webrtc/get_display_media_set_browsertest.cc
@@ -133,7 +133,7 @@
                                     track_ids));
   // If no screen is attached to a device, the |DisplayManager| will add a
   // default device. This same behavior is used in other places in Chrome that
-  // handle multiple screens (e.g. in the window placement API) and
+  // handle multiple screens (e.g. in JS window.getScreenDetails() API) and
   // getDisplayMediaSet will follow the same convention.
   EXPECT_EQ(1u, track_ids.size());
   EXPECT_EQ(track_ids.size(), base::flat_set<std::string>(track_ids).size());
diff --git a/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc b/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc
index a8cc701..5f82d5b 100644
--- a/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc
+++ b/chrome/browser/metrics/variations/variations_http_headers_browsertest.cc
@@ -857,7 +857,7 @@
     : public VariationsHttpHeadersBrowserTest {
  public:
   VariationsHttpHeadersBrowserTestWithOptimizationGuide() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled = {
+    std::vector<base::test::FeatureRefAndParams> enabled = {
         {features::kLoadingPredictorPrefetch, {}},
         {features::kLoadingPredictorUseOptimizationGuide,
          {{"use_predictions_for_preconnect", "true"}}},
diff --git a/chrome/browser/new_tab_page/modules/safe_browsing/safe_browsing_handler_unittest.cc b/chrome/browser/new_tab_page/modules/safe_browsing/safe_browsing_handler_unittest.cc
index fbd0980..164fafc 100644
--- a/chrome/browser/new_tab_page/modules/safe_browsing/safe_browsing_handler_unittest.cc
+++ b/chrome/browser/new_tab_page/modules/safe_browsing/safe_browsing_handler_unittest.cc
@@ -158,7 +158,7 @@
   base::Time initial_security_sensitive_event_time = base::Time::Now();
 
   base::test::ScopedFeatureList feature_list;
-  base::test::ScopedFeatureList::FeatureAndParams ntp_module_feature_params(
+  base::test::FeatureRefAndParams ntp_module_feature_params(
       ntp_features::kNtpSafeBrowsingModule,
       {{ntp_features::kNtpSafeBrowsingModuleCooldownPeriodDaysParam,
         base::NumberToString(cooldown_days)},
diff --git a/chrome/browser/password_manager/account_password_store_factory.cc b/chrome/browser/password_manager/account_password_store_factory.cc
index 62bde03..007463c 100644
--- a/chrome/browser/password_manager/account_password_store_factory.cc
+++ b/chrome/browser/password_manager/account_password_store_factory.cc
@@ -57,10 +57,13 @@
 #if BUILDFLAG(IS_ANDROID)
   NOTREACHED();
 #else
-  // Update all form managers.
+  // Update all form managers. Incognito tabs originated from this profile
+  // can also fill passwords, so they should be included.
   for (Browser* browser : *BrowserList::GetInstance()) {
-    if (browser->profile() != profile)
+    if (browser->profile()->GetOriginalProfile() !=
+        profile->GetOriginalProfile()) {
       continue;
+    }
     TabStripModel* tabs = browser->tab_strip_model();
     for (int index = 0; index < tabs->count(); index++) {
       content::WebContents* web_contents = tabs->GetWebContentsAt(index);
diff --git a/chrome/browser/performance_manager/policies/bfcache_policy_browsertest.cc b/chrome/browser/performance_manager/policies/bfcache_policy_browsertest.cc
index 2f7107a..f5792d6 100644
--- a/chrome/browser/performance_manager/policies/bfcache_policy_browsertest.cc
+++ b/chrome/browser/performance_manager/policies/bfcache_policy_browsertest.cc
@@ -168,8 +168,7 @@
 
  private:
   base::test::ScopedFeatureList feature_list_;
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-      enabled_features_;
+  std::vector<base::test::FeatureRefAndParams> enabled_features_;
   std::vector<base::test::FeatureRef> disabled_features_;
 };
 
diff --git a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc
index bca5efe..97bf622 100644
--- a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc
+++ b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc
@@ -91,11 +91,10 @@
   }
 
   void StartManager(
-      std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-          features_and_params = {
-              {performance_manager::features::kBatterySaverModeAvailable, {}},
-              {performance_manager::features::kHighEfficiencyModeAvailable, {}},
-          }) {
+      std::vector<base::test::FeatureRefAndParams> features_and_params = {
+          {performance_manager::features::kBatterySaverModeAvailable, {}},
+          {performance_manager::features::kHighEfficiencyModeAvailable, {}},
+      }) {
     auto test_sampling_event_source =
         std::make_unique<base::test::TestSamplingEventSource>();
     auto test_battery_level_provider =
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 072a7e30..05cb807 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1083,6 +1083,9 @@
   { key::kArcAppInstallEventLoggingEnabled,
     prefs::kArcAppInstallEventLoggingEnabled,
     base::Value::Type::BOOLEAN },
+  { key::kHindiInscriptLayoutEnabled,
+    prefs::kHindiInscriptLayoutEnabled,
+    base::Value::Type::BOOLEAN },
   { key::kNetworkFileSharesAllowed,
     prefs::kNetworkFileSharesAllowed,
     base::Value::Type::BOOLEAN },
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
index 5b6ea92..5d7d803 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
+++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
@@ -402,11 +402,11 @@
       public testing::WithParamInterface<std::tuple<BlockOnHeaders>> {
  public:
   SearchPrefetchServiceEnabledBrowserTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features = {{kSearchPrefetchServicePrefetching,
-                             {{"max_attempts_per_caching_duration", "3"},
-                              {"cache_size", "1"},
-                              {"device_memory_threshold_MB", "0"}}}};
+    std::vector<base::test::FeatureRefAndParams> enabled_features = {
+        {kSearchPrefetchServicePrefetching,
+         {{"max_attempts_per_caching_duration", "3"},
+          {"cache_size", "1"},
+          {"device_memory_threshold_MB", "0"}}}};
     std::vector<base::test::FeatureRef> disabled_features = {};
     if (BlockOnHeadersEnabled()) {
       enabled_features.push_back({kSearchPrefetchBlockBeforeHeaders, {}});
@@ -3378,12 +3378,12 @@
     : public SearchPrefetchBaseBrowserTest {
  public:
   SearchPrefetchServiceNavigationPrefetchBrowserTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features = {{kSearchPrefetchServicePrefetching,
-                             {{"max_attempts_per_caching_duration", "3"},
-                              {"cache_size", "1"},
-                              {"device_memory_threshold_MB", "0"}}},
-                            {kSearchNavigationPrefetch, {}}};
+    std::vector<base::test::FeatureRefAndParams> enabled_features = {
+        {kSearchPrefetchServicePrefetching,
+         {{"max_attempts_per_caching_duration", "3"},
+          {"cache_size", "1"},
+          {"device_memory_threshold_MB", "0"}}},
+        {kSearchNavigationPrefetch, {}}};
     std::vector<base::test::FeatureRef> disabled_features = {};
 
     feature_list_.InitWithFeaturesAndParameters(enabled_features,
@@ -3725,13 +3725,13 @@
     : public SearchPrefetchBaseBrowserTest {
  public:
   SearchNavigationPrefetchHoldbackBrowserTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features = {{kSearchPrefetchServicePrefetching,
-                             {{"max_attempts_per_caching_duration", "3"},
-                              {"cache_size", "1"},
-                              {"device_memory_threshold_MB", "0"},
-                              {"prefetch_holdback", "true"}}},
-                            {kSearchNavigationPrefetch, {{}}}};
+    std::vector<base::test::FeatureRefAndParams> enabled_features = {
+        {kSearchPrefetchServicePrefetching,
+         {{"max_attempts_per_caching_duration", "3"},
+          {"cache_size", "1"},
+          {"device_memory_threshold_MB", "0"},
+          {"prefetch_holdback", "true"}}},
+        {kSearchNavigationPrefetch, {{}}}};
     std::vector<base::test::FeatureRef> disabled_features = {};
 
     feature_list_.InitWithFeaturesAndParameters(enabled_features,
@@ -3817,13 +3817,13 @@
     : public SearchPrefetchBaseBrowserTest {
  public:
   SearchNavigationPrefetchNoCancelBrowserTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features = {{kSearchPrefetchServicePrefetching,
-                             {{"max_attempts_per_caching_duration", "3"},
-                              {"cache_size", "1"},
-                              {"device_memory_threshold_MB", "0"}}},
-                            {kSearchPrefetchSkipsCancel, {}},
-                            {kSearchNavigationPrefetch, {{}}}};
+    std::vector<base::test::FeatureRefAndParams> enabled_features = {
+        {kSearchPrefetchServicePrefetching,
+         {{"max_attempts_per_caching_duration", "3"},
+          {"cache_size", "1"},
+          {"device_memory_threshold_MB", "0"}}},
+        {kSearchPrefetchSkipsCancel, {}},
+        {kSearchNavigationPrefetch, {{}}}};
     std::vector<base::test::FeatureRef> disabled_features = {};
 
     feature_list_.InitWithFeaturesAndParameters(enabled_features,
diff --git a/chrome/browser/resources/bookmarks/command_manager.ts b/chrome/browser/resources/bookmarks/command_manager.ts
index ea8b8fa..04cbc3b 100644
--- a/chrome/browser/resources/bookmarks/command_manager.ts
+++ b/chrome/browser/resources/bookmarks/command_manager.ts
@@ -126,15 +126,15 @@
     this.addShortcut_(Command.COPY, 'Ctrl|c', 'Meta|c');
     this.addShortcut_(Command.PASTE, 'Ctrl|v', 'Meta|v');
 
-    this.eventTracker_.add(document, 'open-command-menu', e =>
+    this.eventTracker_.add(document, 'open-command-menu', (e: Event) =>
                            this.onOpenCommandMenu_(
                                e as CustomEvent<OpenCommandMenuDetail>));
-    this.eventTracker_.add(document, 'keydown', e =>
+    this.eventTracker_.add(document, 'keydown', (e: Event) =>
                            this.onKeydown_(e as KeyboardEvent));
 
     const addDocumentListenerForCommand = (eventName: string,
                                            command: Command) => {
-      this.eventTracker_.add(document, eventName, e => {
+      this.eventTracker_.add(document, eventName, (e: Event) => {
         if ((e.composedPath()[0] as HTMLElement).tagName === 'INPUT') {
           return;
         }
diff --git a/chrome/browser/resources/bookmarks/dnd_manager.ts b/chrome/browser/resources/bookmarks/dnd_manager.ts
index b6cd724a..5c0f86b 100644
--- a/chrome/browser/resources/bookmarks/dnd_manager.ts
+++ b/chrome/browser/resources/bookmarks/dnd_manager.ts
@@ -282,11 +282,15 @@
     this.dropIndicator_ = new DropIndicator();
     this.autoExpander_ = new AutoExpander();
 
-    this.eventTracker_.add(document, 'dragstart', e => this.onDragStart_(e));
-    this.eventTracker_.add(document, 'dragenter', e => this.onDragEnter_(e));
-    this.eventTracker_.add(document, 'dragover', e => this.onDragOver_(e));
+    this.eventTracker_.add(document, 'dragstart',
+                           (e: Event) => this.onDragStart_(e));
+    this.eventTracker_.add(document, 'dragenter',
+                           (e: Event) => this.onDragEnter_(e));
+    this.eventTracker_.add(document, 'dragover',
+                           (e: Event) => this.onDragOver_(e));
     this.eventTracker_.add(document, 'dragleave', () => this.onDragLeave_());
-    this.eventTracker_.add(document, 'drop', e => this.onDrop_(e));
+    this.eventTracker_.add(document, 'drop',
+                           (e: Event) => this.onDrop_(e));
     this.eventTracker_.add(document, 'dragend', () => this.clearDragData_());
     this.eventTracker_.add(document, 'mousedown', () => this.onMouseDown_());
     this.eventTracker_.add(document, 'touchstart', () => this.onTouchStart_());
diff --git a/chrome/browser/resources/bookmarks/list.ts b/chrome/browser/resources/bookmarks/list.ts
index d8a3917f..dc040692 100644
--- a/chrome/browser/resources/bookmarks/list.ts
+++ b/chrome/browser/resources/bookmarks/list.ts
@@ -93,7 +93,8 @@
   override ready() {
     super.ready();
     this.addEventListener('click', () => this.deselectItems_());
-    this.addEventListener('contextmenu', e => this.onContextMenu_(e));
+    this.addEventListener('contextmenu',
+                          e => this.onContextMenu_(e as MouseEvent));
     this.addEventListener(
         'open-command-menu',
         e => this.onOpenCommandMenu_(e as CustomEvent<OpenCommandMenuDetail>));
@@ -118,7 +119,7 @@
 
     this.eventTracker_.add(
         document, 'highlight-items',
-        e => this.onHighlightItems_(e as CustomEvent<string[]>));
+        (e: Event) => this.onHighlightItems_(e as CustomEvent<string[]>));
     this.eventTracker_.add(
         document, 'import-began', () => this.onImportBegan_());
     this.eventTracker_.add(
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/fake_chrome_event.js b/chrome/browser/resources/chromeos/accessibility/common/testing/fake_chrome_event.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/select_to_speak/fake_chrome_event.js
rename to chrome/browser/resources/chromeos/accessibility/common/testing/fake_chrome_event.js
diff --git a/chrome/browser/resources/chromeos/accessibility/common/testing/fake_settings_private.js b/chrome/browser/resources/chromeos/accessibility/common/testing/fake_settings_private.js
new file mode 100644
index 0000000..87311dc8
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/common/testing/fake_settings_private.js
@@ -0,0 +1,147 @@
+// Copyright 2015 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Fake implementation of chrome.settingsPrivate for testing.
+ * Note: This file is deprecated and is no longer maintained by the browser
+ * settings/WebUI team. For the updated version (JS modules only), see
+ * chrome/test/data/webui/settings/fake_settings_private.js.
+ */
+/**
+ * @typedef {Array<{key: string,
+ *               type: chrome.settingsPrivate.PrefType,
+ *               values: !Array<*>}>}
+ */
+let FakeSettingsPrivatePref;
+
+/**
+ * Creates a deep copy of the object.
+ * @param {*} obj
+ * @return {*}
+ */
+function deepCopy(obj) {
+  return JSON.parse(JSON.stringify(obj));
+}
+
+/**
+ * Fake of chrome.settingsPrivate API. Use by setting
+ * CrSettingsPrefs.deferInitialization to true, then passing a
+ * FakeSettingsPrivate to settings-prefs#initialize().
+ * @implements {SettingsPrivate}
+ */
+class FakeSettingsPrivate {
+  /** @param {Array<!settings.FakeSettingsPrivatePref>=} opt_initialPrefs */
+  constructor(opt_initialPrefs) {
+    this.disallowSetPref_ = false;
+    this.failNextSetPref_ = false;
+
+    this.prefs = {};
+
+    if (!opt_initialPrefs) {
+      return;
+    }
+    for (const pref of opt_initialPrefs) {
+      this.addPref_(pref.type, pref.key, pref.value);
+    }
+
+    // chrome.settingsPrivate override.
+    this.onPrefsChanged = /** @type {!ChromeEvent} */ (new FakeChromeEvent());
+  }
+
+  // chrome.settingsPrivate overrides.
+  getAllPrefs(callback) {
+    // Send a copy of prefs to keep our internal state private.
+    const prefs = [];
+    for (const key in this.prefs) {
+      prefs.push(deepCopy(this.prefs[key]));
+    }
+
+    // Run the callback asynchronously to test that the prefs aren't actually
+    // used before they become available.
+    setTimeout(callback.bind(null, prefs));
+  }
+
+  setPref(key, value, pageId, callback) {
+    const pref = this.prefs[key];
+    assertNotEquals(undefined, pref);
+    assertEquals(typeof value, typeof pref.value);
+    assertEquals(Array.isArray(value), Array.isArray(pref.value));
+
+    if (this.failNextSetPref_) {
+      callback(false);
+      this.failNextSetPref_ = false;
+      return;
+    }
+    assertNotEquals(true, this.disallowSetPref_);
+
+    const changed = JSON.stringify(pref.value) !== JSON.stringify(value);
+    pref.value = deepCopy(value);
+    callback(true);
+
+    // Like chrome.settingsPrivate, send a notification when prefs change.
+    if (changed) {
+      this.sendPrefChanges([{key, value}]);
+    }
+  }
+
+  getPref(key, callback) {
+    const pref = this.prefs[key];
+    assertNotEquals(undefined, pref);
+    callback(
+        /** @type {!chrome.settingsPrivate.PrefObject} */ (deepCopy(pref)));
+  }
+
+  // Functions used by tests.
+
+  /** Instructs the API to return a failure when setPref is next called. */
+  failNextSetPref() {
+    this.failNextSetPref_ = true;
+  }
+
+  /** Instructs the API to assert (fail the test) if setPref is called. */
+  disallowSetPref() {
+    this.disallowSetPref_ = true;
+  }
+
+  allowSetPref() {
+    this.disallowSetPref_ = false;
+  }
+
+  /**
+   * Notifies the listeners of pref changes.
+   * @param {!Array<{key: string, value: *}>} changes
+   */
+  sendPrefChanges(changes) {
+    const prefs = [];
+    for (const change of changes) {
+      const pref = this.prefs[change.key];
+      assertNotEquals(undefined, pref);
+      pref.value = change.value;
+      prefs.push(deepCopy(pref));
+    }
+    /** @type {FakeChromeEvent} */ (this.onPrefsChanged).callListeners(prefs);
+  }
+
+  /** @override */
+  getDefaultZoom() {}
+
+  /** @override */
+  setDefaultZoom() {}
+
+  // Private methods for use by the fake API.
+
+  /**
+   * @param {!chrome.settingsPrivate.PrefType} type
+   * @param {string} key
+   * @param {*} value
+   * @private
+   */
+  addPref_(type, key, value) {
+    this.prefs[key] = {
+      type,
+      key,
+      value,
+    };
+  }
+}
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
index 6484af40..dea3089 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
@@ -105,15 +105,13 @@
     "../common/testing/accessibility_test_base.js",
     "../common/testing/callback_helper.js",
     "../common/testing/e2e_test_base.js",
+    "../common/testing/fake_chrome_event.js",
+    "../common/testing/fake_settings_private.js",
     "../common/testing/mock_storage.js",
     "../common/testing/mock_tts.js",
     "select_to_speak_e2e_test_base.js",
     "pipe.jpg",
   ]
-  extra_js_files = [
-    "fake_settings_private.js",
-    "fake_chrome_event.js",
-  ]
 
   # The test base classes generate C++ code with these deps.
   deps = [
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/fake_settings_private.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/fake_settings_private.js
deleted file mode 100644
index 1493834..0000000
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/fake_settings_private.js
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2015 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Fake implementation of chrome.settingsPrivate for testing.
- * Note: This file is deprecated and is no longer maintained by the browser
- * settings/WebUI team. For the updated version (JS modules only), see
- * chrome/test/data/webui/settings/fake_settings_private.js.
- */
-  /**
-   * @typedef {Array<{key: string,
-   *               type: chrome.settingsPrivate.PrefType,
-   *               values: !Array<*>}>}
-   */
-  let FakeSettingsPrivatePref;
-
-  /**
-   * Creates a deep copy of the object.
-   * @param {*} obj
-   * @return {*}
-   */
-  function deepCopy(obj) {
-    return JSON.parse(JSON.stringify(obj));
-  }
-
-  /**
-   * Fake of chrome.settingsPrivate API. Use by setting
-   * CrSettingsPrefs.deferInitialization to true, then passing a
-   * FakeSettingsPrivate to settings-prefs#initialize().
-   * @implements {SettingsPrivate}
-   */
-  class FakeSettingsPrivate {
-    /** @param {Array<!settings.FakeSettingsPrivatePref>=} opt_initialPrefs */
-    constructor(opt_initialPrefs) {
-      this.disallowSetPref_ = false;
-      this.failNextSetPref_ = false;
-
-      this.prefs = {};
-
-      if (!opt_initialPrefs) {
-        return;
-      }
-      for (const pref of opt_initialPrefs) {
-        this.addPref_(pref.type, pref.key, pref.value);
-      }
-
-      // chrome.settingsPrivate override.
-      this.onPrefsChanged = /** @type {!ChromeEvent} */ (new FakeChromeEvent());
-    }
-
-    // chrome.settingsPrivate overrides.
-    getAllPrefs(callback) {
-      // Send a copy of prefs to keep our internal state private.
-      const prefs = [];
-      for (const key in this.prefs) {
-        prefs.push(deepCopy(this.prefs[key]));
-      }
-
-      // Run the callback asynchronously to test that the prefs aren't actually
-      // used before they become available.
-      setTimeout(callback.bind(null, prefs));
-    }
-
-    setPref(key, value, pageId, callback) {
-      const pref = this.prefs[key];
-      assertNotEquals(undefined, pref);
-      assertEquals(typeof value, typeof pref.value);
-      assertEquals(Array.isArray(value), Array.isArray(pref.value));
-
-      if (this.failNextSetPref_) {
-        callback(false);
-        this.failNextSetPref_ = false;
-        return;
-      }
-      assertNotEquals(true, this.disallowSetPref_);
-
-      const changed = JSON.stringify(pref.value) !== JSON.stringify(value);
-      pref.value = deepCopy(value);
-      callback(true);
-
-      // Like chrome.settingsPrivate, send a notification when prefs change.
-      if (changed) {
-        this.sendPrefChanges([{key, value}]);
-      }
-    }
-
-    getPref(key, callback) {
-      const pref = this.prefs[key];
-      assertNotEquals(undefined, pref);
-      callback(
-          /** @type {!chrome.settingsPrivate.PrefObject} */ (deepCopy(pref)));
-    }
-
-    // Functions used by tests.
-
-    /** Instructs the API to return a failure when setPref is next called. */
-    failNextSetPref() {
-      this.failNextSetPref_ = true;
-    }
-
-    /** Instructs the API to assert (fail the test) if setPref is called. */
-    disallowSetPref() {
-      this.disallowSetPref_ = true;
-    }
-
-    allowSetPref() {
-      this.disallowSetPref_ = false;
-    }
-
-    /**
-     * Notifies the listeners of pref changes.
-     * @param {!Array<{key: string, value: *}>} changes
-     */
-    sendPrefChanges(changes) {
-      const prefs = [];
-      for (const change of changes) {
-        const pref = this.prefs[change.key];
-        assertNotEquals(undefined, pref);
-        pref.value = change.value;
-        prefs.push(deepCopy(pref));
-      }
-      /** @type {FakeChromeEvent} */ (this.onPrefsChanged).callListeners(prefs);
-    }
-
-    /** @override */
-    getDefaultZoom() {}
-
-    /** @override */
-    setDefaultZoom() {}
-
-    // Private methods for use by the fake API.
-
-    /**
-     * @param {!chrome.settingsPrivate.PrefType} type
-     * @param {string} key
-     * @param {*} value
-     * @private
-     */
-    addPref_(type, key, value) {
-      this.prefs[key] = {
-        type,
-        key,
-        value,
-      };
-    }
-  }
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/input_handler.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/input_handler.js
index b6e4afb5..470f9dd 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/input_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/input_handler.js
@@ -34,15 +34,15 @@
  * Class to handle user-input, from mouse, keyboard, and copy-paste events.
  */
 export class InputHandler {
-  /** @param {SelectToSpeakCallbacks} callbacks */
+  /**
+   * Please keep fields in alphabetical order.
+   * @param {!SelectToSpeakCallbacks} callbacks
+   */
   constructor(callbacks) {
-    /** @private {SelectToSpeakCallbacks} */
+    /** @private {!SelectToSpeakCallbacks} */
     this.callbacks_ = callbacks;
 
     /** @private {boolean} */
-    this.trackingMouse_ = false;
-
-    /** @private {boolean} */
     this.didTrackMouse_ = false;
 
     /** @private {boolean} */
@@ -57,11 +57,13 @@
     /** @private {!Set<number>} */
     this.keysPressedTogether_ = new Set();
 
-    /** @private {{x: number, y: number}} */
-    this.mouseStart_ = {x: 0, y: 0};
-
-    /** @private {{x: number, y: number}} */
-    this.mouseEnd_ = {x: 0, y: 0};
+    /**
+     * The timestamp at which the last clipboard data clear was requested.
+     * Used to make sure we don't clear the clipboard on a user's request,
+     * but only after the clipboard was used to read selected text.
+     * @private {Date}
+     */
+    this.lastClearClipboardDataTime_ = new Date(0);
 
     /**
      * The timestamp at which clipboard data read was requested by the user
@@ -72,13 +74,14 @@
      */
     this.lastReadClipboardDataTime_ = new Date(0);
 
-    /**
-     * The timestamp at which the last clipboard data clear was requested.
-     * Used to make sure we don't clear the clipboard on a user's request,
-     * but only after the clipboard was used to read selected text.
-     * @private {Date}
-     */
-    this.lastClearClipboardDataTime_ = new Date(0);
+    /** @private {{x: number, y: number}} */
+    this.mouseStart_ = {x: 0, y: 0};
+
+    /** @private {{x: number, y: number}} */
+    this.mouseEnd_ = {x: 0, y: 0};
+
+    /** @private {boolean} */
+    this.trackingMouse_ = false;
   }
 
   /** @private */
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/prefs_manager.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/prefs_manager.js
index d856b37..67221b6 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/prefs_manager.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/prefs_manager.js
@@ -6,54 +6,13 @@
  * Manages getting and storing user preferences.
  */
 export class PrefsManager {
+  /** Please keep fields in alphabetical order. */
   constructor() {
-    /** @private {?string} */
-    this.voiceNameFromPrefs_ = null;
-
-    /** @private {?string} */
-    this.voiceNameFromLocale_ = null;
-
-    /** @private {?string} */
-    this.enhancedVoiceName_ = PrefsManager.DEFAULT_NETWORK_VOICE;
-
-    /** @private {Set<string>} */
-    this.validVoiceNames_ = new Set();
-
-    /** @private {Map<string, string>} */
-    this.extensionForVoice_ = new Map();
-
-    /** @private {number} */
-    this.speechRate_ = 1.0;
-
-    /** @private {number} */
-    this.speechPitch_ = 1.0;
-
-    /** @private {boolean} */
-    this.wordHighlight_ = true;
-
-    /** @const {string} */
-    this.color_ = '#da36e8';
-
-    /** @private {string} */
-    this.highlightColor_ = '#5e9bff';
-
-    /** @private {boolean} */
-    this.migrationInProgress_ = false;
-
     /** @private {boolean} */
     this.backgroundShadingEnabled_ = false;
 
-    /** @private {boolean} */
-    this.navigationControlsEnabled_ = true;
-
-    /**
-     * A pref indicating whether the user enables the network voices. The pref
-     * is synced to local storage as "enhancedNetworkVoices". Use
-     * this.enhancedNetworkVoicesEnabled() to refer whether to enable the
-     * network voices instead of using this pref directly.
-     * @private {boolean}
-     */
-    this.enhancedNetworkVoicesEnabled_ = false;
+    /** @const {string} */
+    this.color_ = '#da36e8';
 
     /**
      * Whether to allow enhanced network voices in Select-to-Speak. Unlike
@@ -66,8 +25,50 @@
      */
     this.enhancedNetworkVoicesAllowed_ = true;
 
+    /**
+     * A pref indicating whether the user enables the network voices. The pref
+     * is synced to local storage as "enhancedNetworkVoices". Use
+     * this.enhancedNetworkVoicesEnabled() to refer whether to enable the
+     * network voices instead of using this pref directly.
+     * @private {boolean}
+     */
+    this.enhancedNetworkVoicesEnabled_ = false;
+
+    /** @private {?string} */
+    this.enhancedVoiceName_ = PrefsManager.DEFAULT_NETWORK_VOICE;
+
     /** @private {boolean} */
     this.enhancedVoicesDialogShown_ = false;
+
+    /** @private {Map<string, string>} */
+    this.extensionForVoice_ = new Map();
+
+    /** @private {string} */
+    this.highlightColor_ = '#5e9bff';
+
+    /** @private {boolean} */
+    this.migrationInProgress_ = false;
+
+    /** @private {boolean} */
+    this.navigationControlsEnabled_ = true;
+
+    /** @private {number} */
+    this.speechPitch_ = 1.0;
+
+    /** @private {number} */
+    this.speechRate_ = 1.0;
+
+    /** @private {Set<string>} */
+    this.validVoiceNames_ = new Set();
+
+    /** @private {?string} */
+    this.voiceNameFromLocale_ = null;
+
+    /** @private {?string} */
+    this.voiceNameFromPrefs_ = null;
+
+    /** @private {boolean} */
+    this.wordHighlight_ = true;
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
index f4c26c3..e3bdb7a07 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
@@ -57,39 +57,14 @@
  * @implements {SelectToSpeakUiListener}
  */
 export class SelectToSpeak {
+  /** Please keep fields in alphabetical order. */
   constructor() {
     /**
-     * The current state of the SelectToSpeak extension, from
-     * SelectToSpeakState.
-     * @private {!chrome.accessibilityPrivate.SelectToSpeakState}
+     * The start char index of the word to be spoken. The index is relative
+     * to the text content of the current node group.
+     * @private {number}
      */
-    this.state_ = SelectToSpeakState.INACTIVE;
-
-    /** @type {InputHandler} */
-    this.inputHandler_ = null;
-
-    /** @private {chrome.automation.AutomationNode} */
-    this.desktop_;
-
-    chrome.automation.getDesktop(desktop => {
-      this.desktop_ = desktop;
-
-      // After the user selects a region of the screen, we do a hit test at
-      // the center of that box using the automation API. The result of the
-      // hit test is a MOUSE_RELEASED accessibility event.
-      desktop.addEventListener(
-          EventType.MOUSE_RELEASED, evt => this.onAutomationHitTest_(evt),
-          true);
-    });
-
-    /**
-     * The node groups to be spoken. We process content into node groups and
-     * pass one node group at a time to the TTS engine. Note that we do not use
-     * node groups for user-selected text in Gsuite. See more details in
-     * readNodesBetweenPositions_.
-     * @private {!Array<!ParagraphUtils.NodeGroup>}
-     */
-    this.currentNodeGroups_ = [];
+    this.currentCharIndex_ = -1;
 
     /**
      * The index for the node group currently being spoken in
@@ -119,27 +94,38 @@
     this.currentNodeGroupItemIndex_ = -1;
 
     /**
+     * The node groups to be spoken. We process content into node groups and
+     * pass one node group at a time to the TTS engine. Note that we do not use
+     * node groups for user-selected text in Gsuite. See more details in
+     * readNodesBetweenPositions_.
+     * @private {!Array<!ParagraphUtils.NodeGroup>}
+     */
+    this.currentNodeGroups_ = [];
+
+    /**
      * The indexes within the current node group item representing the word
      * currently being spoken. Only updated if word highlighting is enabled.
      * @private {?{start: number, end: number}}
      */
     this.currentNodeWord_ = null;
 
-    /**
-     * The start char index of the word to be spoken. The index is relative
-     * to the text content of the current node group.
-     * @private {number}
-     */
-    this.currentCharIndex_ = -1;
+    /** @private {chrome.automation.AutomationNode} */
+    this.desktop_;
 
     /**
-     * Whether the current nodes support use of the navigation panel.
+     * Feature flag controlling STS language detection integration.
      * @private {boolean}
      */
-    this.supportsNavigationPanel_ = true;
+    this.enableLanguageDetectionIntegration_ = false;
 
-    /** @private {boolean} */
-    this.scrollToSpokenNode_ = false;
+    /**
+     * Feature flag controlling availability of enhanced network voices
+     * @private {boolean}
+     */
+    this.enhancedVoicesFlag_ = false;
+
+    /** @private {InputHandler} */
+    this.inputHandler_ = null;
 
     /**
      * The interval ID from a call to setInterval, which is set whenever
@@ -151,60 +137,82 @@
     /** @private {Audio} */
     this.null_selection_tone_ = new Audio('earcons/null_selection.ogg');
 
+    /**
+     * Function to be called when a state change request is received from the
+     * accessibilityPrivate API.
+     * @protected {?function()}
+     */
+    this.onStateChangeRequestedCallbackForTest_ = null;
+
     /** @private {PrefsManager} */
     this.prefsManager_ = new PrefsManager();
-    this.prefsManager_.initPreferences();
 
-    /** @private {!UiManager} */
-    this.uiManager_ = new UiManager(this.prefsManager_, this /* listener */);
+    /** @private {boolean} */
+    this.scrollToSpokenNode_ = false;
+
+    /** @private {number} Speech rate multiplier. */
+    this.speechRateMultiplier_ = 1.0;
+
+    /**
+     * The current state of the SelectToSpeak extension, from
+     * SelectToSpeakState.
+     * @private {!chrome.accessibilityPrivate.SelectToSpeakState}
+     */
+    this.state_ = SelectToSpeakState.INACTIVE;
+
+    /**
+     * Whether the current nodes support use of the navigation panel.
+     * @private {boolean}
+     */
+    this.supportsNavigationPanel_ = true;
+
+    /** @private {number} Default speech rate set in system settings. */
+    this.systemSpeechRate_ = 1.0;
 
     /** @private {!TtsManager} */
     this.ttsManager_ = new TtsManager();
 
+    /** @private {!UiManager} */
+    this.uiManager_ = new UiManager(this.prefsManager_, this /* listener */);
+
+    this.init_();
+  }
+
+  /** @private */
+  init_() {
+    chrome.automation.getDesktop(desktop => {
+      this.desktop_ = desktop;
+
+      // After the user selects a region of the screen, we do a hit test at
+      // the center of that box using the automation API. The result of the
+      // hit test is a MOUSE_RELEASED accessibility event.
+      desktop.addEventListener(
+          EventType.MOUSE_RELEASED, evt => this.onAutomationHitTest_(evt),
+          true);
+    });
+
+    this.prefsManager_.initPreferences();
+
     this.runContentScripts_();
     this.setUpEventListeners_();
 
-    /**
-     * Function to be called when a state change request is received from the
-     * accessibilityPrivate API.
-     * @type {?function()}
-     * @protected
-     */
-    this.onStateChangeRequestedCallbackForTest_ = null;
-
-    /**
-     * Feature flag controlling STS language detection integration.
-     * @type {boolean}
-     */
-    this.enableLanguageDetectionIntegration_ = false;
-
     // TODO(chrishall): do we want to (also?) expose this in preferences?
     chrome.commandLinePrivate.hasSwitch(
         'enable-experimental-accessibility-language-detection', result => {
           this.enableLanguageDetectionIntegration_ = result;
         });
 
-    /**
-     * Feature flag controlling availability of enhanced network voices
-     * @type {boolean}
-     */
-    this.enhancedVoicesFlag_ = false;
     chrome.accessibilityPrivate.isFeatureEnabled(
         AccessibilityFeature.ENHANCED_NETWORK_VOICES, result => {
           this.enhancedVoicesFlag_ = result;
         });
 
-    /** @private {number} Default speech rate set in system settings. */
-    this.systemSpeechRate_ = 1.0;
     chrome.settingsPrivate.getPref(SPEECH_RATE_KEY, pref => {
       if (!pref) {
         return;
       }
       this.systemSpeechRate_ = /** @type {number} */ (pref.value);
     });
-
-    /** @private {number} Speech rate multiplier. */
-    this.speechRateMultiplier_ = 1.0;
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js
index 767ecde..4aa4fbd 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-GEN_INCLUDE(['fake_chrome_event.js']);
 GEN_INCLUDE(['select_to_speak_e2e_test_base.js']);
+GEN_INCLUDE(['../common/testing/fake_chrome_event.js']);
+GEN_INCLUDE(['../common/testing/fake_settings_private.js']);
 GEN_INCLUDE(['../common/testing/mock_tts.js']);
-GEN_INCLUDE(['fake_settings_private.js']);
 
 SelectToSpeakEnhancedNetworkTtsVoicesTest = class extends SelectToSpeakE2ETest {
   constructor() {
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_prefs_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_prefs_test.js
index be99009..b25341a3 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_prefs_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_prefs_test.js
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 GEN_INCLUDE(['select_to_speak_e2e_test_base.js']);
-GEN_INCLUDE(['fake_chrome_event.js']);
-GEN_INCLUDE(['fake_settings_private.js']);
+GEN_INCLUDE(['../common/testing/fake_chrome_event.js']);
+GEN_INCLUDE(['../common/testing/fake_settings_private.js']);
 GEN_INCLUDE(['../common/testing/mock_storage.js']);
 
 /**
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/tts_manager.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/tts_manager.js
index 5a912f3a..0466934 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/tts_manager.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/tts_manager.js
@@ -7,26 +7,15 @@
  */
 
 export class TtsManager {
+  /** Please keep fields in alphabetical order. */
   constructor() {
     /**
-     * The text currently being spoken.
-     * @private {string|null}
-     */
-    this.text_ = null;
-
-    /**
      * The TTS options that the client passed in.
      * @private {!chrome.tts.TtsOptions}
      */
     this.clientTtsOptions_ = /** @type {!chrome.tts.TtsOptions} */ ({});
 
     /**
-     * The fallback voice to use if TTS fails.
-     * @private {string|undefined}
-     */
-    this.fallbackVoice_ = undefined;
-
-    /**
      * The current char index to the |this.text_| indicating the current spoken
      * word. For example, if |this.text_| is "hello world" and TTS is speaking
      * the second word, the |this.currentCharIndex_| should be 6.
@@ -35,10 +24,10 @@
     this.currentCharIndex_ = 0;
 
     /**
-     * Whether TTS is speaking.
-     * @private {boolean}
+     * The fallback voice to use if TTS fails.
+     * @private {string|undefined}
      */
-    this.isSpeaking_ = false;
+    this.fallbackVoice_ = undefined;
 
     /**
      * Whether the last TTS request was made with a network voice.
@@ -46,10 +35,22 @@
     this.isNetworkVoice_ = false;
 
     /**
+     * Whether TTS is speaking.
+     * @private {boolean}
+     */
+    this.isSpeaking_ = false;
+
+    /**
      * Function to be called when STS finishes a pausing request.
      * @private {?function()}
      */
     this.pauseCompleteCallback_ = null;
+
+    /**
+     * The text currently being spoken.
+     * @private {string|null}
+     */
+    this.text_ = null;
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/ui_manager.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/ui_manager.js
index f09cdfe5..f352deb 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/ui_manager.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/ui_manager.js
@@ -86,25 +86,31 @@
  */
 export class UiManager {
   /**
+   * Please keep fields in alphabetical order.
    * @param {!PrefsManager} prefsManager
    * @param {!SelectToSpeakUiListener} listener
    */
   constructor(prefsManager, listener) {
-    /** @private {!PrefsManager} */
-    this.prefsManager_ = prefsManager;
+    /** @private {?chrome.automation.AutomationNode} */
+    this.desktop_ = null;
 
     /** @private {!SelectToSpeakUiListener} */
     this.listener_ = listener;
 
-    /** @private {?chrome.automation.AutomationNode} */
-    this.desktop_ = null;
-
     /**
      * Button in the floating panel, useful for restoring focus to the panel.
      * @private {?chrome.automation.AutomationNode}
      */
     this.panelButton_ = null;
 
+    /** @private {!PrefsManager} */
+    this.prefsManager_ = prefsManager;
+
+    this.init_();
+  }
+
+  /** @private */
+  init_() {
     // Cache desktop and listen to focus changes.
     chrome.automation.getDesktop(desktop => {
       this.desktop_ = desktop;
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index 091563d3..2fd6cce 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -218,12 +218,10 @@
     "components/oobe_vars/oobe_shared_vars_css.m.js",
     "components/display_manager_types.m.js",
     "components/gaia_dialog.m.js",
-    "components/hd_iron_icon.m.js",
     "components/long_touch_detector.m.js",
     "components/network_select_login.m.js",
     "components/oobe_a11y_option.m.js",
     "components/oobe_cr_lottie.m.js",
-    "components/oobe_i18n_dropdown.m.js",
     "components/oobe_icons.m.js",
     "components/oobe_network_icons.m.js",
     "components/oobe_select.m.js",
@@ -269,7 +267,9 @@
     "components/gaia_button.js",
     "components/gaia_header.js",
     "components/gaia_input_form.js",
+    "components/hd_iron_icon.js",
     "components/notification_card.js",
+    "components/oobe_i18n_dropdown.js",
     "components/progress_list_item.js",
     "components/security_token_pin.js",
     "screens/common/adb_sideloading.js",
diff --git a/chrome/browser/resources/chromeos/login/components/BUILD.gn b/chrome/browser/resources/chromeos/login/components/BUILD.gn
index a7407d81..52719a6 100644
--- a/chrome/browser/resources/chromeos/login/components/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/components/BUILD.gn
@@ -23,7 +23,7 @@
     ":gaia_dialog.m",
     ":gaia_header",
     ":gaia_input_form",
-    ":hd_iron_icon.m",
+    ":hd_iron_icon",
     ":keyboard_utils_for_injection",
     ":keyboard_utils_for_injection.m",
     ":long_touch_detector.m",
@@ -33,7 +33,7 @@
     ":oobe_apps_list.m",
     ":oobe_carousel.m",
     ":oobe_cr_lottie.m",
-    ":oobe_i18n_dropdown.m",
+    ":oobe_i18n_dropdown",
     ":oobe_icons.m",
     ":oobe_network_icons.m",
     ":oobe_select.m",
@@ -58,14 +58,12 @@
 
                   # Local targets
                   ":gaia_dialog_module",
-                  ":hd_iron_icon_module",
                   ":network_select_login_module",
                   ":oobe_a11y_option_module",
                   ":oobe_a11y_option_module",
                   ":oobe_apps_list_module",
                   ":oobe_carousel_module",
                   ":oobe_cr_lottie_module",
-                  ":oobe_i18n_dropdown_module",
                   ":oobe_icons_module",
                   ":oobe_icons_module",
                   ":oobe_network_icons_module",
@@ -125,12 +123,12 @@
   extra_deps = [ ":web_components" ]
 }
 
-js_library("hd_iron_icon.m") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/components/hd_iron_icon.m.js" ]
+js_library("hd_iron_icon") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/components/hd_iron_icon.js" ]
   deps = [
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
-  extra_deps = [ ":hd_iron_icon_module" ]
+  extra_deps = [ ":web_components" ]
 }
 
 js_library("keyboard_utils_for_injection.m") {
@@ -181,13 +179,13 @@
   extra_deps = [ ":oobe_icons_module" ]
 }
 
-js_library("oobe_i18n_dropdown.m") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.m.js" ]
+js_library("oobe_i18n_dropdown") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.js" ]
   deps = [
     ":oobe_select.m",
     ":oobe_types.m",
   ]
-  extra_deps = [ ":oobe_i18n_dropdown_module" ]
+  extra_deps = [ ":web_components" ]
 }
 
 js_library("oobe_carousel.m") {
@@ -287,15 +285,6 @@
   namespace_rewrites = oobe_namespace_rewrites
 }
 
-polymer_modulizer("hd_iron_icon") {
-  js_file = "hd_iron_icon.js"
-  html_file = "hd_iron_icon.html"
-  html_type = "dom-module"
-  auto_imports = oobe_auto_imports
-  migrated_imports = oobe_migrated_imports
-  namespace_rewrites = oobe_namespace_rewrites
-}
-
 polymer_modulizer("network_select_login") {
   js_file = "network_select_login.js"
   html_file = "network_select_login.html"
@@ -329,15 +318,6 @@
   html_type = "iron-iconset"
 }
 
-polymer_modulizer("oobe_i18n_dropdown") {
-  js_file = "oobe_i18n_dropdown.js"
-  html_file = "oobe_i18n_dropdown.html"
-  html_type = "dom-module"
-  auto_imports = oobe_auto_imports
-  migrated_imports = oobe_migrated_imports
-  namespace_rewrites = oobe_namespace_rewrites
-}
-
 polymer_modulizer("oobe_carousel") {
   js_file = "oobe_carousel.js"
   html_file = "oobe_carousel.html"
@@ -398,8 +378,10 @@
     "gaia_button.js",
     "gaia_header.js",
     "gaia_input_form.js",
+    "hd_iron_icon.js",
     "notification_card.js",
     "progress_list_item.js",
+    "oobe_i18n_dropdown.js",
     "security_token_pin.js",
   ]
 }
diff --git a/chrome/browser/resources/chromeos/login/components/hd_iron_icon.html b/chrome/browser/resources/chromeos/login/components/hd_iron_icon.html
index e9fd3614..fbdf00e 100644
--- a/chrome/browser/resources/chromeos/login/components/hd_iron_icon.html
+++ b/chrome/browser/resources/chromeos/login/components/hd_iron_icon.html
@@ -4,46 +4,20 @@
 found in the LICENSE file.
 -->
 
-<link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<style include="oobe-common-styles">
+  @media all and (-webkit-max-device-pixel-ratio: 1.5) {
+    #icon2x {
+      display: none;
+    }
+  }
 
-<link rel="import" href="./common_styles/common_styles.html">
-
-<!--
-  <iron-icon> that automatically displays one of the two icons depending on
-  display resolution,
-
-  Example:
-    <hd-iron-icon icon1x="icons:wifi-1x" icon2x="icons:wifi-2x"></hd-iron-icon>
-
-  Attributes:
-    1x and 2x icons:
-      'icon1x' - a name of icon from material design set to show on button.
-      'icon2x' - a name of icon from material design set to show on button.
-    1x and 2x sources:
-      'src1x' - A direct source to a file. For example, a SVG file.
-      'src2x' - A direct source to a file. For example, a SVG file.
-
--->
-<dom-module id="hd-iron-icon">
-  <template>
-    <style include="oobe-common-styles">
-      @media all and (-webkit-max-device-pixel-ratio: 1.5) {
-        #icon2x {
-          display: none;
-        }
-      }
-
-      @media all and (-webkit-min-device-pixel-ratio: 1.5) {
-        #icon1x {
-          display: none;
-        }
-      }
-    </style>
-    <div class="flex layout vertical" aria-hidden="true">
-      <iron-icon id="icon1x" icon="[[icon1x]]" src="[[src1x]]"></iron-icon>
-      <iron-icon id="icon2x" icon="[[icon2x]]" src="[[src2x]]"></iron-icon>
-    </div>
-  </template>
-  <script src="hd_iron_icon.js"></script>
-</dom-module>
+  @media all and (-webkit-min-device-pixel-ratio: 1.5) {
+    #icon1x {
+      display: none;
+    }
+  }
+</style>
+<div class="flex layout vertical" aria-hidden="true">
+  <iron-icon id="icon1x" icon="[[icon1x]]" src="[[src1x]]"></iron-icon>
+  <iron-icon id="icon2x" icon="[[icon2x]]" src="[[src2x]]"></iron-icon>
+</div>
diff --git a/chrome/browser/resources/chromeos/login/components/hd_iron_icon.js b/chrome/browser/resources/chromeos/login/components/hd_iron_icon.js
index 39312a8..66f6ae3 100644
--- a/chrome/browser/resources/chromeos/login/components/hd_iron_icon.js
+++ b/chrome/browser/resources/chromeos/login/components/hd_iron_icon.js
@@ -2,17 +2,39 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/* #js_imports_placeholder */
+/**
+ * @fileoverview <iron-icon> that automatically displays one of the two icons
+ * depending on display resolution,
+ *
+ * Example:
+ *    <hd-iron-icon icon1x="icons:wifi-1x"
+ * icon2x="icons:wifi-2x"></hd-iron-icon>
+ *
+ *  Attributes:
+ *    1x and 2x icons:
+ *      'icon1x' - a name of icon from material design set to show on button.
+ *      'icon2x' - a name of icon from material design set to show on button.
+ *   1x and 2x sources:
+ *     'src1x' - A direct source to a file. For example, a SVG file.
+ *     'src2x' - A direct source to a file. For example, a SVG file.
+ */
+
+import '//resources/polymer/v3_0/iron-icon/iron-icon.js';
+import './common_styles/common_styles.m.js';
+
+import {html, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 /**
  * @polymer
  */
-class HdIronIcon extends Polymer.Element {
+class HdIronIcon extends PolymerElement {
   static get is() {
     return 'hd-iron-icon';
   }
 
-  /* #html_template_placeholder */
+  static get template() {
+    return html`{__html_template__}`;
+  }
 
   static get properties() {
     return {
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.html b/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.html
index 53b06d9..f17670b 100644
--- a/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.html
+++ b/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.html
@@ -1,24 +1,19 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<!--
+Copyright 2022 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
 
-<link rel="import" href="chrome://resources/cr_elements/md_select.css.html">
+<style include="md-select">
+  :host {
+    font-size: var(--oobe-select-font-size);
+    line-height: var(--oobe-select-line-height);
+    --md-select-width: 240px;
+  }
 
-<link rel="import" href="./oobe_select.html">
-
-<dom-module id="oobe-i18n-dropdown">
-  <template>
-    <style include="md-select">
-      :host {
-        font-size: var(--oobe-select-font-size);
-        line-height: var(--oobe-select-line-height);
-        --md-select-width: 240px;
-      }
-
-      select {
-        height: var(--oobe-select-height);
-      }
-    </style>
-    <select id="select" aria-label$="[[labelForAria]]" class="md-select" >
-    </select>
-  </template>
-  <script src="oobe_i18n_dropdown.js"></script>
-</dom-module>
+  select {
+    height: var(--oobe-select-height);
+  }
+</style>
+<select id="select" aria-label$="[[labelForAria]]" class="md-select" >
+</select>
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.js b/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.js
index 6b736ec..8b3a6f9f 100644
--- a/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.js
+++ b/chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.js
@@ -2,7 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/* #js_imports_placeholder */
+import '//resources/cr_elements/md_select.css.js';
+
+import {html, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {setupSelect} from './oobe_select.m.js';
+
 
 /**
  * Languages/keyboard descriptor to display
@@ -14,12 +19,14 @@
  * Polymer class definition for 'oobe-i18n-dropdown'.
  * @polymer
  */
-class OobeI18nDropdown extends Polymer.Element {
+class OobeI18nDropdown extends PolymerElement {
   static get is() {
     return 'oobe-i18n-dropdown';
   }
 
-  /* #html_template_placeholder */
+  static get template() {
+    return html`{__html_template__}`;
+  }
 
   static get properties() {
     return {
diff --git a/chrome/browser/resources/chromeos/login/debug/debug.js b/chrome/browser/resources/chromeos/login/debug/debug.js
index 58c3a8c5..f36dece 100644
--- a/chrome/browser/resources/chromeos/login/debug/debug.js
+++ b/chrome/browser/resources/chromeos/login/debug/debug.js
@@ -1020,6 +1020,8 @@
             googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
             crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
             countryCode: 'us',
+            showRecoveryOption: false,
+            recoveryOptionDefault: false,
           },
         },
         {
@@ -1035,6 +1037,25 @@
             googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
             crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
             countryCode: 'us',
+            showRecoveryOption: false,
+            recoveryOptionDefault: false,
+          },
+        },
+        {
+          id: 'regular-recovery',
+          trigger: (screen) => {
+            screen.setUsageOptinHidden(true);
+          },
+          data: {
+            isArcEnabled: true,
+            isDemo: false,
+            isChildAccount: false,
+            isTosHidden: false,
+            googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
+            crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
+            countryCode: 'us',
+            showRecoveryOption: true,
+            recoveryOptionDefault: true,
           },
         },
         {
@@ -1050,6 +1071,8 @@
             googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
             crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
             countryCode: 'us',
+            showRecoveryOption: false,
+            recoveryOptionDefault: false,
           },
         },
         {
@@ -1065,6 +1088,8 @@
             googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
             crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
             countryCode: 'us',
+            showRecoveryOption: false,
+            recoveryOptionDefault: false,
           },
         },
         {
@@ -1077,6 +1102,8 @@
             googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
             crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
             countryCode: 'us',
+            showRecoveryOption: false,
+            recoveryOptionDefault: false,
           },
         },
         {
@@ -1092,6 +1119,8 @@
             googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
             crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
             countryCode: 'us',
+            showRecoveryOption: false,
+            recoveryOptionDefault: false,
           },
         },
         {
@@ -1107,6 +1136,8 @@
             googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
             crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
             countryCode: 'us',
+            showRecoveryOption: false,
+            recoveryOptionDefault: false,
           },
         },
         {
@@ -1124,6 +1155,8 @@
             googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
             crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
             countryCode: 'us',
+            showRecoveryOption: false,
+            recoveryOptionDefault: false,
           },
         },
         {
@@ -1140,6 +1173,8 @@
             googleEulaUrl: 'https://policies.google.com/terms/embedded?hl=en',
             crosEulaUrl: 'https://www.google.com/intl/en/chrome/terms/',
             countryCode: 'us',
+            showRecoveryOption: false,
+            recoveryOptionDefault: false,
           },
         },
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
index 62b9319..655faae 100644
--- a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
+++ b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
@@ -113,7 +113,9 @@
   "ash/webui/common/resources/network/network_select.html",
   "ash/webui/common/resources/network/onc_mojo.html",
   "chrome/browser/resources/chromeos/login/components/gaia_button.html",
+  "chrome/browser/resources/chromeos/login/components/hd_iron_icon.html",
   "chrome/browser/resources/chromeos/login/components/notification_card.html",
+  "chrome/browser/resources/chromeos/login/components/oobe_i18n_dropdown.html",
   "chrome/browser/resources/chromeos/login/components/progress_list_item.html",
   "chrome/browser/resources/chromeos/login/components/security_token_pin.html",
   "chrome/browser/resources/chromeos/login/screens/common/offline_ad_login.html",
diff --git a/chrome/browser/resources/chromeos/login/screens/common/consolidated_consent.html b/chrome/browser/resources/chromeos/login/screens/common/consolidated_consent.html
index 579406a37..473999a 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/consolidated_consent.html
+++ b/chrome/browser/resources/chromeos/login/screens/common/consolidated_consent.html
@@ -231,6 +231,22 @@
       </cr-toggle>
     </div>
 
+    <!-- Recovery toggle row -->
+    <div id="recovery" class="layout horizontal center oobe-optin-row"
+        hidden="[[!recoveryVisible_]]">
+      <div class="oobe-optin-content flex">
+        <span id="recoveryTitle" class="oobe-optin-title">
+          [[i18nDynamic(locale, 'consolidatedConsentRecoveryOptInTitle')]]
+        </span>
+        <span>
+          [[i18nDynamic(locale, 'consolidatedConsentRecoveryOptIn')]]
+        </span>
+      </div>
+      <cr-toggle id="recoveryOptIn" checked="{{recoveryChecked}}"
+          aria-describedby="recoveryTitle">
+      </cr-toggle>
+    </div>
+
     <!-- Location services toggle row -->
     <div id="location" class="layout horizontal center oobe-optin-row"
         hidden="[[isArcOptInsHidden_(isArcEnabled_, isDemo_)]]">
diff --git a/chrome/browser/resources/chromeos/login/screens/common/consolidated_consent.js b/chrome/browser/resources/chromeos/login/screens/common/consolidated_consent.js
index 5d882bd7..6ca0959 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/consolidated_consent.js
+++ b/chrome/browser/resources/chromeos/login/screens/common/consolidated_consent.js
@@ -166,6 +166,16 @@
         type: Boolean,
         value: true,
       },
+
+      recoveryVisible_: {
+        type: Boolean,
+        value: false,
+      },
+
+      recoveryChecked: {
+        type: Boolean,
+        value: false,
+      },
     };
   }
 
@@ -249,6 +259,9 @@
     this.isTosHidden_ = data['isTosHidden'];
     this.countryCode_ = data['countryCode'];
 
+    this.recoveryVisible_ = data['showRecoveryOption'];
+    this.recoveryChecked = data['recoveryOptionDefault'];
+
     if (this.isDemo_) {
       this.usageOptinHidden_ = false;
       this.usageOptinHiddenLoading_ = false;
@@ -713,6 +726,7 @@
       this.backupChecked,
       this.locationChecked,
       this.arcTosContent_,
+      this.recoveryChecked,
     ]);
   }
 
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js
index 9b1b76d..bbe9ef63 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js
@@ -5,6 +5,7 @@
 import '//resources/polymer/v3_0/paper-styles/color.js';
 import '//resources/polymer/v3_0/iron-icon/iron-icon.js';
 import '../../components/oobe_icons.m.js';
+import '../../components/oobe_i18n_dropdown.js';
 import '../../components/buttons/oobe_back_button.m.js';
 import '../../components/buttons/oobe_text_button.m.js';
 import '../../components/common_styles/common_styles.m.js';
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/hid_detection.js b/chrome/browser/resources/chromeos/login/screens/oobe/hid_detection.js
index 9a4d477..f0fe5bf 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/hid_detection.js
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/hid_detection.js
@@ -9,7 +9,7 @@
 
 import '//resources/polymer/v3_0/paper-styles/color.js';
 import '//resources/ash/common/bluetooth/bluetooth_pairing_enter_code_page.js';
-import '../../components/hd_iron_icon.m.js';
+import '../../components/hd_iron_icon.js';
 import '../../components/oobe_icons.m.js';
 import '../../components/common_styles/common_styles.m.js';
 import '../../components/common_styles/oobe_dialog_host_styles.m.js';
diff --git a/chrome/browser/resources/downloads/manager.ts b/chrome/browser/resources/downloads/manager.ts
index 57f8c06..f7d4e43 100644
--- a/chrome/browser/resources/downloads/manager.ts
+++ b/chrome/browser/resources/downloads/manager.ts
@@ -145,7 +145,7 @@
     ];
 
     this.eventTracker_.add(
-        document, 'keydown', e => this.onKeyDown_(e as KeyboardEvent));
+        document, 'keydown', (e: Event) => this.onKeyDown_(e as KeyboardEvent));
     this.eventTracker_.add(document, 'click', () => this.onClick_());
 
     this.loaded_.promise.then(() => {
diff --git a/chrome/browser/resources/history/app.ts b/chrome/browser/resources/history/app.ts
index 6b54282..51d42ad 100644
--- a/chrome/browser/resources/history/app.ts
+++ b/chrome/browser/resources/history/app.ts
@@ -261,7 +261,7 @@
     super.connectedCallback();
 
     this.eventTracker_.add(
-        document, 'keydown', e => this.onKeyDown_(e as KeyboardEvent));
+        document, 'keydown', (e: Event) => this.onKeyDown_(e as KeyboardEvent));
     this.eventTracker_.add(
         document, 'visibilitychange', this.onVisibilityChange_.bind(this));
     this.addWebUIListener(
diff --git a/chrome/browser/resources/history/history_item.ts b/chrome/browser/resources/history/history_item.ts
index f27d8a6a..2743f5c0 100644
--- a/chrome/browser/resources/history/history_item.ts
+++ b/chrome/browser/resources/history/history_item.ts
@@ -128,7 +128,7 @@
       // history items are items in a potentially long list.
       this.eventTracker_.add(
           this.$.checkbox, 'keydown',
-          e => this.onCheckboxKeydown_(e as KeyboardEvent));
+          (e: Event) => this.onCheckboxKeydown_(e as KeyboardEvent));
     });
   }
 
diff --git a/chrome/browser/resources/new_tab_page/lazy_load.ts b/chrome/browser/resources/new_tab_page/lazy_load.ts
index 5154b82e..37a1e9d5 100644
--- a/chrome/browser/resources/new_tab_page/lazy_load.ts
+++ b/chrome/browser/resources/new_tab_page/lazy_load.ts
@@ -20,6 +20,7 @@
 export {CustomizeDialogElement} from './customize_dialog.js';
 export {CustomizeModulesElement} from './customize_modules.js';
 export {CustomizeShortcutsElement} from './customize_shortcuts.js';
+export {LensErrorType, LensFormElement} from './lens_form.js';
 export {LensUploadDialogElement} from './lens_upload_dialog.js';
 export {MiddleSlotPromoElement, PromoDismissAction} from './middle_slot_promo.js';
 export {ChromeCartProxy} from './modules/cart/chrome_cart_proxy.js';
diff --git a/chrome/browser/resources/new_tab_page/lens_form.html b/chrome/browser/resources/new_tab_page/lens_form.html
new file mode 100644
index 0000000..7cb403ff
--- /dev/null
+++ b/chrome/browser/resources/new_tab_page/lens_form.html
@@ -0,0 +1,18 @@
+<style>
+  #lensForm {
+    display: none;
+  }
+</style>
+
+<div id="lensForm">
+  <form id="fileForm"
+        action="[[uploadFileAction_]]"
+        enctype="multipart/form-data"
+        method="POST">
+    <input id="fileInput"
+           name="encoded_image"
+           type="file"
+           accept="[[supportedFileTypes_]]"
+           on-change="handleFileInputChange_"></input>
+  </form>
+</div>
diff --git a/chrome/browser/resources/new_tab_page/lens_form.ts b/chrome/browser/resources/new_tab_page/lens_form.ts
new file mode 100644
index 0000000..a67f68a1
--- /dev/null
+++ b/chrome/browser/resources/new_tab_page/lens_form.ts
@@ -0,0 +1,127 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './lens_form.html.js';
+
+/** Lens service endpoint for the Upload by File action. */
+const UPLOAD_FILE_ACTION = 'https://lens.google.com/upload';
+
+const SUPPORTED_FILE_TYPES = [
+  'image/bmp',
+  'image/heic',
+  'image/heif',
+  'image/jpeg',
+  'image/png',
+  'image/tiff',
+  'image/webp',
+  'image/x-icon',
+];
+
+/** Maximum file size support by Lens in bytes. */
+const MAX_FILE_SIZE_BYTES = 20 * 1024 * 1024;  // 20MB
+
+export enum LensErrorType {
+  // The user attempted to upload multiple files at the same time.
+  MULTIPLE_FILES,
+  // The user didn't provide a file.
+  NO_FILE,
+  // The user provided a file type that is not supported.
+  FILE_TYPE,
+  // The user provided a file that is too large.
+  FILE_SIZE,
+}
+
+export interface LensFormElement {
+  $: {
+    fileForm: HTMLFormElement,
+    fileInput: HTMLInputElement,
+  };
+}
+
+export class LensFormElement extends PolymerElement {
+  static get is() {
+    return 'ntp-lens-form';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      supportedFileTypes_: {
+        type: String,
+        readOnly: true,
+        value: SUPPORTED_FILE_TYPES.join(','),
+      },
+      uploadFileAction_: {
+        type: String,
+        readOnly: true,
+        value: UPLOAD_FILE_ACTION,
+      },
+    };
+  }
+
+  openSystemFilePicker() {
+    this.$.fileInput.click();
+  }
+
+  private handleFileInputChange_() {
+    const fileList = this.$.fileInput.files;
+    if (fileList) {
+      this.submitFileList_(fileList);
+    }
+  }
+
+  private submitFileList_(files: FileList) {
+    if (files.length > 1) {
+      this.dispatchError_(LensErrorType.MULTIPLE_FILES);
+      return;
+    }
+    const file = files[0];
+
+    if (!file) {
+      this.dispatchError_(LensErrorType.NO_FILE);
+      return;
+    }
+    return this.submitFile_(file);
+  }
+
+  private submitFile_(file: File) {
+    if (!SUPPORTED_FILE_TYPES.includes(file.type)) {
+      this.dispatchError_(LensErrorType.FILE_TYPE);
+      return;
+    }
+
+    if (file.size > MAX_FILE_SIZE_BYTES) {
+      this.dispatchError_(LensErrorType.FILE_SIZE);
+      return;
+    }
+
+    const dataTransfer = new DataTransfer();
+    dataTransfer.items.add(file);
+    this.$.fileInput.files = dataTransfer.files;
+
+    this.dispatchEvent(new Event('loading'));
+    this.$.fileForm.submit();
+  }
+
+  private dispatchError_(errorType: LensErrorType) {
+    this.dispatchEvent(new CustomEvent('error', {
+      bubbles: false,
+      composed: false,
+      detail: errorType,
+    }));
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'ntp-lens-form': LensFormElement;
+  }
+}
+
+customElements.define(LensFormElement.is, LensFormElement);
diff --git a/chrome/browser/resources/new_tab_page/lens_upload_dialog.html b/chrome/browser/resources/new_tab_page/lens_upload_dialog.html
index 01256762..aa0247f 100644
--- a/chrome/browser/resources/new_tab_page/lens_upload_dialog.html
+++ b/chrome/browser/resources/new_tab_page/lens_upload_dialog.html
@@ -20,7 +20,7 @@
     width: calc(100% + 8px);
   }
 
-  :host([is-dragging_]), 
+  :host([is-dragging_]),
   :host([is-loading_]) {
     --upload-dialog-drag-drop-background: var(--google-blue-50);
   }
@@ -246,9 +246,14 @@
   }
 </style>
 
+<ntp-lens-form id="lensForm"
+               on-loading="handleFormLoading_"
+               on-error="handleFormError_">
+</ntp-lens-form>
+
 <div id="dialog" hidden$="{{isHidden_}}" tabindex="-1" lang="$i18n{language}">
   <div id="container">
-    <cr-icon-button id="closeButton" class="icon-clear" 
+    <cr-icon-button id="closeButton" class="icon-clear"
         title="$i18n{lensSearchUploadDialogCloseButtonLabel}"
         on-click="onCloseButtonClick_">
     </cr-icon-button>
@@ -262,7 +267,10 @@
           <div id="dragDropIllustration"></div>
           <div class="drag-drop-title">
             <span id="dragText">$i18n{lensSearchUploadDialogDragTitle}</span>
-            <span tabindex="0" role="button" id="uploadText">
+            <span tabindex="0"
+                  role="button"
+                  id="uploadText"
+                  on-click="onUploadFileClick_">
               $i18n{lensSearchUploadDialogUploadFileTitle}
             </span>
           </div>
@@ -275,7 +283,7 @@
           </div>
           <div id="inputContainer">
             <input id="inputBox" autocomplete="false" autocorrect="false"
-                placeholder="$i18n{lensSearchUploadDialogTextPlaceholder}" 
+                placeholder="$i18n{lensSearchUploadDialogTextPlaceholder}"
                 text="text">
             <div id="inputSubmit" tabindex="0" role="button">
               $i18n{lensSearchUploadDialogSearchButtonLabel}
@@ -319,4 +327,4 @@
       </template>
     </div>
   </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/chrome/browser/resources/new_tab_page/lens_upload_dialog.ts b/chrome/browser/resources/new_tab_page/lens_upload_dialog.ts
index 6917ccf..ffda4a0 100644
--- a/chrome/browser/resources/new_tab_page/lens_upload_dialog.ts
+++ b/chrome/browser/resources/new_tab_page/lens_upload_dialog.ts
@@ -8,6 +8,7 @@
 
 import {afterNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+import {LensErrorType, LensFormElement} from './lens_form.js';
 import {getTemplate} from './lens_upload_dialog.html.js';
 import {WindowProxy} from './window_proxy.js';
 
@@ -29,6 +30,7 @@
 export interface LensUploadDialogElement {
   $: {
     dialog: HTMLDivElement,
+    lensForm: LensFormElement,
   };
 }
 
@@ -162,6 +164,18 @@
   private onOfflineRetryButtonClick_() {
     this.setOnlineState_();
   }
+
+  private onUploadFileClick_() {
+    this.$.lensForm.openSystemFilePicker();
+  }
+
+  private handleFormLoading_() {
+    this.dialogState_ = DialogState.LOADING;
+  }
+
+  private handleFormError_(_event: CustomEvent<LensErrorType>) {
+    // TODO(crbug.com/1367506): Implement error state.
+  }
 }
 declare global {
   interface HTMLElementTagNameMap {
diff --git a/chrome/browser/resources/new_tab_page/new_tab_page.gni b/chrome/browser/resources/new_tab_page/new_tab_page.gni
index 123aa97..4dd699500 100644
--- a/chrome/browser/resources/new_tab_page/new_tab_page.gni
+++ b/chrome/browser/resources/new_tab_page/new_tab_page.gni
@@ -29,6 +29,7 @@
       "customize_shortcuts.ts",
       "doodle_share_dialog.ts",
       "iframe.ts",
+      "lens_form.ts",
       "lens_upload_dialog.ts",
       "logo.ts",
       "middle_slot_promo.ts",
diff --git a/chrome/browser/resources/pdf/pdf_viewer.ts b/chrome/browser/resources/pdf/pdf_viewer.ts
index faa76a4..05bb506 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.ts
+++ b/chrome/browser/resources/pdf/pdf_viewer.ts
@@ -503,6 +503,8 @@
   private onPresentClick_() {
     const scroller = this.$.scroller;
 
+    this.viewport.saveZoomState();
+
     Promise
         .all([
           eventToPromise('fullscreenchange', scroller),
@@ -526,6 +528,9 @@
 
             // Ensure that directional keys still work after exiting.
             this.shadowRoot!.querySelector('embed')!.focus();
+
+            // Set zoom back to original zoom before presentation mode.
+            this.viewport.restoreZoomState();
           });
 
           // Nothing else to do here. The viewport will be updated as a result
diff --git a/chrome/browser/resources/pdf/pdf_viewer_base.ts b/chrome/browser/resources/pdf/pdf_viewer_base.ts
index 9d0373f..c7256eb 100644
--- a/chrome/browser/resources/pdf/pdf_viewer_base.ts
+++ b/chrome/browser/resources/pdf/pdf_viewer_base.ts
@@ -191,7 +191,7 @@
     this.tracker.add(
         pluginController.getEventTarget(),
         PluginControllerEventType.PLUGIN_MESSAGE,
-        e => this.handlePluginMessage(e as CustomEvent<MessageData>));
+        (e: Event) => this.handlePluginMessage(e as CustomEvent<MessageData>));
 
     document.body.addEventListener('change-page-and-xy', e => {
       const point =
diff --git a/chrome/browser/resources/pdf/viewport.ts b/chrome/browser/resources/pdf/viewport.ts
index f334ef2..edbfc3e 100644
--- a/chrome/browser/resources/pdf/viewport.ts
+++ b/chrome/browser/resources/pdf/viewport.ts
@@ -77,6 +77,13 @@
   private internalZoom_: number = 1;
 
   /**
+   * Zoom state used to change zoom and fitting type to what it was
+   * originally when saved.
+   */
+  private savedZoom_: number|null = null;
+  private savedFittingType_: FittingType|null = null;
+
+  /**
    * Predefined zoom factors to be used when zooming in/out. These are in
    * ascending order.
    */
@@ -591,6 +598,30 @@
     });
   }
 
+  /**
+   * Save the current zoom and fitting type.
+   */
+  saveZoomState() {
+    this.savedZoom_ = this.internalZoom_;
+    this.savedFittingType_ = this.fittingType_;
+  }
+
+  /**
+   * Set zoom and fitting type to what it was when saved. See saveZoomState().
+   */
+  restoreZoomState() {
+    assert(
+        this.savedZoom_ !== null && this.savedFittingType_ !== null,
+        'No saved zoom state exists');
+    if (this.savedFittingType_ === FittingType.NONE) {
+      this.setZoom(this.savedZoom_);
+    } else {
+      this.setFittingType(this.savedFittingType_);
+    }
+    this.savedZoom_ = null;
+    this.savedFittingType_ = null;
+  }
+
   /** @param e Event containing the old browser zoom. */
   private updateZoomFromBrowserChange_(e: CustomEvent<number>) {
     const oldBrowserZoom = e.detail;
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index c5f643c..8dd737b 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -239,9 +239,6 @@
     "site_settings/pdf_documents.ts",
     "site_settings/protocol_handlers.ts",
     "site_settings/settings_category_default_radio_group.ts",
-    "site_settings/site_data_details_subpage.ts",
-    "site_settings/site_data_entry.ts",
-    "site_settings/site_data.ts",
     "site_settings/site_details_permission.ts",
     "site_settings/site_details.ts",
     "site_settings/site_entry.ts",
@@ -363,8 +360,6 @@
     "settings_page/main_page_mixin.ts",
     "settings_routes.ts",
     "site_settings/constants.ts",
-    "site_settings/cookie_info.ts",
-    "site_settings/local_data_browser_proxy.ts",
     "site_settings/site_settings_mixin.ts",
     "site_settings/site_settings_prefs_browser_proxy.ts",
     "site_settings/website_usage_browser_proxy.ts",
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html
index 5a633a61..7adf9c7f 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -2,14 +2,14 @@
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
         section="a11y" focus-config="[[focusConfig_]]">
       <div route-path="default">
-<if expr="chromeos_ash">
+<if expr="is_chromeos">
         <cr-link-row
             label="$i18n{manageAccessibilityFeatures}"
             on-click="onManageSystemAccessibilityFeaturesTap_"
             sub-label="$i18n{moreFeaturesLinkDescription}" external>
         </cr-link-row>
 </if>
-<if expr="not chromeos_ash">
+<if expr="not is_chromeos">
         <template is="dom-if" if="[[captionSettingsOpensExternally_]]">
           <template is="dom-if" if="[[enableLiveCaption_]]">
             <settings-live-caption prefs="{{prefs}}"></settings-live-caption>
@@ -58,7 +58,7 @@
             external>
         </cr-link-row>
       </div>
-<if expr="not chromeos_ash">
+<if expr="not is_chromeos">
       <template is="dom-if" if="[[!captionSettingsOpensExternally_]]">
         <template is="dom-if" route-path="/captions">
           <settings-subpage
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.ts b/chrome/browser/resources/settings/a11y_page/a11y_page.ts
index bed2088a..b6d24aaf 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.ts
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.ts
@@ -12,7 +12,7 @@
 import '../controls/settings_toggle_button.js';
 import '../settings_page/settings_animated_pages.js';
 import '../settings_shared.css.js';
-// <if expr="not is_macosx and not chromeos_ash">
+// <if expr="not is_macosx and not is_chromeos">
 import './captions_subpage.js';
 import '../settings_page/settings_subpage.js';
 // </if>
@@ -67,7 +67,7 @@
         notify: true,
       },
 
-      // <if expr="not chromeos_ash">
+      // <if expr="not is_chromeos">
       enableLiveCaption_: {
         type: Boolean,
         value: function() {
@@ -127,7 +127,7 @@
     };
   }
 
-  // <if expr="not chromeos_ash">
+  // <if expr="not is_chromeos">
   private enableLiveCaption_: boolean;
   private showFocusHighlightOption_: boolean;
   // </if>
@@ -172,7 +172,7 @@
     }
   }
 
-  // <if expr="not chromeos_ash">
+  // <if expr="not is_chromeos">
   private onFocusHighlightChange_(event: Event) {
     chrome.metricsPrivate.recordBoolean(
         'Accessibility.FocusHighlight.ToggleEnabled',
@@ -180,7 +180,7 @@
   }
   // </if>
 
-  // <if expr="chromeos_ash">
+  // <if expr="is_chromeos">
   private onManageSystemAccessibilityFeaturesTap_() {
     if (loadTimeData.valueExists(
             'isAccessibilityOSSettingsVisibilityEnabled') &&
diff --git a/chrome/browser/resources/settings/appearance_page/home_url_input.ts b/chrome/browser/resources/settings/appearance_page/home_url_input.ts
index 888b92d1..b3f7b97 100644
--- a/chrome/browser/resources/settings/appearance_page/home_url_input.ts
+++ b/chrome/browser/resources/settings/appearance_page/home_url_input.ts
@@ -62,7 +62,7 @@
     };
   }
 
-  pref: chrome.settingsPrivate.PrefObject|undefined;
+  pref: chrome.settingsPrivate.PrefObject<string>|undefined;
   disabled: boolean;
   canTab: boolean;
   invalid: boolean;
diff --git a/chrome/browser/resources/settings/chromeos/device_page/display.html b/chrome/browser/resources/settings/chromeos/device_page/display.html
index f5e6ce6..418b3da6 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/display.html
+++ b/chrome/browser/resources/settings/chromeos/device_page/display.html
@@ -1,4 +1,5 @@
-<style include="settings-shared md-select iron-flex iron-flex-alignment">
+<style include="cr-shared-style settings-shared md-select iron-flex
+  iron-flex-alignment">
   .indented {
     align-self: stretch;
     margin-inline-start: var(--cr-section-indent-padding);
@@ -328,6 +329,7 @@
     </div>
     <settings-dropdown-menu
         id="nightLightScheduleTypeDropDown"
+        class="cr-row-gap"
         label="$i18n{displayNightLightScheduleLabel}"
         aria-describedby="nightLightScheduleSubLabel"
         pref="{{prefs.ash.night_light.schedule_type}}"
diff --git a/chrome/browser/resources/settings/chromeos/device_page/display.js b/chrome/browser/resources/settings/chromeos/device_page/display.js
index ad711a4..330c819 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/display.js
+++ b/chrome/browser/resources/settings/chromeos/device_page/display.js
@@ -22,10 +22,11 @@
 import '../../settings_vars.css.js';
 import '../../controls/settings_dropdown_menu.js';
 import 'chrome://resources/cr_elements/cr_slider/cr_slider.js';
+import 'chrome://resources/cr_elements/cr_shared_style.css.js';
 
-import {focusWithoutInk} from 'chrome://resources/ash/common/focus_without_ink_js.js';
 import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js';
 import {assert} from 'chrome://resources/js/assert.js';
+import {focusWithoutInk} from 'chrome://resources/ash/common/focus_without_ink_js.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {flush, html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
diff --git a/chrome/browser/resources/settings/chromeos/settings_scheduler_slider/settings_scheduler_slider.ts b/chrome/browser/resources/settings/chromeos/settings_scheduler_slider/settings_scheduler_slider.ts
index 3232948a..8a6ace4 100644
--- a/chrome/browser/resources/settings/chromeos/settings_scheduler_slider/settings_scheduler_slider.ts
+++ b/chrome/browser/resources/settings/chromeos/settings_scheduler_slider/settings_scheduler_slider.ts
@@ -45,11 +45,6 @@
   ddy: number,
 }>;
 
-interface PrefObject extends chrome.settingsPrivate.PrefObject {
-  type: chrome.settingsPrivate.PrefType.NUMBER;
-  value: number;
-}
-
 const HOURS_PER_DAY = 24;
 const MIN_KNOBS_DISTANCE_MINUTES = 60;
 const OFFSET_MINUTES_6PM = 18 * 60;
@@ -151,8 +146,8 @@
     ];
   }
 
-  prefStartTime: PrefObject;
-  prefEndTime: PrefObject;
+  prefStartTime: chrome.settingsPrivate.PrefObject<number>;
+  prefEndTime: chrome.settingsPrivate.PrefObject<number>;
   private dragObject_: HTMLElement|null;
   private isReady_: boolean;
   private isRTL_: boolean;
diff --git a/chrome/browser/resources/settings/controls/settings_slider.ts b/chrome/browser/resources/settings/controls/settings_slider.ts
index 5996455..c2b7b4a 100644
--- a/chrome/browser/resources/settings/controls/settings_slider.ts
+++ b/chrome/browser/resources/settings/controls/settings_slider.ts
@@ -94,7 +94,7 @@
     ];
   }
 
-  pref: chrome.settingsPrivate.PrefObject;
+  pref: chrome.settingsPrivate.PrefObject<number>;
   ticks: SliderTick[]|number[];
   scale: number;
   min: number;
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts
index 81edcce..5f1b24f7 100644
--- a/chrome/browser/resources/settings/lazy_load.ts
+++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -26,7 +26,6 @@
 import './privacy_page/security_keys_phones_dialog.js';
 import './privacy_page/security_page.js';
 import './site_settings/all_sites.js';
-import './site_settings/site_data_details_subpage.js';
 import './site_settings_page/site_settings_page.js';
 import './site_settings/category_default_setting.js';
 import './site_settings/category_setting_exceptions.js';
@@ -35,7 +34,6 @@
 import './site_settings/pdf_documents.js';
 import './site_settings/protocol_handlers.js';
 import './site_settings/settings_category_default_radio_group.js';
-import './site_settings/site_data.js';
 import './site_settings/site_details.js';
 import './site_settings/zoom_levels.js';
 // <if expr="not is_chromeos">
@@ -193,14 +191,10 @@
 export {ChooserExceptionListElement} from './site_settings/chooser_exception_list.js';
 export {ChooserExceptionListEntryElement} from './site_settings/chooser_exception_list_entry.js';
 export {ChooserType, ContentSetting, ContentSettingsTypes, CookieControlsMode, NotificationSetting, SITE_EXCEPTION_WILDCARD, SiteSettingSource, SortMethod} from './site_settings/constants.js';
-export {CookieDetails, cookieInfo} from './site_settings/cookie_info.js';
 export {SettingsEditExceptionDialogElement} from './site_settings/edit_exception_dialog.js';
-export {LocalDataBrowserProxy, LocalDataBrowserProxyImpl, LocalDataItem} from './site_settings/local_data_browser_proxy.js';
 export {AppHandlerEntry, AppProtocolEntry, HandlerEntry, ProtocolEntry, ProtocolHandlersElement} from './site_settings/protocol_handlers.js';
 export {SettingsReviewNotificationPermissionsElement} from './site_settings/review_notification_permissions.js';
 export {SettingsCategoryDefaultRadioGroupElement} from './site_settings/settings_category_default_radio_group.js';
-export {SiteDataElement} from './site_settings/site_data.js';
-export {SiteDataDetailsSubpageElement} from './site_settings/site_data_details_subpage.js';
 export {SiteDetailsElement} from './site_settings/site_details.js';
 export {SiteDetailsPermissionElement} from './site_settings/site_details_permission.js';
 export {SiteEntryElement} from './site_settings/site_entry.js';
diff --git a/chrome/browser/resources/settings/privacy_page/cookies_page.html b/chrome/browser/resources/settings/privacy_page/cookies_page.html
index 82bd129..93e41c70 100644
--- a/chrome/browser/resources/settings/privacy_page/cookies_page.html
+++ b/chrome/browser/resources/settings/privacy_page/cookies_page.html
@@ -163,7 +163,7 @@
         on-settings-boolean-control-change="onNetworkPredictionChange_">
     </settings-toggle-button>
     <cr-link-row id="site-data-trigger" class="hr"
-        on-click="onSiteDataClick_" label="[[getSiteDataLabel_()]]"
+        on-click="onSiteDataClick_" label="$i18n{cookiePageAllSitesLink}"
         role-description="$i18n{subpageArrowRoleDescription}">
     </cr-link-row>
     <div id="exceptionHeader">
diff --git a/chrome/browser/resources/settings/privacy_page/cookies_page.ts b/chrome/browser/resources/settings/privacy_page/cookies_page.ts
index 641ead6..e30db45 100644
--- a/chrome/browser/resources/settings/privacy_page/cookies_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/cookies_page.ts
@@ -140,12 +140,6 @@
         },
       },
 
-      enableConsolidatedSiteStorageControls_: {
-        type: Boolean,
-        value: () =>
-            loadTimeData.getBoolean('consolidatedSiteStorageControlsEnabled'),
-      },
-
       focusConfig: {
         type: Object,
         observer: 'focusConfigChanged_',
@@ -167,7 +161,6 @@
   private cookiesContentSettingType_: ContentSettingsTypes;
   private exceptionListsReadOnly_: boolean;
   private blockAllPref_: chrome.settingsPrivate.PrefObject;
-  private enableConsolidatedSiteStorageControls_: boolean;
   focusConfig: FocusConfig;
 
   private metricsBrowserProxy_: MetricsBrowserProxy =
@@ -175,24 +168,15 @@
 
   private focusConfigChanged_(_newConfig: FocusConfig, oldConfig: FocusConfig) {
     assert(!oldConfig);
-    assert(
-        this.enableConsolidatedSiteStorageControls_ ?
-            routes.SITE_SETTINGS_ALL :
-            routes.SITE_SETTINGS_SITE_DATA);
     const selectSiteDataLinkRow = () => {
       const toFocus =
           this.shadowRoot!.querySelector<HTMLElement>('#site-data-trigger');
       assert(toFocus);
       focusWithoutInk(toFocus);
     };
-    if (this.enableConsolidatedSiteStorageControls_) {
-      this.focusConfig.set(
-          `${routes.SITE_SETTINGS_ALL.path}_${routes.COOKIES.path}`,
-          selectSiteDataLinkRow);
-    } else {
-      this.focusConfig.set(
-          routes.SITE_SETTINGS_SITE_DATA.path, selectSiteDataLinkRow);
-    }
+    this.focusConfig.set(
+        `${routes.SITE_SETTINGS_ALL.path}_${routes.COOKIES.path}`,
+        selectSiteDataLinkRow);
   }
 
   override currentRouteChanged(route: Route) {
@@ -213,18 +197,8 @@
   }
   // </if>
 
-  private getSiteDataLabel_(): string {
-    return this.enableConsolidatedSiteStorageControls_ ?
-        this.i18n('cookiePageAllSitesLink') :
-        this.i18n('siteSettingsCookieLink');
-  }
-
   private onSiteDataClick_() {
-    if (this.enableConsolidatedSiteStorageControls_) {
-      Router.getInstance().navigateTo(routes.SITE_SETTINGS_ALL);
-    } else {
-      Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
-    }
+    Router.getInstance().navigateTo(routes.SITE_SETTINGS_ALL);
   }
 
   private onGeneratedPrefsUpdated_() {
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.ts b/chrome/browser/resources/settings/privacy_page/personalization_options.ts
index 25cc81c..3941dbb 100644
--- a/chrome/browser/resources/settings/privacy_page/personalization_options.ts
+++ b/chrome/browser/resources/settings/privacy_page/personalization_options.ts
@@ -119,7 +119,7 @@
   syncStatus: SyncStatus;
 
   // <if expr="_google_chrome and not chromeos_ash">
-  private metricsReportingPref_: chrome.settingsPrivate.PrefObject;
+  private metricsReportingPref_: chrome.settingsPrivate.PrefObject<boolean>;
   private showRestart_: boolean;
   // </if>
 
@@ -218,7 +218,7 @@
 
   private setMetricsReportingPref_(metricsReporting: MetricsReporting) {
     const hadPreviousPref = this.metricsReportingPref_.value !== undefined;
-    const pref: chrome.settingsPrivate.PrefObject = {
+    const pref: chrome.settingsPrivate.PrefObject<boolean> = {
       key: '',
       type: chrome.settingsPrivate.PrefType.BOOLEAN,
       value: metricsReporting.enabled,
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts
index efc73f5..f02d8c40 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts
@@ -86,7 +86,7 @@
    * set with the next sync prefs update.
    */
   private syncAllCache_: boolean|null = null;
-  private historySyncVirtualPref_: chrome.settingsPrivate.PrefObject;
+  private historySyncVirtualPref_: chrome.settingsPrivate.PrefObject<boolean>;
   private metricsBrowserProxy_: MetricsBrowserProxy =
       MetricsBrowserProxyImpl.getInstance();
   private startStateHistorySyncOn_: boolean;
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 1b1b150..c5d18c1a 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -246,16 +246,6 @@
           </settings-cookies-page>
         </settings-subpage>
       </template>
-      <template is="dom-if" route-path="/siteData" no-search>
-        <settings-subpage page-title="$i18n{siteSettingsCookieHeader}"
-            search-label="$i18n{siteSettingsCookieSearch}"
-            search-term="{{siteDataFilter_}}"
-            preserve-search-term>
-          <site-data filter="[[siteDataFilter_]]"
-              focus-config="[[focusConfig_]]">
-          </site-data>
-        </settings-subpage>
-      </template>
       <template is="dom-if" route-path="/content/images" no-search>
         <settings-subpage page-title="$i18n{siteSettingsCategoryImages}"
             search-label="$i18n{siteSettingsAllSitesSearch}"
@@ -746,16 +736,6 @@
           </site-details>
         </settings-subpage>
       </template>
-      <template is="dom-if" route-path="/cookies/detail" no-search>
-        <settings-subpage page-title="[[pageTitle]]">
-          <cr-button slot="subpage-title-extra"
-              on-click="onRemoveAllCookiesFromSite_">
-            $i18n{siteSettingsCookieRemoveAll}
-          </cr-button>
-          <site-data-details-subpage page-title="{{pageTitle}}">
-          </site-data-details-subpage>
-        </settings-subpage>
-      </template>
       <template is="dom-if" route-path="/content/protectedContent" no-search>
 <if expr="not chromeos_ash and not chromeos_lacros and not is_win">
         <settings-subpage page-title="$i18n{siteSettingsProtectedContent}">
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
index b96ab8b..e2ad521 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
@@ -15,7 +15,6 @@
 import '../controls/settings_toggle_button.js';
 import '../prefs/prefs.js';
 import '../site_settings/settings_category_default_radio_group.js';
-import '../site_settings/site_data_details_subpage.js';
 import '../settings_page/settings_animated_pages.js';
 import '../settings_page/settings_subpage.js';
 import '../settings_shared.css.js';
@@ -46,7 +45,7 @@
 
 interface BlockAutoplayStatus {
   enabled: boolean;
-  pref: chrome.settingsPrivate.PrefObject;
+  pref: chrome.settingsPrivate.PrefObject<boolean>;
 }
 
 export interface SettingsPrivacyPageElement {
@@ -220,7 +219,6 @@
       },
 
       searchFilter_: String,
-      siteDataFilter_: String,
 
       /**
        * Expose ContentSettingsTypes enum to HTML bindings.
@@ -274,7 +272,6 @@
   private safetyCheckNotificationPermissionsEnabled_: boolean;
   private focusConfig_: FocusConfig;
   private searchFilter_: string;
-  private siteDataFilter_: string;
   private browserProxy_: PrivacyPageBrowserProxy =
       PrivacyPageBrowserProxyImpl.getInstance();
   private metricsBrowserProxy_: MetricsBrowserProxy =
@@ -345,19 +342,6 @@
     this.browserProxy_.setBlockAutoplayEnabled(target.checked);
   }
 
-  /**
-   * This is a workaround to connect the remove all button to the subpage.
-   */
-  private onRemoveAllCookiesFromSite_() {
-    // Intentionally not casting to SiteDataDetailsSubpageElement, as this would
-    // require importing site_data_details_subpage.js and would endup in the
-    // main JS bundle.
-    const node = this.shadowRoot!.querySelector('site-data-details-subpage');
-    if (node) {
-      node.removeAll();
-    }
-  }
-
   private onClearBrowsingDataTap_() {
     this.interactedWithPage_();
 
diff --git a/chrome/browser/resources/settings/privacy_page/secure_dns.ts b/chrome/browser/resources/settings/privacy_page/secure_dns.ts
index a259f1b2..5254cfc 100644
--- a/chrome/browser/resources/settings/privacy_page/secure_dns.ts
+++ b/chrome/browser/resources/settings/privacy_page/secure_dns.ts
@@ -134,7 +134,7 @@
   }
 
   private secureDnsDescription_: string;
-  private secureDnsToggle_: chrome.settingsPrivate.PrefObject;
+  private secureDnsToggle_: chrome.settingsPrivate.PrefObject<boolean>;
   private showRadioGroup_: boolean;
   private secureDnsRadio_: SecureDnsMode;
   private resolverOptions_: ResolverOption[];
@@ -301,7 +301,7 @@
     }
     // If the underlying secure DNS mode pref has an enforced value, communicate
     // that via the toggle pref.
-    const pref: chrome.settingsPrivate.PrefObject = {
+    const pref: chrome.settingsPrivate.PrefObject<boolean> = {
       key: '',
       type: chrome.settingsPrivate.PrefType.BOOLEAN,
       value: this.secureDnsToggle_.value,
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts
index 762f5c9..ad75a39 100644
--- a/chrome/browser/resources/settings/route.ts
+++ b/chrome/browser/resources/settings/route.ts
@@ -57,11 +57,6 @@
       r.SITE_SETTINGS.createChild('backgroundSync');
   r.SITE_SETTINGS_CAMERA = r.SITE_SETTINGS.createChild('camera');
   r.SITE_SETTINGS_CLIPBOARD = r.SITE_SETTINGS.createChild('clipboard');
-  if (!loadTimeData.getBoolean('consolidatedSiteStorageControlsEnabled')) {
-    r.SITE_SETTINGS_SITE_DATA = r.COOKIES.createChild('/siteData');
-    r.SITE_SETTINGS_DATA_DETAILS =
-        r.SITE_SETTINGS_SITE_DATA.createChild('/cookies/detail');
-  }
   r.SITE_SETTINGS_IDLE_DETECTION = r.SITE_SETTINGS.createChild('idleDetection');
   r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images');
   r.SITE_SETTINGS_MIXEDSCRIPT = r.SITE_SETTINGS.createChild('insecureContent');
diff --git a/chrome/browser/resources/settings/settings_routes.ts b/chrome/browser/resources/settings/settings_routes.ts
index 964998b..2bace34b 100644
--- a/chrome/browser/resources/settings/settings_routes.ts
+++ b/chrome/browser/resources/settings/settings_routes.ts
@@ -59,7 +59,6 @@
   SITE_SETTINGS_CAMERA: Route;
   SITE_SETTINGS_CLIPBOARD: Route;
   SITE_SETTINGS_COOKIES: Route;
-  SITE_SETTINGS_DATA_DETAILS: Route;
   SITE_SETTINGS_FEDERATED_IDENTITY_API: Route;
   SITE_SETTINGS_HANDLERS: Route;
   SITE_SETTINGS_HID_DEVICES: Route;
@@ -79,7 +78,6 @@
   SITE_SETTINGS_PDF_DOCUMENTS: Route;
   SITE_SETTINGS_POPUPS: Route;
   SITE_SETTINGS_PROTECTED_CONTENT: Route;
-  SITE_SETTINGS_SITE_DATA: Route;
   SITE_SETTINGS_SITE_DETAILS: Route;
   SITE_SETTINGS_USB_DEVICES: Route;
   SITE_SETTINGS_SERIAL_PORTS: Route;
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.html b/chrome/browser/resources/settings/site_settings/all_sites.html
index b4807744..66162f69 100644
--- a/chrome/browser/resources/settings/site_settings/all_sites.html
+++ b/chrome/browser/resources/settings/site_settings/all_sites.html
@@ -42,7 +42,7 @@
     <div id="sort">
       <label id="sortLabel">$i18n{siteSettingsAllSitesSort}</label>
       <select id="sortMethod" class="md-select" aria-labelledby="sortLabel"
-        on-change="onSortMethodChanged_">
+          on-change="onSortMethodChanged_">
         <option value="[[sortMethods_.MOST_VISITED]]">
           $i18n{siteSettingsAllSitesSortMethodMostVisited}
         </option>
@@ -98,87 +98,17 @@
     <cr-lazy-render id="menu">
       <template>
         <cr-action-menu role-description="$i18n{menu}">
-          <template is="dom-if" if="[[enableFirstPartySetsUI_]]">
-            <button class="dropdown-item" role="menuitem"
-                on-click="onShowRelatedSites_">
-                $i18n{firstPartySetsShowRelatedSitesButton}
-            </button>
-            <button class="dropdown-item" role="menuitem"
-                on-click="onRemove_">
-                $i18n{firstPartySetsSiteClearStorageButton}
-            </button>
-          </template>
-          <template is="dom-if" if="[[!enableFirstPartySetsUI_]]">
-            <button hidden$="[[actionMenuModel_.isPartitioned]]"
-                class="dropdown-item" role="menuitem"
-                on-click="onConfirmResetSettings_">
-              $i18n{siteSettingsSiteGroupReset}
-            </button>
-            <button class="dropdown-item" role="menuitem"
-                on-click="onConfirmClearData_">
-              $i18n{siteSettingsSiteGroupDelete}
-            </button>
-          </template>
+          <button class="dropdown-item" role="menuitem"
+              on-click="onShowRelatedSites_">
+            $i18n{firstPartySetsShowRelatedSitesButton}
+          </button>
+          <button class="dropdown-item" role="menuitem" on-click="onRemove_">
+            $i18n{firstPartySetsSiteClearStorageButton}
+          </button>
         </cr-action-menu>
       </template>
     </cr-lazy-render>
 
-    <!-- Confirm reset settings dialog. -->
-    <cr-lazy-render id="confirmResetSettings">
-      <template>
-        <cr-dialog close-text="$i18n{close}">
-          <div slot="title">
-            $i18n{siteSettingsSiteGroupResetDialogTitle}
-          </div>
-          <div slot="body">
-            [[getResetPermissionsLabel_(actionMenuModel_)]]
-          </div>
-          <div slot="button-container">
-            <cr-button class="cancel-button" on-click="onCloseDialog_">
-              $i18n{cancel}
-            </cr-button>
-            <cr-button class="action-button" on-click="onResetSettings_">
-              $i18n{siteSettingsSiteResetAll}
-            </cr-button>
-          </div>
-        </cr-dialog>
-      </template>
-    </cr-lazy-render>
-
-    <!-- Confirm clear data dialog. -->
-    <cr-lazy-render id="confirmClearData">
-      <template>
-        <cr-dialog close-text="$i18n{close}">
-          <div slot="title">
-            $i18n{siteSettingsSiteGroupDeleteDialogTitle}
-          </div>
-          <div slot="body">
-            [[getClearDataLabel_(actionMenuModel_)]]
-            <div class="detail-list">
-              <div class="detail">
-                <iron-icon icon="all-sites:logout" aria-hidden="true"
-                  role="presentation"></iron-icon>
-                [[getLogoutLabel_()]]
-              </div>
-              <div class="detail">
-                <iron-icon icon="all-sites:offline" aria-hidden="true"
-                  role="presentation"></iron-icon>
-                $i18n{siteSettingsSiteGroupDeleteOfflineData}
-              </div>
-            </div>
-          </div>
-          <div slot="button-container">
-            <cr-button class="cancel-button" on-click="onCloseDialog_">
-              $i18n{cancel}
-            </cr-button>
-            <cr-button class="action-button" on-click="onClearData_">
-              $i18n{siteSettingsSiteClearStorage}
-            </cr-button>
-          </div>
-        </cr-dialog>
-      </template>
-    </cr-lazy-render>
-
     <!-- Confirm remove site dialog. -->
     <cr-lazy-render id="confirmRemoveSite">
       <template>
@@ -198,7 +128,7 @@
               $i18n{siteSettingsRemoveSiteOfflineData}
             </div>
             <div id="permissionsBulletPoint" class="detail"
-              hidden$="[[!showPermissionsBulletPoint_(actionMenuModel_)]]">
+                hidden$="[[!showPermissionsBulletPoint_(actionMenuModel_)]]">
               <iron-icon icon="settings:permissions"></iron-icon>
               $i18n{siteSettingsRemoveSitePermissions}
             </div>
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.ts b/chrome/browser/resources/settings/site_settings/all_sites.ts
index dce009d6..05318d5 100644
--- a/chrome/browser/resources/settings/site_settings/all_sites.ts
+++ b/chrome/browser/resources/settings/site_settings/all_sites.ts
@@ -23,9 +23,9 @@
 import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
 import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
 import {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js';
-import {assert} from 'chrome://resources/js/assert_ts.js';
 import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {WebUIListenerMixin, WebUIListenerMixinInterface} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
+import {assert} from 'chrome://resources/js/assert_ts.js';
 import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 import {afterNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -36,7 +36,6 @@
 
 import {getTemplate} from './all_sites.html.js';
 import {AllSitesAction2, AllSitesDialog, ContentSetting, SortMethod} from './constants.js';
-import {LocalDataBrowserProxy, LocalDataBrowserProxyImpl} from './local_data_browser_proxy.js';
 import {SiteSettingsMixin, SiteSettingsMixinInterface} from './site_settings_mixin.js';
 import {OriginInfo, SiteGroup} from './site_settings_prefs_browser_proxy.js';
 
@@ -72,9 +71,7 @@
     clearAllButton: HTMLElement,
     clearLabel: HTMLElement,
     confirmClearAllData: CrLazyRenderElement<CrDialogElement>,
-    confirmClearData: CrLazyRenderElement<CrDialogElement>,
     confirmRemoveSite: CrLazyRenderElement<CrDialogElement>,
-    confirmResetSettings: CrLazyRenderElement<CrDialogElement>,
     listContainer: HTMLElement,
     menu: CrLazyRenderElement<CrActionMenuElement>,
     sortMethod: HTMLSelectElement,
@@ -151,14 +148,6 @@
       },
 
       /**
-       * Whether First Party Sets are enabled.
-       */
-      enableFirstPartySetsUI_: {
-        type: Boolean,
-        value: () => loadTimeData.getBoolean('firstPartySetsUIEnabled'),
-      },
-
-      /**
        * All possible sort methods.
        */
       sortMethods_: {
@@ -211,15 +200,12 @@
   private filteredList_: SiteGroup[];
   subpageRoute: Route;
   filter: string;
-  private enableFirstPartySetsUI_: boolean;
   private selectedItem_: SelectedItem|null;
   private listBlurred_: boolean;
   private actionMenuModel_: ActionMenuModel|null;
   private clearAllData_: boolean;
   private sortMethod_?: SortMethod;
   private totalUsage_: string;
-  private localDataBrowserProxy_: LocalDataBrowserProxy =
-      LocalDataBrowserProxyImpl.getInstance();
 
   override ready() {
     super.ready();
@@ -578,38 +564,6 @@
   }
 
   /**
-   * Confirms the resetting of all content settings for an origin.
-   */
-  private onConfirmResetSettings_(e: Event) {
-    e.preventDefault();
-    const scope = this.actionMenuModel_!.actionScope === 'origin' ? 'Origin' :
-                                                                    'SiteGroup';
-    const scopes = [AllSitesDialog.RESET_PERMISSIONS, scope, 'DialogOpened'];
-    this.recordUserAction_(scopes);
-    this.$.confirmResetSettings.get().showModal();
-  }
-
-  /**
-   * Confirms the clearing of all storage data for an etld+1.
-   */
-  private onConfirmClearData_(e: Event) {
-    e.preventDefault();
-    const {actionScope, index, origin} = this.actionMenuModel_!;
-    const {origins, hasInstalledPWA} = this.filteredList_[index];
-
-    const scope = actionScope === 'origin' ? 'Origin' : 'SiteGroup';
-    const appInstalled = actionScope === 'origin' ?
-        (origins.find(o => o.origin === origin) || {}).isInstalled :
-        hasInstalledPWA;
-    const installed = appInstalled ? 'Installed' : '';
-
-    const scopes =
-        [AllSitesDialog.CLEAR_DATA, scope, installed, 'DialogOpened'];
-    this.recordUserAction_(scopes);
-    this.$.confirmClearData.get().showModal();
-  }
-
-  /**
    * Checks if a filter is applied.
    * @return True if a filter is applied.
    */
@@ -669,72 +623,6 @@
     this.$.menu.get().close();
   }
 
-  /**
-   * Get the appropriate label string for the clear data dialog based on whether
-   * user is clearing data for an origin or siteGroup, and whether or not the
-   * origin/siteGroup has an associated installed app.
-   */
-  private getClearDataLabel_(): string {
-    // actionMenuModel_ will be null when dialog closes
-    if (this.actionMenuModel_ === null) {
-      return '';
-    }
-
-    const {index, origin} = this.actionMenuModel_;
-
-    const {origins, hasInstalledPWA} = this.filteredList_[index];
-
-    if (origin) {
-      const {isInstalled = false} =
-          origins.find(o => o.origin === origin) || {};
-      const messageId = isInstalled ?
-          'siteSettingsOriginDeleteConfirmationInstalled' :
-          'siteSettingsOriginDeleteConfirmation';
-      return loadTimeData.substituteString(
-          this.i18n(messageId), this.originRepresentation(origin));
-    } else {
-      // Clear SiteGroup
-      let messageId;
-      if (hasInstalledPWA) {
-        const multipleAppsInstalled = (this.filteredList_[index].origins || [])
-                                          .filter(o => o.isInstalled)
-                                          .length > 1;
-
-        messageId = multipleAppsInstalled ?
-            'siteSettingsSiteGroupDeleteConfirmationInstalledPlural' :
-            'siteSettingsSiteGroupDeleteConfirmationInstalled';
-      } else {
-        messageId = 'siteSettingsSiteGroupDeleteConfirmationNew';
-      }
-      const displayName = this.actionMenuModel_.item.etldPlus1 ||
-          this.originRepresentation(
-              this.actionMenuModel_.item.origins[0].origin);
-      return loadTimeData.substituteString(this.i18n(messageId), displayName);
-    }
-  }
-
-  /**
-   * Get the appropriate label for the reset permissions confirmation
-   * dialog, dependent on whether user is resetting permissions for an
-   * origin or an entire SiteGroup.
-   */
-  private getResetPermissionsLabel_(): string {
-    if (this.actionMenuModel_ === null) {
-      return '';
-    }
-
-    if (this.actionMenuModel_.actionScope === 'origin') {
-      return loadTimeData.substituteString(
-          this.i18n('siteSettingsSiteResetConfirmation'),
-          this.originRepresentation(this.actionMenuModel_.origin));
-    }
-    return loadTimeData.substituteString(
-        this.i18n('siteSettingsSiteGroupResetConfirmation'),
-        this.actionMenuModel_.item.etldPlus1 ||
-            this.originRepresentation(
-                this.actionMenuModel_.item.origins[0].origin));
-  }
-
   private getRemoveSiteTitle_(): string {
     if (this.actionMenuModel_ === null) {
       return '';
@@ -867,17 +755,6 @@
     return this.i18n(signOutLabelId);
   }
 
-  /**
-   * Get the appropriate label for the clear data confirmation
-   * dialog, depending on whether the user is clearing data for a
-   * single origin or an entire site group.
-   */
-  private getLogoutLabel_(): string {
-    return this.actionMenuModel_!.actionScope === 'origin' ?
-        this.i18n('siteSettingsSiteClearStorageSignOut') :
-        this.i18n('siteSettingsSiteGroupDeleteSignOut');
-  }
-
   private recordUserAction_(scopes: string[]) {
     chrome.metricsPrivate.recordUserAction(
         ['AllSites', ...scopes].filter(Boolean).join('_'));
@@ -906,75 +783,6 @@
   }
 
   /**
-   * Resets all permissions for a single origin or all origins listed in
-   * |siteGroup.origins|.
-   */
-  private onResetSettings_(e: Event) {
-    const {actionScope, index, origin} = this.actionMenuModel_!;
-    const siteGroupToUpdate = this.filteredList_[index];
-
-    const updatedSiteGroup: SiteGroup = {
-      etldPlus1: siteGroupToUpdate.etldPlus1,
-      hasInstalledPWA: false,
-      numCookies: siteGroupToUpdate.numCookies,
-      fpsOwner: siteGroupToUpdate.fpsOwner,
-      fpsNumMembers: siteGroupToUpdate.fpsNumMembers,
-      origins: [],
-    };
-
-    if (actionScope === 'origin') {
-      this.browserProxy.recordAction(AllSitesAction2.RESET_ORIGIN_PERMISSIONS);
-      this.recordUserAction_(
-          [AllSitesDialog.RESET_PERMISSIONS, 'Origin', 'Confirm']);
-
-      this.resetPermissionsForOrigin_(origin);
-      updatedSiteGroup.origins = siteGroupToUpdate.origins;
-      const updatedOrigin =
-          updatedSiteGroup.origins.find(o => o.origin === origin)!;
-      updatedOrigin.hasPermissionSettings = false;
-      if (updatedOrigin.numCookies <= 0 || updatedOrigin.usage <= 0) {
-        updatedSiteGroup.origins =
-            updatedSiteGroup.origins.filter(o => o.origin !== origin);
-      }
-    } else {
-      // Reset permissions for entire site group
-      this.browserProxy.recordAction(
-          AllSitesAction2.RESET_SITE_GROUP_PERMISSIONS);
-      this.recordUserAction_(
-          [AllSitesDialog.RESET_PERMISSIONS, 'SiteGroup', 'Confirm']);
-
-      if (this.actionMenuModel_!.item.etldPlus1 !==
-          siteGroupToUpdate.etldPlus1) {
-        return;
-      }
-      siteGroupToUpdate.origins.forEach(originEntry => {
-        this.resetPermissionsForOrigin_(originEntry.origin);
-        if (originEntry.numCookies > 0 || originEntry.usage > 0) {
-          originEntry.hasPermissionSettings = false;
-          updatedSiteGroup.origins.push(originEntry);
-        }
-      });
-    }
-
-    if (updatedSiteGroup.origins.length > 0) {
-      this.set('filteredList_.' + index, updatedSiteGroup);
-    } else if (siteGroupToUpdate.numCookies > 0) {
-      // If there is no origin for this site group that has any data,
-      // but the ETLD+1 has cookies in use, create a origin placeholder
-      // for display purposes.
-      const originPlaceHolder = this.generatePlaceholderOrigin_(
-          siteGroupToUpdate.etldPlus1, siteGroupToUpdate.numCookies);
-      updatedSiteGroup.origins.push(originPlaceHolder);
-      this.set('filteredList_.' + index, updatedSiteGroup);
-    } else {
-      this.splice('filteredList_', index, 1);
-    }
-
-    this.$.allSitesList.fire('iron-resize');
-    this.onCloseDialog_(e);
-  }
-
-  /**
    * Helper to remove data and cookies for an etldPlus1.
    * @param index The index of the target siteGroup in filteredList_ that should
    *     be cleared.
@@ -1003,41 +811,6 @@
     this.updateSiteGroup_(index, updatedSiteGroup);
   }
 
-  /**
-   * Helper to remove data and cookies for an origin.
-   * @param index The index of the target siteGroup in filteredList_ that should
-   *     be cleared.
-   * @param origin The origin of the target origin that should be cleared.
-   */
-  private clearDataForOrigin_(index: number, origin: string) {
-    this.browserProxy.clearUnpartitionedOriginDataAndCookies(
-        this.toUrl(origin)!.href);
-
-    const siteGroupToUpdate = this.filteredList_[index];
-    const updatedSiteGroup: SiteGroup = {
-      etldPlus1: siteGroupToUpdate.etldPlus1,
-      hasInstalledPWA: false,
-      numCookies: 0,
-      fpsOwner: siteGroupToUpdate.fpsOwner,
-      fpsNumMembers: siteGroupToUpdate.fpsNumMembers,
-      origins: [],
-    };
-
-    const updatedOrigin =
-        siteGroupToUpdate.origins.find(o => o.origin === origin)!;
-    if (updatedOrigin.hasPermissionSettings) {
-      updatedOrigin.numCookies = 0;
-      updatedOrigin.usage = 0;
-      updatedSiteGroup.origins = siteGroupToUpdate.origins;
-    } else {
-      updatedSiteGroup.origins =
-          siteGroupToUpdate.origins.filter(o => o.origin !== origin);
-    }
-
-    updatedSiteGroup.hasInstalledPWA =
-        updatedSiteGroup.origins.some(o => o.isInstalled);
-    this.updateSiteGroup_(index, updatedSiteGroup);
-  }
 
   /**
    * Updates the UI after permissions have been reset or data/cookies
@@ -1057,42 +830,6 @@
   }
 
   /**
-   * Clear data and cookies for an etldPlus1.
-   */
-  private onClearData_(e: Event) {
-    const {index, actionScope, origin} = this.actionMenuModel_!;
-    const scopes: string[] = [AllSitesDialog.CLEAR_DATA];
-
-    if (actionScope === 'origin') {
-      this.browserProxy.recordAction(AllSitesAction2.CLEAR_ORIGIN_DATA);
-
-      const {origins} = this.filteredList_[index];
-
-      scopes.push('Origin');
-      const installed =
-          (origins.find(o => o.origin === origin) || {}).isInstalled ?
-          'Installed' :
-          '';
-      this.recordUserAction_([...scopes, installed, 'Confirm']);
-
-      this.clearDataForOrigin_(index, origin);
-    } else {
-      this.browserProxy.recordAction(AllSitesAction2.CLEAR_SITE_GROUP_DATA);
-
-      scopes.push('SiteGroup');
-      const {hasInstalledPWA} = this.filteredList_[index];
-      const installed = hasInstalledPWA ? 'Installed' : '';
-      this.recordUserAction_([...scopes, installed, 'Confirm']);
-
-      this.clearDataForSiteGroupIndex_(index);
-    }
-
-    this.$.allSitesList.fire('iron-resize');
-    this.updateTotalUsage_();
-    this.onCloseDialog_(e);
-  }
-
-  /**
    * Clear data and cookies for all sites.
    */
   private onClearAllData_(e: Event) {
diff --git a/chrome/browser/resources/settings/site_settings/cookie_info.ts b/chrome/browser/resources/settings/site_settings/cookie_info.ts
deleted file mode 100644
index 4fe022f..0000000
--- a/chrome/browser/resources/settings/site_settings/cookie_info.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// clang-format off
-import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-// clang-format on
-
-export interface CookieDetails {
-  hasChildren: boolean;
-  id: string;
-  idPath: string;
-  title: string;
-  totalUsage: string;
-  type: string;
-}
-
-export interface CookieDataForDisplay {
-  content: string;
-  label: string;
-}
-
-// This structure maps the various cookie type names from C++ (hence the
-// underscores) to arrays of the different types of data each has, along with
-// the i18n name for the description of that data type.
-// This structure serves three purposes:
-// 1) to list what subset of the cookie data we want to show in the UI.
-// 2) What order to show it in.
-// 3) What user friendly label to prefix the data with.
-export const cookieInfo: {[key: string]: string[][]} = {
-  'cookie': [
-    ['name', 'cookieName'],
-    ['content', 'cookieContent'],
-    ['domain', 'cookieDomain'],
-    ['path', 'cookiePath'],
-    ['sendfor', 'cookieSendFor'],
-    ['accessibleToScript', 'cookieAccessibleToScript'],
-    ['created', 'cookieCreated'],
-    ['expires', 'cookieExpires'],
-  ],
-  'database': [
-    ['origin', 'databaseOrigin'],
-    ['size', 'localStorageSize'],
-    ['modified', 'localStorageLastModified'],
-  ],
-  'local_storage': [
-    ['origin', 'localStorageOrigin'],
-    ['size', 'localStorageSize'],
-    ['modified', 'localStorageLastModified'],
-  ],
-  'indexed_db': [
-    ['origin', 'indexedDbOrigin'],
-    ['size', 'indexedDbSize'],
-    ['modified', 'indexedDbLastModified'],
-  ],
-  'file_system': [
-    ['origin', 'fileSystemOrigin'],
-    ['persistent', 'fileSystemPersistentUsage'],
-    ['temporary', 'fileSystemTemporaryUsage'],
-  ],
-  'quota': [['origin', 'quotaOrigin'], ['totalUsage', 'quotaSize']],
-  'service_worker':
-      [['origin', 'serviceWorkerOrigin'], ['size', 'serviceWorkerSize']],
-  'shared_worker':
-      [['worker', 'sharedWorkerWorker'], ['name', 'sharedWorkerName']],
-  'cache_storage': [
-    ['origin', 'cacheStorageOrigin'],
-    ['size', 'cacheStorageSize'],
-    ['modified', 'cacheStorageLastModified'],
-  ],
-  'flash_lso': [['domain', 'cookieDomain']],
-};
-
-/**
- * Get cookie data for a given HTML node.
- * @param data The contents of the cookie.
- */
-export function getCookieData(data: CookieDetails): CookieDataForDisplay[] {
-  const out: CookieDataForDisplay[] = [];
-  const fields = cookieInfo[data.type];
-  for (let i = 0; i < fields.length; i++) {
-    const field = fields[i];
-    // Iterate through the keys found in |cookieInfo| for the given |type|
-    // and see if those keys are present in the data. If so, display them
-    // (in the order determined by |cookieInfo|).
-    const key = field[0];
-    const value = (data as unknown as {[key: string]: string})[key];
-    if (value.length > 0) {
-      const entry = {
-        label: loadTimeData.getString(field[1]),
-        content: value,
-      };
-      out.push(entry);
-    }
-  }
-  return out;
-}
diff --git a/chrome/browser/resources/settings/site_settings/local_data_browser_proxy.ts b/chrome/browser/resources/settings/site_settings/local_data_browser_proxy.ts
deleted file mode 100644
index 84392d84..0000000
--- a/chrome/browser/resources/settings/site_settings/local_data_browser_proxy.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview A helper object used from the Cookies and Local Storage Data
- * section.
- */
-
-// clang-format off
-import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
-import {CookieDetails} from './cookie_info.js';
-// clang-format on
-
-export interface LocalDataItem {
-  localData: string;
-  site: string;
-}
-
-export interface LocalDataBrowserProxy {
-  getDisplayList(filter: string): Promise<LocalDataItem[]>;
-
-  /**
-   * Removes all local data (local storage, cookies, etc.).
-   * Note: on-tree-item-removed will not be sent.
-   */
-  removeAll(): Promise<void>;
-
-  /**
-   * Remove items that pass the current filter. Completion signaled by
-   * on-tree-item-removed.
-   */
-  removeShownItems(): void;
-
-  /**
-   * Remove data for a specific site. Completion signaled by
-   * on-tree-item-removed.
-   */
-  removeSite(site: string): void;
-
-  /**
-   * Gets the cookie details for a particular site.
-   */
-  getCookieDetails(site: string): Promise<CookieDetails[]>;
-
-  /**
-   * Gets the plural string for a given number of cookies.
-   * @param numCookies The number of cookies.
-   */
-  getNumCookiesString(numCookies: number): Promise<string>;
-
-  /**
-   * Gets display string for FPS information of owner and member count.
-   * @param fpsNumMembers The number of members in the first party set.
-   * @param fpsOwner The eTLD+1 for the first party set owner.
-   */
-  getFpsMembershipLabel(fpsNumMembers: number, fpsOwner: string):
-      Promise<string>;
-
-  /**
-   * Reloads all local data.
-   * TODO(dschuyler): rename function to reload().
-   */
-  reloadCookies(): Promise<void>;
-
-  /**
-   * Removes a given piece of site data.
-   * @param path The path to the item in the tree model.
-   */
-  removeItem(path: string): void;
-
-  /**
-   * Removes all SameSite=None cookies, as well as storage available in
-   * third-party contexts.
-   * Note: on-tree-item-removed will not be sent.
-   */
-  removeAllThirdPartyCookies(): Promise<void>;
-}
-
-export class LocalDataBrowserProxyImpl implements LocalDataBrowserProxy {
-  getDisplayList(filter: string) {
-    return sendWithPromise('localData.getDisplayList', filter);
-  }
-
-  removeAll() {
-    return sendWithPromise('localData.removeAll');
-  }
-
-  removeShownItems() {
-    chrome.send('localData.removeShownItems');
-  }
-
-  removeSite(site: string) {
-    chrome.send('localData.removeSite', [site]);
-  }
-
-  getCookieDetails(site: string) {
-    return sendWithPromise('localData.getCookieDetails', site);
-  }
-
-  getNumCookiesString(numCookies: number) {
-    return sendWithPromise('localData.getNumCookiesString', numCookies);
-  }
-
-  getFpsMembershipLabel(fpsNumMembers: number, fpsOwner: string) {
-    return sendWithPromise('getFpsMembershipLabel', fpsNumMembers, fpsOwner);
-  }
-
-  reloadCookies() {
-    return sendWithPromise('localData.reload');
-  }
-
-  removeItem(path: string) {
-    chrome.send('localData.removeItem', [path]);
-  }
-
-  removeAllThirdPartyCookies() {
-    return sendWithPromise('localData.removeThirdPartyCookies');
-  }
-
-  static getInstance(): LocalDataBrowserProxy {
-    return instance || (instance = new LocalDataBrowserProxyImpl());
-  }
-
-  static setInstance(obj: LocalDataBrowserProxy) {
-    instance = obj;
-  }
-}
-
-let instance: LocalDataBrowserProxy|null = null;
diff --git a/chrome/browser/resources/settings/site_settings/protocol_handlers.ts b/chrome/browser/resources/settings/site_settings/protocol_handlers.ts
index 1a03d97..4858894 100644
--- a/chrome/browser/resources/settings/site_settings/protocol_handlers.ts
+++ b/chrome/browser/resources/settings/site_settings/protocol_handlers.ts
@@ -144,7 +144,7 @@
   toggleOffLabel: string;
   toggleOnLabel: string;
   ignoredProtocols: HandlerEntry[];
-  private handlersEnabledPref_: chrome.settingsPrivate.PrefObject;
+  private handlersEnabledPref_: chrome.settingsPrivate.PrefObject<boolean>;
 
   override ready() {
     super.ready();
diff --git a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts
index caefac3..ff77593 100644
--- a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts
+++ b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts
@@ -111,7 +111,7 @@
   blockOptionLabel: string;
   blockOptionSubLabel: string;
   blockOptionIcon: string;
-  private pref_: chrome.settingsPrivate.PrefObject;
+  private pref_: chrome.settingsPrivate.PrefObject<number>;
 
   override ready() {
     super.ready();
diff --git a/chrome/browser/resources/settings/site_settings/site_data.html b/chrome/browser/resources/settings/site_settings/site_data.html
deleted file mode 100644
index 7f8f0d0..0000000
--- a/chrome/browser/resources/settings/site_settings/site_data.html
+++ /dev/null
@@ -1,77 +0,0 @@
-    <style include="cr-shared-style settings-shared">
-      paper-spinner-lite {
-        height: var(--cr-icon-size);
-        opacity: 0;
-        transition-delay: 1s;
-        width: var(--cr-icon-size);
-      }
-
-      paper-spinner-lite[active] {
-        opacity: 1;
-      }
-
-      #removeShowingSites {
-        margin-inline-start: auto;
-      }
-    </style>
-    <div class="cr-row continuation">
-      <paper-spinner-lite active="[[isLoading_]]"></paper-spinner-lite>
-      <cr-button disabled$="[[isLoading_]]" id="removeShowingSites"
-          on-click="onRemoveShowingSitesTap_" hidden$="[[!sites.length]]">
-        [[computeRemoveLabel_(filter)]]
-      </cr-button>
-      <cr-button disabled$="[[isLoading_]]" id="removeThirdPartyCookies"
-          class="cr-button-gap"
-          on-click="onRemoveThirdPartyCookiesTap_"
-          hidden$="[[!showRemoveThirdPartyCookies_(sites.length, filter)]]">
-          $i18n{siteSettingsCookieRemoveAllThirdParty}
-      </cr-button>
-    </div>
-    <iron-list id="list" items="[[sites]]" preserve-focus
-        scroll-target="[[subpageScrollTarget]]" class="cr-separators">
-      <template>
-        <site-data-entry id$="siteItem_[[item.site]]" actionable
-            model="[[item]]" first$="[[!index]]" tabindex$="[[tabIndex]]"
-            iron-list-tab-index="[[tabIndex]]" last-focused="{{lastFocused_}}"
-            list-blurred="{{listBlurred_}}" on-click="onSiteClick_"
-            on-remove-site="onRemoveSite_" focus-row-index="[[index]]">
-        </site-data-entry>
-      </template>
-    </iron-list>
-
-    <!-- Confirm Delete dialog -->
-    <cr-dialog id="confirmDeleteDialog" close-text="$i18n{close}"
-        on-close="onConfirmDeleteDialogClosed_">
-      <div slot="title">
-        $i18n{siteSettingsCookieRemoveDialogTitle}
-      </div>
-      <div slot="body">$i18n{siteSettingsCookieRemoveMultipleConfirmation}</div>
-      <div slot="button-container">
-        <cr-button class="cancel-button" on-click="onCloseDialog_">
-          $i18n{cancel}
-        </cr-button>
-        <cr-button class="action-button" on-click="onConfirmDelete_">
-          $i18n{siteSettingsCookiesClearAll}
-        </cr-button>
-      </div>
-    </cr-dialog>
-
-    <!-- Confirm Delete Third Party Cookies dialog -->
-    <cr-dialog id="confirmDeleteThirdPartyDialog" close-text="$i18n{close}"
-        on-close="onConfirmDeleteThirdPartyDialogClosed_">
-      <div slot="title">
-        $i18n{siteSettingsCookieRemoveThirdPartyDialogTitle}
-      </div>
-      <div slot="body">
-        $i18n{siteSettingsCookieRemoveThirdPartyConfirmation}
-      </div>
-      <div slot="button-container">
-        <cr-button class="cancel-button" on-click="onCloseThirdPartyDialog_">
-          $i18n{cancel}
-        </cr-button>
-        <cr-button class="action-button" on-click="onConfirmThirdPartyDelete_">
-          $i18n{siteSettingsCookiesClearThirdParty}
-        </cr-button>
-      </div>
-    </cr-dialog>
-
diff --git a/chrome/browser/resources/settings/site_settings/site_data.ts b/chrome/browser/resources/settings/site_settings/site_data.ts
deleted file mode 100644
index d5ac0e4..0000000
--- a/chrome/browser/resources/settings/site_settings/site_data.ts
+++ /dev/null
@@ -1,322 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview
- * 'site-data' handles showing the local storage summary list for all sites.
- */
-
-import 'chrome://resources/cr_elements/cr_button/cr_button.js';
-import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
-import 'chrome://resources/cr_elements/cr_search_field/cr_search_field.js';
-import 'chrome://resources/cr_elements/icons.html.js';
-import 'chrome://resources/cr_elements/cr_shared_style.css.js';
-import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
-import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
-import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
-import '../settings_shared.css.js';
-import './site_data_entry.js';
-
-import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
-import {assert} from 'chrome://resources/js/assert_ts.js';
-import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js';
-import {ListPropertyUpdateMixin} from 'chrome://resources/cr_elements/list_property_update_mixin.js';
-import {WebUIListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
-import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
-import {DomRepeatEvent, microTask, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {BaseMixin} from '../base_mixin.js';
-import {FocusConfig} from '../focus_config.js';
-import {GlobalScrollTargetMixin} from '../global_scroll_target_mixin.js';
-import {loadTimeData} from '../i18n_setup.js';
-import {MetricsBrowserProxyImpl, PrivacyElementInteractions} from '../metrics_browser_proxy.js';
-import {routes} from '../route.js';
-import {Route, Router} from '../router.js';
-
-import {LocalDataBrowserProxy, LocalDataBrowserProxyImpl, LocalDataItem} from './local_data_browser_proxy.js';
-import {getTemplate} from './site_data.html.js';
-
-interface SelectedItem {
-  item: LocalDataItem;
-  index: number;
-}
-
-export interface SiteDataElement {
-  $: {
-    confirmDeleteDialog: CrDialogElement,
-    confirmDeleteThirdPartyDialog: CrDialogElement,
-    list: IronListElement,
-    removeShowingSites: HTMLElement,
-    removeAllThirdPartyCookies: HTMLElement,
-  };
-}
-
-const SiteDataElementBase = ListPropertyUpdateMixin(
-    GlobalScrollTargetMixin(WebUIListenerMixin(BaseMixin(PolymerElement))));
-
-export class SiteDataElement extends SiteDataElementBase {
-  static get is() {
-    return 'site-data';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      /**
-       * The current filter applied to the cookie data list.
-       */
-      filter: {
-        observer: 'onFilterChanged_',
-        notify: true,
-        type: String,
-      },
-
-      focusConfig: {
-        type: Object,
-        observer: 'focusConfigChanged_',
-      },
-
-      isLoading_: Boolean,
-
-      sites: {
-        type: Array,
-        value() {
-          return [];
-        },
-      },
-
-      /**
-       * GlobalScrollTargetMixin
-       */
-      subpageRoute: {
-        type: Object,
-        value: routes.SITE_SETTINGS_SITE_DATA,
-      },
-
-      lastFocused_: Object,
-      listBlurred_: Boolean,
-    };
-  }
-
-  filter: string;
-  focusConfig: FocusConfig;
-  private isLoading_: boolean;
-  sites: LocalDataItem[];
-  subpageRoute: Route;
-  private listBlurred_: boolean;
-  private browserProxy_: LocalDataBrowserProxy =
-      LocalDataBrowserProxyImpl.getInstance();
-  private lastSelected_: SelectedItem|null;
-
-  constructor() {
-    super();
-
-    /**
-     * When navigating to site data details sub-page, |lastSelected_| holds the
-     * site name as well as the index of the selected site. This is used when
-     * navigating back to site data in order to focus on the correct site.
-     */
-    this.lastSelected_ = null;
-  }
-
-  override ready() {
-    super.ready();
-
-    this.addWebUIListener('on-tree-item-removed', () => this.updateSiteList_());
-  }
-
-  /**
-   * Reload cookies when the site data page is visited.
-   *
-   * RouteObserverMixin
-   */
-  override currentRouteChanged(currentRoute: Route, previousRoute: Route) {
-    super.currentRouteChanged(currentRoute);
-    // Reload cookies on navigation to the site data page from a different
-    // page. Avoid reloading on repeated navigations to the same page, as these
-    // are likely search queries.
-    if (currentRoute === routes.SITE_SETTINGS_SITE_DATA &&
-        currentRoute !== previousRoute) {
-      this.isLoading_ = true;
-      // Needed to fix iron-list rendering issue. The list will not render
-      // correctly until a scroll occurs.
-      // See https://crbug.com/853906.
-      const ironList = this.shadowRoot!.querySelector('iron-list')!;
-      ironList.scrollToIndex(0);
-      this.browserProxy_.reloadCookies().then(() => this.updateSiteList_());
-    }
-  }
-
-  private focusConfigChanged_(_newConfig: FocusConfig, oldConfig: FocusConfig) {
-    // focusConfig is set only once on the parent, so this observer should only
-    // fire once.
-    assert(!oldConfig);
-
-    // Populate the |focusConfig| map of the parent <settings-animated-pages>
-    // element, with additional entries that correspond to subpage trigger
-    // elements residing in this element's Shadow DOM.
-    if (routes.SITE_SETTINGS_DATA_DETAILS) {
-      const onNavigatedTo = () => microTask.run(() => {
-        if (this.lastSelected_ === null || this.sites.length === 0) {
-          return;
-        }
-
-        const lastSelectedSite = this.lastSelected_.item.site;
-        const lastSelectedIndex = this.lastSelected_.index;
-        this.lastSelected_ = null;
-
-        const indexFromId =
-            this.sites.findIndex(site => site.site === lastSelectedSite);
-
-        // If the site is no longer in |sites|, use the index as a fallback.
-        // Since the sites are sorted, an alternative could be to select the
-        // site that comes next in sort order.
-        const indexFallback = lastSelectedIndex < this.sites.length ?
-            lastSelectedIndex :
-            this.sites.length - 1;
-        const index = indexFromId > -1 ? indexFromId : indexFallback;
-        this.focusOnSiteSelectButton_(index);
-      });
-      this.focusConfig.set(
-          routes.SITE_SETTINGS_DATA_DETAILS.path, onNavigatedTo);
-    }
-  }
-
-  private focusOnSiteSelectButton_(index: number) {
-    const ironList = this.shadowRoot!.querySelector('iron-list')!;
-    ironList.focusItem(index);
-    const siteToSelect = this.sites[index].site.replace(/[.]/g, '\\.');
-    const button =
-        this.$$(`#siteItem_${siteToSelect}`)!.shadowRoot!
-            .querySelector<HTMLElement>('.subpage-arrow');
-    assert(button);
-    focusWithoutInk(button);
-  }
-
-  private onFilterChanged_(_current: string, previous?: string) {
-    // Ignore filter changes which do not occur on the site data page. The
-    // site settings data details subpage expects the tree model to remain in
-    // the same state.
-    if (previous === undefined ||
-        Router.getInstance().getCurrentRoute() !==
-            routes.SITE_SETTINGS_SITE_DATA) {
-      return;
-    }
-    this.updateSiteList_();
-  }
-
-  /**
-   * Gather all the site data.
-   */
-  private updateSiteList_() {
-    this.isLoading_ = true;
-    this.browserProxy_.getDisplayList(this.filter).then(localDataItems => {
-      this.updateList('sites', item => item.site, localDataItems);
-      this.isLoading_ = false;
-      this.fire('site-data-list-complete');
-    });
-  }
-
-  /**
-   * Returns the string to use for the Remove label.
-   * @param filter The current filter string.
-   */
-  private computeRemoveLabel_(filter: string): string {
-    if (filter.length === 0) {
-      return loadTimeData.getString('siteSettingsCookieRemoveAll');
-    }
-    return loadTimeData.getString('siteSettingsCookieRemoveAllShown');
-  }
-
-  private onCloseDialog_() {
-    this.$.confirmDeleteDialog.close();
-  }
-
-  private onCloseThirdPartyDialog_() {
-    this.$.confirmDeleteThirdPartyDialog.close();
-  }
-
-  private onConfirmDeleteDialogClosed_() {
-    focusWithoutInk(this.$.removeShowingSites);
-  }
-
-  private onConfirmDeleteThirdPartyDialogClosed_() {
-    focusWithoutInk(this.$.removeAllThirdPartyCookies);
-  }
-
-  /**
-   * Shows a dialog to confirm the deletion of multiple sites.
-   */
-  private onRemoveShowingSitesTap_(e: Event) {
-    e.preventDefault();
-    this.$.confirmDeleteDialog.showModal();
-  }
-
-  /**
-   * Shows a dialog to confirm the deletion of cookies available
-   * in third-party contexts and associated site data.
-   */
-  private onRemoveThirdPartyCookiesTap_(e: Event) {
-    e.preventDefault();
-    this.$.confirmDeleteThirdPartyDialog.showModal();
-  }
-
-  /**
-   * Called when deletion for all showing sites has been confirmed.
-   */
-  private onConfirmDelete_() {
-    this.$.confirmDeleteDialog.close();
-    if (this.filter.length === 0) {
-      MetricsBrowserProxyImpl.getInstance().recordSettingsPageHistogram(
-          PrivacyElementInteractions.SITE_DATA_REMOVE_ALL);
-      this.browserProxy_.removeAll().then(() => {
-        this.sites = [];
-      });
-    } else {
-      MetricsBrowserProxyImpl.getInstance().recordSettingsPageHistogram(
-          PrivacyElementInteractions.SITE_DATA_REMOVE_FILTERED);
-      this.browserProxy_.removeShownItems();
-      // We just deleted all items found by the filter, let's reset the filter.
-      this.fire('clear-subpage-search');
-    }
-  }
-
-  /**
-   * Called when deletion of all third-party cookies and site data has been
-   * confirmed.
-   */
-  private onConfirmThirdPartyDelete_() {
-    this.$.confirmDeleteThirdPartyDialog.close();
-    this.browserProxy_.removeAllThirdPartyCookies().then(() => {
-      this.updateSiteList_();
-    });
-  }
-
-  private onSiteClick_(event: DomRepeatEvent<LocalDataItem>) {
-    // If any delete button is selected, the focus will be in a bad state when
-    // returning to this page. To avoid this, the site select button is given
-    // focus. See https://crbug.com/872197.
-    this.focusOnSiteSelectButton_(event.model.index);
-    Router.getInstance().navigateTo(
-        routes.SITE_SETTINGS_DATA_DETAILS,
-        new URLSearchParams('site=' + event.model.item.site));
-    this.lastSelected_ = event.model;
-  }
-
-  private showRemoveThirdPartyCookies_(): boolean {
-    return loadTimeData.getBoolean('enableRemovingAllThirdPartyCookies') &&
-        this.sites.length > 0 && this.filter.length === 0;
-  }
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'site-data': SiteDataElement;
-  }
-}
-
-customElements.define(SiteDataElement.is, SiteDataElement);
diff --git a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html b/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html
deleted file mode 100644
index f4e8961c..0000000
--- a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html
+++ /dev/null
@@ -1,44 +0,0 @@
-    <style include="cr-shared-style settings-shared md-select iron-flex">
-      .cr-row {
-        padding-inline-start: 0;
-      }
-
-      [first] {
-        border-top: none;
-      }
-
-      cr-expand-button {
-        padding: 0 var(--cr-section-padding);
-      }
-
-      .separator {
-        margin-inline-start: 0;
-      }
-
-      .secondary,
-      .start {
-        max-width: 100%;
-        word-break: break-word;
-      }
-    </style>
-    <template is="dom-repeat" items="[[entries_]]">
-      <div class="cr-row" first$="[[!index]]">
-        <cr-expand-button class="flex" expanded="{{item.expanded_}}">
-          [[getEntryDescription_(item)]]
-        </cr-expand-button>
-        <div class="separator"></div>
-        <cr-icon-button class="icon-clear" data-id-path$="[[item.idPath]]"
-            on-click="onRemove_"></cr-icon-button>
-      </div>
-      <iron-collapse class="list-frame vertical-list"
-          opened="[[item.expanded_]]">
-        <template is="dom-repeat" items="[[getCookieNodes_(item)]]">
-          <div class="list-item two-line">
-            <div class="start">
-              [[item.label]]
-              <div class="secondary">[[item.content]]</div>
-            </div>
-          </div>
-        </template>
-      </iron-collapse>
-    </template>
diff --git a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.ts b/chrome/browser/resources/settings/site_settings/site_data_details_subpage.ts
deleted file mode 100644
index e298b0d..0000000
--- a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.ts
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2015 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js';
-import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
-import 'chrome://resources/cr_elements/cr_shared_style.css.js';
-import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
-import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
-import '../settings_shared.css.js';
-
-import {WebUIListenerMixin, WebUIListenerMixinInterface} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {loadTimeData} from '../i18n_setup.js';
-import {MetricsBrowserProxyImpl, PrivacyElementInteractions} from '../metrics_browser_proxy.js';
-import {routes} from '../route.js';
-import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../router.js';
-
-import {CookieDataForDisplay, CookieDetails, getCookieData} from './cookie_info.js';
-import {LocalDataBrowserProxy, LocalDataBrowserProxyImpl} from './local_data_browser_proxy.js';
-import {getTemplate} from './site_data_details_subpage.html.js';
-
-
-const categoryLabels: {[key: string]: string} = {
-  cache_storage: loadTimeData.getString('cookieCacheStorage'),
-  database: loadTimeData.getString('cookieDatabaseStorage'),
-  file_system: loadTimeData.getString('cookieFileSystem'),
-  flash_lso: loadTimeData.getString('cookieFlashLso'),
-  indexed_db: loadTimeData.getString('cookieDatabaseStorage'),
-  local_storage: loadTimeData.getString('cookieLocalStorage'),
-  service_worker: loadTimeData.getString('cookieServiceWorker'),
-  shared_worker: loadTimeData.getString('cookieSharedWorker'),
-  quota: loadTimeData.getString('cookieQuotaStorage'),
-};
-
-/**
- * 'site-data-details-subpage' Display cookie contents.
- */
-
-const SiteDataDetailsSubpageElementBase =
-    RouteObserverMixin(WebUIListenerMixin(PolymerElement)) as {
-      new (): PolymerElement & WebUIListenerMixinInterface &
-          RouteObserverMixinInterface,
-    };
-
-export class SiteDataDetailsSubpageElement extends
-    SiteDataDetailsSubpageElementBase {
-  static get is() {
-    return 'site-data-details-subpage';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      /**
-       * The cookie entries for the given site.
-       */
-      entries_: Array,
-
-      /** Set the page title on the settings-subpage parent. */
-      pageTitle: {
-        type: String,
-        notify: true,
-      },
-
-      site_: String,
-    };
-  }
-
-  private entries_: Array<CookieDetails&{expanded_: boolean}>;
-  pageTitle: string;
-  private site_: string;
-  private browserProxy_: LocalDataBrowserProxy =
-      LocalDataBrowserProxyImpl.getInstance();
-
-  override ready() {
-    super.ready();
-
-    this.addWebUIListener(
-        'on-tree-item-removed', () => this.getCookieDetails_());
-  }
-
-  /**
-   * RouteObserverMixin
-   */
-  override currentRouteChanged(route: Route) {
-    if (route !== routes.SITE_SETTINGS_DATA_DETAILS) {
-      return;
-    }
-    const site = Router.getInstance().getQueryParameters().get('site');
-    if (!site) {
-      return;
-    }
-    this.site_ = site;
-    this.pageTitle = loadTimeData.getStringF('siteSettingsCookieSubpage', site);
-    this.getCookieDetails_();
-  }
-
-  private getCookieDetails_() {
-    if (!this.site_) {
-      return;
-    }
-    this.browserProxy_.getCookieDetails(this.site_)
-        .then(
-            (cookies: CookieDetails[]) => this.onCookiesLoaded_(cookies),
-            () => this.onCookiesLoadFailed_());
-  }
-
-  private getCookieNodes_(node: CookieDetails): CookieDataForDisplay[] {
-    return getCookieData(node);
-  }
-
-  private onCookiesLoaded_(cookies: CookieDetails[]) {
-    this.entries_ = cookies.map(c => {
-      // Set up flag for expanding cookie details.
-      (c as CookieDetails & {expanded_: boolean}).expanded_ = false;
-      return c;
-    }) as Array<CookieDetails&{expanded_: boolean}>;
-  }
-
-  /**
-   * The site was not found. E.g. The site data may have been deleted or the
-   * site URL parameter may be mistyped.
-   */
-  private onCookiesLoadFailed_() {
-    this.entries_ = [];
-  }
-
-  /**
-   * Retrieves a string description for the provided |item|.
-   */
-  private getEntryDescription_(item: CookieDetails): string {
-    // Frequently there are multiple cookies per site. To avoid showing a list
-    // of '1 cookie', '1 cookie', ... etc, it is better to show the title of the
-    // cookie to differentiate them.
-    if (item.type === 'cookie') {
-      return item.title;
-    }
-    return categoryLabels[item.type];
-  }
-
-  /**
-   * A handler for when the user opts to remove a single cookie.
-   */
-  private onRemove_(event: Event) {
-    MetricsBrowserProxyImpl.getInstance().recordSettingsPageHistogram(
-        PrivacyElementInteractions.COOKIE_DETAILS_REMOVE_ITEM);
-    this.browserProxy_.removeItem(
-        (event.currentTarget as HTMLElement).dataset['idPath']!);
-  }
-
-  /**
-   * A handler for when the user opts to remove all cookies.
-   */
-  removeAll() {
-    MetricsBrowserProxyImpl.getInstance().recordSettingsPageHistogram(
-        PrivacyElementInteractions.COOKIE_DETAILS_REMOVE_ALL);
-    this.browserProxy_.removeSite(this.site_);
-  }
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'site-data-details-subpage': SiteDataDetailsSubpageElement;
-  }
-}
-
-customElements.define(
-    SiteDataDetailsSubpageElement.is, SiteDataDetailsSubpageElement);
diff --git a/chrome/browser/resources/settings/site_settings/site_data_entry.html b/chrome/browser/resources/settings/site_settings/site_data_entry.html
deleted file mode 100644
index efc6db9..0000000
--- a/chrome/browser/resources/settings/site_settings/site_data_entry.html
+++ /dev/null
@@ -1,16 +0,0 @@
-    <style include="cr-shared-style settings-shared iron-flex">
-    </style>
-    <div class="cr-row continuation two-line" focus-row-container actionable>
-      <site-favicon url="[[model.site]]"></site-favicon>
-      <div class="flex cr-row-gap">
-        <span class="url-directionality">[[model.site]]</span>
-        <div class="secondary">[[model.localData]]</div>
-      </div>
-      <cr-icon-button class="subpage-arrow" aria-label$="[[model.site]]"
-          focus-row-control focus-type="showDetails"></cr-icon-button>
-      <div class="separator"></div>
-      <cr-icon-button class="icon-delete-gray"
-          title$="[[i18n('siteSettingsCookieRemoveSite', model.site)]]"
-          on-click="onRemove_" focus-row-control focus-type="remove">
-      </cr-icon-button>
-    </div>
diff --git a/chrome/browser/resources/settings/site_settings/site_data_entry.ts b/chrome/browser/resources/settings/site_settings/site_data_entry.ts
deleted file mode 100644
index 8b80d9f0..0000000
--- a/chrome/browser/resources/settings/site_settings/site_data_entry.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview
- * 'site-data-entry' handles showing the local storage summary for a site.
- */
-
-import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
-import 'chrome://resources/cr_elements/icons.html.js';
-import 'chrome://resources/cr_elements/cr_shared_style.css.js';
-import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
-import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
-import '../settings_shared.css.js';
-import '../site_favicon.js';
-
-import {FocusRowMixin} from 'chrome://resources/js/focus_row_mixin.js';
-import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {MetricsBrowserProxyImpl, PrivacyElementInteractions} from '../metrics_browser_proxy.js';
-
-import {LocalDataBrowserProxyImpl, LocalDataItem} from './local_data_browser_proxy.js';
-import {getTemplate} from './site_data_entry.html.js';
-
-const SiteDataEntryElementBase = FocusRowMixin(I18nMixin(PolymerElement));
-
-class SiteDataEntryElement extends SiteDataEntryElementBase {
-  static get is() {
-    return 'site-data-entry';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      model: Object,
-    };
-  }
-
-  model: LocalDataItem;
-
-  /**
-   * Deletes all site data for this site.
-   */
-  private onRemove_(e: Event) {
-    e.stopPropagation();
-    MetricsBrowserProxyImpl.getInstance().recordSettingsPageHistogram(
-        PrivacyElementInteractions.SITE_DATA_REMOVE_SITE);
-    LocalDataBrowserProxyImpl.getInstance().removeSite(this.model.site);
-  }
-}
-
-customElements.define(SiteDataEntryElement.is, SiteDataEntryElement);
diff --git a/chrome/browser/resources/settings/site_settings/site_entry.html b/chrome/browser/resources/settings/site_settings/site_entry.html
index 6c3b34ad..aa271d92 100644
--- a/chrome/browser/resources/settings/site_settings/site_entry.html
+++ b/chrome/browser/resources/settings/site_settings/site_entry.html
@@ -90,32 +90,23 @@
               focus-row-control focus-type="show-detail"></cr-icon-button>
         </div>
         <div class="row-aligned">
-          <template is="dom-if"
-              if="[[!enableConsolidatedSiteStorageControls_]]">
+          <template is="dom-if" if="[[isFpsMember_(siteGroup.fpsOwner)]]">
             <div class="separator"></div>
-            <cr-icon-button class="icon-more-vert" id="overflowMenuButton"
-                title="$i18n{moreActions}" on-click="showOverflowMenu_"
-                focus-row-control focus-type="more-actions"></cr-icon-button>
+            <cr-icon-button class="icon-more-vert"
+                id="fpsOverflowMenuButton"
+                title="$i18n{moreActions}"
+                on-click="showOverflowMenu_"
+                focus-row-control focus-type="more-actions"
+                aria-label$="[[getMoreActionsLabel_(siteGroup)]]">
+            </cr-icon-button>
           </template>
-          <template is="dom-if" if="[[enableConsolidatedSiteStorageControls_]]">
-            <template is="dom-if" if="[[isFpsMember_(siteGroup.fpsOwner)]]">
-              <div class="separator"></div>
-              <cr-icon-button class="icon-more-vert"
-                  id="fpsOverflowMenuButton"
-                  title="$i18n{moreActions}"
-                  on-click="showOverflowMenu_"
-                  focus-row-control focus-type="more-actions"
-                  aria-label$="[[getMoreActionsLabel_(siteGroup)]]">
-              </cr-icon-button>
-            </template>
-            <template is="dom-if" if="[[!isFpsMember_(siteGroup.fpsOwner)]]">
-              <div class="separator"></div>
-              <cr-icon-button class="icon-delete-gray" id="removeSiteButton"
-                  title$=
-                    "[[i18n('siteSettingsCookieRemoveSite', displayName_)]]"
-                  on-click="onRemove_" focus-row-control focus-type="remove">
-              </cr-icon-button>
-            </template>
+          <template is="dom-if" if="[[!isFpsMember_(siteGroup.fpsOwner)]]">
+            <div class="separator"></div>
+            <cr-icon-button class="icon-delete-gray" id="removeSiteButton"
+                title$=
+                  "[[i18n('siteSettingsCookieRemoveSite', displayName_)]]"
+                on-click="onRemove_" focus-row-control focus-type="remove">
+            </cr-icon-button>
           </template>
         </div>
       </div>
@@ -173,29 +164,15 @@
                     </cr-icon-button>
                   </div>
                   <div class="row-aligned">
-                    <template is="dom-if"
-                        if="[[!enableConsolidatedSiteStorageControls_]]">
-                      <div class="separator"></div>
-                      <cr-icon-button class="icon-more-vert"
-                          id="originOverflowMenuButton"
-                          data-origin$="[[item.origin]]" data-context="origin"
-                          title="$i18n{moreActions}"
-                          on-click="showOverflowMenu_"
-                          focus-row-control focus-type="more-actions">
-                      </cr-icon-button>
-                    </template>
-                    <template is="dom-if"
-                        if="[[enableConsolidatedSiteStorageControls_]]">
-                      <div class="separator"></div>
-                      <cr-icon-button class="icon-delete-gray"
-                          id="removeOriginButton"
-                          title$="[[getRemoveOriginButtonTitle_(item.origin)]]"
-                          data-origin$="[[item.origin]]" data-context="origin"
-                          data-partitioned$="[[item.isPartitioned]]"
-                          on-click="onRemove_" focus-row-control
-                          focus-type="remove">
-                      </cr-icon-button>
-                    </template>
+                    <div class="separator"></div>
+                    <cr-icon-button class="icon-delete-gray"
+                        id="removeOriginButton"
+                        title$="[[getRemoveOriginButtonTitle_(item.origin)]]"
+                        data-origin$="[[item.origin]]" data-context="origin"
+                        data-partitioned$="[[item.isPartitioned]]"
+                        on-click="onRemove_" focus-row-control
+                        focus-type="remove">
+                    </cr-icon-button>
                   </div>
                 </div>
               </template>
diff --git a/chrome/browser/resources/settings/site_settings/site_entry.ts b/chrome/browser/resources/settings/site_settings/site_entry.ts
index a251d99b..f105fe4f 100644
--- a/chrome/browser/resources/settings/site_settings/site_entry.ts
+++ b/chrome/browser/resources/settings/site_settings/site_entry.ts
@@ -16,20 +16,18 @@
 
 import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
 import {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js';
-import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js';
-import {FocusRowMixin} from 'chrome://resources/js/focus_row_mixin.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
+import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js';
+import {EventTracker} from 'chrome://resources/js/event_tracker.js';
+import {FocusRowMixin} from 'chrome://resources/js/focus_row_mixin.js';
 import {IronCollapseElement} from 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
 import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {BaseMixin} from '../base_mixin.js';
-import {loadTimeData} from '../i18n_setup.js';
 import {routes} from '../route.js';
 import {Router} from '../router.js';
 
 import {AllSitesAction2, SortMethod} from './constants.js';
-import {LocalDataBrowserProxy, LocalDataBrowserProxyImpl} from './local_data_browser_proxy.js';
 import {getTemplate} from './site_entry.html.js';
 import {SiteSettingsMixin} from './site_settings_mixin.js';
 import {OriginInfo, SiteGroup} from './site_settings_prefs_browser_proxy.js';
@@ -132,12 +130,6 @@
        * The selected sort method.
        */
       sortMethod: {type: String, observer: 'updateOrigins_'},
-
-      enableConsolidatedSiteStorageControls_: {
-        type: Boolean,
-        value: () =>
-            loadTimeData.getBoolean('consolidatedSiteStorageControlsEnabled'),
-      },
     };
   }
 
@@ -157,12 +149,9 @@
   private originUsages_: string[];
   private cookiesNum_: string[];
   sortMethod?: SortMethod;
-  private enableConsolidatedSiteStorageControls_: boolean;
   private fpsEnterprisePref_: chrome.settingsPrivate.PrefObject;
 
   private button_: Element|null = null;
-  private localDataBrowserProxy_: LocalDataBrowserProxy =
-      LocalDataBrowserProxyImpl.getInstance();
   private eventTracker_: EventTracker = new EventTracker();
 
   override disconnectedCallback() {
@@ -338,7 +327,7 @@
     if (numCookies === 0) {
       return Promise.resolve('');
     }
-    return this.localDataBrowserProxy_.getNumCookiesString(numCookies);
+    return this.browserProxy.getNumCookiesString(numCookies);
   }
 
   /**
@@ -350,7 +339,7 @@
     if (!this.siteGroup.fpsOwner) {
       this.fpsMembershipLabel_ = '';
     } else {
-      this.localDataBrowserProxy_
+      this.browserProxy
           .getFpsMembershipLabel(
               this.siteGroup.fpsNumMembers!, this.siteGroup.fpsOwner!)
           .then(label => this.fpsMembershipLabel_ = label);
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.ts b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.ts
index 460b719b..e6f8266 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.ts
+++ b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.ts
@@ -470,6 +470,20 @@
 
   /** Resets the notification permission for the origin. */
   resetNotificationPermissionForOrigin(origin: string): void;
+
+  /**
+   * Gets display string for FPS information of owner and member count.
+   * @param fpsNumMembers The number of members in the first party set.
+   * @param fpsOwner The eTLD+1 for the first party set owner.
+   */
+  getFpsMembershipLabel(fpsNumMembers: number, fpsOwner: string):
+      Promise<string>;
+
+  /**
+   * Gets the plural string for a given number of cookies.
+   * @param numCookies The number of cookies.
+   */
+  getNumCookiesString(numCookies: number): Promise<string>;
 }
 
 export class SiteSettingsPrefsBrowserProxyImpl implements
@@ -658,6 +672,14 @@
     ]);
   }
 
+  getFpsMembershipLabel(fpsNumMembers: number, fpsOwner: string) {
+    return sendWithPromise('getFpsMembershipLabel', fpsNumMembers, fpsOwner);
+  }
+
+  getNumCookiesString(numCookies: number) {
+    return sendWithPromise('getNumCookiesString', numCookies);
+  }
+
   static getInstance(): SiteSettingsPrefsBrowserProxy {
     return instance || (instance = new SiteSettingsPrefsBrowserProxyImpl());
   }
diff --git a/chrome/browser/resources/side_panel/bookmarks/bookmarks_drag_manager.ts b/chrome/browser/resources/side_panel/bookmarks/bookmarks_drag_manager.ts
index b9b7bce..331b59bd 100644
--- a/chrome/browser/resources/side_panel/bookmarks/bookmarks_drag_manager.ts
+++ b/chrome/browser/resources/side_panel/bookmarks/bookmarks_drag_manager.ts
@@ -181,14 +181,16 @@
 
   startObserving() {
     this.eventTracker_.add(
-        this.delegate_, 'dragstart', e => this.onDragStart_(e as DragEvent));
+        this.delegate_, 'dragstart',
+        (e: Event) => this.onDragStart_(e as DragEvent));
     this.eventTracker_.add(
-        this.delegate_, 'dragover', e => this.onDragOver_(e as DragEvent));
+        this.delegate_, 'dragover',
+        (e: Event) => this.onDragOver_(e as DragEvent));
     this.eventTracker_.add(
         this.delegate_, 'dragleave', () => this.onDragLeave_());
     this.eventTracker_.add(this.delegate_, 'dragend', () => this.cancelDrag_());
     this.eventTracker_.add(
-        this.delegate_, 'drop', e => this.onDrop_(e as DragEvent));
+        this.delegate_, 'drop', (e: Event) => this.onDrop_(e as DragEvent));
 
     if (loadTimeData.getBoolean('bookmarksDragAndDropEnabled')) {
       chrome.bookmarkManagerPrivate.onDragEnter.addListener(
@@ -266,4 +268,4 @@
     this.dragSession_.finish();
     this.dragSession_ = null;
   }
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/resources/tab_strip/tab_list.ts b/chrome/browser/resources/tab_strip/tab_list.ts
index e8cd181..7909f39 100644
--- a/chrome/browser/resources/tab_strip/tab_list.ts
+++ b/chrome/browser/resources/tab_strip/tab_list.ts
@@ -255,15 +255,17 @@
     });
 
     this.eventTracker_.add(
-        document, 'contextmenu', e => this.onContextMenu_(e));
+        document, 'contextmenu', (e: Event) => this.onContextMenu_(e));
     this.eventTracker_.add(
-        document, 'pointerup', e => this.onPointerUp_(e as PointerEvent));
+        document, 'pointerup',
+        (e: Event) => this.onPointerUp_(e as PointerEvent));
     this.eventTracker_.add(
         document, 'visibilitychange', () => this.onDocumentVisibilityChange_());
     this.eventTracker_.add(window, 'blur', () => this.onWindowBlur_());
-    this.eventTracker_.add(this, 'scroll', e => this.onScroll_(e));
+    this.eventTracker_.add(this, 'scroll', (e: Event) => this.onScroll_(e));
     this.eventTracker_.add(
-        document, 'touchstart', e => this.onTouchStart_(e as TouchEvent));
+        document, 'touchstart',
+        (e: Event) => this.onTouchStart_(e as TouchEvent));
     // Touchmove events happen when a user has started a touch gesture sequence
     // and proceeded to move their touch pointer across the screen. Ensure that
     // we clear the `last_targeted_item_` in these cases to ensure the pressed
diff --git a/chrome/browser/resources/whats_new/whats_new_app.ts b/chrome/browser/resources/whats_new/whats_new_app.ts
index 648ebf54..abaeb0e 100644
--- a/chrome/browser/resources/whats_new/whats_new_app.ts
+++ b/chrome/browser/resources/whats_new/whats_new_app.ts
@@ -87,7 +87,8 @@
     this.url_ = url.concat(`latest=${latest}`);
 
     this.eventTracker_.add(
-        window, 'message', event => this.handleMessage_(event as MessageEvent));
+        window, 'message',
+        (event: Event) => this.handleMessage_(event as MessageEvent));
   }
 
   private handleMessage_(event: MessageEvent) {
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
index 604b7f60..f53c6df 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
@@ -1115,8 +1115,8 @@
             &ChromePasswordProtectionServiceDeferActivationBrowserTest::
                 GetWebContents,
             base::Unretained(this))) {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        additional_features = {{features::kBackForwardCache, {}}};
+    std::vector<base::test::FeatureRefAndParams> additional_features = {
+        {features::kBackForwardCache, {}}};
     scoped_feature_list_.InitWithFeaturesAndParameters(
         content::DefaultEnabledBackForwardCacheParametersForTests(
             additional_features),
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 646ffbb..5b87f443 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -137,7 +137,7 @@
 using content::RenderFrameHost;
 using content::WebContents;
 using security_interstitials::BaseSafeBrowsingErrorUI;
-using FeatureAndParams = base::test::ScopedFeatureList::FeatureAndParams;
+using FeatureAndParams = base::test::FeatureRefAndParams;
 
 namespace safe_browsing {
 
@@ -474,7 +474,7 @@
     const char kTagAndAttributeParamName[] = "tag_attribute_csv";
     std::map<std::string, std::string> parameters = {
         {kTagAndAttributeParamName, "div,foo,div,baz"}};
-    base::test::ScopedFeatureList::FeatureAndParams tag_and_attribute(
+    base::test::FeatureRefAndParams tag_and_attribute(
         safe_browsing::kThreatDomDetailsTagAndAttributeFeature, parameters);
     scoped_feature_list_.InitWithFeaturesAndParameters({tag_and_attribute}, {});
   }
diff --git a/chrome/browser/segmentation_platform/android/contextual_page_action_controller_android.cc b/chrome/browser/segmentation_platform/android/contextual_page_action_controller_android.cc
index 04d97e6..6d5e232 100644
--- a/chrome/browser/segmentation_platform/android/contextual_page_action_controller_android.cc
+++ b/chrome/browser/segmentation_platform/android/contextual_page_action_controller_android.cc
@@ -45,6 +45,7 @@
   segmentation_platform::SegmentationPlatformService*
       segmentation_platform_service = segmentation_platform::
           SegmentationPlatformServiceFactory::GetForProfile(profile);
+  DCHECK(segmentation_platform_service);
   segmentation_platform_service->GetSelectedSegmentOnDemand(
       segmentation_platform::kContextualPageActionsKey, input_context,
       base::BindOnce(&RunGetSelectedSegmentCallback,
diff --git a/chrome/browser/segmentation_platform/service_browsertest.cc b/chrome/browser/segmentation_platform/service_browsertest.cc
index 8fc8d2a..fdb1abc 100644
--- a/chrome/browser/segmentation_platform/service_browsertest.cc
+++ b/chrome/browser/segmentation_platform/service_browsertest.cc
@@ -43,13 +43,13 @@
  public:
   SegmentationPlatformTest() {
     feature_list_.InitWithFeaturesAndParameters(
-        {base::test::ScopedFeatureList::FeatureAndParams(
-             features::kSegmentationPlatformFeature, {}),
-         base::test::ScopedFeatureList::FeatureAndParams(
+        {base::test::FeatureRefAndParams(features::kSegmentationPlatformFeature,
+                                         {}),
+         base::test::FeatureRefAndParams(
              features::kSegmentationStructuredMetricsFeature, {}),
-         base::test::ScopedFeatureList::FeatureAndParams(
+         base::test::FeatureRefAndParams(
              features::kSegmentationPlatformUkmEngine, {}),
-         base::test::ScopedFeatureList::FeatureAndParams(
+         base::test::FeatureRefAndParams(
              features::kSegmentationPlatformLowEngagementFeature,
              {{"enable_default_model", "true"}})},
         {});
diff --git a/chrome/browser/sessions/DEPS b/chrome/browser/sessions/DEPS
index 7878abe..ee77d5b 100644
--- a/chrome/browser/sessions/DEPS
+++ b/chrome/browser/sessions/DEPS
@@ -8,4 +8,8 @@
     # Tests may depend upon views.
     "+chrome/browser/ui/views",
   ],
+  "session_restore\.cc": [
+    "+ash/shell.h",
+    "+ash/metrics/login_unlock_throughput_recorder.h",
+  ],
 }
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index f71a402e..f49871b 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -92,7 +92,11 @@
 #include "extensions/common/extension_set.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/metrics/login_unlock_throughput_recorder.h"
+#include "ash/shell.h"
 #include "chrome/browser/ash/boot_times_recorder.h"
+#include "components/app_restore/window_properties.h"
+#include "ui/compositor/layer.h"
 #endif
 
 using content::NavigationController;
@@ -114,6 +118,50 @@
 // Pointers to SessionRestoreImpls which are currently restoring the session.
 std::set<SessionRestoreImpl*>* active_session_restorers = nullptr;
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+void StartRecordingRestoredWindowsMetrics(
+    const std::vector<std::unique_ptr<sessions::SessionWindow>>& windows) {
+  // Ash is not always initialized in unit tests.
+  if (!ash::Shell::HasInstance())
+    return;
+
+  ash::LoginUnlockThroughputRecorder* throughput_recorder =
+      ash::Shell::Get()->login_unlock_throughput_recorder();
+
+  for (const auto& w : windows) {
+    if (w->type == sessions::SessionWindow::TYPE_NORMAL) {
+      throughput_recorder->AddScheduledRestoreWindow(
+          w->window_id.id(), w->app_name,
+          ash::LoginUnlockThroughputRecorder::kBrowser);
+    }
+  }
+}
+
+void ReportRestoredWindowCreated(aura::Window* window) {
+  // Ash is not always initialized in unit tests.
+  if (!ash::Shell::HasInstance())
+    return;
+
+  const int32_t restore_window_id =
+      window->GetProperty(app_restore::kRestoreWindowIdKey);
+
+  // Restored window IDs are always non-zero.
+  if (restore_window_id == 0)
+    return;
+
+  ash::LoginUnlockThroughputRecorder* throughput_recorder =
+      ash::Shell::Get()->login_unlock_throughput_recorder();
+  throughput_recorder->OnRestoredWindowCreated(restore_window_id);
+  aura::Window* root_window = window->GetRootWindow();
+  if (root_window) {
+    ui::Compositor* compositor = root_window->layer()->GetCompositor();
+    throughput_recorder->OnBeforeRestoredWindowShown(restore_window_id,
+                                                     compositor);
+  }
+}
+
+#endif
+
 }  // namespace
 
 // SessionRestoreImpl ---------------------------------------------------------
@@ -415,6 +463,11 @@
     if (!read_error_)
       read_error_ = read_error;
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+    if (!read_error_)
+      StartRecordingRestoredWindowsMetrics(windows);
+#endif
+
     // Copy windows into windows_ so that we can combine both app and browser
     // windows together before doing a one-pass restore.
     std::copy(std::make_move_iterator(windows.begin()),
@@ -576,6 +629,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
         ash::BootTimesRecorder::Get()->AddLoginTimeMarker(
             "SessionRestore-CreateRestoredBrowser-End", false);
+        ReportRestoredWindowCreated(browser->window()->GetNativeWindow());
 #endif
       }
 
diff --git a/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc b/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc
index cab47af..ef1331a 100644
--- a/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc
+++ b/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc
@@ -156,8 +156,7 @@
   }
 
   void SetUpFeature(base::TimeDelta fallback_delay) {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     std::vector<base::test::FeatureRef> disabled_features;
     if (IsFeatureEnabled()) {
       base::FieldTrialParams params;
diff --git a/chrome/browser/storage_access_api/api_browsertest.cc b/chrome/browser/storage_access_api/api_browsertest.cc
index 7f83bd4..08c4f97 100644
--- a/chrome/browser/storage_access_api/api_browsertest.cc
+++ b/chrome/browser/storage_access_api/api_browsertest.cc
@@ -80,9 +80,8 @@
     InProcessBrowserTest::SetUp();
   }
 
-  virtual std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-  GetEnabledFeatures() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled({
+  virtual std::vector<base::test::FeatureRefAndParams> GetEnabledFeatures() {
+    std::vector<base::test::FeatureRefAndParams> enabled({
         {net::features::kStorageAccessAPI,
          {
              {
@@ -718,9 +717,8 @@
                                         std::get<1>(GetParam())) {}
 
  protected:
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-  GetEnabledFeatures() override {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled =
+  std::vector<base::test::FeatureRefAndParams> GetEnabledFeatures() override {
+    std::vector<base::test::FeatureRefAndParams> enabled =
         StorageAccessAPIBaseBrowserTest::GetEnabledFeatures();
     enabled.push_back(
         {blink::features::kStorageAccessAPIForOriginExtension, {}});
@@ -778,6 +776,11 @@
       base::StrCat({"https://", kHostB, ":",
                     base::NumberToString(https_server().port())})));
   EXPECT_TRUE(storage::test::HasStorageAccessForFrame(GetFrame()));
+  // Repeated calls should also return true.
+  EXPECT_TRUE(storage::test::RequestStorageAccessForOrigin(
+      GetPrimaryMainFrame(),
+      base::StrCat({"https://", kHostB, ":",
+                    base::NumberToString(https_server().port())})));
 
   // Navigate iframe to a cross-site, cookie-reading endpoint, and verify that
   // the cookie is sent:
@@ -815,8 +818,7 @@
   }
 
  protected:
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-  GetEnabledFeatures() override {
+  std::vector<base::test::FeatureRefAndParams> GetEnabledFeatures() override {
     return {{blink::features::kStorageAccessAPIForOriginExtension, {}},
             {net::features::kStorageAccessAPI,
              {
@@ -1025,8 +1027,7 @@
     }
     return {net::features::kStorageAccessAPI};
   }
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-  GetEnabledFeatures() override {
+  std::vector<base::test::FeatureRefAndParams> GetEnabledFeatures() override {
     // When the standard API is enabled, return the parent class's enabled
     // feature list. Otherwise, enable only the extension; this should not take
     // effect.
@@ -1071,8 +1072,7 @@
   }
 
  protected:
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-  GetEnabledFeatures() override {
+  std::vector<base::test::FeatureRefAndParams> GetEnabledFeatures() override {
     return {
         {net::features::kStorageAccessAPI,
          {
@@ -1175,8 +1175,7 @@
       : StorageAccessAPIBaseBrowserTest(false, false) {}
 
  protected:
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-  GetEnabledFeatures() override {
+  std::vector<base::test::FeatureRefAndParams> GetEnabledFeatures() override {
     return {
         {net::features::kStorageAccessAPI,
          {
@@ -1243,9 +1242,8 @@
             /*permission_grants_unpartitioned_storage=*/false,
             /*is_storage_partitioned=*/false) {}
 
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-  GetEnabledFeatures() override {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled =
+  std::vector<base::test::FeatureRefAndParams> GetEnabledFeatures() override {
+    std::vector<base::test::FeatureRefAndParams> enabled =
         StorageAccessAPIBaseBrowserTest::GetEnabledFeatures();
     enabled.push_back({net::features::kPartitionedCookies, {}});
     enabled.push_back(
diff --git a/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc b/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
index 9e91876..2337209 100644
--- a/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
+++ b/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
@@ -299,7 +299,7 @@
   const bool permission_allowed = (content_setting == CONTENT_SETTING_ALLOW);
   UpdateTabContext(id, requesting_origin, permission_allowed);
 
-  if (!permission_allowed) {
+  if (!permission_allowed || !persist) {
     if (content_setting == CONTENT_SETTING_DEFAULT) {
       content_setting = CONTENT_SETTING_ASK;
     }
diff --git a/chrome/browser/storage_access_api/storage_access_grant_permission_context_unittest.cc b/chrome/browser/storage_access_api/storage_access_grant_permission_context_unittest.cc
index f9ba075..fb72df4 100644
--- a/chrome/browser/storage_access_api/storage_access_grant_permission_context_unittest.cc
+++ b/chrome/browser/storage_access_api/storage_access_grant_permission_context_unittest.cc
@@ -43,7 +43,7 @@
     : public ChromeRenderViewHostTestHarness {
  public:
   explicit StorageAccessGrantPermissionContextTest(bool saa_enabled) {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled;
+    std::vector<base::test::FeatureRefAndParams> enabled;
     std::vector<base::test::FeatureRef> disabled;
     if (saa_enabled) {
       enabled.push_back({net::features::kStorageAccessAPI,
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc b/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
index c64543cb..bdf926e2 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
@@ -604,8 +604,7 @@
 }
 
 void SupervisedUserIframeFilterTest::InitFeatures() {
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-      enabled_features_and_params;
+  std::vector<base::test::FeatureRefAndParams> enabled_features_and_params;
   std::vector<base::test::FeatureRef> disabled_features;
   if (IsWebFilterInterstitialRefreshEnabled()) {
     enabled_features_and_params.emplace_back(
diff --git a/chrome/browser/tab_contents/form_interaction_tab_helper_unittest.cc b/chrome/browser/tab_contents/form_interaction_tab_helper_unittest.cc
index 4198abe..41b6cac7 100644
--- a/chrome/browser/tab_contents/form_interaction_tab_helper_unittest.cc
+++ b/chrome/browser/tab_contents/form_interaction_tab_helper_unittest.cc
@@ -114,7 +114,7 @@
       public testing::WithParamInterface<ChildFrameType> {
  public:
   FormInteractionTabHelperWithChildTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled;
+    std::vector<base::test::FeatureRefAndParams> enabled;
     enabled.push_back(
         {blink::features::kFencedFrames, {{"implementation_type", "mparch"}}});
     enabled.push_back({blink::features::kInitialNavigationEntry, {}});
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 31871f6..f335c3d 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1666,8 +1666,6 @@
       "webui/settings/search_engines_handler.h",
       "webui/settings/settings_clear_browsing_data_handler.cc",
       "webui/settings/settings_clear_browsing_data_handler.h",
-      "webui/settings/settings_cookies_view_handler.cc",
-      "webui/settings/settings_cookies_view_handler.h",
       "webui/settings/settings_localized_strings_provider.cc",
       "webui/settings/settings_localized_strings_provider.h",
       "webui/settings/settings_media_devices_selection_handler.cc",
@@ -3107,7 +3105,6 @@
       "//ash/components/peripheral_notification",
       "//ash/components/phonehub",
       "//ash/components/phonehub:debug",
-      "//ash/components/tether",
       "//ash/constants",
       "//ash/keyboard/ui",
       "//ash/public/cpp",
@@ -3242,6 +3239,7 @@
       "//chromeos/ash/components/proximity_auth",
       "//chromeos/ash/components/settings",
       "//chromeos/ash/components/string_matching",
+      "//chromeos/ash/components/tether",
       "//chromeos/ash/resources",
       "//chromeos/ash/services/assistant:lib",
       "//chromeos/ash/services/assistant/public/cpp",
diff --git a/chrome/browser/ui/android/omnibox/BUILD.gn b/chrome/browser/ui/android/omnibox/BUILD.gn
index 03ef64a..560558f 100644
--- a/chrome/browser/ui/android/omnibox/BUILD.gn
+++ b/chrome/browser/ui/android/omnibox/BUILD.gn
@@ -335,6 +335,8 @@
     "java/res/layout/omnibox_results_container.xml",
     "java/res/layout/suggestions_tile_view.xml",
     "java/res/layout/url_action_container.xml",
+    "java/res/values-night/dimens.xml",
+    "java/res/values-night/drawables.xml",
     "java/res/values/colors.xml",
     "java/res/values/dimens.xml",
     "java/res/values/drawables.xml",
diff --git a/chrome/browser/ui/android/omnibox/java/res/values-night/dimens.xml b/chrome/browser/ui/android/omnibox/java/res/values-night/dimens.xml
new file mode 100644
index 0000000..d81f5889
--- /dev/null
+++ b/chrome/browser/ui/android/omnibox/java/res/values-night/dimens.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2022 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Omnibox suggestions -->
+    <dimen name="omnibox_suggestion_bg_elevation">@dimen/default_elevation_1</dimen>
+    <dimen name="omnibox_suggestion_dropdown_bg_elevation">@dimen/default_elevation_0</dimen>
+</resources>
diff --git a/chrome/browser/ui/android/omnibox/java/res/values-night/drawables.xml b/chrome/browser/ui/android/omnibox/java/res/values-night/drawables.xml
new file mode 100644
index 0000000..d47c0b36
--- /dev/null
+++ b/chrome/browser/ui/android/omnibox/java/res/values-night/drawables.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2022 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<resources>
+    <drawable name="tile_view_icon_background_modern_updated">@drawable/oval_surface_1</drawable>
+</resources>
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsChecker.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsChecker.java
index e1e8544d..11382b94 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsChecker.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsChecker.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.toolbar;
 
+import android.os.Handler;
+
 import androidx.annotation.NonNull;
 
 import org.chromium.base.Callback;
@@ -19,15 +21,19 @@
     private final ViewResourceAdapter mViewResourceAdapter;
     @NonNull
     private final ObservableSupplier<Integer> mConstraintsSupplier;
+    @NonNull
+    private final Handler mHandler;
 
     /**
      * @param viewResourceAdapter The target to notify when a capture is needed.
      * @param constraintsSupplier The underlying supplier for the state of constraints.
+     * @param handler Handler to post deferred tasks to.
      */
     public ConstraintsChecker(@NonNull ViewResourceAdapter viewResourceAdapter,
-            @NonNull ObservableSupplier<Integer> constraintsSupplier) {
+            @NonNull ObservableSupplier<Integer> constraintsSupplier, @NonNull Handler handler) {
         mViewResourceAdapter = viewResourceAdapter;
         mConstraintsSupplier = constraintsSupplier;
+        mHandler = handler;
     }
 
     /**
@@ -53,7 +59,7 @@
     public void onResult(Integer result) {
         if (!areControlsLocked()) {
             mConstraintsSupplier.removeObserver(this);
-            mViewResourceAdapter.onResourceRequested();
+            mHandler.post(() -> mViewResourceAdapter.onResourceRequested());
         }
     }
 }
\ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsCheckerTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsCheckerTest.java
index 673ecf8e..ebaa559 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsCheckerTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsCheckerTest.java
@@ -5,9 +5,13 @@
 package org.chromium.chrome.browser.toolbar;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.os.Handler;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -30,13 +34,22 @@
 
     @Mock
     private ViewResourceAdapter mViewResourceAdapter;
+    @Mock
+    private Handler mHandler;
 
     private ObservableSupplierImpl mConstraintsSupplier = new ObservableSupplierImpl();
 
     @Test
     public void testScheduleRequestResourceOnUnlock() {
+        doAnswer((invocation) -> {
+            Runnable runnable = (Runnable) invocation.getArguments()[0];
+            runnable.run();
+            return null;
+        })
+                .when(mHandler)
+                .post(any(Runnable.class));
         ConstraintsChecker constraintsChecker =
-                new ConstraintsChecker(mViewResourceAdapter, mConstraintsSupplier);
+                new ConstraintsChecker(mViewResourceAdapter, mConstraintsSupplier, mHandler);
         constraintsChecker.scheduleRequestResourceOnUnlock();
         mConstraintsSupplier.set(BrowserControlsState.SHOWN);
         verify(mViewResourceAdapter, times(0)).onResourceRequested();
@@ -51,7 +64,7 @@
     @Test
     public void testAreControlsLocked() {
         ConstraintsChecker constraintsChecker =
-                new ConstraintsChecker(mViewResourceAdapter, mConstraintsSupplier);
+                new ConstraintsChecker(mViewResourceAdapter, mConstraintsSupplier, mHandler);
         assertEquals(true, constraintsChecker.areControlsLocked());
 
         mConstraintsSupplier.set(BrowserControlsState.SHOWN);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java
index fb398a8..8e5e930 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java
@@ -159,12 +159,12 @@
         return isPriceTrackingPageActionEnabled() || isReaderModePageActionEnabled();
     }
 
-    private static boolean isPriceTrackingPageActionEnabled() {
+    public static boolean isPriceTrackingPageActionEnabled() {
         return ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING)
                 && ChromeFeatureList.isEnabled(ChromeFeatureList.SHOPPING_LIST);
     }
 
-    private static boolean isReaderModePageActionEnabled() {
+    public static boolean isReaderModePageActionEnabled() {
         return ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXTUAL_PAGE_ACTION_READER_MODE);
     }
 
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java
index 9651936..32f1b93 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java
@@ -8,6 +8,8 @@
 import android.graphics.Canvas;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.AttributeSet;
 
 import androidx.annotation.NonNull;
@@ -120,6 +122,7 @@
      */
     public void setConstraintsSupplier(ObservableSupplier<Integer> constraintsSupplier) {
         assert mConstraintsChecker == null;
-        mConstraintsChecker = new ConstraintsChecker(getResourceAdapter(), constraintsSupplier);
+        mConstraintsChecker = new ConstraintsChecker(
+                getResourceAdapter(), constraintsSupplier, new Handler(Looper.getMainLooper()));
     }
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
index 876408f..51308db 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
@@ -11,6 +11,8 @@
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -237,7 +239,8 @@
 
             assert mConstraintsObserver == null;
             if (constraintsSupplier != null) {
-                mConstraintsObserver = new ConstraintsChecker(this, constraintsSupplier);
+                mConstraintsObserver = new ConstraintsChecker(
+                        this, constraintsSupplier, new Handler(Looper.getMainLooper()));
             }
 
             assert mTabSupplier == null;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
index 955cfc81..c28a563 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
@@ -18,6 +18,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowLooper;
 
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.UmaRecorderHolder;
@@ -218,6 +219,7 @@
 
         // BOTH should cause a new onResourceRequested call.
         mConstraintsSupplier.set(BrowserControlsState.BOTH);
+        ShadowLooper.idleMainLooper();
         Assert.assertEquals(1, onResourceRequestedCount.get());
 
         // The constraints should no longer block isDirty/captures.
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
index 2965e206..50f10fc2 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
@@ -3331,6 +3331,7 @@
       base::BindOnce(&CreateTestHoldingSpaceImage));
   const auto& pinned_item_id = pinned_item->id();
   model->AddItem(std::move(pinned_item));
+  task_environment()->RunUntilIdle();
 
   if (suggestion_feature_enabled)
     expected = {{HoldingSpaceItem::Type::kLocalSuggestion, file_path_2}};
@@ -3339,6 +3340,7 @@
   // Unpin the suggested Drive file and verify that the suggestion is re-added
   // to the model if suggestions are enabled.
   model->RemoveItem(pinned_item_id);
+  task_environment()->RunUntilIdle();
 
   if (suggestion_feature_enabled) {
     expected = {{HoldingSpaceItem::Type::kLocalSuggestion, file_path_2},
@@ -3373,6 +3375,7 @@
   // the suggestion is removed from the model if suggestions are enabled.
   model->InitializeOrRemoveItem(partially_initialized_pinned_item_ptr->id(),
                                 GetFileSystemUrl(GetProfile(), file_path_2));
+  task_environment()->RunUntilIdle();
 
   if (suggestion_feature_enabled)
     expected = {{HoldingSpaceItem::Type::kDriveSuggestion, file_path_1}};
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_suggestions_delegate.cc b/chrome/browser/ui/ash/holding_space/holding_space_suggestions_delegate.cc
index 719725f7..cc1c3eb 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_suggestions_delegate.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_suggestions_delegate.cc
@@ -61,7 +61,9 @@
         return item->IsInitialized() &&
                ItemIsPinnedSuggestion(item, suggestions_by_type_);
       })) {
-    UpdateSuggestionsInModel();
+    // Update suggestions asynchronously to avoid updating suggestions along
+    // with other model updates.
+    MaybeScheduleUpdateSuggestionsInModel();
   }
 }
 
@@ -71,14 +73,19 @@
         return item->IsInitialized() &&
                ItemIsPinnedSuggestion(item, suggestions_by_type_);
       })) {
-    UpdateSuggestionsInModel();
+    // Update suggestions asynchronously to avoid updating suggestions along
+    // with other model updates.
+    MaybeScheduleUpdateSuggestionsInModel();
   }
 }
 
 void HoldingSpaceSuggestionsDelegate::OnHoldingSpaceItemInitialized(
     const HoldingSpaceItem* item) {
-  if (ItemIsPinnedSuggestion(item, suggestions_by_type_))
-    UpdateSuggestionsInModel();
+  if (ItemIsPinnedSuggestion(item, suggestions_by_type_)) {
+    // Update suggestions asynchronously to avoid updating suggestions along
+    // with other model updates.
+    MaybeScheduleUpdateSuggestionsInModel();
+  }
 }
 
 void HoldingSpaceSuggestionsDelegate::OnPersistenceRestored() {
@@ -113,6 +120,17 @@
                          weak_factory_.GetWeakPtr(), type));
 }
 
+void HoldingSpaceSuggestionsDelegate::MaybeScheduleUpdateSuggestionsInModel() {
+  // Return early if the task of updating model suggestions has been scheduled.
+  if (suggestion_update_timer_.IsRunning())
+    return;
+
+  suggestion_update_timer_.Start(
+      FROM_HERE, /*delay=*/base::TimeDelta(),
+      base::BindOnce(&HoldingSpaceSuggestionsDelegate::UpdateSuggestionsInModel,
+                     weak_factory_.GetWeakPtr()));
+}
+
 void HoldingSpaceSuggestionsDelegate::OnSuggestionsFetched(
     app_list::FileSuggestionType type,
     const absl::optional<std::vector<app_list::FileSuggestData>>& suggestions) {
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_suggestions_delegate.h b/chrome/browser/ui/ash/holding_space/holding_space_suggestions_delegate.h
index 648c1bb..8b914e1 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_suggestions_delegate.h
+++ b/chrome/browser/ui/ash/holding_space/holding_space_suggestions_delegate.h
@@ -7,6 +7,7 @@
 
 #include <set>
 
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/app_list/search/files/file_suggest_keyed_service.h"
 #include "chrome/browser/ui/app_list/search/files/file_suggest_util.h"
 #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_delegate.h"
@@ -45,6 +46,9 @@
   // early if the fetch on the suggestions of `type` is already pending.
   void MaybeFetchSuggestions(app_list::FileSuggestionType type);
 
+  // Maybe schedules a task to update suggestions in the holding space model.
+  void MaybeScheduleUpdateSuggestionsInModel();
+
   // Called when fetching file suggestions finishes.
   void OnSuggestionsFetched(
       app_list::FileSuggestionType type,
@@ -69,6 +73,9 @@
   std::map<app_list::FileSuggestionType, std::vector<app_list::FileSuggestData>>
       suggestions_by_type_;
 
+  // Used to schedule the task of updating suggestions in model.
+  base::OneShotTimer suggestion_update_timer_;
+
   base::WeakPtrFactory<HoldingSpaceSuggestionsDelegate> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ui/ash/network/network_portal_signin_controller.cc b/chrome/browser/ui/ash/network/network_portal_signin_controller.cc
index 6dd70ab..b7784ac 100644
--- a/chrome/browser/ui/ash/network/network_portal_signin_controller.cc
+++ b/chrome/browser/ui/ash/network/network_portal_signin_controller.cc
@@ -105,6 +105,17 @@
 
 NetworkPortalSigninController::SigninMode
 NetworkPortalSigninController::GetSigninMode() const {
+  if (!user_manager::UserManager::IsInitialized()
+      || !user_manager::UserManager::Get()->IsUserLoggedIn()) {
+    NET_LOG(DEBUG) << "GetSigninMode: Not logged in";
+    return SigninMode::kSigninDialog;
+  }
+
+  if (user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp()) {
+    NET_LOG(DEBUG) << "GetSigninMode: Kiosk app";
+    return SigninMode::kSigninDialog;
+  }
+
   Profile* profile = ProfileManager::GetActiveUserProfile();
   if (!profile) {
     // Login screen. Always show a dialog using the signin profile.
diff --git a/chrome/browser/ui/ash/network/network_portal_signin_controller_unittest.cc b/chrome/browser/ui/ash/network/network_portal_signin_controller_unittest.cc
index 9a4d1ad..e7596a00 100644
--- a/chrome/browser/ui/ash/network/network_portal_signin_controller_unittest.cc
+++ b/chrome/browser/ui/ash/network/network_portal_signin_controller_unittest.cc
@@ -26,6 +26,7 @@
 #include "components/proxy_config/proxy_config_dictionary.h"
 #include "components/proxy_config/proxy_config_pref_names.h"
 #include "components/proxy_config/proxy_prefs.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -170,6 +171,16 @@
   EXPECT_FALSE(controller_->dialog_url().empty());
 }
 
+TEST_F(NetworkPortalSigninControllerTest, KioskMode) {
+  SimulateLogin();
+  const user_manager::User* user = user_manager_->AddKioskAppUser(
+      AccountId::FromUserEmail("fake_user@test"));
+  user_manager_->LoginUser(user->GetAccountId());
+
+  controller_->ShowSignin();
+  EXPECT_FALSE(controller_->dialog_url().empty());
+}
+
 TEST_F(NetworkPortalSigninControllerTest, AuthenticationIgnoresProxyTrue) {
   SimulateLogin();
   // kCaptivePortalAuthenticationIgnoresProxy defaults to true
diff --git a/chrome/browser/ui/ash/network/tether_notification_presenter.h b/chrome/browser/ui/ash/network/tether_notification_presenter.h
index 69ab7e63..70062bb 100644
--- a/chrome/browser/ui/ash/network/tether_notification_presenter.h
+++ b/chrome/browser/ui/ash/network/tether_notification_presenter.h
@@ -8,12 +8,12 @@
 #include <memory>
 #include <string>
 
-#include "ash/components/tether/notification_presenter.h"
 #include "ash/constants/notifier_catalogs.h"
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/network/network_state.h"
+#include "chromeos/ash/components/tether/notification_presenter.h"
 #include "ui/message_center/public/cpp/notification.h"
 
 class Profile;
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
index 589f64e8..568ca547 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
@@ -12,6 +12,7 @@
 #include "ash/components/arc/arc_util.h"
 #include "ash/constants/app_types.h"
 #include "ash/constants/ash_pref_names.h"
+#include "ash/metrics/login_unlock_throughput_recorder.h"
 #include "ash/public/cpp/multi_user_window_manager.h"
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/public/cpp/shelf_model.h"
@@ -129,6 +130,26 @@
   return standard_image;
 }
 
+// Report shelf buttons initialized to LoginUnlockThroughputRecorder.
+void ReportInitShelfIconList(const ash::ShelfModel* model) {
+  // Shell is not always initializaed in tests.
+  if (!ash::Shell::HasInstance())
+    return;
+
+  ash::Shell::Get()->login_unlock_throughput_recorder()->InitShelfIconList(
+      model);
+}
+
+// Report shelf buttons updated to LoginUnlockThroughputRecorder.
+void ReportUpdateShelfIconList(const ash::ShelfModel* model) {
+  // Shell is not always initializaed in tests.
+  if (!ash::Shell::HasInstance())
+    return;
+
+  ash::Shell::Get()->login_unlock_throughput_recorder()->UpdateShelfIconList(
+      model);
+}
+
 }  // namespace
 
 // A class to get events from ChromeOS when a user gets changed or added.
@@ -316,6 +337,7 @@
   if (browser_status_monitor_) {
     browser_status_monitor_->Initialize();
   }
+  ReportInitShelfIconList(model_);
 }
 
 ash::ShelfID ChromeShelfController::CreateAppItem(
@@ -465,6 +487,8 @@
             new_item.id.app_id, image);
     model_->Set(model_->ItemIndexByID(shelf_id), new_item);
   }
+
+  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::UpdateItemImage(const std::string& app_id) {
@@ -687,6 +711,7 @@
         model_->GetItemIndexForType(ash::TYPE_UNPINNED_BROWSER_SHORTCUT);
     if (item_index >= 0) {
       model_->RemoveItemAt(item_index);
+      ReportUpdateShelfIconList(model_);
       return;
     }
   }
@@ -712,6 +737,8 @@
 
   browser_item.status = browser_status;
   model_->Set(browser_index, browser_item);
+
+  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::SetShelfIDForBrowserWindowContents(
@@ -796,6 +823,8 @@
   model_->RemoveItemAt(index);
   model_->AddAt(index, item,
                 std::make_unique<AppShortcutShelfItemController>(item.id));
+
+  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::PinAppAtIndex(const std::string& app_id,
@@ -810,6 +839,8 @@
 
   model_->AddAt(target_index, item,
                 std::make_unique<AppShortcutShelfItemController>(item.id));
+
+  ReportUpdateShelfIconList(model_);
 }
 
 int ChromeShelfController::PinnedItemIndexByAppID(const std::string& app_id) {
@@ -1100,6 +1131,8 @@
     model_->Set(index, item);
     // It's possible we're waiting on more than one item, so don't break.
   }
+
+  ReportUpdateShelfIconList(model_);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1141,6 +1174,8 @@
   const int index = model_->ItemIndexByID(id);
   if (index >= 0 && index < model_->item_count())
     model_->RemoveItemAt(index);
+
+  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::PinRunningAppInternal(
@@ -1273,6 +1308,8 @@
   }
 
   UpdatePolicyPinnedAppsFromPrefs();
+
+  ReportUpdateShelfIconList(model_);
 }
 
 bool ChromeShelfController::EnsureAppPinnedInModelAtIndex(
@@ -1330,6 +1367,8 @@
     item.pinned_by_policy = pinned_by_policy;
     model_->Set(model_index, item);
   }
+
+  ReportUpdateShelfIconList(model_);
 }
 
 ash::ShelfItemStatus ChromeShelfController::GetAppState(
@@ -1373,6 +1412,8 @@
   item.app_status = ShelfControllerHelper::GetAppStatus(
       latest_active_profile_, item_delegate->shelf_id().app_id);
   model_->AddAt(index, item, std::move(item_delegate));
+
+  ReportUpdateShelfIconList(model_);
   return item.id;
 }
 
@@ -1402,6 +1443,8 @@
     model_->Add(browser_shortcut,
                 std::make_unique<BrowserShortcutShelfItemController>(model_));
   }
+
+  ReportUpdateShelfIconList(model_);
 }
 
 int ChromeShelfController::FindInsertionPoint() {
@@ -1568,6 +1611,8 @@
   // Update the pin position preference as needed.
   if (ShouldSyncItemWithReentrancy(item))
     SyncPinPosition(item.id);
+
+  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::ShelfItemRemoved(int index,
@@ -1594,4 +1639,6 @@
     SyncPinPosition(item.id);
   else if (ShouldSyncItemWithReentrancy(old_item) && !ItemTypeIsPinned(item))
     shelf_prefs_->RemovePinPosition(profile(), old_item.id);
+
+  ReportUpdateShelfIconList(model_);
 }
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 068d07a8..dd8a75b 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -14,6 +14,7 @@
 #include "base/i18n/rtl.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/autofill/address_normalizer_factory.h"
 #include "chrome/browser/autofill/autocomplete_history_manager_factory.h"
@@ -67,6 +68,7 @@
 #include "components/autofill/core/common/autofill_payments_features.h"
 #include "components/autofill/core/common/autofill_prefs.h"
 #include "components/autofill/core/common/autofill_switches.h"
+#include "components/autofill/core/common/form_interactions_flow.h"
 #include "components/autofill_assistant/browser/features.h"
 #include "components/autofill_assistant/browser/public/prefs.h"
 #include "components/autofill_assistant/browser/public/runtime_manager.h"
@@ -1151,6 +1153,18 @@
   return log_manager_.get();
 }
 
+FormInteractionsFlowId
+ChromeAutofillClient::GetCurrentFormInteractionsFlowId() {
+  constexpr base::TimeDelta max_flow_time = base::Minutes(20);
+  base::Time now = AutofillClock::Now();
+
+  if (now - flow_id_date_ > max_flow_time || now < flow_id_date_) {
+    flow_id_ = FormInteractionsFlowId(base::GUID::GenerateRandomV4());
+    flow_id_date_ = now;
+  }
+  return flow_id_;
+}
+
 void ChromeAutofillClient::LoadRiskData(
     base::OnceCallback<void(const std::string&)> callback) {
   risk_util::LoadRiskData(0, web_contents(), std::move(callback));
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 4820ce94..8f3c0a3 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -227,6 +227,7 @@
   void ExecuteCommand(int id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
   LogManager* GetLogManager() const override;
+  FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
 
   // RiskDataLoader:
   void LoadRiskData(
@@ -268,6 +269,8 @@
   std::unique_ptr<FormDataImporter> form_data_importer_;
   base::WeakPtr<AutofillPopupControllerImpl> popup_controller_;
   std::unique_ptr<LogManager> log_manager_;
+  FormInteractionsFlowId flow_id_{};
+  base::Time flow_id_date_;
   // If set to true, the popup will stay open regardless of external changes on
   // the test machine, that may normally cause the popup to be hidden
   bool keep_popup_open_for_testing_ = false;
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client_unittest.cc b/chrome/browser/ui/autofill/chrome_autofill_client_unittest.cc
index 1665bc86..e37c7a9 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client_unittest.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client_unittest.cc
@@ -4,16 +4,15 @@
 
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
 
-#include <memory>
-
-#include "base/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/fast_checkout/fast_checkout_features.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/autofill/core/browser/test_autofill_clock.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/autofill/core/common/form_interactions_flow.h"
 #include "components/autofill_assistant/browser/features.h"
 #include "components/autofill_assistant/browser/public/prefs.h"
 #include "components/prefs/pref_service.h"
@@ -63,6 +62,60 @@
   raw_ptr<TestPersonalDataManager> personal_data_manager_ = nullptr;
 };
 
+TEST_F(ChromeAutofillClientTest, GetFormInteractionsFlowId_BelowMaxFlowTime) {
+  // Arbitrary fixed date to avoid using Now().
+  base::Time july_2022 = base::Time::FromDoubleT(1658620440);
+  base::TimeDelta below_max_flow_time = base::Minutes(10);
+
+  autofill::TestAutofillClock test_clock(july_2022);
+
+  FormInteractionsFlowId first_interaction_flow_id =
+      client()->GetCurrentFormInteractionsFlowId();
+
+  test_clock.Advance(below_max_flow_time);
+
+  EXPECT_EQ(first_interaction_flow_id,
+            client()->GetCurrentFormInteractionsFlowId());
+}
+
+TEST_F(ChromeAutofillClientTest, GetFormInteractionsFlowId_AboveMaxFlowTime) {
+  // Arbitrary fixed date to avoid using Now().
+  base::Time july_2022 = base::Time::FromDoubleT(1658620440);
+  base::TimeDelta above_max_flow_time = base::Minutes(21);
+
+  autofill::TestAutofillClock test_clock(july_2022);
+
+  FormInteractionsFlowId first_interaction_flow_id =
+      client()->GetCurrentFormInteractionsFlowId();
+
+  test_clock.Advance(above_max_flow_time);
+
+  EXPECT_NE(first_interaction_flow_id,
+            client()->GetCurrentFormInteractionsFlowId());
+}
+
+TEST_F(ChromeAutofillClientTest, GetFormInteractionsFlowId_AdvancedTwice) {
+  // Arbitrary fixed date to avoid using Now().
+  base::Time july_2022 = base::Time::FromDoubleT(1658620440);
+  base::TimeDelta above_half_max_flow_time = base::Minutes(15);
+
+  autofill::TestAutofillClock test_clock(july_2022);
+
+  FormInteractionsFlowId first_interaction_flow_id =
+      client()->GetCurrentFormInteractionsFlowId();
+
+  test_clock.Advance(above_half_max_flow_time);
+
+  FormInteractionsFlowId second_interaction_flow_id =
+      client()->GetCurrentFormInteractionsFlowId();
+
+  test_clock.Advance(above_half_max_flow_time);
+
+  EXPECT_EQ(first_interaction_flow_id, second_interaction_flow_id);
+  EXPECT_NE(first_interaction_flow_id,
+            client()->GetCurrentFormInteractionsFlowId());
+}
+
 #if BUILDFLAG(IS_ANDROID)
 TEST_F(ChromeAutofillClientTest, IsFastCheckoutSupportedWithDisabledFeature) {
   ScopedFeatureList feature_list;
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 94f60a27..d9c78ef 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -93,7 +93,6 @@
 #include "chrome/browser/web_applications/web_app_id.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
-#include "chrome/common/buildflags.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/content_restriction.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
index 836284c..64abf02 100644
--- a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
+++ b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
@@ -114,30 +114,6 @@
                                        owner, command, tooltip_id);
 }
 
-ui::TouchBarAction TouchBarActionFromCommand(int command) {
-  switch (command) {
-    case IDC_BACK:
-      return ui::TouchBarAction::BACK;
-    case IDC_FORWARD:
-      return ui::TouchBarAction::FORWARD;
-    case IDC_STOP:
-      return ui::TouchBarAction::STOP;
-    case IDC_RELOAD:
-      return ui::TouchBarAction::RELOAD;
-    case IDC_HOME:
-      return ui::TouchBarAction::HOME;
-    case IDC_FOCUS_LOCATION:
-      return ui::TouchBarAction::SEARCH;
-    case IDC_BOOKMARK_THIS_TAB:
-      return ui::TouchBarAction::STAR;
-    case IDC_NEW_TAB:
-      return ui::TouchBarAction::NEW_TAB;
-    default:
-      NOTREACHED();
-      return ui::TouchBarAction::TOUCH_BAR_ACTION_COUNT;
-  }
-}
-
 // A class registered for C++ notifications. This is used to detect changes in
 // the profile preferences and the back/forward commands.
 class TouchBarNotificationBridge : public CommandObserver,
@@ -612,7 +588,6 @@
 
 - (void)executeCommand:(id)sender {
   int command = [sender tag];
-  ui::LogTouchBarUMA(TouchBarActionFromCommand(command));
   _browser->command_controller()->ExecuteCommand(command);
 }
 
diff --git a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm
index 976dfac7..ab4f48f4 100644
--- a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm
@@ -177,7 +177,6 @@
 }
 
 - (void)acceptCreditCard:(id)sender {
-  ui::LogTouchBarUMA(ui::TouchBarAction::CREDIT_CARD_AUTOFILL);
   _controller->AcceptSuggestion([sender tag]);
 }
 
diff --git a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
index e375b39f..1d242564 100644
--- a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
@@ -7,7 +7,6 @@
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
 #import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
@@ -164,15 +163,4 @@
   EXPECT_EQ("bufflehead canvasback", base::SysNSStringToUTF8([button title]));
 }
 
-// Tests that the touch bar histogram is logged correctly.
-TEST_F(CreditCardAutofillTouchBarControllerUnitTest, TouchBarMetric) {
-  {
-    base::HistogramTester histogram_tester;
-    [touch_bar_controller_ acceptCreditCard:nil];
-    histogram_tester.ExpectBucketCount("TouchBar.Default.Metrics",
-                                       ui::TouchBarAction::CREDIT_CARD_AUTOFILL,
-                                       1);
-  }
-}
-
 }  // namespace
diff --git a/chrome/browser/ui/commerce/price_tracking/shopping_list_ui_tab_helper.cc b/chrome/browser/ui/commerce/price_tracking/shopping_list_ui_tab_helper.cc
index a9638a9..3e31fa6 100644
--- a/chrome/browser/ui/commerce/price_tracking/shopping_list_ui_tab_helper.cc
+++ b/chrome/browser/ui/commerce/price_tracking/shopping_list_ui_tab_helper.cc
@@ -95,8 +95,7 @@
   last_fetched_image_ = gfx::Image();
   last_fetched_image_url_ = GURL();
 
-  if (!shopping_service_ || !prefs_ ||
-      !IsShoppingListAllowedForEnterprise(prefs_))
+  if (!shopping_service_ || !prefs_ || !IsShoppingListEnabled(prefs_))
     return;
 
   // Cancel any pending callbacks by invalidating any weak pointers.
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.h b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
index 07eeac78..232938c 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.h
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
@@ -119,12 +119,11 @@
 
   // Enter tab-initiated fullscreen mode. FullscreenController decides whether
   // to also fullscreen the browser window. See 'FullscreenWithinTab Note'.
-  // |requesting_frame| is the specific content frame requesting fullscreen.
-  // If the Window Placement experiment is enabled, fullscreen may be requested
-  // on a particular display. In that case, |display_id| is the display's id;
+  // `requesting_frame` is the specific content frame requesting fullscreen.
+  // Sites with the Window Management permission may request fullscreen on a
+  // particular display. In that case, `display_id` is the display's id;
   // otherwise, display::kInvalidDisplayId indicates no display is specified.
-  //
-  // |CanEnterFullscreenModeForTab()| must return true on entry.
+  // `CanEnterFullscreenModeForTab()` must return true on entry.
   void EnterFullscreenModeForTab(
       content::RenderFrameHost* requesting_frame,
       const int64_t display_id = display::kInvalidDisplayId);
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 44c4d05e..659551a42 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -764,8 +764,8 @@
 #endif  // BUILDFLAG(IS_MAC)
 };
 
-// Tests FullscreenController support of Multi-Screen Window Placement features.
-// Sites with the Window Placement permission can request fullscreen on a
+// Tests FullscreenController support of multi-screen features.
+// Sites with the Window Management permission can request fullscreen on a
 // specific screen, move fullscreen windows to different displays, and more.
 class MultiScreenFullscreenControllerInteractiveTest
     : public FullscreenControllerInteractiveTest {
@@ -1172,7 +1172,7 @@
   permissions::PermissionRequestManager* permission_request_manager =
       permissions::PermissionRequestManager::FromWebContents(tab);
 
-  // Request the Window Placement permission and accept the prompt after user
+  // Request the Window Management permission and accept the prompt after user
   // activation expires; accepting should grant a new transient activation
   // signal that can be used to request fullscreen, without another gesture.
   ExecuteScriptAsync(tab, "getScreenDetails()");
@@ -1285,7 +1285,7 @@
   // Execute JS to request fullscreen and open a popup on separate screens.
   const std::string script = R"(
     (async () => {
-      // Note: WindowPlacementPermissionContext will send an activation signal.
+      // Note: WindowManagementPermissionContext will send an activation signal.
       window.screenDetails = await window.getScreenDetails();
 
       const fullscreen_change_promise = new Promise(resolve => {
diff --git a/chrome/browser/ui/hats/hats_service_browsertest.cc b/chrome/browser/ui/hats/hats_service_browsertest.cc
index 802250a..eac3d8d 100644
--- a/chrome/browser/ui/hats/hats_service_browsertest.cc
+++ b/chrome/browser/ui/hats/hats_service_browsertest.cc
@@ -34,10 +34,10 @@
 
 namespace {
 
-base::test::ScopedFeatureList::FeatureAndParams probability_zero{
+base::test::FeatureRefAndParams probability_zero{
     features::kHappinessTrackingSurveysForDesktopSettings,
     {{"probability", "0.000"}}};
-base::test::ScopedFeatureList::FeatureAndParams probability_one{
+base::test::FeatureRefAndParams probability_one{
     features::kHappinessTrackingSurveysForDesktopSettings,
     {{"probability", "1.000"},
      {"survey", kHatsSurveyTriggerSettings},
@@ -66,8 +66,7 @@
 class HatsServiceBrowserTestBase : public InProcessBrowserTest {
  protected:
   explicit HatsServiceBrowserTestBase(
-      std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-          enabled_features)
+      std::vector<base::test::FeatureRefAndParams> enabled_features)
       : enabled_features_(enabled_features) {
     scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features_, {});
   }
@@ -99,8 +98,7 @@
 
   base::test::ScopedFeatureList scoped_feature_list_;
 
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-      enabled_features_;
+  std::vector<base::test::FeatureRefAndParams> enabled_features_;
 };
 
 class HatsServiceProbabilityZero : public HatsServiceBrowserTestBase {
diff --git a/chrome/browser/ui/popup_browsertest.cc b/chrome/browser/ui/popup_browsertest.cc
index ec65cabf..4da806f 100644
--- a/chrome/browser/ui/popup_browsertest.cc
+++ b/chrome/browser/ui/popup_browsertest.cc
@@ -39,7 +39,7 @@
 namespace {
 
 // Tests of window placement for popup browser windows. Test fixtures are run
-// with and without the experimental WindowPlacement blink feature.
+// with and without multi-screen Window Management permisison.
 class PopupBrowserTest : public InProcessBrowserTest,
                          public ::testing::WithParamInterface<bool> {
  public:
@@ -53,10 +53,10 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         embedder_support::kDisablePopupBlocking);
-    const bool enable_window_placement = GetParam();
+    const bool enable_window_management = GetParam();
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        enable_window_placement ? switches::kEnableBlinkFeatures
-                                : switches::kDisableBlinkFeatures,
+        enable_window_management ? switches::kEnableBlinkFeatures
+                                 : switches::kDisableBlinkFeatures,
         "WindowPlacement");
   }
 
@@ -284,8 +284,8 @@
   // TODO(crbug.com/1119974): this test could be in content_browsertests
   // and not browser_tests if permission controls were supported.
 
-  if (GetParam()) {  // Check whether the WindowPlacement feature is enabled.
-    // Request and auto-accept the Window Placement permission request.
+  if (GetParam()) {  // Check whether to test multi-screen features.
+    // Request and auto-accept the permission request.
     permissions::PermissionRequestManager* permission_request_manager =
         permissions::PermissionRequestManager::FromWebContents(opener);
     permission_request_manager->set_auto_response_for_test(
@@ -324,7 +324,7 @@
       popup->window()->GetNativeWindow());
   WidgetBoundsChangeWaiter(widget, /*move_by=*/40, /*resize_by=*/0).Wait();
   auto new_popup_display = GetDisplayNearestBrowser(popup);
-  // The popup only moves to the second screen with Window Placement permission.
+  // The popup only moves to the second screen with permission.
   EXPECT_EQ(GetParam(), original_popup_display != new_popup_display);
   EXPECT_EQ(GetParam(), second_display == new_popup_display);
   // The popup is always constrained to the bounds of the target display.
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc b/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
index 4877018b..1f6da8f2 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller_unittest.cc
@@ -157,9 +157,6 @@
 // and severity when an upgrade is detected.
 TEST_P(AppMenuIconControllerTest, UpgradeNotification) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Forcibly enable Lacros Profile migration.
-  base::test::ScopedFeatureList feature_list(
-      ash::features::kLacrosProfileMigrationForAnyUser);
   auto set_lacros_enabled =
       crosapi::browser_util::SetLacrosEnabledForTest(true);
 #endif
diff --git a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
index 25074151..a2c89853 100644
--- a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
@@ -160,10 +160,6 @@
   EXPECT_TRUE(detector->notify_upgrade());
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Forcibly enable Lacros Profile migration,
-  // so that IDC_LACROS_DATA_MIGRATION can get visible.
-  base::test::ScopedFeatureList feature_list(
-      ash::features::kLacrosProfileMigrationForAnyUser);
   auto set_lacros_enabled =
       crosapi::browser_util::SetLacrosEnabledForTest(true);
 #endif
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
index f0c1f99..07237364 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
@@ -232,7 +232,7 @@
                                   base::Unretained(bubble_delegate))))
       .SetInitiallyFocusedField(kBookmarkName);
 
-  if (base::FeatureList::IsEnabled(commerce::kShoppingList)) {
+  if (commerce::IsShoppingListEnabled(profile->GetPrefs())) {
     absl::optional<commerce::ProductInfo> product_info =
         commerce::ShoppingServiceFactory::GetForBrowserContext(profile)
             ->GetAvailableProductInfoForUrl(url);
diff --git a/chrome/browser/ui/views/commerce/price_tracking_icon_view.cc b/chrome/browser/ui/views/commerce/price_tracking_icon_view.cc
index 7383fdd..575dde4f 100644
--- a/chrome/browser/ui/views/commerce/price_tracking_icon_view.cc
+++ b/chrome/browser/ui/views/commerce/price_tracking_icon_view.cc
@@ -9,13 +9,16 @@
 #include "chrome/browser/commerce/shopping_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/commerce/price_tracking/shopping_list_ui_tab_helper.h"
 #include "chrome/browser/ui/views/commerce/price_tracking_bubble_dialog_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
 #include "chrome/common/pref_names.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/commerce/core/price_tracking_utils.h"
+#include "components/feature_engagement/public/feature_constants.h"
 #include "components/omnibox/browser/vector_icons.h"
 #include "components/power_bookmarks/core/power_bookmark_utils.h"
 #include "components/power_bookmarks/core/proto/power_bookmark_meta.pb.h"
@@ -30,13 +33,14 @@
 PriceTrackingIconView::PriceTrackingIconView(
     IconLabelBubbleView::Delegate* parent_delegate,
     Delegate* delegate,
-    Profile* profile)
+    Browser* browser)
     : PageActionIconView(nullptr,
                          0,
                          parent_delegate,
                          delegate,
                          "PriceTracking"),
-      profile_(profile),
+      browser_(browser),
+      profile_(browser->profile()),
       bubble_coordinator_(this),
       icon_(&omnibox::kPriceTrackingDisabledIcon) {
   SetProperty(views::kElementIdentifierKey, kPriceTrackingChipElementId);
@@ -149,6 +153,8 @@
     base::RecordAction(
         base::UserMetricsAction("Commerce.PriceTracking.OmniboxChip.Tracked"));
     commerce::MaybeEnableEmailNotifications(profile_->GetPrefs());
+    browser_->window()->MaybeShowFeaturePromo(
+        feature_engagement::kIPHPriceTrackingInSidePanelFeature);
   }
 
   const bookmarks::BookmarkNode* node =
diff --git a/chrome/browser/ui/views/commerce/price_tracking_icon_view.h b/chrome/browser/ui/views/commerce/price_tracking_icon_view.h
index 8b1d16c2..b0f4266 100644
--- a/chrome/browser/ui/views/commerce/price_tracking_icon_view.h
+++ b/chrome/browser/ui/views/commerce/price_tracking_icon_view.h
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
 #include "ui/gfx/vector_icon_types.h"
 
+class Browser;
 class Profile;
 
 // This icon appears in the location bar when the current page qualifies for
@@ -19,7 +20,7 @@
  public:
   PriceTrackingIconView(IconLabelBubbleView::Delegate* parent_delegate,
                         Delegate* delegate,
-                        Profile* profile);
+                        Browser* browser);
   ~PriceTrackingIconView() override;
 
   // PageActionIconView:
@@ -46,7 +47,8 @@
   bool IsPriceTracking() const;
   bool ShouldShowFirstUseExperienceBubble() const;
 
-  raw_ptr<Profile> profile_;
+  const raw_ptr<Browser> browser_;
+  const raw_ptr<Profile> profile_;
   PriceTrackingBubbleCoordinator bubble_coordinator_;
 
   raw_ptr<const gfx::VectorIcon> icon_;
diff --git a/chrome/browser/ui/views/commerce/price_tracking_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/commerce/price_tracking_icon_view_interactive_uitest.cc
index e8f5e1ef..92d536d4 100644
--- a/chrome/browser/ui/views/commerce/price_tracking_icon_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/commerce/price_tracking_icon_view_interactive_uitest.cc
@@ -23,9 +23,11 @@
 #include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/mock_shopping_service.h"
 #include "components/commerce/core/test_utils.h"
+#include "components/feature_engagement/public/feature_constants.h"
 #include "components/omnibox/browser/vector_icons.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
+#include "components/user_education/test/feature_promo_test_util.h"
 #include "content/public/test/browser_test.h"
 #include "ui/base/interaction/element_identifier.h"
 #include "ui/base/interaction/element_tracker.h"
@@ -44,7 +46,10 @@
 class PriceTrackingIconViewInteractiveTest : public InProcessBrowserTest {
  public:
   PriceTrackingIconViewInteractiveTest() {
-    test_features_.InitAndEnableFeature(commerce::kShoppingList);
+    test_features_.InitWithFeatures(
+        {commerce::kShoppingList,
+         feature_engagement::kIPHPriceTrackingInSidePanelFeature},
+        {});
   }
 
   PriceTrackingIconViewInteractiveTest(
@@ -292,6 +297,12 @@
 
 IN_PROC_BROWSER_TEST_F(PriceTrackingBubbleInteractiveTest,
                        TrackPriceOnFUEBubble) {
+  BrowserFeaturePromoController* const promo_controller =
+      BrowserView::GetBrowserViewForBrowser(browser())
+          ->GetFeaturePromoController();
+  EXPECT_TRUE(
+      user_education::test::WaitForFeatureEngagementReady(promo_controller));
+
   // Show PriceTackingIconView.
   auto* icon_view = GetChip();
   icon_view->ForceVisibleForTesting(/*is_tracking_price=*/false);
@@ -324,6 +335,10 @@
   EXPECT_EQ(icon_view->GetTextForTooltipAndAccessibleName(),
             l10n_util::GetStringUTF16(IDS_OMNIBOX_TRACKING_PRICE));
   EXPECT_TRUE(GetBookmarkStar()->GetActive());
+
+  // Verify IPH is showing after accepting the FUE bubble.
+  EXPECT_TRUE(promo_controller->IsPromoActive(
+      feature_engagement::kIPHPriceTrackingInSidePanelFeature));
 }
 
 IN_PROC_BROWSER_TEST_F(PriceTrackingBubbleInteractiveTest,
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index ed0b1e37..c3264c2 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1647,7 +1647,7 @@
   // This is only done once when the app is first opened so that there is only
   // one subscriber per web contents.
   if (AppUsesBorderlessMode() && !old_contents) {
-    SetWindowPlacementPermissionSubscriptionForBorderlessMode(new_contents);
+    SetWindowManagementPermissionSubscriptionForBorderlessMode(new_contents);
     UpdateIsIsolatedWebApp();
   }
 }
@@ -1659,13 +1659,13 @@
     return;
 
   // This is to unsubscribe the window-placement permission subscriber.
-  if (window_placement_subscription_id_) {
+  if (window_management_subscription_id_) {
     contents->GetPrimaryMainFrame()
         ->GetBrowserContext()
         ->GetPermissionController()
         ->UnsubscribePermissionStatusChange(
-            window_placement_subscription_id_.value());
-    window_placement_subscription_id_.reset();
+            window_management_subscription_id_.value());
+    window_management_subscription_id_.reset();
   }
 
   // We need to reset the current tab contents to null before it gets
@@ -2191,13 +2191,13 @@
                 blink::PermissionType::WINDOW_PLACEMENT, url)
             .status;
 
-    window_placement_permission_granted_ =
+    window_management_permission_granted_ =
         status == blink::mojom::PermissionStatus::GRANTED;
   } else {
     // Defaults to the value of borderless_mode_enabled if web contents are
     // null. These get overridden when the app is launched and its web contents
     // are ready.
-    window_placement_permission_granted_ = borderless_mode_enabled;
+    window_management_permission_granted_ = borderless_mode_enabled;
     is_isolated_web_app_ = borderless_mode_enabled;
   }
 
@@ -2210,16 +2210,16 @@
   }
 }
 
-void BrowserView::UpdateWindowPlacementPermission(
+void BrowserView::UpdateWindowManagementPermission(
     blink::mojom::PermissionStatus status) {
-  window_placement_permission_granted_ =
+  window_management_permission_granted_ =
       status == blink::mojom::PermissionStatus::GRANTED;
 
   // The layout has to update to reflect the borderless mode view change.
   InvalidateLayout();
 }
 
-void BrowserView::SetWindowPlacementPermissionSubscriptionForBorderlessMode(
+void BrowserView::SetWindowManagementPermissionSubscriptionForBorderlessMode(
     content::WebContents* web_contents) {
   content::RenderFrameHost* rfh = web_contents->GetPrimaryMainFrame();
   auto* controller = rfh->GetBrowserContext()->GetPermissionController();
@@ -2227,7 +2227,7 @@
   // Last committed URL is null when PWA is opened from chrome://apps.
   url::Origin url = url::Origin::Create(web_contents->GetVisibleURL());
 
-  UpdateWindowPlacementPermission(
+  UpdateWindowManagementPermission(
       controller
           ->GetPermissionResultForOriginWithoutContext(
               blink::PermissionType::WINDOW_PLACEMENT, url)
@@ -2235,10 +2235,10 @@
 
   // It is safe to bind base::Unretained(this) because WebContents is
   // owned by BrowserView.
-  window_placement_subscription_id_ =
+  window_management_subscription_id_ =
       controller->SubscribePermissionStatusChange(
           blink::PermissionType::WINDOW_PLACEMENT, rfh->GetProcess(), url,
-          base::BindRepeating(&BrowserView::UpdateWindowPlacementPermission,
+          base::BindRepeating(&BrowserView::UpdateWindowManagementPermission,
                               base::Unretained(this)));
 }
 
@@ -2260,7 +2260,7 @@
 }
 
 bool BrowserView::IsBorderlessModeEnabled() const {
-  return borderless_mode_enabled_ && window_placement_permission_granted_ &&
+  return borderless_mode_enabled_ && window_management_permission_granted_ &&
          is_isolated_web_app_;
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 7813973b..e645f2e 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -399,7 +399,7 @@
       OnLinkOpeningFromGestureCallback callback);
 
   // Updates the variable keeping track of the borderless mode visibility, which
-  // together with the `window_placement_permission_granted_` controls whether
+  // together with the `window_management_permission_granted_` controls whether
   // the title bar is shown or not.
   void UpdateBorderlessModeEnabled();
 
@@ -422,8 +422,8 @@
     return borderless_mode_enabled_;
   }
 
-  bool window_placement_permission_granted_for_testing() const {
-    return window_placement_permission_granted_;
+  bool window_management_permission_granted_for_testing() const {
+    return window_management_permission_granted_;
   }
 
   void set_isolated_web_app_true_for_testing() { is_isolated_web_app_ = true; }
@@ -958,14 +958,14 @@
   // Updates the visibility of the Window Controls Overlay toggle button.
   void UpdateWindowControlsOverlayToggleVisible();
 
-  // Updates the variable keeping track of the window-placement permission,
+  // Updates the variable keeping track of the "window-placement" permission,
   // which together with borderless_mode_enabled_ controls whether the title bar
   // is shown or not.
-  void UpdateWindowPlacementPermission(blink::mojom::PermissionStatus status);
+  void UpdateWindowManagementPermission(blink::mojom::PermissionStatus status);
 
   // Sets the callback which is called when the status of the window-placement
   // permission changes.
-  void SetWindowPlacementPermissionSubscriptionForBorderlessMode(
+  void SetWindowManagementPermissionSubscriptionForBorderlessMode(
       content::WebContents* web_contents);
 
   // Updates whether the web app is an isolated web app.
@@ -1224,10 +1224,10 @@
   bool window_controls_overlay_enabled_ = false;
   bool should_show_window_controls_overlay_toggle_ = false;
   bool borderless_mode_enabled_ = false;
-  bool window_placement_permission_granted_ = false;
+  bool window_management_permission_granted_ = false;
   bool is_isolated_web_app_ = false;
   absl::optional<content::PermissionController::SubscriptionId>
-      window_placement_subscription_id_;
+      window_management_subscription_id_;
 
   mutable base::WeakPtrFactory<BrowserView> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
index 5b53e2e6..52488c9 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -1113,8 +1113,7 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     MediaDialogViewBrowserTest::SetUpCommandLine(command_line);
 
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     std::map<std::string, std::string> params;
 #if BUILDFLAG(IS_ANDROID)
     params["process_binding_strength"] = "NORMAL";
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index 1b555a5d..4bf75837 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -69,7 +69,7 @@
 #include "chrome/browser/ash/input_method/mock_input_method_manager_impl.h"
 #endif
 
-using FeatureAndParams = base::test::ScopedFeatureList::FeatureAndParams;
+using FeatureAndParams = base::test::FeatureRefAndParams;
 using gfx::Range;
 using metrics::OmniboxEventProto;
 
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_controller.cc b/chrome/browser/ui/views/page_action/page_action_icon_controller.cc
index b46b49b..798cd60 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_controller.cc
+++ b/chrome/browser/ui/views/page_action/page_action_icon_controller.cc
@@ -158,10 +158,10 @@
                                        params.page_action_icon_delegate));
         break;
       case PageActionIconType::kPriceTracking:
-        add_page_action_icon(type, std::make_unique<PriceTrackingIconView>(
-                                       params.icon_label_bubble_delegate,
-                                       params.page_action_icon_delegate,
-                                       params.browser->profile()));
+        add_page_action_icon(
+            type, std::make_unique<PriceTrackingIconView>(
+                      params.icon_label_bubble_delegate,
+                      params.page_action_icon_delegate, params.browser));
         break;
       case PageActionIconType::kPwaInstall:
         DCHECK(params.command_updater);
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
index f2647f9..5101969a 100644
--- a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
@@ -111,8 +111,8 @@
     base::FieldTrialParams iph_demo_params;
     iph_demo_params[feature_engagement::kIPHDemoModeFeatureChoiceParam] =
         feature_engagement::kIPHDesktopPwaInstallFeature.name;
-    base::test::ScopedFeatureList::FeatureAndParams iph_demo(
-        feature_engagement::kIPHDemoMode, iph_demo_params);
+    base::test::FeatureRefAndParams iph_demo(feature_engagement::kIPHDemoMode,
+                                             iph_demo_params);
 
     // kIPHDemoMode will bypass IPH framework's triggering validation so that
     // we can test PWA specific triggering logic.
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
index 185eb7e..157dfc3 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -260,8 +260,7 @@
   virtual bool digital_asset_links_enabled() const { return false; }
 
   void SetUp() override {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     std::vector<base::test::FeatureRef> disabled_features;
 
     if (digital_asset_links_enabled()) {
diff --git a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
index 29e2400c..071e5e6 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
+++ b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
@@ -418,15 +418,16 @@
   // the currently hosted SidePanelEntry.
   DCHECK(content_wrapper->children().size() <= 1);
 
+  content_wrapper->SetVisible(true);
   GetContentView()->SetVisible(true);
   if (current_entry_ && content_wrapper->children().size()) {
     auto current_entry_view =
         content_wrapper->RemoveChildViewT(content_wrapper->children().front());
     current_entry_->CacheView(std::move(current_entry_view));
   }
-  content_wrapper->AddChildView(content_view.has_value()
-                                    ? std::move(content_view.value())
-                                    : entry->GetContent());
+  auto* content = content_wrapper->AddChildView(
+      content_view.has_value() ? std::move(content_view.value())
+                               : entry->GetContent());
   if (auto* contextual_registry = GetActiveContextualRegistry())
     contextual_registry->ResetActiveEntry();
   auto* previous_entry = current_entry_.get();
@@ -435,7 +436,7 @@
   if (previous_entry) {
     previous_entry->OnEntryHidden();
   } else {
-    header_combobox_->RequestFocus();
+    content->RequestFocus();
   }
   header_open_in_new_tab_button_->SetVisible(
       current_entry_->GetOpenInNewTabURL().is_valid());
diff --git a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_browsertest.cc b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_browsertest.cc
index 26e50099..c13c148 100644
--- a/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/site_data/page_specific_site_data_dialog_browsertest.cc
@@ -53,10 +53,9 @@
       public ::testing::WithParamInterface<bool> {
  public:
   PageSpecificSiteDataDialogBrowserTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features = {
-            {net::features::kPartitionedCookies, {}},
-            {net::features::kPartitionedCookiesBypassOriginTrial, {}}};
+    std::vector<base::test::FeatureRefAndParams> enabled_features = {
+        {net::features::kPartitionedCookies, {}},
+        {net::features::kPartitionedCookiesBypassOriginTrial, {}}};
 
     std::vector<base::test::FeatureRef> disabled_features;
     if (GetParam()) {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 3fab434..1799b84 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -136,8 +136,8 @@
     TabDragContext* drag_context) {
   if (base::FeatureList::IsEnabled(features::kSplitTabStrip)) {
     return std::make_unique<CompoundTabContainer>(
-        raw_ref<TabContainerController>(*tab_strip), hover_card_controller,
-        drag_context, *tab_strip, tab_strip);
+        raw_ref<TabContainerController>::from_ptr(tab_strip),
+        hover_card_controller, drag_context, *tab_strip, tab_strip);
   }
   return std::make_unique<TabContainerImpl>(
       *tab_strip, hover_card_controller, drag_context, *tab_strip, tab_strip);
diff --git a/chrome/browser/ui/views/user_education/browser_user_education_service.cc b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
index 24f7909..a01d59b 100644
--- a/chrome/browser/ui/views/user_education/browser_user_education_service.cc
+++ b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
@@ -336,6 +336,11 @@
           .SetCustomActionIsDefault(true)
           .SetCustomActionDismissText(IDS_NOT_NOW)
           .SetBubbleTitleText(IDS_HIGH_EFFICIENCY_MODE_PROMO_TITLE)));
+
+  // kIPHPriceTrackingInSidePanelFeature;
+  registry.RegisterFeature(FeaturePromoSpecification::CreateForLegacyPromo(
+      &feature_engagement::kIPHPriceTrackingInSidePanelFeature,
+      kReadLaterButtonElementId, IDS_PRICE_TRACKING_SIDE_PANEL_IPH));
 }
 
 void MaybeRegisterChromeTutorials(
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
index 15b719a..f4cdf81 100644
--- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
@@ -476,7 +476,7 @@
     return app_id;
   }
 
-  void GrantWindowPlacementPermission() {
+  void GrantWindowManagementPermission() {
     auto* web_contents = helper()->browser_view()->GetActiveWebContents();
 
     std::string permission_auto_approve_script = R"(
@@ -516,14 +516,14 @@
 };
 
 IN_PROC_BROWSER_TEST_F(WebAppFrameToolbarBrowserTest_Borderless,
-                       AppUsesBorderlessModeAndHasWindowPlacementPermission) {
+                       AppUsesBorderlessModeAndHasWindowManagementPermission) {
   InstallAndLaunchWebApp(/*uses_borderless=*/true);
-  GrantWindowPlacementPermission();
+  GrantWindowManagementPermission();
 
   ASSERT_TRUE(helper()->browser_view()->borderless_mode_enabled_for_testing());
   ASSERT_TRUE(helper()
                   ->browser_view()
-                  ->window_placement_permission_granted_for_testing());
+                  ->window_management_permission_granted_for_testing());
   ASSERT_TRUE(helper()->browser_view()->IsBorderlessModeEnabled());
   ASSERT_FALSE(
       helper()->web_app_frame_toolbar()->GetAppMenuButton()->GetVisible());
@@ -550,7 +550,7 @@
   EXPECT_TRUE(EvalJs(web_contents, match_media_standalone).ExtractBool());
   ASSERT_EQ(blue, EvalJs(web_contents, get_background_color));
 
-  GrantWindowPlacementPermission();
+  GrantWindowManagementPermission();
   ASSERT_TRUE(helper()->browser_view()->IsBorderlessModeEnabled());
 
   // Validate that after granting the permission the display-mode matches with
@@ -561,12 +561,12 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppFrameToolbarBrowserTest_Borderless,
-    AppUsesBorderlessModeAndDoesNotHaveWindowPlacementPermission) {
+    AppUsesBorderlessModeAndDoesNotHaveWindowManagementPermission) {
   InstallAndLaunchWebApp(/*uses_borderless=*/true);
   ASSERT_TRUE(helper()->browser_view()->borderless_mode_enabled_for_testing());
   ASSERT_FALSE(helper()
                    ->browser_view()
-                   ->window_placement_permission_granted_for_testing());
+                   ->window_management_permission_granted_for_testing());
   ASSERT_FALSE(helper()->browser_view()->IsBorderlessModeEnabled());
 }
 
@@ -576,7 +576,7 @@
   ASSERT_FALSE(helper()->browser_view()->borderless_mode_enabled_for_testing());
   ASSERT_FALSE(helper()
                    ->browser_view()
-                   ->window_placement_permission_granted_for_testing());
+                   ->window_management_permission_granted_for_testing());
   ASSERT_FALSE(helper()->browser_view()->IsBorderlessModeEnabled());
   ASSERT_TRUE(
       helper()->web_app_frame_toolbar()->GetAppMenuButton()->GetVisible());
diff --git a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
index f247043..818a535 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.h"
 #include "chrome/browser/ui/webauthn/authenticator_request_dialog.h"
 #include "chrome/browser/ui/webauthn/authenticator_request_sheet_model.h"
+#include "chrome/browser/ui/webauthn/sheet_models.h"
 #include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/browser_test.h"
@@ -138,7 +139,7 @@
           transport_availability;
       transport_availability.available_transports = {
           AuthenticatorTransport::kUsbHumanInterfaceDevice,
-          AuthenticatorTransport::kInternal, AuthenticatorTransport::kHybrid};
+          AuthenticatorTransport::kHybrid};
 
       std::array<uint8_t, device::kP256X962Length> public_key = {0};
       AuthenticatorRequestDialogModel::PairedPhone phone("Phone", 0,
@@ -159,6 +160,13 @@
               dialog_model_.get());
 
       // The "manage devices" button should have been shown on this sheet.
+      EXPECT_EQ(
+          reinterpret_cast<AuthenticatorSheetModelBase*>(
+              test::AuthenticatorRequestDialogViewTestApi::GetSheet(dialog)
+                  ->model())
+              ->dialog_model()
+              ->current_step(),
+          AuthenticatorRequestDialogModel::Step::kMechanismSelection);
       EXPECT_TRUE(test::AuthenticatorRequestDialogViewTestApi::GetSheet(dialog)
                       ->model()
                       ->IsManageDevicesButtonVisible());
diff --git a/chrome/browser/ui/webui/chromeos/login/consolidated_consent_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/consolidated_consent_screen_handler.cc
index 7ba102e..3f07c9a 100644
--- a/chrome/browser/ui/webui/chromeos/login/consolidated_consent_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/consolidated_consent_screen_handler.cc
@@ -12,6 +12,7 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/login/localized_values_builder.h"
+#include "ui/chromeos/devicetype_utils.h"
 
 namespace chromeos {
 
@@ -51,6 +52,11 @@
                IDS_CONSOLIDATED_CONSENT_BACKUP_OPT_IN_CHILD);
   builder->Add("consolidatedConsenttBackupOptInLearnMoreLink",
                IDS_CONSOLIDATED_CONSENT_BACKUP_OPT_IN_LEARN_MORE_LINK);
+  builder->Add("consolidatedConsentRecoveryOptInTitle",
+               IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN_TITLE);
+  builder->AddF("consolidatedConsentRecoveryOptIn",
+                IDS_CONSOLIDATED_CONSENT_RECOVERY_OPT_IN,
+                ui::GetChromeOSDeviceTypeResourceId());
   builder->Add("consolidatedConsentLocationOptInTitle",
                IDS_CONSOLIDATED_CONSENT_LOCATION_OPT_IN_TITLE);
   builder->Add("consolidatedConsentLocationOptIn",
diff --git a/chrome/browser/ui/webui/chromeos/user_image_source.cc b/chrome/browser/ui/webui/chromeos/user_image_source.cc
index 7afcfe1..705fa24 100644
--- a/chrome/browser/ui/webui/chromeos/user_image_source.cc
+++ b/chrome/browser/ui/webui/chromeos/user_image_source.cc
@@ -140,7 +140,8 @@
           !user->HasDefaultImage() || user->has_image_bytes());
 
     if (user->has_image_bytes()) {
-      if (user->image_format() == user_manager::UserImage::FORMAT_PNG) {
+      if (user->image_format() == user_manager::UserImage::FORMAT_PNG ||
+          user->image_format() == user_manager::UserImage::FORMAT_WEBP) {
         return GetUserImageFrame(user->image_bytes(), user->image_format(),
                                  frame);
       } else {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 2ce61f0..33d3be3 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -44,7 +44,6 @@
 #include "chrome/browser/ui/webui/print_preview/print_preview_metrics.h"
 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
-#include "chrome/common/buildflags.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/crash_keys.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index a0db7330..7636778 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -19,7 +19,6 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/common/buildflags.h"
 #include "components/prefs/pref_service.h"
 #include "components/printing/common/print.mojom.h"
 #include "content/public/browser/web_ui_message_handler.h"
diff --git a/chrome/browser/ui/webui/settings/OWNERS b/chrome/browser/ui/webui/settings/OWNERS
index d27a101..7db49e8 100644
--- a/chrome/browser/ui/webui/settings/OWNERS
+++ b/chrome/browser/ui/webui/settings/OWNERS
@@ -11,6 +11,5 @@
 per-file safe_browsing_handler*=sauski@google.com
 per-file safety_check_handler*=andzaytsev@google.com,rainhard@chromium.org
 per-file settings_clear_browsing_data_handler*=sauski@google.com
-per-file settings_cookies_view_handler*=sauski@google.com
 per-file settings_localized_strings_provider*=sauski@google.com
 per-file settings_security_key_handler*=file://device/fido/OWNERS
diff --git a/chrome/browser/ui/webui/settings/ash/internet_handler.h b/chrome/browser/ui/webui/settings/ash/internet_handler.h
index 5c3ef4d..ca212675 100644
--- a/chrome/browser/ui/webui/settings/ash/internet_handler.h
+++ b/chrome/browser/ui/webui/settings/ash/internet_handler.h
@@ -7,8 +7,8 @@
 
 #include <memory>
 
-#include "ash/components/tether/gms_core_notifications_state_tracker.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+#include "chromeos/ash/components/tether/gms_core_notifications_state_tracker.h"
 #include "ui/gfx/native_widget_types.h"
 
 class Profile;
diff --git a/chrome/browser/ui/webui/settings/ash/internet_handler_unittest.cc b/chrome/browser/ui/webui/settings/ash/internet_handler_unittest.cc
index 72faf79..9d17a08 100644
--- a/chrome/browser/ui/webui/settings/ash/internet_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/ash/internet_handler_unittest.cc
@@ -6,8 +6,8 @@
 
 #include <memory>
 
-#include "ash/components/tether/fake_gms_core_notifications_state_tracker.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
+#include "chromeos/ash/components/tether/fake_gms_core_notifications_state_tracker.h"
 #include "content/public/test/test_web_ui.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/ui/webui/settings/hats_handler_unittest.cc b/chrome/browser/ui/webui/settings/hats_handler_unittest.cc
index 7690c45..58c1609 100644
--- a/chrome/browser/ui/webui/settings/hats_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/hats_handler_unittest.cc
@@ -34,13 +34,13 @@
 class HatsHandlerTest : public ChromeRenderViewHostTestHarness {
  public:
   HatsHandlerTest() {
-    base::test::ScopedFeatureList::FeatureAndParams settings_privacy{
+    base::test::FeatureRefAndParams settings_privacy{
         features::kHappinessTrackingSurveysForDesktopSettingsPrivacy,
         {{"settings-time", "15s"}}};
-    base::test::ScopedFeatureList::FeatureAndParams privacy_sandbox{
+    base::test::FeatureRefAndParams privacy_sandbox{
         features::kHappinessTrackingSurveysForDesktopPrivacySandbox,
         {{"settings-time", "10s"}}};
-    base::test::ScopedFeatureList::FeatureAndParams privacy_guide{
+    base::test::FeatureRefAndParams privacy_guide{
         features::kHappinessTrackingSurveysForDesktopPrivacyGuide,
         {{"settings-time", "15s"}}};
     scoped_feature_list_.InitWithFeaturesAndParameters(
@@ -138,7 +138,7 @@
  public:
   HatsHandlerNoSandboxTest() {
     scoped_feature_list_.Reset();
-    base::test::ScopedFeatureList::FeatureAndParams settings_privacy{
+    base::test::FeatureRefAndParams settings_privacy{
         features::kHappinessTrackingSurveysForDesktopSettingsPrivacy,
         {{"no-sandbox", "true"}}};
     scoped_feature_list_.InitWithFeaturesAndParameters({settings_privacy}, {});
diff --git a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc b/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc
deleted file mode 100644
index ff22eb5..0000000
--- a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc
+++ /dev/null
@@ -1,505 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/settings/settings_cookies_view_handler.h"
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/i18n/number_formatting.h"
-#include "base/ranges/algorithm.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/browsing_data/third_party_data_remover.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/cookies_tree_model_util.h"
-#include "chrome/grit/generated_resources.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/site_instance.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/browser/web_ui.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/text/bytes_formatting.h"
-
-namespace storage {
-class FileSystemContext;
-}
-
-namespace {
-
-int GetCategoryLabelID(CookieTreeNode::DetailedInfo::NodeType node_type) {
-  constexpr struct {
-    CookieTreeNode::DetailedInfo::NodeType node_type;
-    int id;
-  } kCategoryLabels[] = {
-      // Multiple keys (node_type) may have the same value (id).
-
-      {CookieTreeNode::DetailedInfo::TYPE_DATABASES,
-       IDS_SETTINGS_COOKIES_DATABASE_STORAGE},
-      {CookieTreeNode::DetailedInfo::TYPE_DATABASE,
-       IDS_SETTINGS_COOKIES_DATABASE_STORAGE},
-
-      {CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGES,
-       IDS_SETTINGS_COOKIES_LOCAL_STORAGE},
-      {CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE,
-       IDS_SETTINGS_COOKIES_LOCAL_STORAGE},
-
-      {CookieTreeNode::DetailedInfo::TYPE_INDEXED_DBS,
-       IDS_SETTINGS_COOKIES_DATABASE_STORAGE},
-      {CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB,
-       IDS_SETTINGS_COOKIES_DATABASE_STORAGE},
-
-      {CookieTreeNode::DetailedInfo::TYPE_FILE_SYSTEMS,
-       IDS_SETTINGS_COOKIES_FILE_SYSTEM},
-      {CookieTreeNode::DetailedInfo::TYPE_FILE_SYSTEM,
-       IDS_SETTINGS_COOKIES_FILE_SYSTEM},
-
-      {CookieTreeNode::DetailedInfo::TYPE_SERVICE_WORKERS,
-       IDS_SETTINGS_COOKIES_SERVICE_WORKER},
-      {CookieTreeNode::DetailedInfo::TYPE_SERVICE_WORKER,
-       IDS_SETTINGS_COOKIES_SERVICE_WORKER},
-
-      {CookieTreeNode::DetailedInfo::TYPE_SHARED_WORKERS,
-       IDS_SETTINGS_COOKIES_SHARED_WORKER},
-      {CookieTreeNode::DetailedInfo::TYPE_SHARED_WORKER,
-       IDS_SETTINGS_COOKIES_SHARED_WORKER},
-
-      {CookieTreeNode::DetailedInfo::TYPE_CACHE_STORAGES,
-       IDS_SETTINGS_COOKIES_CACHE_STORAGE},
-      {CookieTreeNode::DetailedInfo::TYPE_CACHE_STORAGE,
-       IDS_SETTINGS_COOKIES_CACHE_STORAGE},
-
-      {CookieTreeNode::DetailedInfo::TYPE_QUOTA,
-       IDS_SETTINGS_COOKIES_QUOTA_STORAGE},
-  };
-  // Before optimizing, consider the data size and the cost of L2 cache misses.
-  // A linear search over a couple dozen integers is very fast.
-  for (size_t i = 0; i < std::size(kCategoryLabels); ++i) {
-    if (kCategoryLabels[i].node_type == node_type) {
-      return kCategoryLabels[i].id;
-    }
-  }
-  NOTREACHED();
-  return 0;
-}
-
-}  // namespace
-
-namespace settings {
-
-constexpr char kLocalData[] = "localData";
-constexpr char kSite[] = "site";
-
-CookiesViewHandler::Request::Request(TreeModelBatchBehavior batch_behavior,
-                                     base::OnceClosure initial_task)
-    : batch_behavior(batch_behavior), initial_task(std::move(initial_task)) {
-  if (batch_behavior == Request::ASYNC_BATCH)
-    batch_end_task = base::DoNothing();
-}
-
-CookiesViewHandler::Request::Request(base::OnceClosure initial_task,
-                                     base::OnceClosure batch_end_task)
-    : batch_behavior(Request::TreeModelBatchBehavior::ASYNC_BATCH),
-      initial_task(std::move(initial_task)),
-      batch_end_task(std::move(batch_end_task)) {}
-
-CookiesViewHandler::Request::~Request() = default;
-
-CookiesViewHandler::Request::Request(Request&& other) {
-  initial_task = std::move(other.initial_task);
-  batch_end_task = std::move(other.batch_end_task);
-}
-
-CookiesViewHandler::CookiesViewHandler()
-    : batch_update_(false), model_util_(new CookiesTreeModelUtil) {}
-
-CookiesViewHandler::~CookiesViewHandler() {
-}
-
-void CookiesViewHandler::OnJavascriptAllowed() {
-  // Some requests assume that a tree model has already been created, creating
-  // here ensures this is true.
-  pending_requests_.emplace(
-      Request::ASYNC_BATCH,
-      base::BindOnce(&CookiesViewHandler::RecreateCookiesTreeModel,
-                     callback_weak_ptr_factory_.GetWeakPtr()));
-  ProcessPendingRequests();
-}
-
-void CookiesViewHandler::OnJavascriptDisallowed() {
-  callback_weak_ptr_factory_.InvalidateWeakPtrs();
-  pending_requests_ = std::queue<Request>();
-}
-
-void CookiesViewHandler::RegisterMessages() {
-  web_ui()->RegisterMessageCallback(
-      "localData.getDisplayList",
-      base::BindRepeating(&CookiesViewHandler::HandleGetDisplayList,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "localData.removeAll",
-      base::BindRepeating(&CookiesViewHandler::HandleRemoveAll,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "localData.removeShownItems",
-      base::BindRepeating(&CookiesViewHandler::HandleRemoveShownItems,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "localData.removeItem",
-      base::BindRepeating(&CookiesViewHandler::HandleRemoveItem,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "localData.getCookieDetails",
-      base::BindRepeating(&CookiesViewHandler::HandleGetCookieDetails,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "localData.getNumCookiesString",
-      base::BindRepeating(&CookiesViewHandler::HandleGetNumCookiesString,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "localData.removeSite",
-      base::BindRepeating(&CookiesViewHandler::HandleRemoveSite,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "localData.removeThirdPartyCookies",
-      base::BindRepeating(&CookiesViewHandler::HandleRemoveThirdParty,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "localData.reload",
-      base::BindRepeating(&CookiesViewHandler::HandleReloadCookies,
-                          base::Unretained(this)));
-}
-
-void CookiesViewHandler::TreeNodesAdded(ui::TreeModel* model,
-                                        ui::TreeModelNode* parent,
-                                        size_t start,
-                                        size_t count) {}
-
-void CookiesViewHandler::TreeNodesRemoved(ui::TreeModel* model,
-                                          ui::TreeModelNode* parent,
-                                          size_t start,
-                                          size_t count) {
-  // Skip if there is a batch update in progress.
-  if (batch_update_)
-    return;
-  FireWebUIListener("on-tree-item-removed");
-}
-
-void CookiesViewHandler::TreeModelBeginBatch(CookiesTreeModel* model) {
-  DCHECK(!batch_update_);  // There should be no nested batch begin.
-  DCHECK(!pending_requests_.empty());
-  batch_update_ = true;
-
-  DCHECK_NE(Request::NO_BATCH, pending_requests_.front().batch_behavior);
-}
-
-void CookiesViewHandler::TreeModelEndBatch(CookiesTreeModel* model) {
-  DCHECK(batch_update_);
-  DCHECK(!pending_requests_.empty());
-  batch_update_ = false;
-
-  DCHECK_NE(Request::NO_BATCH, pending_requests_.front().batch_behavior);
-
-  if (pending_requests_.front().batch_behavior == Request::ASYNC_BATCH) {
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, std::move(pending_requests_.front().batch_end_task));
-
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(&CookiesViewHandler::RequestComplete,
-                                  callback_weak_ptr_factory_.GetWeakPtr()));
-  }
-}
-
-void CookiesViewHandler::SetCookiesTreeModelForTesting(
-    std::unique_ptr<CookiesTreeModel> cookies_tree_model) {
-  cookies_tree_model_for_testing_ = std::move(cookies_tree_model);
-}
-
-void CookiesViewHandler::RecreateCookiesTreeModel() {
-  cookies_tree_model_.reset();
-  filter_.clear();
-  cookies_tree_model_ = cookies_tree_model_for_testing_.get()
-                            ? std::move(cookies_tree_model_for_testing_)
-                            : CookiesTreeModel::CreateForProfileDeprecated(
-                                  Profile::FromWebUI(web_ui()));
-  cookies_tree_model_->AddCookiesTreeObserver(this);
-}
-
-void CookiesViewHandler::HandleGetCookieDetails(const base::Value::List& args) {
-  CHECK_EQ(2U, args.size());
-  std::string callback_id = args[0].GetString();
-  std::string site = args[1].GetString();
-
-  AllowJavascript();
-  pending_requests_.emplace(
-      Request::NO_BATCH, base::BindOnce(&CookiesViewHandler::GetCookieDetails,
-                                        callback_weak_ptr_factory_.GetWeakPtr(),
-                                        callback_id, site));
-  ProcessPendingRequests();
-}
-
-void CookiesViewHandler::GetCookieDetails(const std::string& callback_id,
-                                          const std::string& site) {
-  const CookieTreeNode* node = model_util_->GetTreeNodeFromTitle(
-      cookies_tree_model_->GetRoot(), base::UTF8ToUTF16(site));
-
-  if (!node) {
-    RejectJavascriptCallback(base::Value(callback_id), base::Value());
-    return;
-  }
-
-  base::Value::List children = model_util_->GetChildNodeDetailsDeprecated(node);
-
-  ResolveJavascriptCallback(base::Value(callback_id), children);
-}
-
-void CookiesViewHandler::HandleGetNumCookiesString(
-    const base::Value::List& args) {
-  CHECK_EQ(2U, args.size());
-  std::string callback_id;
-  callback_id = args[0].GetString();
-  int num_cookies = args[1].GetInt();
-
-  AllowJavascript();
-  const std::u16string string =
-      num_cookies > 0 ? l10n_util::GetPluralStringFUTF16(
-                            IDS_SETTINGS_SITE_SETTINGS_NUM_COOKIES, num_cookies)
-                      : std::u16string();
-
-  ResolveJavascriptCallback(base::Value(callback_id), base::Value(string));
-}
-
-void CookiesViewHandler::HandleGetDisplayList(const base::Value::List& args) {
-  CHECK_EQ(2U, args.size());
-  std::string callback_id = args[0].GetString();
-  std::u16string filter = base::UTF8ToUTF16(args[1].GetString());
-
-  AllowJavascript();
-  pending_requests_.emplace(
-      Request::SYNC_BATCH,
-      base::BindOnce(&CookiesViewHandler::GetDisplayList,
-                     callback_weak_ptr_factory_.GetWeakPtr(), callback_id,
-                     filter));
-
-  ProcessPendingRequests();
-}
-
-void CookiesViewHandler::GetDisplayList(std::string callback_id,
-                                        const std::u16string& filter) {
-  if (filter != filter_) {
-    filter_ = filter;
-    cookies_tree_model_->UpdateSearchResults(filter_);
-    DCHECK(!batch_update_) << "Expected CookiesTreeModel::UpdateSearchResults "
-                           << "to execute synchronously.";
-  }
-  ReturnLocalDataList(callback_id);
-}
-
-void CookiesViewHandler::HandleReloadCookies(const base::Value::List& args) {
-  CHECK_EQ(1U, args.size());
-  std::string callback_id = args[0].GetString();
-
-  // Allowing Javascript for the first time will queue a task to create a new
-  // tree model. Thus the tree model only needs to be recreated if Javascript
-  // has already been allowed. Reload cookies is often the first call made by
-  // pages using this handler, so this avoids unnecessary work.
-  if (IsJavascriptAllowed()) {
-    pending_requests_.emplace(
-        base::BindOnce(&CookiesViewHandler::RecreateCookiesTreeModel,
-                       callback_weak_ptr_factory_.GetWeakPtr()),
-        base::BindOnce(&CookiesViewHandler::ResolveJavascriptCallback,
-                       callback_weak_ptr_factory_.GetWeakPtr(),
-                       base::Value(callback_id), base::Value()));
-  } else {
-    AllowJavascript();
-    pending_requests_.emplace(
-        Request::NO_BATCH,
-        base::BindOnce(&CookiesViewHandler::ResolveJavascriptCallback,
-                       callback_weak_ptr_factory_.GetWeakPtr(),
-                       base::Value(callback_id), base::Value()));
-  }
-  ProcessPendingRequests();
-}
-
-void CookiesViewHandler::HandleRemoveAll(const base::Value::List& args) {
-  CHECK_EQ(1U, args.size());
-  AllowJavascript();
-
-  std::string callback_id = args[0].GetString();
-
-  pending_requests_.emplace(
-      Request::SYNC_BATCH,
-      base::BindOnce(&CookiesViewHandler::RemoveAll,
-                     callback_weak_ptr_factory_.GetWeakPtr(), callback_id));
-  ProcessPendingRequests();
-}
-
-void CookiesViewHandler::RemoveAll(const std::string& callback_id) {
-  cookies_tree_model_->DeleteAllStoredObjects();
-  ResolveJavascriptCallback(base::Value(callback_id), base::Value());
-}
-
-void CookiesViewHandler::HandleRemoveItem(const base::Value::List& args) {
-  std::string node_path = args[0].GetString();
-
-  AllowJavascript();
-  pending_requests_.emplace(
-      Request::NO_BATCH,
-      base::BindOnce(&CookiesViewHandler::RemoveItem,
-                     callback_weak_ptr_factory_.GetWeakPtr(), node_path));
-  ProcessPendingRequests();
-}
-
-void CookiesViewHandler::RemoveItem(const std::string& path) {
-  const CookieTreeNode* node =
-      model_util_->GetTreeNodeFromPath(cookies_tree_model_->GetRoot(), path);
-  if (node) {
-    cookies_tree_model_->DeleteCookieNode(const_cast<CookieTreeNode*>(node));
-  }
-}
-
-void CookiesViewHandler::HandleRemoveThirdParty(const base::Value::List& args) {
-  CHECK_EQ(1U, args.size());
-  std::string callback_id = args[0].GetString();
-
-  AllowJavascript();
-  Profile* profile = Profile::FromWebUI(web_ui());
-
-  pending_requests_.emplace(
-      base::BindOnce(
-          ClearThirdPartyData,
-          base::BindOnce(&CookiesViewHandler::RecreateCookiesTreeModel,
-                         callback_weak_ptr_factory_.GetWeakPtr()),
-          profile),
-      base::BindOnce(&CookiesViewHandler::ResolveJavascriptCallback,
-                     callback_weak_ptr_factory_.GetWeakPtr(),
-                     base::Value(callback_id), base::Value()));
-  ProcessPendingRequests();
-}
-
-void CookiesViewHandler::HandleRemoveShownItems(const base::Value::List& args) {
-  CHECK_EQ(0U, args.size());
-
-  AllowJavascript();
-  pending_requests_.emplace(
-      Request::NO_BATCH,
-      base::BindOnce(&CookiesViewHandler::RemoveShownItems,
-                     callback_weak_ptr_factory_.GetWeakPtr()));
-  ProcessPendingRequests();
-}
-
-void CookiesViewHandler::RemoveShownItems() {
-  CookieTreeNode* parent = cookies_tree_model_->GetRoot();
-  while (!parent->children().empty())
-    cookies_tree_model_->DeleteCookieNode(parent->children().front().get());
-}
-
-void CookiesViewHandler::HandleRemoveSite(const base::Value::List& args) {
-  CHECK_EQ(1U, args.size());
-  std::u16string site = base::UTF8ToUTF16(args[0].GetString());
-  AllowJavascript();
-  pending_requests_.emplace(
-      Request::NO_BATCH,
-      base::BindOnce(&CookiesViewHandler::RemoveSite,
-                     callback_weak_ptr_factory_.GetWeakPtr(), site));
-  ProcessPendingRequests();
-}
-
-void CookiesViewHandler::RemoveSite(const std::u16string& site) {
-  CookieTreeNode* parent = cookies_tree_model_->GetRoot();
-  const auto i =
-      base::ranges::find(parent->children(), site, &CookieTreeNode::GetTitle);
-  if (i != parent->children().cend()) {
-    cookies_tree_model_->DeleteCookieNode(i->get());
-  }
-}
-
-void CookiesViewHandler::ReturnLocalDataList(const std::string& callback_id) {
-  CHECK(cookies_tree_model_.get());
-  auto* parent = cookies_tree_model_->GetRoot();
-
-  // The layers in the CookieTree are:
-  //   root - Top level.
-  //   site - www.google.com, example.com, etc.
-  //   category - Cookies, Local Storage, etc.
-  //   item - Info on the actual thing.
-  // Gather list of sites with some highlights of the categories and items.
-  base::Value::List site_list;
-  for (const auto& site : parent->children()) {
-    std::u16string description;
-    for (const auto& category : site->children()) {
-      const auto node_type = category->GetDetailedInfo().node_type;
-      if (!description.empty())
-        description += u", ";
-      size_t item_count = category->children().size();
-
-      switch (node_type) {
-        case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
-          DCHECK_EQ(0u, item_count);
-          item_count = 1;
-          [[fallthrough]];
-        case CookieTreeNode::DetailedInfo::TYPE_COOKIES:
-          description += l10n_util::GetPluralStringFUTF16(
-              IDS_SETTINGS_SITE_SETTINGS_NUM_COOKIES,
-              static_cast<int>(item_count));
-          break;
-        default:
-          int ids_value = GetCategoryLabelID(node_type);
-          if (!ids_value) {
-            // If we don't have a label to call it by, don't show it. Please add
-            // a label ID if an expected category is not appearing in the UI.
-            continue;
-          }
-          description += l10n_util::GetStringUTF16(ids_value);
-          break;
-      }
-    }
-    base::Value::Dict list_info;
-    list_info.Set(kLocalData, description);
-    list_info.Set(kSite, site->GetTitle());
-    site_list.Append(std::move(list_info));
-  }
-
-  // Sort the list into alphabetical order based on site name.
-  std::sort(site_list.begin(), site_list.end(),
-            [=](const base::Value& a, const base::Value& b) {
-              return *a.FindStringKey(kSite) < *b.FindStringKey(kSite);
-            });
-
-  ResolveJavascriptCallback(base::Value(callback_id), site_list);
-}
-
-void CookiesViewHandler::ProcessPendingRequests() {
-  if (pending_requests_.empty())
-    return;
-
-  // To ensure that multiple requests do not run during a tree model batch
-  // update, only tasks for a single request are queued at any one time.
-  if (request_in_progress_)
-    return;
-
-  request_in_progress_ = true;
-
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, std::move(pending_requests_.front().initial_task));
-  if (pending_requests_.front().batch_behavior != Request::ASYNC_BATCH) {
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(&CookiesViewHandler::RequestComplete,
-                                  callback_weak_ptr_factory_.GetWeakPtr()));
-  }
-}
-
-void CookiesViewHandler::RequestComplete() {
-  DCHECK(!pending_requests_.empty());
-  DCHECK(!batch_update_);
-  request_in_progress_ = false;
-  pending_requests_.pop();
-  ProcessPendingRequests();
-}
-
-}  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.h b/chrome/browser/ui/webui/settings/settings_cookies_view_handler.h
deleted file mode 100644
index 51990be3..0000000
--- a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.h
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_COOKIES_VIEW_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_COOKIES_VIEW_HANDLER_H_
-
-#include <memory>
-#include <queue>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/gtest_prod_util.h"
-#include "chrome/browser/browsing_data/cookies_tree_model.h"
-#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
-
-class CookiesTreeModelUtil;
-
-namespace settings {
-
-class CookiesViewHandler : public SettingsPageUIHandler,
-                           public CookiesTreeModel::Observer {
- public:
-  CookiesViewHandler();
-
-  CookiesViewHandler(const CookiesViewHandler&) = delete;
-  CookiesViewHandler& operator=(const CookiesViewHandler&) = delete;
-
-  ~CookiesViewHandler() override;
-
-  // SettingsPageUIHandler:
-  void OnJavascriptAllowed() override;
-  void OnJavascriptDisallowed() override;
-  void RegisterMessages() override;
-
-  // CookiesTreeModel::Observer:
-  void TreeNodesAdded(ui::TreeModel* model,
-                      ui::TreeModelNode* parent,
-                      size_t start,
-                      size_t count) override;
-  void TreeNodesRemoved(ui::TreeModel* model,
-                        ui::TreeModelNode* parent,
-                        size_t start,
-                        size_t count) override;
-  void TreeNodeChanged(ui::TreeModel* model, ui::TreeModelNode* node) override {
-  }
-  void TreeModelBeginBatch(CookiesTreeModel* model) override;
-  void TreeModelEndBatch(CookiesTreeModel* model) override;
-
-  // Sets the tree model that will be used when the handler creates a tree
-  // model, instead of building from from the profile.
-  void SetCookiesTreeModelForTesting(
-      std::unique_ptr<CookiesTreeModel> cookies_tree_model);
-
- private:
-  friend class CookiesViewHandlerTest;
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest, HandleGetDisplayList);
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest, HandleRemoveShownItems);
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest, SingleRequestDuringBatch);
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest, NoStarvation);
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest, ImmediateTreeOperation);
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest,
-                           HandleReloadCookiesAndGetDisplayList);
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest, HandleGetCookieDetails);
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest, HandleRemoveAll);
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest, HandleRemoveItem);
-  FRIEND_TEST_ALL_PREFIXES(CookiesViewHandlerTest, HandleRemoveSite);
-
-  // Recreates the CookiesTreeModel and resets the current |filter_|.
-  void RecreateCookiesTreeModel();
-
-  // Set |filter_| and get a portion (or all) of the list items.
-  void HandleGetDisplayList(const base::Value::List& args);
-  void GetDisplayList(std::string callback_id, const std::u16string& filter);
-
-  // Remove all items matching the current |filter_|.
-  void HandleRemoveShownItems(const base::Value::List& args);
-  void RemoveShownItems();
-
-  // Remove selected sites data.
-  void HandleRemoveSite(const base::Value::List& args);
-  void RemoveSite(const std::u16string& site);
-
-  // Retrieve cookie details for a specific site.
-  void HandleGetCookieDetails(const base::Value::List& args);
-  void GetCookieDetails(const std::string& callback_id,
-                        const std::string& site);
-
-  // Gets a plural string for the given number of cookies.
-  void HandleGetNumCookiesString(const base::Value::List& args);
-
-  // Remove all sites data.
-  void HandleRemoveAll(const base::Value::List& args);
-  void RemoveAll(const std::string& callback_id);
-
-  // Remove a single item.
-  void HandleRemoveItem(const base::Value::List& args);
-  void RemoveItem(const std::string& path);
-
-  // Removes cookies and site data available in third-party contexts.
-  void HandleRemoveThirdParty(const base::Value::List& args);
-
-  void ReturnLocalDataList(const std::string& callback_id);
-
-  // Reloads the CookiesTreeModel and passes the nodes to
-  // 'CookiesView.loadChildren' to update the WebUI.
-  void HandleReloadCookies(const base::Value::List& args);
-
-  // Flag to indicate whether there is a batch update in progress.
-  bool batch_update_;
-
-  // The Cookies Tree model
-  std::unique_ptr<CookiesTreeModel> cookies_tree_model_;
-
-  // Cookies tree model which can be set for testing and will be used instead
-  // of creating one directly from the profile.
-  std::unique_ptr<CookiesTreeModel> cookies_tree_model_for_testing_;
-
-  // Only show items that contain |filter|.
-  std::u16string filter_;
-
-  struct Request {
-    // Specifies the batch behavior of the tree model when this request is run
-    // against it. Batch behavior must be constant across invocations, and
-    // defines when tasks can be queued.
-    enum TreeModelBatchBehavior {
-      // The request will not cause a batch operation to be started. Tasks may
-      // only be queued when the request is first processed.
-      NO_BATCH,
-
-      // The request will cause a batch to start and finish syncronously. Tasks
-      // may only be queued when the request is first processed.
-      SYNC_BATCH,
-
-      // The request will cause an asynchronous batch update to be run. Both
-      // batch end and begin may occur asynchronously. Tasks may be queued when
-      // the request is first processed, and when the batch is finished.
-      ASYNC_BATCH
-    };
-
-    // Creates a request with a task to be queued when the request is first
-    // processed.
-    Request(TreeModelBatchBehavior batch_behavior,
-            base::OnceClosure initial_task);
-
-    // Creates a request with both a task to be queued when processed, and a
-    // task to be queued when the tree model batch finishes. This constructor
-    // implies |batch_behavior| == ASYNC_BATCH.
-    Request(base::OnceClosure initial_task, base::OnceClosure batch_end_task);
-
-    ~Request();
-    Request(const Request&) = delete;
-    Request(Request&& other);
-    Request& operator=(const Request&&) = delete;
-
-    TreeModelBatchBehavior batch_behavior;
-
-    // Task which is run when the request reaches the front of the queue.
-    // Task must only interact with the tree model in a synchronous manner.
-    base::OnceClosure initial_task;
-
-    // Optional task which is queued to run when the tree model batch ends.
-    // Only valid when |batch_behavior| == ASYNC_BATCH. Must only interact with
-    // the tree model in a synchronous manner.
-    base::OnceClosure batch_end_task;
-  };
-
-  // The current client requests.
-  std::queue<Request> pending_requests_;
-  bool request_in_progress_ = false;
-
-  // Check the request queue and process the first request if approproiate.
-  void ProcessPendingRequests();
-
-  // Signal that the request at the head of the request queue is complete.
-  void RequestComplete();
-
-  // Sorted index list, by site. Indexes refer to |model->GetRoot()| children.
-  typedef std::pair<std::u16string, size_t> LabelAndIndex;
-  std::vector<LabelAndIndex> sorted_sites_;
-
-  std::unique_ptr<CookiesTreeModelUtil> model_util_;
-
-  // Used to cancel callbacks when JavaScript becomes disallowed.
-  base::WeakPtrFactory<CookiesViewHandler> callback_weak_ptr_factory_{this};
-};
-
-}  // namespace settings
-
-#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_SETTINGS_COOKIES_VIEW_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/settings_cookies_view_handler_unittest.cc b/chrome/browser/ui/webui/settings/settings_cookies_view_handler_unittest.cc
deleted file mode 100644
index 03da5be..0000000
--- a/chrome/browser/ui/webui/settings/settings_cookies_view_handler_unittest.cc
+++ /dev/null
@@ -1,521 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/settings/settings_cookies_view_handler.h"
-
-#include <memory>
-#include <string>
-
-#include "base/test/bind.h"
-#include "base/values.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "components/browsing_data/content/mock_cookie_helper.h"
-#include "components/browsing_data/content/mock_local_storage_helper.h"
-#include "content/public/test/test_web_ui.h"
-#include "third_party/blink/public/common/storage_key/storage_key.h"
-
-namespace {
-
-constexpr char kCallbackId[] = "test-callback-id";
-constexpr char kTestOrigin1[] = "https://a-example.com";
-constexpr char kTestOrigin2[] = "https://b-example.com";
-constexpr char kTestHost1[] = "a-example.com";
-constexpr char kTestHost2[] = "b-example.com";
-constexpr char kTestCookie1[] = "A=1";
-constexpr char kTestCookie2[] = "B=1";
-
-}  // namespace
-
-namespace settings {
-
-class CookiesViewHandlerTest : public ChromeRenderViewHostTestHarness {
- public:
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-
-    web_ui_ = std::make_unique<content::TestWebUI>();
-    web_ui_->set_web_contents(web_contents());
-    handler_ = std::make_unique<CookiesViewHandler>();
-    handler_->set_web_ui(web_ui());
-    web_ui_->ClearTrackedCalls();
-  }
-
-  void TearDown() override {
-    handler_->set_web_ui(nullptr);
-    handler_.reset();
-    web_ui_.reset();
-
-    ChromeRenderViewHostTestHarness::TearDown();
-  }
-
-  void SetupTreeModelForTesting() {
-    mock_browsing_data_cookie_helper =
-        base::MakeRefCounted<browsing_data::MockCookieHelper>(profile());
-    mock_browsing_data_local_storage_helper =
-        base::MakeRefCounted<browsing_data::MockLocalStorageHelper>(profile());
-
-    auto container = std::make_unique<LocalDataContainer>(
-        mock_browsing_data_cookie_helper,
-        /*database_helper=*/nullptr, mock_browsing_data_local_storage_helper,
-        /*session_storage_helper=*/nullptr,
-        /*indexed_db_helper=*/nullptr,
-        /*file_system_helper=*/nullptr,
-        /*quota_helper=*/nullptr,
-        /*service_worker_helper=*/nullptr,
-        /*data_shared_worker_helper=*/nullptr,
-        /*cache_storage_helper=*/nullptr);
-    auto mock_cookies_tree_model = std::make_unique<CookiesTreeModel>(
-        std::move(container), profile()->GetExtensionSpecialStoragePolicy());
-
-    mock_browsing_data_local_storage_helper->AddLocalStorageForStorageKey(
-        blink::StorageKey::CreateFromStringForTesting(kTestOrigin1), 2);
-    mock_browsing_data_local_storage_helper->AddLocalStorageForStorageKey(
-        blink::StorageKey::CreateFromStringForTesting(kTestOrigin2), 3);
-
-    mock_browsing_data_cookie_helper->AddCookieSamples(GURL(kTestOrigin1),
-                                                       kTestCookie1);
-    mock_browsing_data_cookie_helper->AddCookieSamples(GURL(kTestOrigin2),
-                                                       kTestCookie2);
-
-    handler()->SetCookiesTreeModelForTesting(
-        std::move(mock_cookies_tree_model));
-  }
-
-  void NotifyTreeModel() {
-    mock_browsing_data_local_storage_helper->Notify();
-    mock_browsing_data_cookie_helper->Notify();
-  }
-
-  void SetupHandlerWithTreeModel() {
-    SetupTreeModelForTesting();
-    base::Value reload_args(base::Value::Type::LIST);
-    reload_args.Append(kCallbackId);
-    handler()->HandleReloadCookies(reload_args.GetList());
-
-    // The handler will post a task to recreate the tree model.
-    task_environment()->RunUntilIdle();
-    NotifyTreeModel();
-
-    // After batch end, the handler will have posted a task to complete
-    // the callback.
-    task_environment()->RunUntilIdle();
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIResponse", data.function_name());
-    EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-    ASSERT_TRUE(data.arg2()->GetBool());
-
-    web_ui_->ClearTrackedCalls();
-  }
-
-  content::TestWebUI* web_ui() { return web_ui_.get(); }
-  CookiesViewHandler* handler() { return handler_.get(); }
-
- private:
-  std::unique_ptr<content::TestWebUI> web_ui_;
-  std::unique_ptr<CookiesViewHandler> handler_;
-
-  // Ref pointers to storage helpers used in the tree model used for testing.
-  // Retained to allow control over batch update completion.
-  scoped_refptr<browsing_data::MockLocalStorageHelper>
-      mock_browsing_data_local_storage_helper;
-  scoped_refptr<browsing_data::MockCookieHelper>
-      mock_browsing_data_cookie_helper;
-};
-
-TEST_F(CookiesViewHandlerTest, SingleRequestDuringBatch) {
-  // Ensure that multiple requests do not run while a tree model batch process
-  // is running.
-  SetupTreeModelForTesting();
-
-  constexpr char kReloadCallbackID[] = "reload-cookies-callback";
-  constexpr char kGetDisplaylistCallbackID[] = "get-display-list-callback";
-
-  base::Value reload_args(base::Value::Type::LIST);
-  reload_args.Append(kReloadCallbackID);
-  handler()->HandleReloadCookies(reload_args.GetList());
-  task_environment()->RunUntilIdle();
-
-  // At the point the handler will have recreated the model (using the provided
-  // test model) and will be awaiting batch end. Performing another request
-  // should result in it not being satisfied, and instead being queued.
-  base::Value get_display_list_args(base::Value::Type::LIST);
-  get_display_list_args.Append(kGetDisplaylistCallbackID);
-  get_display_list_args.Append("");
-  handler()->HandleGetDisplayList(get_display_list_args.GetList());
-  task_environment()->RunUntilIdle();
-
-  // Because the tree model hasn't completed the batch, no callback should
-  // have been completed.
-  EXPECT_EQ(0U, web_ui()->call_data().size());
-
-  // Completing the tree model batch should result in both callbacks being
-  // completed in the correct order.
-  NotifyTreeModel();
-  task_environment()->RunUntilIdle();
-  EXPECT_EQ(2U, web_ui()->call_data().size());
-
-  const content::TestWebUI::CallData& reload_response =
-      *web_ui()->call_data().front();
-  EXPECT_EQ("cr.webUIResponse", reload_response.function_name());
-  EXPECT_EQ(kReloadCallbackID, reload_response.arg1()->GetString());
-  ASSERT_TRUE(reload_response.arg2()->GetBool());
-
-  const content::TestWebUI::CallData& get_display_list_response =
-      *web_ui()->call_data().back();
-  EXPECT_EQ("cr.webUIResponse", get_display_list_response.function_name());
-  EXPECT_EQ(kGetDisplaylistCallbackID,
-            get_display_list_response.arg1()->GetString());
-  ASSERT_TRUE(get_display_list_response.arg2()->GetBool());
-  const base::Value::List& local_data_list =
-      get_display_list_response.arg3()->GetList();
-  ASSERT_EQ(2U, local_data_list.size());
-  EXPECT_EQ(kTestHost1, local_data_list[0].FindKey("site")->GetString());
-  EXPECT_EQ(kTestHost2, local_data_list[1].FindKey("site")->GetString());
-}
-
-TEST_F(CookiesViewHandlerTest, NoStarvation) {
-  SetupHandlerWithTreeModel();
-
-  // Confirm that the request queue does not starve during various combinations
-  // of requests. This is achieved by queueing numerous permutations of requests
-  // which have different interaction properties with the tree model.
-  std::string current_filter = kTestHost1;
-  auto get_display_list_new_filter =
-      base::BindLambdaForTesting([&](std::string callback_id) {
-        base::Value args(base::Value::Type::LIST);
-        args.Append(callback_id);
-        current_filter = current_filter == kTestHost1 ? "" : kTestHost1;
-        args.Append(kTestHost1);
-        handler()->HandleGetDisplayList(args.GetList());
-      });
-  auto get_display_list_same_filter =
-      base::BindLambdaForTesting([&](std::string callback_id) {
-        base::Value args(base::Value::Type::LIST);
-        args.Append(callback_id);
-        args.Append(current_filter);
-        handler()->HandleGetDisplayList(args.GetList());
-      });
-  auto get_cookie_details =
-      base::BindLambdaForTesting([&](std::string callback_id) {
-        base::Value args(base::Value::Type::LIST);
-        args.Append(callback_id);
-        args.Append(kTestHost1);
-        handler()->HandleGetCookieDetails(args.GetList());
-      });
-  auto reload_cookies =
-      base::BindLambdaForTesting([&](std::string callback_id) {
-        base::Value args(base::Value::Type::LIST);
-        args.Append(callback_id);
-        handler()->HandleReloadCookies(args.GetList());
-      });
-  auto remove_third_party =
-      base::BindLambdaForTesting([&](std::string callback_id) {
-        base::Value args(base::Value::Type::LIST);
-        args.Append(callback_id);
-        handler()->HandleRemoveThirdParty(args.GetList());
-      });
-  // Include a dummy request which allows the request queue to be cleared. This
-  // ensures that requests may be queued up both during, and outside of, batch
-  // updates.
-  auto process_pending_requests = base::BindLambdaForTesting(
-      [&](std::string callback_id) { task_environment()->RunUntilIdle(); });
-
-  // For completeness, test every permutation of these calls.
-  std::vector<std::pair<int, base::RepeatingCallback<void(std::string)>>>
-      request_functions = {
-          {1, get_display_list_new_filter}, {2, get_display_list_same_filter},
-          {3, get_cookie_details},          {4, reload_cookies},
-          {5, remove_third_party},          {6, process_pending_requests},
-      };
-  auto request_function_ordering =
-      [](const std::pair<int, base::RepeatingCallback<void(std::string)>>& left,
-         std::pair<int, base::RepeatingCallback<void(std::string)>>& right) {
-        return left.first < right.first;
-      };
-  std::sort(request_functions.begin(), request_functions.end(),
-            request_function_ordering);
-
-  size_t expected_response_count = 0;
-  do {
-    for (const auto& function : request_functions) {
-      // Provide a unique callback ID for each request.
-      function.second.Run(
-          std::string(kCallbackId)
-              .append(base::NumberToString(expected_response_count)));
-
-      if (function.second != process_pending_requests)
-        expected_response_count++;
-    }
-  } while (std::next_permutation(request_functions.begin(),
-                                 request_functions.end(),
-                                 request_function_ordering));
-
-  task_environment()->RunUntilIdle();
-
-  // Ensure that callbacks have been fulfilled in the order they were queued.
-  ASSERT_EQ(expected_response_count, web_ui()->call_data().size());
-  for (size_t i = 0; i < expected_response_count; i++) {
-    EXPECT_EQ(std::string(kCallbackId).append(base::NumberToString(i)),
-              web_ui()->call_data()[i]->arg1()->GetString());
-  }
-}
-
-TEST_F(CookiesViewHandlerTest, ImmediateTreeOperation) {
-  // Check that a query which assumes a tree model to have been created
-  // previously results in a tree being created before the request is handled.
-  SetupTreeModelForTesting();
-
-  base::Value args(base::Value::Type::LIST);
-  args.Append(kCallbackId);
-  args.Append(kTestHost1);
-  handler()->HandleGetCookieDetails(args.GetList());
-  task_environment()->RunUntilIdle();
-
-  // At this point the handler should have queued the creation of a tree and
-  // be awaiting batch completion.
-  NotifyTreeModel();
-  task_environment()->RunUntilIdle();
-
-  // Check that the returned information is accurate, despite not having
-  // previously loaded the tree.
-  const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-  EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-  EXPECT_EQ("cr.webUIResponse", data.function_name());
-  ASSERT_TRUE(data.arg2()->GetBool());
-
-  const base::Value::List& cookies_list = data.arg3()->GetList();
-  ASSERT_EQ(2UL, cookies_list.size());
-  EXPECT_EQ("cookie", cookies_list[0].FindKey("type")->GetString());
-  EXPECT_EQ("local_storage", cookies_list[1].FindKey("type")->GetString());
-}
-
-TEST_F(CookiesViewHandlerTest, HandleGetDisplayList) {
-  // Ensure that getting the display list works appropriately.
-  SetupHandlerWithTreeModel();
-
-  // Retrieve a filtered list.
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kCallbackId);
-    args.Append(kTestHost1);
-
-    handler()->HandleGetDisplayList(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIResponse", data.function_name());
-    EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-    ASSERT_TRUE(data.arg2()->GetBool());
-    const base::Value::List& local_data_list = data.arg3()->GetList();
-    ASSERT_EQ(1U, local_data_list.size());
-    EXPECT_EQ(kTestHost1, local_data_list[0].FindKey("site")->GetString());
-  }
-
-  // Remove the filter and confirm the full list is returned.
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kCallbackId);
-    args.Append("");
-
-    handler()->HandleGetDisplayList(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIResponse", data.function_name());
-    EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-    ASSERT_TRUE(data.arg2()->GetBool());
-    const base::Value::List& local_data_list = data.arg3()->GetList();
-    ASSERT_EQ(2U, local_data_list.size());
-    EXPECT_EQ(kTestHost1, local_data_list[0].FindKey("site")->GetString());
-    EXPECT_EQ(kTestHost2, local_data_list[1].FindKey("site")->GetString());
-  }
-}
-
-TEST_F(CookiesViewHandlerTest, HandleRemoveShownItems) {
-  // Ensure that removing shown items only removes items appropriate for the
-  // current filter.
-  SetupHandlerWithTreeModel();
-
-  // Apply a filter to the list and confirm it is returned.
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kCallbackId);
-    args.Append(kTestHost2);
-    handler()->HandleGetDisplayList(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIResponse", data.function_name());
-    EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-    ASSERT_TRUE(data.arg2()->GetBool());
-    const base::Value::List& local_data_list = data.arg3()->GetList();
-    ASSERT_EQ(1U, local_data_list.size());
-    EXPECT_EQ(kTestHost2, local_data_list[0].FindKey("site")->GetString());
-  }
-
-  // Remove displayed items.
-  {
-    base::Value args(base::Value::Type::LIST);
-    handler()->HandleRemoveShownItems(args.GetList());
-    task_environment()->RunUntilIdle();
-  }
-
-  // Remove the filter and confirm unremoved items are returned.
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kCallbackId);
-    args.Append("");
-    handler()->HandleGetDisplayList(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIResponse", data.function_name());
-    EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-    ASSERT_TRUE(data.arg2()->GetBool());
-    const base::Value::List& local_data_list = data.arg3()->GetList();
-    ASSERT_EQ(1U, local_data_list.size());
-    EXPECT_EQ(kTestHost1, local_data_list[0].FindKey("site")->GetString());
-  }
-}
-
-TEST_F(CookiesViewHandlerTest, HandleGetCookieDetails) {
-  // Ensure that the cookie details are correctly returned for a site.
-  SetupHandlerWithTreeModel();
-  base::Value args(base::Value::Type::LIST);
-  args.Append(kCallbackId);
-  args.Append(kTestHost1);
-  handler()->HandleGetCookieDetails(args.GetList());
-  task_environment()->RunUntilIdle();
-
-  const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-  EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-  EXPECT_EQ("cr.webUIResponse", data.function_name());
-  ASSERT_TRUE(data.arg2()->GetBool());
-
-  const base::Value::List& cookies_list = data.arg3()->GetList();
-  ASSERT_EQ(2UL, cookies_list.size());
-  EXPECT_EQ("cookie", cookies_list[0].FindKey("type")->GetString());
-  EXPECT_EQ("local_storage", cookies_list[1].FindKey("type")->GetString());
-}
-
-TEST_F(CookiesViewHandlerTest, HandleRemoveAll) {
-  // Ensure that RemoveAll removes all cookies & storage.
-  SetupHandlerWithTreeModel();
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kCallbackId);
-    handler()->HandleRemoveAll(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-    EXPECT_EQ("cr.webUIResponse", data.function_name());
-    ASSERT_TRUE(data.arg2()->GetBool());
-  }
-
-  // Ensure returned display list is empty.
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kCallbackId);
-    args.Append("");
-    handler()->HandleGetDisplayList(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIResponse", data.function_name());
-    EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-    ASSERT_TRUE(data.arg2()->GetBool());
-    const base::Value::List& local_data_list = data.arg3()->GetList();
-    ASSERT_EQ(0U, local_data_list.size());
-  }
-}
-
-TEST_F(CookiesViewHandlerTest, HandleRemoveItem) {
-  // Delete an individual piece of site data. This requires first getting the
-  // node path ID via the HandleGetCookieDetails function.
-  SetupHandlerWithTreeModel();
-
-  // Get the appropriate path for removal.
-  std::string node_path_id;
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kCallbackId);
-    args.Append(kTestHost1);
-    handler()->HandleGetCookieDetails(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    const base::Value::List& cookies_list = data.arg3()->GetList();
-    ASSERT_EQ(2UL, cookies_list.size());
-    // Find the entry item associated with the kTestCookie1 cookie.
-    for (const auto& cookie : cookies_list) {
-      if (cookie.FindKey("type")->GetString() == "cookie")
-        node_path_id = cookie.FindKey("idPath")->GetString();
-    }
-  }
-
-  // Remove path and ensure that the removed item listener fires.
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(node_path_id);
-    handler()->HandleRemoveItem(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    // Removal should fire an update event.
-    const content::TestWebUI::CallData& all_data =
-        *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIListenerCallback", all_data.function_name());
-    EXPECT_EQ("on-tree-item-removed", all_data.arg1()->GetString());
-  }
-
-  // Ensure that the removed item is no longer present in cookie details.
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kCallbackId);
-    args.Append(kTestHost1);
-    handler()->HandleGetCookieDetails(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    const base::Value::List& cookies_list = data.arg3()->GetList();
-    ASSERT_EQ(1UL, cookies_list.size());
-    EXPECT_EQ("local_storage", cookies_list[0].FindKey("type")->GetString());
-  }
-}
-
-TEST_F(CookiesViewHandlerTest, HandleRemoveSite) {
-  SetupHandlerWithTreeModel();
-
-  // Check that removing a single site works.
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kTestHost1);
-    handler()->HandleRemoveSite(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    // Removal should fire an update event.
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIListenerCallback", data.function_name());
-    EXPECT_EQ("on-tree-item-removed", data.arg1()->GetString());
-  }
-
-  // Check that the removed site is no longer present in the display list.
-  {
-    base::Value args(base::Value::Type::LIST);
-    args.Append(kCallbackId);
-    args.Append("");
-    handler()->HandleGetDisplayList(args.GetList());
-    task_environment()->RunUntilIdle();
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIResponse", data.function_name());
-    EXPECT_EQ(kCallbackId, data.arg1()->GetString());
-    ASSERT_TRUE(data.arg2()->GetBool());
-    const base::Value::List& local_data_list = data.arg3()->GetList();
-    ASSERT_EQ(1U, local_data_list.size());
-    EXPECT_EQ(kTestHost2, local_data_list[0].FindKey("site")->GetString());
-  }
-}
-
-}  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 02ef370..5c53907 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -248,10 +248,10 @@
      IDS_SETTINGS_SLIDER_MIN_MAX_ARIA_ROLE_DESCRIPTION},
     {"caretBrowsingTitle", IDS_SETTINGS_ENABLE_CARET_BROWSING_TITLE},
     {"caretBrowsingSubtitle", IDS_SETTINGS_ENABLE_CARET_BROWSING_SUBTITLE},
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
     {"manageAccessibilityFeatures",
      IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES},
-#else  // !BUILDFLAG(IS_CHROMEOS_ASH)
+#else  // !BUILDFLAG(IS_CHROMEOS)
     {"focusHighlightLabel",
      IDS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION},
 #endif
@@ -1660,16 +1660,6 @@
   html_source->AddBoolean(
       "driveSuggestAvailable",
       base::FeatureList::IsEnabled(omnibox::kDocumentProvider));
-  html_source->AddBoolean(
-      "consolidatedSiteStorageControlsEnabled",
-      base::FeatureList::IsEnabled(
-          features::kConsolidatedSiteStorageControls) ||
-          // The third release of Privacy Sandbox settings depends on the
-          // simplified control structure. Ideally simplified controls will
-          // launch to 100% in advance of the Privacy Sandbox, but the Sandbox
-          // cannot launch without this simplification enabled.
-          base::FeatureList::IsEnabled(
-              privacy_sandbox::kPrivacySandboxSettings3));
 
   bool show_secure_dns = IsSecureDnsAvailable();
   bool link_secure_dns = ShouldLinkSecureDnsOsSettings();
@@ -2474,33 +2464,10 @@
     {"siteSettingsSourceKillSwitch",
      IDS_SETTINGS_SITE_SETTINGS_SOURCE_KILL_SWITCH},
     {"siteSettingsReset", IDS_SETTINGS_SITE_SETTINGS_RESET_BUTTON},
-    {"siteSettingsCookieHeader", IDS_SETTINGS_SITE_SETTINGS_COOKIE_HEADER},
-    {"siteSettingsCookieLink", IDS_SETTINGS_SITE_SETTINGS_COOKIE_LINK},
-    {"siteSettingsCookieRemove", IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE},
-    {"siteSettingsCookieRemoveAll",
-     IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_ALL},
-    {"siteSettingsCookieRemoveAllShown",
-     IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_ALL_SHOWN},
-    {"siteSettingsCookieRemoveAllThirdParty",
-     IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_ALL_THIRD_PARTY},
-    {"siteSettingsCookieRemoveThirdPartyDialogTitle",
-     IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIE_REMOVE_DIALOG_TITLE},
-    {"siteSettingsCookieRemoveThirdPartyConfirmation",
-     IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIE_REMOVE_CONFIRMATION},
-    {"siteSettingsCookiesClearThirdParty",
-     IDS_SETTINGS_SITE_SETTINGS_CLEAR_THIRD_PARTY_COOKIES},
     {"siteSettingsCookiesThirdPartyExceptionLabel",
      IDS_SETTINGS_SITE_SETTINGS_THIRD_PARTY_COOKIES_EXCEPTION_LABEL},
-    {"siteSettingsCookieRemoveDialogTitle",
-     IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_DIALOG_TITLE},
-    {"siteSettingsCookieRemoveMultipleConfirmation",
-     IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_MULTIPLE},
     {"siteSettingsCookieRemoveSite",
      IDS_SETTINGS_SITE_SETTINGS_COOKIE_REMOVE_SITE},
-    {"siteSettingsCookiesClearAll",
-     IDS_SETTINGS_SITE_SETTINGS_COOKIES_CLEAR_ALL},
-    {"siteSettingsCookieSearch", IDS_SETTINGS_SITE_SETTINGS_COOKIE_SEARCH},
-    {"siteSettingsCookieSubpage", IDS_SETTINGS_SITE_SETTINGS_COOKIE_SUBPAGE},
     {"siteSettingsDelete", IDS_SETTINGS_SITE_SETTINGS_DELETE},
     {"siteSettingsClearAllStorageDialogTitle",
      IDS_SETTINGS_SITE_SETTINGS_CLEAR_ALL_STORAGE_DIALOG_TITLE},
@@ -2536,10 +2503,6 @@
      IDS_SETTINGS_SITE_SETTINGS_FIRST_PARTY_SETS_SHOW_RELATED_SITES_BUTTON},
     {"firstPartySetsSiteClearStorageButton",
      IDS_SETTINGS_SITE_SETTINGS_FIRST_PARTY_SETS_SITE_CLEAR_STORAGE_BUTTON},
-    {"siteSettingsOriginDeleteConfirmation",
-     IDS_SETTINGS_SITE_SETTINGS_ORIGIN_DELETE_CONFIRMATION},
-    {"siteSettingsOriginDeleteConfirmationInstalled",
-     IDS_SETTINGS_SITE_SETTINGS_ORIGIN_DELETE_CONFIRMATION_INSTALLED},
     {"siteSettingsSiteGroupDeleteConfirmationInstalledPlural",
      IDS_SETTINGS_SITE_SETTINGS_SITE_GROUP_DELETE_CONFIRMATION_INSTALLED_PLURAL},
     {"siteSettingsSiteClearStorage",
@@ -2963,11 +2926,6 @@
       cmd.HasSwitch(::switches::kEnableExperimentalWebPlatformFeatures));
 
   html_source->AddBoolean(
-      "enableRemovingAllThirdPartyCookies",
-      base::FeatureList::IsEnabled(
-          browsing_data::features::kEnableRemovingAllThirdPartyCookies));
-
-  html_source->AddBoolean(
       "enableQuietNotificationPromptsSetting",
       base::FeatureList::IsEnabled(features::kQuietNotificationPrompts));
 
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index fb00ddeb..cfc4b783 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -53,7 +53,6 @@
 #include "chrome/browser/ui/webui/settings/safety_check_handler.h"
 #include "chrome/browser/ui/webui/settings/search_engines_handler.h"
 #include "chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h"
-#include "chrome/browser/ui/webui/settings/settings_cookies_view_handler.h"
 #include "chrome/browser/ui/webui/settings/settings_localized_strings_provider.h"
 #include "chrome/browser/ui/webui/settings/settings_media_devices_selection_handler.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
@@ -207,7 +206,6 @@
   AddSettingsPageUIHandler(
       std::make_unique<ClearBrowsingDataHandler>(web_ui, profile));
   AddSettingsPageUIHandler(std::make_unique<SafetyCheckHandler>());
-  AddSettingsPageUIHandler(std::make_unique<CookiesViewHandler>());
   AddSettingsPageUIHandler(std::make_unique<DownloadsHandler>(profile));
   AddSettingsPageUIHandler(std::make_unique<ExtensionControlHandler>());
   AddSettingsPageUIHandler(std::make_unique<FontHandler>(profile));
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc
index 4f917d86..9a286b6 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -762,6 +762,10 @@
       "recordAction",
       base::BindRepeating(&SiteSettingsHandler::HandleRecordAction,
                           base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "getNumCookiesString",
+      base::BindRepeating(&SiteSettingsHandler::HandleGetNumCookiesString,
+                          base::Unretained(this)));
 }
 
 void SiteSettingsHandler::OnJavascriptAllowed() {
@@ -2113,6 +2117,22 @@
   LogAllSitesAction(static_cast<AllSitesAction2>(action));
 }
 
+void SiteSettingsHandler::HandleGetNumCookiesString(
+    const base::Value::List& args) {
+  CHECK_EQ(2U, args.size());
+  std::string callback_id;
+  callback_id = args[0].GetString();
+  int num_cookies = args[1].GetInt();
+
+  AllowJavascript();
+  const std::u16string string =
+      num_cookies > 0 ? l10n_util::GetPluralStringFUTF16(
+                            IDS_SETTINGS_SITE_SETTINGS_NUM_COOKIES, num_cookies)
+                      : std::u16string();
+
+  ResolveJavascriptCallback(base::Value(callback_id), base::Value(string));
+}
+
 void SiteSettingsHandler::RemoveNonTreeModelData(
     const std::vector<url::Origin>& origins) {
   // TODO(crbug.com/1268626): Remove client hint information, which cannot be
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.h b/chrome/browser/ui/webui/settings/site_settings_handler.h
index 8e613538..58da77b 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.h
@@ -320,6 +320,9 @@
   // Record metrics for actions on All Sites Page.
   void HandleRecordAction(const base::Value::List& args);
 
+  // Gets a plural string for the given number of cookies.
+  void HandleGetNumCookiesString(const base::Value::List& args);
+
   // Provides an opportunity for site data which is not integrated into the
   // tree model to be removed when entries for |origins| are removed.
   // TODO(crbug.com/1271155): This function is a temporary hack while the
diff --git a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc
index cf364e0..9984e146 100644
--- a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc
+++ b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/commerce/shopping_service_factory.h"
+#include "chrome/browser/feature_engagement/tracker_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/webui/favicon_source.h"
@@ -124,7 +125,9 @@
       BookmarkModelFactory::GetForBrowserContext(profile);
   commerce::ShoppingService* shopping_service =
       commerce::ShoppingServiceFactory::GetForBrowserContext(profile);
+  feature_engagement::Tracker* const tracker =
+      feature_engagement::TrackerFactory::GetForBrowserContext(profile);
   shopping_list_handler_ = std::make_unique<commerce::ShoppingListHandler>(
       std::move(page), std::move(receiver), bookmark_model, shopping_service,
-      g_browser_process->GetApplicationLocale());
+      profile->GetPrefs(), tracker, g_browser_process->GetApplicationLocale());
 }
diff --git a/chrome/browser/ui/webui/side_panel/reading_list/reading_list_ui.cc b/chrome/browser/ui/webui/side_panel/reading_list/reading_list_ui.cc
index 6d000f8d..b6ab8a7 100644
--- a/chrome/browser/ui/webui/side_panel/reading_list/reading_list_ui.cc
+++ b/chrome/browser/ui/webui/side_panel/reading_list/reading_list_ui.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/commerce/shopping_service_factory.h"
+#include "chrome/browser/feature_engagement/tracker_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/read_later/reading_list_model_factory.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -170,9 +171,11 @@
       BookmarkModelFactory::GetForBrowserContext(profile);
   commerce::ShoppingService* shopping_service =
       commerce::ShoppingServiceFactory::GetForBrowserContext(profile);
+  feature_engagement::Tracker* const tracker =
+      feature_engagement::TrackerFactory::GetForBrowserContext(profile);
   shopping_list_handler_ = std::make_unique<commerce::ShoppingListHandler>(
       std::move(page), std::move(receiver), bookmark_model, shopping_service,
-      g_browser_process->GetApplicationLocale());
+      profile->GetPrefs(), tracker, g_browser_process->GetApplicationLocale());
 }
 
 void ReadingListUI::SetActiveTabURL(const GURL& url) {
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_service_unittest.cc b/chrome/browser/updates/announcement_notification/announcement_notification_service_unittest.cc
index 2203c7c6..a4cb7a4 100644
--- a/chrome/browser/updates/announcement_notification/announcement_notification_service_unittest.cc
+++ b/chrome/browser/updates/announcement_notification/announcement_notification_service_unittest.cc
@@ -102,8 +102,7 @@
             int current_version,
             bool new_profile,
             bool guest_profile = false) {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     std::vector<base::test::FeatureRef> disabled_features;
     if (enable_feature)
       enabled_features.emplace_back(kAnnouncementNotification, parameters);
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index d90e984..d95b0c5 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -1097,29 +1097,23 @@
       !is_get_assertion && kShowCreatePlatformPasskeyStep &&
       base::FeatureList::IsEnabled(
           device::kWebAuthnNewDiscoverableCredentialsUi);
-
-  // Advance to the platform authenticator for:
-  // - getAssertion requests with a matching platform credential
-  // - makeCredential requests with attachment=platform
   if (base::Contains(transport_availability_.available_transports,
                      AuthenticatorTransport::kInternal) &&
       (transport_availability_.has_platform_authenticator_credential ==
            device::FidoRequestHandlerBase::RecognizedCredential::
                kHasRecognizedCredential ||
-       (show_create_passkey_step &&
-        transport_availability_.available_transports.size() == 1)) &&
+       show_create_passkey_step) &&
       !use_conditional_mediation_) {
     priority_transport = AuthenticatorTransport::kInternal;
   }
 
-  std::vector<AuthenticatorTransport> transports_to_list_if_active = {
-      AuthenticatorTransport::kUsbHumanInterfaceDevice,
-  };
-
+  std::vector<AuthenticatorTransport> transports_to_list_if_active;
   if (!use_conditional_mediation_) {
     // Conditional requests offer platform credentials through the autofill UI.
     transports_to_list_if_active.push_back(AuthenticatorTransport::kInternal);
   }
+  transports_to_list_if_active.push_back(
+      AuthenticatorTransport::kUsbHumanInterfaceDevice);
 
   const auto kCable = AuthenticatorTransport::kHybrid;
   bool include_add_phone_option = false;
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
index 463f6dc..625f092 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
@@ -204,26 +204,26 @@
       {mc, {usb}, {}, {}, {t(usb)}, usb_ui},
       {ga, {usb}, {}, {}, {t(usb)}, usb_ui},
       // ... otherwise should the selection sheet.
-      {mc, {usb, internal}, {}, {}, {t(usb), t(internal)}, mss},
-      {ga, {usb, internal}, {}, {}, {t(usb), t(internal)}, mss},
+      {ga, {usb, cable}, {}, {}, {t(usb), add}, mss},
+      {ga, {usb, cable}, {}, {}, {t(usb), add}, mss},
 
       // If the platform authenticator has a credential it should activate.
-      {ga, {usb, internal}, {has_plat}, {}, {t(usb), t(internal)}, plat_ui},
+      {ga, {usb, internal}, {has_plat}, {}, {t(internal), t(usb)}, plat_ui},
       // ... but with an empty allow list the user should be prompted first.
       {ga,
        {usb, internal},
        {has_plat, one_cred, empty_al},
        {},
-       {t(usb), t(internal)},
+       {t(internal), t(usb)},
        use_pk},
       {ga,
        {usb, internal},
        {has_plat, two_cred, empty_al},
        {},
-       {t(usb), t(internal)},
+       {t(internal), t(usb)},
        use_pk_multi},
 
-      // MakeCredential with attachmemt=platform shows the 'Create a passkey'
+      // MakeCredential with attachment=platform shows the 'Create a passkey'
       // step, but only on macOS. On other OSes, we defer to the platform.
       {mc,
        {internal},
@@ -236,6 +236,19 @@
        plat_ui
 #endif
       },
+      // MakeCredential with attachment=undefined also shows the 'Create a
+      // passkey' step on macOS. On other OSes, we show mechanism selection.
+      {mc,
+       {usb, internal},
+       {},
+       {},
+       {t(internal), t(usb)},
+#if BUILDFLAG(IS_MAC)
+       create_pk
+#else
+       mss
+#endif
+      },
 
       // If the Windows API is available without caBLE, it should activate.
       {mc, {}, {has_winapi}, {}, {winapi}, plat_ui},
@@ -581,6 +594,7 @@
     model.AddObserver(&mock_observer);
 
     TransportAvailabilityInfo transports_info;
+    transports_info.request_type = RequestType::kGetAssertion;
     transports_info.available_transports = kAllTransportsWithoutCable;
 
     EXPECT_CALL(mock_observer, OnStepTransition());
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index e3047fa..ca761725 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1665662309-72384622bbc28aa805a0f32ea5f726752a1477da.profdata
+chrome-linux-main-1665683972-b231a6000fbf697649d58a61ced2a6cbf9b323c8.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 83f3bf3..18fd987 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1665662309-d25866d9028bf5edbbedf62c0529178ab0686317.profdata
+chrome-mac-main-1665683972-8472583865427d6bd4b39786257e09c0986f9fcc.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 19233be..f02b642 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1665662309-6d7c4f76cce91e249a444376029a6df46b6e65d6.profdata
+chrome-win32-main-1665673120-7baff30fe58cba814b897ff8b6c341e70ec06893.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 7a4aa1f..9737ab5d 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1665662309-b2fe0265c6ca402a138f436a03c832aaae293c4f.profdata
+chrome-win64-main-1665694288-62ecc6570a8a2a9bb7bd62acece4924e5b21163d.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 1b2aa02..a7ea6dc 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -38,7 +38,6 @@
     "CHROME_ROOT_STORE_POLICY_SUPPORTED=$chrome_root_store_policy_supported",
     "ENABLE_BACKGROUND_MODE=$enable_background_mode",
     "ENABLE_BACKGROUND_CONTENTS=$enable_background_contents",
-    "ENABLE_BASIC_PRINT_DIALOG=$enable_basic_print_dialog",
     "ENABLE_CHROME_NOTIFICATIONS=$enable_chrome_notifications",
     "ENABLE_CLICK_TO_CALL=$enable_click_to_call",
     "ENABLE_DOWNGRADE_PROCESSING=$enable_downgrade_processing",
diff --git a/chrome/common/apps/platform_apps/api/enterprise_remote_apps.idl b/chrome/common/apps/platform_apps/api/enterprise_remote_apps.idl
index 6046079..f8d1bf96 100644
--- a/chrome/common/apps/platform_apps/api/enterprise_remote_apps.idl
+++ b/chrome/common/apps/platform_apps/api/enterprise_remote_apps.idl
@@ -34,6 +34,18 @@
     DOMString? iconUrl;
   };
 
+  // Possible sort order positions for $(ref:sortLauncher).
+  enum RemoteAppsPosition {
+    // Before native apps, in alphabetical, case insensitive, order.
+    REMOTE_APPS_FIRST
+  };
+
+  // Options for $(ref:sortLauncher).
+  // |position|: Remote apps and folders sort order position.
+  dictionary SortLauncherOptions {
+    RemoteAppsPosition position;
+  };
+
   interface Functions {
     // Adds a Remote Apps folder to the launcher. Empty folders are not shown
     // in the launcher.
@@ -52,6 +64,12 @@
     static void deleteApp(
         DOMString appId,
         optional VoidCallback callback);
+
+    // Sorts the Remote apps and folders according to the position specified in
+    // the SortLauncherOptions.
+    static void sortLauncher(
+        SortLauncherOptions options,
+        optional VoidCallback callback);
   };
 
   interface Events {
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index b17d455..f9352a3b 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -154,10 +154,6 @@
              "ClientStorageAccessContextAuditing",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kConsolidatedSiteStorageControls,
-             "ConsolidatedSiteStorageControls",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables or disables "usm" service in the list of user services returned by
 // userInfo Gaia message.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index dd401a53b..6de3cf7 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -111,9 +111,6 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kClientStorageAccessContextAuditing);
 
-COMPONENT_EXPORT(CHROME_FEATURES)
-BASE_DECLARE_FEATURE(kConsolidatedSiteStorageControls);
-
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kCrOSEnableUSMUserService);
diff --git a/chrome/common/features.gni b/chrome/common/features.gni
index b1a0c38..21cc974e 100644
--- a/chrome/common/features.gni
+++ b/chrome/common/features.gni
@@ -42,10 +42,6 @@
   enable_background_contents = !is_android
   enable_background_mode = !is_android && !is_chromeos
 
-  # Enable the printing system dialog for platforms that support printing
-  # and have a system dialog.
-  enable_basic_print_dialog = enable_basic_printing && !is_chromeos
-
   # Enables usage of notifications via Chrome's MessageCenter.
   enable_chrome_notifications = is_mac || is_win || is_linux || is_fuchsia
 
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 9b3e3cd..f1bd990 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -627,6 +627,11 @@
 const char kLanguageShouldMergeInputMethods[] =
     "settings.language.merge_input_methods";
 
+// An boolean pref that controls whether or not Hindi Inscript keyboard layout
+// is available. Set with the corresponding enterprise user policy.
+const char kHindiInscriptLayoutEnabled[] =
+    "settings.input.hindi_inscript_layout_enabled";
+
 // A boolean pref which turns on Advanced Filesystem
 // (USB support, SD card, etc).
 const char kLabsAdvancedFilesystemEnabled[] =
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index a522b2a..028f700 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -252,6 +252,7 @@
 extern const char kLanguageImeMenuActivated[];
 extern const char kLanguageInputMethodSpecificSettings[];
 extern const char kLanguageShouldMergeInputMethods[];
+extern const char kHindiInscriptLayoutEnabled[];
 
 extern const char kLabsAdvancedFilesystemEnabled[];
 extern const char kLabsMediaplayerEnabled[];
diff --git a/chrome/common/safe_browsing/binary_feature_extractor_win.cc b/chrome/common/safe_browsing/binary_feature_extractor_win.cc
index 840e5bb..104e424 100644
--- a/chrome/common/safe_browsing/binary_feature_extractor_win.cc
+++ b/chrome/common/safe_browsing/binary_feature_extractor_win.cc
@@ -49,10 +49,13 @@
 
   DVLOG(2) << "Checking signature for " << file_path.value();
 
+  base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
+                                 base::File::FLAG_WIN_SHARE_DELETE);
+
   WINTRUST_FILE_INFO file_info = {0};
   file_info.cbStruct = sizeof(file_info);
   file_info.pcwszFilePath = file_path.value().c_str();
-  file_info.hFile = NULL;
+  file_info.hFile = file.GetPlatformFile();
   file_info.pgKnownSubject = NULL;
 
   WINTRUST_DATA wintrust_data = {0};
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 26fae9f..b68fa1b 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -6936,7 +6936,6 @@
       "../browser/ui/webui/settings/reset_settings_handler_unittest.cc",
       "../browser/ui/webui/settings/safety_check_handler_unittest.cc",
       "../browser/ui/webui/settings/settings_clear_browsing_data_handler_unittest.cc",
-      "../browser/ui/webui/settings/settings_cookies_view_handler_unittest.cc",
       "../browser/ui/webui/settings/settings_manage_profile_handler_unittest.cc",
       "../browser/ui/webui/settings/settings_security_key_handler_unittest.cc",
       "../browser/ui/webui/settings/settings_utils_unittest.cc",
@@ -11132,6 +11131,7 @@
     sources = [
       "../browser/ash/crosapi/test/crosapi_test_base.cc",
       "../browser/ash/crosapi/test/crosapi_test_base.h",
+      "../browser/ash/crosapi/test/network_change_ash_crosapitest.cc",
     ]
     deps = [
       ":ash_crosapi_tests_runner",
@@ -11156,10 +11156,7 @@
     use_xvfb = use_xvfb_in_this_config
     defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 
-    sources = [
-      "../browser/ash/crosapi/test/file_manager_ash_browsertest.cc",
-      "../browser/ash/crosapi/test/network_change_ash_browsertest.cc",
-    ]
+    sources = [ "../browser/ash/crosapi/test/file_manager_ash_browsertest.cc" ]
     deps = [
       ":browser_tests_runner",
       ":test_support_ui",
diff --git a/chrome/test/data/banners/main.js b/chrome/test/data/banners/main.js
index 2118b402f..1574533 100644
--- a/chrome/test/data/banners/main.js
+++ b/chrome/test/data/banners/main.js
@@ -107,6 +107,9 @@
         e.preventDefault();
         setTimeout(() => e.prompt(), 0);
         break;
+      case Action.CANCEL_PROMPT:
+        e.preventDefault();
+        break;
       case Action.CANCEL_PROMPT_AND_NAVIGATE:
         e.preventDefault();
         // Navigate the window to trigger cancellation in the renderer.
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn
index e46b06070..8e51439b 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/BUILD.gn
@@ -30,6 +30,8 @@
     "evil/test.js",
     "get_all/sw.js",
     "get_all/test.js",
+    "get_metadata/sw.js",
+    "get_metadata/test.js",
     "helpers.js",
     "move_entry/sw.js",
     "move_entry/test.js",
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/manifest.json b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/manifest.json
new file mode 100644
index 0000000..348549fc
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/manifest.json
@@ -0,0 +1,23 @@
+{
+  // chrome-extension://pkplfbidichfdicaijlchgnapepdginl
+  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtDfX9dHNh948bt00YhZBm3P6E5QLaOt+v8kXVtibQfiPtOD2FTScB/f0wX/EQWVO7BkaSOsRkTPcPIgocyMPYr2FLgqGLFlYT9nQpKJZUFNF5oJ5rG6Nv7ppf4zEB3j6da1IBRTz2yOZ+6O1TMZxol/V62/QcqrJeggsHTEPGLdr9Ua4b1Ka0xKJnJngZljsbw93FI1o+P9dAh5BS6wTPiZI/vmJVjvMTkSTnaZ3n9Go2t7A0XLcSxLcVyuLAd2mAvSN0mIviOukdM66wr7llif71nKuUt+4qvlr/r9HfwzN6pA4jkwhtS1UD+3CmB+wsHwsnohNcuu4FIQ6rgq/7QIDAQAB",
+  "name": "chrome.fileSystemProvider.onGetMetadataRequested",
+  "version": "0.1",
+  "manifest_version": 3,
+  "description":
+      "Test for chrome.fileSystemProvider.onGetMetadataRequested() in service workers.",
+  "permissions": [
+    "fileSystemProvider",
+    {
+      "fileSystem": ["requestFileSystem", "write"]
+    },
+    "fileManagerPrivate"
+  ],
+  "file_system_provider_capabilities": {
+    "source": "device"
+  },
+  "background": {
+    "service_worker": "sw.js",
+    "type": "module"
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/sw.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/sw.js
new file mode 100644
index 0000000..ac074135
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/sw.js
@@ -0,0 +1,7 @@
+// Copyright 2022 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 {serviceWorkerMain} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
+
+serviceWorkerMain(self);
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/test.html b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/test.html
new file mode 100644
index 0000000..9980fda0
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/test.html
@@ -0,0 +1 @@
+<script type="module" src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/test.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/test.js
new file mode 100644
index 0000000..0773769
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/get_metadata/test.js
@@ -0,0 +1,208 @@
+// Copyright 2022 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 {mountTestFileSystem, remoteProvider} from '/_test_resources/api_test/file_system_provider/service_worker/helpers.js';
+// For shared constants.
+import {TestFileSystemProvider} from '/_test_resources/api_test/file_system_provider/service_worker/provider.js';
+
+/**
+ * @param {!FileEntry|!DirectoryEntry} entry
+ * @returns {!Promise<!Metadata>}
+ */
+async function getMetadata(entry) {
+  return new Promise((resolve, reject) => entry.getMetadata(resolve, reject));
+}
+
+async function main() {
+  await navigator.serviceWorker.ready;
+
+  const fileSystem = await mountTestFileSystem();
+
+  chrome.test.runTests([
+    // Read metadata of the root.
+    async function getRootMetadataSuccess() {
+      try {
+        const meta = await getMetadata(fileSystem.fileSystem.root);
+        chrome.test.assertEq(0, meta.size);
+        chrome.test.assertEq(
+            new Date(2014, 4, 28, 10, 39, 15).toString(),
+            meta.modificationTime.toString());
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Read metadata of an existing testing file.
+    async function getFileMetadataSuccess() {
+      try {
+        await remoteProvider.resetState();
+        const fileEntry = await fileSystem.getFileEntry(
+            TestFileSystemProvider.FILE_READ_SUCCESS,
+            {create: false},
+        );
+        const meta = await getMetadata(fileEntry);
+        chrome.test.assertEq(
+            TestFileSystemProvider.INITIAL_TEXT.length, meta.size);
+        chrome.test.assertEq(
+            new Date(2014, 1, 25, 7, 36, 12).toString(),
+            meta.modificationTime.toString());
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Read metadata of an existing testing file, which however has an invalid
+    // modification time. It should not cause an error, but an invalid date
+    // should be passed to fileapi instead. The reason is, that there is no
+    // easy way to verify an incorrect modification time at early stage.
+    async function getFileMetadataWrongTimeSuccess() {
+      try {
+        const fileEntry = await fileSystem.getFileEntry(
+            TestFileSystemProvider.FILE_INVALID_DATE,
+            {create: false},
+        );
+        const meta = await getMetadata(fileEntry);
+        chrome.test.assertTrue(Number.isNaN(meta.modificationTime.getTime()));
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Read metadata of a directory which does not exist, what should return an
+    // error. DirectoryEntry.getDirectory() causes fetching metadata.
+    async function getFileMetadataNotFound() {
+      try {
+        const TEST_DIR = 'non-existent';
+        await remoteProvider.resetState();
+        try {
+          await fileSystem.getDirectoryEntry(
+              TEST_DIR,
+              {create: false},
+          );
+          chrome.test.fail('Getting a directory should have failed.');
+        } catch (e) {
+          chrome.test.assertEq('NotFoundError', e.name);
+        }
+        const {entryPath} =
+            await remoteProvider.waitForEvent('onGetMetadataRequested');
+        chrome.test.assertEq(`/${TEST_DIR}`, entryPath);
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Read metadata of a file using getDirectory(). An error should be returned
+    // because of type mismatching. DirectoryEntry.getDirectory() causes
+    // fetching metadata.
+    async function getFileMetadataWrongType() {
+      try {
+        await remoteProvider.resetState();
+        try {
+          await fileSystem.getDirectoryEntry(
+              TestFileSystemProvider.FILE_READ_SUCCESS,
+              {create: false},
+          );
+          chrome.test.fail('Getting a directory should have failed.');
+        } catch (e) {
+          chrome.test.assertEq('TypeMismatchError', e.name);
+        }
+        const {entryPath} =
+            await remoteProvider.waitForEvent('onGetMetadataRequested');
+        chrome.test.assertEq(
+            `/${TestFileSystemProvider.FILE_READ_SUCCESS}`, entryPath);
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Resolving a file should only request is_directory field.
+    async function getMetadataForGetFile() {
+      try {
+        await remoteProvider.resetState();
+        await fileSystem.getFileEntry(
+            `/${TestFileSystemProvider.FILE_ONLY_TYPE}`,
+            {create: false},
+        );
+        const options =
+            await remoteProvider.waitForEvent('onGetMetadataRequested');
+        chrome.test.assertEq(options.isDirectory, true);
+        chrome.test.assertEq(options.name, false);
+        chrome.test.assertEq(options.size, false);
+        chrome.test.assertEq(options.modificationTime, false);
+        chrome.test.assertEq(options.thumbnail, false);
+        chrome.test.assertEq(options.mimeType, false);
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Check that if a requested mandatory field is missing, then the error
+    // callback is invoked.
+    async function getMetadataMissingFields() {
+      try {
+        await remoteProvider.resetState();
+        const fileEntry = await fileSystem.getFileEntry(
+            `/${TestFileSystemProvider.FILE_ONLY_TYPE_AND_SIZE}`,
+            {create: false},
+        );
+        try {
+          await getMetadata(fileEntry);
+          chrome.test.fail('Getting metadata should have failed.');
+        } catch (e) {
+          chrome.test.assertEq('InvalidStateError', e.name);
+        }
+        const options =
+            await remoteProvider.waitForEvent('onGetMetadataRequested');
+        chrome.test.assertEq(options.isDirectory, true);
+        chrome.test.assertEq(options.name, false);
+        chrome.test.assertEq(options.size, false);
+        chrome.test.assertEq(options.modificationTime, false);
+        chrome.test.assertEq(options.thumbnail, false);
+        chrome.test.assertEq(options.mimeType, false);
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+
+    // Fetch only requested fields.
+    async function getEntryPropertiesFewFields() {
+      try {
+        await remoteProvider.resetState();
+        const fileEntry = await fileSystem.getFileEntry(
+            `/${TestFileSystemProvider.FILE_ONLY_TYPE_AND_SIZE}`,
+            {create: false},
+        );
+        const fileProperties = await new Promise(
+            resolve => chrome.fileManagerPrivate.getEntryProperties(
+                [fileEntry], ['size'], resolve));
+        chrome.test.assertEq(1, fileProperties.length);
+        chrome.test.assertEq(1024 * 4, fileProperties[0].size);
+
+        // The first call is from getFileEntry.
+        await remoteProvider.waitForEvent('onGetMetadataRequested');
+        // The second call is from getEntryProperties.
+        const options =
+            await remoteProvider.waitForEvent('onGetMetadataRequested');
+        chrome.test.assertEq(options.isDirectory, false);
+        chrome.test.assertEq(options.name, false);
+        chrome.test.assertEq(options.size, true);
+        chrome.test.assertEq(options.modificationTime, false);
+        chrome.test.assertEq(options.thumbnail, false);
+        chrome.test.assertEq(options.mimeType, false);
+        chrome.test.succeed();
+      } catch (e) {
+        chrome.test.fail(e);
+      }
+    },
+  ]);
+}
+
+main();
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js
index b79d9ba..cc45e7c 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js
+++ b/chrome/test/data/extensions/api_test/file_system_provider/service_worker/provider.js
@@ -66,6 +66,8 @@
 
 class Entry {
   /**
+   * @param {string} key name identifying the entry in a directory (separate
+   *    from name in the metadata to allow returning a different value there).
    * @param {{
    *  name: string,
    *  isDirectory: boolean,
@@ -75,12 +77,12 @@
    * @param {?string} contents
    * @param {Array<!Entry>} children
    */
-  constructor(metadata, contents, children) {
+  constructor(key, metadata, contents, children) {
+    this.key = key;
     this.metadata = metadata;
     this.contents = contents;
     /** @type {!Object<string, !Entry>} */
-    this.children =
-        Object.fromEntries((children || []).map(e => [e.metadata.name, e]));
+    this.children = Object.fromEntries((children || []).map(e => [e.key, e]));
   }
 
   /**
@@ -90,7 +92,7 @@
    */
   static file(name, modificationTime, contents) {
     return new Entry(
-        {
+        name, {
           name,
           isDirectory: false,
           size: contents.length,
@@ -106,8 +108,9 @@
    */
   static dir(name, modificationTime, children) {
     return new Entry(
-        {
+        name, {
           name,
+          size: 0,
           isDirectory: true,
           modificationTime,
         },
@@ -174,6 +177,28 @@
         entry.metadata.size = -entry.metadata.size;
         return entry;
       })(),
+      // File with invalid date for the modification time.
+      Entry.file(
+          TestFileSystemProvider.FILE_INVALID_DATE, new Date('Invalid date.'),
+          ''),
+      // File with only isDirectory flag as metadata.
+      (() => {
+        const entry = Entry.file(
+            TestFileSystemProvider.FILE_ONLY_TYPE,
+            new Date(2014, 1, 25, 7, 36, 12), '');
+        const {isDirectory} = entry.metadata;
+        entry.metadata = {isDirectory};
+        return entry;
+      })(),
+      // File with only size as metadata.
+      (() => {
+        const entry = Entry.file(
+            TestFileSystemProvider.FILE_ONLY_TYPE_AND_SIZE,
+            new Date(2014, 1, 25, 7, 36, 12), 'A'.repeat(1024 * 4));
+        const {isDirectory, size} = entry.metadata;
+        entry.metadata = {isDirectory, size};
+        return entry;
+      })(),
     ]);
 
     /**
@@ -294,7 +319,8 @@
       const {dirPath} = splitPath(path);
       // Restore Date objects after receiving data via postMessage.
       file.metadata.modificationTime = new Date(file.metadata.modificationTime);
-      const entry = new Entry(file.metadata, file.contents, null);
+      const entry =
+          new Entry(file.metadata.name, file.metadata, file.contents, null);
       this.findEntryByPath(dirPath).children[entry.metadata.name] = entry;
     }
   }
@@ -420,6 +446,9 @@
    * @returns {?Entry}
    */
   findEntryByPath(pathString) {
+    if (pathString === '/') {
+      return this.root;
+    }
     let path = pathString.split('/');
     if (path[0] != '') {
       // Must start with "/"
@@ -599,6 +628,7 @@
    *     callback with an error code.
    */
   onGetMetadataRequested(options, onSuccess, onError) {
+    this.recordEvent('onGetMetadataRequested', options);
     if (options.fileSystemId !== this.fileSystemId) {
       onError(chrome.fileSystemProvider.ProviderError.SECURITY);
       return;
@@ -1046,6 +1076,31 @@
 TestFileSystemProvider.FILE_NEGATIVE_SIZE = 'negative-size.txt';
 
 /**
+ * File with invalid modification time.
+ *
+ * @type {string}
+ * @const
+ */
+TestFileSystemProvider.FILE_INVALID_DATE = 'invalid-date.txt';
+
+/**
+ * File with only type for metadata fields.
+ *
+ * @type {string}
+ * @const
+ */
+TestFileSystemProvider.FILE_ONLY_TYPE = 'metadata-only-type.txt';
+
+/**
+ * File with only size for metadata fields.
+ *
+ * @type {string}
+ * @const
+ */
+TestFileSystemProvider.FILE_ONLY_TYPE_AND_SIZE =
+    'metadata-only-type-and-size.txt';
+
+/**
  * Initial contents of default testing files.
  *
  * @type {string}
diff --git a/chrome/test/data/extensions/remote_apps/extension_api/test.js b/chrome/test/data/extensions/remote_apps/extension_api/test.js
index e50e988..f3eca9c 100644
--- a/chrome/test/data/extensions/remote_apps/extension_api/test.js
+++ b/chrome/test/data/extensions/remote_apps/extension_api/test.js
@@ -134,6 +134,45 @@
           });
     });
   },
+  // Adds the following Remote apps and folders: `test app 5`, `Test App 7`,
+  // `Test App 6 Folder`, `Test App 8` (contained by the folder) and sorts the
+  // items after prompted by the calling site.
+  async function AddRemoteItemsForSort() {
+    chrome.enterprise.remoteApps.addApp(
+        {name: 'test app 5', iconUrl, addToFront: true}, (appId) => {
+          chrome.test.assertNoLastError();
+          chrome.test.assertEq('Id 1', appId);
+
+          chrome.enterprise.remoteApps.addApp(
+              {name: 'Test App 7', iconUrl, addToFront: true}, (appId) => {
+                chrome.test.assertNoLastError();
+                chrome.test.assertEq('Id 2', appId);
+
+                chrome.enterprise.remoteApps.addFolder(
+                    {name: 'Test App 6 Folder', addToFront: true},
+                    (folderId) => {
+                      chrome.test.assertNoLastError();
+                      chrome.test.assertEq('Id 3', folderId);
+
+                      chrome.enterprise.remoteApps.addApp(
+                          {name: 'Test App 8', folderId, iconUrl}, (appId) => {
+                            chrome.test.assertNoLastError();
+                            chrome.test.assertEq('Id 4', appId);
+
+                            chrome.test.sendMessage('Ready to sort', () => {
+                              // Sorts all launcher items with REMOTE_APPS_FIRST
+                              // order.
+                              chrome.enterprise.remoteApps.sortLauncher(
+                                  {position: 'REMOTE_APPS_FIRST'}, () => {
+                                    chrome.test.assertNoLastError();
+                                    chrome.test.succeed();
+                                  });
+                            });
+                          });
+                    });
+              });
+        });
+  },
 ];
 
 chrome.test.getConfig(async (config) => {
diff --git a/chrome/test/data/pdf/fullscreen_test.ts b/chrome/test/data/pdf/fullscreen_test.ts
index 3fa33f9..c62d13d 100644
--- a/chrome/test/data/pdf/fullscreen_test.ts
+++ b/chrome/test/data/pdf/fullscreen_test.ts
@@ -23,6 +23,35 @@
   await eventToPromise('fullscreenchange', scroller);
 }
 
+async function enterAndExitFullscreen(): Promise<void> {
+  // Subsequent calls to requestFullScreen() fail with an "API can only be
+  // initiated by a user gesture" error, so we need to run with user
+  // gesture.
+  function enterFullscreenWithUserGesture(): Promise<void> {
+    return new Promise(res => {
+      chrome.test.runWithUserGesture(() => {
+        ensureFullscreen().then(res);
+      });
+    });
+  }
+
+  await enterFullscreenWithUserGesture();
+  document.exitFullscreen();
+  await eventToPromise('fullscreenchange', scroller);
+}
+
+async function assertEnterAndExitFullscreenWithType(fittingType: FittingType):
+    Promise<void> {
+  // Fullscreen must be exited at the start of this test in order for it to
+  // function properly.
+  chrome.test.assertTrue(document.fullscreenElement === null);
+
+  viewer.viewport.setFittingType(fittingType);
+  await enterAndExitFullscreen();
+  chrome.test.assertTrue(document.fullscreenElement === null);
+  chrome.test.assertEq(fittingType, viewer.viewport.fittingType);
+}
+
 const tests = [
   async function testFullscreen() {
     chrome.test.assertTrue(scroller !== null);
@@ -138,9 +167,6 @@
       chrome.test.succeed();
     });
   },
-  // Note: The following test needs to be the last one, because subsequent calls
-  // to requestFullScreen() fail with an "API can only be initiated by a user
-  // gesture" error.
   async function testFocusAfterExiting() {
     await ensureFullscreen();
     document.exitFullscreen();
@@ -148,6 +174,32 @@
     chrome.test.assertEq('EMBED', getDeepActiveElement()!.nodeName);
     chrome.test.succeed();
   },
+  async function testZoomAfterExiting() {
+    // Fullscreen must be exited at the start of this test in order for it to
+    // function properly.
+    chrome.test.assertTrue(document.fullscreenElement === null);
+
+    // Zoom before fullscreen should be restored after entering and exiting
+    // fullscreen.
+    viewer.viewport.setZoom(0.5);
+    await enterAndExitFullscreen();
+    chrome.test.assertEq(0.5, viewer.viewport.getZoom());
+    chrome.test.assertEq(FittingType.NONE, viewer.viewport.fittingType);
+
+    chrome.test.succeed();
+  },
+  async function testEnterAndExitFullscreenWithType_FitToPage() {
+    await assertEnterAndExitFullscreenWithType(FittingType.FIT_TO_PAGE);
+    chrome.test.succeed();
+  },
+  async function testEnterAndExitFullscreenWithType_FitToWidth() {
+    await assertEnterAndExitFullscreenWithType(FittingType.FIT_TO_WIDTH);
+    chrome.test.succeed();
+  },
+  async function testEnterAndExitFullscreenWithType_FitToHeight() {
+    await assertEnterAndExitFullscreenWithType(FittingType.FIT_TO_HEIGHT);
+    chrome.test.succeed();
+  },
 ];
 
 chrome.test.runTests(tests);
diff --git a/chrome/test/data/pdf/zoom_manager_test.ts b/chrome/test/data/pdf/zoom_manager_test.ts
index f031ce6e..65c72409 100644
--- a/chrome/test/data/pdf/zoom_manager_test.ts
+++ b/chrome/test/data/pdf/zoom_manager_test.ts
@@ -18,10 +18,10 @@
     addZoomListeners(target: EventTarget) {
       this.tracker_.add(
           target, 'set-zoom',
-          e => this.setZoom((e as CustomEvent<number>).detail));
+          (e: Event) => this.setZoom((e as CustomEvent<number>).detail));
       this.tracker_.add(
           target, 'update-zoom-from-browser',
-          e => this.updateZoomFromBrowserChange(
+          (e: Event) => this.updateZoomFromBrowserChange(
               (e as CustomEvent<number>).detail));
     }
 
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 226296c..9d8f639 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -20235,5 +20235,38 @@
         }
       }
     ]
+  },
+  "HindiInscriptLayoutEnabled": {
+    "os": ["chromeos_ash"],
+    "policy_pref_mapping_tests": [
+      {
+        "policies": {},
+        "prefs": {
+          "settings.input.hindi_inscript_layout_enabled": {
+            "default_value": false
+          }
+        }
+      },
+      {
+        "policies": {
+          "HindiInscriptLayoutEnabled": false
+        },
+        "prefs": {
+          "settings.input.hindi_inscript_layout_enabled": {
+            "value": false
+          }
+        }
+      },
+      {
+        "policies": {
+          "HindiInscriptLayoutEnabled": true
+        },
+        "prefs": {
+          "settings.input.hindi_inscript_layout_enabled": {
+            "value": true
+          }
+        }
+      }
+    ]
   }
 }
diff --git a/chrome/test/data/webui/i18n_process_css_test.html b/chrome/test/data/webui/i18n_process_css_test.html
deleted file mode 100644
index 550e555..0000000
--- a/chrome/test/data/webui/i18n_process_css_test.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype html>
-<head>
-  <link rel="stylesheet" href="chrome://resources/css/i18n_process.css">
-</head>
-<body>
-  <h1 i18n-content="buy"></h1>
-  <span i18n-values=".innerHTML:link"></span>
-  <script src="i18n_process_css_test.js"></script>
-</body>
diff --git a/chrome/test/data/webui/i18n_process_css_test.js b/chrome/test/data/webui/i18n_process_css_test.js
deleted file mode 100644
index 6118965ab..0000000
--- a/chrome/test/data/webui/i18n_process_css_test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-function testI18nProcess_NbspPlaceholder() {
-  const h1 = document.querySelector('h1');
-  const span = document.querySelector('span');
-
-  assertFalse(document.documentElement.hasAttribute('i18n-processed'));
-  assertEquals('', h1.textContent);
-  assertEquals('', span.textContent);
-
-  /* We can't check that the non-breaking space hack actually works because it
-   * uses :psuedo-elements that are inaccessible to the DOM. Let's just check
-   * that they're not auto-collapsed. */
-  assertNotEqual(0, h1.offsetHeight);
-  assertNotEqual(0, span.offsetHeight);
-
-  h1.removeAttribute('i18n-content');
-  assertEquals(0, h1.offsetHeight);
-
-  span.removeAttribute('i18n-values');
-  assertEquals(0, span.offsetHeight);
-}
diff --git a/chrome/test/data/webui/mock_timer_test.html b/chrome/test/data/webui/mock_timer_test.html
deleted file mode 100644
index f12290d4..0000000
--- a/chrome/test/data/webui/mock_timer_test.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<script src="mock_timer.js"></script>
-<script src="mock_timer_test.js"></script>
-</body>
-</html>
diff --git a/chrome/test/data/webui/new_tab_page/BUILD.gn b/chrome/test/data/webui/new_tab_page/BUILD.gn
index 2e71a8cb..6a4b728e 100644
--- a/chrome/test/data/webui/new_tab_page/BUILD.gn
+++ b/chrome/test/data/webui/new_tab_page/BUILD.gn
@@ -18,6 +18,7 @@
                            "customize_shortcuts_test.ts",
                            "doodle_share_dialog_focus_test.ts",
                            "doodle_share_dialog_test.ts",
+                           "lens_form_test.ts",
                            "lens_upload_dialog_test.ts",
                            "logo_test.ts",
                            "metrics_test_support.ts",
diff --git a/chrome/test/data/webui/new_tab_page/lens_form_test.ts b/chrome/test/data/webui/new_tab_page/lens_form_test.ts
new file mode 100644
index 0000000..0f4e135b3
--- /dev/null
+++ b/chrome/test/data/webui/new_tab_page/lens_form_test.ts
@@ -0,0 +1,112 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://webui-test/mojo_webui_test_support.js';
+import 'chrome://new-tab-page/new_tab_page.js';
+
+import {LensErrorType, LensFormElement} from 'chrome://new-tab-page/lazy_load.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
+suite('LensFormTest', () => {
+  let lensForm: LensFormElement;
+
+  let fileFormSubmitted = false;
+  let lastError: LensErrorType|null = null;
+  let loading = false;
+
+  setup(() => {
+    lensForm = document.createElement('ntp-lens-form');
+    document.body.appendChild(lensForm);
+
+    lensForm.$.fileForm.submit = () => {
+      fileFormSubmitted = true;
+    };
+
+    lensForm.addEventListener('error', (e: Event) => {
+      const event = e as CustomEvent<LensErrorType>;
+      lastError = event.detail;
+    });
+
+    lensForm.addEventListener('loading', () => {
+      loading = true;
+    });
+  });
+
+  teardown(() => {
+    fileFormSubmitted = false;
+    lastError = null;
+    loading = false;
+  });
+
+  test('select png files should submit file form', async () => {
+    // Arrange.
+    const file = new File([], 'file-name.png', {type: 'image/png'});
+
+    // Act.
+    dispatchFileInputChange(file);
+
+    // Assert.
+    assertTrue(fileFormSubmitted);
+    assertEquals(null, lastError);
+    assertTrue(loading);
+  });
+
+  test(
+      'select multiple files should fail with multiple files error',
+      async () => {
+        // Arrange.
+        const file1 = new File([], 'file-1.png', {type: 'image/png'});
+        const file2 = new File([], 'file-2.png', {type: 'image/png'});
+        const dataTransfer = new DataTransfer();
+        dataTransfer.items.add(file1);
+        dataTransfer.items.add(file2);
+
+        // Act.
+        dispatchFileInputChangeWithDataTransfer(dataTransfer);
+
+        // Assert.
+        assertFalse(fileFormSubmitted);
+        assertEquals(LensErrorType.MULTIPLE_FILES, lastError);
+        assertFalse(loading);
+      });
+
+  test('select no files should fail with no files error', async () => {
+    // Arrange.
+    const dataTransfer = new DataTransfer();
+
+    // Act.
+    dispatchFileInputChangeWithDataTransfer(dataTransfer);
+
+    // Assert.
+    assertFalse(fileFormSubmitted);
+    assertEquals(LensErrorType.NO_FILE, lastError);
+    assertFalse(loading);
+  });
+
+  test(
+      'select unsupported file type should fail with file type error',
+      async () => {
+        // Arrange.
+        const file = new File([], 'file-name.pdf', {type: 'image/pdf'});
+
+        // Act.
+        dispatchFileInputChange(file);
+
+        // Assert.
+        assertFalse(fileFormSubmitted);
+        assertEquals(LensErrorType.FILE_TYPE, lastError);
+        assertFalse(loading);
+      });
+
+  function dispatchFileInputChangeWithDataTransfer(dataTransfer: DataTransfer) {
+    lensForm.$.fileInput.files = dataTransfer.files;
+    lensForm.$.fileInput.dispatchEvent(new Event('change'));
+  }
+
+  function dispatchFileInputChange(file: File) {
+    const dataTransfer = new DataTransfer();
+    dataTransfer.items.add(file);
+    dispatchFileInputChangeWithDataTransfer(dataTransfer);
+  }
+});
diff --git a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
index 79027c55a..8bb9761 100644
--- a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
+++ b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
@@ -145,6 +145,17 @@
   mocha.run();
 });
 
+var NewTabPageLensFormTest = class extends NewTabPageBrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://new-tab-page/test_loader.html?module=new_tab_page/lens_form_test.js';
+  }
+};
+
+TEST_F('NewTabPageLensFormTest', 'All', function() {
+  mocha.run();
+});
+
 var NewTabPageLensUploadDialogTest = class extends NewTabPageBrowserTest {
   /** @override */
   get browsePreload() {
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index 74ff3985..762a877b 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -118,8 +118,6 @@
   "settings_subpage_test.ts",
   "settings_textarea_tests.ts",
   "settings_ui_tests.ts",
-  "site_data_details_subpage_tests.ts",
-  "site_data_test.ts",
   "site_details_permission_tests.ts",
   "site_details_tests.ts",
   "site_entry_tests.ts",
@@ -133,7 +131,6 @@
   "test_clear_browsing_data_browser_proxy.ts",
   "test_extension_control_browser_proxy.ts",
   "test_hats_browser_proxy.ts",
-  "test_local_data_browser_proxy.ts",
   "test_metrics_browser_proxy.ts",
   "test_open_window_proxy.ts",
   "test_password_manager_proxy.ts",
diff --git a/chrome/test/data/webui/settings/OWNERS b/chrome/test/data/webui/settings/OWNERS
index 8b41083..e25fe989 100644
--- a/chrome/test/data/webui/settings/OWNERS
+++ b/chrome/test/data/webui/settings/OWNERS
@@ -16,8 +16,6 @@
 per-file secure_dns_test.ts=sauski@google.com
 per-file security_keys_subpage_test.ts=sauski@google.com
 per-file security_page_test.ts=sauski@google.com
-per-file site_data_details_subpage_tests.ts=sauski@google.com
-per-file site_data_test.ts=sauski@google.com
 per-file site_details_permission_tests.ts=sauski@google.com
 per-file site_details_tests.ts=sauski@google.com
 per-file site_entry_tests.ts=sauski@google.com
diff --git a/chrome/test/data/webui/settings/all_sites_tests.ts b/chrome/test/data/webui/settings/all_sites_tests.ts
index 4468365..89eee5b 100644
--- a/chrome/test/data/webui/settings/all_sites_tests.ts
+++ b/chrome/test/data/webui/settings/all_sites_tests.ts
@@ -5,26 +5,32 @@
 // clang-format off
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {AllSitesElement, ContentSetting, ContentSettingsTypes, LocalDataBrowserProxyImpl, SiteGroup, SiteSettingsPrefsBrowserProxyImpl, SortMethod} from 'chrome://settings/lazy_load.js';
+import {AllSitesElement, ContentSetting, ContentSettingsTypes, SiteGroup, SiteSettingsPrefsBrowserProxyImpl, SortMethod} from 'chrome://settings/lazy_load.js';
 import {CrSettingsPrefs, Router, routes} from 'chrome://settings/settings.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {isChildVisible} from 'chrome://webui-test/test_util.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 
-import {TestLocalDataBrowserProxy} from './test_local_data_browser_proxy.js';
 import {TestSiteSettingsPrefsBrowserProxy} from './test_site_settings_prefs_browser_proxy.js';
 import {createContentSettingTypeToValuePair, createOriginInfo, createRawSiteException, createSiteGroup, createSiteSettingsPrefs, SiteSettingsPref} from './test_util.js';
 
 // clang-format on
 
-suite('AllSites_DisabledConsolidatedControls', function() {
+suite('AllSites_DisableFirstPartySets', function() {
   /**
    * An example eTLD+1 Object with multiple origins grouped under it.
    */
   const TEST_MULTIPLE_SITE_GROUP = createSiteGroup('example.com', [
-    'http://example.com',
-    'https://www.example.com',
-    'https://login.example.com',
+    'http://subdomain.example.com/',
+    'https://www.example.com/',
+    'https://login.example.com/',
+  ]);
+
+  /**
+   * An example eTLD+1 Object with a single origin grouped under it.
+   */
+  const TEST_SINGLE_SITE_GROUP = createSiteGroup('example.com', [
+    'https://single.example.com/',
   ]);
 
   /**
@@ -40,16 +46,11 @@
    */
   let browserProxy: TestSiteSettingsPrefsBrowserProxy;
 
-  /**
-   * The mock local data proxy object to use during test.
-   */
-  let localDataBrowserProxy: TestLocalDataBrowserProxy;
-
   suiteSetup(function() {
     CrSettingsPrefs.setInitialized();
 
     loadTimeData.overrideValues({
-      consolidatedSiteStorageControlsEnabled: false,
+      firstPartySetsUIEnabled: false,
     });
   });
 
@@ -86,9 +87,7 @@
           ]),
     ]);
     browserProxy = new TestSiteSettingsPrefsBrowserProxy();
-    localDataBrowserProxy = new TestLocalDataBrowserProxy();
     SiteSettingsPrefsBrowserProxyImpl.setInstance(browserProxy);
-    LocalDataBrowserProxyImpl.setInstance(localDataBrowserProxy);
     testElement = document.createElement('all-sites');
     assertTrue(!!testElement);
     document.body.appendChild(testElement);
@@ -582,202 +581,6 @@
     assertEquals(addOrigin, siteEntries[3]!.siteGroup.origins[0]!.origin);
   });
 
-  function resetSettingsViaOverflowMenu(buttonType: string) {
-    assertTrue(
-        buttonType === 'cancel-button' || buttonType === 'action-button');
-    flush();
-    const siteEntries =
-        testElement.$.listContainer.querySelectorAll('site-entry');
-    assertEquals(1, siteEntries.length);
-    const overflowMenuButton =
-        siteEntries[0]!.$$<HTMLElement>('#overflowMenuButton')!;
-    assertFalse(
-        overflowMenuButton.closest<HTMLElement>('.row-aligned')!.hidden);
-
-    // Open the reset settings dialog.
-    // Test clicking on the overflow menu button opens the menu.
-    const overflowMenu = testElement.$.menu.get();
-    assertFalse(overflowMenu.open);
-    overflowMenuButton.click();
-    assertTrue(overflowMenu.open);
-    flush();
-    const menuItems =
-        overflowMenu.querySelectorAll<HTMLElement>('.dropdown-item');
-    // Open the reset settings dialog and tap the |buttonType| button.
-    assertFalse(testElement.$.confirmResetSettings.get().open);
-    menuItems[0]!.click();
-    assertTrue(testElement.$.confirmResetSettings.get().open);
-    const actionButtonList =
-        testElement.$.confirmResetSettings.get().querySelectorAll<HTMLElement>(
-            `.${buttonType}`);
-    assertEquals(1, actionButtonList.length);
-    actionButtonList[0]!.click();
-
-    // Check the dialog and overflow menu are now both closed.
-    assertFalse(testElement.$.confirmResetSettings.get().open);
-    assertFalse(overflowMenu.open);
-  }
-
-  test('cancelling the confirm dialog on resetting settings works', function() {
-    testElement.siteGroupMap.set(
-        TEST_MULTIPLE_SITE_GROUP.etldPlus1,
-        JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)));
-    testElement.forceListUpdateForTesting();
-    resetSettingsViaOverflowMenu('cancel-button');
-  });
-
-  test('reset settings via overflow menu (no data or cookies)', function() {
-    // Test when entire siteGroup has no data or cookies.
-    // Clone this object to avoid propagating changes made in this test.
-    testElement.siteGroupMap.set(
-        TEST_MULTIPLE_SITE_GROUP.etldPlus1,
-        JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)));
-    testElement.forceListUpdateForTesting();
-    resetSettingsViaOverflowMenu('action-button');
-    // Ensure a call was made to setOriginPermissions for each origin.
-    assertEquals(
-        TEST_MULTIPLE_SITE_GROUP.origins.length,
-        browserProxy.getCallCount('setOriginPermissions'));
-    assertEquals(testElement.$.allSitesList.items!.length, 0);
-  });
-
-  test(
-      'reset settings via overflow menu (one has data and cookies)',
-      function() {
-        // Test when one origin has data and cookies.
-        // Clone this object to avoid propagating changes made in this test.
-        const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-        siteGroup.origins[0].hasPermissionSettings = true;
-        siteGroup.origins[0].usage = 100;
-        siteGroup.origins[0].numCookies = 2;
-        testElement.siteGroupMap.set(
-            siteGroup.etldPlus1, JSON.parse(JSON.stringify(siteGroup)));
-        testElement.forceListUpdateForTesting();
-        resetSettingsViaOverflowMenu('action-button');
-        assertEquals(testElement.$.allSitesList.items!.length, 1);
-        assertEquals(1, testElement.$.allSitesList.items![0].origins.length);
-        assertFalse(testElement.$.allSitesList.items![0]
-                        .origins[0]
-                        .hasPermissionSettings);
-        assertEquals(
-            testElement.$.allSitesList.items![0].origins[0].usage, 100);
-        assertEquals(
-            testElement.$.allSitesList.items![0].origins[0].numCookies, 2);
-      });
-
-  test('reset settings via overflow menu (etld+1 has cookies)', function() {
-    // Test when none of origin have data or cookies, but etld+1 has
-    // cookies. In this case, a placeholder origin will be created with the
-    // Etld+1 cookies number. Clone this object to avoid propagating changes
-    // made in this test.
-    const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-    siteGroup.numCookies = 5;
-    testElement.siteGroupMap.set(
-        siteGroup.etldPlus1, JSON.parse(JSON.stringify(siteGroup)));
-    testElement.forceListUpdateForTesting();
-    resetSettingsViaOverflowMenu('action-button');
-    assertEquals(testElement.$.allSitesList.items!.length, 1);
-    assertEquals(1, testElement.$.allSitesList.items![0].origins.length);
-    assertFalse(
-        testElement.$.allSitesList.items![0].origins[0].hasPermissionSettings);
-    assertEquals(testElement.$.allSitesList.items![0].origins[0].usage, 0);
-    assertEquals(testElement.$.allSitesList.items![0].origins[0].numCookies, 5);
-  });
-
-  function clearDataViaOverflowMenu(buttonType: string) {
-    assertTrue(
-        buttonType === 'cancel-button' || buttonType === 'action-button');
-    flush();
-    const siteEntries =
-        testElement.$.listContainer.querySelectorAll('site-entry');
-    assertEquals(1, siteEntries.length);
-    const overflowMenuButton =
-        siteEntries[0]!.$$<HTMLElement>('#overflowMenuButton')!;
-    assertFalse(
-        overflowMenuButton.closest<HTMLElement>('.row-aligned')!.hidden);
-
-    // Open the clear data dialog.
-    const overflowMenu = testElement.$.menu.get();
-    // Test clicking on the overflow menu button opens the menu.
-    assertFalse(overflowMenu.open);
-    overflowMenuButton.click();
-    assertTrue(overflowMenu.open);
-    flush();
-    const menuItems =
-        overflowMenu.querySelectorAll<HTMLElement>('.dropdown-item');
-
-    // Open the clear data dialog and tap the |buttonType| button.
-    assertFalse(testElement.$.confirmClearData.get().open);
-    menuItems[1]!.click();
-    assertTrue(testElement.$.confirmClearData.get().open);
-    const actionButtonList =
-        testElement.$.confirmClearData.get().querySelectorAll<HTMLElement>(
-            `.${buttonType}`);
-    assertEquals(1, actionButtonList.length);
-    actionButtonList[0]!.click();
-
-    // Check the dialog and overflow menu are now both closed.
-    assertFalse(testElement.$.confirmClearData.get().open);
-    assertFalse(overflowMenu.open);
-  }
-
-  test('cancelling the confirm dialog on clear data works', function() {
-    testElement.siteGroupMap.set(
-        TEST_MULTIPLE_SITE_GROUP.etldPlus1,
-        JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)));
-    testElement.forceListUpdateForTesting();
-    clearDataViaOverflowMenu('cancel-button');
-  });
-
-  test('clear data via overflow menu (no permission and no data)', function() {
-    // Test when all origins has no permission settings and no data.
-    // Clone this object to avoid propagating changes made in this test.
-    testElement.siteGroupMap.set(
-        TEST_MULTIPLE_SITE_GROUP.etldPlus1,
-        JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP)));
-    testElement.forceListUpdateForTesting();
-    clearDataViaOverflowMenu('action-button');
-    // Ensure a call was made to clearEtldPlus1DataAndCookies.
-    assertEquals(1, browserProxy.getCallCount('clearEtldPlus1DataAndCookies'));
-    assertEquals(testElement.$.allSitesList.items!.length, 0);
-  });
-
-  test('clear data via overflow menu (one origin has permission)', function() {
-    // Test when there is one origin has permissions settings.
-    // Clone this object to avoid propagating changes made in this test.
-    const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-    siteGroup.origins[0].hasPermissionSettings = true;
-    testElement.siteGroupMap.set(
-        siteGroup.etldPlus1, JSON.parse(JSON.stringify(siteGroup)));
-    testElement.forceListUpdateForTesting();
-    clearDataViaOverflowMenu('action-button');
-    assertEquals(testElement.$.allSitesList.items!.length, 1);
-    assertEquals(testElement.$.allSitesList.items![0].origins.length, 1);
-  });
-
-  test(
-      'clear data via overflow menu (one origin has permission and data)',
-      function() {
-        // Test when one origin has permission settings and data, clear data
-        // only clears the data and cookies.
-        const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-        siteGroup.origins[0].hasPermissionSettings = true;
-        siteGroup.origins[0].usage = 100;
-        siteGroup.origins[0].numCookies = 3;
-        testElement.siteGroupMap.set(
-            siteGroup.etldPlus1, JSON.parse(JSON.stringify(siteGroup)));
-        testElement.forceListUpdateForTesting();
-        clearDataViaOverflowMenu('action-button');
-        assertEquals(testElement.$.allSitesList.items!.length, 1);
-        assertEquals(testElement.$.allSitesList.items![0].origins.length, 1);
-        assertTrue(testElement.$.allSitesList.items![0]
-                       .origins[0]
-                       .hasPermissionSettings);
-        assertEquals(testElement.$.allSitesList.items![0].origins[0].usage, 0);
-        assertEquals(
-            testElement.$.allSitesList.items![0].origins[0].numCookies, 0);
-      });
-
   function clearDataViaClearAllButton(buttonType: string) {
     assertTrue(
         buttonType === 'cancel-button' || buttonType === 'action-button');
@@ -859,249 +662,6 @@
         assertEquals(testElement.$.allSitesList.items![0].origins.length, 1);
       });
 
-  /**
-   * Opens the overflow menu for a specific origin within a SiteEntry, clicks
-   * on the clear data option, and then clicks on either the cancel or clear
-   * data button.
-   * @param buttonType The button to click on the clear data dialog
-   * @param siteGroup The SiteGroup for which the origin to clear
-   *     belongs to.
-   * @param originIndex The index of the origin to clear in the
-   *     SiteGroup.origins array.
-   */
-  function clearOriginDataViaOverflowMenu(
-      buttonType: string, siteGroup: SiteGroup, originIndex: number) {
-    assertTrue(
-        buttonType === 'cancel-button' || buttonType === 'action-button');
-    flush();
-    const siteEntries =
-        testElement.$.listContainer.querySelectorAll('site-entry');
-    assertEquals(1, siteEntries.length);
-
-    const expandButton = siteEntries[0]!.$.expandIcon;
-    // Open the overflow menu.
-    const overflowMenu = testElement.$.menu.get();
-    assertFalse(overflowMenu.open);
-    testElement.dispatchEvent(new CustomEvent('open-menu', {
-      bubbles: true,
-      composed: true,
-      detail: {
-        target: expandButton,
-        index: 0,
-        item: siteGroup,
-        origin: siteGroup.origins[originIndex]!.origin,
-        actionScope: 'origin',
-      },
-    }));
-    assertTrue(overflowMenu.open);
-    flush();
-    const menuItems =
-        overflowMenu.querySelectorAll<HTMLElement>('.dropdown-item');
-
-    // Open the clear data dialog and tap the |buttonType| button.
-    assertFalse(testElement.$.confirmClearData.get().open);
-    menuItems[1]!.click();
-    assertTrue(testElement.$.confirmClearData.get().open);
-    const actionButtonList =
-        testElement.$.confirmClearData.get().querySelectorAll<HTMLElement>(
-            `.${buttonType}`);
-    assertEquals(1, actionButtonList.length);
-    actionButtonList[0]!.click();
-
-    // Check the dialog and overflow menu are now both closed.
-    assertFalse(testElement.$.confirmClearData.get().open);
-    assertFalse(overflowMenu.open);
-  }
-
-  test('cancelling the confirm dialog on clear data works', function() {
-    const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-    testElement.siteGroupMap.set(siteGroup.etldPlus1, siteGroup);
-    testElement.forceListUpdateForTesting();
-    assertEquals(1, testElement.$.allSitesList.items!.length);
-    assertEquals(3, testElement.$.allSitesList.items![0].origins.length);
-    clearOriginDataViaOverflowMenu('cancel-button', siteGroup, 0);
-    assertEquals(1, testElement.$.allSitesList.items!.length);
-    assertEquals(3, testElement.$.allSitesList.items![0].origins.length);
-  });
-
-  test('clear single origin data via overflow menu', function() {
-    const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-    siteGroup.origins[0].hasPermissionSettings = false;
-    siteGroup.origins[0].usage = 100;
-    siteGroup.origins[0].numCookies = 3;
-    testElement.siteGroupMap.set(
-        siteGroup.etldPlus1, JSON.parse(JSON.stringify(siteGroup)));
-    testElement.forceListUpdateForTesting();
-    clearOriginDataViaOverflowMenu('action-button', siteGroup, 0);
-    assertEquals(1, testElement.$.allSitesList.items!.length);
-    assertEquals(2, testElement.$.allSitesList.items![0].origins.length);
-  });
-
-  test(
-      'clear single origin data via overflow menu (has permissions)',
-      function() {
-        const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-        siteGroup.origins[0].hasPermissionSettings = true;
-        siteGroup.origins[0].usage = 100;
-        siteGroup.origins[0].numCookies = 3;
-        testElement.siteGroupMap.set(
-            siteGroup.etldPlus1, JSON.parse(JSON.stringify(siteGroup)));
-        testElement.forceListUpdateForTesting();
-        clearOriginDataViaOverflowMenu('action-button', siteGroup, 0);
-        assertEquals(1, testElement.$.allSitesList.items!.length);
-        assertEquals(3, testElement.$.allSitesList.items![0].origins.length);
-
-        const updatedOrigin = testElement.$.allSitesList.items![0].origins[0];
-        assertTrue(updatedOrigin.hasPermissionSettings);
-        assertEquals(0, updatedOrigin.usage);
-        assertEquals(0, updatedOrigin.numCookies);
-      });
-
-  /**
-   * Clicks on the overflow menu for a specific origin, hits the reset
-   * permissions button on the overflow menu, and takes the specified action on
-   * the confirmation dialog.
-   * @param buttonType The button to click on the confirmation dialog.
-   * @param siteGroup The SiteGroup to which the origin to reset
-   *     belongs to.
-   * @param originIndex The index in the SiteGroup.origins array of the
-   *     origin to reset permissions for.
-   */
-  function resetOriginSettingsViaOverflowMenu(
-      buttonType: string, siteGroup: SiteGroup, originIndex: number) {
-    assertTrue(
-        buttonType === 'cancel-button' || buttonType === 'action-button');
-    flush();
-    const siteEntries =
-        testElement.$.listContainer.querySelectorAll('site-entry');
-    assertEquals(1, siteEntries.length);
-
-    const expandButton = siteEntries[0]!.$.expandIcon;
-    // Open the overflow menu.
-    const overflowMenu = testElement.$.menu.get();
-    assertFalse(overflowMenu.open);
-    testElement.dispatchEvent(new CustomEvent('open-menu', {
-      bubbles: true,
-      composed: true,
-      detail: {
-        target: expandButton,
-        index: 0,
-        item: siteGroup,
-        origin: siteGroup.origins[originIndex]!.origin,
-        actionScope: 'origin',
-      },
-    }));
-    assertTrue(overflowMenu.open);
-    flush();
-    const menuItems =
-        overflowMenu.querySelectorAll<HTMLElement>('.dropdown-item');
-
-    // Open the clear data dialog and tap the |buttonType| button.
-    assertFalse(testElement.$.confirmResetSettings.get().open);
-    menuItems[0]!.click();
-    assertTrue(testElement.$.confirmResetSettings.get().open);
-    const actionButtonList =
-        testElement.$.confirmResetSettings.get().querySelectorAll<HTMLElement>(
-            `.${buttonType}`);
-    assertEquals(1, actionButtonList.length);
-    actionButtonList[0]!.click();
-
-    // Check the dialog and overflow menu are now both closed.
-    assertFalse(testElement.$.confirmResetSettings.get().open);
-    assertFalse(overflowMenu.open);
-  }
-
-  test('cancelling the confirm dialog on resetting settings works', function() {
-    const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-    testElement.siteGroupMap.set(siteGroup.etldPlus1, siteGroup);
-    testElement.forceListUpdateForTesting();
-    assertEquals(1, testElement.$.allSitesList.items!.length);
-    assertEquals(3, testElement.$.allSitesList.items![0].origins.length);
-    resetOriginSettingsViaOverflowMenu('cancel-button', siteGroup, 0);
-    assertEquals(1, testElement.$.allSitesList.items!.length);
-    assertEquals(3, testElement.$.allSitesList.items![0].origins.length);
-  });
-
-  test(
-      'clear single origin permissions via overflow menu (no usage/cookies)',
-      function() {
-        const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-        siteGroup.origins[0].hasPermissionSettings = true;
-        siteGroup.origins[0].usage = 0;
-        siteGroup.origins[0].numCookies = 0;
-        testElement.siteGroupMap.set(
-            siteGroup.etldPlus1, JSON.parse(JSON.stringify(siteGroup)));
-        testElement.forceListUpdateForTesting();
-        resetOriginSettingsViaOverflowMenu('action-button', siteGroup, 0);
-        assertEquals(1, testElement.$.allSitesList.items!.length);
-        assertEquals(2, testElement.$.allSitesList.items![0].origins.length);
-      });
-
-  test(
-      'clear single origin permissions via overflow menu (has usage/cookies)',
-      function() {
-        const siteGroup = JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-        siteGroup.origins[0].hasPermissionSettings = true;
-        siteGroup.origins[0].usage = 100;
-        siteGroup.origins[0].numCookies = 10;
-        testElement.siteGroupMap.set(
-            siteGroup.etldPlus1, JSON.parse(JSON.stringify(siteGroup)));
-        testElement.forceListUpdateForTesting();
-        resetOriginSettingsViaOverflowMenu('action-button', siteGroup, 0);
-        assertEquals(1, testElement.$.allSitesList.items!.length);
-        assertEquals(3, testElement.$.allSitesList.items![0].origins.length);
-      });
-});
-
-suite('AllSites_EnabledConsolidatedControls', function() {
-  /**
-   * An example eTLD+1 Object with multiple origins grouped under it.
-   */
-  const TEST_MULTIPLE_SITE_GROUP = createSiteGroup('example.com', [
-    'http://subdomain.example.com/',
-    'https://www.example.com/',
-    'https://login.example.com/',
-  ]);
-
-  /**
-   * An example eTLD+1 Object with a single origin grouped under it.
-   */
-  const TEST_SINGLE_SITE_GROUP = createSiteGroup('example.com', [
-    'https://single.example.com',
-  ]);
-
-  let testElement: AllSitesElement;
-
-  /**
-   * The mock proxy object to use during test.
-   */
-  let browserProxy: TestSiteSettingsPrefsBrowserProxy;
-
-  /**
-   * The mock local data proxy object to use during test.
-   */
-  let localDataBrowserProxy: TestLocalDataBrowserProxy;
-
-  suiteSetup(function() {
-    loadTimeData.overrideValues({
-      consolidatedSiteStorageControlsEnabled: true,
-    });
-  });
-
-  // Initialize a site-list before each test.
-  setup(async function() {
-    document.body.innerHTML =
-        window.trustedTypes!.emptyHTML as unknown as string;
-
-    browserProxy = new TestSiteSettingsPrefsBrowserProxy();
-    localDataBrowserProxy = new TestLocalDataBrowserProxy();
-    SiteSettingsPrefsBrowserProxyImpl.setInstance(browserProxy);
-    LocalDataBrowserProxyImpl.setInstance(localDataBrowserProxy);
-    testElement = document.createElement('all-sites');
-    assertTrue(!!testElement);
-    document.body.appendChild(testElement);
-  });
-
   function removeFirstOrigin() {
     const siteEntries =
         testElement.$.listContainer.querySelectorAll('site-entry');
@@ -1137,11 +697,6 @@
     return testElement.i18n(messageId);
   }
 
-  function getSubstitutedString(messageId: string, substitute: string): string {
-    return loadTimeData.substituteString(
-        testElement.i18n(messageId), substitute);
-  }
-
   test('remove site group', function() {
     testElement.siteGroupMap.set(
         TEST_MULTIPLE_SITE_GROUP.etldPlus1,
@@ -1490,16 +1045,10 @@
    */
   let browserProxy: TestSiteSettingsPrefsBrowserProxy;
 
-  /**
-   * The mock local data proxy object to use during test.
-   */
-  let localDataBrowserProxy: TestLocalDataBrowserProxy;
-
   suiteSetup(function() {
     CrSettingsPrefs.setInitialized();
 
     loadTimeData.overrideValues({
-      consolidatedSiteStorageControlsEnabled: true,
       firstPartySetsUIEnabled: true,
     });
   });
@@ -1515,9 +1064,7 @@
         window.trustedTypes!.emptyHTML as unknown as string;
 
     browserProxy = new TestSiteSettingsPrefsBrowserProxy();
-    localDataBrowserProxy = new TestLocalDataBrowserProxy();
     SiteSettingsPrefsBrowserProxyImpl.setInstance(browserProxy);
-    LocalDataBrowserProxyImpl.setInstance(localDataBrowserProxy);
     testElement = document.createElement('all-sites');
     assertTrue(!!testElement);
     document.body.appendChild(testElement);
@@ -1692,7 +1239,7 @@
         let siteEntries =
             testElement.$.listContainer.querySelectorAll('site-entry');
         assertEquals(testElement.$.allSitesList.items!.length, 2);
-        await localDataBrowserProxy.whenCalled('getFpsMembershipLabel');
+        await browserProxy.whenCalled('getFpsMembershipLabel');
         assertEquals(
             '· 2 sites in google.com\'s group',
             siteEntries[1]!.$.fpsMembership.innerText.trim());
@@ -1702,7 +1249,7 @@
         siteEntries =
             testElement.$.listContainer.querySelectorAll('site-entry');
         assertEquals(testElement.$.allSitesList.items!.length, 1);
-        await localDataBrowserProxy.whenCalled('getFpsMembershipLabel');
+        await browserProxy.whenCalled('getFpsMembershipLabel');
         assertEquals(
             '· 1 site in google.com\'s group',
             siteEntries[1]!.$.fpsMembership.innerText.trim());
@@ -1721,7 +1268,7 @@
         let siteEntries =
             testElement.$.listContainer.querySelectorAll('site-entry');
         assertEquals(testElement.$.allSitesList.items!.length, 2);
-        await localDataBrowserProxy.whenCalled('getFpsMembershipLabel');
+        await browserProxy.whenCalled('getFpsMembershipLabel');
         assertEquals(
             '· 2 sites in google.com\'s group',
             siteEntries[1]!.$.fpsMembership.innerText.trim());
@@ -1748,7 +1295,7 @@
         assertEquals(1, originEntries.length);
 
         // Ensure that first party set info is unaffected by origin removal.
-        await localDataBrowserProxy.whenCalled('getFpsMembershipLabel');
+        await browserProxy.whenCalled('getFpsMembershipLabel');
         assertEquals(
             '· 2 sites in google.com\'s group',
             siteEntries[1]!.$.fpsMembership.innerText.trim());
@@ -1768,7 +1315,7 @@
         // set at the eTLD+1 level so it converts to an ungrouped site entry and
         // first party set information remain unchanged.
         assertEquals(testElement.$.allSitesList.items!.length, 2);
-        await localDataBrowserProxy.whenCalled('getFpsMembershipLabel');
+        await browserProxy.whenCalled('getFpsMembershipLabel');
         assertEquals(
             '· 2 sites in google.com\'s group',
             siteEntries[1]!.$.fpsMembership.innerText.trim());
diff --git a/chrome/test/data/webui/settings/cookies_page_test.ts b/chrome/test/data/webui/settings/cookies_page_test.ts
index 791741ac..222563a0 100644
--- a/chrome/test/data/webui/settings/cookies_page_test.ts
+++ b/chrome/test/data/webui/settings/cookies_page_test.ts
@@ -25,7 +25,6 @@
 
   suiteSetup(function() {
     loadTimeData.overrideValues({
-      consolidatedSiteStorageControlsEnabled: false,
       // <if expr="chromeos_lacros">
       isSecondaryUser: false,
       // </if>
@@ -285,91 +284,6 @@
   });
 });
 
-suite('CrSettingsCookiesPageTest_consolidatedControlsDisabled', function() {
-  let page: SettingsCookiesPageElement;
-  let settingsPrefs: SettingsPrefsElement;
-
-  suiteSetup(function() {
-    settingsPrefs = document.createElement('settings-prefs');
-    return CrSettingsPrefs.initialized;
-  });
-
-  setup(function() {
-    document.body.innerHTML =
-        window.trustedTypes!.emptyHTML as unknown as string;
-    page = document.createElement('settings-cookies-page');
-    page.prefs = settingsPrefs.prefs!;
-    page.set('prefs.generated.cookie_session_only', {
-      value: false,
-    });
-    page.set('prefs.privacy_sandbox.apis_enabled_v2.value', true);
-    page.set(
-        'prefs.generated.cookie_primary_setting.value',
-        CookiePrimarySetting.ALLOW_ALL);
-    document.body.appendChild(page);
-    flush();
-  });
-
-  teardown(function() {
-    page.remove();
-    Router.getInstance().resetRouteForTesting();
-  });
-
-  test('AllSiteDataLink_consolidatedControlsDisabled', function() {
-    const siteDataLinkRow =
-        page.shadowRoot!.querySelector<CrLinkRowElement>('#site-data-trigger')!;
-    assertEquals(siteDataLinkRow.label, page.i18n('siteSettingsCookieLink'));
-
-    siteDataLinkRow.click();
-    assertEquals(
-        Router.getInstance().getCurrentRoute(), routes.SITE_SETTINGS_SITE_DATA);
-  });
-});
-
-suite('CrSettingsCookiesPageTest_consolidatedControlsEnabled', function() {
-  let page: SettingsCookiesPageElement;
-  let settingsPrefs: SettingsPrefsElement;
-
-  suiteSetup(function() {
-    loadTimeData.overrideValues({
-      consolidatedSiteStorageControlsEnabled: true,
-    });
-    settingsPrefs = document.createElement('settings-prefs');
-    return CrSettingsPrefs.initialized;
-  });
-
-  setup(function() {
-    document.body.innerHTML =
-        window.trustedTypes!.emptyHTML as unknown as string;
-    page = document.createElement('settings-cookies-page');
-    page.prefs = settingsPrefs.prefs!;
-    page.set('prefs.generated.cookie_session_only', {
-      value: false,
-    });
-    page.set('prefs.privacy_sandbox.apis_enabled_v2.value', true);
-    page.set(
-        'prefs.generated.cookie_primary_setting.value',
-        CookiePrimarySetting.ALLOW_ALL);
-    document.body.appendChild(page);
-    flush();
-  });
-
-  teardown(function() {
-    page.remove();
-    Router.getInstance().resetRouteForTesting();
-  });
-
-  test('AllSiteDataLink_consolidatedControlsEnabled', function() {
-    const siteDataLinkRow =
-        page.shadowRoot!.querySelector<CrLinkRowElement>('#site-data-trigger')!;
-    assertEquals(siteDataLinkRow.label, page.i18n('cookiePageAllSitesLink'));
-
-    siteDataLinkRow.click();
-    assertEquals(
-        Router.getInstance().getCurrentRoute(), routes.SITE_SETTINGS_ALL);
-  });
-});
-
 // <if expr="chromeos_lacros">
 suite('CrSettingsCookiesPageTest_lacrosSecondaryProfile', function() {
   let page: SettingsCookiesPageElement;
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index b26b2b5e..0e07062 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -688,15 +688,6 @@
   get browsePreload() {
     return 'chrome://settings/test_loader.html?module=settings/cookies_page_test.js';
   }
-
-  /** @override */
-  get featureListInternal() {
-    return {
-      enabled: [
-        'features::kConsolidatedSiteStorageControls',
-      ],
-    };
-  }
 };
 
 // Flaky on MacOS bots and times out on Linux Dbg: https://crbug.com/1240747
@@ -713,50 +704,6 @@
   runMochaSuite('CrSettingsCookiesPageTest_FirstPartySetsUIEnabled');
 });
 
-// Flaky on MacOS bots and times out on Linux Dbg: https://crbug.com/1240747
-GEN('#if (BUILDFLAG(IS_MAC)) || (BUILDFLAG(IS_LINUX) && !defined(NDEBUG))');
-GEN('#define MAYBE_ConsolidatedControlsEnabled DISABLED_ConsolidatedControlsEnabled');
-GEN('#else');
-GEN('#define MAYBE_ConsolidatedControlsEnabled ConsolidatedControlsEnabled');
-GEN('#endif');
-TEST_F(
-    'CrSettingsCookiesPageTest', 'MAYBE_ConsolidatedControlsEnabled',
-    function() {
-      runMochaSuite('CrSettingsCookiesPageTest_consolidatedControlsEnabled');
-    });
-
-var CrSettingsCookiesPageConsolidatedDisabledTest =
-    class extends CrSettingsBrowserTest {
-  /** @override */
-  get browsePreload() {
-    return 'chrome://settings/test_loader.html?module=settings/cookies_page_test.js';
-  }
-
-  /** @override */
-  get featureListInternal() {
-    return {
-      disabled: [
-        'features::kConsolidatedSiteStorageControls',
-        // TODO(crbug.com/1238757)- Remove this when consolidated storage
-        // launches.
-        'privacy_sandbox::kPrivacySandboxSettings3',
-      ],
-    };
-  }
-};
-
-// Flaky on MacOS bots and times out on Linux Dbg: https://crbug.com/1240747
-GEN('#if (BUILDFLAG(IS_MAC)) || (BUILDFLAG(IS_LINUX) && !defined(NDEBUG))');
-GEN('#define MAYBE_ConsolidatedControlsDisabled DISABLED_ConsolidatedControlsDisabled');
-GEN('#else');
-GEN('#define MAYBE_ConsolidatedControlsDisabled ConsolidatedControlsDisaled');
-GEN('#endif');
-TEST_F(
-    'CrSettingsCookiesPageConsolidatedDisabledTest',
-    'MAYBE_ConsolidatedControlsDisabled', function() {
-      runMochaSuite('CrSettingsCookiesPageTest_consolidatedControlsDisabled');
-    });
-
 var CrSettingsRouteTest = class extends CrSettingsBrowserTest {
   /** @override */
   get browsePreload() {
@@ -811,52 +758,6 @@
 });
 
 
-var CrSettingsSiteDataTest = class extends CrSettingsBrowserTest {
-  /** @override */
-  get browsePreload() {
-    return 'chrome://settings/test_loader.html?module=settings/site_data_test.js';
-  }
-
-  /** @override */
-  get featureList() {
-    return {
-      disabled: [
-        'features::kConsolidatedSiteStorageControls',
-        // TODO(crbug.com/1238757)- Remove this when consolidated storage
-        // launches.
-        'privacy_sandbox::kPrivacySandboxSettings3',
-      ],
-    };
-  }
-};
-
-TEST_F('CrSettingsSiteDataTest', 'All', function() {
-  mocha.run();
-});
-
-var CrSettingsSiteDataDetailsSubpageTest = class extends CrSettingsBrowserTest {
-  /** @override */
-  get browsePreload() {
-    return 'chrome://settings/test_loader.html?module=settings/site_data_details_subpage_tests.js';
-  }
-
-  /** @override */
-  get featureList() {
-    return {
-      disabled: [
-        'features::kConsolidatedSiteStorageControls',
-        // TODO(crbug.com/1238757)- Remove this when consolidated storage
-        // launches.
-        'privacy_sandbox::kPrivacySandboxSettings3',
-      ],
-    };
-  }
-};
-
-TEST_F('CrSettingsSiteDataDetailsSubpageTest', 'All', function() {
-  mocha.run();
-});
-
 var CrSettingsReviewNotificationPermissionsTest =
     class extends CrSettingsBrowserTest {
   /** @override */
diff --git a/chrome/test/data/webui/settings/site_data_details_subpage_tests.ts b/chrome/test/data/webui/settings/site_data_details_subpage_tests.ts
deleted file mode 100644
index 9bb5c3f..0000000
--- a/chrome/test/data/webui/settings/site_data_details_subpage_tests.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// clang-format off
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {CookieDetails, cookieInfo, LocalDataBrowserProxyImpl, SiteDataDetailsSubpageElement} from 'chrome://settings/lazy_load.js';
-import {MetricsBrowserProxyImpl, PrivacyElementInteractions, Router,routes} from 'chrome://settings/settings.js';
-import {assertEquals} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
-
-import {TestLocalDataBrowserProxy} from './test_local_data_browser_proxy.js';
-import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js';
-
-// clang-format on
-
-/** @fileoverview Suite of tests for site-data-details-subpage. */
-suite('SiteDataDetailsSubpage', function() {
-  let page: SiteDataDetailsSubpageElement;
-
-  let browserProxy: TestLocalDataBrowserProxy;
-
-  let testMetricsBrowserProxy: TestMetricsBrowserProxy;
-
-  const cookieDetails: CookieDetails&{[key: string]: string | boolean} = {
-    accessibleToScript: 'Yes',
-    content: 'dummy_cookie_contents',
-    created: 'Tuesday, February 7, 2017 at 11:28:45 AM',
-    domain: '.foo.com',
-    expires: 'Wednesday, February 7, 2018 at 11:28:45 AM',
-    hasChildren: false,
-    id: '328',
-    idPath: '74,165,328',
-    name: 'abcd',
-    path: '/',
-    sendfor: 'Any kind of connection',
-    title: 'abcd',
-    totalUsage: '1kB',
-    type: 'cookie',
-  };
-
-  const site: string = 'foo.com';
-
-  setup(function() {
-    browserProxy = new TestLocalDataBrowserProxy();
-    browserProxy.setCookieDetails([cookieDetails]);
-    LocalDataBrowserProxyImpl.setInstance(browserProxy);
-    testMetricsBrowserProxy = new TestMetricsBrowserProxy();
-    MetricsBrowserProxyImpl.setInstance(testMetricsBrowserProxy);
-    document.body.innerHTML =
-        window.trustedTypes!.emptyHTML as unknown as string;
-    page = document.createElement('site-data-details-subpage');
-    Router.getInstance().navigateTo(
-        routes.SITE_SETTINGS_DATA_DETAILS, new URLSearchParams('site=' + site));
-
-    document.body.appendChild(page);
-  });
-
-  teardown(function() {
-    Router.getInstance().resetRouteForTesting();
-  });
-
-  test('DetailsShownForCookie', async function() {
-    const actualSite: string =
-        await browserProxy.whenCalled('getCookieDetails');
-    assertEquals(site, actualSite);
-
-    flush();
-    const entries = page.shadowRoot!.querySelectorAll('.cr-row');
-    assertEquals(1, entries.length);
-
-    const listItems = page.shadowRoot!.querySelectorAll('.list-item');
-    // |cookieInfo| is a global var defined in
-    // site_settings/cookie_info.js, and specifies the fields that are
-    // shown for a cookie.
-    assertEquals(cookieInfo['cookie']!.length, listItems.length);
-
-    // Check that all the cookie information is presented in the DOM.
-    const cookieDetailValues =
-        page.shadowRoot!.querySelectorAll<HTMLElement>('.secondary');
-    cookieDetailValues.forEach(function(div: HTMLElement, i: number) {
-      const key = cookieInfo['cookie']![i]![0]!;
-      assertEquals(cookieDetails[key], div.textContent);
-    });
-  });
-
-  test('InteractionMetrics', async function() {
-    // Confirm that various page interactions record the appropriate metric.
-    await flushTasks();
-    page.shadowRoot!.querySelector<HTMLElement>('.icon-clear')!.click();
-    let metric =
-        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
-    assertEquals(PrivacyElementInteractions.COOKIE_DETAILS_REMOVE_ITEM, metric);
-    testMetricsBrowserProxy.reset();
-
-    // removeAll is public on the element to allow it to be called from a button
-    // located in the enclosing settings-subpage element. It is not bound to
-    // interactions with any part of the element under test, and is thus called
-    // directly from the test.
-    page.removeAll();
-    metric =
-        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
-    assertEquals(PrivacyElementInteractions.COOKIE_DETAILS_REMOVE_ALL, metric);
-  });
-});
diff --git a/chrome/test/data/webui/settings/site_data_test.ts b/chrome/test/data/webui/settings/site_data_test.ts
deleted file mode 100644
index 1925440..0000000
--- a/chrome/test/data/webui/settings/site_data_test.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// clang-format off
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {LocalDataBrowserProxyImpl, SiteDataElement} from 'chrome://settings/lazy_load.js';
-import {MetricsBrowserProxyImpl, PrivacyElementInteractions, Router,routes} from 'chrome://settings/settings.js';
-import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {eventToPromise} from 'chrome://webui-test/test_util.js';
-import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
-
-import {TestLocalDataBrowserProxy} from './test_local_data_browser_proxy.js';
-import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js';
-
-// clang-format on
-
-suite('SiteDataTest', function() {
-  let siteData: SiteDataElement;
-
-  let testBrowserProxy: TestLocalDataBrowserProxy;
-
-  let testMetricsBrowserProxy: TestMetricsBrowserProxy;
-
-  setup(function() {
-    Router.getInstance().navigateTo(routes.SITE_SETTINGS);
-    testMetricsBrowserProxy = new TestMetricsBrowserProxy();
-    MetricsBrowserProxyImpl.setInstance(testMetricsBrowserProxy);
-    testBrowserProxy = new TestLocalDataBrowserProxy();
-    LocalDataBrowserProxyImpl.setInstance(testBrowserProxy);
-    siteData = document.createElement('site-data');
-    siteData.filter = '';
-  });
-
-  teardown(function() {
-    siteData.remove();
-  });
-
-  test('remove button (trash) calls remove on origin', async function() {
-    const sites = [
-      {site: 'Hello', localData: 'Cookiez!'},
-    ];
-    testBrowserProxy.setCookieList(sites);
-    document.body.appendChild(siteData);
-    Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
-
-    await eventToPromise('site-data-list-complete', siteData);
-    flush();
-    const button =
-        siteData.shadowRoot!.querySelector('site-data-entry')!.shadowRoot!
-            .querySelector<HTMLElement>('.icon-delete-gray');
-    assertTrue(!!button);
-    assertEquals('CR-ICON-BUTTON', button.tagName);
-    button.click();
-    const path = await testBrowserProxy.whenCalled('removeSite');
-    assertEquals('Hello', path);
-    const metric =
-        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
-    assertEquals(PrivacyElementInteractions.SITE_DATA_REMOVE_SITE, metric);
-  });
-
-  test('remove button hidden when no search results', async function() {
-    const sites = [
-      {site: 'Hello', localData: 'Cookiez!'},
-      {site: 'World', localData: 'Cookiez!'},
-    ];
-    testBrowserProxy.setCookieList(sites);
-    document.body.appendChild(siteData);
-    Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
-
-    await eventToPromise('site-data-list-complete', siteData);
-    assertEquals(2, siteData.$.list.items!.length);
-    siteData.filter = 'Hello';
-    await eventToPromise('site-data-list-complete', siteData);
-    assertEquals(1, siteData.$.list.items!.length);
-  });
-
-  test('calls reloadCookies() when created', async function() {
-    Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
-    document.body.appendChild(siteData);
-    Router.getInstance().navigateTo(routes.COOKIES);
-    await testBrowserProxy.whenCalled('reloadCookies');
-  });
-
-  test('calls reloadCookies() when visited again', async function() {
-    document.body.appendChild(siteData);
-    Router.getInstance().navigateTo(routes.COOKIES);
-    testBrowserProxy.reset();
-    Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
-    await testBrowserProxy.whenCalled('reloadCookies');
-  });
-
-  test('no call to reloadCookies() on same route navigation', async function() {
-    // Check that providing a search query parameter while navigating and a
-    // search filter to the cookies page does not reload cookies, but instead
-    // updates the list.
-    document.body.appendChild(siteData);
-    Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
-    await testBrowserProxy.whenCalled('reloadCookies');
-
-    Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
-    await flushTasks();
-    assertEquals(1, testBrowserProxy.getCallCount('reloadCookies'));
-  });
-
-  test('remove button records interaction metric', async function() {
-    // Check that the remove button correctly records an interaction metric
-    // based on whether the list is filtered or not.
-    document.body.appendChild(siteData);
-    siteData.$.removeShowingSites.click();
-    flush();
-
-    siteData.shadowRoot!.querySelector<HTMLElement>('.action-button')!.click();
-    let metric =
-        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
-    assertEquals(PrivacyElementInteractions.SITE_DATA_REMOVE_ALL, metric);
-    testMetricsBrowserProxy.reset();
-
-    // Add a filter and repeat.
-    siteData.filter = 'Test';
-    siteData.$.removeShowingSites.click();
-    flush();
-
-    siteData.shadowRoot!.querySelector<HTMLElement>('.action-button')!.click();
-    metric =
-        await testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram');
-    assertEquals(PrivacyElementInteractions.SITE_DATA_REMOVE_FILTERED, metric);
-  });
-
-  test('changes to filter update list', async function() {
-    // Check that updating the page filter correctly calls update display list.
-    document.body.appendChild(siteData);
-    Router.getInstance().navigateTo(routes.COOKIES);
-    flush();
-
-    // Changes to the filter while not on the site data page should not be
-    // responded to.
-    siteData.set('filter', 'Test');
-    await flushTasks();
-    assertEquals(0, testBrowserProxy.getCallCount('getDisplayList'));
-
-    Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
-    let filter = await testBrowserProxy.whenCalled('getDisplayList');
-    assertEquals('Test', filter);
-    testBrowserProxy.reset();
-
-    siteData.set('filter', 'Test2');
-    filter = await testBrowserProxy.whenCalled('getDisplayList');
-    assertEquals('Test2', filter);
-  });
-});
diff --git a/chrome/test/data/webui/settings/site_entry_tests.ts b/chrome/test/data/webui/settings/site_entry_tests.ts
index 05a7c81b..525b7b5 100644
--- a/chrome/test/data/webui/settings/site_entry_tests.ts
+++ b/chrome/test/data/webui/settings/site_entry_tests.ts
@@ -5,20 +5,18 @@
 // clang-format off
 import 'chrome://webui-test/cr_elements/cr_policy_strings.js';
 
-import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {LocalDataBrowserProxyImpl, SiteEntryElement, SiteSettingsPrefsBrowserProxyImpl, SortMethod} from 'chrome://settings/lazy_load.js';
+import {SiteEntryElement, SiteSettingsPrefsBrowserProxyImpl, SortMethod} from 'chrome://settings/lazy_load.js';
 import {Router, routes} from 'chrome://settings/settings.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {eventToPromise, isChildVisible} from 'chrome://webui-test/test_util.js';
 
-import {TestLocalDataBrowserProxy} from './test_local_data_browser_proxy.js';
 import {TestSiteSettingsPrefsBrowserProxy} from './test_site_settings_prefs_browser_proxy.js';
 import {createOriginInfo,createSiteGroup} from './test_util.js';
 
 // clang-format on
 
-suite('SiteEntry_DisabledConsolidatedControls', function() {
+suite('SiteEntry', function() {
   /**
    * An example eTLD+1 Object with multiple origins grouped under it.
    */
@@ -41,27 +39,14 @@
   let browserProxy: TestSiteSettingsPrefsBrowserProxy;
 
   /**
-   * The mock local data proxy object to use during test.
-   */
-  let localDataBrowserProxy: TestLocalDataBrowserProxy;
-
-  /**
    * A site list element created before each test.
    */
   let testElement: SiteEntryElement;
 
-  suiteSetup(function() {
-    loadTimeData.overrideValues({
-      consolidatedSiteStorageControlsEnabled: false,
-    });
-  });
-
   // Initialize a site-list before each test.
   setup(function() {
     browserProxy = new TestSiteSettingsPrefsBrowserProxy();
-    localDataBrowserProxy = new TestLocalDataBrowserProxy();
     SiteSettingsPrefsBrowserProxyImpl.setInstance(browserProxy);
-    LocalDataBrowserProxyImpl.setInstance(localDataBrowserProxy);
 
     document.body.innerHTML =
         window.trustedTypes!.emptyHTML as unknown as string;
@@ -145,41 +130,6 @@
         Router.getInstance().getQueryParameters().get('site'));
   });
 
-  test('with single origin, shows overflow menu', function() {
-    testElement.siteGroup = TEST_SINGLE_SITE_GROUP;
-    flush();
-    const overflowMenuButton =
-        testElement.$$<HTMLElement>('#overflowMenuButton')!;
-    assertFalse(
-        overflowMenuButton.closest<HTMLElement>('.row-aligned')!.hidden);
-  });
-
-  test('clear data for single origin fires the right method', async function() {
-    testElement.siteGroup =
-        JSON.parse(JSON.stringify(TEST_MULTIPLE_SITE_GROUP));
-    flush();
-
-    const collapseChild = testElement.$.originList.get();
-    flush();
-    const originList = collapseChild.querySelectorAll('.hr');
-    assertEquals(3, originList.length);
-
-    for (let i = 0; i < originList.length; i++) {
-      const menuOpened = eventToPromise('open-menu', testElement);
-      const originEntry = originList[i]!;
-      const overflowMenuButton =
-          originEntry.querySelector<HTMLElement>('#originOverflowMenuButton')!;
-      overflowMenuButton.click();
-      const openMenuEvent = await menuOpened;
-
-      const args = openMenuEvent.detail;
-      const {actionScope, index, origin} = args;
-      assertEquals('origin', actionScope);
-      assertEquals(testElement.listIndex, index);
-      assertEquals(testElement.siteGroup.origins[i]!.origin, origin);
-    }
-  });
-
   test(
       'moving from grouped to ungrouped does not get stuck in opened state',
       function() {
@@ -213,7 +163,7 @@
     testElement.siteGroup = testSiteGroup;
 
     flush();
-    const args = await localDataBrowserProxy.whenCalled('getNumCookiesString');
+    const args = await browserProxy.whenCalled('getNumCookiesString');
     assertEquals(3, args);
     assertFalse(cookiesLabel.hidden);
     assertEquals('· 3 cookies', cookiesLabel.textContent!.trim());
@@ -234,7 +184,7 @@
     testElement.siteGroup = testSiteGroup;
 
     flush();
-    const args = await localDataBrowserProxy.whenCalled('getNumCookiesString');
+    const args = await browserProxy.whenCalled('getNumCookiesString');
     assertEquals(3, args);
     assertFalse(cookiesLabel.hidden);
     assertEquals('· 3 cookies', cookiesLabel.textContent!.trim());
@@ -443,57 +393,6 @@
         origins[2]!.querySelector<HTMLElement>(
                        '#originSiteRepresentation')!.innerText.trim());
   });
-});
-
-suite('SiteEntry_EnabledConsolidatedControls', function() {
-  /**
-   * An example eTLD+1 Object with multiple origins grouped under it.
-   */
-  const TEST_MULTIPLE_SITE_GROUP = createSiteGroup('example.com', [
-    'http://example.com',
-    'https://www.example.com',
-    'https://login.example.com',
-  ]);
-  /**
-   * An example eTLD+1 Object with a single origin in it.
-   */
-  const TEST_SINGLE_SITE_GROUP = createSiteGroup('foo.com', [
-    'https://login.foo.com',
-  ]);
-
-  /**
-   * The mock proxy object to use during test.
-   */
-  let browserProxy: TestSiteSettingsPrefsBrowserProxy;
-
-  /**
-   * The mock local data proxy object to use during test.
-   */
-  let localDataBrowserProxy: TestLocalDataBrowserProxy;
-
-  /**
-   * A site list element created before each test.
-   */
-  let testElement: SiteEntryElement;
-
-  suiteSetup(function() {
-    loadTimeData.overrideValues({
-      consolidatedSiteStorageControlsEnabled: true,
-    });
-  });
-
-  // Initialize a site-list before each test.
-  setup(function() {
-    browserProxy = new TestSiteSettingsPrefsBrowserProxy();
-    localDataBrowserProxy = new TestLocalDataBrowserProxy();
-    SiteSettingsPrefsBrowserProxyImpl.setInstance(browserProxy);
-    LocalDataBrowserProxyImpl.setInstance(localDataBrowserProxy);
-
-    document.body.innerHTML =
-        window.trustedTypes!.emptyHTML as unknown as string;
-    testElement = document.createElement('site-entry');
-    document.body.appendChild(testElement);
-  });
 
   test('remove site fires correct event for individual site', async function() {
     testElement.siteGroup =
@@ -628,7 +527,7 @@
     testElement.siteGroup = fooSiteGroup;
     flush();
 
-    await localDataBrowserProxy.whenCalled('getFpsMembershipLabel');
+    await browserProxy.whenCalled('getFpsMembershipLabel');
     // Assert first party set membership information is set correctly.
     assertFalse(fpsMembershipLabel.hidden);
     assertEquals(
diff --git a/chrome/test/data/webui/settings/test_local_data_browser_proxy.ts b/chrome/test/data/webui/settings/test_local_data_browser_proxy.ts
deleted file mode 100644
index 5876c2f7..0000000
--- a/chrome/test/data/webui/settings/test_local_data_browser_proxy.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// clang-format off
-import {CookieDetails, LocalDataBrowserProxy, LocalDataItem} from 'chrome://settings/lazy_load.js';
-import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
-// clang-format on
-
-/**
- * A test version of LocalDataBrowserProxy. Provides helper methods
- * for allowing tests to know when a method was called, as well as
- * specifying mock responses.
- */
-export class TestLocalDataBrowserProxy extends TestBrowserProxy implements
-    LocalDataBrowserProxy {
-  private cookieDetails_: CookieDetails[] = [];
-  private cookieList_: LocalDataItem[] = [];
-  private filteredCookieList_: LocalDataItem[] = [];
-
-  constructor() {
-    super([
-      'getDisplayList',
-      'removeAll',
-      'removeShownItems',
-      'removeItem',
-      'removeSite',
-      'getCookieDetails',
-      'getNumCookiesString',
-      'getFpsMembershipLabel',
-      'reloadCookies',
-      'removeCookie',
-      'removeAllThirdPartyCookies',
-    ]);
-  }
-
-  setCookieDetails(cookieDetails: CookieDetails[]) {
-    this.cookieDetails_ = cookieDetails;
-  }
-
-  setCookieList(cookieList: LocalDataItem[]) {
-    this.cookieList_ = cookieList;
-    this.filteredCookieList_ = cookieList;
-  }
-
-  getDisplayList(filter: string) {
-    this.methodCalled('getDisplayList', filter);
-    if (filter === undefined) {
-      filter = '';
-    }
-    /** @type {!Array<!LocalDataItem>} */
-    const output: LocalDataItem[] = [];
-    for (let i = 0; i < this.cookieList_.length; ++i) {
-      if (this.cookieList_[i]!.site.indexOf(filter) >= 0) {
-        output.push(this.filteredCookieList_[i]!);
-      }
-    }
-    return Promise.resolve(output);
-  }
-
-  removeAll() {
-    this.methodCalled('removeAll');
-    return Promise.resolve();
-  }
-
-  removeShownItems() {
-    this.methodCalled('removeShownItems');
-  }
-
-  removeSite(site: string) {
-    this.methodCalled('removeSite', site);
-  }
-
-  getCookieDetails(site: string) {
-    this.methodCalled('getCookieDetails', site);
-    return Promise.resolve(this.cookieDetails_);
-  }
-
-  getNumCookiesString(numCookies: number) {
-    this.methodCalled('getNumCookiesString', numCookies);
-    return Promise.resolve(
-        `${numCookies} ` + (numCookies === 1 ? 'cookie' : 'cookies'));
-  }
-
-  getFpsMembershipLabel(fpsNumMembers: number, fpsOwner: string) {
-    this.methodCalled('getFpsMembershipLabel', fpsNumMembers, fpsOwner);
-    return Promise.resolve([
-      `${fpsNumMembers}`,
-      (fpsNumMembers === 1 ? 'site' : 'sites'),
-      `in ${fpsOwner}'s group`,
-    ].join(' '));
-  }
-
-  reloadCookies() {
-    this.methodCalled('reloadCookies');
-    return Promise.resolve();
-  }
-
-  removeItem(path: string) {
-    this.methodCalled('removeItem', path);
-  }
-
-  removeAllThirdPartyCookies() {
-    this.methodCalled('removeAllThirdPartyCookies');
-    return Promise.resolve();
-  }
-}
diff --git a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.ts b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.ts
index 97d5558..87d7c325 100644
--- a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.ts
+++ b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.ts
@@ -73,6 +73,8 @@
       'resetNotificationPermissionForOrigin',
       'allowNotificationPermissionForOrigin',
       'undoIgnoreNotificationPermissionForOrigin',
+      'getFpsMembershipLabel',
+      'getNumCookiesString',
     ]);
 
 
@@ -635,4 +637,19 @@
   undoIgnoreNotificationPermissionForOrigin(origin: string): void {
     this.methodCalled('undoIgnoreNotificationPermissionForOrigin', origin);
   }
+
+  getFpsMembershipLabel(fpsNumMembers: number, fpsOwner: string) {
+    this.methodCalled('getFpsMembershipLabel', fpsNumMembers, fpsOwner);
+    return Promise.resolve([
+      `${fpsNumMembers}`,
+      (fpsNumMembers === 1 ? 'site' : 'sites'),
+      `in ${fpsOwner}'s group`,
+    ].join(' '));
+  }
+
+  getNumCookiesString(numCookies: number) {
+    this.methodCalled('getNumCookiesString', numCookies);
+    return Promise.resolve(
+        `${numCookies} ` + (numCookies === 1 ? 'cookie' : 'cookies'));
+  }
 }
diff --git a/chrome/test/data/webui/webui_resource_browsertest.cc b/chrome/test/data/webui/webui_resource_browsertest.cc
index 1de72f4..d43a1527 100644
--- a/chrome/test/data/webui/webui_resource_browsertest.cc
+++ b/chrome/test/data/webui/webui_resource_browsertest.cc
@@ -53,10 +53,6 @@
 }
 #endif
 
-IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, I18nProcessCssTest) {
-  LoadTestUrl("i18n_process_css_test.html");
-}
-
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, MockTimerTest) {
   LoadTestUrl("?module=mock_timer_test.js");
 }
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 4ee1468..25ed918 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -359,6 +359,7 @@
         "activity_impl_linux.cc",
         "app/server/linux/server.cc",
         "app/server/linux/server.h",
+        "device_management/dm_storage_linux.cc",
         "linux/linux_util.cc",
         "linux/linux_util.h",
         "linux/net/network.cc",
diff --git a/chrome/updater/app/server/linux/server.cc b/chrome/updater/app/server/linux/server.cc
index d2a6136..ee7e4dec 100644
--- a/chrome/updater/app/server/linux/server.cc
+++ b/chrome/updater/app/server/linux/server.cc
@@ -7,13 +7,42 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/notreached.h"
 #include "chrome/updater/app/app.h"
+#include "chrome/updater/update_service.h"
+#include "chrome/updater/update_service_internal.h"
 
 namespace updater {
 
+AppServerLinux::AppServerLinux() = default;
+AppServerLinux::~AppServerLinux() = default;
+
 // TODO(crbug.com/1276117) - implement.
-scoped_refptr<App> MakeAppServer() {
+void AppServerLinux::ActiveDuty(scoped_refptr<UpdateService> update_service) {
   NOTIMPLEMENTED();
-  return nullptr;
+}
+
+void AppServerLinux::ActiveDutyInternal(
+    scoped_refptr<UpdateServiceInternal> update_service_internal) {
+  NOTIMPLEMENTED();
+}
+
+bool AppServerLinux::SwapInNewVersion() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool AppServerLinux::MigrateLegacyUpdaters(
+    base::RepeatingCallback<void(const RegistrationRequest&)>
+        register_callback) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+void AppServerLinux::UninstallSelf() {
+  NOTIMPLEMENTED();
+}
+
+scoped_refptr<App> MakeAppServer() {
+  return base::MakeRefCounted<AppServerLinux>();
 }
 
 }  // namespace updater
diff --git a/chrome/updater/app/server/linux/server.h b/chrome/updater/app/server/linux/server.h
index b86ba88..d22fabc 100644
--- a/chrome/updater/app/server/linux/server.h
+++ b/chrome/updater/app/server/linux/server.h
@@ -6,10 +6,31 @@
 #define CHROME_UPDATER_APP_SERVER_LINUX_SERVER_H_
 
 #include "base/memory/scoped_refptr.h"
+#include "chrome/updater/app/app_server.h"
 
 namespace updater {
 
 class App;
+class UpdateService;
+class UpdateServiceInternal;
+
+class AppServerLinux : public AppServer {
+ public:
+  AppServerLinux();
+
+ private:
+  ~AppServerLinux() override;
+
+  // Overrides for AppServer.
+  void ActiveDuty(scoped_refptr<UpdateService> update_service) override;
+  void ActiveDutyInternal(
+      scoped_refptr<UpdateServiceInternal> update_service_internal) override;
+  bool SwapInNewVersion() override;
+  bool MigrateLegacyUpdaters(
+      base::RepeatingCallback<void(const RegistrationRequest&)>
+          register_callback) override;
+  void UninstallSelf() override;
+};
 
 scoped_refptr<App> MakeAppServer();
 
diff --git a/chrome/updater/device_management/dm_storage.cc b/chrome/updater/device_management/dm_storage.cc
index 4c005714..64f04ce 100644
--- a/chrome/updater/device_management/dm_storage.cc
+++ b/chrome/updater/device_management/dm_storage.cc
@@ -70,15 +70,6 @@
 
 }  // namespace
 
-#if BUILDFLAG(IS_LINUX)
-// TODO(crbug.com/1276162) - implement.
-DMStorage::DMStorage(const base::FilePath& policy_cache_root)
-    : policy_cache_root_(policy_cache_root),
-      policy_info_file_(policy_cache_root_.AppendASCII(kPolicyInfoFileName)) {
-  NOTIMPLEMENTED();
-}
-#endif  // BUILDFLAG(IS_LINUX)
-
 DMStorage::DMStorage(const base::FilePath& policy_cache_root,
                      std::unique_ptr<TokenServiceInterface> token_service)
     : policy_cache_root_(policy_cache_root),
@@ -215,12 +206,4 @@
   return omaha_settings;
 }
 
-#if BUILDFLAG(IS_LINUX)
-// TODO(crbug.com/1276162) - implement.
-scoped_refptr<DMStorage> GetDefaultDMStorage() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-#endif
-
 }  // namespace updater
diff --git a/chrome/updater/device_management/dm_storage_linux.cc b/chrome/updater/device_management/dm_storage_linux.cc
new file mode 100644
index 0000000..09cab3d
--- /dev/null
+++ b/chrome/updater/device_management/dm_storage_linux.cc
@@ -0,0 +1,107 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_refptr.h"
+#include "chrome/updater/device_management/dm_storage.h"
+
+#include <string>
+
+#include "base/check.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/strings/string_util.h"
+#include "chrome/updater/updater_branding.h"
+
+namespace updater {
+namespace {
+
+constexpr char kEnrollmentTokenFilepath[] =
+    "/opt/" COMPANY_SHORTNAME_STRING "/" PRODUCT_FULLNAME_STRING
+    "/CloudManagementEnrollmentToken";
+constexpr char kDmTokenFilepath[] =
+    "/opt/" COMPANY_SHORTNAME_STRING "/" PRODUCT_FULLNAME_STRING
+    "/CloudManagement";
+
+std::string GetMachineId() {
+  std::string machine_id;
+  if (!base::ReadFileToString(base::FilePath("/etc/machine-id"), &machine_id))
+    return std::string();
+  return machine_id;
+}
+
+// Reads a token from the given file. Returns the empty string if the file could
+// not be read.
+std::string LoadTokenFromFile(const std::string& token_file_path) {
+  std::string token_value;
+  if (!base::ReadFileToString(base::FilePath(token_file_path), &token_value))
+    return std::string();
+
+  return std::string(base::TrimWhitespaceASCII(token_value, base::TRIM_ALL));
+}
+}  // namespace
+
+class TokenService : public TokenServiceInterface {
+ public:
+  TokenService() = default;
+  ~TokenService() override = default;
+
+  // Overrides for TokenServiceInterface.
+  std::string GetDeviceID() const override { return device_id_; }
+
+  bool IsEnrollmentMandatory() const override {
+    // TODO(crbug.com/1345407) : check if enrollment is mandatory.
+    return false;
+  }
+
+  bool StoreEnrollmentToken(const std::string& enrollment_token) override {
+    if (!base::ImportantFileWriter::WriteFileAtomically(
+            base::FilePath(kEnrollmentTokenFilepath), enrollment_token)) {
+      return false;
+    }
+
+    enrollment_token_ = enrollment_token;
+    return true;
+  }
+
+  std::string GetEnrollmentToken() const override { return enrollment_token_; }
+
+  bool StoreDmToken(const std::string& dm_token) override {
+    if (!base::ImportantFileWriter::WriteFileAtomically(
+            base::FilePath(kDmTokenFilepath), dm_token)) {
+      return false;
+    }
+    dm_token_ = dm_token;
+    return true;
+  }
+
+  bool DeleteDmToken() override {
+    if (!base::DeleteFile(base::FilePath(kDmTokenFilepath))) {
+      return false;
+    }
+    dm_token_.clear();
+    return true;
+  }
+
+  std::string GetDmToken() const override { return dm_token_; }
+
+ private:
+  // Cached values in memory.
+  const std::string device_id_ = GetMachineId();
+  std::string enrollment_token_ = LoadTokenFromFile(kEnrollmentTokenFilepath);
+  std::string dm_token_ = LoadTokenFromFile(kDmTokenFilepath);
+};
+
+DMStorage::DMStorage(const base::FilePath& policy_cache_root)
+    : DMStorage(policy_cache_root, std::make_unique<TokenService>()) {}
+
+scoped_refptr<DMStorage> GetDefaultDMStorage() {
+  return base::MakeRefCounted<DMStorage>(
+      base::FilePath("/opt")
+          .AppendASCII(COMPANY_SHORTNAME_STRING)
+          .AppendASCII(PRODUCT_FULLNAME_STRING)
+          .AppendASCII("DeviceManagement"));
+}
+
+}  // namespace updater
diff --git a/chrome/updater/linux/linux_util.cc b/chrome/updater/linux/linux_util.cc
index 89f0fc09..a46b74b 100644
--- a/chrome/updater/linux/linux_util.cc
+++ b/chrome/updater/linux/linux_util.cc
@@ -7,7 +7,7 @@
 #include "base/base_paths.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
-#include "chrome/updater/updater_branding.h"
+#include "chrome/updater/constants.h"
 #include "chrome/updater/updater_scope.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -39,7 +39,7 @@
 }
 
 base::FilePath GetExecutableRelativePath() {
-  return base::FilePath(PRODUCT_FULLNAME_STRING);
+  return base::FilePath(kExecutableName);
 }
 
 }  // namespace updater
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index cf5c4e67..91305ef 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -750,14 +750,7 @@
 
 #if BUILDFLAG(CHROMIUM_BRANDING) || BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #if !defined(COMPONENT_BUILD)
-// Disabled on Windows due to undiagnosed typelib errors even after
-// instrumenting the build; see https://crbug.com/1341471.
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_SelfUpdateFromOldReal DISABLED_SelfUpdateFromOldReal
-#else
-#define MAYBE_SelfUpdateFromOldReal SelfUpdateFromOldReal
-#endif
-TEST_F(IntegrationTest, MAYBE_SelfUpdateFromOldReal) {
+TEST_F(IntegrationTest, SelfUpdateFromOldReal) {
   ScopedServer test_server(test_commands_);
 
   SetupRealUpdaterLowerVersion();
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index b0eedbb..3cf8355 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-15180.0.0
\ No newline at end of file
+15182.0.0
\ No newline at end of file
diff --git a/chromeos/ash/components/BUILD.gn b/chromeos/ash/components/BUILD.gn
index 46756e3..a1f9f8e 100644
--- a/chromeos/ash/components/BUILD.gn
+++ b/chromeos/ash/components/BUILD.gn
@@ -40,6 +40,7 @@
     "//chromeos/ash/components/smbfs:unit_tests",
     "//chromeos/ash/components/string_matching:unit_tests",
     "//chromeos/ash/components/sync_wifi:unit_tests",
+    "//chromeos/ash/components/tether:unit_tests",
     "//chromeos/ash/components/timezone:unit_tests",
     "//chromeos/ash/components/tpm:unit_tests",
     "//chromeos/ash/components/trash_service:unit_tests",
diff --git a/chromeos/ash/components/language/language_packs/language_pack_manager.cc b/chromeos/ash/components/language/language_packs/language_pack_manager.cc
index 9d1720a..44e7a4036 100644
--- a/chromeos/ash/components/language/language_packs/language_pack_manager.cc
+++ b/chromeos/ash/components/language/language_packs/language_pack_manager.cc
@@ -20,6 +20,17 @@
 namespace ash::language_packs {
 namespace {
 
+// Feature IDs.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+// See enum LanguagePackFeatureIds in tools/metrics/histograms/enums.xml.
+enum class FeatureIdsEnum {
+  kUnknown = 0,
+  kHandwriting = 1,
+  kTts = 2,
+  kMaxValue = kTts,
+};
+
 // PackResult that is returned by an invalid feature ID is specified.
 PackResult CreateInvalidDlcPackResult() {
   return {
@@ -180,6 +191,18 @@
   std::move(callback).Run(result);
 }
 
+// This function returns the enum value of a feature ID that matches the
+// corresponding value in the UMA Histogram enum.
+FeatureIdsEnum GetFeatureIdValueForUma(const std::string& feature_id) {
+  if (feature_id == kHandwritingFeatureId)
+    return FeatureIdsEnum::kHandwriting;
+  if (feature_id == kTtsFeatureId)
+    return FeatureIdsEnum::kTts;
+
+  // Default value of unknown.
+  return FeatureIdsEnum::kUnknown;
+}
+
 }  // namespace
 
 bool LanguagePackManager::IsPackAvailable(const std::string& feature_id,
@@ -221,6 +244,8 @@
 
   base::UmaHistogramSparse("ChromeOS.LanguagePacks.GetPackState.LanguageCode",
                            static_cast<int32_t>(base::PersistentHash(locale)));
+  base::UmaHistogramEnumeration("ChromeOS.LanguagePacks.GetPackState.FeatureId",
+                                GetFeatureIdValueForUma(feature_id));
 
   DlcserviceClient::Get()->GetDlcState(
       *dlc_id, base::BindOnce(&OnGetDlcState, std::move(callback)));
diff --git a/ash/components/tether/BUILD.gn b/chromeos/ash/components/tether/BUILD.gn
similarity index 97%
rename from ash/components/tether/BUILD.gn
rename to chromeos/ash/components/tether/BUILD.gn
index c223e29e..b0996a64 100644
--- a/ash/components/tether/BUILD.gn
+++ b/chromeos/ash/components/tether/BUILD.gn
@@ -117,7 +117,6 @@
   ]
 
   deps = [
-    "//ash/components/tether/proto",
     "//ash/constants",
     "//ash/services/device_sync/public/cpp",
     "//ash/services/multidevice_setup/public/cpp:cpp",
@@ -127,6 +126,7 @@
     "//base",
     "//chromeos/ash/components/multidevice/logging",
     "//chromeos/ash/components/network",
+    "//chromeos/ash/components/tether/proto",
     "//chromeos/dbus/power",
     "//chromeos/login/login_state",
     "//components/pref_registry",
@@ -200,7 +200,6 @@
   public_deps = [ ":tether" ]
 
   deps = [
-    "//ash/components/tether/proto",
     "//ash/services/device_sync/public/cpp:test_support",
     "//ash/services/secure_channel/public/cpp/client:test_support",
     "//ash/services/secure_channel/public/cpp/shared",
@@ -209,6 +208,7 @@
     "//chromeos/ash/components/multidevice",
     "//chromeos/ash/components/multidevice:test_support",
     "//chromeos/ash/components/network:test_support",
+    "//chromeos/ash/components/tether/proto",
     "//device/bluetooth",
     "//testing/gmock",
     "//testing/gtest",
@@ -262,7 +262,6 @@
   deps = [
     ":test_support",
     ":tether",
-    "//ash/components/tether/proto",
     "//ash/services/device_sync:test_support",
     "//ash/services/device_sync/public/cpp",
     "//ash/services/device_sync/public/cpp:test_support",
@@ -270,12 +269,14 @@
     "//ash/services/multidevice_setup/public/cpp:test_support",
     "//ash/services/multidevice_setup/public/mojom:mojom",
     "//ash/services/secure_channel:test_support",
+    "//ash/services/secure_channel/public/cpp/client",
     "//ash/services/secure_channel/public/cpp/client:test_support",
     "//ash/services/secure_channel/public/cpp/shared",
     "//base/test:test_support",
     "//chromeos/ash/components/multidevice",
     "//chromeos/ash/components/multidevice:test_support",
     "//chromeos/ash/components/network:test_support",
+    "//chromeos/ash/components/tether/proto",
     "//chromeos/dbus/power",
     "//chromeos/login/login_state",
     "//components/prefs:test_support",
diff --git a/ash/components/tether/COMMON_METADATA b/chromeos/ash/components/tether/COMMON_METADATA
similarity index 100%
rename from ash/components/tether/COMMON_METADATA
rename to chromeos/ash/components/tether/COMMON_METADATA
diff --git a/chromeos/ash/components/tether/DEPS b/chromeos/ash/components/tether/DEPS
new file mode 100644
index 0000000..54053c8
--- /dev/null
+++ b/chromeos/ash/components/tether/DEPS
@@ -0,0 +1,16 @@
+include_rules = [
+  "+ash/services/device_sync/public/cpp",
+  "+ash/services/multidevice_setup/public",
+  "+ash/services/secure_channel/public",
+  "+chromeos/ash/components/multidevice",
+  "+chromeos/ash/components/network",
+  "+device/bluetooth",
+  "+components/session_manager/core",
+]
+
+specific_include_rules = {
+  ".*unittest\.cc": [
+    "+ash/services/device_sync",
+    "+components/sync_preferences/testing_pref_service_syncable.h",
+  ]
+}
diff --git a/chromeos/ash/components/tether/DIR_METADATA b/chromeos/ash/components/tether/DIR_METADATA
new file mode 100644
index 0000000..9af97369
--- /dev/null
+++ b/chromeos/ash/components/tether/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chromeos/ash/components/tether/COMMON_METADATA"
diff --git a/ash/components/tether/OWNERS b/chromeos/ash/components/tether/OWNERS
similarity index 100%
rename from ash/components/tether/OWNERS
rename to chromeos/ash/components/tether/OWNERS
diff --git a/ash/components/tether/active_host.cc b/chromeos/ash/components/tether/active_host.cc
similarity index 97%
rename from ash/components/tether/active_host.cc
rename to chromeos/ash/components/tether/active_host.cc
index 4e417b5..b8d43e4 100644
--- a/ash/components/tether/active_host.cc
+++ b/chromeos/ash/components/tether/active_host.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
-#include "ash/components/tether/pref_names.h"
-#include "ash/components/tether/tether_host_fetcher.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
+#include "chromeos/ash/components/tether/pref_names.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
diff --git a/ash/components/tether/active_host.h b/chromeos/ash/components/tether/active_host.h
similarity index 97%
rename from ash/components/tether/active_host.h
rename to chromeos/ash/components/tether/active_host.h
index 94ab199f..acd7c64 100644
--- a/ash/components/tether/active_host.h
+++ b/chromeos/ash/components/tether/active_host.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 ASH_COMPONENTS_TETHER_ACTIVE_HOST_H_
-#define ASH_COMPONENTS_TETHER_ACTIVE_HOST_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_ACTIVE_HOST_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_ACTIVE_HOST_H_
 
 #include <string>
 
@@ -165,4 +165,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_ACTIVE_HOST_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_ACTIVE_HOST_H_
diff --git a/ash/components/tether/active_host_network_state_updater.cc b/chromeos/ash/components/tether/active_host_network_state_updater.cc
similarity index 95%
rename from ash/components/tether/active_host_network_state_updater.cc
rename to chromeos/ash/components/tether/active_host_network_state_updater.cc
index 4bfc5e2..976b5b0d 100644
--- a/ash/components/tether/active_host_network_state_updater.cc
+++ b/chromeos/ash/components/tether/active_host_network_state_updater.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/active_host_network_state_updater.h"
+#include "chromeos/ash/components/tether/active_host_network_state_updater.h"
 
-#include "ash/components/tether/active_host.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/active_host_network_state_updater.h b/chromeos/ash/components/tether/active_host_network_state_updater.h
similarity index 78%
rename from ash/components/tether/active_host_network_state_updater.h
rename to chromeos/ash/components/tether/active_host_network_state_updater.h
index 1fea882f..59bcfc8 100644
--- a/ash/components/tether/active_host_network_state_updater.h
+++ b/chromeos/ash/components/tether/active_host_network_state_updater.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_ACTIVE_HOST_NETWORK_STATE_UPDATER_H_
-#define ASH_COMPONENTS_TETHER_ACTIVE_HOST_NETWORK_STATE_UPDATER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_ACTIVE_HOST_NETWORK_STATE_UPDATER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_ACTIVE_HOST_NETWORK_STATE_UPDATER_H_
 
-#include "ash/components/tether/active_host.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
 namespace ash {
 
@@ -40,4 +40,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_ACTIVE_HOST_NETWORK_STATE_UPDATER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_ACTIVE_HOST_NETWORK_STATE_UPDATER_H_
diff --git a/ash/components/tether/active_host_network_state_updater_unittest.cc b/chromeos/ash/components/tether/active_host_network_state_updater_unittest.cc
similarity index 96%
rename from ash/components/tether/active_host_network_state_updater_unittest.cc
rename to chromeos/ash/components/tether/active_host_network_state_updater_unittest.cc
index 5eab3af..591f8b8 100644
--- a/ash/components/tether/active_host_network_state_updater_unittest.cc
+++ b/chromeos/ash/components/tether/active_host_network_state_updater_unittest.cc
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/active_host_network_state_updater.h"
+#include "chromeos/ash/components/tether/active_host_network_state_updater.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_active_host.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/task_environment.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
diff --git a/ash/components/tether/active_host_unittest.cc b/chromeos/ash/components/tether/active_host_unittest.cc
similarity index 98%
rename from ash/components/tether/active_host_unittest.cc
rename to chromeos/ash/components/tether/active_host_unittest.cc
index d724a62..f2b1b4d 100644
--- a/ash/components/tether/active_host_unittest.cc
+++ b/chromeos/ash/components/tether/active_host_unittest.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_tether_host_fetcher.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/fake_tether_host_fetcher.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/ash/components/tether/asynchronous_shutdown_object_container.h b/chromeos/ash/components/tether/asynchronous_shutdown_object_container.h
similarity index 86%
rename from ash/components/tether/asynchronous_shutdown_object_container.h
rename to chromeos/ash/components/tether/asynchronous_shutdown_object_container.h
index c4b4a2d..cc000ec 100644
--- a/ash/components/tether/asynchronous_shutdown_object_container.h
+++ b/chromeos/ash/components/tether/asynchronous_shutdown_object_container.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 ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
-#define ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
 
 #include "base/callback_forward.h"
 
@@ -47,4 +47,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
diff --git a/ash/components/tether/asynchronous_shutdown_object_container_impl.cc b/chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.cc
similarity index 93%
rename from ash/components/tether/asynchronous_shutdown_object_container_impl.cc
rename to chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.cc
index d8b0da84..c23230e 100644
--- a/ash/components/tether/asynchronous_shutdown_object_container_impl.cc
+++ b/chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/asynchronous_shutdown_object_container_impl.h"
+#include "chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.h"
 
-#include "ash/components/tether/disconnect_tethering_request_sender_impl.h"
-#include "ash/components/tether/network_configuration_remover.h"
-#include "ash/components/tether/wifi_hotspot_disconnector_impl.h"
 #include "ash/services/device_sync/public/cpp/device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ptr_util.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender_impl.h"
+#include "chromeos/ash/components/tether/network_configuration_remover.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/asynchronous_shutdown_object_container_impl.h b/chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.h
similarity index 90%
rename from ash/components/tether/asynchronous_shutdown_object_container_impl.h
rename to chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.h
index 911901a..f3ca491 100644
--- a/ash/components/tether/asynchronous_shutdown_object_container_impl.h
+++ b/chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
 
 #include <memory>
 
-#include "ash/components/tether/asynchronous_shutdown_object_container.h"
-#include "ash/components/tether/disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/asynchronous_shutdown_object_container.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender.h"
 // TODO(https://crbug.com/1164001): move to forward declaration
 #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/callback.h"
@@ -103,7 +103,6 @@
   void SetTestDoubles(std::unique_ptr<DisconnectTetheringRequestSender>
                           disconnect_tethering_request_sender);
 
-
   TetherHostFetcher* tether_host_fetcher_;
   std::unique_ptr<DisconnectTetheringRequestSender>
       disconnect_tethering_request_sender_;
@@ -118,4 +117,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
diff --git a/ash/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc b/chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc
similarity index 95%
rename from ash/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc
rename to chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc
index b789098e..d86698c 100644
--- a/ash/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc
+++ b/chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc
@@ -2,13 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/asynchronous_shutdown_object_container_impl.h"
+#include "chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_disconnect_tethering_request_sender.h"
-#include "ash/components/tether/fake_tether_host_fetcher.h"
-#include "ash/components/tether/tether_component_impl.h"
 #include "ash/services/device_sync/fake_remote_device_provider.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/device_sync/remote_device_provider_impl.h"
@@ -17,6 +14,9 @@
 #include "base/memory/ptr_util.h"
 #include "base/test/task_environment.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/fake_tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/tether_component_impl.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ash/components/tether/connect_tethering_operation.cc b/chromeos/ash/components/tether/connect_tethering_operation.cc
similarity index 96%
rename from ash/components/tether/connect_tethering_operation.cc
rename to chromeos/ash/components/tether/connect_tethering_operation.cc
index 043f5bd..5805ca0 100644
--- a/ash/components/tether/connect_tethering_operation.cc
+++ b/chromeos/ash/components/tether/connect_tethering_operation.cc
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/connect_tethering_operation.h"
+#include "chromeos/ash/components/tether/connect_tethering_operation.h"
 
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/proto/tether.pb.h"
-#include "ash/components/tether/tether_host_response_recorder.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/connect_tethering_operation.h b/chromeos/ash/components/tether/connect_tethering_operation.h
similarity index 91%
rename from ash/components/tether/connect_tethering_operation.h
rename to chromeos/ash/components/tether/connect_tethering_operation.h
index 11706d3a..a01001ee 100644
--- a/ash/components/tether/connect_tethering_operation.h
+++ b/chromeos/ash/components/tether/connect_tethering_operation.h
@@ -2,30 +2,30 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_CONNECT_TETHERING_OPERATION_H_
-#define ASH_COMPONENTS_TETHER_CONNECT_TETHERING_OPERATION_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_CONNECT_TETHERING_OPERATION_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_CONNECT_TETHERING_OPERATION_H_
 
 #include <stdint.h>
 
 #include <map>
 #include <vector>
 
-#include "ash/components/tether/message_transfer_operation.h"
-#include "chromeos/ash/components/multidevice/remote_device_ref.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/gtest_prod_util.h"
 #include "base/observer_list.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
+#include "chromeos/ash/components/multidevice/remote_device_ref.h"
+#include "chromeos/ash/components/tether/message_transfer_operation.h"
 
-namespace ash {
-
-namespace device_sync {
+namespace ash::device_sync {
 class DeviceSyncClient;
 }
 
-namespace tether {
+namespace ash::secure_channel {
+class SecureChannelClient;
+}
+
+namespace ash::tether {
 
 class MessageWrapper;
 class TetherHostResponseRecorder;
@@ -162,8 +162,6 @@
   base::ObserverList<Observer>::Unchecked observer_list_;
 };
 
-}  // namespace tether
+}  // namespace ash::tether
 
-}  // namespace ash
-
-#endif  // ASH_COMPONENTS_TETHER_CONNECT_TETHERING_OPERATION_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_CONNECT_TETHERING_OPERATION_H_
diff --git a/ash/components/tether/connect_tethering_operation_unittest.cc b/chromeos/ash/components/tether/connect_tethering_operation_unittest.cc
similarity index 96%
rename from ash/components/tether/connect_tethering_operation_unittest.cc
rename to chromeos/ash/components/tether/connect_tethering_operation_unittest.cc
index 95d1f1ea5..3bbe732 100644
--- a/ash/components/tether/connect_tethering_operation_unittest.cc
+++ b/chromeos/ash/components/tether/connect_tethering_operation_unittest.cc
@@ -2,16 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/connect_tethering_operation.h"
+#include "chromeos/ash/components/tether/connect_tethering_operation.h"
 
 #include <memory>
 #include <vector>
 
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/mock_tether_host_response_recorder.h"
-#include "ash/components/tether/proto/tether.pb.h"
-#include "ash/components/tether/proto_test_util.h"
-#include "ash/components/tether/test_timer_factory.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_client_channel.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_connection_attempt.h"
@@ -23,6 +18,11 @@
 #include "base/time/time.h"
 #include "base/timer/mock_timer.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/mock_tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
+#include "chromeos/ash/components/tether/proto_test_util.h"
+#include "chromeos/ash/components/tether/test_timer_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/ash/components/tether/connection_preserver.cc b/chromeos/ash/components/tether/connection_preserver.cc
similarity index 83%
rename from ash/components/tether/connection_preserver.cc
rename to chromeos/ash/components/tether/connection_preserver.cc
index 28d2a3af..3397d61a 100644
--- a/ash/components/tether/connection_preserver.cc
+++ b/chromeos/ash/components/tether/connection_preserver.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 "ash/components/tether/connection_preserver.h"
+#include "chromeos/ash/components/tether/connection_preserver.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/connection_preserver.h b/chromeos/ash/components/tether/connection_preserver.h
similarity index 83%
rename from ash/components/tether/connection_preserver.h
rename to chromeos/ash/components/tether/connection_preserver.h
index 799f262..41c2e3be8 100644
--- a/ash/components/tether/connection_preserver.h
+++ b/chromeos/ash/components/tether/connection_preserver.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 ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_H_
-#define ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_H_
 
 #include <memory>
 
@@ -34,4 +34,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_H_
diff --git a/ash/components/tether/connection_preserver_impl.cc b/chromeos/ash/components/tether/connection_preserver_impl.cc
similarity index 98%
rename from ash/components/tether/connection_preserver_impl.cc
rename to chromeos/ash/components/tether/connection_preserver_impl.cc
index bafdddc..b5256f2e 100644
--- a/ash/components/tether/connection_preserver_impl.cc
+++ b/chromeos/ash/components/tether/connection_preserver_impl.cc
@@ -2,9 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/connection_preserver_impl.h"
+#include "chromeos/ash/components/tether/connection_preserver_impl.h"
 
-#include "ash/components/tether/tether_host_response_recorder.h"
 #include "base/bind.h"
 #include "base/ranges/algorithm.h"
 #include "base/timer/timer.h"
@@ -13,6 +12,7 @@
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_type_pattern.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/connection_preserver_impl.h b/chromeos/ash/components/tether/connection_preserver_impl.h
similarity index 91%
rename from ash/components/tether/connection_preserver_impl.h
rename to chromeos/ash/components/tether/connection_preserver_impl.h
index 870fe9d1..a4c057d 100644
--- a/ash/components/tether/connection_preserver_impl.h
+++ b/chromeos/ash/components/tether/connection_preserver_impl.h
@@ -2,13 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_IMPL_H_
 
 #include <memory>
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/connection_preserver.h"
 #include "ash/services/device_sync/public/cpp/device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/client_channel.h"
 #include "ash/services/secure_channel/public/cpp/client/connection_attempt.h"
@@ -17,6 +15,8 @@
 #include "ash/services/secure_channel/public/mojom/secure_channel.mojom.h"
 #include "base/timer/timer.h"
 #include "base/unguessable_token.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/connection_preserver.h"
 
 namespace ash {
 
@@ -106,4 +106,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_CONNECTION_PRESERVER_IMPL_H_
diff --git a/ash/components/tether/connection_preserver_impl_unittest.cc b/chromeos/ash/components/tether/connection_preserver_impl_unittest.cc
similarity index 97%
rename from ash/components/tether/connection_preserver_impl_unittest.cc
rename to chromeos/ash/components/tether/connection_preserver_impl_unittest.cc
index 3bc62bb..4889c46 100644
--- a/ash/components/tether/connection_preserver_impl_unittest.cc
+++ b/chromeos/ash/components/tether/connection_preserver_impl_unittest.cc
@@ -2,13 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/connection_preserver_impl.h"
+#include "chromeos/ash/components/tether/connection_preserver_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/mock_tether_host_response_recorder.h"
-#include "ash/components/tether/timer_factory.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_client_channel.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_connection_attempt.h"
@@ -22,6 +19,9 @@
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/mock_tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/timer_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
@@ -97,9 +97,7 @@
     connection_preserver_->SetTimerForTesting(base::WrapUnique(mock_timer_));
   }
 
-  void TearDown() override {
-    connection_preserver_.reset();
-  }
+  void TearDown() override { connection_preserver_.reset(); }
 
   void SimulateSuccessfulHostScan(multidevice::RemoteDeviceRef remote_device,
                                   bool should_remain_registered) {
diff --git a/ash/components/tether/crash_recovery_manager.h b/chromeos/ash/components/tether/crash_recovery_manager.h
similarity index 83%
rename from ash/components/tether/crash_recovery_manager.h
rename to chromeos/ash/components/tether/crash_recovery_manager.h
index e1d4b8c..141e0ea 100644
--- a/ash/components/tether/crash_recovery_manager.h
+++ b/chromeos/ash/components/tether/crash_recovery_manager.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 ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_H_
-#define ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_H_
 
 #include "base/callback.h"
 
@@ -36,4 +36,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_H_
diff --git a/ash/components/tether/crash_recovery_manager_impl.cc b/chromeos/ash/components/tether/crash_recovery_manager_impl.cc
similarity index 97%
rename from ash/components/tether/crash_recovery_manager_impl.cc
rename to chromeos/ash/components/tether/crash_recovery_manager_impl.cc
index fa8a496..18abc4a 100644
--- a/ash/components/tether/crash_recovery_manager_impl.cc
+++ b/chromeos/ash/components/tether/crash_recovery_manager_impl.cc
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/crash_recovery_manager_impl.h"
+#include "chromeos/ash/components/tether/crash_recovery_manager_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/host_scan_cache.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
@@ -14,6 +13,7 @@
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/crash_recovery_manager_impl.h b/chromeos/ash/components/tether/crash_recovery_manager_impl.h
similarity index 87%
rename from ash/components/tether/crash_recovery_manager_impl.h
rename to chromeos/ash/components/tether/crash_recovery_manager_impl.h
index 983a1ed..69e5371 100644
--- a/ash/components/tether/crash_recovery_manager_impl.h
+++ b/chromeos/ash/components/tether/crash_recovery_manager_impl.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_IMPL_H_
 
 #include <string>
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/crash_recovery_manager.h"
 #include "base/callback.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/crash_recovery_manager.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace ash {
@@ -80,4 +80,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_CRASH_RECOVERY_MANAGER_IMPL_H_
diff --git a/ash/components/tether/crash_recovery_manager_impl_unittest.cc b/chromeos/ash/components/tether/crash_recovery_manager_impl_unittest.cc
similarity index 93%
rename from ash/components/tether/crash_recovery_manager_impl_unittest.cc
rename to chromeos/ash/components/tether/crash_recovery_manager_impl_unittest.cc
index 914d89f..c450f8c6 100644
--- a/ash/components/tether/crash_recovery_manager_impl_unittest.cc
+++ b/chromeos/ash/components/tether/crash_recovery_manager_impl_unittest.cc
@@ -2,20 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/crash_recovery_manager_impl.h"
+#include "chromeos/ash/components/tether/crash_recovery_manager_impl.h"
 
 #include <memory>
 #include <sstream>
 
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/fake_host_scan_cache.h"
-#include "ash/components/tether/host_scan_cache_entry.h"
 #include "base/bind.h"
 #include "base/test/task_environment.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/host_scan_cache_entry.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
 
@@ -70,8 +70,7 @@
         std::make_unique<DeviceIdTetherNetworkGuidMap>();
   }
 
-  void TearDown() override {
-  }
+  void TearDown() override {}
 
   std::string GetTetherNetworkGuid() {
     return device_id_tether_network_guid_map_->GetTetherNetworkGuidForDeviceId(
diff --git a/ash/components/tether/device_id_tether_network_guid_map.cc b/chromeos/ash/components/tether/device_id_tether_network_guid_map.cc
similarity index 90%
rename from ash/components/tether/device_id_tether_network_guid_map.cc
rename to chromeos/ash/components/tether/device_id_tether_network_guid_map.cc
index fbeab8ec..b299c8d1 100644
--- a/ash/components/tether/device_id_tether_network_guid_map.cc
+++ b/chromeos/ash/components/tether/device_id_tether_network_guid_map.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 "ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/device_id_tether_network_guid_map.h b/chromeos/ash/components/tether/device_id_tether_network_guid_map.h
similarity index 83%
rename from ash/components/tether/device_id_tether_network_guid_map.h
rename to chromeos/ash/components/tether/device_id_tether_network_guid_map.h
index 6e757a64b..2fa54f0 100644
--- a/ash/components/tether/device_id_tether_network_guid_map.h
+++ b/chromeos/ash/components/tether/device_id_tether_network_guid_map.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 ASH_COMPONENTS_TETHER_DEVICE_ID_TETHER_NETWORK_GUID_MAP_H_
-#define ASH_COMPONENTS_TETHER_DEVICE_ID_TETHER_NETWORK_GUID_MAP_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_DEVICE_ID_TETHER_NETWORK_GUID_MAP_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_DEVICE_ID_TETHER_NETWORK_GUID_MAP_H_
 
 #include <string>
 
@@ -39,4 +39,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_DEVICE_ID_TETHER_NETWORK_GUID_MAP_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_DEVICE_ID_TETHER_NETWORK_GUID_MAP_H_
diff --git a/ash/components/tether/device_status_util.cc b/chromeos/ash/components/tether/device_status_util.cc
similarity index 96%
rename from ash/components/tether/device_status_util.cc
rename to chromeos/ash/components/tether/device_status_util.cc
index 01076eb..d440ef86 100644
--- a/ash/components/tether/device_status_util.cc
+++ b/chromeos/ash/components/tether/device_status_util.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 "ash/components/tether/device_status_util.h"
+#include "chromeos/ash/components/tether/device_status_util.h"
 
 #include "base/cxx17_backports.h"
 
diff --git a/ash/components/tether/device_status_util.h b/chromeos/ash/components/tether/device_status_util.h
similarity index 86%
rename from ash/components/tether/device_status_util.h
rename to chromeos/ash/components/tether/device_status_util.h
index 64230e4..ab205e6 100644
--- a/ash/components/tether/device_status_util.h
+++ b/chromeos/ash/components/tether/device_status_util.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_DEVICE_STATUS_UTIL_H_
-#define ASH_COMPONENTS_TETHER_DEVICE_STATUS_UTIL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_DEVICE_STATUS_UTIL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_DEVICE_STATUS_UTIL_H_
 
-#include "ash/components/tether/proto/tether.pb.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
 
 namespace ash {
 
@@ -36,4 +36,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_DEVICE_STATUS_UTIL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_DEVICE_STATUS_UTIL_H_
diff --git a/ash/components/tether/device_status_util_unittest.cc b/chromeos/ash/components/tether/device_status_util_unittest.cc
similarity index 94%
rename from ash/components/tether/device_status_util_unittest.cc
rename to chromeos/ash/components/tether/device_status_util_unittest.cc
index 85bc0917..75b45547 100644
--- a/ash/components/tether/device_status_util_unittest.cc
+++ b/chromeos/ash/components/tether/device_status_util_unittest.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/device_status_util.h"
+#include "chromeos/ash/components/tether/device_status_util.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_tether_host_fetcher.h"
-#include "ash/components/tether/proto_test_util.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/fake_tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/proto_test_util.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/components/tether/disconnect_tethering_operation.cc b/chromeos/ash/components/tether/disconnect_tethering_operation.cc
similarity index 92%
rename from ash/components/tether/disconnect_tethering_operation.cc
rename to chromeos/ash/components/tether/disconnect_tethering_operation.cc
index e9b35d1..c588fbc2 100644
--- a/ash/components/tether/disconnect_tethering_operation.cc
+++ b/chromeos/ash/components/tether/disconnect_tethering_operation.cc
@@ -2,16 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/disconnect_tethering_operation.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_operation.h"
 
 #include <memory>
 
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/proto/tether.pb.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/disconnect_tethering_operation.h b/chromeos/ash/components/tether/disconnect_tethering_operation.h
similarity index 85%
rename from ash/components/tether/disconnect_tethering_operation.h
rename to chromeos/ash/components/tether/disconnect_tethering_operation.h
index 6cec30d..56ec552 100644
--- a/ash/components/tether/disconnect_tethering_operation.h
+++ b/chromeos/ash/components/tether/disconnect_tethering_operation.h
@@ -2,24 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_OPERATION_H_
-#define ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_OPERATION_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_OPERATION_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_OPERATION_H_
 
-#include "ash/components/tether/message_transfer_operation.h"
-#include "base/time/time.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/gtest_prod_util.h"
 #include "base/observer_list.h"
 #include "base/time/clock.h"
+#include "base/time/time.h"
+#include "chromeos/ash/components/tether/message_transfer_operation.h"
 
-namespace ash {
-
-namespace device_sync {
+namespace ash::device_sync {
 class DeviceSyncClient;
 }
 
-namespace tether {
+namespace ash::secure_channel {
+class SecureChannelClient;
+}
+
+namespace ash::tether {
 
 // Operation which sends a disconnect message to a tether host.
 class DisconnectTetheringOperation : public MessageTransferOperation {
@@ -95,8 +95,6 @@
   base::Time disconnect_start_time_;
 };
 
-}  // namespace tether
+}  // namespace ash::tether
 
-}  // namespace ash
-
-#endif  // ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_OPERATION_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_OPERATION_H_
diff --git a/ash/components/tether/disconnect_tethering_operation_unittest.cc b/chromeos/ash/components/tether/disconnect_tethering_operation_unittest.cc
similarity index 96%
rename from ash/components/tether/disconnect_tethering_operation_unittest.cc
rename to chromeos/ash/components/tether/disconnect_tethering_operation_unittest.cc
index 69445de0e..810698e 100644
--- a/ash/components/tether/disconnect_tethering_operation_unittest.cc
+++ b/chromeos/ash/components/tether/disconnect_tethering_operation_unittest.cc
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/disconnect_tethering_operation.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_operation.h"
 
 #include <memory>
 #include <vector>
 
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/proto/tether.pb.h"
-#include "ash/components/tether/test_timer_factory.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_client_channel.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_connection_attempt.h"
@@ -21,6 +18,9 @@
 #include "base/time/time.h"
 #include "base/timer/mock_timer.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
+#include "chromeos/ash/components/tether/test_timer_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/components/tether/disconnect_tethering_request_sender.cc b/chromeos/ash/components/tether/disconnect_tethering_request_sender.cc
similarity index 90%
rename from ash/components/tether/disconnect_tethering_request_sender.cc
rename to chromeos/ash/components/tether/disconnect_tethering_request_sender.cc
index 562d7bc..c022d7cd 100644
--- a/ash/components/tether/disconnect_tethering_request_sender.cc
+++ b/chromeos/ash/components/tether/disconnect_tethering_request_sender.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 "ash/components/tether/disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/disconnect_tethering_request_sender.h b/chromeos/ash/components/tether/disconnect_tethering_request_sender.h
similarity index 84%
rename from ash/components/tether/disconnect_tethering_request_sender.h
rename to chromeos/ash/components/tether/disconnect_tethering_request_sender.h
index 829f8102..a490c3b 100644
--- a/ash/components/tether/disconnect_tethering_request_sender.h
+++ b/chromeos/ash/components/tether/disconnect_tethering_request_sender.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 ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_H_
-#define ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_H_
 
 #include "base/observer_list.h"
 
@@ -53,4 +53,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_H_
diff --git a/ash/components/tether/disconnect_tethering_request_sender_impl.cc b/chromeos/ash/components/tether/disconnect_tethering_request_sender_impl.cc
similarity index 95%
rename from ash/components/tether/disconnect_tethering_request_sender_impl.cc
rename to chromeos/ash/components/tether/disconnect_tethering_request_sender_impl.cc
index bb7fea01..1264918 100644
--- a/ash/components/tether/disconnect_tethering_request_sender_impl.cc
+++ b/chromeos/ash/components/tether/disconnect_tethering_request_sender_impl.cc
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/disconnect_tethering_request_sender_impl.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/tether_host_fetcher.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/disconnect_tethering_request_sender_impl.h b/chromeos/ash/components/tether/disconnect_tethering_request_sender_impl.h
similarity index 79%
rename from ash/components/tether/disconnect_tethering_request_sender_impl.h
rename to chromeos/ash/components/tether/disconnect_tethering_request_sender_impl.h
index ed6d54e..56a6905 100644
--- a/ash/components/tether/disconnect_tethering_request_sender_impl.h
+++ b/chromeos/ash/components/tether/disconnect_tethering_request_sender_impl.h
@@ -2,24 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_IMPL_H_
 
 #include <map>
 
-#include "ash/components/tether/disconnect_tethering_operation.h"
-#include "ash/components/tether/disconnect_tethering_request_sender.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_operation.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace ash {
-
-namespace device_sync {
+namespace ash::device_sync {
 class DeviceSyncClient;
 }
 
-namespace tether {
+namespace ash::secure_channel {
+class SecureChannelClient;
+}
+
+namespace ash::tether {
 
 class TetherHostFetcher;
 
@@ -84,8 +84,6 @@
       this};
 };
 
-}  // namespace tether
+}  // namespace ash::tether
 
-}  // namespace ash
-
-#endif  // ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_DISCONNECT_TETHERING_REQUEST_SENDER_IMPL_H_
diff --git a/ash/components/tether/disconnect_tethering_request_sender_impl_unittest.cc b/chromeos/ash/components/tether/disconnect_tethering_request_sender_impl_unittest.cc
similarity index 96%
rename from ash/components/tether/disconnect_tethering_request_sender_impl_unittest.cc
rename to chromeos/ash/components/tether/disconnect_tethering_request_sender_impl_unittest.cc
index 8bebaf3..d8c75e9 100644
--- a/ash/components/tether/disconnect_tethering_request_sender_impl_unittest.cc
+++ b/chromeos/ash/components/tether/disconnect_tethering_request_sender_impl_unittest.cc
@@ -2,19 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/disconnect_tethering_request_sender_impl.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/disconnect_tethering_operation.h"
-#include "ash/components/tether/disconnect_tethering_request_sender.h"
-#include "ash/components/tether/fake_tether_host_fetcher.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/task_environment.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_operation.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/fake_tether_host_fetcher.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
diff --git a/ash/components/tether/fake_active_host.cc b/chromeos/ash/components/tether/fake_active_host.cc
similarity index 98%
rename from ash/components/tether/fake_active_host.cc
rename to chromeos/ash/components/tether/fake_active_host.cc
index 3fb65af..ff8ef10 100644
--- a/ash/components/tether/fake_active_host.cc
+++ b/chromeos/ash/components/tether/fake_active_host.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 "ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/fake_active_host.h b/chromeos/ash/components/tether/fake_active_host.h
similarity index 87%
rename from ash/components/tether/fake_active_host.h
rename to chromeos/ash/components/tether/fake_active_host.h
index 84a00c0..ae21b73 100644
--- a/ash/components/tether/fake_active_host.h
+++ b/chromeos/ash/components/tether/fake_active_host.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_ACTIVE_HOST_H_
-#define ASH_COMPONENTS_TETHER_FAKE_ACTIVE_HOST_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_ACTIVE_HOST_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_ACTIVE_HOST_H_
 
 #include <string>
 
-#include "ash/components/tether/active_host.h"
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
 namespace ash {
 
@@ -55,4 +55,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_ACTIVE_HOST_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_ACTIVE_HOST_H_
diff --git a/ash/components/tether/fake_asynchronous_shutdown_object_container.cc b/chromeos/ash/components/tether/fake_asynchronous_shutdown_object_container.cc
similarity index 93%
rename from ash/components/tether/fake_asynchronous_shutdown_object_container.cc
rename to chromeos/ash/components/tether/fake_asynchronous_shutdown_object_container.cc
index cdefb22..76aee15 100644
--- a/ash/components/tether/fake_asynchronous_shutdown_object_container.cc
+++ b/chromeos/ash/components/tether/fake_asynchronous_shutdown_object_container.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 "ash/components/tether/fake_asynchronous_shutdown_object_container.h"
+#include "chromeos/ash/components/tether/fake_asynchronous_shutdown_object_container.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_asynchronous_shutdown_object_container.h b/chromeos/ash/components/tether/fake_asynchronous_shutdown_object_container.h
similarity index 87%
rename from ash/components/tether/fake_asynchronous_shutdown_object_container.h
rename to chromeos/ash/components/tether/fake_asynchronous_shutdown_object_container.h
index 3c6bb94f..03fd9b6 100644
--- a/ash/components/tether/fake_asynchronous_shutdown_object_container.h
+++ b/chromeos/ash/components/tether/fake_asynchronous_shutdown_object_container.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
 
-#include "ash/components/tether/asynchronous_shutdown_object_container.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "chromeos/ash/components/tether/asynchronous_shutdown_object_container.h"
 
 namespace ash {
 
@@ -75,4 +75,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_ASYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
diff --git a/ash/components/tether/fake_connection_preserver.cc b/chromeos/ash/components/tether/fake_connection_preserver.cc
similarity index 88%
rename from ash/components/tether/fake_connection_preserver.cc
rename to chromeos/ash/components/tether/fake_connection_preserver.cc
index 1275689a..489fe640 100644
--- a/ash/components/tether/fake_connection_preserver.cc
+++ b/chromeos/ash/components/tether/fake_connection_preserver.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 "ash/components/tether/fake_connection_preserver.h"
+#include "chromeos/ash/components/tether/fake_connection_preserver.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_connection_preserver.h b/chromeos/ash/components/tether/fake_connection_preserver.h
similarity index 76%
rename from ash/components/tether/fake_connection_preserver.h
rename to chromeos/ash/components/tether/fake_connection_preserver.h
index 4b1484f6..98c88ecc 100644
--- a/ash/components/tether/fake_connection_preserver.h
+++ b/chromeos/ash/components/tether/fake_connection_preserver.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_CONNECTION_PRESERVER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_CONNECTION_PRESERVER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_CONNECTION_PRESERVER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_CONNECTION_PRESERVER_H_
 
 #include <string>
 
-#include "ash/components/tether/connection_preserver.h"
+#include "chromeos/ash/components/tether/connection_preserver.h"
 
 namespace ash {
 
@@ -38,4 +38,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_CONNECTION_PRESERVER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_CONNECTION_PRESERVER_H_
diff --git a/ash/components/tether/fake_crash_recovery_manager.cc b/chromeos/ash/components/tether/fake_crash_recovery_manager.cc
similarity index 88%
rename from ash/components/tether/fake_crash_recovery_manager.cc
rename to chromeos/ash/components/tether/fake_crash_recovery_manager.cc
index efc34b9..3f18021 100644
--- a/ash/components/tether/fake_crash_recovery_manager.cc
+++ b/chromeos/ash/components/tether/fake_crash_recovery_manager.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 "ash/components/tether/fake_crash_recovery_manager.h"
+#include "chromeos/ash/components/tether/fake_crash_recovery_manager.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_crash_recovery_manager.h b/chromeos/ash/components/tether/fake_crash_recovery_manager.h
similarity index 76%
rename from ash/components/tether/fake_crash_recovery_manager.h
rename to chromeos/ash/components/tether/fake_crash_recovery_manager.h
index 4439daf..239d606 100644
--- a/ash/components/tether/fake_crash_recovery_manager.h
+++ b/chromeos/ash/components/tether/fake_crash_recovery_manager.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_CRASH_RECOVERY_MANAGER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_CRASH_RECOVERY_MANAGER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_CRASH_RECOVERY_MANAGER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_CRASH_RECOVERY_MANAGER_H_
 
-#include "ash/components/tether/crash_recovery_manager.h"
 #include "base/callback.h"
+#include "chromeos/ash/components/tether/crash_recovery_manager.h"
 
 namespace ash {
 
@@ -38,4 +38,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_CRASH_RECOVERY_MANAGER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_CRASH_RECOVERY_MANAGER_H_
diff --git a/ash/components/tether/fake_disconnect_tethering_request_sender.cc b/chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.cc
similarity index 90%
rename from ash/components/tether/fake_disconnect_tethering_request_sender.cc
rename to chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.cc
index 2bbfdc5..b96f0c9 100644
--- a/ash/components/tether/fake_disconnect_tethering_request_sender.cc
+++ b/chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.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 "ash/components/tether/fake_disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_disconnect_tethering_request_sender.h b/chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.h
similarity index 79%
rename from ash/components/tether/fake_disconnect_tethering_request_sender.h
rename to chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.h
index c279ffa..d357936 100644
--- a/ash/components/tether/fake_disconnect_tethering_request_sender.h
+++ b/chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_DISCONNECT_TETHERING_REQUEST_SENDER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_DISCONNECT_TETHERING_REQUEST_SENDER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_DISCONNECT_TETHERING_REQUEST_SENDER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_DISCONNECT_TETHERING_REQUEST_SENDER_H_
 
 #include <string>
 #include <vector>
 
-#include "ash/components/tether/disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender.h"
 
 namespace ash {
 
@@ -50,4 +50,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_DISCONNECT_TETHERING_REQUEST_SENDER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_DISCONNECT_TETHERING_REQUEST_SENDER_H_
diff --git a/ash/components/tether/fake_gms_core_notifications_state_tracker.cc b/chromeos/ash/components/tether/fake_gms_core_notifications_state_tracker.cc
similarity index 89%
rename from ash/components/tether/fake_gms_core_notifications_state_tracker.cc
rename to chromeos/ash/components/tether/fake_gms_core_notifications_state_tracker.cc
index 9d398ec..6ffbd627 100644
--- a/ash/components/tether/fake_gms_core_notifications_state_tracker.cc
+++ b/chromeos/ash/components/tether/fake_gms_core_notifications_state_tracker.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 "ash/components/tether/fake_gms_core_notifications_state_tracker.h"
+#include "chromeos/ash/components/tether/fake_gms_core_notifications_state_tracker.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_gms_core_notifications_state_tracker.h b/chromeos/ash/components/tether/fake_gms_core_notifications_state_tracker.h
similarity index 79%
rename from ash/components/tether/fake_gms_core_notifications_state_tracker.h
rename to chromeos/ash/components/tether/fake_gms_core_notifications_state_tracker.h
index bafd4dcc..dfe17f900 100644
--- a/ash/components/tether/fake_gms_core_notifications_state_tracker.h
+++ b/chromeos/ash/components/tether/fake_gms_core_notifications_state_tracker.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
 
 #include <string>
 #include <vector>
 
-#include "ash/components/tether/gms_core_notifications_state_tracker.h"
+#include "chromeos/ash/components/tether/gms_core_notifications_state_tracker.h"
 
 namespace ash {
 
@@ -52,4 +52,4 @@
 }  // namespace tether
 }  // namespace chromeos
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
diff --git a/ash/components/tether/fake_host_scan_cache.cc b/chromeos/ash/components/tether/fake_host_scan_cache.cc
similarity index 95%
rename from ash/components/tether/fake_host_scan_cache.cc
rename to chromeos/ash/components/tether/fake_host_scan_cache.cc
index e165b32..e2db1f1 100644
--- a/ash/components/tether/fake_host_scan_cache.cc
+++ b/chromeos/ash/components/tether/fake_host_scan_cache.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 "ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_host_scan_cache.h b/chromeos/ash/components/tether/fake_host_scan_cache.h
similarity index 84%
rename from ash/components/tether/fake_host_scan_cache.h
rename to chromeos/ash/components/tether/fake_host_scan_cache.h
index 0e8654f..15fe85c9 100644
--- a/ash/components/tether/fake_host_scan_cache.h
+++ b/chromeos/ash/components/tether/fake_host_scan_cache.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_CACHE_H_
-#define ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_CACHE_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_CACHE_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_CACHE_H_
 
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
 
-#include "ash/components/tether/host_scan_cache.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
 
 namespace ash {
 
@@ -52,4 +52,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_CACHE_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_CACHE_H_
diff --git a/ash/components/tether/fake_host_scan_scheduler.cc b/chromeos/ash/components/tether/fake_host_scan_scheduler.cc
similarity index 85%
rename from ash/components/tether/fake_host_scan_scheduler.cc
rename to chromeos/ash/components/tether/fake_host_scan_scheduler.cc
index 095843b..e54da1b3 100644
--- a/ash/components/tether/fake_host_scan_scheduler.cc
+++ b/chromeos/ash/components/tether/fake_host_scan_scheduler.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 "ash/components/tether/fake_host_scan_scheduler.h"
+#include "chromeos/ash/components/tether/fake_host_scan_scheduler.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_host_scan_scheduler.h b/chromeos/ash/components/tether/fake_host_scan_scheduler.h
similarity index 72%
rename from ash/components/tether/fake_host_scan_scheduler.h
rename to chromeos/ash/components/tether/fake_host_scan_scheduler.h
index 2d4e2fa1..d02693f 100644
--- a/ash/components/tether/fake_host_scan_scheduler.h
+++ b/chromeos/ash/components/tether/fake_host_scan_scheduler.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_SCHEDULER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_SCHEDULER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_SCHEDULER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_SCHEDULER_H_
 
-#include "ash/components/tether/host_scan_scheduler.h"
+#include "chromeos/ash/components/tether/host_scan_scheduler.h"
 
 namespace ash {
 
@@ -34,4 +34,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_SCHEDULER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_HOST_SCAN_SCHEDULER_H_
diff --git a/ash/components/tether/fake_host_scanner.cc b/chromeos/ash/components/tether/fake_host_scanner.cc
similarity index 91%
rename from ash/components/tether/fake_host_scanner.cc
rename to chromeos/ash/components/tether/fake_host_scanner.cc
index bc61ab94..c2494a7 100644
--- a/ash/components/tether/fake_host_scanner.cc
+++ b/chromeos/ash/components/tether/fake_host_scanner.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 "ash/components/tether/fake_host_scanner.h"
+#include "chromeos/ash/components/tether/fake_host_scanner.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_host_scanner.h b/chromeos/ash/components/tether/fake_host_scanner.h
similarity index 75%
rename from ash/components/tether/fake_host_scanner.h
rename to chromeos/ash/components/tether/fake_host_scanner.h
index 2baa3cb..48a7ff0 100644
--- a/ash/components/tether/fake_host_scanner.h
+++ b/chromeos/ash/components/tether/fake_host_scanner.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_HOST_SCANNER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_HOST_SCANNER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_HOST_SCANNER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_HOST_SCANNER_H_
 
-#include "ash/components/tether/host_scanner.h"
+#include "chromeos/ash/components/tether/host_scanner.h"
 
 namespace ash {
 
@@ -39,4 +39,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_HOST_SCANNER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_HOST_SCANNER_H_
diff --git a/ash/components/tether/fake_network_configuration_remover.cc b/chromeos/ash/components/tether/fake_network_configuration_remover.cc
similarity index 88%
rename from ash/components/tether/fake_network_configuration_remover.cc
rename to chromeos/ash/components/tether/fake_network_configuration_remover.cc
index 9191a6f..234a2fe 100644
--- a/ash/components/tether/fake_network_configuration_remover.cc
+++ b/chromeos/ash/components/tether/fake_network_configuration_remover.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 "ash/components/tether/fake_network_configuration_remover.h"
+#include "chromeos/ash/components/tether/fake_network_configuration_remover.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_network_configuration_remover.h b/chromeos/ash/components/tether/fake_network_configuration_remover.h
similarity index 75%
rename from ash/components/tether/fake_network_configuration_remover.h
rename to chromeos/ash/components/tether/fake_network_configuration_remover.h
index 0473b146..b0773335c 100644
--- a/ash/components/tether/fake_network_configuration_remover.h
+++ b/chromeos/ash/components/tether/fake_network_configuration_remover.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_NETWORK_CONFIGURATION_REMOVER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_NETWORK_CONFIGURATION_REMOVER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_NETWORK_CONFIGURATION_REMOVER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_NETWORK_CONFIGURATION_REMOVER_H_
 
 #include <string>
 
-#include "ash/components/tether/network_configuration_remover.h"
+#include "chromeos/ash/components/tether/network_configuration_remover.h"
 
 namespace ash {
 
@@ -41,4 +41,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_NETWORK_CONFIGURATION_REMOVER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_NETWORK_CONFIGURATION_REMOVER_H_
diff --git a/ash/components/tether/fake_notification_presenter.cc b/chromeos/ash/components/tether/fake_notification_presenter.cc
similarity index 96%
rename from ash/components/tether/fake_notification_presenter.cc
rename to chromeos/ash/components/tether/fake_notification_presenter.cc
index 0733be9d..029a97e 100644
--- a/ash/components/tether/fake_notification_presenter.cc
+++ b/chromeos/ash/components/tether/fake_notification_presenter.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 "ash/components/tether/fake_notification_presenter.h"
+#include "chromeos/ash/components/tether/fake_notification_presenter.h"
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
diff --git a/ash/components/tether/fake_notification_presenter.h b/chromeos/ash/components/tether/fake_notification_presenter.h
similarity index 87%
rename from ash/components/tether/fake_notification_presenter.h
rename to chromeos/ash/components/tether/fake_notification_presenter.h
index bc25ea8..e5c21d39 100644
--- a/ash/components/tether/fake_notification_presenter.h
+++ b/chromeos/ash/components/tether/fake_notification_presenter.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_NOTIFICATION_PRESENTER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_NOTIFICATION_PRESENTER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_NOTIFICATION_PRESENTER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_NOTIFICATION_PRESENTER_H_
 
 #include <memory>
 #include <string>
 
-#include "ash/components/tether/notification_presenter.h"
+#include "chromeos/ash/components/tether/notification_presenter.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace ash {
@@ -62,4 +62,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_NOTIFICATION_PRESENTER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_NOTIFICATION_PRESENTER_H_
diff --git a/ash/components/tether/fake_synchronous_shutdown_object_container.cc b/chromeos/ash/components/tether/fake_synchronous_shutdown_object_container.cc
similarity index 91%
rename from ash/components/tether/fake_synchronous_shutdown_object_container.cc
rename to chromeos/ash/components/tether/fake_synchronous_shutdown_object_container.cc
index f29788c..925e8e4f 100644
--- a/ash/components/tether/fake_synchronous_shutdown_object_container.cc
+++ b/chromeos/ash/components/tether/fake_synchronous_shutdown_object_container.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 "ash/components/tether/fake_synchronous_shutdown_object_container.h"
+#include "chromeos/ash/components/tether/fake_synchronous_shutdown_object_container.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_synchronous_shutdown_object_container.h b/chromeos/ash/components/tether/fake_synchronous_shutdown_object_container.h
similarity index 84%
rename from ash/components/tether/fake_synchronous_shutdown_object_container.h
rename to chromeos/ash/components/tether/fake_synchronous_shutdown_object_container.h
index 6bc8b1a..e58ffab 100644
--- a/ash/components/tether/fake_synchronous_shutdown_object_container.h
+++ b/chromeos/ash/components/tether/fake_synchronous_shutdown_object_container.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
 
-#include "ash/components/tether/synchronous_shutdown_object_container.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "chromeos/ash/components/tether/synchronous_shutdown_object_container.h"
 
 namespace ash {
 
@@ -62,4 +62,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
diff --git a/ash/components/tether/fake_tether_component.cc b/chromeos/ash/components/tether/fake_tether_component.cc
similarity index 93%
rename from ash/components/tether/fake_tether_component.cc
rename to chromeos/ash/components/tether/fake_tether_component.cc
index 42e558f4..6999721 100644
--- a/ash/components/tether/fake_tether_component.cc
+++ b/chromeos/ash/components/tether/fake_tether_component.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 "ash/components/tether/fake_tether_component.h"
+#include "chromeos/ash/components/tether/fake_tether_component.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_tether_component.h b/chromeos/ash/components/tether/fake_tether_component.h
similarity index 76%
rename from ash/components/tether/fake_tether_component.h
rename to chromeos/ash/components/tether/fake_tether_component.h
index 756538c0..a964965 100644
--- a/ash/components/tether/fake_tether_component.h
+++ b/chromeos/ash/components/tether/fake_tether_component.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_TETHER_COMPONENT_H_
-#define ASH_COMPONENTS_TETHER_FAKE_TETHER_COMPONENT_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_COMPONENT_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_COMPONENT_H_
 
-#include "ash/components/tether/tether_component.h"
-#include "ash/components/tether/tether_disconnector.h"
+#include "chromeos/ash/components/tether/tether_component.h"
+#include "chromeos/ash/components/tether/tether_disconnector.h"
 
 namespace ash {
 
@@ -43,4 +43,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_TETHER_COMPONENT_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_COMPONENT_H_
diff --git a/ash/components/tether/fake_tether_connector.cc b/chromeos/ash/components/tether/fake_tether_connector.cc
similarity index 92%
rename from ash/components/tether/fake_tether_connector.cc
rename to chromeos/ash/components/tether/fake_tether_connector.cc
index ca95ae6..36dfce3 100644
--- a/ash/components/tether/fake_tether_connector.cc
+++ b/chromeos/ash/components/tether/fake_tether_connector.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 "ash/components/tether/fake_tether_connector.h"
+#include "chromeos/ash/components/tether/fake_tether_connector.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_tether_connector.h b/chromeos/ash/components/tether/fake_tether_connector.h
similarity index 85%
rename from ash/components/tether/fake_tether_connector.h
rename to chromeos/ash/components/tether/fake_tether_connector.h
index 598dc55..48b2f72d 100644
--- a/ash/components/tether/fake_tether_connector.h
+++ b/chromeos/ash/components/tether/fake_tether_connector.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_TETHER_CONNECTOR_H_
-#define ASH_COMPONENTS_TETHER_FAKE_TETHER_CONNECTOR_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_CONNECTOR_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_CONNECTOR_H_
 
-#include "ash/components/tether/tether_connector.h"
 #include "base/callback_forward.h"
 #include "chromeos/ash/components/network/network_connection_handler.h"
+#include "chromeos/ash/components/tether/tether_connector.h"
 
 namespace ash {
 
@@ -57,4 +57,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_TETHER_CONNECTOR_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_CONNECTOR_H_
diff --git a/ash/components/tether/fake_tether_disconnector.cc b/chromeos/ash/components/tether/fake_tether_disconnector.cc
similarity index 93%
rename from ash/components/tether/fake_tether_disconnector.cc
rename to chromeos/ash/components/tether/fake_tether_disconnector.cc
index 78f8601..51421fd 100644
--- a/ash/components/tether/fake_tether_disconnector.cc
+++ b/chromeos/ash/components/tether/fake_tether_disconnector.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 "ash/components/tether/fake_tether_disconnector.h"
+#include "chromeos/ash/components/tether/fake_tether_disconnector.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_tether_disconnector.h b/chromeos/ash/components/tether/fake_tether_disconnector.h
similarity index 82%
rename from ash/components/tether/fake_tether_disconnector.h
rename to chromeos/ash/components/tether/fake_tether_disconnector.h
index 75d3848..1ddc51d 100644
--- a/ash/components/tether/fake_tether_disconnector.h
+++ b/chromeos/ash/components/tether/fake_tether_disconnector.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_TETHER_DISCONNECTOR_H_
-#define ASH_COMPONENTS_TETHER_FAKE_TETHER_DISCONNECTOR_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_DISCONNECTOR_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_DISCONNECTOR_H_
 
-#include "ash/components/tether/tether_disconnector.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
 #include "base/callback_forward.h"
 #include "chromeos/ash/components/network/network_connection_handler.h"
+#include "chromeos/ash/components/tether/tether_disconnector.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 
 namespace ash {
 
@@ -57,4 +57,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_TETHER_DISCONNECTOR_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_DISCONNECTOR_H_
diff --git a/ash/components/tether/fake_tether_host_fetcher.cc b/chromeos/ash/components/tether/fake_tether_host_fetcher.cc
similarity index 94%
rename from ash/components/tether/fake_tether_host_fetcher.cc
rename to chromeos/ash/components/tether/fake_tether_host_fetcher.cc
index a2fdd78..4b4fb05 100644
--- a/ash/components/tether/fake_tether_host_fetcher.cc
+++ b/chromeos/ash/components/tether/fake_tether_host_fetcher.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 "ash/components/tether/fake_tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/fake_tether_host_fetcher.h"
 
 #include "base/memory/ptr_util.h"
 
diff --git a/ash/components/tether/fake_tether_host_fetcher.h b/chromeos/ash/components/tether/fake_tether_host_fetcher.h
similarity index 81%
rename from ash/components/tether/fake_tether_host_fetcher.h
rename to chromeos/ash/components/tether/fake_tether_host_fetcher.h
index 7d178f60..a802aa0b 100644
--- a/ash/components/tether/fake_tether_host_fetcher.h
+++ b/chromeos/ash/components/tether/fake_tether_host_fetcher.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_TETHER_HOST_FETCHER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_TETHER_HOST_FETCHER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_HOST_FETCHER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_HOST_FETCHER_H_
 
 #include <vector>
 
-#include "ash/components/tether/tether_host_fetcher.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher.h"
 
 namespace ash {
 
@@ -47,4 +47,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_TETHER_HOST_FETCHER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_HOST_FETCHER_H_
diff --git a/ash/components/tether/fake_tether_session_completion_logger.cc b/chromeos/ash/components/tether/fake_tether_session_completion_logger.cc
similarity index 87%
rename from ash/components/tether/fake_tether_session_completion_logger.cc
rename to chromeos/ash/components/tether/fake_tether_session_completion_logger.cc
index 01dabc5..fdd27bd 100644
--- a/ash/components/tether/fake_tether_session_completion_logger.cc
+++ b/chromeos/ash/components/tether/fake_tether_session_completion_logger.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 "ash/components/tether/fake_tether_session_completion_logger.h"
+#include "chromeos/ash/components/tether/fake_tether_session_completion_logger.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_tether_session_completion_logger.h b/chromeos/ash/components/tether/fake_tether_session_completion_logger.h
similarity index 77%
rename from ash/components/tether/fake_tether_session_completion_logger.h
rename to chromeos/ash/components/tether/fake_tether_session_completion_logger.h
index 3793b47..2263872 100644
--- a/ash/components/tether/fake_tether_session_completion_logger.h
+++ b/chromeos/ash/components/tether/fake_tether_session_completion_logger.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_TETHER_SESSION_COMPLETION_LOGGER_H_
-#define ASH_COMPONENTS_TETHER_FAKE_TETHER_SESSION_COMPLETION_LOGGER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_SESSION_COMPLETION_LOGGER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_SESSION_COMPLETION_LOGGER_H_
 
 #include <memory>
 
-#include "ash/components/tether/tether_session_completion_logger.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 
 namespace ash {
 
@@ -43,4 +43,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_TETHER_SESSION_COMPLETION_LOGGER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_TETHER_SESSION_COMPLETION_LOGGER_H_
diff --git a/ash/components/tether/fake_wifi_hotspot_connector.cc b/chromeos/ash/components/tether/fake_wifi_hotspot_connector.cc
similarity index 94%
rename from ash/components/tether/fake_wifi_hotspot_connector.cc
rename to chromeos/ash/components/tether/fake_wifi_hotspot_connector.cc
index cb93fe3..67d77d8 100644
--- a/ash/components/tether/fake_wifi_hotspot_connector.cc
+++ b/chromeos/ash/components/tether/fake_wifi_hotspot_connector.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 "ash/components/tether/fake_wifi_hotspot_connector.h"
+#include "chromeos/ash/components/tether/fake_wifi_hotspot_connector.h"
 
 #include "base/memory/ptr_util.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
diff --git a/ash/components/tether/fake_wifi_hotspot_connector.h b/chromeos/ash/components/tether/fake_wifi_hotspot_connector.h
similarity index 83%
rename from ash/components/tether/fake_wifi_hotspot_connector.h
rename to chromeos/ash/components/tether/fake_wifi_hotspot_connector.h
index cce1f4c..6ac45bf 100644
--- a/ash/components/tether/fake_wifi_hotspot_connector.h
+++ b/chromeos/ash/components/tether/fake_wifi_hotspot_connector.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_CONNECTOR_H_
-#define ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_CONNECTOR_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_CONNECTOR_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_CONNECTOR_H_
 
 #include <string>
 
-#include "ash/components/tether/wifi_hotspot_connector.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_connector.h"
 
 namespace ash {
 
@@ -52,4 +52,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_CONNECTOR_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_CONNECTOR_H_
diff --git a/ash/components/tether/fake_wifi_hotspot_disconnector.cc b/chromeos/ash/components/tether/fake_wifi_hotspot_disconnector.cc
similarity index 90%
rename from ash/components/tether/fake_wifi_hotspot_disconnector.cc
rename to chromeos/ash/components/tether/fake_wifi_hotspot_disconnector.cc
index 07faba8..00389a793 100644
--- a/ash/components/tether/fake_wifi_hotspot_disconnector.cc
+++ b/chromeos/ash/components/tether/fake_wifi_hotspot_disconnector.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 "ash/components/tether/fake_wifi_hotspot_disconnector.h"
+#include "chromeos/ash/components/tether/fake_wifi_hotspot_disconnector.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/fake_wifi_hotspot_disconnector.h b/chromeos/ash/components/tether/fake_wifi_hotspot_disconnector.h
similarity index 80%
rename from ash/components/tether/fake_wifi_hotspot_disconnector.h
rename to chromeos/ash/components/tether/fake_wifi_hotspot_disconnector.h
index 4701bd2..7d96fdc 100644
--- a/ash/components/tether/fake_wifi_hotspot_disconnector.h
+++ b/chromeos/ash/components/tether/fake_wifi_hotspot_disconnector.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_DISCONNECTOR_H_
-#define ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_DISCONNECTOR_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_DISCONNECTOR_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_DISCONNECTOR_H_
 
-#include "ash/components/tether/wifi_hotspot_disconnector.h"
 #include "base/callback.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_disconnector.h"
 
 namespace ash {
 
@@ -46,4 +46,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_DISCONNECTOR_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_FAKE_WIFI_HOTSPOT_DISCONNECTOR_H_
diff --git a/ash/components/tether/gms_core_notifications_state_tracker.cc b/chromeos/ash/components/tether/gms_core_notifications_state_tracker.cc
similarity index 90%
rename from ash/components/tether/gms_core_notifications_state_tracker.cc
rename to chromeos/ash/components/tether/gms_core_notifications_state_tracker.cc
index 7182b8c..37a1e9db 100644
--- a/ash/components/tether/gms_core_notifications_state_tracker.cc
+++ b/chromeos/ash/components/tether/gms_core_notifications_state_tracker.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 "ash/components/tether/gms_core_notifications_state_tracker.h"
+#include "chromeos/ash/components/tether/gms_core_notifications_state_tracker.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/gms_core_notifications_state_tracker.h b/chromeos/ash/components/tether/gms_core_notifications_state_tracker.h
similarity index 86%
rename from ash/components/tether/gms_core_notifications_state_tracker.h
rename to chromeos/ash/components/tether/gms_core_notifications_state_tracker.h
index 638ca260..3d1bafc 100644
--- a/ash/components/tether/gms_core_notifications_state_tracker.h
+++ b/chromeos/ash/components/tether/gms_core_notifications_state_tracker.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 ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
-#define ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
 
 #include <string>
 #include <vector>
@@ -60,4 +60,4 @@
 }  // namespace tether
 }  // namespace chromeos
 
-#endif  // ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_H_
diff --git a/ash/components/tether/gms_core_notifications_state_tracker_impl.cc b/chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.cc
similarity index 97%
rename from ash/components/tether/gms_core_notifications_state_tracker_impl.cc
rename to chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.cc
index 12c3c9e..ec92a901 100644
--- a/ash/components/tether/gms_core_notifications_state_tracker_impl.cc
+++ b/chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/gms_core_notifications_state_tracker_impl.h"
+#include "chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.h"
 
 #include <sstream>
 
diff --git a/ash/components/tether/gms_core_notifications_state_tracker_impl.h b/chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.h
similarity index 78%
rename from ash/components/tether/gms_core_notifications_state_tracker_impl.h
rename to chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.h
index 3b76a88..d4f51c3 100644
--- a/ash/components/tether/gms_core_notifications_state_tracker_impl.h
+++ b/chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_IMPL_H_
 
 #include <map>
 #include <string>
 #include <vector>
 
-#include "ash/components/tether/gms_core_notifications_state_tracker.h"
-#include "ash/components/tether/host_scanner_operation.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
+#include "chromeos/ash/components/tether/gms_core_notifications_state_tracker.h"
+#include "chromeos/ash/components/tether/host_scanner_operation.h"
 
 namespace ash {
 
@@ -56,4 +56,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_GMS_CORE_NOTIFICATIONS_STATE_TRACKER_IMPL_H_
diff --git a/ash/components/tether/gms_core_notifications_state_tracker_impl_unittest.cc b/chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl_unittest.cc
similarity index 98%
rename from ash/components/tether/gms_core_notifications_state_tracker_impl_unittest.cc
rename to chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl_unittest.cc
index 27d63c9..ff15b35 100644
--- a/ash/components/tether/gms_core_notifications_state_tracker_impl_unittest.cc
+++ b/chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/gms_core_notifications_state_tracker_impl.h"
+#include "chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.h"
 
 #include <memory>
 #include <sstream>
diff --git a/ash/components/tether/host_connection_metrics_logger.cc b/chromeos/ash/components/tether/host_connection_metrics_logger.cc
similarity index 98%
rename from ash/components/tether/host_connection_metrics_logger.cc
rename to chromeos/ash/components/tether/host_connection_metrics_logger.cc
index a3fd0ba..0d0c6c2 100644
--- a/ash/components/tether/host_connection_metrics_logger.cc
+++ b/chromeos/ash/components/tether/host_connection_metrics_logger.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 "ash/components/tether/host_connection_metrics_logger.h"
+#include "chromeos/ash/components/tether/host_connection_metrics_logger.h"
 
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
diff --git a/ash/components/tether/host_connection_metrics_logger.h b/chromeos/ash/components/tether/host_connection_metrics_logger.h
similarity index 96%
rename from ash/components/tether/host_connection_metrics_logger.h
rename to chromeos/ash/components/tether/host_connection_metrics_logger.h
index 59094f1..4c3fce6a 100644
--- a/ash/components/tether/host_connection_metrics_logger.h
+++ b/chromeos/ash/components/tether/host_connection_metrics_logger.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_HOST_CONNECTION_METRICS_LOGGER_H_
-#define ASH_COMPONENTS_TETHER_HOST_CONNECTION_METRICS_LOGGER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_CONNECTION_METRICS_LOGGER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_CONNECTION_METRICS_LOGGER_H_
 
 #include <map>
 #include <string>
 
-#include "ash/components/tether/active_host.h"
 #include "base/gtest_prod_util.h"
 #include "base/time/time.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
 namespace base {
 class Clock;
@@ -213,4 +213,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOST_CONNECTION_METRICS_LOGGER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_CONNECTION_METRICS_LOGGER_H_
diff --git a/ash/components/tether/host_connection_metrics_logger_unittest.cc b/chromeos/ash/components/tether/host_connection_metrics_logger_unittest.cc
similarity index 98%
rename from ash/components/tether/host_connection_metrics_logger_unittest.cc
rename to chromeos/ash/components/tether/host_connection_metrics_logger_unittest.cc
index b6e2f8af..894e04a 100644
--- a/ash/components/tether/host_connection_metrics_logger_unittest.cc
+++ b/chromeos/ash/components/tether/host_connection_metrics_logger_unittest.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_connection_metrics_logger.h"
+#include "chromeos/ash/components/tether/host_connection_metrics_logger.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_active_host.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
diff --git a/ash/components/tether/host_scan_cache.cc b/chromeos/ash/components/tether/host_scan_cache.cc
similarity index 93%
rename from ash/components/tether/host_scan_cache.cc
rename to chromeos/ash/components/tether/host_scan_cache.cc
index 1631616..2558582 100644
--- a/ash/components/tether/host_scan_cache.cc
+++ b/chromeos/ash/components/tether/host_scan_cache.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 "ash/components/tether/host_scan_cache.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/host_scan_cache.h b/chromeos/ash/components/tether/host_scan_cache.h
similarity index 89%
rename from ash/components/tether/host_scan_cache.h
rename to chromeos/ash/components/tether/host_scan_cache.h
index 4f3ba9c4..93c2568 100644
--- a/ash/components/tether/host_scan_cache.h
+++ b/chromeos/ash/components/tether/host_scan_cache.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_H_
 
 #include <string>
 #include <unordered_set>
 
-#include "ash/components/tether/host_scan_cache_entry.h"
 #include "base/observer_list.h"
+#include "chromeos/ash/components/tether/host_scan_cache_entry.h"
 
 namespace ash {
 
@@ -68,4 +68,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_H_
diff --git a/ash/components/tether/host_scan_cache_entry.cc b/chromeos/ash/components/tether/host_scan_cache_entry.cc
similarity index 97%
rename from ash/components/tether/host_scan_cache_entry.cc
rename to chromeos/ash/components/tether/host_scan_cache_entry.cc
index aa743389..023ba65 100644
--- a/ash/components/tether/host_scan_cache_entry.cc
+++ b/chromeos/ash/components/tether/host_scan_cache_entry.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 "ash/components/tether/host_scan_cache_entry.h"
+#include "chromeos/ash/components/tether/host_scan_cache_entry.h"
 
 #include "base/check_op.h"
 #include "base/memory/ptr_util.h"
diff --git a/ash/components/tether/host_scan_cache_entry.h b/chromeos/ash/components/tether/host_scan_cache_entry.h
similarity index 91%
rename from ash/components/tether/host_scan_cache_entry.h
rename to chromeos/ash/components/tether/host_scan_cache_entry.h
index 270f6905..ca3bf11 100644
--- a/ash/components/tether/host_scan_cache_entry.h
+++ b/chromeos/ash/components/tether/host_scan_cache_entry.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 ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_ENTRY_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_ENTRY_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_ENTRY_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_ENTRY_H_
 
 #include <memory>
 #include <string>
@@ -77,4 +77,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_ENTRY_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_CACHE_ENTRY_H_
diff --git a/ash/components/tether/host_scan_cache_unittest.cc b/chromeos/ash/components/tether/host_scan_cache_unittest.cc
similarity index 93%
rename from ash/components/tether/host_scan_cache_unittest.cc
rename to chromeos/ash/components/tether/host_scan_cache_unittest.cc
index ee5f2af9b..41b1d2ab 100644
--- a/ash/components/tether/host_scan_cache_unittest.cc
+++ b/chromeos/ash/components/tether/host_scan_cache_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_scan_cache.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
 
 #include <memory>
 #include <unordered_map>
 
-#include "ash/components/tether/fake_host_scan_cache.h"
-#include "ash/components/tether/host_scan_test_util.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/host_scan_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
diff --git a/ash/components/tether/host_scan_device_prioritizer.h b/chromeos/ash/components/tether/host_scan_device_prioritizer.h
similarity index 85%
rename from ash/components/tether/host_scan_device_prioritizer.h
rename to chromeos/ash/components/tether/host_scan_device_prioritizer.h
index afc87c9e..83c04ec 100644
--- a/ash/components/tether/host_scan_device_prioritizer.h
+++ b/chromeos/ash/components/tether/host_scan_device_prioritizer.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 ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_H_
 
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 
@@ -38,4 +38,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_H_
diff --git a/ash/components/tether/host_scan_device_prioritizer_impl.cc b/chromeos/ash/components/tether/host_scan_device_prioritizer_impl.cc
similarity index 93%
rename from ash/components/tether/host_scan_device_prioritizer_impl.cc
rename to chromeos/ash/components/tether/host_scan_device_prioritizer_impl.cc
index 31efcc0..6814583 100644
--- a/ash/components/tether/host_scan_device_prioritizer_impl.cc
+++ b/chromeos/ash/components/tether/host_scan_device_prioritizer_impl.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_scan_device_prioritizer_impl.h"
+#include "chromeos/ash/components/tether/host_scan_device_prioritizer_impl.h"
 
-#include "ash/components/tether/pref_names.h"
-#include "ash/components/tether/tether_host_response_recorder.h"
 #include "base/containers/adapters.h"
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/pref_names.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
diff --git a/ash/components/tether/host_scan_device_prioritizer_impl.h b/chromeos/ash/components/tether/host_scan_device_prioritizer_impl.h
similarity index 76%
rename from ash/components/tether/host_scan_device_prioritizer_impl.h
rename to chromeos/ash/components/tether/host_scan_device_prioritizer_impl.h
index c6f5228..60b221f 100644
--- a/ash/components/tether/host_scan_device_prioritizer_impl.h
+++ b/chromeos/ash/components/tether/host_scan_device_prioritizer_impl.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_IMPL_H_
 
-#include "ash/components/tether/host_scan_device_prioritizer.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
+#include "chromeos/ash/components/tether/host_scan_device_prioritizer.h"
 
 namespace ash {
 
@@ -38,4 +38,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_DEVICE_PRIORITIZER_IMPL_H_
diff --git a/ash/components/tether/host_scan_device_prioritizer_impl_unittest.cc b/chromeos/ash/components/tether/host_scan_device_prioritizer_impl_unittest.cc
similarity index 95%
rename from ash/components/tether/host_scan_device_prioritizer_impl_unittest.cc
rename to chromeos/ash/components/tether/host_scan_device_prioritizer_impl_unittest.cc
index 653cd8f..26aee4e5 100644
--- a/ash/components/tether/host_scan_device_prioritizer_impl_unittest.cc
+++ b/chromeos/ash/components/tether/host_scan_device_prioritizer_impl_unittest.cc
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_scan_device_prioritizer_impl.h"
+#include "chromeos/ash/components/tether/host_scan_device_prioritizer_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/tether_host_response_recorder.h"
+#include "base/strings/string_number_conversions.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -22,7 +23,7 @@
     int id,
     int64_t last_update_time_millis) {
   return multidevice::RemoteDeviceRefBuilder()
-      .SetPublicKey("publicKey" + std::to_string(id))
+      .SetPublicKey("publicKey" + base::NumberToString(id))
       .SetLastUpdateTimeMillis(last_update_time_millis)
       .Build();
 }
diff --git a/ash/components/tether/host_scan_scheduler.h b/chromeos/ash/components/tether/host_scan_scheduler.h
similarity index 79%
rename from ash/components/tether/host_scan_scheduler.h
rename to chromeos/ash/components/tether/host_scan_scheduler.h
index a44ba6ebe..88cf32c 100644
--- a/ash/components/tether/host_scan_scheduler.h
+++ b/chromeos/ash/components/tether/host_scan_scheduler.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 ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_H_
 
 namespace ash {
 
@@ -29,4 +29,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_H_
diff --git a/ash/components/tether/host_scan_scheduler_impl.cc b/chromeos/ash/components/tether/host_scan_scheduler_impl.cc
similarity index 98%
rename from ash/components/tether/host_scan_scheduler_impl.cc
rename to chromeos/ash/components/tether/host_scan_scheduler_impl.cc
index 710b7465..9eb5a56 100644
--- a/ash/components/tether/host_scan_scheduler_impl.cc
+++ b/chromeos/ash/components/tether/host_scan_scheduler_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_scan_scheduler_impl.h"
+#include "chromeos/ash/components/tether/host_scan_scheduler_impl.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/host_scan_scheduler_impl.h b/chromeos/ash/components/tether/host_scan_scheduler_impl.h
similarity index 89%
rename from ash/components/tether/host_scan_scheduler_impl.h
rename to chromeos/ash/components/tether/host_scan_scheduler_impl.h
index 44a7569..aa50001 100644
--- a/ash/components/tether/host_scan_scheduler_impl.h
+++ b/chromeos/ash/components/tether/host_scan_scheduler_impl.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_IMPL_H_
 
 #include <memory>
 
-#include "ash/components/tether/host_scan_scheduler.h"
-#include "ash/components/tether/host_scanner.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chromeos/ash/components/network/network_state_handler_observer.h"
+#include "chromeos/ash/components/tether/host_scan_scheduler.h"
+#include "chromeos/ash/components/tether/host_scanner.h"
 #include "components/session_manager/core/session_manager_observer.h"
 
 namespace base {
@@ -97,4 +97,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_SCHEDULER_IMPL_H_
diff --git a/ash/components/tether/host_scan_scheduler_impl_unittest.cc b/chromeos/ash/components/tether/host_scan_scheduler_impl_unittest.cc
similarity index 98%
rename from ash/components/tether/host_scan_scheduler_impl_unittest.cc
rename to chromeos/ash/components/tether/host_scan_scheduler_impl_unittest.cc
index 60918b7..550a618 100644
--- a/ash/components/tether/host_scan_scheduler_impl_unittest.cc
+++ b/chromeos/ash/components/tether/host_scan_scheduler_impl_unittest.cc
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_scan_scheduler_impl.h"
+#include "chromeos/ash/components/tether/host_scan_scheduler_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_host_scanner.h"
 #include "ash/services/device_sync/cryptauth_device_manager.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
@@ -19,6 +18,7 @@
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
 #include "chromeos/ash/components/network/network_type_pattern.h"
+#include "chromeos/ash/components/tether/fake_host_scanner.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "components/session_manager/core/session_manager.h"
diff --git a/ash/components/tether/host_scan_test_util.cc b/chromeos/ash/components/tether/host_scan_test_util.cc
similarity index 97%
rename from ash/components/tether/host_scan_test_util.cc
rename to chromeos/ash/components/tether/host_scan_test_util.cc
index 8084dd2a..9284fa85 100644
--- a/ash/components/tether/host_scan_test_util.cc
+++ b/chromeos/ash/components/tether/host_scan_test_util.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 "ash/components/tether/host_scan_test_util.h"
+#include "chromeos/ash/components/tether/host_scan_test_util.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/host_scan_test_util.h b/chromeos/ash/components/tether/host_scan_test_util.h
similarity index 87%
rename from ash/components/tether/host_scan_test_util.h
rename to chromeos/ash/components/tether/host_scan_test_util.h
index 9a8ef3e6..8edf478 100644
--- a/ash/components/tether/host_scan_test_util.h
+++ b/chromeos/ash/components/tether/host_scan_test_util.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_HOST_SCAN_TEST_UTIL_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCAN_TEST_UTIL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_TEST_UTIL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_TEST_UTIL_H_
 
 #include <string>
 #include <unordered_map>
 
-#include "ash/components/tether/host_scan_cache_entry.h"
+#include "chromeos/ash/components/tether/host_scan_cache_entry.h"
 
 namespace ash {
 
@@ -57,4 +57,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCAN_TEST_UTIL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCAN_TEST_UTIL_H_
diff --git a/ash/components/tether/host_scanner.cc b/chromeos/ash/components/tether/host_scanner.cc
similarity index 91%
rename from ash/components/tether/host_scanner.cc
rename to chromeos/ash/components/tether/host_scanner.cc
index 1d3d04f..1867d17 100644
--- a/ash/components/tether/host_scanner.cc
+++ b/chromeos/ash/components/tether/host_scanner.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 "ash/components/tether/host_scanner.h"
+#include "chromeos/ash/components/tether/host_scanner.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/host_scanner.h b/chromeos/ash/components/tether/host_scanner.h
similarity index 87%
rename from ash/components/tether/host_scanner.h
rename to chromeos/ash/components/tether/host_scanner.h
index 08f7702b..d804b78 100644
--- a/ash/components/tether/host_scanner.h
+++ b/chromeos/ash/components/tether/host_scanner.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 ASH_COMPONENTS_TETHER_HOST_SCANNER_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCANNER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCANNER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCANNER_H_
 
 #include "base/observer_list.h"
 
@@ -54,4 +54,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCANNER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCANNER_H_
diff --git a/ash/components/tether/host_scanner_impl.cc b/chromeos/ash/components/tether/host_scanner_impl.cc
similarity index 94%
rename from ash/components/tether/host_scanner_impl.cc
rename to chromeos/ash/components/tether/host_scanner_impl.cc
index cfed231..cc02cd2 100644
--- a/ash/components/tether/host_scanner_impl.cc
+++ b/chromeos/ash/components/tether/host_scanner_impl.cc
@@ -2,22 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_scanner_impl.h"
+#include "chromeos/ash/components/tether/host_scanner_impl.h"
 
 #include <algorithm>
 
-#include "ash/components/tether/connection_preserver.h"
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/device_status_util.h"
-#include "ash/components/tether/gms_core_notifications_state_tracker_impl.h"
-#include "ash/components/tether/host_scan_cache.h"
-#include "ash/components/tether/tether_host_fetcher.h"
-#include "ash/components/tether/top_level_host_scan_cache.h"
 #include "ash/constants/ash_switches.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "chromeos/ash/components/network/network_state.h"
+#include "chromeos/ash/components/tether/connection_preserver.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/device_status_util.h"
+#include "chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/top_level_host_scan_cache.h"
 #include "components/session_manager/core/session_manager.h"
 
 namespace ash {
diff --git a/ash/components/tether/host_scanner_impl.h b/chromeos/ash/components/tether/host_scanner_impl.h
similarity index 88%
rename from ash/components/tether/host_scanner_impl.h
rename to chromeos/ash/components/tether/host_scanner_impl.h
index c429933..ad7b1710 100644
--- a/ash/components/tether/host_scanner_impl.h
+++ b/chromeos/ash/components/tether/host_scanner_impl.h
@@ -2,37 +2,37 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_HOST_SCANNER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCANNER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCANNER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCANNER_IMPL_H_
 
 #include <string>
 #include <unordered_set>
 #include <vector>
 
-#include "ash/components/tether/host_scanner.h"
-#include "ash/components/tether/host_scanner_operation.h"
-#include "ash/components/tether/notification_presenter.h"
-#include "chromeos/ash/components/multidevice/remote_device_ref.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/time/clock.h"
+#include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/host_scanner.h"
+#include "chromeos/ash/components/tether/host_scanner_operation.h"
+#include "chromeos/ash/components/tether/notification_presenter.h"
 #include "components/session_manager/core/session_manager_observer.h"
 
-namespace session_manager {
-class SessionManager;
-}  // namespace session_manager
-
-namespace ash {
-
-namespace device_sync {
+namespace ash::device_sync {
 class DeviceSyncClient;
 }
 
-namespace tether {
+namespace ash::secure_channel {
+class SecureChannelClient;
+}
+
+namespace session_manager {
+class SessionManager;
+}
+
+namespace ash::tether {
 
 class ConnectionPreserver;
 class DeviceIdTetherNetworkGuidMap;
@@ -142,8 +142,6 @@
   base::WeakPtrFactory<HostScannerImpl> weak_ptr_factory_{this};
 };
 
-}  // namespace tether
+}  // namespace ash::tether
 
-}  // namespace ash
-
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCANNER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCANNER_IMPL_H_
diff --git a/ash/components/tether/host_scanner_impl_unittest.cc b/chromeos/ash/components/tether/host_scanner_impl_unittest.cc
similarity index 97%
rename from ash/components/tether/host_scanner_impl_unittest.cc
rename to chromeos/ash/components/tether/host_scanner_impl_unittest.cc
index 8892aff0..1091b52 100644
--- a/ash/components/tether/host_scanner_impl_unittest.cc
+++ b/chromeos/ash/components/tether/host_scanner_impl_unittest.cc
@@ -2,25 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_scanner_impl.h"
+#include "chromeos/ash/components/tether/host_scanner_impl.h"
 
 #include <algorithm>
 #include <memory>
 #include <vector>
 
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/fake_connection_preserver.h"
-#include "ash/components/tether/fake_host_scan_cache.h"
-#include "ash/components/tether/fake_notification_presenter.h"
-#include "ash/components/tether/fake_tether_host_fetcher.h"
-#include "ash/components/tether/gms_core_notifications_state_tracker_impl.h"
-#include "ash/components/tether/host_scan_device_prioritizer.h"
-#include "ash/components/tether/host_scanner.h"
-#include "ash/components/tether/mock_tether_host_response_recorder.h"
-#include "ash/components/tether/proto_test_util.h"
-#include "ash/components/tether/top_level_host_scan_cache.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -29,6 +19,17 @@
 #include "base/time/time.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/fake_connection_preserver.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/fake_notification_presenter.h"
+#include "chromeos/ash/components/tether/fake_tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/gms_core_notifications_state_tracker_impl.h"
+#include "chromeos/ash/components/tether/host_scan_device_prioritizer.h"
+#include "chromeos/ash/components/tether/host_scanner.h"
+#include "chromeos/ash/components/tether/mock_tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/proto_test_util.h"
+#include "chromeos/ash/components/tether/top_level_host_scan_cache.h"
 #include "components/session_manager/core/session_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
diff --git a/ash/components/tether/host_scanner_operation.cc b/chromeos/ash/components/tether/host_scanner_operation.cc
similarity index 95%
rename from ash/components/tether/host_scanner_operation.cc
rename to chromeos/ash/components/tether/host_scanner_operation.cc
index 1d4d2fb4..2d5be86a 100644
--- a/ash/components/tether/host_scanner_operation.cc
+++ b/chromeos/ash/components/tether/host_scanner_operation.cc
@@ -2,21 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_scanner_operation.h"
+#include "chromeos/ash/components/tether/host_scanner_operation.h"
 
 #include <memory>
 
-#include "ash/components/tether/connection_preserver.h"
-#include "ash/components/tether/host_scan_device_prioritizer.h"
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/proto/tether.pb.h"
-#include "ash/components/tether/tether_host_response_recorder.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/ash/components/tether/connection_preserver.h"
+#include "chromeos/ash/components/tether/host_scan_device_prioritizer.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/host_scanner_operation.h b/chromeos/ash/components/tether/host_scanner_operation.h
similarity index 91%
rename from ash/components/tether/host_scanner_operation.h
rename to chromeos/ash/components/tether/host_scanner_operation.h
index 774df64..3b8f282 100644
--- a/ash/components/tether/host_scanner_operation.h
+++ b/chromeos/ash/components/tether/host_scanner_operation.h
@@ -2,28 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_HOST_SCANNER_OPERATION_H_
-#define ASH_COMPONENTS_TETHER_HOST_SCANNER_OPERATION_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCANNER_OPERATION_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCANNER_OPERATION_H_
 
 #include <map>
 #include <vector>
 
-#include "ash/components/tether/message_transfer_operation.h"
-#include "base/time/time.h"
-#include "chromeos/ash/components/multidevice/remote_device_ref.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/gtest_prod_util.h"
 #include "base/observer_list.h"
 #include "base/time/clock.h"
+#include "base/time/time.h"
+#include "chromeos/ash/components/multidevice/remote_device_ref.h"
+#include "chromeos/ash/components/tether/message_transfer_operation.h"
 
-namespace ash {
-
-namespace device_sync {
+namespace ash::device_sync {
 class DeviceSyncClient;
 }
 
-namespace tether {
+namespace ash::secure_channel {
+class SecureChannelClient;
+}
+
+namespace ash::tether {
 
 class ConnectionPreserver;
 class HostScanDevicePrioritizer;
@@ -152,8 +152,6 @@
   base::WeakPtrFactory<HostScannerOperation> weak_ptr_factory_{this};
 };
 
-}  // namespace tether
+}  // namespace ash::tether
 
-}  // namespace ash
-
-#endif  // ASH_COMPONENTS_TETHER_HOST_SCANNER_OPERATION_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOST_SCANNER_OPERATION_H_
diff --git a/ash/components/tether/host_scanner_operation_unittest.cc b/chromeos/ash/components/tether/host_scanner_operation_unittest.cc
similarity index 96%
rename from ash/components/tether/host_scanner_operation_unittest.cc
rename to chromeos/ash/components/tether/host_scanner_operation_unittest.cc
index 2ef3f3ef..8cfa40b 100644
--- a/ash/components/tether/host_scanner_operation_unittest.cc
+++ b/chromeos/ash/components/tether/host_scanner_operation_unittest.cc
@@ -2,18 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/host_scanner_operation.h"
+#include "chromeos/ash/components/tether/host_scanner_operation.h"
 
 #include <algorithm>
 #include <memory>
 #include <vector>
 
-#include "ash/components/tether/fake_connection_preserver.h"
-#include "ash/components/tether/host_scan_device_prioritizer.h"
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/mock_tether_host_response_recorder.h"
-#include "ash/components/tether/proto/tether.pb.h"
-#include "ash/components/tether/proto_test_util.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_client_channel.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_connection_attempt.h"
@@ -24,6 +18,12 @@
 #include "base/test/task_environment.h"
 #include "base/test/test_simple_task_runner.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/fake_connection_preserver.h"
+#include "chromeos/ash/components/tether/host_scan_device_prioritizer.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/mock_tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
+#include "chromeos/ash/components/tether/proto_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
diff --git a/ash/components/tether/hotspot_usage_duration_tracker.cc b/chromeos/ash/components/tether/hotspot_usage_duration_tracker.cc
similarity index 97%
rename from ash/components/tether/hotspot_usage_duration_tracker.cc
rename to chromeos/ash/components/tether/hotspot_usage_duration_tracker.cc
index d1c05ee7..28906cdb 100644
--- a/ash/components/tether/hotspot_usage_duration_tracker.cc
+++ b/chromeos/ash/components/tether/hotspot_usage_duration_tracker.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 "ash/components/tether/hotspot_usage_duration_tracker.h"
+#include "chromeos/ash/components/tether/hotspot_usage_duration_tracker.h"
 
 #include "base/metrics/histogram_macros.h"
 #include "base/time/clock.h"
diff --git a/ash/components/tether/hotspot_usage_duration_tracker.h b/chromeos/ash/components/tether/hotspot_usage_duration_tracker.h
similarity index 80%
rename from ash/components/tether/hotspot_usage_duration_tracker.h
rename to chromeos/ash/components/tether/hotspot_usage_duration_tracker.h
index 80ed1d15..3d0e0e9 100644
--- a/ash/components/tether/hotspot_usage_duration_tracker.h
+++ b/chromeos/ash/components/tether/hotspot_usage_duration_tracker.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_HOTSPOT_USAGE_DURATION_TRACKER_H_
-#define ASH_COMPONENTS_TETHER_HOTSPOT_USAGE_DURATION_TRACKER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_HOTSPOT_USAGE_DURATION_TRACKER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_HOTSPOT_USAGE_DURATION_TRACKER_H_
 
-#include "ash/components/tether/active_host.h"
 #include "base/time/time.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
 namespace base {
 class Clock;
@@ -48,4 +48,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_HOTSPOT_USAGE_DURATION_TRACKER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_HOTSPOT_USAGE_DURATION_TRACKER_H_
diff --git a/ash/components/tether/hotspot_usage_duration_tracker_unittest.cc b/chromeos/ash/components/tether/hotspot_usage_duration_tracker_unittest.cc
similarity index 96%
rename from ash/components/tether/hotspot_usage_duration_tracker_unittest.cc
rename to chromeos/ash/components/tether/hotspot_usage_duration_tracker_unittest.cc
index e4833ad..afd71dd 100644
--- a/ash/components/tether/hotspot_usage_duration_tracker_unittest.cc
+++ b/chromeos/ash/components/tether/hotspot_usage_duration_tracker_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/hotspot_usage_duration_tracker.h"
+#include "chromeos/ash/components/tether/hotspot_usage_duration_tracker.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_active_host.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/components/tether/keep_alive_operation.cc b/chromeos/ash/components/tether/keep_alive_operation.cc
similarity index 93%
rename from ash/components/tether/keep_alive_operation.cc
rename to chromeos/ash/components/tether/keep_alive_operation.cc
index 7b1d36d..2917c4a 100644
--- a/ash/components/tether/keep_alive_operation.cc
+++ b/chromeos/ash/components/tether/keep_alive_operation.cc
@@ -2,14 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/keep_alive_operation.h"
+#include "chromeos/ash/components/tether/keep_alive_operation.h"
 
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/proto/tether.pb.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/keep_alive_operation.h b/chromeos/ash/components/tether/keep_alive_operation.h
similarity index 85%
rename from ash/components/tether/keep_alive_operation.h
rename to chromeos/ash/components/tether/keep_alive_operation.h
index bb456619..2881664 100644
--- a/ash/components/tether/keep_alive_operation.h
+++ b/chromeos/ash/components/tether/keep_alive_operation.h
@@ -2,24 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_
-#define ASH_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_
 
-#include "ash/components/tether/message_transfer_operation.h"
-#include "base/time/time.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/gtest_prod_util.h"
 #include "base/observer_list.h"
 #include "base/time/clock.h"
+#include "base/time/time.h"
+#include "chromeos/ash/components/tether/message_transfer_operation.h"
 
-namespace ash {
-
-namespace device_sync {
+namespace ash::device_sync {
 class DeviceSyncClient;
 }
 
-namespace tether {
+namespace ash::secure_channel {
+class SecureChannelClient;
+}
+
+namespace ash::tether {
 
 // Operation which sends a keep-alive message to a tether host and receives an
 // update about the host's status.
@@ -94,8 +94,6 @@
   base::Time keep_alive_tickle_request_start_time_;
 };
 
-}  // namespace tether
+}  // namespace ash::tether
 
-}  // namespace ash
-
-#endif  // ASH_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_
diff --git a/ash/components/tether/keep_alive_operation_unittest.cc b/chromeos/ash/components/tether/keep_alive_operation_unittest.cc
similarity index 96%
rename from ash/components/tether/keep_alive_operation_unittest.cc
rename to chromeos/ash/components/tether/keep_alive_operation_unittest.cc
index fde8180..124175f7e 100644
--- a/ash/components/tether/keep_alive_operation_unittest.cc
+++ b/chromeos/ash/components/tether/keep_alive_operation_unittest.cc
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/keep_alive_operation.h"
+#include "chromeos/ash/components/tether/keep_alive_operation.h"
 
 #include <memory>
 #include <vector>
 
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/proto_test_util.h"
-#include "ash/components/tether/test_timer_factory.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_client_channel.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_connection_attempt.h"
@@ -18,6 +15,9 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/proto_test_util.h"
+#include "chromeos/ash/components/tether/test_timer_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/ash/components/tether/keep_alive_scheduler.cc b/chromeos/ash/components/tether/keep_alive_scheduler.cc
similarity index 95%
rename from ash/components/tether/keep_alive_scheduler.cc
rename to chromeos/ash/components/tether/keep_alive_scheduler.cc
index b156300..404f988 100644
--- a/ash/components/tether/keep_alive_scheduler.cc
+++ b/chromeos/ash/components/tether/keep_alive_scheduler.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/keep_alive_scheduler.h"
+#include "chromeos/ash/components/tether/keep_alive_scheduler.h"
 
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/host_scan_cache.h"
 #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
 #include "base/metrics/histogram_functions.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/keep_alive_scheduler.h b/chromeos/ash/components/tether/keep_alive_scheduler.h
similarity index 81%
rename from ash/components/tether/keep_alive_scheduler.h
rename to chromeos/ash/components/tether/keep_alive_scheduler.h
index af5e4795..7906a76b 100644
--- a/ash/components/tether/keep_alive_scheduler.h
+++ b/chromeos/ash/components/tether/keep_alive_scheduler.h
@@ -2,27 +2,27 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_KEEP_ALIVE_SCHEDULER_H_
-#define ASH_COMPONENTS_TETHER_KEEP_ALIVE_SCHEDULER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_KEEP_ALIVE_SCHEDULER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_KEEP_ALIVE_SCHEDULER_H_
 
 #include <memory>
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/device_status_util.h"
-#include "ash/components/tether/keep_alive_operation.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/device_status_util.h"
+#include "chromeos/ash/components/tether/keep_alive_operation.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace ash {
-
-namespace device_sync {
+namespace ash::device_sync {
 class DeviceSyncClient;
 }
 
-namespace tether {
+namespace ash::secure_channel {
+class SecureChannelClient;
+}
+
+namespace ash::tether {
 
 class HostScanCache;
 class DeviceIdTetherNetworkGuidMap;
@@ -83,8 +83,6 @@
   base::WeakPtrFactory<KeepAliveScheduler> weak_ptr_factory_{this};
 };
 
-}  // namespace tether
+}  // namespace ash::tether
 
-}  // namespace ash
-
-#endif  // ASH_COMPONENTS_TETHER_KEEP_ALIVE_SCHEDULER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_KEEP_ALIVE_SCHEDULER_H_
diff --git a/ash/components/tether/keep_alive_scheduler_unittest.cc b/chromeos/ash/components/tether/keep_alive_scheduler_unittest.cc
similarity index 96%
rename from ash/components/tether/keep_alive_scheduler_unittest.cc
rename to chromeos/ash/components/tether/keep_alive_scheduler_unittest.cc
index 2d14ecb..22653e4 100644
--- a/ash/components/tether/keep_alive_scheduler_unittest.cc
+++ b/chromeos/ash/components/tether/keep_alive_scheduler_unittest.cc
@@ -2,20 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/keep_alive_scheduler.h"
+#include "chromeos/ash/components/tether/keep_alive_scheduler.h"
 
 #include <memory>
 #include <vector>
 
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/fake_host_scan_cache.h"
-#include "ash/components/tether/proto_test_util.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ptr_util.h"
 #include "base/timer/mock_timer.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/proto_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
diff --git a/ash/components/tether/message_transfer_operation.cc b/chromeos/ash/components/tether/message_transfer_operation.cc
similarity index 97%
rename from ash/components/tether/message_transfer_operation.cc
rename to chromeos/ash/components/tether/message_transfer_operation.cc
index b4b0f662..4f2549b9 100644
--- a/ash/components/tether/message_transfer_operation.cc
+++ b/chromeos/ash/components/tether/message_transfer_operation.cc
@@ -2,16 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/message_transfer_operation.h"
+#include "chromeos/ash/components/tether/message_transfer_operation.h"
 
 #include <memory>
 #include <set>
 
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/timer_factory.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/timer_factory.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/message_transfer_operation.h b/chromeos/ash/components/tether/message_transfer_operation.h
similarity index 94%
rename from ash/components/tether/message_transfer_operation.h
rename to chromeos/ash/components/tether/message_transfer_operation.h
index 37709ca9..0af038e 100644
--- a/ash/components/tether/message_transfer_operation.h
+++ b/chromeos/ash/components/tether/message_transfer_operation.h
@@ -2,28 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_MESSAGE_TRANSFER_OPERATION_H_
-#define ASH_COMPONENTS_TETHER_MESSAGE_TRANSFER_OPERATION_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_MESSAGE_TRANSFER_OPERATION_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_MESSAGE_TRANSFER_OPERATION_H_
 
 #include <map>
 #include <vector>
 
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/proto/tether.pb.h"
 #include "ash/services/device_sync/public/cpp/device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/client_channel.h"
 #include "ash/services/secure_channel/public/cpp/client/connection_attempt.h"
-// TODO(https://crbug.com/1164001): move to forward declaration.
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "ash/services/secure_channel/public/cpp/shared/connection_priority.h"
 #include "ash/services/secure_channel/public/mojom/secure_channel.mojom.h"
 #include "base/timer/timer.h"
 #include "base/unguessable_token.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace ash {
+namespace ash::secure_channel {
+class SecureChannelClient;
+}
 
-namespace tether {
+namespace ash::tether {
 
 class TimerFactory;
 
@@ -207,8 +207,6 @@
   base::WeakPtrFactory<MessageTransferOperation> weak_ptr_factory_{this};
 };
 
-}  // namespace tether
+}  // namespace ash::tether
 
-}  // namespace ash
-
-#endif  // ASH_COMPONENTS_TETHER_MESSAGE_TRANSFER_OPERATION_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_MESSAGE_TRANSFER_OPERATION_H_
diff --git a/ash/components/tether/message_transfer_operation_unittest.cc b/chromeos/ash/components/tether/message_transfer_operation_unittest.cc
similarity index 97%
rename from ash/components/tether/message_transfer_operation_unittest.cc
rename to chromeos/ash/components/tether/message_transfer_operation_unittest.cc
index 5c0c726..c8a0770 100644
--- a/ash/components/tether/message_transfer_operation_unittest.cc
+++ b/chromeos/ash/components/tether/message_transfer_operation_unittest.cc
@@ -2,20 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/message_transfer_operation.h"
+#include "chromeos/ash/components/tether/message_transfer_operation.h"
 
 #include <memory>
 
-#include "ash/components/tether/message_wrapper.h"
-#include "ash/components/tether/proto_test_util.h"
-#include "ash/components/tether/test_timer_factory.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_client_channel.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_connection_attempt.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ptr_util.h"
 #include "base/timer/mock_timer.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/proto_test_util.h"
+#include "chromeos/ash/components/tether/test_timer_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/components/tether/message_wrapper.cc b/chromeos/ash/components/tether/message_wrapper.cc
similarity index 98%
rename from ash/components/tether/message_wrapper.cc
rename to chromeos/ash/components/tether/message_wrapper.cc
index 4110e29..0d1038f 100644
--- a/ash/components/tether/message_wrapper.cc
+++ b/chromeos/ash/components/tether/message_wrapper.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 "ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/message_wrapper.h b/chromeos/ash/components/tether/message_wrapper.h
similarity index 89%
rename from ash/components/tether/message_wrapper.h
rename to chromeos/ash/components/tether/message_wrapper.h
index 847226a2..6db2f83 100644
--- a/ash/components/tether/message_wrapper.h
+++ b/chromeos/ash/components/tether/message_wrapper.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_MESSAGE_WRAPPER_H_
-#define ASH_COMPONENTS_TETHER_MESSAGE_WRAPPER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_MESSAGE_WRAPPER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_MESSAGE_WRAPPER_H_
 
 #include <google/protobuf/message_lite.h>
 #include <memory>
 
-#include "ash/components/tether/proto/tether.pb.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
 
 namespace ash {
 
@@ -62,4 +62,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_MESSAGE_WRAPPER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_MESSAGE_WRAPPER_H_
diff --git a/ash/components/tether/message_wrapper_unittest.cc b/chromeos/ash/components/tether/message_wrapper_unittest.cc
similarity index 97%
rename from ash/components/tether/message_wrapper_unittest.cc
rename to chromeos/ash/components/tether/message_wrapper_unittest.cc
index ee9dd03e..49c6981 100644
--- a/ash/components/tether/message_wrapper_unittest.cc
+++ b/chromeos/ash/components/tether/message_wrapper_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/message_wrapper.h"
+#include "chromeos/ash/components/tether/message_wrapper.h"
 
 #include <sstream>
 
-#include "ash/components/tether/proto/tether.pb.h"
-#include "ash/components/tether/proto_test_util.h"
 #include "base/base64url.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
+#include "chromeos/ash/components/tether/proto_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/components/tether/mock_host_connection_metrics_logger.cc b/chromeos/ash/components/tether/mock_host_connection_metrics_logger.cc
similarity index 76%
rename from ash/components/tether/mock_host_connection_metrics_logger.cc
rename to chromeos/ash/components/tether/mock_host_connection_metrics_logger.cc
index 3bc0b6c..2dab9c1 100644
--- a/ash/components/tether/mock_host_connection_metrics_logger.cc
+++ b/chromeos/ash/components/tether/mock_host_connection_metrics_logger.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/mock_host_connection_metrics_logger.h"
+#include "chromeos/ash/components/tether/mock_host_connection_metrics_logger.h"
 
-#include "ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/mock_host_connection_metrics_logger.h b/chromeos/ash/components/tether/mock_host_connection_metrics_logger.h
similarity index 73%
rename from ash/components/tether/mock_host_connection_metrics_logger.h
rename to chromeos/ash/components/tether/mock_host_connection_metrics_logger.h
index 98572b9..552281bd 100644
--- a/ash/components/tether/mock_host_connection_metrics_logger.h
+++ b/chromeos/ash/components/tether/mock_host_connection_metrics_logger.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_MOCK_HOST_CONNECTION_METRICS_LOGGER_H_
-#define ASH_COMPONENTS_TETHER_MOCK_HOST_CONNECTION_METRICS_LOGGER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_MOCK_HOST_CONNECTION_METRICS_LOGGER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_MOCK_HOST_CONNECTION_METRICS_LOGGER_H_
 
 #include <string>
 
-#include "ash/components/tether/host_connection_metrics_logger.h"
+#include "chromeos/ash/components/tether/host_connection_metrics_logger.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace ash {
@@ -36,4 +36,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_MOCK_HOST_CONNECTION_METRICS_LOGGER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_MOCK_HOST_CONNECTION_METRICS_LOGGER_H_
diff --git a/ash/components/tether/mock_tether_host_response_recorder.cc b/chromeos/ash/components/tether/mock_tether_host_response_recorder.cc
similarity index 83%
rename from ash/components/tether/mock_tether_host_response_recorder.cc
rename to chromeos/ash/components/tether/mock_tether_host_response_recorder.cc
index ec517e2..46fdb90c 100644
--- a/ash/components/tether/mock_tether_host_response_recorder.cc
+++ b/chromeos/ash/components/tether/mock_tether_host_response_recorder.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 "ash/components/tether/mock_tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/mock_tether_host_response_recorder.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/mock_tether_host_response_recorder.h b/chromeos/ash/components/tether/mock_tether_host_response_recorder.h
similarity index 78%
rename from ash/components/tether/mock_tether_host_response_recorder.h
rename to chromeos/ash/components/tether/mock_tether_host_response_recorder.h
index f450517..9b90e8f4 100644
--- a/ash/components/tether/mock_tether_host_response_recorder.h
+++ b/chromeos/ash/components/tether/mock_tether_host_response_recorder.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_MOCK_TETHER_HOST_RESPONSE_RECORDER_H_
-#define ASH_COMPONENTS_TETHER_MOCK_TETHER_HOST_RESPONSE_RECORDER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_MOCK_TETHER_HOST_RESPONSE_RECORDER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_MOCK_TETHER_HOST_RESPONSE_RECORDER_H_
 
 #include <vector>
 
-#include "ash/components/tether/tether_host_response_recorder.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace ash {
@@ -39,4 +39,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_MOCK_TETHER_HOST_RESPONSE_RECORDER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_MOCK_TETHER_HOST_RESPONSE_RECORDER_H_
diff --git a/ash/components/tether/network_configuration_remover.cc b/chromeos/ash/components/tether/network_configuration_remover.cc
similarity index 95%
rename from ash/components/tether/network_configuration_remover.cc
rename to chromeos/ash/components/tether/network_configuration_remover.cc
index 1cd0a3cb..e95bc2e 100644
--- a/ash/components/tether/network_configuration_remover.cc
+++ b/chromeos/ash/components/tether/network_configuration_remover.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 "ash/components/tether/network_configuration_remover.h"
+#include "chromeos/ash/components/tether/network_configuration_remover.h"
 
 #include "base/bind.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
diff --git a/ash/components/tether/network_configuration_remover.h b/chromeos/ash/components/tether/network_configuration_remover.h
similarity index 83%
rename from ash/components/tether/network_configuration_remover.h
rename to chromeos/ash/components/tether/network_configuration_remover.h
index cc042f3..4cc048be 100644
--- a/ash/components/tether/network_configuration_remover.h
+++ b/chromeos/ash/components/tether/network_configuration_remover.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 ASH_COMPONENTS_TETHER_NETWORK_CONFIGURATION_REMOVER_H_
-#define ASH_COMPONENTS_TETHER_NETWORK_CONFIGURATION_REMOVER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_CONFIGURATION_REMOVER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_CONFIGURATION_REMOVER_H_
 
 #include <string>
 
@@ -40,4 +40,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_NETWORK_CONFIGURATION_REMOVER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_CONFIGURATION_REMOVER_H_
diff --git a/ash/components/tether/network_configuration_remover_unittest.cc b/chromeos/ash/components/tether/network_configuration_remover_unittest.cc
similarity index 95%
rename from ash/components/tether/network_configuration_remover_unittest.cc
rename to chromeos/ash/components/tether/network_configuration_remover_unittest.cc
index e856e6a..28a1b81 100644
--- a/ash/components/tether/network_configuration_remover_unittest.cc
+++ b/chromeos/ash/components/tether/network_configuration_remover_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 "ash/components/tether/network_configuration_remover.h"
+#include "chromeos/ash/components/tether/network_configuration_remover.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/network_connection_handler_tether_delegate.cc b/chromeos/ash/components/tether/network_connection_handler_tether_delegate.cc
similarity index 94%
rename from ash/components/tether/network_connection_handler_tether_delegate.cc
rename to chromeos/ash/components/tether/network_connection_handler_tether_delegate.cc
index 655242ac..2056df9 100644
--- a/ash/components/tether/network_connection_handler_tether_delegate.cc
+++ b/chromeos/ash/components/tether/network_connection_handler_tether_delegate.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/network_connection_handler_tether_delegate.h"
+#include "chromeos/ash/components/tether/network_connection_handler_tether_delegate.h"
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/tether_connector.h"
-#include "ash/components/tether/tether_disconnector.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/containers/contains.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/tether_connector.h"
+#include "chromeos/ash/components/tether/tether_disconnector.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/network_connection_handler_tether_delegate.h b/chromeos/ash/components/tether/network_connection_handler_tether_delegate.h
similarity index 90%
rename from ash/components/tether/network_connection_handler_tether_delegate.h
rename to chromeos/ash/components/tether/network_connection_handler_tether_delegate.h
index 68a7f749..2bcf7c7 100644
--- a/ash/components/tether/network_connection_handler_tether_delegate.h
+++ b/chromeos/ash/components/tether/network_connection_handler_tether_delegate.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 ASH_COMPONENTS_TETHER_NETWORK_CONNECTION_HANDLER_TETHER_DELEGATE_H_
-#define ASH_COMPONENTS_TETHER_NETWORK_CONNECTION_HANDLER_TETHER_DELEGATE_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_CONNECTION_HANDLER_TETHER_DELEGATE_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_CONNECTION_HANDLER_TETHER_DELEGATE_H_
 
 #include <unordered_map>
 
@@ -76,4 +76,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_NETWORK_CONNECTION_HANDLER_TETHER_DELEGATE_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_CONNECTION_HANDLER_TETHER_DELEGATE_H_
diff --git a/ash/components/tether/network_connection_handler_tether_delegate_unittest.cc b/chromeos/ash/components/tether/network_connection_handler_tether_delegate_unittest.cc
similarity index 94%
rename from ash/components/tether/network_connection_handler_tether_delegate_unittest.cc
rename to chromeos/ash/components/tether/network_connection_handler_tether_delegate_unittest.cc
index fc2d5a28..fd44829 100644
--- a/ash/components/tether/network_connection_handler_tether_delegate_unittest.cc
+++ b/chromeos/ash/components/tether/network_connection_handler_tether_delegate_unittest.cc
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/network_connection_handler_tether_delegate.h"
+#include "chromeos/ash/components/tether/network_connection_handler_tether_delegate.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/fake_tether_connector.h"
-#include "ash/components/tether/fake_tether_disconnector.h"
-#include "ash/components/tether/tether_disconnector.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/ash/components/network/network_connection_handler.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_tether_connector.h"
+#include "chromeos/ash/components/tether/fake_tether_disconnector.h"
+#include "chromeos/ash/components/tether/tether_disconnector.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
diff --git a/ash/components/tether/network_host_scan_cache.cc b/chromeos/ash/components/tether/network_host_scan_cache.cc
similarity index 95%
rename from ash/components/tether/network_host_scan_cache.cc
rename to chromeos/ash/components/tether/network_host_scan_cache.cc
index f1cbc7db..f032efb 100644
--- a/ash/components/tether/network_host_scan_cache.cc
+++ b/chromeos/ash/components/tether/network_host_scan_cache.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/network_host_scan_cache.h"
+#include "chromeos/ash/components/tether/network_host_scan_cache.h"
 
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/tether_host_response_recorder.h"
 #include "base/containers/contains.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/network_host_scan_cache.h b/chromeos/ash/components/tether/network_host_scan_cache.h
similarity index 84%
rename from ash/components/tether/network_host_scan_cache.h
rename to chromeos/ash/components/tether/network_host_scan_cache.h
index 073cef0b..b4c20f9d 100644
--- a/ash/components/tether/network_host_scan_cache.h
+++ b/chromeos/ash/components/tether/network_host_scan_cache.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_NETWORK_HOST_SCAN_CACHE_H_
-#define ASH_COMPONENTS_TETHER_NETWORK_HOST_SCAN_CACHE_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_HOST_SCAN_CACHE_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_HOST_SCAN_CACHE_H_
 
 #include <memory>
 #include <string>
 #include <unordered_set>
 
-#include "ash/components/tether/host_scan_cache.h"
-#include "ash/components/tether/tether_host_response_recorder.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 
 namespace ash {
 
@@ -64,4 +64,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_NETWORK_HOST_SCAN_CACHE_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_HOST_SCAN_CACHE_H_
diff --git a/ash/components/tether/network_host_scan_cache_unittest.cc b/chromeos/ash/components/tether/network_host_scan_cache_unittest.cc
similarity index 95%
rename from ash/components/tether/network_host_scan_cache_unittest.cc
rename to chromeos/ash/components/tether/network_host_scan_cache_unittest.cc
index cf4a2b25..f673054f 100644
--- a/ash/components/tether/network_host_scan_cache_unittest.cc
+++ b/chromeos/ash/components/tether/network_host_scan_cache_unittest.cc
@@ -2,25 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/network_host_scan_cache.h"
+#include "chromeos/ash/components/tether/network_host_scan_cache.h"
 
 #include <memory>
 #include <vector>
 
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/fake_host_scan_cache.h"
-#include "ash/components/tether/host_scan_test_util.h"
-#include "ash/components/tether/mock_tether_host_response_recorder.h"
 #include "base/containers/contains.h"
 #include "base/test/task_environment.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/host_scan_test_util.h"
+#include "chromeos/ash/components/tether/mock_tether_host_response_recorder.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using testing::NiceMock;
 using testing::Invoke;
+using testing::NiceMock;
 
 namespace ash {
 
diff --git a/ash/components/tether/network_list_sorter.cc b/chromeos/ash/components/tether/network_list_sorter.cc
similarity index 97%
rename from ash/components/tether/network_list_sorter.cc
rename to chromeos/ash/components/tether/network_list_sorter.cc
index 8fa4221..d23578f 100644
--- a/ash/components/tether/network_list_sorter.cc
+++ b/chromeos/ash/components/tether/network_list_sorter.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 "ash/components/tether/network_list_sorter.h"
+#include "chromeos/ash/components/tether/network_list_sorter.h"
 
 #include <algorithm>
 
diff --git a/ash/components/tether/network_list_sorter.h b/chromeos/ash/components/tether/network_list_sorter.h
similarity index 84%
rename from ash/components/tether/network_list_sorter.h
rename to chromeos/ash/components/tether/network_list_sorter.h
index 26d9f17d..2663e5c 100644
--- a/ash/components/tether/network_list_sorter.h
+++ b/chromeos/ash/components/tether/network_list_sorter.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 ASH_COMPONENTS_TETHER_NETWORK_LIST_SORTER_H_
-#define ASH_COMPONENTS_TETHER_NETWORK_LIST_SORTER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_LIST_SORTER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_LIST_SORTER_H_
 
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
@@ -34,4 +34,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_NETWORK_LIST_SORTER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_NETWORK_LIST_SORTER_H_
diff --git a/ash/components/tether/network_list_sorter_unittest.cc b/chromeos/ash/components/tether/network_list_sorter_unittest.cc
similarity index 98%
rename from ash/components/tether/network_list_sorter_unittest.cc
rename to chromeos/ash/components/tether/network_list_sorter_unittest.cc
index febea275..c164bc2a 100644
--- a/ash/components/tether/network_list_sorter_unittest.cc
+++ b/chromeos/ash/components/tether/network_list_sorter_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 "ash/components/tether/network_list_sorter.h"
+#include "chromeos/ash/components/tether/network_list_sorter.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/notification_presenter.h b/chromeos/ash/components/tether/notification_presenter.h
similarity index 86%
rename from ash/components/tether/notification_presenter.h
rename to chromeos/ash/components/tether/notification_presenter.h
index 134824fb..173157e5 100644
--- a/ash/components/tether/notification_presenter.h
+++ b/chromeos/ash/components/tether/notification_presenter.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 ASH_COMPONENTS_TETHER_NOTIFICATION_PRESENTER_H_
-#define ASH_COMPONENTS_TETHER_NOTIFICATION_PRESENTER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_NOTIFICATION_PRESENTER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_NOTIFICATION_PRESENTER_H_
 
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/network/network_state.h"
@@ -67,11 +67,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when the migration is finished.
-namespace chromeos {
-namespace tether {
-using ::ash::tether::NotificationPresenter;
-}  // namespace tether
-}  // namespace chromeos
-
-#endif  // ASH_COMPONENTS_TETHER_NOTIFICATION_PRESENTER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_NOTIFICATION_PRESENTER_H_
diff --git a/ash/components/tether/notification_remover.cc b/chromeos/ash/components/tether/notification_remover.cc
similarity index 94%
rename from ash/components/tether/notification_remover.cc
rename to chromeos/ash/components/tether/notification_remover.cc
index a892fb27..4de7239 100644
--- a/ash/components/tether/notification_remover.cc
+++ b/chromeos/ash/components/tether/notification_remover.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/notification_remover.h"
+#include "chromeos/ash/components/tether/notification_remover.h"
 
-#include "ash/components/tether/notification_presenter.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/notification_presenter.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/notification_remover.h b/chromeos/ash/components/tether/notification_remover.h
similarity index 85%
rename from ash/components/tether/notification_remover.h
rename to chromeos/ash/components/tether/notification_remover.h
index 90299f4..45cbe1c 100644
--- a/ash/components/tether/notification_remover.h
+++ b/chromeos/ash/components/tether/notification_remover.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_NOTIFICATION_REMOVER_H_
-#define ASH_COMPONENTS_TETHER_NOTIFICATION_REMOVER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_NOTIFICATION_REMOVER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_NOTIFICATION_REMOVER_H_
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/host_scan_cache.h"
 #include "chromeos/ash/components/network/network_state_handler_observer.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
 
 namespace ash {
 
@@ -57,4 +57,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_NOTIFICATION_REMOVER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_NOTIFICATION_REMOVER_H_
diff --git a/ash/components/tether/notification_remover_unittest.cc b/chromeos/ash/components/tether/notification_remover_unittest.cc
similarity index 92%
rename from ash/components/tether/notification_remover_unittest.cc
rename to chromeos/ash/components/tether/notification_remover_unittest.cc
index ffb691c..180f312 100644
--- a/ash/components/tether/notification_remover_unittest.cc
+++ b/chromeos/ash/components/tether/notification_remover_unittest.cc
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/notification_remover.h"
+#include "chromeos/ash/components/tether/notification_remover.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/fake_host_scan_cache.h"
-#include "ash/components/tether/fake_notification_presenter.h"
-#include "ash/components/tether/host_scan_test_util.h"
 #include "base/test/task_environment.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/fake_notification_presenter.h"
+#include "chromeos/ash/components/tether/host_scan_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
 
@@ -44,9 +44,7 @@
         host_scan_cache_.get(), active_host_.get());
   }
 
-  void TearDown() override {
-    notification_remover_.reset();
-  }
+  void TearDown() override { notification_remover_.reset(); }
 
   void NotifyPotentialHotspotNearby() {
     notification_presenter_->NotifyPotentialHotspotNearby(
diff --git a/ash/components/tether/persistent_host_scan_cache.h b/chromeos/ash/components/tether/persistent_host_scan_cache.h
similarity index 75%
rename from ash/components/tether/persistent_host_scan_cache.h
rename to chromeos/ash/components/tether/persistent_host_scan_cache.h
index 754aca0..8dd7941 100644
--- a/ash/components/tether/persistent_host_scan_cache.h
+++ b/chromeos/ash/components/tether/persistent_host_scan_cache.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_H_
-#define ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_H_
 
-#include "ash/components/tether/host_scan_cache.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
 
 namespace ash {
 
@@ -32,4 +32,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_H_
diff --git a/ash/components/tether/persistent_host_scan_cache_impl.cc b/chromeos/ash/components/tether/persistent_host_scan_cache_impl.cc
similarity index 97%
rename from ash/components/tether/persistent_host_scan_cache_impl.cc
rename to chromeos/ash/components/tether/persistent_host_scan_cache_impl.cc
index 1aced1c..538f596 100644
--- a/ash/components/tether/persistent_host_scan_cache_impl.cc
+++ b/chromeos/ash/components/tether/persistent_host_scan_cache_impl.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/persistent_host_scan_cache_impl.h"
+#include "chromeos/ash/components/tether/persistent_host_scan_cache_impl.h"
 
 #include <memory>
 #include <unordered_set>
 
-#include "ash/components/tether/pref_names.h"
 #include "base/check.h"
 #include "base/notreached.h"
+#include "chromeos/ash/components/tether/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
diff --git a/ash/components/tether/persistent_host_scan_cache_impl.h b/chromeos/ash/components/tether/persistent_host_scan_cache_impl.h
similarity index 84%
rename from ash/components/tether/persistent_host_scan_cache_impl.h
rename to chromeos/ash/components/tether/persistent_host_scan_cache_impl.h
index f1976030..82aae9fd 100644
--- a/ash/components/tether/persistent_host_scan_cache_impl.h
+++ b/chromeos/ash/components/tether/persistent_host_scan_cache_impl.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_IMPL_H_
-#define ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_IMPL_H_
 
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
 
-#include "ash/components/tether/persistent_host_scan_cache.h"
+#include "chromeos/ash/components/tether/persistent_host_scan_cache.h"
 
 class PrefRegistrySimple;
 class PrefService;
@@ -58,4 +58,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_PERSISTENT_HOST_SCAN_CACHE_IMPL_H_
diff --git a/ash/components/tether/persistent_host_scan_cache_impl_unittest.cc b/chromeos/ash/components/tether/persistent_host_scan_cache_impl_unittest.cc
similarity index 96%
rename from ash/components/tether/persistent_host_scan_cache_impl_unittest.cc
rename to chromeos/ash/components/tether/persistent_host_scan_cache_impl_unittest.cc
index 5d68f5a..0e4e9f4 100644
--- a/ash/components/tether/persistent_host_scan_cache_impl_unittest.cc
+++ b/chromeos/ash/components/tether/persistent_host_scan_cache_impl_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/persistent_host_scan_cache_impl.h"
+#include "chromeos/ash/components/tether/persistent_host_scan_cache_impl.h"
 
 #include <memory>
 #include <unordered_map>
 
-#include "ash/components/tether/fake_host_scan_cache.h"
-#include "ash/components/tether/host_scan_test_util.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/host_scan_test_util.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/components/tether/pref_names.cc b/chromeos/ash/components/tether/pref_names.cc
similarity index 93%
rename from ash/components/tether/pref_names.cc
rename to chromeos/ash/components/tether/pref_names.cc
index a516222a..c69ca84 100644
--- a/ash/components/tether/pref_names.cc
+++ b/chromeos/ash/components/tether/pref_names.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 "ash/components/tether/pref_names.h"
+#include "chromeos/ash/components/tether/pref_names.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/pref_names.h b/chromeos/ash/components/tether/pref_names.h
similarity index 93%
rename from ash/components/tether/pref_names.h
rename to chromeos/ash/components/tether/pref_names.h
index e2fec9f..beb4e3e3 100644
--- a/ash/components/tether/pref_names.h
+++ b/chromeos/ash/components/tether/pref_names.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 ASH_COMPONENTS_TETHER_PREF_NAMES_H_
-#define ASH_COMPONENTS_TETHER_PREF_NAMES_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_PREF_NAMES_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_PREF_NAMES_H_
 
 namespace ash {
 
@@ -61,4 +61,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_PREF_NAMES_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_PREF_NAMES_H_
diff --git a/ash/components/tether/proto/BUILD.gn b/chromeos/ash/components/tether/proto/BUILD.gn
similarity index 100%
rename from ash/components/tether/proto/BUILD.gn
rename to chromeos/ash/components/tether/proto/BUILD.gn
diff --git a/ash/components/tether/proto/tether.proto b/chromeos/ash/components/tether/proto/tether.proto
similarity index 100%
rename from ash/components/tether/proto/tether.proto
rename to chromeos/ash/components/tether/proto/tether.proto
diff --git a/ash/components/tether/proto_test_util.cc b/chromeos/ash/components/tether/proto_test_util.cc
similarity index 95%
rename from ash/components/tether/proto_test_util.cc
rename to chromeos/ash/components/tether/proto_test_util.cc
index 4a0b8632..29dc919 100644
--- a/ash/components/tether/proto_test_util.cc
+++ b/chromeos/ash/components/tether/proto_test_util.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 "ash/components/tether/proto_test_util.h"
+#include "chromeos/ash/components/tether/proto_test_util.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/proto_test_util.h b/chromeos/ash/components/tether/proto_test_util.h
similarity index 80%
rename from ash/components/tether/proto_test_util.h
rename to chromeos/ash/components/tether/proto_test_util.h
index d36e453b..7bc92c0 100644
--- a/ash/components/tether/proto_test_util.h
+++ b/chromeos/ash/components/tether/proto_test_util.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_PROTO_TEST_UTIL_H_
-#define ASH_COMPONENTS_TETHER_PROTO_TEST_UTIL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_PROTO_TEST_UTIL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_PROTO_TEST_UTIL_H_
 
-#include "ash/components/tether/proto/tether.pb.h"
+#include "chromeos/ash/components/tether/proto/tether.pb.h"
 
 namespace ash {
 
@@ -34,4 +34,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_PROTO_TEST_UTIL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_PROTO_TEST_UTIL_H_
diff --git a/ash/components/tether/synchronous_shutdown_object_container.h b/chromeos/ash/components/tether/synchronous_shutdown_object_container.h
similarity index 81%
rename from ash/components/tether/synchronous_shutdown_object_container.h
rename to chromeos/ash/components/tether/synchronous_shutdown_object_container.h
index b796339..d793f7a66 100644
--- a/ash/components/tether/synchronous_shutdown_object_container.h
+++ b/chromeos/ash/components/tether/synchronous_shutdown_object_container.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 ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
-#define ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
 
 namespace ash {
 
@@ -39,4 +39,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_H_
diff --git a/ash/components/tether/synchronous_shutdown_object_container_impl.cc b/chromeos/ash/components/tether/synchronous_shutdown_object_container_impl.cc
similarity index 81%
rename from ash/components/tether/synchronous_shutdown_object_container_impl.cc
rename to chromeos/ash/components/tether/synchronous_shutdown_object_container_impl.cc
index ec75eb4..dedc9bc 100644
--- a/ash/components/tether/synchronous_shutdown_object_container_impl.cc
+++ b/chromeos/ash/components/tether/synchronous_shutdown_object_container_impl.cc
@@ -2,36 +2,37 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/synchronous_shutdown_object_container_impl.h"
+#include "chromeos/ash/components/tether/synchronous_shutdown_object_container_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/active_host_network_state_updater.h"
-#include "ash/components/tether/asynchronous_shutdown_object_container.h"
-#include "ash/components/tether/connection_preserver_impl.h"
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/host_connection_metrics_logger.h"
-#include "ash/components/tether/host_scan_device_prioritizer_impl.h"
-#include "ash/components/tether/host_scan_scheduler_impl.h"
-#include "ash/components/tether/host_scanner_impl.h"
-#include "ash/components/tether/hotspot_usage_duration_tracker.h"
-#include "ash/components/tether/keep_alive_scheduler.h"
-#include "ash/components/tether/network_connection_handler_tether_delegate.h"
-#include "ash/components/tether/network_host_scan_cache.h"
-#include "ash/components/tether/network_list_sorter.h"
-#include "ash/components/tether/notification_remover.h"
-#include "ash/components/tether/persistent_host_scan_cache_impl.h"
-#include "ash/components/tether/tether_connector_impl.h"
-#include "ash/components/tether/tether_disconnector_impl.h"
-#include "ash/components/tether/tether_host_response_recorder.h"
-#include "ash/components/tether/tether_network_disconnection_handler.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
-#include "ash/components/tether/timer_factory.h"
-#include "ash/components/tether/top_level_host_scan_cache.h"
-#include "ash/components/tether/wifi_hotspot_connector.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ptr_util.h"
 #include "base/time/default_clock.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/active_host_network_state_updater.h"
+#include "chromeos/ash/components/tether/asynchronous_shutdown_object_container.h"
+#include "chromeos/ash/components/tether/connection_preserver_impl.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/host_connection_metrics_logger.h"
+#include "chromeos/ash/components/tether/host_scan_device_prioritizer_impl.h"
+#include "chromeos/ash/components/tether/host_scan_scheduler_impl.h"
+#include "chromeos/ash/components/tether/host_scanner_impl.h"
+#include "chromeos/ash/components/tether/hotspot_usage_duration_tracker.h"
+#include "chromeos/ash/components/tether/keep_alive_scheduler.h"
+#include "chromeos/ash/components/tether/network_connection_handler_tether_delegate.h"
+#include "chromeos/ash/components/tether/network_host_scan_cache.h"
+#include "chromeos/ash/components/tether/network_list_sorter.h"
+#include "chromeos/ash/components/tether/notification_remover.h"
+#include "chromeos/ash/components/tether/persistent_host_scan_cache_impl.h"
+#include "chromeos/ash/components/tether/tether_connector_impl.h"
+#include "chromeos/ash/components/tether/tether_disconnector_impl.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/tether_network_disconnection_handler.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
+#include "chromeos/ash/components/tether/timer_factory.h"
+#include "chromeos/ash/components/tether/top_level_host_scan_cache.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_connector.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/synchronous_shutdown_object_container_impl.h b/chromeos/ash/components/tether/synchronous_shutdown_object_container_impl.h
similarity index 92%
rename from ash/components/tether/synchronous_shutdown_object_container_impl.h
rename to chromeos/ash/components/tether/synchronous_shutdown_object_container_impl.h
index 980693e..9186ff8 100644
--- a/ash/components/tether/synchronous_shutdown_object_container_impl.h
+++ b/chromeos/ash/components/tether/synchronous_shutdown_object_container_impl.h
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
 
 #include <memory>
 
-#include "ash/components/tether/synchronous_shutdown_object_container.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
+#include "chromeos/ash/components/tether/synchronous_shutdown_object_container.h"
 
 class PrefService;
 
@@ -23,6 +21,10 @@
 class DeviceSyncClient;
 }
 
+namespace secure_channel {
+class SecureChannelClient;
+}
+
 class NetworkConnect;
 class NetworkConnectionHandler;
 class NetworkStateHandler;
@@ -157,4 +159,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_SYNCHRONOUS_SHUTDOWN_OBJECT_CONTAINER_IMPL_H_
diff --git a/ash/components/tether/test_timer_factory.cc b/chromeos/ash/components/tether/test_timer_factory.cc
similarity index 90%
rename from ash/components/tether/test_timer_factory.cc
rename to chromeos/ash/components/tether/test_timer_factory.cc
index 56066883..8df994e 100644
--- a/ash/components/tether/test_timer_factory.cc
+++ b/chromeos/ash/components/tether/test_timer_factory.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 "ash/components/tether/test_timer_factory.h"
+#include "chromeos/ash/components/tether/test_timer_factory.h"
 
 #include "base/check.h"
 
diff --git a/ash/components/tether/test_timer_factory.h b/chromeos/ash/components/tether/test_timer_factory.h
similarity index 82%
rename from ash/components/tether/test_timer_factory.h
rename to chromeos/ash/components/tether/test_timer_factory.h
index a5734ef..610798a 100644
--- a/ash/components/tether/test_timer_factory.h
+++ b/chromeos/ash/components/tether/test_timer_factory.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_TEST_TIMER_FACTORY_H_
-#define ASH_COMPONENTS_TETHER_TEST_TIMER_FACTORY_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TEST_TIMER_FACTORY_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TEST_TIMER_FACTORY_H_
 
 #include <memory>
 #include <string>
 
-#include "ash/components/tether/timer_factory.h"
 #include "base/containers/flat_map.h"
 #include "base/timer/mock_timer.h"
 #include "base/timer/timer.h"
+#include "chromeos/ash/components/tether/timer_factory.h"
 
 namespace ash {
 namespace tether {
@@ -45,4 +45,4 @@
 }  // namespace tether
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TEST_TIMER_FACTORY_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TEST_TIMER_FACTORY_H_
diff --git a/ash/components/tether/tether_component.cc b/chromeos/ash/components/tether/tether_component.cc
similarity index 92%
rename from ash/components/tether/tether_component.cc
rename to chromeos/ash/components/tether/tether_component.cc
index fd3a287a..9493393 100644
--- a/ash/components/tether/tether_component.cc
+++ b/chromeos/ash/components/tether/tether_component.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 "ash/components/tether/tether_component.h"
+#include "chromeos/ash/components/tether/tether_component.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/tether_component.h b/chromeos/ash/components/tether/tether_component.h
similarity index 90%
rename from ash/components/tether/tether_component.h
rename to chromeos/ash/components/tether/tether_component.h
index 5a76b80..0f0d031 100644
--- a/ash/components/tether/tether_component.h
+++ b/chromeos/ash/components/tether/tether_component.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 ASH_COMPONENTS_TETHER_TETHER_COMPONENT_H_
-#define ASH_COMPONENTS_TETHER_TETHER_COMPONENT_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_COMPONENT_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_COMPONENT_H_
 
 #include "base/observer_list.h"
 
@@ -66,4 +66,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_COMPONENT_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_COMPONENT_H_
diff --git a/ash/components/tether/tether_component_impl.cc b/chromeos/ash/components/tether/tether_component_impl.cc
similarity index 91%
rename from ash/components/tether/tether_component_impl.cc
rename to chromeos/ash/components/tether/tether_component_impl.cc
index e43253c6..82a8ab1 100644
--- a/ash/components/tether/tether_component_impl.cc
+++ b/chromeos/ash/components/tether/tether_component_impl.cc
@@ -2,26 +2,26 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_component_impl.h"
+#include "chromeos/ash/components/tether/tether_component_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/asynchronous_shutdown_object_container_impl.h"
-#include "ash/components/tether/crash_recovery_manager_impl.h"
-#include "ash/components/tether/host_scan_scheduler.h"
-#include "ash/components/tether/persistent_host_scan_cache_impl.h"
-#include "ash/components/tether/synchronous_shutdown_object_container_impl.h"
-#include "ash/components/tether/tether_disconnector.h"
-#include "ash/components/tether/tether_host_response_recorder.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
-#include "ash/components/tether/wifi_hotspot_disconnector_impl.h"
 #include "ash/services/device_sync/public/cpp/device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.h"
+#include "chromeos/ash/components/tether/crash_recovery_manager_impl.h"
+#include "chromeos/ash/components/tether/host_scan_scheduler.h"
+#include "chromeos/ash/components/tether/persistent_host_scan_cache_impl.h"
+#include "chromeos/ash/components/tether/synchronous_shutdown_object_container_impl.h"
+#include "chromeos/ash/components/tether/tether_disconnector.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 
 namespace ash {
diff --git a/ash/components/tether/tether_component_impl.h b/chromeos/ash/components/tether/tether_component_impl.h
similarity index 92%
rename from ash/components/tether/tether_component_impl.h
rename to chromeos/ash/components/tether/tether_component_impl.h
index 17ea18e..19ec3f84 100644
--- a/ash/components/tether/tether_component_impl.h
+++ b/chromeos/ash/components/tether/tether_component_impl.h
@@ -2,16 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_TETHER_COMPONENT_IMPL_H_
-#define ASH_COMPONENTS_TETHER_TETHER_COMPONENT_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_COMPONENT_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_COMPONENT_IMPL_H_
 
 #include <memory>
 
-#include "ash/components/tether/tether_component.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/tether/tether_component.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 
@@ -31,6 +29,10 @@
 class DeviceSyncClient;
 }
 
+namespace secure_channel {
+class SecureChannelClient;
+}
+
 class ManagedNetworkConfigurationHandler;
 class NetworkConnect;
 class NetworkConnectionHandler;
@@ -136,4 +138,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_COMPONENT_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_COMPONENT_IMPL_H_
diff --git a/ash/components/tether/tether_component_impl_unittest.cc b/chromeos/ash/components/tether/tether_component_impl_unittest.cc
similarity index 92%
rename from ash/components/tether/tether_component_impl_unittest.cc
rename to chromeos/ash/components/tether/tether_component_impl_unittest.cc
index cee3437d..000887e 100644
--- a/ash/components/tether/tether_component_impl_unittest.cc
+++ b/chromeos/ash/components/tether/tether_component_impl_unittest.cc
@@ -2,22 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_component_impl.h"
+#include "chromeos/ash/components/tether/tether_component_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/asynchronous_shutdown_object_container_impl.h"
-#include "ash/components/tether/crash_recovery_manager_impl.h"
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/fake_asynchronous_shutdown_object_container.h"
-#include "ash/components/tether/fake_crash_recovery_manager.h"
-#include "ash/components/tether/fake_host_scan_scheduler.h"
-#include "ash/components/tether/fake_synchronous_shutdown_object_container.h"
-#include "ash/components/tether/fake_tether_disconnector.h"
-#include "ash/components/tether/synchronous_shutdown_object_container_impl.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
+#include "chromeos/ash/components/tether/asynchronous_shutdown_object_container_impl.h"
+#include "chromeos/ash/components/tether/crash_recovery_manager_impl.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_asynchronous_shutdown_object_container.h"
+#include "chromeos/ash/components/tether/fake_crash_recovery_manager.h"
+#include "chromeos/ash/components/tether/fake_host_scan_scheduler.h"
+#include "chromeos/ash/components/tether/fake_synchronous_shutdown_object_container.h"
+#include "chromeos/ash/components/tether/fake_tether_disconnector.h"
+#include "chromeos/ash/components/tether/synchronous_shutdown_object_container_impl.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
diff --git a/ash/components/tether/tether_connector.h b/chromeos/ash/components/tether/tether_connector.h
similarity index 88%
rename from ash/components/tether/tether_connector.h
rename to chromeos/ash/components/tether/tether_connector.h
index 0a632aac..95664c8 100644
--- a/ash/components/tether/tether_connector.h
+++ b/chromeos/ash/components/tether/tether_connector.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 ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_H_
-#define ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_H_
 
 #include "base/callback_forward.h"
 #include "chromeos/ash/components/network/network_connection_handler.h"
@@ -42,4 +42,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_H_
diff --git a/ash/components/tether/tether_connector_impl.cc b/chromeos/ash/components/tether/tether_connector_impl.cc
similarity index 95%
rename from ash/components/tether/tether_connector_impl.cc
rename to chromeos/ash/components/tether/tether_connector_impl.cc
index 5b98c17a..236d9e9 100644
--- a/ash/components/tether/tether_connector_impl.cc
+++ b/chromeos/ash/components/tether/tether_connector_impl.cc
@@ -2,17 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_connector_impl.h"
+#include "chromeos/ash/components/tether/tether_connector_impl.h"
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/disconnect_tethering_request_sender.h"
-#include "ash/components/tether/host_connection_metrics_logger.h"
-#include "ash/components/tether/host_scan_cache.h"
-#include "ash/components/tether/notification_presenter.h"
-#include "ash/components/tether/tether_host_fetcher.h"
-#include "ash/components/tether/wifi_hotspot_connector.h"
-#include "ash/components/tether/wifi_hotspot_disconnector.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/metrics/histogram_macros.h"
@@ -20,6 +12,15 @@
 #include "chromeos/ash/components/network/network_handler.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/host_connection_metrics_logger.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
+#include "chromeos/ash/components/tether/notification_presenter.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_connector.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_disconnector.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/tether_connector_impl.h b/chromeos/ash/components/tether/tether_connector_impl.h
similarity index 90%
rename from ash/components/tether/tether_connector_impl.h
rename to chromeos/ash/components/tether/tether_connector_impl.h
index 1b270a6..0ab50865 100644
--- a/ash/components/tether/tether_connector_impl.h
+++ b/chromeos/ash/components/tether/tether_connector_impl.h
@@ -2,17 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_IMPL_H_
-#define ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_IMPL_H_
 
-#include "ash/components/tether/connect_tethering_operation.h"
-#include "ash/components/tether/host_connection_metrics_logger.h"
-#include "ash/components/tether/tether_connector.h"
-#include "base/time/time.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "chromeos/ash/components/network/network_connection_handler.h"
+#include "chromeos/ash/components/tether/connect_tethering_operation.h"
+#include "chromeos/ash/components/tether/host_connection_metrics_logger.h"
+#include "chromeos/ash/components/tether/tether_connector.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace ash {
@@ -21,6 +19,10 @@
 class DeviceSyncClient;
 }
 
+namespace secure_channel {
+class SecureChannelClient;
+}
+
 class NetworkStateHandler;
 
 namespace tether {
@@ -128,4 +130,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_CONNECTOR_IMPL_H_
diff --git a/ash/components/tether/tether_connector_impl_unittest.cc b/chromeos/ash/components/tether/tether_connector_impl_unittest.cc
similarity index 96%
rename from ash/components/tether/tether_connector_impl_unittest.cc
rename to chromeos/ash/components/tether/tether_connector_impl_unittest.cc
index 92f0868c..11f816b 100644
--- a/ash/components/tether/tether_connector_impl_unittest.cc
+++ b/chromeos/ash/components/tether/tether_connector_impl_unittest.cc
@@ -2,24 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_connector_impl.h"
+#include "chromeos/ash/components/tether/tether_connector_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/connect_tethering_operation.h"
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/fake_disconnect_tethering_request_sender.h"
-#include "ash/components/tether/fake_host_scan_cache.h"
-#include "ash/components/tether/fake_notification_presenter.h"
-#include "ash/components/tether/fake_tether_host_fetcher.h"
-#include "ash/components/tether/fake_wifi_hotspot_connector.h"
-#include "ash/components/tether/fake_wifi_hotspot_disconnector.h"
-#include "ash/components/tether/mock_host_connection_metrics_logger.h"
-#include "ash/components/tether/mock_tether_host_response_recorder.h"
-#include "ash/components/tether/tether_connector.h"
 #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
 #include "ash/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
+#include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -30,6 +19,18 @@
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
+#include "chromeos/ash/components/tether/connect_tethering_operation.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/fake_notification_presenter.h"
+#include "chromeos/ash/components/tether/fake_tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/fake_wifi_hotspot_connector.h"
+#include "chromeos/ash/components/tether/fake_wifi_hotspot_disconnector.h"
+#include "chromeos/ash/components/tether/mock_host_connection_metrics_logger.h"
+#include "chromeos/ash/components/tether/mock_tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/tether_connector.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
diff --git a/ash/components/tether/tether_disconnector.h b/chromeos/ash/components/tether/tether_disconnector.h
similarity index 79%
rename from ash/components/tether/tether_disconnector.h
rename to chromeos/ash/components/tether/tether_disconnector.h
index 9ecc597..add02e43 100644
--- a/ash/components/tether/tether_disconnector.h
+++ b/chromeos/ash/components/tether/tether_disconnector.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_H_
-#define ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_H_
 
 #include <string>
 
-#include "ash/components/tether/disconnect_tethering_operation.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/ash/components/network/network_connection_handler.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_operation.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 
 namespace ash {
 
@@ -46,4 +46,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_H_
diff --git a/ash/components/tether/tether_disconnector_impl.cc b/chromeos/ash/components/tether/tether_disconnector_impl.cc
similarity index 90%
rename from ash/components/tether/tether_disconnector_impl.cc
rename to chromeos/ash/components/tether/tether_disconnector_impl.cc
index 15b681e..b422c187 100644
--- a/ash/components/tether/tether_disconnector_impl.cc
+++ b/chromeos/ash/components/tether/tether_disconnector_impl.cc
@@ -2,20 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_disconnector_impl.h"
+#include "chromeos/ash/components/tether/tether_disconnector_impl.h"
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/disconnect_tethering_request_sender.h"
-#include "ash/components/tether/network_configuration_remover.h"
-#include "ash/components/tether/tether_connector.h"
-#include "ash/components/tether/wifi_hotspot_disconnector.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/values.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "chromeos/ash/components/network/network_connection_handler.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/network_configuration_remover.h"
+#include "chromeos/ash/components/tether/tether_connector.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_disconnector.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/tether_disconnector_impl.h b/chromeos/ash/components/tether/tether_disconnector_impl.h
similarity index 85%
rename from ash/components/tether/tether_disconnector_impl.h
rename to chromeos/ash/components/tether/tether_disconnector_impl.h
index 99d8cc33..fb04e4b 100644
--- a/ash/components/tether/tether_disconnector_impl.h
+++ b/chromeos/ash/components/tether/tether_disconnector_impl.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_IMPL_H_
-#define ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_IMPL_H_
 
 #include <memory>
 #include <string>
 
-#include "ash/components/tether/tether_disconnector.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/tether/tether_disconnector.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 
 namespace ash {
 
@@ -67,4 +67,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_DISCONNECTOR_IMPL_H_
diff --git a/ash/components/tether/tether_disconnector_impl_unittest.cc b/chromeos/ash/components/tether/tether_disconnector_impl_unittest.cc
similarity index 94%
rename from ash/components/tether/tether_disconnector_impl_unittest.cc
rename to chromeos/ash/components/tether/tether_disconnector_impl_unittest.cc
index 18bf776..2e45c927 100644
--- a/ash/components/tether/tether_disconnector_impl_unittest.cc
+++ b/chromeos/ash/components/tether/tether_disconnector_impl_unittest.cc
@@ -2,20 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_disconnector_impl.h"
+#include "chromeos/ash/components/tether/tether_disconnector_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/fake_disconnect_tethering_request_sender.h"
-#include "ash/components/tether/fake_tether_connector.h"
-#include "ash/components/tether/fake_tether_session_completion_logger.h"
-#include "ash/components/tether/fake_wifi_hotspot_disconnector.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
 #include "base/bind.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/fake_tether_connector.h"
+#include "chromeos/ash/components/tether/fake_tether_session_completion_logger.h"
+#include "chromeos/ash/components/tether/fake_wifi_hotspot_disconnector.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
diff --git a/ash/components/tether/tether_host_fetcher.cc b/chromeos/ash/components/tether/tether_host_fetcher.cc
similarity index 95%
rename from ash/components/tether/tether_host_fetcher.cc
rename to chromeos/ash/components/tether/tether_host_fetcher.cc
index 16f5a07..e49697df 100644
--- a/ash/components/tether/tether_host_fetcher.cc
+++ b/chromeos/ash/components/tether/tether_host_fetcher.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 "ash/components/tether/tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/tether_host_fetcher.h b/chromeos/ash/components/tether/tether_host_fetcher.h
similarity index 91%
rename from ash/components/tether/tether_host_fetcher.h
rename to chromeos/ash/components/tether/tether_host_fetcher.h
index d46d9a73..426b9b6cb 100644
--- a/ash/components/tether/tether_host_fetcher.h
+++ b/chromeos/ash/components/tether/tether_host_fetcher.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_H_
-#define ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_H_
 
 #include <memory>
 
@@ -71,4 +71,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_H_
diff --git a/ash/components/tether/tether_host_fetcher_impl.cc b/chromeos/ash/components/tether/tether_host_fetcher_impl.cc
similarity index 97%
rename from ash/components/tether/tether_host_fetcher_impl.cc
rename to chromeos/ash/components/tether/tether_host_fetcher_impl.cc
index 41af463..55e93b8b 100644
--- a/ash/components/tether/tether_host_fetcher_impl.cc
+++ b/chromeos/ash/components/tether/tether_host_fetcher_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_host_fetcher_impl.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher_impl.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/tether_host_fetcher_impl.h b/chromeos/ash/components/tether/tether_host_fetcher_impl.h
similarity index 92%
rename from ash/components/tether/tether_host_fetcher_impl.h
rename to chromeos/ash/components/tether/tether_host_fetcher_impl.h
index 538abad..59febb0 100644
--- a/ash/components/tether/tether_host_fetcher_impl.h
+++ b/chromeos/ash/components/tether/tether_host_fetcher_impl.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_IMPL_H_
-#define ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_IMPL_H_
 
 #include <memory>
 
-#include "ash/components/tether/tether_host_fetcher.h"
 #include "ash/services/device_sync/public/cpp/device_sync_client.h"
 #include "ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/ash/components/multidevice/remote_device_ref.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher.h"
 
 namespace ash {
 
@@ -91,4 +91,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_HOST_FETCHER_IMPL_H_
diff --git a/ash/components/tether/tether_host_fetcher_impl_unittest.cc b/chromeos/ash/components/tether/tether_host_fetcher_impl_unittest.cc
similarity index 99%
rename from ash/components/tether/tether_host_fetcher_impl_unittest.cc
rename to chromeos/ash/components/tether/tether_host_fetcher_impl_unittest.cc
index 268139f..99c9942 100644
--- a/ash/components/tether/tether_host_fetcher_impl_unittest.cc
+++ b/chromeos/ash/components/tether/tether_host_fetcher_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_host_fetcher_impl.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher_impl.h"
 
 #include <memory>
 #include <vector>
diff --git a/ash/components/tether/tether_host_response_recorder.cc b/chromeos/ash/components/tether/tether_host_response_recorder.cc
similarity index 96%
rename from ash/components/tether/tether_host_response_recorder.cc
rename to chromeos/ash/components/tether/tether_host_response_recorder.cc
index aaf4a67..e9d22d06 100644
--- a/ash/components/tether/tether_host_response_recorder.cc
+++ b/chromeos/ash/components/tether/tether_host_response_recorder.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 
 #include <memory>
 
-#include "ash/components/tether/pref_names.h"
 #include "base/values.h"
+#include "chromeos/ash/components/tether/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 
diff --git a/ash/components/tether/tether_host_response_recorder.h b/chromeos/ash/components/tether/tether_host_response_recorder.h
similarity index 93%
rename from ash/components/tether/tether_host_response_recorder.h
rename to chromeos/ash/components/tether/tether_host_response_recorder.h
index ba2d694..d68c972 100644
--- a/ash/components/tether/tether_host_response_recorder.h
+++ b/chromeos/ash/components/tether/tether_host_response_recorder.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 ASH_COMPONENTS_TETHER_TETHER_HOST_RESPONSE_RECORDER_H_
-#define ASH_COMPONENTS_TETHER_TETHER_HOST_RESPONSE_RECORDER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_HOST_RESPONSE_RECORDER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_HOST_RESPONSE_RECORDER_H_
 
 #include <string>
 #include <vector>
@@ -94,4 +94,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_HOST_RESPONSE_RECORDER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_HOST_RESPONSE_RECORDER_H_
diff --git a/ash/components/tether/tether_host_response_recorder_unittest.cc b/chromeos/ash/components/tether/tether_host_response_recorder_unittest.cc
similarity index 98%
rename from ash/components/tether/tether_host_response_recorder_unittest.cc
rename to chromeos/ash/components/tether/tether_host_response_recorder_unittest.cc
index c47a5ca..b0c0c58 100644
--- a/ash/components/tether/tether_host_response_recorder_unittest.cc
+++ b/chromeos/ash/components/tether/tether_host_response_recorder_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 "ash/components/tether/tether_host_response_recorder.h"
+#include "chromeos/ash/components/tether/tether_host_response_recorder.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/tether_network_disconnection_handler.cc b/chromeos/ash/components/tether/tether_network_disconnection_handler.cc
similarity index 89%
rename from ash/components/tether/tether_network_disconnection_handler.cc
rename to chromeos/ash/components/tether/tether_network_disconnection_handler.cc
index 5a920aa..c6a9a478 100644
--- a/ash/components/tether/tether_network_disconnection_handler.cc
+++ b/chromeos/ash/components/tether/tether_network_disconnection_handler.cc
@@ -2,13 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_network_disconnection_handler.h"
+#include "chromeos/ash/components/tether/tether_network_disconnection_handler.h"
 
-#include "ash/components/tether/disconnect_tethering_request_sender.h"
-#include "ash/components/tether/network_configuration_remover.h"
-#include "ash/components/tether/tether_disconnector.h"
-#include "ash/components/tether/tether_host_fetcher.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/memory/ptr_util.h"
@@ -18,6 +13,11 @@
 #include "chromeos/ash/components/network/network_handler.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/network_configuration_remover.h"
+#include "chromeos/ash/components/tether/tether_disconnector.h"
+#include "chromeos/ash/components/tether/tether_host_fetcher.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/tether_network_disconnection_handler.h b/chromeos/ash/components/tether/tether_network_disconnection_handler.h
similarity index 88%
rename from ash/components/tether/tether_network_disconnection_handler.h
rename to chromeos/ash/components/tether/tether_network_disconnection_handler.h
index fcceca46..15bc815 100644
--- a/ash/components/tether/tether_network_disconnection_handler.h
+++ b/chromeos/ash/components/tether/tether_network_disconnection_handler.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_TETHER_NETWORK_DISCONNECTION_HANDLER_H_
-#define ASH_COMPONENTS_TETHER_TETHER_NETWORK_DISCONNECTION_HANDLER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_NETWORK_DISCONNECTION_HANDLER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_NETWORK_DISCONNECTION_HANDLER_H_
 
-#include "ash/components/tether/active_host.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/ash/components/network/network_state_handler_observer.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
 namespace base {
 class TaskRunner;
@@ -72,4 +72,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_NETWORK_DISCONNECTION_HANDLER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_NETWORK_DISCONNECTION_HANDLER_H_
diff --git a/ash/components/tether/tether_network_disconnection_handler_unittest.cc b/chromeos/ash/components/tether/tether_network_disconnection_handler_unittest.cc
similarity index 92%
rename from ash/components/tether/tether_network_disconnection_handler_unittest.cc
rename to chromeos/ash/components/tether/tether_network_disconnection_handler_unittest.cc
index e02acea22..1e00b1ee 100644
--- a/ash/components/tether/tether_network_disconnection_handler_unittest.cc
+++ b/chromeos/ash/components/tether/tether_network_disconnection_handler_unittest.cc
@@ -2,16 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/tether_network_disconnection_handler.h"
+#include "chromeos/ash/components/tether/tether_network_disconnection_handler.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/fake_disconnect_tethering_request_sender.h"
-#include "ash/components/tether/fake_network_configuration_remover.h"
-#include "ash/components/tether/fake_tether_session_completion_logger.h"
-#include "ash/components/tether/network_configuration_remover.h"
-#include "ash/components/tether/tether_session_completion_logger.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
@@ -19,6 +13,12 @@
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_disconnect_tethering_request_sender.h"
+#include "chromeos/ash/components/tether/fake_network_configuration_remover.h"
+#include "chromeos/ash/components/tether/fake_tether_session_completion_logger.h"
+#include "chromeos/ash/components/tether/network_configuration_remover.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
 
diff --git a/ash/components/tether/tether_session_completion_logger.cc b/chromeos/ash/components/tether/tether_session_completion_logger.cc
similarity index 89%
rename from ash/components/tether/tether_session_completion_logger.cc
rename to chromeos/ash/components/tether/tether_session_completion_logger.cc
index 30355946..28ad35af 100644
--- a/ash/components/tether/tether_session_completion_logger.cc
+++ b/chromeos/ash/components/tether/tether_session_completion_logger.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 "ash/components/tether/tether_session_completion_logger.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 
 #include "base/metrics/histogram_macros.h"
 
diff --git a/ash/components/tether/tether_session_completion_logger.h b/chromeos/ash/components/tether/tether_session_completion_logger.h
similarity index 83%
rename from ash/components/tether/tether_session_completion_logger.h
rename to chromeos/ash/components/tether/tether_session_completion_logger.h
index cecc15e..10420d5 100644
--- a/ash/components/tether/tether_session_completion_logger.h
+++ b/chromeos/ash/components/tether/tether_session_completion_logger.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 ASH_COMPONENTS_TETHER_TETHER_SESSION_COMPLETION_LOGGER_H_
-#define ASH_COMPONENTS_TETHER_TETHER_SESSION_COMPLETION_LOGGER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_SESSION_COMPLETION_LOGGER_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_SESSION_COMPLETION_LOGGER_H_
 
 namespace ash {
 
@@ -47,4 +47,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TETHER_SESSION_COMPLETION_LOGGER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TETHER_SESSION_COMPLETION_LOGGER_H_
diff --git a/ash/components/tether/tether_session_completion_logger_unittest.cc b/chromeos/ash/components/tether/tether_session_completion_logger_unittest.cc
similarity index 97%
rename from ash/components/tether/tether_session_completion_logger_unittest.cc
rename to chromeos/ash/components/tether/tether_session_completion_logger_unittest.cc
index 6a96eeb..67ac91a5 100644
--- a/ash/components/tether/tether_session_completion_logger_unittest.cc
+++ b/chromeos/ash/components/tether/tether_session_completion_logger_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 "ash/components/tether/tether_session_completion_logger.h"
+#include "chromeos/ash/components/tether/tether_session_completion_logger.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/timer_factory.cc b/chromeos/ash/components/tether/timer_factory.cc
similarity index 87%
rename from ash/components/tether/timer_factory.cc
rename to chromeos/ash/components/tether/timer_factory.cc
index c18e31b..dad4e57 100644
--- a/ash/components/tether/timer_factory.cc
+++ b/chromeos/ash/components/tether/timer_factory.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 "ash/components/tether/timer_factory.h"
+#include "chromeos/ash/components/tether/timer_factory.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/timer_factory.h b/chromeos/ash/components/tether/timer_factory.h
similarity index 78%
rename from ash/components/tether/timer_factory.h
rename to chromeos/ash/components/tether/timer_factory.h
index bb5da2a..a6e4ac8e 100644
--- a/ash/components/tether/timer_factory.h
+++ b/chromeos/ash/components/tether/timer_factory.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 ASH_COMPONENTS_TETHER_TIMER_FACTORY_H_
-#define ASH_COMPONENTS_TETHER_TIMER_FACTORY_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TIMER_FACTORY_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TIMER_FACTORY_H_
 
 #include <memory>
 
@@ -28,4 +28,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TIMER_FACTORY_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TIMER_FACTORY_H_
diff --git a/ash/components/tether/top_level_host_scan_cache.cc b/chromeos/ash/components/tether/top_level_host_scan_cache.cc
similarity index 96%
rename from ash/components/tether/top_level_host_scan_cache.cc
rename to chromeos/ash/components/tether/top_level_host_scan_cache.cc
index f291935..3b19d8b 100644
--- a/ash/components/tether/top_level_host_scan_cache.cc
+++ b/chromeos/ash/components/tether/top_level_host_scan_cache.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/top_level_host_scan_cache.h"
+#include "chromeos/ash/components/tether/top_level_host_scan_cache.h"
 
 #include <algorithm>
 
-#include "ash/components/tether/active_host.h"
-#include "ash/components/tether/persistent_host_scan_cache.h"
-#include "ash/components/tether/timer_factory.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
+#include "chromeos/ash/components/tether/active_host.h"
+#include "chromeos/ash/components/tether/persistent_host_scan_cache.h"
+#include "chromeos/ash/components/tether/timer_factory.h"
 
 namespace ash {
 
diff --git a/ash/components/tether/top_level_host_scan_cache.h b/chromeos/ash/components/tether/top_level_host_scan_cache.h
similarity index 92%
rename from ash/components/tether/top_level_host_scan_cache.h
rename to chromeos/ash/components/tether/top_level_host_scan_cache.h
index b9043d2..06f06983 100644
--- a/ash/components/tether/top_level_host_scan_cache.h
+++ b/chromeos/ash/components/tether/top_level_host_scan_cache.h
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_TOP_LEVEL_HOST_SCAN_CACHE_H_
-#define ASH_COMPONENTS_TETHER_TOP_LEVEL_HOST_SCAN_CACHE_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_TOP_LEVEL_HOST_SCAN_CACHE_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_TOP_LEVEL_HOST_SCAN_CACHE_H_
 
 #include <memory>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
 
-#include "ash/components/tether/host_scan_cache.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
+#include "chromeos/ash/components/tether/host_scan_cache.h"
 
 namespace ash {
 
@@ -88,4 +88,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_TOP_LEVEL_HOST_SCAN_CACHE_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_TOP_LEVEL_HOST_SCAN_CACHE_H_
diff --git a/ash/components/tether/top_level_host_scan_cache_unittest.cc b/chromeos/ash/components/tether/top_level_host_scan_cache_unittest.cc
similarity index 96%
rename from ash/components/tether/top_level_host_scan_cache_unittest.cc
rename to chromeos/ash/components/tether/top_level_host_scan_cache_unittest.cc
index fce9c1d..16404e7 100644
--- a/ash/components/tether/top_level_host_scan_cache_unittest.cc
+++ b/chromeos/ash/components/tether/top_level_host_scan_cache_unittest.cc
@@ -2,22 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/top_level_host_scan_cache.h"
+#include "chromeos/ash/components/tether/top_level_host_scan_cache.h"
 
 #include <memory>
 #include <unordered_map>
 #include <vector>
 
-#include "ash/components/tether/device_id_tether_network_guid_map.h"
-#include "ash/components/tether/fake_active_host.h"
-#include "ash/components/tether/fake_host_scan_cache.h"
-#include "ash/components/tether/host_scan_test_util.h"
-#include "ash/components/tether/persistent_host_scan_cache.h"
-#include "ash/components/tether/timer_factory.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/timer/mock_timer.h"
+#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/ash/components/tether/fake_active_host.h"
+#include "chromeos/ash/components/tether/fake_host_scan_cache.h"
+#include "chromeos/ash/components/tether/host_scan_test_util.h"
+#include "chromeos/ash/components/tether/persistent_host_scan_cache.h"
+#include "chromeos/ash/components/tether/timer_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/components/tether/wifi_hotspot_connector.cc b/chromeos/ash/components/tether/wifi_hotspot_connector.cc
similarity index 99%
rename from ash/components/tether/wifi_hotspot_connector.cc
rename to chromeos/ash/components/tether/wifi_hotspot_connector.cc
index 8620310..0ddb319 100644
--- a/ash/components/tether/wifi_hotspot_connector.cc
+++ b/chromeos/ash/components/tether/wifi_hotspot_connector.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 "ash/components/tether/wifi_hotspot_connector.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_connector.h"
 
 #include <memory>
 
diff --git a/ash/components/tether/wifi_hotspot_connector.h b/chromeos/ash/components/tether/wifi_hotspot_connector.h
similarity index 92%
rename from ash/components/tether/wifi_hotspot_connector.h
rename to chromeos/ash/components/tether/wifi_hotspot_connector.h
index 3614b32..8f8d4df 100644
--- a/ash/components/tether/wifi_hotspot_connector.h
+++ b/chromeos/ash/components/tether/wifi_hotspot_connector.h
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_CONNECTOR_H_
-#define ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_CONNECTOR_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_CONNECTOR_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_CONNECTOR_H_
 
-#include "ash/components/tether/active_host.h"
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -14,6 +13,7 @@
 #include "base/timer/timer.h"
 #include "base/values.h"
 #include "chromeos/ash/components/network/network_state_handler_observer.h"
+#include "chromeos/ash/components/tether/active_host.h"
 
 namespace base {
 class TaskRunner;
@@ -99,4 +99,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_CONNECTOR_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_CONNECTOR_H_
diff --git a/ash/components/tether/wifi_hotspot_connector_unittest.cc b/chromeos/ash/components/tether/wifi_hotspot_connector_unittest.cc
similarity index 99%
rename from ash/components/tether/wifi_hotspot_connector_unittest.cc
rename to chromeos/ash/components/tether/wifi_hotspot_connector_unittest.cc
index f5ab55a..19c2d97 100644
--- a/ash/components/tether/wifi_hotspot_connector_unittest.cc
+++ b/chromeos/ash/components/tether/wifi_hotspot_connector_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 "ash/components/tether/wifi_hotspot_connector.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_connector.h"
 
 #include <memory>
 #include <sstream>
@@ -294,9 +294,7 @@
         CreateConfigurationJsonString(std::string(kOtherWifiServiceGuid)));
   }
 
-  void TearDown() override {
-    wifi_hotspot_connector_.reset();
-  }
+  void TearDown() override { wifi_hotspot_connector_.reset(); }
 
   void VerifyTimerSet() {
     EXPECT_TRUE(mock_timer_->IsRunning());
diff --git a/ash/components/tether/wifi_hotspot_disconnector.h b/chromeos/ash/components/tether/wifi_hotspot_disconnector.h
similarity index 84%
rename from ash/components/tether/wifi_hotspot_disconnector.h
rename to chromeos/ash/components/tether/wifi_hotspot_disconnector.h
index 11e1de7..830537c 100644
--- a/ash/components/tether/wifi_hotspot_disconnector.h
+++ b/chromeos/ash/components/tether/wifi_hotspot_disconnector.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 ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_H_
-#define ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_H_
 
 #include "base/callback.h"
 #include "chromeos/ash/components/network/network_connection_handler.h"
@@ -38,4 +38,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_H_
diff --git a/ash/components/tether/wifi_hotspot_disconnector_impl.cc b/chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.cc
similarity index 96%
rename from ash/components/tether/wifi_hotspot_disconnector_impl.cc
rename to chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.cc
index d697000..aff0256f 100644
--- a/ash/components/tether/wifi_hotspot_disconnector_impl.cc
+++ b/chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.cc
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/wifi_hotspot_disconnector_impl.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.h"
 
-#include "ash/components/tether/network_configuration_remover.h"
-#include "ash/components/tether/pref_names.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
@@ -13,6 +11,8 @@
 #include "chromeos/ash/components/network/network_connection_handler.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/tether/network_configuration_remover.h"
+#include "chromeos/ash/components/tether/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
diff --git a/ash/components/tether/wifi_hotspot_disconnector_impl.h b/chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.h
similarity index 89%
rename from ash/components/tether/wifi_hotspot_disconnector_impl.h
rename to chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.h
index f72beb7..c4572956 100644
--- a/ash/components/tether/wifi_hotspot_disconnector_impl.h
+++ b/chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_IMPL_H_
-#define ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_IMPL_H_
 
-#include "ash/components/tether/wifi_hotspot_disconnector.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_disconnector.h"
 
 class PrefRegistrySimple;
 class PrefService;
@@ -68,4 +68,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_TETHER_WIFI_HOTSPOT_DISCONNECTOR_IMPL_H_
diff --git a/ash/components/tether/wifi_hotspot_disconnector_impl_unittest.cc b/chromeos/ash/components/tether/wifi_hotspot_disconnector_impl_unittest.cc
similarity index 96%
rename from ash/components/tether/wifi_hotspot_disconnector_impl_unittest.cc
rename to chromeos/ash/components/tether/wifi_hotspot_disconnector_impl_unittest.cc
index c61a7c24..c4952ff 100644
--- a/ash/components/tether/wifi_hotspot_disconnector_impl_unittest.cc
+++ b/chromeos/ash/components/tether/wifi_hotspot_disconnector_impl_unittest.cc
@@ -2,12 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/tether/wifi_hotspot_disconnector_impl.h"
+#include "chromeos/ash/components/tether/wifi_hotspot_disconnector_impl.h"
 
 #include <memory>
 
-#include "ash/components/tether/fake_network_configuration_remover.h"
-#include "ash/components/tether/pref_names.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/task_environment.h"
@@ -15,6 +13,8 @@
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_test_helper.h"
+#include "chromeos/ash/components/tether/fake_network_configuration_remover.h"
+#include "chromeos/ash/components/tether/pref_names.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -121,9 +121,7 @@
         test_pref_service_.get(), fake_configuration_remover_.get());
   }
 
-  void TearDown() override {
-    wifi_hotspot_disconnector_.reset();
-  }
+  void TearDown() override { wifi_hotspot_disconnector_.reset(); }
 
   void SimulateConnectionToWifiNetwork() {
     wifi_service_path_ = helper_.ConfigureService(
diff --git a/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.cc b/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.cc
index 109db85e..bf8608d 100644
--- a/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.cc
+++ b/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.cc
@@ -15,6 +15,8 @@
 namespace quick_pair {
 
 constexpr int kBitsInByte = 8;
+constexpr uint8_t kRecentlyUsedByte = 0x05;
+constexpr uint8_t kInUseByte = 0x06;
 
 AccountKeyFilter::AccountKeyFilter(
     const NotDiscoverableAdvertisement& advertisement)
@@ -51,17 +53,7 @@
 AccountKeyFilter& AccountKeyFilter::operator=(AccountKeyFilter&&) = default;
 AccountKeyFilter::~AccountKeyFilter() = default;
 
-bool AccountKeyFilter::Test(
-    const std::vector<uint8_t>& account_key_bytes) const {
-  if (bit_sets_.empty())
-    return false;
-
-  // We first need to append the salt value to the input (see
-  // https://developers.google.com/nearby/fast-pair/spec#AccountKeyFilter).
-  std::vector<uint8_t> data(account_key_bytes);
-  for (auto& byte : salt_values_)
-    data.push_back(byte);
-
+bool AccountKeyFilter::IsAccountKeyInFilter(std::vector<uint8_t> data) const {
   std::array<uint8_t, 32> hashed = crypto::SHA256Hash(data);
 
   // Iterate over the hashed input in 4 byte increments, combine those 4
@@ -84,5 +76,30 @@
   return true;
 }
 
+bool AccountKeyFilter::Test(
+    const std::vector<uint8_t>& account_key_bytes) const {
+  if (bit_sets_.empty())
+    return false;
+
+  // We first need to append the salt value to the input (see
+  // https://developers.google.com/nearby/fast-pair/spec#AccountKeyFilter).
+  std::vector<uint8_t> default_account_key(account_key_bytes);
+  for (auto& byte : salt_values_)
+    default_account_key.push_back(byte);
+
+  // We need to try account keys with different first bytes in case
+  // the peripheral is SASS per
+  // https://developers.google.com/nearby/fast-pair/early-access/specifications/extensions/sass#SassAdvertisingPayload
+  std::vector<uint8_t> recently_used_account_key(default_account_key);
+  recently_used_account_key[0] = kRecentlyUsedByte;
+
+  std::vector<uint8_t> in_use_account_key(default_account_key);
+  in_use_account_key[0] = kInUseByte;
+
+  return IsAccountKeyInFilter(default_account_key) ||
+         IsAccountKeyInFilter(in_use_account_key) ||
+         IsAccountKeyInFilter(recently_used_account_key);
+}
+
 }  // namespace quick_pair
 }  // namespace ash
diff --git a/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.h b/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.h
index 036ba06..470704aa 100644
--- a/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.h
+++ b/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.h
@@ -24,6 +24,10 @@
   AccountKeyFilter& operator=(AccountKeyFilter&&);
   ~AccountKeyFilter();
 
+  // Helper to Test, specifically tests whether hashed |data|
+  // is in the account key filter.
+  bool IsAccountKeyInFilter(std::vector<uint8_t> data) const;
+
   // Tests whether the |account_key_bytes| belong to this Account Key Filter.
   // Note: The return value may be a false positive, but will never be a false
   // negative.
diff --git a/chromeos/ash/services/quick_pair/public/cpp/account_key_filter_unittest.cc b/chromeos/ash/services/quick_pair/public/cpp/account_key_filter_unittest.cc
index ca01f5c..5785a0c6 100644
--- a/chromeos/ash/services/quick_pair/public/cpp/account_key_filter_unittest.cc
+++ b/chromeos/ash/services/quick_pair/public/cpp/account_key_filter_unittest.cc
@@ -34,6 +34,14 @@
 const std::vector<uint8_t> kSalt3{0x6C, 0xE5};
 const std::vector<uint8_t> kBatteryData3{0x33, 0xE4, 0xE4, 0x4C};
 
+const std::vector<uint8_t> kAccountKey4{0x04, 0x3F, 0xC1, 0x8C, 0x63, 0xDC,
+                                        0x75, 0x1A, 0xE8, 0x1A, 0xCF, 0x65,
+                                        0x10, 0x15, 0x1D, 0xB0};
+const std::vector<uint8_t> kFilter4{0x19, 0x23, 0x50, 0xE8, 0x37,
+                                    0x68, 0xF0, 0x65, 0x22};
+const std::vector<uint8_t> kSalt4{0xD7, 0xDE};
+const std::vector<uint8_t> kBatteryData4{0x33, 0xE4, 0xE4, 0x64};
+
 class AccountKeyFilterTest : public testing::Test {};
 
 TEST_F(AccountKeyFilterTest, EmptyFilter) {
@@ -87,5 +95,15 @@
   EXPECT_TRUE(AccountKeyFilter(kFilter3, salt_values).Test(kAccountKey3));
 }
 
+TEST_F(AccountKeyFilterTest, SassEnabledPeripheral) {
+  // Devices with battery data create account filters by concatenating data to
+  // end of salt bytes
+  std::vector<uint8_t> salt_values{};
+  salt_values.insert(salt_values.end(), kSalt4.begin(), kSalt4.end());
+  salt_values.insert(salt_values.end(), kBatteryData4.begin(),
+                     kBatteryData4.end());
+  EXPECT_TRUE(AccountKeyFilter(kFilter4, salt_values).Test(kAccountKey4));
+}
+
 }  // namespace quick_pair
 }  // namespace ash
diff --git a/chromeos/components/remote_apps/mojom/remote_apps.mojom b/chromeos/components/remote_apps/mojom/remote_apps.mojom
index 015265c..a4266e9b1 100644
--- a/chromeos/components/remote_apps/mojom/remote_apps.mojom
+++ b/chromeos/components/remote_apps/mojom/remote_apps.mojom
@@ -26,6 +26,9 @@
 
 // Interface for communication between an extension and the Remote Apps
 // Manager or |RemoteAppsProxyLacros|.
+//
+// Next MinVersion: 2
+// Next Method ID: 4
 [Stable]
 interface RemoteApps {
   // Adds a Remote Apps folder to the launcher. Empty folders are not shown in
@@ -73,6 +76,14 @@
   // Output parameters:
   // - |error|: A string describing the error if any.
   DeleteApp@2(string app_id) => (string? error);
+
+  // Sorts the Remote apps and folders at the front of the launcher, in
+  // alphabetical, case insensitive, order.
+  //
+  // Output parameters:
+  // - |error|: A string describing the error if any.
+  [MinVersion=1]
+  SortLauncherWithRemoteAppsFirst@3() => (string? error);
 };
 
 // Factory for creating an instance of |RemoteApps|.
diff --git a/chromeos/metrics/login_event_recorder.cc b/chromeos/metrics/login_event_recorder.cc
index b6cf00b..388f6c339 100644
--- a/chromeos/metrics/login_event_recorder.cc
+++ b/chromeos/metrics/login_event_recorder.cc
@@ -106,6 +106,10 @@
   total_hist->AddTime(total);
   std::string output =
       base::StringPrintf("%s: %.2f", uma_name.c_str(), total.InSecondsF());
+  if (uma_name == "BootTime.Login2" || uma_name == "BootTime.LoginNewUser") {
+    UMA_HISTOGRAM_CUSTOM_TIMES("Ash.Tast.BootTime.Login2", total,
+                               base::Milliseconds(1), base::Seconds(300), 100);
+  }
   base::Time prev = first;
   // Convert base::Time to base::TimeTicks for tracing.
   auto time2timeticks = [](const base::Time& ts) {
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt
index b346d5e..a63d59b7 100644
--- a/chromeos/profiles/orderfile.newest.txt
+++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@
-chromeos-chrome-orderfile-field-108-5323.0-1664790676-benchmark-108.0.5338.0-r1.orderfile.xz
+chromeos-chrome-orderfile-field-108-5323.0-1664790676-benchmark-108.0.5344.0-r1.orderfile.xz
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index fc71fe8..edd4e1f6 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -30,9 +30,6 @@
   # b/251833060
   "peripherals.LaunchAppFromGuestSession.diagnostics",
 
-  # b/251877133
-  "policy.*",
-
   # b/251877700
   "policy.DefaultSearchProviderEnabled",
 
diff --git a/chromeos/ui/frame/desks/move_to_desks_menu_delegate.cc b/chromeos/ui/frame/desks/move_to_desks_menu_delegate.cc
index 132d461..0f017d6 100644
--- a/chromeos/ui/frame/desks/move_to_desks_menu_delegate.cc
+++ b/chromeos/ui/frame/desks/move_to_desks_menu_delegate.cc
@@ -16,7 +16,7 @@
 
 int MapCommandIdToDeskIndex(int command_id) {
   DCHECK_GE(command_id, chromeos::MoveToDesksMenuModel::MOVE_TO_DESK_1);
-  DCHECK_LE(command_id, chromeos::MoveToDesksMenuModel::MOVE_TO_DESK_8);
+  DCHECK_LE(command_id, chromeos::MoveToDesksMenuModel::MOVE_TO_DESK_16);
   return command_id - chromeos::MoveToDesksMenuModel::MOVE_TO_DESK_1;
 }
 
@@ -27,7 +27,7 @@
 
 bool IsMoveToDeskCommand(int command_id) {
   return command_id >= chromeos::MoveToDesksMenuModel::MOVE_TO_DESK_1 &&
-         command_id <= chromeos::MoveToDesksMenuModel::MOVE_TO_DESK_8;
+         command_id <= chromeos::MoveToDesksMenuModel::MOVE_TO_DESK_16;
 }
 
 }  // namespace
@@ -69,7 +69,7 @@
 
 bool MoveToDesksMenuDelegate::IsItemForCommandIdDynamic(int command_id) const {
   // The potential command_id is from MoveToDesksMenuModel::MOVE_TO_DESK_1
-  // to MoveToDesksMenuModel::MOVE_TO_DESK_8,
+  // to MoveToDesksMenuModel::MOVE_TO_DESK_16,
   // MoveToDesksMenuModel::TOGGLE_ASSIGN_TO_ALL_DESKS.
   // For Move window to desk menu, all the menu items are dynamic.
   // Therefore, checking whether command_id is within the range from
diff --git a/chromeos/ui/frame/desks/move_to_desks_menu_model.cc b/chromeos/ui/frame/desks/move_to_desks_menu_model.cc
index d61bbd1..a7d4e4179 100644
--- a/chromeos/ui/frame/desks/move_to_desks_menu_model.cc
+++ b/chromeos/ui/frame/desks/move_to_desks_menu_model.cc
@@ -19,7 +19,15 @@
                     MOVE_TO_DESK_4 == MOVE_TO_DESK_5 - 1 &&
                     MOVE_TO_DESK_5 == MOVE_TO_DESK_6 - 1 &&
                     MOVE_TO_DESK_6 == MOVE_TO_DESK_7 - 1 &&
-                    MOVE_TO_DESK_7 == MOVE_TO_DESK_8 - 1,
+                    MOVE_TO_DESK_7 == MOVE_TO_DESK_8 - 1 &&
+                    MOVE_TO_DESK_8 == MOVE_TO_DESK_9 - 1 &&
+                    MOVE_TO_DESK_9 == MOVE_TO_DESK_10 - 1 &&
+                    MOVE_TO_DESK_10 == MOVE_TO_DESK_11 - 1 &&
+                    MOVE_TO_DESK_11 == MOVE_TO_DESK_12 - 1 &&
+                    MOVE_TO_DESK_12 == MOVE_TO_DESK_13 - 1 &&
+                    MOVE_TO_DESK_13 == MOVE_TO_DESK_14 - 1 &&
+                    MOVE_TO_DESK_14 == MOVE_TO_DESK_15 - 1 &&
+                    MOVE_TO_DESK_15 == MOVE_TO_DESK_16 - 1,
                 "MOVE_TO_DESK_* commands must be in order.");
 
   if (add_title)
@@ -30,7 +38,7 @@
   assign_to_all_desks_item_index_ = GetItemCount() - 1;
   AddSeparator(ui::NORMAL_SEPARATOR);
 
-  constexpr int kMaxNumberOfDesks = MOVE_TO_DESK_8 - MOVE_TO_DESK_1 + 1;
+  constexpr int kMaxNumberOfDesks = MOVE_TO_DESK_16 - MOVE_TO_DESK_1 + 1;
   for (int i = 0; i < kMaxNumberOfDesks; ++i)
     AddCheckItem(MOVE_TO_DESK_1 + i, std::u16string());
 }
diff --git a/chromeos/ui/frame/desks/move_to_desks_menu_model.h b/chromeos/ui/frame/desks/move_to_desks_menu_model.h
index 9dccd3c8..d2356f9 100644
--- a/chromeos/ui/frame/desks/move_to_desks_menu_model.h
+++ b/chromeos/ui/frame/desks/move_to_desks_menu_model.h
@@ -38,7 +38,15 @@
     MOVE_TO_DESK_6 = 40806,
     MOVE_TO_DESK_7 = 40807,
     MOVE_TO_DESK_8 = 40808,
-    TOGGLE_ASSIGN_TO_ALL_DESKS = 40809,
+    MOVE_TO_DESK_9 = 40809,
+    MOVE_TO_DESK_10 = 40810,
+    MOVE_TO_DESK_11 = 40811,
+    MOVE_TO_DESK_12 = 40812,
+    MOVE_TO_DESK_13 = 40813,
+    MOVE_TO_DESK_14 = 40814,
+    MOVE_TO_DESK_15 = 40815,
+    MOVE_TO_DESK_16 = 40816,
+    TOGGLE_ASSIGN_TO_ALL_DESKS = 40817,
   };
 
   // SimpleMenuModel:
diff --git a/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc b/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
index 7bd1e82..e8df325 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
@@ -364,7 +364,7 @@
       public ::testing::WithParamInterface<bool> {
  public:
   ContentAutofillDriverFactoryTest_FencedFrames() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled;
+    std::vector<base::test::FeatureRefAndParams> enabled;
     std::vector<base::test::FeatureRef> disabled;
     enabled.push_back(
         {blink::features::kFencedFrames, {{"implementation_type", "mparch"}}});
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 3181e98..9a4e769f 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -263,8 +263,6 @@
     "metrics/form_events/form_event_logger_base.cc",
     "metrics/form_events/form_event_logger_base.h",
     "metrics/form_events/form_events.h",
-    "metrics/form_interactions_counter.cc",
-    "metrics/form_interactions_counter.h",
     "metrics/payments/credit_card_save_metrics.cc",
     "metrics/payments/credit_card_save_metrics.h",
     "metrics/payments/local_card_migration_metrics.cc",
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index d8ba58e..306c74c4 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -22,6 +22,7 @@
 #include "components/autofill/core/browser/ui/popup_item_ids.h"
 #include "components/autofill/core/browser/ui/popup_types.h"
 #include "components/autofill/core/browser/ui/touch_to_fill_delegate.h"
+#include "components/autofill/core/common/form_interactions_flow.h"
 #include "components/profile_metrics/browser_profile_type.h"
 #include "components/security_state/core/security_state.h"
 #include "components/translate/core/browser/language_state.h"
@@ -762,6 +763,14 @@
   // details page for the offers in a promo code suggestions popup. Every offer
   // in a promo code suggestions popup links to the same offer details page.
   virtual void OpenPromoCodeOfferDetailsURL(const GURL& url) = 0;
+
+  // Updates and returns the current form interactions flow id. This is used as
+  // an approximation for keeping track of the number of user interactions with
+  // related forms for logging. Example implementation: the flow id is set to a
+  // GUID on the first call. That same GUID will be returned for consecutive
+  // calls in the next 20 minutes. Afterwards a new GUID is set and the pattern
+  // repeated.
+  virtual FormInteractionsFlowId GetCurrentFormInteractionsFlowId() = 0;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 3d0a5e6..96f24ae 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -673,8 +673,7 @@
       // determining the heuristics.
       form_structure->RetrieveFromCache(
           *cached_form_structure,
-          /*should_keep_cached_value=*/true,
-          /*only_server_and_autofill_state=*/true);
+          FormStructure::RetrieveFromCacheReason::kFormParsing);
       if (form_structure->value_from_dynamic_change_form())
         value_from_dynamic_change_form_ = true;
 
@@ -781,9 +780,9 @@
 
     // We need to keep the server data if available. We need to use them while
     // determining the heuristics.
-    form_structure->RetrieveFromCache(*cached_form_structure,
-                                      /*should_keep_cached_value=*/true,
-                                      /*only_server_and_autofill_state=*/true);
+    form_structure->RetrieveFromCache(
+        *cached_form_structure,
+        FormStructure::RetrieveFromCacheReason::kFormParsing);
     if (form_structure->value_from_dynamic_change_form())
       value_from_dynamic_change_form_ = true;
   }
@@ -859,9 +858,8 @@
   if (cached_form) {
     // We need to keep the server data if available. We need to use them while
     // determining the heuristics.
-    form_structure->RetrieveFromCache(*cached_form,
-                                      /*should_keep_cached_value=*/true,
-                                      /*only_server_and_autofill_state=*/true);
+    form_structure->RetrieveFromCache(
+        *cached_form, FormStructure::RetrieveFromCacheReason::kFormParsing);
 
     NotifyObservers(&Observer::OnFormParsed);
     if (form_structure.get()->value_from_dynamic_change_form())
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index 34bd843..6949035 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -489,8 +489,6 @@
 
   CountryNames::SetLocaleString(app_locale_);
   offer_manager_ = client->GetAutofillOfferManager();
-
-  form_interactions_counter_ = std::make_unique<FormInteractionsCounter>();
 }
 
 BrowserAutofillManager::~BrowserAutofillManager() {
@@ -969,8 +967,8 @@
     profile_form_bitmask = data_util::DetermineGroups(*form_structure);
   }
 
+  auto* logger = GetEventFormLogger(autofill_field->Type().group());
   if (!autofill_field->is_autofilled) {
-    auto* logger = GetEventFormLogger(autofill_field->Type().group());
     if (logger)
       logger->OnTypedIntoNonFilledField();
   }
@@ -990,7 +988,6 @@
         autofill_field->Type().group(),
         client()->GetSecurityLevelForUmaHistograms(), profile_form_bitmask);
 
-    auto* logger = GetEventFormLogger(autofill_field->Type().group());
     if (logger)
       logger->OnEditedAutofilledField();
 
@@ -1005,8 +1002,8 @@
 
   UpdateInitialInteractionTimestamp(timestamp);
 
-  form_interactions_counter_->OnTextFieldDidChange(
-      autofill_field->GetFieldSignature());
+  if (logger)
+    logger->OnTextFieldDidChange(autofill_field->global_id());
 }
 
 bool BrowserAutofillManager::IsFormNonSecure(const FormData& form) const {
@@ -1544,7 +1541,6 @@
     int frontend_id) {
   single_field_form_fill_router_->OnSingleFieldSuggestionSelected(value,
                                                                   frontend_id);
-  form_interactions_counter_->OnAutocompleteFill();
 }
 
 void BrowserAutofillManager::OnUserHideSuggestions(const FormData& form,
@@ -1825,17 +1821,20 @@
       submitted_form->ShouldBeQueried()) {
     autofill_assistant::AutofillAssistantIntent intent =
         autofill_assistant::AutofillAssistantIntent::UNDEFINED_INTENT;
+    FormInteractionCounts form_interaction_counts = {};
     if (submitted_form->field_count() > 0) {
       const AutofillField* autofill_field = submitted_form->field(0);
       auto* logger = GetEventFormLogger(autofill_field->Type().group());
-      if (logger)
+      if (logger) {
         intent = logger->autofill_assistant_intent();
+        form_interaction_counts = logger->form_interaction_counts();
+      }
     }
 
     submitted_form->LogQualityMetrics(
         submitted_form->form_parsed_timestamp(), interaction_time,
         submission_time, form_interactions_ukm_logger(), did_show_suggestions_,
-        observed_submission, form_interactions_counter_->GetCounts(), intent);
+        observed_submission, form_interaction_counts, intent);
   }
   if (submitted_form->ShouldBeUploaded())
     UploadFormData(*submitted_form, observed_submission);
@@ -1906,7 +1905,6 @@
   fast_checkout_delegate_->Reset();
   touch_to_fill_delegate_->Reset();
   filling_context_.clear();
-  form_interactions_counter_ = std::make_unique<FormInteractionsCounter>();
 }
 
 bool BrowserAutofillManager::RefreshDataModels() {
@@ -2226,14 +2224,12 @@
       credit_card_form_event_logger_->OnDidFillSuggestion(
           credit_card_, *form_structure, *autofill_field, newly_filled_fields,
           base::flat_set<FieldGlobalId>(std::move(safe_fields)), sync_state_);
-      form_interactions_counter_->OnAutofillFill();
     }
 
     if (!is_credit_card) {
       address_form_event_logger_->OnDidFillSuggestion(
           *absl::get<const AutofillProfile*>(profile_or_credit_card),
           *form_structure, *autofill_field, sync_state_);
-      form_interactions_counter_->OnAutofillFill();
     }
   }
 
@@ -2314,9 +2310,9 @@
   }
 
   auto submitted_form = std::make_unique<FormStructure>(form);
-  submitted_form->RetrieveFromCache(*cached_submitted_form,
-                                    /*should_keep_cached_value=*/false,
-                                    /*only_server_and_autofill_state=*/false);
+  submitted_form->RetrieveFromCache(
+      *cached_submitted_form,
+      FormStructure::RetrieveFromCacheReason::kFormImport);
   if (value_from_dynamic_change_form_) {
     submitted_form->set_value_from_dynamic_change_form(true);
   }
diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h
index 1a32560..3c7aea0 100644
--- a/components/autofill/core/browser/browser_autofill_manager.h
+++ b/components/autofill/core/browser/browser_autofill_manager.h
@@ -30,7 +30,6 @@
 #include "components/autofill/core/browser/form_types.h"
 #include "components/autofill/core/browser/metrics/form_events/address_form_event_logger.h"
 #include "components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.h"
-#include "components/autofill/core/browser/metrics/form_interactions_counter.h"
 #include "components/autofill/core/browser/payments/autofill_offer_manager.h"
 #include "components/autofill/core/browser/payments/card_unmask_delegate.h"
 #include "components/autofill/core/browser/payments/credit_card_access_manager.h"
@@ -424,6 +423,10 @@
       std::unique_ptr<CreditCardAccessManager> manager) {
     credit_card_access_manager_ = std::move(manager);
   }
+
+  const FormInteractionsFlowId& address_form_interactions_flow_id_for_test() {
+    return address_form_event_logger_->form_interactions_flow_id_for_test();
+  }
 #endif  // UNIT_TEST
 
  private:
@@ -788,10 +791,6 @@
   // interaction and re-used throughout the context of this manager.
   AutofillSyncSigninState sync_state_ = AutofillSyncSigninState::kNumSyncStates;
 
-  // Used to keep track of user interactions with text fields, Autocomplete and
-  // Autofill.
-  std::unique_ptr<FormInteractionsCounter> form_interactions_counter_;
-
   // Helps with measuring whether phone number is collected and whether it is in
   // conjunction with WebOTP or OneTimeCode (OTC).
   // value="0" label="Phone Not Collected, WebOTP Not Used, OTC Not Used"
diff --git a/components/autofill/core/browser/form_parsing/parsing_test_utils.cc b/components/autofill/core/browser/form_parsing/parsing_test_utils.cc
index 66a7d3e..34c5087 100644
--- a/components/autofill/core/browser/form_parsing/parsing_test_utils.cc
+++ b/components/autofill/core/browser/form_parsing/parsing_test_utils.cc
@@ -22,7 +22,7 @@
 
 FormFieldTestBase::FormFieldTestBase(
     PatternProviderFeatureState pattern_provider_feature_state) {
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled;
+  std::vector<base::test::FeatureRefAndParams> enabled;
   std::vector<base::test::FeatureRef> disabled;
   if (pattern_provider_feature_state.enable) {
     enabled.emplace_back(
diff --git a/components/autofill/core/browser/form_parsing/phone_field_unittest.cc b/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
index 74207c6..1fbb7271 100644
--- a/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
+++ b/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
@@ -39,7 +39,7 @@
     : public testing::TestWithParam<PatternProviderFeatureState> {
  public:
   PhoneFieldTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled;
+    std::vector<base::test::FeatureRefAndParams> enabled;
     std::vector<base::test::FeatureRef> disabled;
     if (GetParam().enable) {
       enabled.emplace_back(
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 1e8359a..bcf94a6f 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -802,10 +802,8 @@
          ShouldBeParsed();
 }
 
-void FormStructure::RetrieveFromCache(
-    const FormStructure& cached_form,
-    const bool should_keep_cached_value,
-    const bool only_server_and_autofill_state) {
+void FormStructure::RetrieveFromCache(const FormStructure& cached_form,
+                                      RetrieveFromCacheReason reason) {
   // Build a table to lookup AutofillFields by their FieldGlobalId.
   std::map<FieldGlobalId, const AutofillField*> cached_fields_by_id;
   for (const std::unique_ptr<autofill::AutofillField>& field : cached_form)
@@ -851,49 +849,69 @@
     if (!cached_field)
       continue;
 
-    if (should_keep_cached_value) {
-      // During form parsing (as in "assigning field types to fields")
-      // |should_keep_cached_value| is true to preserve the |value|
-      // (which represents the initial value found at page load).
-      field->is_autofilled = cached_field->is_autofilled;
-      if (field->form_control_type != "select-one") {
-        field->value = cached_field->value;
-        value_from_dynamic_change_form_ = true;
-      }
-    } else {
-      // Here |should_keep_cached_value| is false, meaning that we are in the
-      // phase of importing a submitted form.
-      bool same_value_as_on_page_load = field->value == cached_field->value;
-      bool field_is_neither_state_nor_country =
-          field->server_type() != ADDRESS_HOME_COUNTRY &&
-          field->server_type() != ADDRESS_HOME_STATE;
-      if (field->form_control_type != "select-one" &&
-          same_value_as_on_page_load && field_is_neither_state_nor_country) {
+    switch (reason) {
+      case RetrieveFromCacheReason::kFormParsing:
+        // During form parsing (as in "assigning field types to fields")
+        // the `value` represents the initial value found at page load and needs
+        // to be preserved.
+        if (field->form_control_type != "select-one") {
+          field->value = cached_field->value;
+          value_from_dynamic_change_form_ = true;
+        }
+        break;
+      case RetrieveFromCacheReason::kFormImport:
         // From the perspective of learning user data, text fields containing
-        // default values are equivalent to empty fields.
+        // default values are equivalent to empty fields. So if the value of
+        // a submitted form corresponds to the initial value of the field, we
+        // clear that value.
         // Since a website can prefill country and state values based on
-        // GeoIp, we want to hold on to these values. All others are cleared.
-        field->value = std::u16string();
-      }
+        // GeoIP, we want to hold on to these values.
+        const bool same_value_as_on_page_load =
+            field->value == cached_field->value;
+        const bool field_is_neither_state_nor_country =
+            field->server_type() != ADDRESS_HOME_COUNTRY &&
+            field->server_type() != ADDRESS_HOME_STATE;
+        if (field->form_control_type != "select-one" &&
+            same_value_as_on_page_load && field_is_neither_state_nor_country) {
+          field->value = std::u16string();
+        }
+        break;
     }
 
     field->set_server_predictions(cached_field->server_predictions());
-    field->set_previously_autofilled(cached_field->previously_autofilled());
 
+    // TODO(crbug.com/1373362): The following is the statement which we want
+    // to have here once features::kAutofillDontPreserveAutofillState is
+    // launched:
+    // ---
+    // We don't preserve the `is_autofilled` state from the cache, because
+    // form parsing and form import both start in the renderer and the renderer
+    // shares it's most recent status of whether the fields are currently
+    // in autofilled state. Any modifications by JavaScript or the user
+    // may take a field out of the autofilled state and get propagated to the
+    // AutofillManager via OnTextFieldDidChangeImpl anyways.
+    // ---
+    // For now we gate this behavioral change by a feature flag to ensure that
+    // it does not cause a regression.
+    if (!base::FeatureList::IsEnabled(
+            features::kAutofillDontPreserveAutofillState)) {
+      // Preserve state whether the field was autofilled before.
+      if (reason == RetrieveFromCacheReason::kFormParsing)
+        field->is_autofilled = cached_field->is_autofilled;
+    }
+
+    field->set_previously_autofilled(cached_field->previously_autofilled());
     if (cached_field->value_not_autofilled_over_existing_value_hash()) {
       field->set_value_not_autofilled_over_existing_value_hash(
           *cached_field->value_not_autofilled_over_existing_value_hash());
     }
 
-    // Only retrieve an overall prediction from cache if a server prediction
-    // is set.
-    if (base::FeatureList::IsEnabled(
-            features::kAutofillRetrieveOverallPredictionsFromCache) &&
-        field->server_type() != NO_SERVER_DATA) {
-      field->SetTypeTo(cached_field->Type());
-    }
-
-    if (!only_server_and_autofill_state) {
+    // During form parsing, we don't care for heuristic field classifications
+    // and information derived from the autocomplete attribute as those are
+    // either regenerated or copied from the form that the renderer sent.
+    // During import, no parsing happens and we want to preserve the last field
+    // classification.
+    if (reason == RetrieveFromCacheReason::kFormImport) {
       // Transfer attributes of the cached AutofillField to the newly created
       // AutofillField.
       for (int i = 0; i <= static_cast<int>(PatternSource::kMaxValue); ++i) {
@@ -903,6 +921,19 @@
       field->SetHtmlType(cached_field->html_type(), cached_field->html_mode());
       field->section = cached_field->section;
       field->set_only_fill_when_focused(cached_field->only_fill_when_focused());
+
+      // Only retrieve an overall prediction from cache if a server prediction
+      // is set.
+      // The following is just gated behind a flag because it changes behavior.
+      // We are pretty convinced that this should be enabled by default.
+      if (base::FeatureList::IsEnabled(
+              features::kAutofillRetrieveOverallPredictionsFromCache)) {
+        // During import the final field type is used to decide which
+        // information to store in an address profile or credit card. As
+        // rationalization is an important component of determinig the final
+        // field type, the output should be preserved.
+        field->SetTypeTo(cached_field->Type());
+      }
     }
   }
 
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h
index 5fef59a..81f175b 100644
--- a/components/autofill/core/browser/form_structure.h
+++ b/components/autofill/core/browser/form_structure.h
@@ -21,7 +21,6 @@
 #include "components/autofill/core/browser/form_parsing/field_candidates.h"
 #include "components/autofill/core/browser/form_types.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
-#include "components/autofill/core/browser/metrics/form_interactions_counter.h"
 #include "components/autofill/core/browser/proto/api_v1.pb.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/dense_set.h"
@@ -192,10 +191,58 @@
   // crowd-sourcing server. It is not applied for Password Manager votes.
   bool ShouldBeUploaded() const;
 
-  // Sets the field types to be those set for |cached_form|.
+  // This enum defines the behavior of RetrieveFromCache, which needs to adapt
+  // to the reason for retrieving data from the cache.
+  enum class RetrieveFromCacheReason {
+    // kFormParsing refers to the process of assigning field types to fields
+    // when the renderer notifies the browser about a new, modified or
+    // interacted with form.
+    //
+    // During form parsing, the browser receives a FormData object from the
+    // renderer that is converted to a FormStructure object. RetrieveFromCache
+    // is responsible for retaining information from the history of the fields
+    // in the form (e.g. information about previous fill operations):
+    //
+    // - The `is_autofilled` and similar members of a field are copied from the
+    //   cached form so that a field that was once labeled as autofilled remains
+    //   autofilled.
+    //
+    // - The `value` of a field is copied from the cache as it represents the
+    //   initial value of a field during page load time and must not be updated
+    //   if a form is parsed a second time.
+    //
+    // - Also server predictions are preserved (while heuristic predictions
+    //   are discarded because they will be generated during the parsing).
+    kFormParsing,
+
+    // kFormImport refers to the process of importing address profiles / credit
+    // cards from user-filled forms after a form submission.
+    //
+    // During form import, the browser receives a FormData object from the
+    // renderer that is converted to a FormStructure object. RetrieveFromCache
+    // is responsible for processing the FormData so that the FormStructure
+    // contains the right information that facilitate importing. Therefore,
+    // similar work happen as for kFormParsing, except:
+    //
+    // - During form import, we want to copy field type information from
+    //   previous parse operations as these tell which information to save.
+    //
+    // - The `value` of a FormStructure's field typically represents the
+    //   initially observed value of a field during page load. So during
+    //   kFormParsing the value is persisted. During import, however, we want to
+    //   store the last observed value. Furthermore, if the submitted value of a
+    //   field has never been changed, we ignore the previous value from import
+    //   (unless it's a state or country as websites can find meanigful default
+    //   values via GeoIP).
+    kFormImport,
+  };
+
+  // Assumes that `*this` is FormStructure which was freshly created from a
+  // FormData object that the renderer sent to the browser and copies relevant
+  // information from a `cached_form` to `*this`. Depending on the passed
+  // `reason`, a different subset of data can be copied.
   void RetrieveFromCache(const FormStructure& cached_form,
-                         const bool should_keep_cached_value,
-                         const bool only_server_and_autofill_state);
+                         RetrieveFromCacheReason reason);
 
   // Logs quality metrics for |this|, which should be a user-submitted form.
   // This method should only be called after the possible field types have been
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index b90569f7..8c187dd4 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -170,7 +170,7 @@
  public:
   FormStructureTest_ForPatternSource() {
     scoped_feature_list_.InitWithFeaturesAndParameters(
-        {base::test::ScopedFeatureList::FeatureAndParams(
+        {base::test::FeatureRefAndParams(
             features::kAutofillParsingPatternProvider,
             {{"prediction_source", pattern_source_as_string()}})},
         {});
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.cc b/components/autofill/core/browser/metrics/autofill_metrics.cc
index b067083..eef13ac7 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/metrics/metrics_hashes.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
@@ -31,6 +32,7 @@
 #include "components/autofill/core/common/autofill_prefs.h"
 #include "components/autofill/core/common/autofill_tick_clock.h"
 #include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/form_interactions_flow.h"
 #include "components/language/core/browser/language_usage_metrics.h"
 #include "services/metrics/public/cpp/metrics_utils.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
@@ -2715,9 +2717,7 @@
           std::min(form_interaction_counts.form_element_user_modifications,
                    kFormUserInteractionsOverflowBucket))
       .SetAutofillFills(std::min(form_interaction_counts.autofill_fills,
-                                 kFormUserInteractionsOverflowBucket))
-      .SetAutocompleteFills(std::min(form_interaction_counts.autocomplete_fills,
-                                     kFormUserInteractionsOverflowBucket));
+                                 kFormUserInteractionsOverflowBucket));
   if (form_parsed_timestamp.is_null())
     DCHECK(state == NON_FILLABLE_FORM_OR_NEW_DATA ||
            state == FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS)
@@ -2738,14 +2738,20 @@
     bool suggestions_shown,
     bool edited_autofilled_field,
     bool suggestion_filled,
-    autofill_assistant::AutofillAssistantIntent intent) {
+    autofill_assistant::AutofillAssistantIntent intent,
+    const FormInteractionCounts& form_interaction_counts,
+    const FormInteractionsFlowId& flow_id) {
   if (!CanLog())
     return;
 
   ukm::builders::Autofill_KeyMetrics builder(source_id_);
   builder.SetFillingReadiness(data_to_fill_available)
       .SetFillingAssistance(suggestion_filled)
-      .SetFormTypes(FormTypesToBitVector(form_types));
+      .SetFormTypes(FormTypesToBitVector(form_types))
+      .SetAutofillFills(form_interaction_counts.autofill_fills)
+      .SetFormElementUserModifications(
+          form_interaction_counts.form_element_user_modifications)
+      .SetFlowId(base::HashMetricName(flow_id->AsLowercaseString()));
 
   if (intent != autofill_assistant::AutofillAssistantIntent::UNDEFINED_INTENT)
     builder.SetAutofillAssistantIntent(static_cast<int64_t>(intent));
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.h b/components/autofill/core/browser/metrics/autofill_metrics.h
index 307f460..1169240 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.h
+++ b/components/autofill/core/browser/metrics/autofill_metrics.h
@@ -23,7 +23,6 @@
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_types.h"
 #include "components/autofill/core/browser/metrics/form_events/form_events.h"
-#include "components/autofill/core/browser/metrics/form_interactions_counter.h"
 #include "components/autofill/core/browser/sync_utils.h"
 #include "components/autofill/core/browser/ui/popup_types.h"
 #include "components/autofill/core/common/dense_set.h"
@@ -982,7 +981,9 @@
                        bool suggestions_shown,
                        bool edited_autofilled_field,
                        bool suggestion_filled,
-                       autofill_assistant::AutofillAssistantIntent intent);
+                       autofill_assistant::AutofillAssistantIntent intent,
+                       const FormInteractionCounts& form_interaction_counts,
+                       const FormInteractionsFlowId& flow_id);
     void LogFormEvent(FormEvent form_event,
                       const DenseSet<FormType>& form_types,
                       const base::TimeTicks& form_parsed_timestamp);
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_test_base.h b/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
index 5d0658f..0ed768a 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
+++ b/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_AUTOFILL_METRICS_TEST_BASE_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_AUTOFILL_METRICS_TEST_BASE_H_
 
+#include "base/metrics/metrics_hashes.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "components/autofill/core/browser/autofill_form_test_utils.h"
@@ -171,6 +172,10 @@
     return *autofill_client_->GetPersonalDataManager();
   }
 
+  uint64_t address_form_flow_id_hash() {
+    return base::HashMetricName(autofill_manager().GetAddressFormFlowId());
+  }
+
   const bool is_in_any_main_frame_ = true;
   base::test::TaskEnvironment task_environment_;
   test::AutofillEnvironment autofill_environment_;
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index 215cdc29..93e5f27 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -40,7 +40,6 @@
 #include "components/autofill/core/browser/metrics/form_events/address_form_event_logger.h"
 #include "components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.h"
 #include "components/autofill/core/browser/metrics/form_events/form_events.h"
-#include "components/autofill/core/browser/metrics/form_interactions_counter.h"
 #include "components/autofill/core/browser/metrics/payments/credit_card_save_metrics.h"
 #include "components/autofill/core/browser/payments/credit_card_access_manager.h"
 #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
@@ -64,6 +63,7 @@
 #include "components/autofill/core/common/dense_set.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/form_interactions_flow.h"
 #include "components/autofill/core/common/signatures.h"
 #include "components/autofill/core/common/unique_ids.h"
 #include "components/prefs/pref_service.h"
@@ -231,9 +231,7 @@
               {UkmFormSubmittedType::kFormElementUserModificationsName,
                form_interaction_counts.form_element_user_modifications},
               {UkmFormSubmittedType::kAutofillFillsName,
-               form_interaction_counts.autofill_fills},
-              {UkmFormSubmittedType::kAutocompleteFillsName,
-               form_interaction_counts.autocomplete_fills}}});
+               form_interaction_counts.autofill_fills}}});
 }
 
 void AppendFieldFillStatusUkm(const FormData& form,
@@ -3338,8 +3336,8 @@
   // because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
   VerifySubmitFormUkm(test_ukm_recorder_, form,
                       AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
-                      /*is_for_credit_card=*/true, /* has_upi_vpa_field=*/false,
-                      {FormType::kCreditCardForm}, {0, 3, 0});
+                      /*is_for_credit_card=*/true, /*has_upi_vpa_field=*/false,
+                      {FormType::kCreditCardForm}, {.autofill_fills = 3});
 }
 
 // Test that the UPI Checkout flow form submit is correctly logged
@@ -3479,10 +3477,11 @@
                Collapse(CalculateFormSignature(form)).value()}}});
   // Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState|
   // because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
-  VerifySubmitFormUkm(
-      test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
-      /*is_for_credit_card=*/false,
-      /* has_upi_vpa_field=*/false, {FormType::kAddressForm}, {0, 2, 0});
+  VerifySubmitFormUkm(test_ukm_recorder_, form,
+                      AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
+                      /*is_for_credit_card=*/false,
+                      /*has_upi_vpa_field=*/false, {FormType::kAddressForm},
+                      {.autofill_fills = 2});
 }
 
 // Tests that the Autofill_PolledCreditCardSuggestions user action is only
@@ -4908,7 +4907,7 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/true,
-                        /* has_upi_vpa_field=*/false,
+                        /*has_upi_vpa_field=*/false,
                         {FormType::kCreditCardForm});
   }
 
@@ -4951,7 +4950,7 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/true,
-                        /* has_upi_vpa_field=*/false,
+                        /*has_upi_vpa_field=*/false,
                         {FormType::kCreditCardForm});
   }
 
@@ -4998,7 +4997,7 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/true,
-                        /* has_upi_vpa_field=*/false,
+                        /*has_upi_vpa_field=*/false,
                         {FormType::kCreditCardForm});
   }
 
@@ -5043,8 +5042,8 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/true,
-                        /* has_upi_vpa_field=*/false,
-                        {FormType::kCreditCardForm}, {0, 1, 0});
+                        /*has_upi_vpa_field=*/false,
+                        {FormType::kCreditCardForm}, {.autofill_fills = 1});
   }
 
   // Reset the autofill manager state and purge UKM logs.
@@ -5090,8 +5089,8 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/true,
-                        /* has_upi_vpa_field=*/false,
-                        {FormType::kCreditCardForm}, {0, 1, 0});
+                        /*has_upi_vpa_field=*/false,
+                        {FormType::kCreditCardForm}, {.autofill_fills = 1});
   }
 
   // Reset the autofill manager state and purge UKM logs.
@@ -5137,8 +5136,8 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/true,
-                        /* has_upi_vpa_field=*/false,
-                        {FormType::kCreditCardForm}, {0, 1, 0});
+                        /*has_upi_vpa_field=*/false,
+                        {FormType::kCreditCardForm}, {.autofill_fills = 1});
   }
 
   // Reset the autofill manager state and purge UKM logs.
@@ -5183,8 +5182,8 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/true,
-                        /* has_upi_vpa_field=*/false,
-                        {FormType::kCreditCardForm}, {0, 1, 0});
+                        /*has_upi_vpa_field=*/false,
+                        {FormType::kCreditCardForm}, {.autofill_fills = 1});
   }
 
   // Reset the autofill manager state and purge UKM logs.
@@ -5210,7 +5209,7 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/true,
-                        /* has_upi_vpa_field=*/false,
+                        /*has_upi_vpa_field=*/false,
                         {FormType::kCreditCardForm});
 
     SubmitForm(form);
@@ -5227,8 +5226,7 @@
           {UkmFormSubmittedType::kFormSignatureName,
            Collapse(CalculateFormSignature(form)).value()},
           {UkmFormSubmittedType::kFormElementUserModificationsName, 0},
-          {UkmFormSubmittedType::kAutofillFillsName, 0},
-          {UkmFormSubmittedType::kAutocompleteFillsName, 0}},
+          {UkmFormSubmittedType::kAutofillFillsName, 0}},
          {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
            AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
           {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
@@ -5239,8 +5237,7 @@
           {UkmFormSubmittedType::kFormSignatureName,
            Collapse(CalculateFormSignature(form)).value()},
           {UkmFormSubmittedType::kFormElementUserModificationsName, 0},
-          {UkmFormSubmittedType::kAutofillFillsName, 0},
-          {UkmFormSubmittedType::kAutocompleteFillsName, 0}}});
+          {UkmFormSubmittedType::kAutofillFillsName, 0}}});
 
     histogram_tester.ExpectBucketCount(
         "Autofill.FormEvents.CreditCard",
@@ -5391,7 +5388,7 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/true,
-                        /* has_upi_vpa_field=*/false,
+                        /*has_upi_vpa_field=*/false,
                         {FormType::kCreditCardForm});
   }
 }
@@ -6561,7 +6558,7 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/false,
-                        /* has_upi_vpa_field=*/false, {FormType::kAddressForm});
+                        /*has_upi_vpa_field=*/false, {FormType::kAddressForm});
   }
 
   // Reset the autofill manager state and purge UKM logs.
@@ -6588,7 +6585,7 @@
     VerifySubmitFormUkm(test_ukm_recorder_, form,
                         AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
                         /*is_for_credit_card=*/false,
-                        /* has_upi_vpa_field=*/false, {FormType::kAddressForm});
+                        /*has_upi_vpa_field=*/false, {FormType::kAddressForm});
   }
 
   // Reset the autofill manager state and purge UKM logs.
@@ -7155,8 +7152,7 @@
          {UkmFormSubmittedType::kFormSignatureName,
           Collapse(CalculateFormSignature(form)).value()},
          {UkmFormSubmittedType::kFormElementUserModificationsName, 0},
-         {UkmFormSubmittedType::kAutofillFillsName, 0},
-         {UkmFormSubmittedType::kAutocompleteFillsName, 0}});
+         {UkmFormSubmittedType::kAutofillFillsName, 0}});
     VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
               expected_form_submission_ukm_metrics);
 
@@ -7191,8 +7187,7 @@
          {UkmFormSubmittedType::kFormSignatureName,
           Collapse(CalculateFormSignature(form)).value()},
          {UkmFormSubmittedType::kFormElementUserModificationsName, 0},
-         {UkmFormSubmittedType::kAutofillFillsName, 0},
-         {UkmFormSubmittedType::kAutocompleteFillsName, 0}});
+         {UkmFormSubmittedType::kAutofillFillsName, 0}});
     VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
               expected_form_submission_ukm_metrics);
 
@@ -7231,8 +7226,7 @@
          {UkmFormSubmittedType::kFormSignatureName,
           Collapse(CalculateFormSignature(form)).value()},
          {UkmFormSubmittedType::kFormElementUserModificationsName, 0},
-         {UkmFormSubmittedType::kAutofillFillsName, 0},
-         {UkmFormSubmittedType::kAutocompleteFillsName, 0}});
+         {UkmFormSubmittedType::kAutofillFillsName, 0}});
 
     VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
               expected_form_submission_ukm_metrics);
@@ -7279,8 +7273,7 @@
          {UkmFormSubmittedType::kFormSignatureName,
           Collapse(CalculateFormSignature(form)).value()},
          {UkmFormSubmittedType::kFormElementUserModificationsName, 0},
-         {UkmFormSubmittedType::kAutofillFillsName, 0},
-         {UkmFormSubmittedType::kAutocompleteFillsName, 0}});
+         {UkmFormSubmittedType::kAutofillFillsName, 0}});
     VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
               expected_form_submission_ukm_metrics);
 
@@ -7315,8 +7308,7 @@
          {UkmFormSubmittedType::kFormSignatureName,
           Collapse(CalculateFormSignature(form)).value()},
          {UkmFormSubmittedType::kFormElementUserModificationsName, 0},
-         {UkmFormSubmittedType::kAutofillFillsName, 0},
-         {UkmFormSubmittedType::kAutocompleteFillsName, 0}});
+         {UkmFormSubmittedType::kAutofillFillsName, 0}});
     VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
               expected_form_submission_ukm_metrics);
 
@@ -7352,8 +7344,7 @@
          {UkmFormSubmittedType::kFormSignatureName,
           Collapse(CalculateFormSignature(form)).value()},
          {UkmFormSubmittedType::kFormElementUserModificationsName, 0},
-         {UkmFormSubmittedType::kAutofillFillsName, 0},
-         {UkmFormSubmittedType::kAutocompleteFillsName, 0}});
+         {UkmFormSubmittedType::kAutofillFillsName, 0}});
     VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
               expected_form_submission_ukm_metrics);
 
@@ -7414,8 +7405,7 @@
          {UkmFormSubmittedType::kFormSignatureName,
           Collapse(CalculateFormSignature(form)).value()},
          {UkmFormSubmittedType::kFormElementUserModificationsName, 0},
-         {UkmFormSubmittedType::kAutofillFillsName, 0},
-         {UkmFormSubmittedType::kAutocompleteFillsName, 0}});
+         {UkmFormSubmittedType::kAutofillFillsName, 0}});
     VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
               expected_form_submission_ukm_metrics);
 
@@ -9512,7 +9502,7 @@
     AddressFormEventLogger logger(
         /*is_in_any_main_frame=*/true,
         /*form_interactions_ukm_logger=*/nullptr,
-        /*client=*/nullptr);
+        /*client=*/autofill_client_.get());
     logger.OnDidSeeFillableDynamicForm(AutofillSyncSigninState::kSignedOut,
                                        form_structure);
     histogram_tester.ExpectBucketCount(
@@ -9524,7 +9514,7 @@
     AddressFormEventLogger logger(
         /*is_in_any_main_frame=*/true,
         /*form_interactions_ukm_logger=*/nullptr,
-        /*client=*/nullptr);
+        /*client=*/autofill_client_.get());
     logger.OnDidRefill(AutofillSyncSigninState::kSignedIn, form_structure);
     histogram_tester.ExpectBucketCount(
         "Autofill.FormEvents.Address.WithNoData.SignedIn",
@@ -9638,6 +9628,7 @@
     SubmitForm(form);
   }
 
+  uint64_t flow_id = address_form_flow_id_hash();
   ResetDriverToCommitMetrics();
 
   // Phase 2: Validate Funnel expectations.
@@ -9691,12 +9682,16 @@
         "Autofill.Autocomplete.NotOff.FillingAcceptance.Address", 1, 1);
     histogram_tester.ExpectTotalCount(
         "Autofill.Autocomplete.Off.FillingAcceptance.Address", 0);
-    VerifyUkm(test_ukm_recorder_, form, UkmAutofillKeyMetricsType::kEntryName,
-              {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
-                {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 1},
-                {UkmAutofillKeyMetricsType::kFillingCorrectnessName, 1},
-                {UkmAutofillKeyMetricsType::kFillingAssistanceName, 1},
-                {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
+    VerifyUkm(
+        test_ukm_recorder_, form, UkmAutofillKeyMetricsType::kEntryName,
+        {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+          {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 1},
+          {UkmAutofillKeyMetricsType::kFillingCorrectnessName, 1},
+          {UkmAutofillKeyMetricsType::kFillingAssistanceName, 1},
+          {UkmAutofillKeyMetricsType::kAutofillFillsName, 1},
+          {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 0},
+          {UkmAutofillKeyMetricsType::kFlowIdName, flow_id},
+          {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
   } else {
     histogram_tester.ExpectTotalCount(
         "Autofill.KeyMetrics.FillingReadiness.Address", 0);
@@ -9812,6 +9807,7 @@
 
   SubmitForm(form_);
 
+  uint64_t flow_id = address_form_flow_id_hash();
   ResetDriverToCommitMetrics();
 
   histogram_tester.ExpectBucketCount(
@@ -9828,6 +9824,9 @@
   VerifyUkm(test_ukm_recorder_, form_, UkmAutofillKeyMetricsType::kEntryName,
             {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
               {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+              {UkmAutofillKeyMetricsType::kAutofillFillsName, 0},
+              {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 0},
+              {UkmAutofillKeyMetricsType::kFlowIdName, flow_id},
               {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
 }
 
@@ -9845,6 +9844,7 @@
   SimulateUserChangedTextField(form_, form_.fields[1]);
   SubmitForm(form_);
 
+  uint64_t flow_id = address_form_flow_id_hash();
   ResetDriverToCommitMetrics();
 
   histogram_tester.ExpectBucketCount(
@@ -9861,6 +9861,9 @@
   VerifyUkm(test_ukm_recorder_, form_, UkmAutofillKeyMetricsType::kEntryName,
             {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 0},
               {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+              {UkmAutofillKeyMetricsType::kAutofillFillsName, 0},
+              {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 2},
+              {UkmAutofillKeyMetricsType::kFlowIdName, flow_id},
               {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
 }
 
@@ -9878,6 +9881,7 @@
   SimulateUserChangedTextField(form_, form_.fields[1]);
   SubmitForm(form_);
 
+  uint64_t flow_id = address_form_flow_id_hash();
   ResetDriverToCommitMetrics();
 
   histogram_tester.ExpectBucketCount(
@@ -9895,6 +9899,9 @@
             {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
               {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 0},
               {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+              {UkmAutofillKeyMetricsType::kAutofillFillsName, 0},
+              {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 2},
+              {UkmAutofillKeyMetricsType::kFlowIdName, flow_id},
               {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
 }
 
@@ -9913,6 +9920,7 @@
   SimulateUserChangedTextField(form_, form_.fields[1]);
   SubmitForm(form_);
 
+  uint64_t flow_id = address_form_flow_id_hash();
   ResetDriverToCommitMetrics();
 
   histogram_tester.ExpectBucketCount(
@@ -9931,6 +9939,9 @@
               {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 1},
               {UkmAutofillKeyMetricsType::kFillingCorrectnessName, 0},
               {UkmAutofillKeyMetricsType::kFillingAssistanceName, 1},
+              {UkmAutofillKeyMetricsType::kAutofillFillsName, 1},
+              {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 1},
+              {UkmAutofillKeyMetricsType::kFlowIdName, flow_id},
               {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
 }
 
@@ -9951,6 +9962,7 @@
 
   // Don't submit form.
 
+  uint64_t flow_id = address_form_flow_id_hash();
   ResetDriverToCommitMetrics();
 
   histogram_tester.ExpectTotalCount(
@@ -9969,6 +9981,9 @@
               {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 0},
               {UkmAutofillKeyMetricsType::kFillingCorrectnessName, 0},
               {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+              {UkmAutofillKeyMetricsType::kAutofillFillsName, 0},
+              {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 0},
+              {UkmAutofillKeyMetricsType::kFlowIdName, flow_id},
               {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
 }
 
@@ -10170,9 +10185,8 @@
   VerifySubmitFormUkm(
       test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
       /*is_for_credit_card=*/false,
-      /* has_upi_vpa_field=*/false, {FormType::kAddressForm},
-      {/*form_element_user_modifications=*/1, /*autofill_fills=*/1,
-       /*autocomplete_fills=*/2});
+      /*has_upi_vpa_field=*/false, {FormType::kAddressForm},
+      {.form_element_user_modifications = 1, .autofill_fills = 1});
 }
 
 TEST_F(AutofillMetricsTest, FormInteractionsAreInitiallyZero) {
@@ -10187,12 +10201,10 @@
   SubmitForm(form);
 
   // THEN
-  VerifySubmitFormUkm(
-      test_ukm_recorder_, form, AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
-      /*is_for_credit_card=*/false,
-      /* has_upi_vpa_field=*/false, {FormType::kAddressForm},
-      {/*form_element_user_modifications=*/0, /*autofill_fills=*/0,
-       /*autocomplete_fills=*/0});
+  VerifySubmitFormUkm(test_ukm_recorder_, form,
+                      AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
+                      /*is_for_credit_card=*/false,
+                      /*has_upi_vpa_field=*/false, {FormType::kAddressForm});
 }
 
 // Base class for cross-frame filling metrics, in particular for
@@ -10206,11 +10218,9 @@
 
   AutofillMetricsCrossFrameFormTest() {
     scoped_feature_list_.InitWithFeaturesAndParameters(
-        {base::test::ScopedFeatureList::FeatureAndParams(
-             features::kAutofillAcrossIframes, {}),
-         base::test::ScopedFeatureList::FeatureAndParams(
-             features::kAutofillSharedAutofill,
-             {{"relax_shared_autofill", "true"}})},
+        {base::test::FeatureRefAndParams(features::kAutofillAcrossIframes, {}),
+         base::test::FeatureRefAndParams(features::kAutofillSharedAutofill,
+                                         {{"relax_shared_autofill", "true"}})},
         {});
   }
   ~AutofillMetricsCrossFrameFormTest() override = default;
diff --git a/components/autofill/core/browser/metrics/form_events/address_form_event_logger.cc b/components/autofill/core/browser/metrics/form_events/address_form_event_logger.cc
index 493391e0..935f6d1 100644
--- a/components/autofill/core/browser/metrics/form_events/address_form_event_logger.cc
+++ b/components/autofill/core/browser/metrics/form_events/address_form_event_logger.cc
@@ -24,7 +24,7 @@
     : FormEventLoggerBase("Address",
                           is_in_any_main_frame,
                           form_interactions_ukm_logger,
-                          client ? client->GetLogManager() : nullptr) {}
+                          client) {}
 
 AddressFormEventLogger::~AddressFormEventLogger() = default;
 
@@ -58,6 +58,9 @@
 
   base::RecordAction(
       base::UserMetricsAction("Autofill_FilledProfileSuggestion"));
+
+  ++form_interaction_counts_.autofill_fills;
+  UpdateFlowId();
 }
 
 void AddressFormEventLogger::OnDidSeeFillableDynamicForm(
diff --git a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
index d5e71d8..661be6f 100644
--- a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
+++ b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
@@ -29,7 +29,7 @@
     : FormEventLoggerBase("CreditCard",
                           is_in_any_main_frame,
                           form_interactions_ukm_logger,
-                          client ? client->GetLogManager() : nullptr),
+                          client),
       current_authentication_flow_(UnmaskAuthFlowType::kNone),
       personal_data_manager_(personal_data_manager),
       client_(client) {}
@@ -173,6 +173,9 @@
       base::UserMetricsAction("Autofill_FilledCreditCardSuggestion"));
 
   form_interactions_ukm_logger_->Record(std::move(builder));
+
+  ++form_interaction_counts_.autofill_fills;
+  UpdateFlowId();
 }
 
 void CreditCardFormEventLogger::LogCardUnmaskAuthenticationPromptShown(
diff --git a/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc b/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc
index 34c965d..9d8cfff 100644
--- a/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc
+++ b/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc
@@ -42,11 +42,11 @@
     const std::string& form_type_name,
     bool is_in_any_main_frame,
     AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
-    LogManager* log_manager)
+    AutofillClient* client)
     : form_type_name_(form_type_name),
       is_in_any_main_frame_(is_in_any_main_frame),
       form_interactions_ukm_logger_(form_interactions_ukm_logger),
-      log_manager_(log_manager) {}
+      client_(*client) {}
 
 FormEventLoggerBase::~FormEventLoggerBase() {
   // Don't record Funnel and Key metrics for the ablation group as they don't
@@ -270,8 +270,8 @@
 }
 
 void FormEventLoggerBase::RecordFunnelAndKeyMetrics() {
-  LogBuffer funnel_rows(IsLoggingActive(log_manager_));
-  LogBuffer key_metrics_rows(IsLoggingActive(log_manager_));
+  LogBuffer funnel_rows(IsLoggingActive(client_->GetLogManager()));
+  LogBuffer key_metrics_rows(IsLoggingActive(client_->GetLogManager()));
 
   LOG_AF(funnel_rows) << Tr{} << "Form Type: " << form_type_name_;
   LOG_AF(key_metrics_rows) << Tr{} << "Form Type: " << form_type_name_;
@@ -355,7 +355,8 @@
       form_interactions_ukm_logger_->LogKeyMetrics(
           submitted_form_types_, has_logged_data_to_fill_available_,
           has_logged_suggestions_shown_, has_logged_edited_autofilled_field_,
-          has_logged_suggestion_filled_, intent_);
+          has_logged_suggestion_filled_, intent_, form_interaction_counts_,
+          flow_id_);
     }
   }
   if (has_logged_typed_into_non_filled_field_ ||
@@ -373,12 +374,12 @@
         << Tr{} << "FormSubmission.Submission" << has_logged_will_submit_;
   }
 
-  LOG_AF(log_manager_) << LoggingScope::kMetrics << LogMessage::kFunnelMetrics
-                       << Tag{"table"} << std::move(funnel_rows)
-                       << CTag{"table"};
-  LOG_AF(log_manager_) << LoggingScope::kMetrics << LogMessage::kKeyMetrics
-                       << Tag{"table"} << std::move(key_metrics_rows)
-                       << CTag{"table"};
+  LOG_AF(client_->GetLogManager())
+      << LoggingScope::kMetrics << LogMessage::kFunnelMetrics << Tag{"table"}
+      << std::move(funnel_rows) << CTag{"table"};
+  LOG_AF(client_->GetLogManager())
+      << LoggingScope::kMetrics << LogMessage::kKeyMetrics << Tag{"table"}
+      << std::move(key_metrics_rows) << CTag{"table"};
 }
 
 void FormEventLoggerBase::RecordAblationMetrics() {
@@ -484,4 +485,17 @@
   return intent_;
 }
 
+void FormEventLoggerBase::OnTextFieldDidChange(
+    const FieldGlobalId& field_global_id) {
+  if (field_global_id != last_field_global_id_modified_by_user_) {
+    ++form_interaction_counts_.form_element_user_modifications;
+    last_field_global_id_modified_by_user_ = field_global_id;
+    UpdateFlowId();
+  }
+}
+
+void FormEventLoggerBase::UpdateFlowId() {
+  flow_id_ = client_->GetCurrentFormInteractionsFlowId();
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/metrics/form_events/form_event_logger_base.h b/components/autofill/core/browser/metrics/form_events/form_event_logger_base.h
index 186eb24f..df95b860c 100644
--- a/components/autofill/core/browser/metrics/form_events/form_event_logger_base.h
+++ b/components/autofill/core/browser/metrics/form_events/form_event_logger_base.h
@@ -16,12 +16,11 @@
 #include "components/autofill/core/browser/metrics/form_events/form_events.h"
 #include "components/autofill/core/browser/sync_utils.h"
 #include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/form_interactions_flow.h"
 #include "components/autofill_assistant/core/public/autofill_assistant_intent.h"
 
 namespace autofill {
 
-class LogManager;
-
 // Utility to log autofill form events in the relevant histograms depending on
 // the presence of server and/or local data.
 class FormEventLoggerBase {
@@ -30,7 +29,7 @@
       const std::string& form_type_name,
       bool is_in_any_main_frame,
       AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
-      LogManager* log_manager);
+      AutofillClient* client);
 
   inline void set_server_record_type_count(size_t server_record_type_count) {
     server_record_type_count_ = server_record_type_count;
@@ -86,6 +85,18 @@
 
   autofill_assistant::AutofillAssistantIntent autofill_assistant_intent() const;
 
+  void OnTextFieldDidChange(const FieldGlobalId& field_global_id);
+
+  const FormInteractionCounts& form_interaction_counts() const {
+    return form_interaction_counts_;
+  }
+
+#ifdef UNIT_TEST
+  const FormInteractionsFlowId& form_interactions_flow_id_for_test() {
+    return flow_id_;
+  }
+#endif
+
  protected:
   virtual ~FormEventLoggerBase();
 
@@ -130,6 +141,8 @@
   // called in the destructor.
   void RecordAblationMetrics();
 
+  void UpdateFlowId();
+
   // Constructor parameters.
   std::string form_type_name_;
   bool is_in_any_main_frame_;
@@ -162,6 +175,15 @@
   autofill_assistant::AutofillAssistantIntent intent_ =
       autofill_assistant::AutofillAssistantIntent::UNDEFINED_INTENT;
 
+  // Used to count consecutive modifications on the same field as one change.
+  FieldGlobalId last_field_global_id_modified_by_user_;
+  // Keeps counts of Autofill fills and form elements that were modified by the
+  // user.
+  FormInteractionCounts form_interaction_counts_ = {};
+  // Unique random id that is set on the first form interaction and identical
+  // during the flow.
+  FormInteractionsFlowId flow_id_;
+
   // Form types of the submitted form
   DenseSet<FormType> submitted_form_types_;
 
@@ -170,7 +192,7 @@
       form_interactions_ukm_logger_;
 
   // Weak reference.
-  const raw_ptr<LogManager> log_manager_;
+  const raw_ref<AutofillClient> client_;
 
   AutofillSyncSigninState sync_state_ = AutofillSyncSigninState::kNumSyncStates;
 };
diff --git a/components/autofill/core/browser/metrics/form_interactions_counter.cc b/components/autofill/core/browser/metrics/form_interactions_counter.cc
deleted file mode 100644
index 0da67b1..0000000
--- a/components/autofill/core/browser/metrics/form_interactions_counter.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/metrics/form_interactions_counter.h"
-
-namespace autofill {
-
-FormInteractionsCounter::~FormInteractionsCounter() = default;
-
-void FormInteractionsCounter::OnTextFieldDidChange(
-    const FieldSignature& field_signature) {
-  if (field_signature != last_field_signature_modified_by_user_) {
-    form_interaction_counts_.form_element_user_modifications++;
-    last_field_signature_modified_by_user_ = field_signature;
-  }
-}
-
-void FormInteractionsCounter::OnAutofillFill() {
-  form_interaction_counts_.autofill_fills++;
-}
-
-void FormInteractionsCounter::OnAutocompleteFill() {
-  form_interaction_counts_.autocomplete_fills++;
-}
-
-const FormInteractionCounts& FormInteractionsCounter::GetCounts() const {
-  return form_interaction_counts_;
-}
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/metrics/form_interactions_counter.h b/components/autofill/core/browser/metrics/form_interactions_counter.h
deleted file mode 100644
index 470dd2e..0000000
--- a/components/autofill/core/browser/metrics/form_interactions_counter.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_FORM_INTERACTIONS_COUNTER_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_FORM_INTERACTIONS_COUNTER_H_
-
-#include "components/autofill/core/common/signatures.h"
-
-namespace autofill {
-
-struct FormInteractionCounts {
-  int64_t form_element_user_modifications = 0;
-  int64_t autofill_fills = 0;
-  int64_t autocomplete_fills = 0;
-};
-
-// Holds and increments counts of user interactions with autofillable form
-// elements, Autofill and Autocomplete
-class FormInteractionsCounter {
- public:
-  FormInteractionsCounter() = default;
-  FormInteractionsCounter(const FormInteractionsCounter&) = delete;
-  FormInteractionsCounter& operator=(const FormInteractionsCounter&) = delete;
-
-  virtual ~FormInteractionsCounter();
-
-  void OnTextFieldDidChange(const FieldSignature& field_signature);
-
-  void OnAutofillFill();
-
-  void OnAutocompleteFill();
-
-  const FormInteractionCounts& GetCounts() const;
-
- private:
-  FieldSignature last_field_signature_modified_by_user_;
-
-  FormInteractionCounts form_interaction_counts_ = {};
-};
-
-}  // namespace autofill
-
-#endif
diff --git a/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc b/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
index 1929b17d..edb0c107 100644
--- a/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
@@ -115,7 +115,7 @@
  public:
   AutofillShadowPredictionMetricsTest() {
     scoped_feature_list_.InitWithFeaturesAndParameters(
-        {base::test::ScopedFeatureList::FeatureAndParams(
+        {base::test::FeatureRefAndParams(
             features::kAutofillParsingPatternProvider,
             {{"prediction_source", "default"}})},
         {});
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index b96abf7..e01223c 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -443,7 +443,7 @@
                      error_api_error_reason, "virtual_card_permanent_error")) {
         result =
             AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure;
-      } else if (base::EqualsCaseInsensitiveASCII(error_code, "internal")) {
+      } else if (request_->IsRetryableFailure(error_code)) {
         result = AutofillClient::PaymentsRpcResult::kTryAgainFailure;
       } else if (!error_code.empty() || !request_->IsResponseComplete()) {
         result = AutofillClient::PaymentsRpcResult::kPermanentFailure;
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc
index 760a302..0d91835 100644
--- a/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -798,6 +798,19 @@
   EXPECT_EQ(CvcPosition::kBackOfCard, challenge_option_3.cvc_position);
 }
 
+TEST_F(PaymentsClientTest, VirtualCardCvcRetrieval_FlowStatusPresent) {
+  StartUnmasking(
+      CardUnmaskOptions().with_virtual_card_risk_based().with_cvc("123"));
+  IssueOAuthToken();
+  ReturnResponse(
+      net::HTTP_OK,
+      "{\"flow_status\": \"FLOW_STATUS_INCORRECT_ACCOUNT_SECURITY_CODE\"}");
+
+  // Ensure that it is treated as a try again failure when a flow status is
+  // returned.
+  EXPECT_EQ(AutofillClient::PaymentsRpcResult::kTryAgainFailure, result_);
+}
+
 TEST_F(PaymentsClientTest,
        VirtualCardRiskBasedYellowPathResponseWithUnknownType) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
diff --git a/components/autofill/core/browser/payments/payments_requests/payments_request.cc b/components/autofill/core/browser/payments/payments_requests/payments_request.cc
index 23830df7..3924679 100644
--- a/components/autofill/core/browser/payments/payments_requests/payments_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/payments_request.cc
@@ -15,6 +15,18 @@
 
 PaymentsRequest::~PaymentsRequest() = default;
 
+bool PaymentsRequest::IsRetryableFailure(const std::string& error_code) {
+  // Returns true if the `error_code` denotes this is a retryable failure. This
+  // should be overridden in subclasses that have additional cases where the
+  // PaymentsRpcResult should be kTryAgainFailure if certain conditions are
+  // true. If this function is overridden in subclasses, the super class'
+  // implementation should still be called in addition to the subclass'
+  // implementation. An example of this is in the virtual card CVC
+  // authentication flow, we want to set result to kTryAgainFailure if a flow
+  // status is present in the response.
+  return base::EqualsCaseInsensitiveASCII(error_code, "internal");
+}
+
 base::Value::Dict PaymentsRequest::BuildRiskDictionary(
     const std::string& encoded_risk_data) {
   base::Value::Dict risk_data;
diff --git a/components/autofill/core/browser/payments/payments_requests/payments_request.h b/components/autofill/core/browser/payments/payments_requests/payments_request.h
index bb0a74e..e7d7921 100644
--- a/components/autofill/core/browser/payments/payments_requests/payments_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/payments_request.h
@@ -40,6 +40,11 @@
   // request this is.
   virtual void RespondToDelegate(AutofillClient::PaymentsRpcResult result) = 0;
 
+  // Returns true if the response indicates that we received an error that is
+  // retryable, false otherwise. If this returns true, the PaymentsRpcResult for
+  // the request will be kTryAgainFailure.
+  virtual bool IsRetryableFailure(const std::string& error_code);
+
  protected:
   // Shared helper function to build the risk data sent in the request.
   base::Value::Dict BuildRiskDictionary(const std::string& encoded_risk_data);
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
index d296f94..54c4391 100644
--- a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "components/autofill/core/browser/payments/autofill_error_dialog_context.h"
+#include "components/autofill/core/browser/payments/card_unmask_challenge_option.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
 
 namespace autofill {
@@ -399,6 +400,36 @@
   std::move(callback_).Run(result, response_details_);
 }
 
+bool UnmaskCardRequest::IsRetryableFailure(const std::string& error_code) {
+  // If the response error code indicates we are in the retryable failure case,
+  // return true.
+  if (PaymentsRequest::IsRetryableFailure(error_code))
+    return true;
+
+  // The additional case where this can be a retryable failure is only for
+  // virtual cards, so if we are not in the virtual card unmasking case at this
+  // point, return false.
+  if (request_details_.card.record_type() != CreditCard::VIRTUAL_CARD)
+    return false;
+
+  // If a challenge option was not selected, we are not in the virtual card
+  // unmasking case, so return false.
+  if (!request_details_.selected_challenge_option)
+    return false;
+
+  // The additional retryable failure functionality currently only applies to
+  // virtual card CVC auth, so if we did not select a CVC challenge option,
+  // return false.
+  if (request_details_.selected_challenge_option->type !=
+      CardUnmaskChallengeOptionType::kCvc) {
+    return false;
+  }
+
+  // If we are in the VCN CVC auth case and there is a flow status present
+  // return true, otherwise return false.
+  return !response_details_.flow_status.empty();
+}
+
 bool UnmaskCardRequest::IsAllCardInformationValidIncludingDcvv() {
   return !response_details_.real_pan.empty() &&
          !response_details_.expiration_month.empty() &&
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.h b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.h
index 0479973..706c96ba 100644
--- a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.h
@@ -30,6 +30,7 @@
   void ParseResponse(const base::Value& response) override;
   bool IsResponseComplete() override;
   void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override;
+  bool IsRetryableFailure(const std::string& error_code) override;
 
  private:
   // Returns whether the response contains all the information of the virtual
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_card_request_unittest.cc b/components/autofill/core/browser/payments/payments_requests/unmask_card_request_unittest.cc
index 468805e..890c2f0 100644
--- a/components/autofill/core/browser/payments/payments_requests/unmask_card_request_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_requests/unmask_card_request_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/callback_helpers.h"
+#include "base/json/json_reader.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -107,6 +108,49 @@
   }
 }
 
+TEST_P(VirtualCardUnmaskCardRequestTest, IsRetryableFailure) {
+  if (GetParam() == autofill::CardUnmaskChallengeOptionType::kCvc) {
+    // Test that `IsRetryableFailure()` returns true if the error code denotes
+    // that it is a retryable failure.
+    EXPECT_TRUE(GetRequest()->IsRetryableFailure("internal"));
+
+    // Test that `IsRetryableFailure()` returns true if a flow status is
+    // present.
+    absl::optional<base::Value> response = base::JSONReader::Read(
+        "{\"flow_status\": \"FLOW_STATUS_INCORRECT_ACCOUNT_SECURITY_CODE\"}");
+    ASSERT_TRUE(response);
+    GetRequest()->ParseResponse(*response);
+    EXPECT_TRUE(GetRequest()->IsRetryableFailure(""));
+
+    // The next several tests ensure that `IsRetryableFailure()` returns false
+    // if no flow status is present.
+    response = base::JSONReader::Read(
+        "{\"error\": {\"code\": \"ANYTHING_ELSE\", "
+        "\"api_error_reason\": \"virtual_card_temporary_error\"}, "
+        "\"decline_details\": {\"user_message_title\": "
+        "\"\", \"user_message_description\": "
+        "\"\"}}");
+    ASSERT_TRUE(response);
+    GetRequest()->ParseResponse(*response);
+    EXPECT_FALSE(GetRequest()->IsRetryableFailure(""));
+
+    response = base::JSONReader::Read(
+        "{\"error\": {\"code\": \"ANYTHING_ELSE\", "
+        "\"api_error_reason\": \"virtual_card_permanent_error\"}, "
+        "\"decline_details\": {\"user_message_title\": "
+        "\"\", \"user_message_description\": "
+        "\"\"}}");
+    ASSERT_TRUE(response);
+    GetRequest()->ParseResponse(*response);
+    EXPECT_FALSE(GetRequest()->IsRetryableFailure(""));
+
+    response = base::JSONReader::Read("{ \"pan\": \"1234\" }");
+    ASSERT_TRUE(response);
+    GetRequest()->ParseResponse(*response);
+    EXPECT_FALSE(GetRequest()->IsRetryableFailure(""));
+  }
+}
+
 INSTANTIATE_TEST_SUITE_P(
     ,
     VirtualCardUnmaskCardRequestTest,
diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc
index 308f486..ba5d832 100644
--- a/components/autofill/core/browser/test_autofill_client.cc
+++ b/components/autofill/core/browser/test_autofill_client.cc
@@ -386,6 +386,10 @@
   return log_manager_.get();
 }
 
+FormInteractionsFlowId TestAutofillClient::GetCurrentFormInteractionsFlowId() {
+  return {};
+}
+
 void TestAutofillClient::LoadRiskData(
     base::OnceCallback<void(const std::string&)> callback) {
   std::move(callback).Run("some risk data");
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h
index 4009fac..79a6f73e 100644
--- a/components/autofill/core/browser/test_autofill_client.h
+++ b/components/autofill/core/browser/test_autofill_client.h
@@ -197,6 +197,7 @@
   void ExecuteCommand(int id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
   LogManager* GetLogManager() const override;
+  FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
 
   // RiskDataLoader:
   void LoadRiskData(
diff --git a/components/autofill/core/browser/test_browser_autofill_manager.cc b/components/autofill/core/browser/test_browser_autofill_manager.cc
index 36c224c..a1e9b2a1 100644
--- a/components/autofill/core/browser/test_browser_autofill_manager.cc
+++ b/components/autofill/core/browser/test_browser_autofill_manager.cc
@@ -274,4 +274,8 @@
   call_parent_upload_form_data_ = value;
 }
 
+std::string TestBrowserAutofillManager::GetAddressFormFlowId() {
+  return address_form_interactions_flow_id_for_test()->AsLowercaseString();
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/test_browser_autofill_manager.h b/components/autofill/core/browser/test_browser_autofill_manager.h
index a2506c80..3e46b72 100644
--- a/components/autofill/core/browser/test_browser_autofill_manager.h
+++ b/components/autofill/core/browser/test_browser_autofill_manager.h
@@ -132,6 +132,8 @@
 
   using BrowserAutofillManager::pending_form_data;
 
+  std::string GetAddressFormFlowId();
+
  private:
   raw_ptr<TestAutofillClient> client_;
   raw_ptr<TestAutofillDriver> driver_;
diff --git a/components/autofill/core/common/BUILD.gn b/components/autofill/core/common/BUILD.gn
index cc4efd5..c2d89f11 100644
--- a/components/autofill/core/common/BUILD.gn
+++ b/components/autofill/core/common/BUILD.gn
@@ -43,6 +43,7 @@
     "form_field_data.h",
     "form_field_data_predictions.cc",
     "form_field_data_predictions.h",
+    "form_interactions_flow.h",
     "gaia_id_hash.cc",
     "gaia_id_hash.h",
     "html_field_types.cc",
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index abd84c5..90b9ab9 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -147,6 +147,16 @@
              "AutofillCreateDataForTest",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// FormStructure::RetrieveFromCache used to preserve an AutofillField's
+// is_autofilled from the cache of previously parsed forms. This makes little
+// sense because the renderer sends us the autofill state and has the most
+// recent information. Dropping the old behavior should not make any difference
+// but to be sure, this is gated by a finch experiment.
+// TODO(crbug.com/1373362) Cleanup when launched.
+BASE_FEATURE(kAutofillDontPreserveAutofillState,
+             "AutofillDontPreserveAutofillState",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // If enabled, checking whether a form has disappeared after an Ajax response is
 // delayed because subsequent Ajax responses may restore the form. If disabled,
 // the check happens right after a successful Ajax response.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index e5b3f084..cc274fae 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -61,6 +61,8 @@
 COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillDeferSubmissionClassificationAfterAjax);
 COMPONENT_EXPORT(AUTOFILL)
+BASE_DECLARE_FEATURE(kAutofillDontPreserveAutofillState);
+COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillEnableWithinFencedFrame);
 COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillCreateDataForTest);
 COMPONENT_EXPORT(AUTOFILL)
diff --git a/components/autofill/core/common/form_interactions_flow.h b/components/autofill/core/common/form_interactions_flow.h
new file mode 100644
index 0000000..f9be6a16
--- /dev/null
+++ b/components/autofill/core/common/form_interactions_flow.h
@@ -0,0 +1,25 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_FORM_INTERACTIONS_FLOW_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_FORM_INTERACTIONS_FLOW_H_
+
+#include "base/guid.h"
+#include "base/types/strong_alias.h"
+
+namespace autofill {
+
+// GUID linking together form submissions across navigations.
+using FormInteractionsFlowId =
+    base::StrongAlias<class FormInteractionsFlowIdTag, base::GUID>;
+
+// Counts of user interactions with forms.
+struct FormInteractionCounts {
+  int64_t form_element_user_modifications = 0;
+  int64_t autofill_fills = 0;
+};
+
+}  // namespace autofill
+
+#endif
diff --git a/components/autofill_assistant/browser/starter_heuristic_configs/finch_configs_unittest.cc b/components/autofill_assistant/browser/starter_heuristic_configs/finch_configs_unittest.cc
index 62edf4c6..d6072742 100644
--- a/components/autofill_assistant/browser/starter_heuristic_configs/finch_configs_unittest.cc
+++ b/components/autofill_assistant/browser/starter_heuristic_configs/finch_configs_unittest.cc
@@ -33,8 +33,7 @@
 }
 
 TEST(FinchConfigsTest, UrlHeuristicsAreDistinct) {
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-      features_and_params;
+  std::vector<base::test::FeatureRefAndParams> features_and_params;
   for (size_t i = 0; i < kHeuristicFeatures.size(); ++i) {
     features_and_params.push_back(
         {*kHeuristicFeatures[i],
diff --git a/components/autofill_assistant/content/common/autofill_assistant_types.mojom b/components/autofill_assistant/content/common/autofill_assistant_types.mojom
index 38b4d90..0f594cf 100644
--- a/components/autofill_assistant/content/common/autofill_assistant_types.mojom
+++ b/components/autofill_assistant/content/common/autofill_assistant_types.mojom
@@ -24,4 +24,7 @@
 struct NodeData {
   // The BackendNodeId of this element.
   int32 backend_node_id;
+
+  // Whether an override was used.
+  bool used_override;
 };
diff --git a/components/autofill_assistant/content/common/autofill_assistant_types_mojom_traits.cc b/components/autofill_assistant/content/common/autofill_assistant_types_mojom_traits.cc
index 07a9348..7aa16daa 100644
--- a/components/autofill_assistant/content/common/autofill_assistant_types_mojom_traits.cc
+++ b/components/autofill_assistant/content/common/autofill_assistant_types_mojom_traits.cc
@@ -14,6 +14,7 @@
     Read(autofill_assistant::mojom::NodeDataDataView data,
          autofill_assistant::NodeData* out) {
   out->backend_node_id = data.backend_node_id();
+  out->used_override = data.used_override();
   return true;
 }
 
diff --git a/components/autofill_assistant/content/common/autofill_assistant_types_mojom_traits.h b/components/autofill_assistant/content/common/autofill_assistant_types_mojom_traits.h
index 874b764..70b25a5 100644
--- a/components/autofill_assistant/content/common/autofill_assistant_types_mojom_traits.h
+++ b/components/autofill_assistant/content/common/autofill_assistant_types_mojom_traits.h
@@ -20,6 +20,10 @@
     return r.backend_node_id;
   }
 
+  static bool used_override(const autofill_assistant::NodeData& r) {
+    return r.used_override;
+  }
+
   static bool Read(autofill_assistant::mojom::NodeDataDataView data,
                    autofill_assistant::NodeData* out);
 };
diff --git a/components/autofill_assistant/content/common/node_data.h b/components/autofill_assistant/content/common/node_data.h
index b0cec1e..5ae2562 100644
--- a/components/autofill_assistant/content/common/node_data.h
+++ b/components/autofill_assistant/content/common/node_data.h
@@ -17,7 +17,8 @@
   NodeData& operator=(NodeData&&);
   ~NodeData();
 
-  int32_t backend_node_id;
+  int32_t backend_node_id = -1;
+  bool used_override = false;
 };
 
 }  // namespace autofill_assistant
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardImpressionTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardImpressionTest.java
index 885e0a1..2d98ef4 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardImpressionTest.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardImpressionTest.java
@@ -23,7 +23,7 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.test.util.BlankUiTestActivity;
@@ -112,7 +112,7 @@
 
     @Test
     @SmallTest
-    @FlakyTest(message = "https://crbug.com/1181859")
+    @DisabledTest(message = "https://crbug.com/1181859")
     public void testImpression_Card_Hide() throws TimeoutException {
         int initCount = mPromoSeenCallback.getCallCount();
         setUpPromoCard(false, true);
diff --git a/components/commerce/core/BUILD.gn b/components/commerce/core/BUILD.gn
index 7a58a757..3ac07b1 100644
--- a/components/commerce/core/BUILD.gn
+++ b/components/commerce/core/BUILD.gn
@@ -41,8 +41,11 @@
   deps = [
     ":commerce_heuristics_data",
     ":feature_list",
+    ":pref_names",
+    ":shopping_service_test_support",
     "//base",
     "//base/test:test_support",
+    "//components/prefs:test_support",
     "//testing/gtest",
     "//third_party/re2:re2",
   ]
diff --git a/components/commerce/core/android/java/src/org/chromium/components/commerce/core/ShoppingService.java b/components/commerce/core/android/java/src/org/chromium/components/commerce/core/ShoppingService.java
index dff6dc8..f2649e28 100644
--- a/components/commerce/core/android/java/src/org/chromium/components/commerce/core/ShoppingService.java
+++ b/components/commerce/core/android/java/src/org/chromium/components/commerce/core/ShoppingService.java
@@ -139,6 +139,13 @@
         ShoppingServiceJni.get().fetchPriceEmailPref(mNativeShoppingServiceAndroid, this);
     }
 
+    /** Schedules updates for all products that the user has saved in the bookmarks system. */
+    public void scheduleSavedProductUpdate() {
+        if (mNativeShoppingServiceAndroid == 0) return;
+
+        ShoppingServiceJni.get().scheduleSavedProductUpdate(mNativeShoppingServiceAndroid, this);
+    }
+
     @CalledByNative
     private void destroy() {
         mNativeShoppingServiceAndroid = 0;
@@ -185,5 +192,6 @@
         void getMerchantInfoForUrl(long nativeShoppingServiceAndroid, ShoppingService caller,
                 GURL url, MerchantInfoCallback callback);
         void fetchPriceEmailPref(long nativeShoppingServiceAndroid, ShoppingService caller);
+        void scheduleSavedProductUpdate(long nativeShoppingServiceAndroid, ShoppingService caller);
     }
 }
diff --git a/components/commerce/core/android/shopping_service_android.cc b/components/commerce/core/android/shopping_service_android.cc
index b93cacc..7417baa 100644
--- a/components/commerce/core/android/shopping_service_android.cc
+++ b/components/commerce/core/android/shopping_service_android.cc
@@ -127,4 +127,12 @@
   shopping_service_->FetchPriceEmailPref();
 }
 
+void ShoppingServiceAndroid::ScheduleSavedProductUpdate(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  CHECK(shopping_service_);
+
+  shopping_service_->ScheduleSavedProductUpdate();
+}
+
 }  // namespace commerce
diff --git a/components/commerce/core/android/shopping_service_android.h b/components/commerce/core/android/shopping_service_android.h
index 5771785..162dd8b 100644
--- a/components/commerce/core/android/shopping_service_android.h
+++ b/components/commerce/core/android/shopping_service_android.h
@@ -47,6 +47,9 @@
 
   void FetchPriceEmailPref(JNIEnv* env, const JavaParamRef<jobject>& obj);
 
+  void ScheduleSavedProductUpdate(JNIEnv* env,
+                                  const JavaParamRef<jobject>& obj);
+
   ScopedJavaGlobalRef<jobject> java_ref() { return java_ref_; }
 
  private:
diff --git a/components/commerce/core/bookmark_update_manager.cc b/components/commerce/core/bookmark_update_manager.cc
index 5c088369..8ad49e58 100644
--- a/components/commerce/core/bookmark_update_manager.cc
+++ b/components/commerce/core/bookmark_update_manager.cc
@@ -75,6 +75,12 @@
   pref_service_->SetTime(kShoppingListBookmarkLastUpdateTime,
                          last_update_time_);
 
+  // If something like the enterprise policy was turned off, simply block the
+  // update logic. In the future we can observe the preference and remove or
+  // re-add the scheduled update, but this is easier for now.
+  if (!IsShoppingListEnabled(pref_service_))
+    return;
+
   scheduled_task_ = nullptr;
   ScheduleUpdate();
 
diff --git a/components/commerce/core/bookmark_update_manager_unittest.cc b/components/commerce/core/bookmark_update_manager_unittest.cc
index 5500edd..c0c2936 100644
--- a/components/commerce/core/bookmark_update_manager_unittest.cc
+++ b/components/commerce/core/bookmark_update_manager_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
+#include "base/time/clock.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
 #include "components/bookmarks/test/test_bookmark_client.h"
@@ -47,6 +48,7 @@
     EXPECT_FALSE(IsUpdateScheduled());
 
     RegisterPrefs(pref_service_->registry());
+    pref_service_->SetTime(kShoppingListBookmarkLastUpdateTime, base::Time());
   }
 
   void TearDown() override { update_manager_->CancelUpdates(); }
@@ -60,7 +62,8 @@
   }
 
  protected:
-  base::test::TaskEnvironment task_environment_;
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   base::test::ScopedFeatureList test_features_;
   std::unique_ptr<MockShoppingService> shopping_service_;
   std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
@@ -120,10 +123,6 @@
   test_features_.InitWithFeatures(
       {kShoppingList, kCommerceAllowOnDemandBookmarkUpdates}, {});
 
-  // Set this up so the task runs immediately (last update was a year ago).
-  pref_service_->SetTime(kShoppingListBookmarkLastUpdateTime,
-                         base::Time::Now() - base::Days(365));
-
   const int64_t cluster_id = 123L;
   const bookmarks::BookmarkNode* bookmark = AddProductBookmark(
       bookmark_model_.get(), u"Title", GURL("http://example.com"), cluster_id);
@@ -139,6 +138,7 @@
       std::move(info_map));
 
   update_manager_->ScheduleUpdate();
+  task_environment_.FastForwardBy(base::Days(1));
   base::RunLoop().RunUntilIdle();
 
   auto meta = power_bookmarks::GetNodePowerBookmarkMeta(bookmark_model_.get(),
@@ -153,4 +153,40 @@
   EXPECT_TRUE(time_since_last < base::Minutes(1));
 }
 
+TEST_F(BookmarkUpdateManagerTest, RunScheduledTask_BlockedByPolicy) {
+  test_features_.InitWithFeatures(
+      {kShoppingList, kCommerceAllowOnDemandBookmarkUpdates}, {});
+
+  SetShoppingListEnterprisePolicyPref(pref_service_.get(), false);
+
+  const std::string title = "Title";
+  const int64_t cluster_id = 123L;
+  const bookmarks::BookmarkNode* bookmark = AddProductBookmark(
+      bookmark_model_.get(), u"Title", GURL("http://example.com"), cluster_id);
+
+  ProductInfo new_info;
+  new_info.title = "Updated Title";
+  new_info.product_cluster_id = cluster_id;
+
+  std::map<int64_t, ProductInfo> info_map;
+  info_map[bookmark->id()] = new_info;
+  shopping_service_->SetResponsesForGetUpdatedProductInfoForBookmarks(
+      std::move(info_map));
+
+  update_manager_->ScheduleUpdate();
+  task_environment_.FastForwardBy(base::Hours(6));
+  base::RunLoop().RunUntilIdle();
+
+  auto meta = power_bookmarks::GetNodePowerBookmarkMeta(bookmark_model_.get(),
+                                                        bookmark);
+
+  // The bookmark should not have been updated.
+  EXPECT_EQ(meta->shopping_specifics().title(), title);
+
+  // Even though the update was blocked, we're still scheduling the noop task.
+  // Make sure the previous time was recorded (recorded time is not default).
+  EXPECT_TRUE(pref_service_->GetTime(kShoppingListBookmarkLastUpdateTime) !=
+              base::Time());
+}
+
 }  // namespace commerce
diff --git a/components/commerce/core/commerce_feature_list.cc b/components/commerce/core/commerce_feature_list.cc
index b899bba9..a495b722 100644
--- a/components/commerce/core/commerce_feature_list.cc
+++ b/components/commerce/core/commerce_feature_list.cc
@@ -293,6 +293,11 @@
   return !pref || pref->GetBool();
 }
 
+bool IsShoppingListEnabled(PrefService* prefs) {
+  return base::FeatureList::IsEnabled(kShoppingList) &&
+         IsShoppingListAllowedForEnterprise(prefs);
+}
+
 #if !BUILDFLAG(IS_ANDROID)
 base::TimeDelta GetDiscountFetchDelay() {
   auto delay_from_component =
diff --git a/components/commerce/core/commerce_feature_list.h b/components/commerce/core/commerce_feature_list.h
index d90b850..773fe07 100644
--- a/components/commerce/core/commerce_feature_list.h
+++ b/components/commerce/core/commerce_feature_list.h
@@ -306,6 +306,9 @@
 bool isContextualConsentEnabled();
 // Check if the shopping list feature is allowed for enterprise.
 bool IsShoppingListAllowedForEnterprise(PrefService* prefs);
+// Check if the shopping list is enabled. This only checks the feature flag and
+// whether the feature is allowed by enterprise policy.
+bool IsShoppingListEnabled(PrefService* prefs);
 
 #if !BUILDFLAG(IS_ANDROID)
 // Get the time delay between discount fetches.
diff --git a/components/commerce/core/commerce_feature_list_unittest.cc b/components/commerce/core/commerce_feature_list_unittest.cc
index 46da4989..fca7ba3 100644
--- a/components/commerce/core/commerce_feature_list_unittest.cc
+++ b/components/commerce/core/commerce_feature_list_unittest.cc
@@ -8,6 +8,9 @@
 #include "build/buildflag.h"
 #include "components/commerce/core/commerce_heuristics_data.h"
 #include "components/commerce/core/commerce_heuristics_data_metrics_helper.h"
+#include "components/commerce/core/pref_names.h"
+#include "components/commerce/core/test_utils.h"
+#include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -146,4 +149,31 @@
   ASSERT_FALSE(
       commerce::IsNoDiscountMerchant(GURL("https://www.qux.com/corge")));
 }
+
+TEST_F(CommerceFeatureListTest, TestShoppingListEnabledWithPolicy) {
+  features_.InitAndEnableFeature(commerce::kShoppingList);
+
+  TestingPrefServiceSimple prefs;
+  commerce::RegisterPrefs(prefs.registry());
+
+  commerce::SetShoppingListEnterprisePolicyPref(&prefs, true);
+  ASSERT_TRUE(commerce::IsShoppingListEnabled(&prefs));
+
+  commerce::SetShoppingListEnterprisePolicyPref(&prefs, false);
+  ASSERT_FALSE(commerce::IsShoppingListEnabled(&prefs));
+}
+
+TEST_F(CommerceFeatureListTest,
+       TestShoppingListEnabledWithPolicy_FeatureDisabled) {
+  features_.InitAndDisableFeature(commerce::kShoppingList);
+
+  TestingPrefServiceSimple prefs;
+  commerce::RegisterPrefs(prefs.registry());
+
+  commerce::SetShoppingListEnterprisePolicyPref(&prefs, true);
+  ASSERT_FALSE(commerce::IsShoppingListEnabled(&prefs));
+
+  commerce::SetShoppingListEnterprisePolicyPref(&prefs, false);
+  ASSERT_FALSE(commerce::IsShoppingListEnabled(&prefs));
+}
 #endif  //! BUILDFLAG(IS_ANDROID)
diff --git a/components/commerce/core/test_utils.cc b/components/commerce/core/test_utils.cc
index ecc7c168..da95184 100644
--- a/components/commerce/core/test_utils.cc
+++ b/components/commerce/core/test_utils.cc
@@ -8,9 +8,11 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "components/commerce/core/pref_names.h"
 #include "components/power_bookmarks/core/power_bookmark_utils.h"
 #include "components/power_bookmarks/core/proto/power_bookmark_meta.pb.h"
 #include "components/power_bookmarks/core/proto/shopping_specifics.pb.h"
+#include "components/prefs/pref_service.h"
 #include "url/gurl.h"
 
 namespace commerce {
@@ -41,4 +43,8 @@
   return node;
 }
 
+void SetShoppingListEnterprisePolicyPref(PrefService* prefs, bool enabled) {
+  prefs->SetBoolean(kShoppingListEnabledPrefName, enabled);
+}
+
 }  // namespace commerce
diff --git a/components/commerce/core/test_utils.h b/components/commerce/core/test_utils.h
index ba511c6..4c66025b 100644
--- a/components/commerce/core/test_utils.h
+++ b/components/commerce/core/test_utils.h
@@ -8,6 +8,7 @@
 #include <string>
 
 class GURL;
+class PrefService;
 
 namespace bookmarks {
 class BookmarkModel;
@@ -27,6 +28,10 @@
     const int64_t price_micros = 0L,
     const std::string& currency_code = "usd");
 
+// Sets the state of the enterprise policy for the shopping list feature for
+// testing.
+void SetShoppingListEnterprisePolicyPref(PrefService* prefs, bool enabled);
+
 }  // namespace commerce
 
 #endif  // COMPONENTS_COMMERCE_CORE_TEST_UTILS_H_
diff --git a/components/commerce/core/webui/BUILD.gn b/components/commerce/core/webui/BUILD.gn
index 689cd002a..44f047c 100644
--- a/components/commerce/core/webui/BUILD.gn
+++ b/components/commerce/core/webui/BUILD.gn
@@ -15,6 +15,7 @@
     "//components/bookmarks/browser",
     "//components/commerce/core:feature_list",
     "//components/commerce/core:shopping_service",
+    "//components/feature_engagement/public",
     "//components/payments/core",
     "//components/power_bookmarks/core",
     "//components/prefs",
@@ -37,6 +38,7 @@
     "//components/bookmarks/test",
     "//components/commerce/core:feature_list",
     "//components/commerce/core:shopping_service_test_support",
+    "//components/feature_engagement/test:test_support",
     "//mojo/public/cpp/bindings",
     "//testing/gtest",
     "//url:url",
diff --git a/components/commerce/core/webui/DEPS b/components/commerce/core/webui/DEPS
index 841978b..6053e01 100644
--- a/components/commerce/core/webui/DEPS
+++ b/components/commerce/core/webui/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
   "+mojo/public/cpp/bindings",
   "+content/public/test",
+  "+components/feature_engagement/public",
+  "+components/feature_engagement/test",
 ]
diff --git a/components/commerce/core/webui/shopping_list_handler.cc b/components/commerce/core/webui/shopping_list_handler.cc
index 96be662..9b2c95a 100644
--- a/components/commerce/core/webui/shopping_list_handler.cc
+++ b/components/commerce/core/webui/shopping_list_handler.cc
@@ -13,10 +13,12 @@
 #include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/price_tracking_utils.h"
 #include "components/commerce/core/shopping_service.h"
+#include "components/feature_engagement/public/tracker.h"
 #include "components/payments/core/currency_formatter.h"
 #include "components/power_bookmarks/core/power_bookmark_utils.h"
 #include "components/power_bookmarks/core/proto/power_bookmark_meta.pb.h"
 #include "components/power_bookmarks/core/proto/shopping_specifics.pb.h"
+#include "components/prefs/pref_service.h"
 #include "components/url_formatter/elide_url.h"
 #include "url/gurl.h"
 
@@ -70,11 +72,15 @@
     mojo::PendingReceiver<shopping_list::mojom::ShoppingListHandler> receiver,
     bookmarks::BookmarkModel* bookmark_model,
     ShoppingService* shopping_service,
+    PrefService* prefs,
+    feature_engagement::Tracker* tracker,
     const std::string& locale)
     : remote_page_(std::move(remote_page)),
       receiver_(this, std::move(receiver)),
       bookmark_model_(bookmark_model),
       shopping_service_(shopping_service),
+      pref_service_(prefs),
+      tracker_(tracker),
       locale_(locale) {
   if (base::FeatureList::IsEnabled(kShoppingList)) {
     scoped_observation_.Observe(bookmark_model);
@@ -86,7 +92,7 @@
 
 void ShoppingListHandler::GetAllPriceTrackedBookmarkProductInfo(
     GetAllPriceTrackedBookmarkProductInfoCallback callback) {
-  if (!base::FeatureList::IsEnabled(kShoppingList)) {
+  if (!IsShoppingListEnabled(pref_service_)) {
     std::move(callback).Run({});
     return;
   }
@@ -96,6 +102,11 @@
   std::vector<BookmarkProductInfoPtr> info_list =
       BookmarkListToMojoList(*bookmark_model_, bookmarks, locale_);
 
+  if (!info_list.empty()) {
+    // Record usage for price tracking promo.
+    tracker_->NotifyEvent("price_tracking_side_panel_shown");
+  }
+
   std::move(callback).Run(std::move(info_list));
 }
 
diff --git a/components/commerce/core/webui/shopping_list_handler.h b/components/commerce/core/webui/shopping_list_handler.h
index 42a75ce..ee38aba9 100644
--- a/components/commerce/core/webui/shopping_list_handler.h
+++ b/components/commerce/core/webui/shopping_list_handler.h
@@ -17,10 +17,16 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
+class PrefService;
+
 namespace bookmarks {
 class BookmarkNode;
 }  // namespace bookmarks
 
+namespace feature_engagement {
+class Tracker;
+}  // namespace feature_engagement
+
 namespace commerce {
 
 class ShoppingService;
@@ -33,6 +39,8 @@
       mojo::PendingReceiver<shopping_list::mojom::ShoppingListHandler> receiver,
       bookmarks::BookmarkModel* bookmark_model,
       ShoppingService* shopping_service,
+      PrefService* prefs,
+      feature_engagement::Tracker* tracker,
       const std::string& locale);
   ShoppingListHandler(const ShoppingListHandler&) = delete;
   ShoppingListHandler& operator=(const ShoppingListHandler&) = delete;
@@ -62,12 +70,14 @@
 
   mojo::Remote<shopping_list::mojom::Page> remote_page_;
   mojo::Receiver<shopping_list::mojom::ShoppingListHandler> receiver_;
-  // The bookmark model and shopping service will outlive this implementation
-  // since it is a keyed service bound to the browser context (which in turn has
-  // the same lifecycle as the browser). The web UI that hosts this will be shut
-  // down prior to the rest of the browser.
+  // The bookmark model, shopping service and tracker will outlive this
+  // implementation since it is a keyed service bound to the browser context
+  // (which in turn has the same lifecycle as the browser). The web UI that
+  // hosts this will be shut down prior to the rest of the browser.
   raw_ptr<bookmarks::BookmarkModel> bookmark_model_;
   raw_ptr<ShoppingService> shopping_service_;
+  raw_ptr<PrefService> pref_service_;
+  raw_ptr<feature_engagement::Tracker> tracker_;
   const std::string locale_;
   // Automatically remove this observer from its host when destroyed.
   base::ScopedObservation<bookmarks::BookmarkModel,
diff --git a/components/commerce/core/webui/shopping_list_handler_unittest.cc b/components/commerce/core/webui/shopping_list_handler_unittest.cc
index 76b66fe..d1653ea 100644
--- a/components/commerce/core/webui/shopping_list_handler_unittest.cc
+++ b/components/commerce/core/webui/shopping_list_handler_unittest.cc
@@ -11,12 +11,16 @@
 #include "components/bookmarks/test/test_bookmark_client.h"
 #include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/mock_shopping_service.h"
+#include "components/commerce/core/mojom/shopping_list.mojom.h"
+#include "components/commerce/core/pref_names.h"
 #include "components/commerce/core/price_tracking_utils.h"
 #include "components/commerce/core/test_utils.h"
 #include "components/commerce/core/webui/shopping_list_handler.h"
+#include "components/feature_engagement/test/mock_tracker.h"
 #include "components/power_bookmarks/core/power_bookmark_utils.h"
 #include "components/power_bookmarks/core/proto/power_bookmark_meta.pb.h"
 #include "components/power_bookmarks/core/proto/shopping_specifics.pb.h"
+#include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -40,6 +44,22 @@
   MOCK_METHOD1(PriceUntrackedForBookmark, void(int64_t bookmark_id));
 };
 
+void GetEvaluationProductInfos(
+    base::OnceClosure closure,
+    std::vector<shopping_list::mojom::BookmarkProductInfoPtr> expected,
+    std::vector<shopping_list::mojom::BookmarkProductInfoPtr> found) {
+  ASSERT_EQ(expected.size(), found.size());
+  for (size_t i = 0; i < expected.size(); i++) {
+    ASSERT_EQ(expected[i]->bookmark_id, found[i]->bookmark_id);
+    ASSERT_EQ(expected[i]->info->current_price, found[i]->info->current_price);
+    ASSERT_EQ(expected[i]->info->domain, found[i]->info->domain);
+    ASSERT_EQ(expected[i]->info->title, found[i]->info->title);
+    ASSERT_EQ(expected[i]->info->image_url.spec(),
+              found[i]->info->image_url.spec());
+  }
+  std::move(closure).Run();
+}
+
 class ShoppingListHandlerTest : public testing::Test {
  public:
   ShoppingListHandlerTest() { features_.InitAndEnableFeature(kShoppingList); }
@@ -48,16 +68,22 @@
   void SetUp() override {
     bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel();
     shopping_service_ = std::make_unique<MockShoppingService>();
+    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
+    RegisterPrefs(pref_service_->registry());
+    SetShoppingListEnterprisePolicyPref(pref_service_.get(), true);
     handler_ = std::make_unique<commerce::ShoppingListHandler>(
         page_.BindAndGetRemote(),
         mojo::PendingReceiver<shopping_list::mojom::ShoppingListHandler>(),
-        bookmark_model_.get(), shopping_service_.get(), "en-us");
+        bookmark_model_.get(), shopping_service_.get(), pref_service_.get(),
+        &tracker_, "en-us");
   }
 
   MockPage page_;
   std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
   std::unique_ptr<MockShoppingService> shopping_service_;
   std::unique_ptr<commerce::ShoppingListHandler> handler_;
+  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
+  feature_engagement::test::MockTracker tracker_;
   base::test::TaskEnvironment task_environment_;
   base::test::ScopedFeatureList features_;
 };
@@ -179,5 +205,70 @@
   bookmark_model_->SetNodeMetaInfo(node, "test_key", "test_value");
 }
 
+TEST_F(ShoppingListHandlerTest, TestGetProductInfo_FeatureEnabled) {
+  base::RunLoop run_loop;
+  EXPECT_CALL(tracker_, NotifyEvent("price_tracking_side_panel_shown"));
+
+  const bookmarks::BookmarkNode* product = AddProductBookmark(
+      bookmark_model_.get(), u"product 1", GURL("http://example.com/1"), 123L,
+      true, 1230000, "usd");
+
+  std::vector<const bookmarks::BookmarkNode*> bookmark_list;
+  bookmark_list.push_back(product);
+  std::vector<shopping_list::mojom::BookmarkProductInfoPtr> mojo_list =
+      ShoppingListHandler::BookmarkListToMojoList(*bookmark_model_,
+                                                  bookmark_list, "en-us");
+
+  handler_->GetAllPriceTrackedBookmarkProductInfo(
+      base::BindOnce(&GetEvaluationProductInfos, run_loop.QuitClosure(),
+                     std::move(mojo_list)));
+}
+
+class ShoppingListHandlerFeatureDisableTest : public testing::Test {
+ public:
+  ShoppingListHandlerFeatureDisableTest() {
+    features_.InitAndDisableFeature(kShoppingList);
+  }
+
+ protected:
+  void SetUp() override {
+    bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel();
+    shopping_service_ = std::make_unique<MockShoppingService>();
+    handler_ = std::make_unique<commerce::ShoppingListHandler>(
+        page_.BindAndGetRemote(),
+        mojo::PendingReceiver<shopping_list::mojom::ShoppingListHandler>(),
+        bookmark_model_.get(), shopping_service_.get(), pref_service_.get(),
+        &tracker_, "en-us");
+  }
+
+  MockPage page_;
+  std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
+  std::unique_ptr<MockShoppingService> shopping_service_;
+  std::unique_ptr<commerce::ShoppingListHandler> handler_;
+  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
+  feature_engagement::test::MockTracker tracker_;
+  base::test::TaskEnvironment task_environment_;
+  base::test::ScopedFeatureList features_;
+};
+
+TEST_F(ShoppingListHandlerFeatureDisableTest,
+       TestGetProductInfo_FeatureDisabled) {
+  base::RunLoop run_loop;
+  EXPECT_CALL(tracker_, NotifyEvent("price_tracking_side_panel_shown"))
+      .Times(0);
+
+  const bookmarks::BookmarkNode* product = AddProductBookmark(
+      bookmark_model_.get(), u"product 1", GURL("http://example.com/1"), 123L,
+      true, 1230000, "usd");
+
+  std::vector<const bookmarks::BookmarkNode*> bookmark_list;
+  bookmark_list.push_back(product);
+  std::vector<shopping_list::mojom::BookmarkProductInfoPtr> empty_list;
+
+  handler_->GetAllPriceTrackedBookmarkProductInfo(
+      base::BindOnce(&GetEvaluationProductInfos, run_loop.QuitClosure(),
+                     std::move(empty_list)));
+}
+
 }  // namespace
 }  // namespace commerce
\ No newline at end of file
diff --git a/components/commerce_strings.grdp b/components/commerce_strings.grdp
index 651c3e7..edff876 100644
--- a/components/commerce_strings.grdp
+++ b/components/commerce_strings.grdp
@@ -107,7 +107,7 @@
       Get email alerts if the price drops on any site
     </message>
     <message name="IDS_BOOKMARK_STAR_DIALOG_TRACK_PRICE_DESCRIPTION_EMAIL_OFF" desc="The description text for the dialog that is shown when a user clicks the bookmark star icon on a product web page. We use this text only if the email notification is currently turned off by the user. It describes what will happen when price tracking is initiated.">
-      Track prices across multiple sites at the same time
+      Track prices across multiple sites
     </message>
 
     <message name="IDS_BOOKMARKS_MENU_TRACK_PRICE" desc="Text shown as a menu item when the user is on a product page and the product's price is not currently being tracked. User can click this button to track this product.">
diff --git a/components/commerce_strings_grdp/IDS_BOOKMARK_STAR_DIALOG_TRACK_PRICE_DESCRIPTION_EMAIL_OFF.png.sha1 b/components/commerce_strings_grdp/IDS_BOOKMARK_STAR_DIALOG_TRACK_PRICE_DESCRIPTION_EMAIL_OFF.png.sha1
index 8e24f9cf..91547de 100644
--- a/components/commerce_strings_grdp/IDS_BOOKMARK_STAR_DIALOG_TRACK_PRICE_DESCRIPTION_EMAIL_OFF.png.sha1
+++ b/components/commerce_strings_grdp/IDS_BOOKMARK_STAR_DIALOG_TRACK_PRICE_DESCRIPTION_EMAIL_OFF.png.sha1
@@ -1 +1 @@
-27657c14f2d434002b7d5eaf591294ccdfd7fa75
\ No newline at end of file
+585b6eb407f9cf5ecf3257133c2212d690c53de0
\ No newline at end of file
diff --git a/components/content_settings/core/common/cookie_settings_base_unittest.cc b/components/content_settings/core/common/cookie_settings_base_unittest.cc
index 4bd31680..4b2b06a7 100644
--- a/components/content_settings/core/common/cookie_settings_base_unittest.cc
+++ b/components/content_settings/core/common/cookie_settings_base_unittest.cc
@@ -232,7 +232,7 @@
     : public testing::TestWithParam<std::tuple<bool, bool, bool>> {
  public:
   CookieSettingsBaseStorageAccessAPITest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled;
+    std::vector<base::test::FeatureRefAndParams> enabled;
     std::vector<base::test::FeatureRef> disabled;
     if (IsStorageAccessAPIEnabled()) {
       enabled.push_back({net::features::kStorageAccessAPI,
diff --git a/components/desks_storage/core/local_desk_data_manager.cc b/components/desks_storage/core/local_desk_data_manager.cc
index 455a64c6..389df95 100644
--- a/components/desks_storage/core/local_desk_data_manager.cc
+++ b/components/desks_storage/core/local_desk_data_manager.cc
@@ -308,6 +308,13 @@
   std::vector<std::unique_ptr<ash::DeskTemplate>> entry;
   auto& saved_desks = saved_desks_list_[desk_type];
   auto existing_it = saved_desks.find(uuid);
+
+  // The deletion is successful if the entry does not exist.
+  if (existing_it == saved_desks.end()) {
+    std::move(callback).Run(DeleteEntryStatus::kOk);
+    return;
+  }
+
   entry.push_back(std::move(existing_it->second));
   saved_desks_list_[desk_type].erase(existing_it);
 
diff --git a/components/desks_storage/core/local_desk_data_manager_unittests.cc b/components/desks_storage/core/local_desk_data_manager_unittests.cc
index 300ab66..7a72846c1 100644
--- a/components/desks_storage/core/local_desk_data_manager_unittests.cc
+++ b/components/desks_storage/core/local_desk_data_manager_unittests.cc
@@ -921,4 +921,24 @@
   task_environment_.RunUntilIdle();
 }
 
+TEST_F(LocalDeskDataManagerTest, DeleteSameEntryAgain) {
+  data_manager_->AddOrUpdateEntry(std::move(sample_desk_template_one_),
+                                  base::BindOnce(&VerifyEntryAddedCorrectly));
+
+  data_manager_->DeleteEntry(
+      GetTestUuid(TestUuidId(1)),
+      base::BindLambdaForTesting([&](DeskModel::DeleteEntryStatus status) {
+        EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk);
+      }));
+
+  data_manager_->DeleteEntry(
+      GetTestUuid(TestUuidId(1)),
+      base::BindLambdaForTesting([&](DeskModel::DeleteEntryStatus status) {
+        EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk);
+      }));
+
+  VerifyAllEntries(0ul, "Delete one entry");
+  task_environment_.RunUntilIdle();
+}
+
 }  // namespace desks_storage
diff --git a/components/embedder_support/android/util/android_stream_reader_url_loader.cc b/components/embedder_support/android/util/android_stream_reader_url_loader.cc
index b180b88f..2cba6b08 100644
--- a/components/embedder_support/android/util/android_stream_reader_url_loader.cc
+++ b/components/embedder_support/android/util/android_stream_reader_url_loader.cc
@@ -36,6 +36,12 @@
 const char kHTTPOkText[] = "OK";
 const char kHTTPNotFoundText[] = "Not Found";
 
+// If InputStream.available() returns less than this, kMinReadSize will be used
+// instead.
+const int kMinAvailableValueToIgnore = 16;
+
+// The smallest amount we'll try to read at a time.
+const int kMinReadSize = 1024;
 }  // namespace
 
 namespace {
@@ -94,7 +100,12 @@
       // 0. In that case we still want to do a blocking read until there's data
       // or EOF.
       if (input_stream_->BytesAvailable(&available) && available > 0) {
-        // Make sure a bad app doesn't lead to reading past the buffer.
+        // Some implementations might return 1 even when there's more data. To
+        // avoid slowdowns in that case use a minimum of 1KB to read.
+        if (available < kMinAvailableValueToIgnore)
+          available = kMinReadSize;
+
+        // Make sure a we don't read past the buffer size.
         buffer_size = std::min(available, buffer_size);
       } else {
         // `buffer_size' could be large since it comes from the size of the data
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index d5b4a9fc..63c5e6e2 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -9,6 +9,7 @@
 #include "ash/constants/ash_constants.h"
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/frame/non_client_frame_view_ash.h"
+#include "ash/metrics/login_unlock_throughput_recorder.h"
 #include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/rounded_corner_utils.h"
 #include "ash/public/cpp/shelf_types.h"
@@ -652,6 +653,9 @@
   DCHECK(!widget_);
   restore_session_id_.emplace(restore_session_id);
   restore_window_id_.emplace(restore_window_id);
+  ash::LoginUnlockThroughputRecorder* throughput_recorder =
+      ash::Shell::Get()->login_unlock_throughput_recorder();
+  throughput_recorder->OnRestoredWindowCreated(restore_window_id);
 }
 
 void ShellSurfaceBase::SetRestoreInfoWithWindowIdSource(
@@ -1808,6 +1812,17 @@
       needs_layout_on_show_ = false;
     }
 
+    if (restore_window_id_.has_value()) {
+      ash::LoginUnlockThroughputRecorder* throughput_recorder =
+          ash::Shell::Get()->login_unlock_throughput_recorder();
+
+      aura::Window* root_window = host_window()->GetRootWindow();
+      if (root_window) {
+        ui::Compositor* compositor = root_window->layer()->GetCompositor();
+        throughput_recorder->OnBeforeRestoredWindowShown(
+            restore_window_id_.value(), compositor);
+      }
+    }
     widget_->Show();
     if (has_grab_)
       StartCapture();
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index 3fb9fdf..15922da 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -576,8 +576,7 @@
     make_current_ = std::make_unique<ui::ScopedMakeCurrent>(gl_context_.get(),
                                                             gl_surface_.get());
 
-    if (display->ext->b_EGL_EXT_image_flush_external ||
-        display->ext->b_EGL_ARM_implicit_external_sync) {
+    if (display->ext->b_EGL_ARM_implicit_external_sync) {
       egl_sync_type_ = EGL_SYNC_FENCE_KHR;
     }
     if (display->ext->b_EGL_ANDROID_native_fence_sync) {
diff --git a/components/exo/wm_helper_chromeos_unittest.cc b/components/exo/wm_helper_chromeos_unittest.cc
index db82454..77fca7f 100644
--- a/components/exo/wm_helper_chromeos_unittest.cc
+++ b/components/exo/wm_helper_chromeos_unittest.cc
@@ -89,7 +89,7 @@
   EXPECT_EQ(vsync_timing_manager.throttled_interval(), base::TimeDelta());
 
   // Both windows are to be throttled, vsync timing will be adjusted.
-  base::TimeDelta throttled_interval = base::Hertz(ftc->throttled_fps());
+  base::TimeDelta throttled_interval = ftc->current_throttled_frame_interval();
   EXPECT_CALL(observer,
               OnUpdateVSyncParameters(testing::_, throttled_interval));
   ftc->StartThrottling({arc_window_1.get(), arc_window_2.get()});
diff --git a/components/favicon/core/favicon_database.cc b/components/favicon/core/favicon_database.cc
index 73856d6..ba70f3e7 100644
--- a/components/favicon/core/favicon_database.cc
+++ b/components/favicon/core/favicon_database.cc
@@ -389,7 +389,7 @@
       "JOIN icon_mapping ON (icon_mapping.icon_id = favicon_bitmaps.icon_id) "
       "WHERE (favicon_bitmaps.last_requested > 0 AND "
       "       favicon_bitmaps.last_requested < ?)"));
-  old_icons.BindInt64(0, threshold.ToDeltaSinceWindowsEpoch().InMicroseconds());
+  old_icons.BindTime(0, threshold);
 
   std::map<favicon_base::FaviconID, IconMappingsForExpiry> icon_mappings;
 
@@ -445,8 +445,7 @@
     FaviconBitmap favicon_bitmap;
     favicon_bitmap.bitmap_id = statement.ColumnInt64(0);
     favicon_bitmap.icon_id = icon_id;
-    favicon_bitmap.last_updated = base::Time::FromDeltaSinceWindowsEpoch(
-        base::Microseconds(statement.ColumnInt64(1)));
+    favicon_bitmap.last_updated = statement.ColumnTime(1);
     std::vector<uint8_t> bitmap_data_blob;
     statement.ColumnBlobAsVector(2, &bitmap_data_blob);
     if (!bitmap_data_blob.empty()) {
@@ -455,8 +454,7 @@
     }
     favicon_bitmap.pixel_size =
         gfx::Size(statement.ColumnInt(3), statement.ColumnInt(4));
-    favicon_bitmap.last_requested = base::Time::FromDeltaSinceWindowsEpoch(
-        base::Microseconds(statement.ColumnInt64(5)));
+    favicon_bitmap.last_requested = statement.ColumnTime(5);
     favicon_bitmaps->push_back(favicon_bitmap);
   }
   return result;
@@ -479,8 +477,7 @@
     return false;
 
   if (last_updated) {
-    *last_updated = base::Time::FromDeltaSinceWindowsEpoch(
-        base::Microseconds(statement.ColumnInt64(0)));
+    *last_updated = statement.ColumnTime(0);
   }
 
   if (png_icon_data) {
@@ -495,8 +492,7 @@
   }
 
   if (last_requested) {
-    *last_requested = base::Time::FromDeltaSinceWindowsEpoch(
-        base::Microseconds(statement.ColumnInt64(4)));
+    *last_requested = statement.ColumnTime(4);
   }
 
   return true;
@@ -525,16 +521,12 @@
   // On-visit bitmaps:
   //  - keep track of last_updated: last write time is used for expiration;
   //  - always have last_requested==0: no need to keep track of last read time.
-  statement.BindInt64(2, type == ON_VISIT
-                             ? time.ToDeltaSinceWindowsEpoch().InMicroseconds()
-                             : 0);
+  type == ON_VISIT ? statement.BindTime(2, time) : statement.BindInt64(2, 0);
   // On-demand bitmaps:
   //  - always have last_updated==0: last write time is not stored as they are
   //    always expired and thus ready to be replaced by ON_VISIT icons;
   //  - keep track of last_requested: last read time is used for cache eviction.
-  statement.BindInt64(3, type == ON_DEMAND
-                             ? time.ToDeltaSinceWindowsEpoch().InMicroseconds()
-                             : 0);
+  type == ON_DEMAND ? statement.BindTime(3, time) : statement.BindInt64(3, 0);
 
   statement.BindInt(4, pixel_size.width());
   statement.BindInt(5, pixel_size.height());
@@ -561,7 +553,7 @@
   } else {
     statement.BindNull(0);
   }
-  statement.BindInt64(1, time.ToDeltaSinceWindowsEpoch().InMicroseconds());
+  statement.BindTime(1, time);
   statement.BindInt64(2, 0);
   statement.BindInt64(3, bitmap_id);
 
@@ -578,7 +570,7 @@
       db_.GetCachedStatement(SQL_FROM_HERE,
                              "UPDATE favicon_bitmaps SET last_updated=?, "
                              "last_requested=? WHERE id=?"));
-  statement.BindInt64(0, time.ToDeltaSinceWindowsEpoch().InMicroseconds());
+  statement.BindTime(0, time);
   statement.BindInt64(1, 0);
   statement.BindInt64(2, bitmap_id);
   return statement.Run();
@@ -592,8 +584,8 @@
       db_.GetCachedStatement(SQL_FROM_HERE,
                              "UPDATE favicon_bitmaps SET last_updated=0 "
                              "WHERE last_updated>=? AND last_updated<?"));
-  statement.BindInt64(0, begin.ToDeltaSinceWindowsEpoch().InMicroseconds());
-  statement.BindInt64(1, end.ToDeltaSinceWindowsEpoch().InMicroseconds());
+  statement.BindTime(0, begin);
+  statement.BindTime(1, end);
   return statement.Run();
 }
 
@@ -617,10 +609,9 @@
         SQL_FROM_HERE,
         "UPDATE favicon_bitmaps SET last_requested=? WHERE icon_id=? AND "
         "last_requested>0 AND last_requested<=?"));
-    statement.BindInt64(0, time.ToDeltaSinceWindowsEpoch().InMicroseconds());
+    statement.BindTime(0, time);
     statement.BindInt64(1, icon_id);
-    statement.BindInt64(2,
-                        max_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
+    statement.BindTime(2, max_time);
     if (!statement.Run())
       return false;
   }
@@ -659,8 +650,7 @@
     return false;
 
   if (last_updated) {
-    *last_updated = base::Time::FromDeltaSinceWindowsEpoch(
-        base::Microseconds(statement.ColumnInt64(0)));
+    *last_updated = statement.ColumnTime(0);
   }
   return true;
 }
@@ -909,7 +899,7 @@
                                                   "WHERE last_updated < ? "
                                                   "ORDER BY last_updated ASC "
                                                   "LIMIT ?"));
-  statement.BindInt64(0, time.ToDeltaSinceWindowsEpoch().InMicroseconds());
+  statement.BindTime(0, time);
   statement.BindInt64(
       1, max_count == 0 ? std::numeric_limits<int64_t>::max() : max_count);
   std::vector<favicon_base::FaviconID> ids;
diff --git a/components/feature_engagement/public/event_constants.cc b/components/feature_engagement/public/event_constants.cc
index 76b95ca..3fea018 100644
--- a/components/feature_engagement/public/event_constants.cc
+++ b/components/feature_engagement/public/event_constants.cc
@@ -61,6 +61,7 @@
 const char kIncognitoTabOpened[] = "incognito_tab_opened";
 const char kClearedBrowsingData[] = "cleared_browsing_data";
 const char kViewedReadingList[] = "viewed_reading_list";
+const char kViewedWhatsNew[] = "viewed_whats_new";
 const char kTriggeredTranslateInfobar[] = "triggered_translate_infobar";
 const char kBottomToolbarOpened[] = "bottom_toolbar_opened";
 const char kDiscoverFeedLoaded[] = "discover_feed_loaded";
diff --git a/components/feature_engagement/public/event_constants.h b/components/feature_engagement/public/event_constants.h
index b8aa196..f4a6834 100644
--- a/components/feature_engagement/public/event_constants.h
+++ b/components/feature_engagement/public/event_constants.h
@@ -101,6 +101,9 @@
 // The user has viewed their reading list.
 extern const char kViewedReadingList[];
 
+// The user has viewed What's New.
+extern const char kViewedWhatsNew[];
+
 // The user has triggered the translate infobar manually.
 extern const char kTriggeredTranslateInfobar[];
 
diff --git a/components/feature_engagement/public/feature_configurations.cc b/components/feature_engagement/public/feature_configurations.cc
index 9fe5c87..de343bb7 100644
--- a/components/feature_engagement/public/feature_configurations.cc
+++ b/components/feature_engagement/public/feature_configurations.cc
@@ -185,6 +185,19 @@
     return config;
   }
 
+  if (kIPHPriceTrackingInSidePanelFeature.name == feature->name) {
+    absl::optional<FeatureConfig> config = FeatureConfig();
+    config->valid = true;
+    config->availability = Comparator(ANY, 0);
+    config->session_rate = Comparator(ANY, 0);
+    // Show the promo once a year if the price tracking IPH was not triggered.
+    config->trigger = EventConfig("iph_price_tracking_side_panel_trigger",
+                                  Comparator(EQUAL, 0), 360, 360);
+    config->used = EventConfig("price_tracking_side_panel_shown",
+                               Comparator(EQUAL, 0), 360, 360);
+    return config;
+  }
+
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS)
 
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index 384de60a..99a9eda 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -103,6 +103,9 @@
 BASE_FEATURE(kIPHWebUiHelpBubbleTestFeature,
              "IPH_WebUiHelpBubbleTest",
              base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kIPHPriceTrackingInSidePanelFeature,
+             "IPH_PriceTrackingInSidePanel",
+             base::FEATURE_ENABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
 
@@ -382,6 +385,9 @@
 BASE_FEATURE(kIPHBadgedReadingListFeature,
              "IPH_BadgedReadingList",
              base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kIPHBadgedWhatsNewFeature,
+             "IPH_BadgedWhatsNew",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kIPHReadingListMessagesFeature,
              "IPH_ReadingListMessages",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h
index ebebebe1..ad22881 100644
--- a/components/feature_engagement/public/feature_constants.h
+++ b/components/feature_engagement/public/feature_constants.h
@@ -59,6 +59,7 @@
 BASE_DECLARE_FEATURE(kIPHDesktopPwaInstallFeature);
 BASE_DECLARE_FEATURE(kIPHProfileSwitchFeature);
 BASE_DECLARE_FEATURE(kIPHWebUiHelpBubbleTestFeature);
+BASE_DECLARE_FEATURE(kIPHPriceTrackingInSidePanelFeature);
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
 
@@ -169,6 +170,7 @@
 BASE_DECLARE_FEATURE(kIPHNewTabTipFeature);
 BASE_DECLARE_FEATURE(kIPHNewIncognitoTabTipFeature);
 BASE_DECLARE_FEATURE(kIPHBadgedReadingListFeature);
+BASE_DECLARE_FEATURE(kIPHBadgedWhatsNewFeature);
 BASE_DECLARE_FEATURE(kIPHReadingListMessagesFeature);
 BASE_DECLARE_FEATURE(kIPHBadgedTranslateManualTriggerFeature);
 BASE_DECLARE_FEATURE(kIPHDiscoverFeedHeaderFeature);
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc
index 7188143..717c67d 100644
--- a/components/feature_engagement/public/feature_list.cc
+++ b/components/feature_engagement/public/feature_list.cc
@@ -109,6 +109,7 @@
     &kIPHNewTabTipFeature,
     &kIPHNewIncognitoTabTipFeature,
     &kIPHBadgedReadingListFeature,
+    &kIPHBadgedWhatsNewFeature,
     &kIPHReadingListMessagesFeature,
     &kIPHBadgedTranslateManualTriggerFeature,
     &kIPHDiscoverFeedHeaderFeature,
@@ -144,6 +145,7 @@
     &kIPHDesktopSharedHighlightingFeature,
     &kIPHIntentChipFeature,
     &kIPHWebUiHelpBubbleTestFeature,
+    &kIPHPriceTrackingInSidePanelFeature,
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
 
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h
index 727f703..c88745d 100644
--- a/components/feature_engagement/public/feature_list.h
+++ b/components/feature_engagement/public/feature_list.h
@@ -201,6 +201,7 @@
 DEFINE_VARIATION_PARAM(kIPHNewTabTipFeature, "IPH_NewTabTip");
 DEFINE_VARIATION_PARAM(kIPHNewIncognitoTabTipFeature, "IPH_NewIncognitoTabTip");
 DEFINE_VARIATION_PARAM(kIPHBadgedReadingListFeature, "IPH_BadgedReadingList");
+DEFINE_VARIATION_PARAM(kIPHBadgedWhatsNewFeature, "IPH_BadgedWhatsNew");
 DEFINE_VARIATION_PARAM(kIPHReadingListMessagesFeature,
                        "IPH_ReadingListMessages");
 DEFINE_VARIATION_PARAM(kIPHBadgedTranslateManualTriggerFeature,
@@ -254,6 +255,8 @@
 DEFINE_VARIATION_PARAM(kIPHIntentChipFeature, "IPH_IntentChip");
 DEFINE_VARIATION_PARAM(kIPHWebUiHelpBubbleTestFeature,
                        "IPH_WebUiHelpBubbleTest");
+DEFINE_VARIATION_PARAM(kIPHPriceTrackingInSidePanelFeature,
+                       "IPH_PriceTrackingInSidePanel");
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
 
@@ -352,6 +355,7 @@
         VARIATION_ENTRY(kIPHNewTabTipFeature),
         VARIATION_ENTRY(kIPHNewIncognitoTabTipFeature),
         VARIATION_ENTRY(kIPHBadgedReadingListFeature),
+        VARIATION_ENTRY(kIPHBadgedWhatsNewFeature),
         VARIATION_ENTRY(kIPHReadingListMessagesFeature),
         VARIATION_ENTRY(kIPHBadgedTranslateManualTriggerFeature),
         VARIATION_ENTRY(kIPHDiscoverFeedHeaderFeature),
@@ -387,6 +391,7 @@
         VARIATION_ENTRY(kIPHDesktopSharedHighlightingFeature),
         VARIATION_ENTRY(kIPHIntentChipFeature),
         VARIATION_ENTRY(kIPHWebUiHelpBubbleTestFeature),
+        VARIATION_ENTRY(kIPHPriceTrackingInSidePanelFeature),
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
 
diff --git a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
index 4d926a9e..7bd7164 100644
--- a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
@@ -306,6 +306,104 @@
   EXPECT_EQ("dummyresponse", receiver.GetResult()->response_bytes);
 }
 
+TEST_F(FeedStreamTestForAllStreamTypes,
+       ReportContentLifetimeMetricsViaOnLoadStream) {
+  base::HistogramTester histograms;
+  {
+    RefreshResponseData injected_response;
+    injected_response.model_update_request = MakeTypicalInitialModelState();
+    feedstore::Metadata::StreamMetadata::ContentLifetime content_lifetime;
+    content_lifetime.set_stale_age_ms(10);
+    content_lifetime.set_invalid_age_ms(11);
+    injected_response.content_lifetime = std::move(content_lifetime);
+    response_translator_.InjectResponse(std::move(injected_response));
+
+    TestForYouSurface surface(stream_.get());
+    WaitForIdleTaskQueue();
+    ASSERT_TRUE(response_translator_.InjectedResponseConsumed());
+  }
+  ASSERT_TRUE(network_.query_request_sent);
+
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.StaleAgeIsPresent", true, 1);
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.InvalidAgeIsPresent", true, 1);
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.StaleAge", 10, 1);
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.InvalidAge", 11, 1);
+}
+
+TEST_F(FeedStreamTestForAllStreamTypes,
+       DoNotReportContentLifetimeMetricsWhenStreamMetadataNotPopulated) {
+  base::HistogramTester histograms;
+  {
+    RefreshResponseData injected_response;
+    injected_response.model_update_request = MakeTypicalInitialModelState();
+    response_translator_.InjectResponse(std::move(injected_response));
+
+    TestForYouSurface surface(stream_.get());
+    WaitForIdleTaskQueue();
+    ASSERT_TRUE(response_translator_.InjectedResponseConsumed());
+  }
+  ASSERT_TRUE(network_.query_request_sent);
+
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.StaleAgeIsPresent", false, 1);
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.InvalidAgeIsPresent", false, 1);
+}
+
+TEST_F(FeedStreamTestForAllStreamTypes,
+       DoNotReportContentLifetimeStaleAgeWhenNotPopulated) {
+  base::HistogramTester histograms;
+  {
+    RefreshResponseData injected_response;
+    injected_response.model_update_request = MakeTypicalInitialModelState();
+    feedstore::Metadata::StreamMetadata::ContentLifetime content_lifetime;
+    content_lifetime.set_invalid_age_ms(11);
+    injected_response.content_lifetime = std::move(content_lifetime);
+    response_translator_.InjectResponse(std::move(injected_response));
+
+    TestForYouSurface surface(stream_.get());
+    WaitForIdleTaskQueue();
+    ASSERT_TRUE(response_translator_.InjectedResponseConsumed());
+  }
+  ASSERT_TRUE(network_.query_request_sent);
+
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.StaleAgeIsPresent", false, 1);
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.InvalidAgeIsPresent", true, 1);
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.InvalidAge", 11, 1);
+}
+
+TEST_F(FeedStreamTestForAllStreamTypes,
+       DoNotReportContentLifetimeInvalidAgeWhenNotPopulated) {
+  base::HistogramTester histograms;
+  {
+    RefreshResponseData injected_response;
+    injected_response.model_update_request = MakeTypicalInitialModelState();
+    feedstore::Metadata::StreamMetadata::ContentLifetime content_lifetime;
+    content_lifetime.set_stale_age_ms(10);
+    injected_response.content_lifetime = std::move(content_lifetime);
+    response_translator_.InjectResponse(std::move(injected_response));
+
+    TestForYouSurface surface(stream_.get());
+    WaitForIdleTaskQueue();
+    ASSERT_TRUE(response_translator_.InjectedResponseConsumed());
+  }
+  ASSERT_TRUE(network_.query_request_sent);
+
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.StaleAgeIsPresent", true, 1);
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.InvalidAgeIsPresent", false, 1);
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ContentLifetime.StaleAge", 10, 1);
+}
+
 TEST_P(FeedStreamTestForAllStreamTypes, LoadFromNetwork) {
   {
     WaitForIdleTaskQueue();
diff --git a/components/feed/core/v2/api_test/feed_api_test.cc b/components/feed/core/v2/api_test/feed_api_test.cc
index 17920b64..aa9aaa1 100644
--- a/components/feed/core/v2/api_test/feed_api_test.cc
+++ b/components/feed/core/v2/api_test/feed_api_test.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "components/feed/core/v2/api_test/feed_api_test.h"
+#include <string>
 #include "base/time/time.h"
 #include "components/feed/core/proto/v2/wire/reliability_logging_enums.pb.h"
 #include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
@@ -777,22 +778,16 @@
 }
 void TestMetricsReporter::OnLoadStream(
     const StreamType& stream_type,
-    LoadStreamStatus load_from_store_status,
-    LoadStreamStatus final_status,
-    bool is_initial_load,
-    bool loaded_new_content_from_network,
-    base::TimeDelta stored_content_age,
+    const LoadStreamResultSummary& result_summary,
     const ContentStats& content_stats,
-    ContentOrder content_order,
-    std::unique_ptr<LoadLatencyTimes> latencies) {
-  load_stream_from_store_status = load_from_store_status;
-  load_stream_status = final_status;
-  LOG(INFO) << "OnLoadStream: " << final_status
-            << " (store status: " << load_from_store_status << ")";
-  MetricsReporter::OnLoadStream(
-      stream_type, load_from_store_status, final_status, is_initial_load,
-      loaded_new_content_from_network, stored_content_age, content_stats,
-      content_order, std::move(latencies));
+    std::unique_ptr<LoadLatencyTimes> load_latencies) {
+  load_stream_from_store_status = result_summary.load_from_store_status;
+  load_stream_status = result_summary.final_status;
+  LOG(INFO) << "OnLoadStream: " << result_summary.final_status
+            << " (store status: " << result_summary.load_from_store_status
+            << ")";
+  MetricsReporter::OnLoadStream(stream_type, result_summary, content_stats,
+                                std::move(load_latencies));
 }
 void TestMetricsReporter::OnLoadMoreBegin(const StreamType& stream_type,
                                           SurfaceId surface_id) {
diff --git a/components/feed/core/v2/api_test/feed_api_test.h b/components/feed/core/v2/api_test/feed_api_test.h
index 855c6a40..5b44756 100644
--- a/components/feed/core/v2/api_test/feed_api_test.h
+++ b/components/feed/core/v2/api_test/feed_api_test.h
@@ -414,14 +414,9 @@
                           int index_in_stream,
                           int stream_slice_count) override;
   void OnLoadStream(const StreamType& stream_type,
-                    LoadStreamStatus load_from_store_status,
-                    LoadStreamStatus final_status,
-                    bool is_initial_load,
-                    bool loaded_new_content_from_network,
-                    base::TimeDelta stored_content_age,
+                    const LoadStreamResultSummary& result_summary,
                     const ContentStats& content_stats,
-                    ContentOrder content_order,
-                    std::unique_ptr<LoadLatencyTimes> latencies) override;
+                    std::unique_ptr<LoadLatencyTimes> load_latencies) override;
   void OnLoadMoreBegin(const StreamType& stream_type,
                        SurfaceId surface_id) override;
   void OnLoadMore(const StreamType& stream_type,
diff --git a/components/feed/core/v2/feed_stream.cc b/components/feed/core/v2/feed_stream.cc
index ea2b878df..38e882f 100644
--- a/components/feed/core/v2/feed_stream.cc
+++ b/components/feed/core/v2/feed_stream.cc
@@ -14,6 +14,7 @@
 #include "base/containers/cxx20_erase.h"
 #include "base/feature_list.h"
 #include "base/location.h"
+#include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/notreached.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -307,12 +308,26 @@
   if (stream.model)
     content_stats = stream.model->GetContentStats();
 
-  metrics_reporter_->OnLoadStream(
-      stream.type, result.load_from_store_status, result.final_status,
+  // stream_metadata is an optional because in some scenarios StreamLoadComplete
+  // is called bypassing the task queue. In this case WaitForStoreInitialize
+  // task is not completed first and the metadata is not populated. Thus, we
+  // dont need to track content_lifetime.
+  absl::optional<feedstore::Metadata::StreamMetadata> stream_metadata;
+  if (metadata_populated_) {
+    feedstore::Metadata metadata = GetMetadata();
+    stream_metadata =
+        feedstore::MetadataForStream(metadata, result.stream_type);
+  }
+  const MetricsReporter::LoadStreamResultSummary result_summary = {
+      result.load_from_store_status,
+      result.final_status,
       result.load_type == LoadType::kInitialLoad,
-      result.loaded_new_content_from_network, result.stored_content_age,
-      content_stats, GetContentOrder(result.stream_type),
-      std::move(result.latencies));
+      result.loaded_new_content_from_network,
+      result.stored_content_age,
+      GetContentOrder(result.stream_type),
+      stream_metadata};
+  metrics_reporter_->OnLoadStream(stream.type, result_summary, content_stats,
+                                  std::move(result.latencies));
 
   stream.model_loading_in_progress = false;
   stream.surface_updater->LoadStreamComplete(
diff --git a/components/feed/core/v2/metrics_reporter.cc b/components/feed/core/v2/metrics_reporter.cc
index bcce2634..c0dc933 100644
--- a/components/feed/core/v2/metrics_reporter.cc
+++ b/components/feed/core/v2/metrics_reporter.cc
@@ -5,6 +5,7 @@
 
 #include <algorithm>
 #include <cmath>
+#include <memory>
 #include <ratio>
 #include <string>
 
@@ -140,6 +141,35 @@
   }
 }
 
+void ReportContentLifetimeStaleAge(base::TimeDelta content_lifetime_stale_age) {
+  if (content_lifetime_stale_age.is_zero()) {
+    base::UmaHistogramBoolean(
+        "ContentSuggestions.Feed.ContentLifetime.StaleAgeIsPresent", false);
+    return;
+  }
+  base::UmaHistogramBoolean(
+      "ContentSuggestions.Feed.ContentLifetime.StaleAgeIsPresent", true);
+  base::UmaHistogramCustomTimes(
+      "ContentSuggestions.Feed.ContentLifetime.StaleAge",
+      content_lifetime_stale_age, base::Minutes(1), base::Days(7),
+      /*buckets=*/50);
+}
+
+void ReportContentLifetimeInvalidAge(
+    base::TimeDelta content_lifetime_invalid_age) {
+  if (content_lifetime_invalid_age.is_zero()) {
+    base::UmaHistogramBoolean(
+        "ContentSuggestions.Feed.ContentLifetime.InvalidAgeIsPresent", false);
+    return;
+  }
+  base::UmaHistogramBoolean(
+      "ContentSuggestions.Feed.ContentLifetime.InvalidAgeIsPresent", true);
+  base::UmaHistogramCustomTimes(
+      "ContentSuggestions.Feed.ContentLifetime.InvalidAge",
+      content_lifetime_invalid_age, base::Minutes(1), base::Days(7),
+      /*buckets=*/50);
+}
+
 base::StringPiece NetworkRequestTypeUmaName(NetworkRequestType type) {
   switch (type) {
     case NetworkRequestType::kFeedQuery:
@@ -260,6 +290,24 @@
 }
 
 }  // namespace
+MetricsReporter::LoadStreamResultSummary::LoadStreamResultSummary() = default;
+MetricsReporter::LoadStreamResultSummary::LoadStreamResultSummary(
+    LoadStreamStatus load_from_store_status,
+    LoadStreamStatus final_status,
+    bool is_initial_load,
+    bool loaded_new_content_from_network,
+    base::TimeDelta stored_content_age,
+    ContentOrder content_order,
+    absl::optional<feedstore::Metadata::StreamMetadata> stream_metadata) {
+  this->load_from_store_status = load_from_store_status;
+  this->final_status = final_status;
+  this->is_initial_load = is_initial_load;
+  this->loaded_new_content_from_network = loaded_new_content_from_network;
+  this->stored_content_age = stored_content_age;
+  this->content_order = content_order;
+  this->stream_metadata = stream_metadata;
+}
+MetricsReporter::LoadStreamResultSummary::~LoadStreamResultSummary() = default;
 
 MetricsReporter::SurfaceWaiting::SurfaceWaiting() = default;
 MetricsReporter::SurfaceWaiting::SurfaceWaiting(
@@ -831,14 +879,19 @@
 
 void MetricsReporter::OnLoadStream(
     const StreamType& stream_type,
-    LoadStreamStatus load_from_store_status,
-    LoadStreamStatus final_status,
-    bool is_initial_load,
-    bool loaded_new_content_from_network,
-    base::TimeDelta stored_content_age,
+    const LoadStreamResultSummary& result_summary,
     const ContentStats& content_stats,
-    ContentOrder content_order,
     std::unique_ptr<LoadLatencyTimes> load_latencies) {
+  LoadStreamStatus load_from_store_status =
+      result_summary.load_from_store_status;
+  LoadStreamStatus final_status = result_summary.final_status;
+  bool is_initial_load = result_summary.is_initial_load;
+  bool loaded_new_content_from_network =
+      result_summary.loaded_new_content_from_network;
+  base::TimeDelta stored_content_age = result_summary.stored_content_age;
+  absl::optional<feedstore::Metadata::StreamMetadata> stream_metadata =
+      result_summary.stream_metadata;
+  ContentOrder content_order = result_summary.content_order;
   VVLOG << "OnLoadStream load_from_store_status=" << load_from_store_status
         << " final_status=" << final_status;
   load_latencies_ = std::move(load_latencies);
@@ -848,6 +901,19 @@
       base::StrCat({"ContentSuggestions.", HistogramReplacement(stream_type),
                     "LoadStreamStatus.", load_type_name}),
       final_status);
+
+  if (stream_metadata.has_value()) {
+    feedstore::Metadata::StreamMetadata::ContentLifetime content_lifetime =
+        stream_metadata->content_lifetime();
+    base::TimeDelta content_lifetime_stale_age_delta =
+        base::Milliseconds(content_lifetime.stale_age_ms());
+    ReportContentLifetimeStaleAge(content_lifetime_stale_age_delta);
+
+    base::TimeDelta content_lifetime_invalid_age_delta =
+        base::Milliseconds(content_lifetime.invalid_age_ms());
+    ReportContentLifetimeInvalidAge(content_lifetime_invalid_age_delta);
+  }
+
   if (!is_initial_load)
     return;
 
@@ -970,7 +1036,7 @@
   base::UmaHistogramCustomTimes(
       "ContentSuggestions.Feed.Scheduler.TimeSinceLastFetchOnClear",
       time_since_last_clear, base::Seconds(1), base::Days(7),
-      /*bucket_count=*/50);
+      /*buckets=*/50);
 }
 
 void MetricsReporter::ReportPersistentDataIfDayIsDone() {
diff --git a/components/feed/core/v2/metrics_reporter.h b/components/feed/core/v2/metrics_reporter.h
index 3a206e8..0a0d17a 100644
--- a/components/feed/core/v2/metrics_reporter.h
+++ b/components/feed/core/v2/metrics_reporter.h
@@ -11,6 +11,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "components/feed/core/proto/v2/store.pb.h"
 #include "components/feed/core/v2/enums.h"
 #include "components/feed/core/v2/feed_network.h"
 #include "components/feed/core/v2/public/common_enums.h"
@@ -99,14 +100,28 @@
 
   // Stream events.
 
+  struct LoadStreamResultSummary {
+    LoadStreamResultSummary();
+    LoadStreamResultSummary(
+        LoadStreamStatus load_from_store_status,
+        LoadStreamStatus final_status,
+        bool is_initial_load,
+        bool loaded_new_content_from_network,
+        base::TimeDelta stored_content_age,
+        ContentOrder content_order,
+        absl::optional<feedstore::Metadata::StreamMetadata> stream_metadata);
+    ~LoadStreamResultSummary();
+    LoadStreamStatus load_from_store_status;
+    LoadStreamStatus final_status;
+    bool is_initial_load;
+    bool loaded_new_content_from_network;
+    base::TimeDelta stored_content_age;
+    ContentOrder content_order;
+    absl::optional<feedstore::Metadata::StreamMetadata> stream_metadata;
+  };
   virtual void OnLoadStream(const StreamType& stream_type,
-                            LoadStreamStatus load_from_store_status,
-                            LoadStreamStatus final_status,
-                            bool is_initial_load,
-                            bool loaded_new_content_from_network,
-                            base::TimeDelta stored_content_age,
+                            const LoadStreamResultSummary& result_summary,
                             const ContentStats& content_stats,
-                            ContentOrder content_order,
                             std::unique_ptr<LoadLatencyTimes> load_latencies);
   virtual void OnBackgroundRefresh(const StreamType& stream_type,
                                    LoadStreamStatus final_status);
diff --git a/components/feed/core/v2/metrics_reporter_unittest.cc b/components/feed/core/v2/metrics_reporter_unittest.cc
index 11280e67..24a583f 100644
--- a/components/feed/core/v2/metrics_reporter_unittest.cc
+++ b/components/feed/core/v2/metrics_reporter_unittest.cc
@@ -39,6 +39,15 @@
     /*card_count=*/12,
     /*total_content_frame_size_bytes=*/100 * 1024,
     /*shared_state_size=*/200 * 1024};
+const MetricsReporter::LoadStreamResultSummary result_summary =
+    MetricsReporter::LoadStreamResultSummary{
+        LoadStreamStatus::kDataInStoreIsStale,
+        LoadStreamStatus::kLoadedFromNetwork,
+        /*is_initial_load=*/true,
+        /*loaded_new_content_from_network=*/true,
+        /*stored_content_age=*/base::Days(5),
+        ContentOrder::kGrouped,
+        feedstore::Metadata::StreamMetadata()};
 
 class MetricsReporterTest : public testing::Test, MetricsReporter::Delegate {
  protected:
@@ -371,14 +380,8 @@
 }
 
 TEST_F(MetricsReporterTest, ReportsLoadStreamStatus) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kForYou), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadedFromNetwork,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/true,
-      /*stored_content_age=*/base::Days(5), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-
+  reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.LoadStreamStatus.Initial",
       LoadStreamStatus::kLoadedFromNetwork, 1);
@@ -395,14 +398,18 @@
 }
 
 TEST_F(MetricsReporterTest, ReportsLoadStreamStatusWhenDisabled) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kForYou), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadNotAllowedDisabled,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/false,
-      /*stored_content_age=*/base::Days(5), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-
+  feedstore::Metadata::StreamMetadata stream_metadata;
+  MetricsReporter::LoadStreamResultSummary result_summary_ =
+      MetricsReporter::LoadStreamResultSummary{
+          LoadStreamStatus::kDataInStoreIsStale,
+          LoadStreamStatus::kLoadNotAllowedDisabled,
+          /*is_initial_load=*/true,
+          /*loaded_new_content_from_network=*/false,
+          /*stored_content_age=*/base::Days(5),
+          ContentOrder::kGrouped,
+          stream_metadata};
+  reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary_,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.LoadStreamStatus.Initial",
       LoadStreamStatus::kLoadNotAllowedDisabled, 1);
@@ -412,14 +419,8 @@
 }
 
 TEST_F(MetricsReporterTest, WebFeed_ReportsLoadStreamStatus) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kFollowing), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadedFromNetwork,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/true,
-      /*stored_content_age=*/base::Days(5), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-
+  reporter_->OnLoadStream(StreamType(StreamKind::kFollowing), result_summary,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.LoadStreamStatus.Initial",
       LoadStreamStatus::kLoadedFromNetwork, 1);
@@ -446,14 +447,18 @@
 }
 
 TEST_F(MetricsReporterTest, WebFeed_ReportsLoadStreamStatus_ReverseChron) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kFollowing), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadedFromNetwork,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/true,
-      /*stored_content_age=*/base::Days(5), kContentStats,
-      ContentOrder::kReverseChron, std::make_unique<LoadLatencyTimes>());
-
+  feedstore::Metadata::StreamMetadata stream_metadata;
+  MetricsReporter::LoadStreamResultSummary result_summary_ =
+      MetricsReporter::LoadStreamResultSummary{
+          LoadStreamStatus::kDataInStoreIsStale,
+          LoadStreamStatus::kLoadedFromNetwork,
+          /*is_initial_load=*/true,
+          /*loaded_new_content_from_network=*/true,
+          /*stored_content_age=*/base::Days(5),
+          ContentOrder::kReverseChron,
+          stream_metadata};
+  reporter_->OnLoadStream(StreamType(StreamKind::kFollowing), result_summary_,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.LoadedCardCount",
       kContentStats.card_count, 1);
@@ -465,40 +470,42 @@
 }
 
 TEST_F(MetricsReporterTest, WebFeed_ReportsNoContentShown) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kFollowing), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadedFromNetwork,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/true,
-      /*stored_content_age=*/base::Days(5), ContentStats(),
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-
+  reporter_->OnLoadStream(StreamType(StreamKind::kFollowing), result_summary,
+                          ContentStats(), std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.FollowCount.NoContentShown",
       kSubscriptionCount, 1);
 }
 
 TEST_F(MetricsReporterTest, OnLoadStreamDoesNotReportLoadedCardCountOnFailure) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kForYou), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kDataInStoreIsExpired,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/false,
-      /*stored_content_age=*/base::Days(5), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-
+  feedstore::Metadata::StreamMetadata stream_metadata;
+  MetricsReporter::LoadStreamResultSummary result_summary_ =
+      MetricsReporter::LoadStreamResultSummary{
+          LoadStreamStatus::kDataInStoreIsStale,
+          LoadStreamStatus::kDataInStoreIsExpired,
+          /*is_initial_load=*/true,
+          /*loaded_new_content_from_network=*/false,
+          /*stored_content_age=*/base::Days(5),
+          ContentOrder::kGrouped,
+          stream_metadata};
+  reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary_,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectTotalCount("ContentSuggestions.Feed.LoadedCardCount", 0);
 }
 
 TEST_F(MetricsReporterTest, ReportsLoadStreamStatusForManualRefresh) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kForYou), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadedFromNetwork,
-      /*is_initial_load=*/false,
-      /*loaded_new_content_from_network=*/true,
-      /*stored_content_age=*/base::Days(5), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-
+  feedstore::Metadata::StreamMetadata stream_metadata;
+  MetricsReporter::LoadStreamResultSummary result_summary_ =
+      MetricsReporter::LoadStreamResultSummary{
+          LoadStreamStatus::kDataInStoreIsStale,
+          LoadStreamStatus::kLoadedFromNetwork,
+          /*is_initial_load=*/false,
+          /*loaded_new_content_from_network=*/true,
+          /*stored_content_age=*/base::Days(5),
+          ContentOrder::kGrouped,
+          stream_metadata};
+  reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary_,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.LoadStreamStatus.Initial",
       LoadStreamStatus::kLoadedFromNetwork, 0);
@@ -511,14 +518,18 @@
 }
 
 TEST_F(MetricsReporterTest, ReportsLoadStreamStatusIgnoresNoStatusFromStore) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kForYou), LoadStreamStatus::kNoStatus,
-      LoadStreamStatus::kLoadedFromNetwork,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/true,
-      /*stored_content_age=*/base::TimeDelta(), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-
+  feedstore::Metadata::StreamMetadata stream_metadata;
+  MetricsReporter::LoadStreamResultSummary result_summary_ =
+      MetricsReporter::LoadStreamResultSummary{
+          LoadStreamStatus::kNoStatus,
+          LoadStreamStatus::kLoadedFromNetwork,
+          /*is_initial_load=*/true,
+          /*loaded_new_content_from_network=*/true,
+          /*stored_content_age=*/base::TimeDelta(),
+          ContentOrder::kGrouped,
+          stream_metadata};
+  reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary_,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.LoadStreamStatus.Initial",
       LoadStreamStatus::kLoadedFromNetwork, 1);
@@ -530,47 +541,53 @@
 }
 
 TEST_F(MetricsReporterTest, ReportsContentAgeBlockingRefresh) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kForYou), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadedFromNetwork,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/true,
-      /*stored_content_age=*/base::Days(5), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-
+  reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectUniqueTimeSample(
       "ContentSuggestions.Feed.ContentAgeOnLoad.BlockingRefresh", base::Days(5),
       1);
 }
 
 TEST_F(MetricsReporterTest, ReportsContentAgeNoRefresh) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kForYou), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadedFromStore,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/false,
-      /*stored_content_age=*/base::Days(5), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-
+  feedstore::Metadata::StreamMetadata stream_metadata;
+  MetricsReporter::LoadStreamResultSummary result_summary_ =
+      MetricsReporter::LoadStreamResultSummary{
+          LoadStreamStatus::kDataInStoreIsStale,
+          LoadStreamStatus::kLoadedFromNetwork,
+          /*is_initial_load=*/true,
+          /*loaded_new_content_from_network=*/false,
+          /*stored_content_age=*/base::Days(5),
+          ContentOrder::kGrouped,
+          stream_metadata};
+  reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary_,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectUniqueTimeSample(
       "ContentSuggestions.Feed.ContentAgeOnLoad.NotRefreshed", base::Days(5),
       1);
 }
 
 TEST_F(MetricsReporterTest, DoNotReportContentAgeWhenNotPositive) {
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kForYou), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadedFromStore, /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/false,
-      /*stored_content_age=*/-base::Seconds(1), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
-  reporter_->OnLoadStream(
-      StreamType(StreamKind::kForYou), LoadStreamStatus::kDataInStoreIsStale,
-      LoadStreamStatus::kLoadedFromStore,
-      /*is_initial_load=*/true,
-      /*loaded_new_content_from_network=*/false,
-      /*stored_content_age=*/base::TimeDelta(), kContentStats,
-      ContentOrder::kGrouped, std::make_unique<LoadLatencyTimes>());
+  feedstore::Metadata::StreamMetadata stream_metadata;
+  MetricsReporter::LoadStreamResultSummary result_summary_ =
+      MetricsReporter::LoadStreamResultSummary{
+          LoadStreamStatus::kDataInStoreIsStale,
+          LoadStreamStatus::kLoadedFromStore,
+          /*is_initial_load=*/true,
+          /*loaded_new_content_from_network=*/false,
+          /*stored_content_age=*/-base::Seconds(1),
+          ContentOrder::kGrouped,
+          stream_metadata};
+  reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary_,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
+  result_summary_ = {LoadStreamStatus::kDataInStoreIsStale,
+                     LoadStreamStatus::kLoadedFromStore,
+                     /*is_initial_load=*/true,
+                     /*loaded_new_content_from_network=*/false,
+                     /*stored_content_age=*/base::TimeDelta(),
+                     ContentOrder::kGrouped,
+                     stream_metadata};
+  reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary_,
+                          kContentStats, std::make_unique<LoadLatencyTimes>());
   histogram_.ExpectTotalCount(
       "ContentSuggestions.Feed.ContentAgeOnLoad.NotRefreshed", 0);
   histogram_.ExpectTotalCount(
@@ -578,19 +595,24 @@
 }
 
 TEST_F(MetricsReporterTest, ReportsLoadStepLatenciesOnFirstView) {
+  feedstore::Metadata::StreamMetadata stream_metadata;
   {
     auto latencies = std::make_unique<LoadLatencyTimes>();
     task_environment_.FastForwardBy(base::Milliseconds(150));
     latencies->StepComplete(LoadLatencyTimes::kLoadFromStore);
     task_environment_.FastForwardBy(base::Milliseconds(50));
     latencies->StepComplete(LoadLatencyTimes::kUploadActions);
-    reporter_->OnLoadStream(
-        StreamType(StreamKind::kForYou), LoadStreamStatus::kNoStatus,
-        LoadStreamStatus::kLoadedFromNetwork,
-        /*is_initial_load=*/true,
-        /*loaded_new_content_from_network=*/true,
-        /*stored_content_age=*/base::TimeDelta(), kContentStats,
-        ContentOrder::kGrouped, std::move(latencies));
+    MetricsReporter::LoadStreamResultSummary result_summary_ =
+        MetricsReporter::LoadStreamResultSummary{
+            LoadStreamStatus::kNoStatus,
+            LoadStreamStatus::kLoadedFromNetwork,
+            /*is_initial_load=*/true,
+            /*loaded_new_content_from_network=*/true,
+            /*stored_content_age=*/base::TimeDelta(),
+            ContentOrder::kGrouped,
+            stream_metadata};
+    reporter_->OnLoadStream(StreamType(StreamKind::kForYou), result_summary_,
+                            kContentStats, std::move(latencies));
   }
   task_environment_.FastForwardBy(base::Milliseconds(300));
   reporter_->FeedViewed(kSurfaceId);
diff --git a/components/feed/core/v2/public/stream_type.h b/components/feed/core/v2/public/stream_type.h
index 934b51f..d8977ce 100644
--- a/components/feed/core/v2/public/stream_type.h
+++ b/components/feed/core/v2/public/stream_type.h
@@ -19,8 +19,8 @@
  public:
   StreamType() = default;
   virtual ~StreamType() = default;
-  explicit StreamType(StreamKind k, std::string s = "")
-      : kind_(k), web_feed_id_(s) {}
+  explicit StreamType(StreamKind k, std::string s = std::string())
+      : kind_(k), web_feed_id_(std::move(s)) {}
   bool operator<(const StreamType& rhs) const {
     if (kind_ == rhs.kind_) {
       if (kind_ != StreamKind::kChannel)
diff --git a/components/google/core/common/google_util.cc b/components/google/core/common/google_util.cc
index 51f1a81..ce786898 100644
--- a/components/google/core/common/google_util.cc
+++ b/components/google/core/common/google_util.cc
@@ -294,6 +294,7 @@
       ".googlevideo.com",
       ".gstatic.com",
       ".litepages.googlezip.net",
+      ".youtubekids.com",
       ".ytimg.com",
   };
   const std::string host = url.host();
diff --git a/components/history/core/browser/url_database.cc b/components/history/core/browser/url_database.cc
index 43dc8d3..5b25ef7 100644
--- a/components/history/core/browser/url_database.cc
+++ b/components/history/core/browser/url_database.cc
@@ -56,7 +56,7 @@
   i->set_title(s.ColumnString16(2));
   i->set_visit_count(s.ColumnInt(3));
   i->set_typed_count(s.ColumnInt(4));
-  i->set_last_visit(base::Time::FromInternalValue(s.ColumnInt64(5)));
+  i->set_last_visit(s.ColumnTime(5));
   i->set_hidden(s.ColumnInt(6) != 0);
 }
 
@@ -147,7 +147,7 @@
   statement.BindString16(0, info.title());
   statement.BindInt(1, info.visit_count());
   statement.BindInt(2, info.typed_count());
-  statement.BindInt64(3, info.last_visit().ToInternalValue());
+  statement.BindTime(3, info.last_visit());
   statement.BindInt(4, info.hidden() ? 1 : 0);
   statement.BindInt64(5, url_id);
 
@@ -180,7 +180,7 @@
   statement.BindString16(1, info.title());
   statement.BindInt(2, info.visit_count());
   statement.BindInt(3, info.typed_count());
-  statement.BindInt64(4, info.last_visit().ToInternalValue());
+  statement.BindTime(4, info.last_visit());
   statement.BindInt(5, info.hidden() ? 1 : 0);
 
   if (!statement.Run()) {
@@ -235,7 +235,7 @@
   statement.BindString16(2, info.title());
   statement.BindInt(3, info.visit_count());
   statement.BindInt(4, info.typed_count());
-  statement.BindInt64(5, info.last_visit().ToInternalValue());
+  statement.BindTime(5, info.last_visit());
   statement.BindInt(6, info.hidden() ? 1 : 0);
 
   return statement.Run();
@@ -577,7 +577,7 @@
     KeywordID keyword_id,
     const std::u16string& prefix,
     int max_count,
-    KeywordSearchTermVisitList* visits) {
+    std::vector<std::unique_ptr<KeywordSearchTermVisit>>* visits) {
   // NOTE: the keyword_id can be zero if on first run the user does a query
   // before the TemplateURLService has finished loading. As the chances of this
   // occurring are small, we ignore it.
@@ -612,8 +612,7 @@
     visit->term = statement.ColumnString16(0);
     visit->normalized_term = statement.ColumnString16(1);
     visit->visit_count = statement.ColumnInt(2);
-    visit->last_visit_time =
-        base::Time::FromInternalValue(statement.ColumnInt64(3));
+    visit->last_visit_time = statement.ColumnTime(3);
     visits->push_back(std::move(visit));
   }
 }
@@ -661,7 +660,7 @@
 void URLDatabase::GetMostRecentKeywordSearchTerms(
     KeywordID keyword_id,
     base::Time age_threshold,
-    KeywordSearchTermVisitList* visits) {
+    std::vector<std::unique_ptr<KeywordSearchTermVisit>>* visits) {
   // NOTE: the keyword_id can be zero if on first run the user does a query
   // before the TemplateURLService has finished loading. As the chances of this
   // occurring are small, we ignore it.
@@ -716,8 +715,7 @@
     visit->normalized_term = statement.ColumnString16(0);
     visit->term = statement.ColumnString16(1);
     visit->visit_count = statement.ColumnInt(2);
-    visit->last_visit_time =
-        base::Time::FromInternalValue(statement.ColumnInt64(3));
+    visit->last_visit_time = statement.ColumnTime(3);
     visits->push_back(std::move(visit));
   }
 }
diff --git a/components/history/core/browser/visitsegment_database.cc b/components/history/core/browser/visitsegment_database.cc
index 19ec6f6..6f49194 100644
--- a/components/history/core/browser/visitsegment_database.cc
+++ b/components/history/core/browser/visitsegment_database.cc
@@ -171,7 +171,7 @@
   sql::Statement select(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT id, visit_count FROM segment_usage "
       "WHERE time_slot = ? AND segment_id = ?"));
-  select.BindInt64(0, t.ToInternalValue());
+  select.BindTime(0, t);
   select.BindInt64(1, segment_id);
 
   if (!select.is_valid())
@@ -189,7 +189,7 @@
         "INSERT INTO segment_usage "
         "(segment_id, time_slot, visit_count) VALUES (?, ?, ?)"));
     insert.BindInt64(0, segment_id);
-    insert.BindInt64(1, t.ToInternalValue());
+    insert.BindTime(1, t);
     insert.BindInt64(2, static_cast<int64_t>(amount));
 
     return insert.Run();
@@ -223,8 +223,7 @@
       previous_segment_id = segment_id;
     }
 
-    base::Time timeslot =
-        base::Time::FromInternalValue(statement.ColumnInt64(1));
+    base::Time timeslot = statement.ColumnTime(1);
     int visit_count = statement.ColumnInt(2);
     int days_ago = (now - timeslot).InDays();
 
@@ -357,7 +356,7 @@
                                  "segment_usage WHERE segment_id = ?"));
   select.BindInt64(0, from_segment_id);
   while (select.Step()) {
-    base::Time ts = base::Time::FromInternalValue(select.ColumnInt64(0));
+    base::Time ts = select.ColumnTime(0);
     int64_t visit_count = select.ColumnInt64(1);
     IncreaseSegmentVisitCount(to_segment_id, ts, visit_count);
   }
diff --git a/components/media_message_center/media_notification_view_impl.cc b/components/media_message_center/media_notification_view_impl.cc
index 5220c46..2ec54895 100644
--- a/components/media_message_center/media_notification_view_impl.cc
+++ b/components/media_message_center/media_notification_view_impl.cc
@@ -367,7 +367,7 @@
           IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACCESSIBLE_NAME));
 
   if (!accessible_name_.empty())
-    node_data->SetName(accessible_name_);
+    node_data->SetNameChecked(accessible_name_);
 }
 
 void MediaNotificationViewImpl::UpdateWithMediaSessionInfo(
diff --git a/components/media_message_center/media_notification_view_modern_impl.cc b/components/media_message_center/media_notification_view_modern_impl.cc
index 4c9ec004..a08af6ca 100644
--- a/components/media_message_center/media_notification_view_modern_impl.cc
+++ b/components/media_message_center/media_notification_view_modern_impl.cc
@@ -500,7 +500,7 @@
           IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACCESSIBLE_NAME));
 
   if (!accessible_name_.empty())
-    node_data->SetName(accessible_name_);
+    node_data->SetNameChecked(accessible_name_);
 }
 
 void MediaNotificationViewModernImpl::UpdateWithMediaSessionInfo(
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 1779ea0..5b01767 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -300,6 +300,10 @@
     deps += [ ":vector_icons" ]
   }
 
+  if (!is_android) {
+    deps += [ "//components/keep_alive_registry" ]
+  }
+
   if (!is_ios) {
     sources += [
       "actions/history_clusters_action.cc",
diff --git a/components/omnibox/browser/DEPS b/components/omnibox/browser/DEPS
index bd83b20..fd6597e 100644
--- a/components/omnibox/browser/DEPS
+++ b/components/omnibox/browser/DEPS
@@ -14,6 +14,7 @@
   "+components/history/core/browser",
   "+components/history/core/test",
   "+components/history_clusters/core",
+  "+components/keep_alive_registry",
   "+components/keyed_service/content",
   "+components/keyed_service/core",
   "+components/metrics",
diff --git a/components/omnibox/browser/base_search_provider.cc b/components/omnibox/browser/base_search_provider.cc
index d116683..6f7260c 100644
--- a/components/omnibox/browser/base_search_provider.cc
+++ b/components/omnibox/browser/base_search_provider.cc
@@ -20,6 +20,7 @@
 #include "components/omnibox/browser/autocomplete_provider_listener.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/suggestion_answer.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/variations/net/variations_http_headers.h"
@@ -528,7 +529,36 @@
                      match.search_terms_args->additional_query_params));
   const std::pair<MatchMap::iterator, bool> i(
       map->insert(std::make_pair(match_key, match)));
-  if (!i.second) {
+  if (i.second) {
+    auto& added_match = i.first->second;
+    // If the newly added match has non-empty additional query params and
+    // another match with the same search terms and a unique non-empty
+    // additional query params is already present in the map, proactively set
+    // `stripped_destination_url` to be the same as `destination_url`.
+    // Otherwise, `stripped_destination_url` will later be set by
+    // `AutocompleteResult::ComputeStrippedDestinationURL()` which strips away
+    // the additional query params from `destination_url` leaving only the
+    // search terms. That would result in these matches to be erroneously
+    // deduped despite having unique additional query params.
+    // Note that the match previously added to the map will continue to get the
+    // typical `stripped_destination_url` allowing it to be deduped with the
+    // plain-text matches (i.e., with no additional query params) as expected.
+    const auto& added_match_query = match_key.first;
+    const auto& added_match_query_params = match_key.second;
+    if (base::FeatureList::IsEnabled(omnibox::kDisambiguateEntitySuggestions) &&
+        !added_match_query_params.empty()) {
+      for (const auto& entry : *map) {
+        const auto& existing_match_query = entry.first.first;
+        const auto& existing_match_query_params = entry.first.second;
+        if (existing_match_query == added_match_query &&
+            !existing_match_query_params.empty() &&
+            existing_match_query_params != added_match_query_params) {
+          added_match.stripped_destination_url = added_match.destination_url;
+          break;
+        }
+      }
+    }
+  } else {
     auto& existing_match = i.first->second;
     // If a duplicate match is already in the map, replace it with `match` if it
     // is more relevant.
@@ -575,14 +605,20 @@
       }
       existing_match.duplicate_matches.push_back(std::move(match));
     }
-    // Copy over answer data from lower-ranking duplicate, if necessary.
-    // This depends on the lower-ranking duplicate always being added last - see
-    // use of push_back above.
+
+    // Copy over `answer` and `stripped_destination_url` from the lower-ranking
+    // duplicate, if necessary. Note that this requires the lower-ranking
+    // duplicate being added last. See the use of push_back above.
     const auto& less_relevant_duplicate_match =
         existing_match.duplicate_matches.back();
     if (less_relevant_duplicate_match.answer && !existing_match.answer) {
       existing_match.answer = less_relevant_duplicate_match.answer;
     }
+    if (!less_relevant_duplicate_match.stripped_destination_url.is_empty() &&
+        existing_match.stripped_destination_url.is_empty()) {
+      existing_match.stripped_destination_url =
+          less_relevant_duplicate_match.stripped_destination_url;
+    }
   }
 }
 
diff --git a/components/omnibox/browser/base_search_provider_unittest.cc b/components/omnibox/browser/base_search_provider_unittest.cc
index 9eadc8b..0b76221f 100644
--- a/components/omnibox/browser/base_search_provider_unittest.cc
+++ b/components/omnibox/browser/base_search_provider_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_match_type.h"
@@ -20,12 +21,44 @@
 #include "components/omnibox/browser/search_suggestion_parser.h"
 #include "components/omnibox/browser/suggestion_answer.h"
 #include "components/omnibox/browser/test_scheme_classifier.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "components/search_engines/search_terms_data.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_engines/template_url_service_client.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+
+SearchSuggestionParser::SuggestResult BuildSuggestion(
+    const std::u16string& query,
+    AutocompleteMatchType::Type type,
+    std::vector<int> subtypes,
+    const std::string& additional_query_params,
+    int relevance,
+    bool should_prerender) {
+  return SearchSuggestionParser::SuggestResult(
+      /*suggestion=*/query,
+      /*type=*/type,
+      /*subtypes=*/subtypes,
+      /*match_contents=*/query,
+      /*match_contents_prefix=*/u"",
+      /*annotation=*/std::u16string(),
+      /*additional_query_params=*/additional_query_params,
+      /*entity_id=*/"",
+      /*deletion_url=*/std::string(),
+      /*image_dominant_color=*/std::string(),
+      /*image_url=*/std::string(),
+      /*from_keyword=*/false,
+      /*relevance=*/relevance,
+      /*relevance_from_server=*/true,
+      /*should_prefetch=*/false,
+      /*should_prerender=*/should_prerender,
+      /*input_text=*/query);
+}
+
+}  // namespace
+
 using testing::NiceMock;
 using testing::Return;
 using testing::_;
@@ -165,6 +198,136 @@
   EXPECT_EQ(850, duplicate.relevance);
 }
 
+TEST_F(BaseSearchProviderTest, PreserveAdditionalQueryParamsWhenDeduplicating) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(omnibox::kDisambiguateEntitySuggestions);
+
+  TemplateURLData data;
+  data.SetURL("http://example.com/?q={searchTerms}");
+  auto template_url = std::make_unique<TemplateURL>(data);
+
+  TestBaseSearchProvider::MatchMap map;
+  std::u16string query = u"tom cruise";
+
+  // Ensure that a match with empty additional query params is added to the map
+  // without a pre-computed `stripped_destination_url`.
+  SearchSuggestionParser::SuggestResult plain_text = BuildSuggestion(
+      query, AutocompleteMatchType::SEARCH_HISTORY, {omnibox::SUBTYPE_PERSONAL},
+      /*additional_query_params=*/"",
+      /*relevance=*/1300, /*should_prerender=*/false);
+  provider_->AddMatchToMap(
+      plain_text, std::string(), AutocompleteInput(), template_url.get(),
+      client_->GetTemplateURLService()->search_terms_data(),
+      TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map);
+
+  ASSERT_EQ(1U, map.size());
+  AutocompleteMatch match = map[std::make_pair(query, "")];
+  ASSERT_EQ(1300, match.relevance);
+  EXPECT_EQ("http://example.com/?q=tom+cruise", match.destination_url);
+  EXPECT_EQ("", match.stripped_destination_url);
+  ASSERT_EQ(0U, match.duplicate_matches.size());
+
+  // Ensure that a duplicate match, with identical search terms and an empty
+  // additional query params, and with a lower relevance is added as a duplicate
+  // of the existing match in the map without a pre-computed
+  // `stripped_destination_url`.
+  SearchSuggestionParser::SuggestResult duplicate_plain_text = BuildSuggestion(
+      query, AutocompleteMatchType::SEARCH_HISTORY, {omnibox::SUBTYPE_PERSONAL},
+      /*additional_query_params=*/"",
+      /*relevance=*/1299, /*should_prerender=*/false);
+  provider_->AddMatchToMap(
+      duplicate_plain_text, std::string(), AutocompleteInput(),
+      template_url.get(), client_->GetTemplateURLService()->search_terms_data(),
+      TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map);
+
+  ASSERT_EQ(1U, map.size());
+  match = map[std::make_pair(query, "")];
+  ASSERT_EQ(1300, match.relevance);
+  EXPECT_EQ("http://example.com/?q=tom+cruise", match.destination_url);
+  EXPECT_EQ("", match.stripped_destination_url);
+  ASSERT_EQ(1U, match.duplicate_matches.size());
+  ASSERT_EQ(1299, match.duplicate_matches[0].relevance);
+
+  // Ensure that the first match, with duplicate search terms and a unique
+  // non-empty additional query params, is added to the map without a
+  // pre-computed `stripped_destination_url`.
+  SearchSuggestionParser::SuggestResult entity_1 = BuildSuggestion(
+      query, AutocompleteMatchType::SEARCH_HISTORY, {omnibox::SUBTYPE_PERSONAL},
+      /*additional_query_params=*/"gs_ssp=1",
+      /*relevance=*/1298, /*should_prerender=*/false);
+  provider_->AddMatchToMap(
+      entity_1, std::string(), AutocompleteInput(), template_url.get(),
+      client_->GetTemplateURLService()->search_terms_data(),
+      TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map);
+
+  ASSERT_EQ(2U, map.size());
+  match = map[std::make_pair(query, "gs_ssp=1")];
+  ASSERT_EQ(1298, match.relevance);
+  EXPECT_EQ("http://example.com/?gs_ssp=1&q=tom+cruise", match.destination_url);
+  EXPECT_EQ("", match.stripped_destination_url);
+  ASSERT_EQ(0U, match.duplicate_matches.size());
+
+  // Ensure that a subsequent match, with duplicate search terms and a unique
+  // non-empty additional query params, is added to the map with a pre-computed
+  // `stripped_destination_url`.
+  SearchSuggestionParser::SuggestResult entity_2 = BuildSuggestion(
+      query, AutocompleteMatchType::SEARCH_HISTORY, {omnibox::SUBTYPE_PERSONAL},
+      /*additional_query_params=*/"gs_ssp=2",
+      /*relevance=*/1297, /*should_prerender=*/false);
+  provider_->AddMatchToMap(
+      entity_2, std::string(), AutocompleteInput(), template_url.get(),
+      client_->GetTemplateURLService()->search_terms_data(),
+      TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map);
+
+  ASSERT_EQ(3U, map.size());
+  match = map[std::make_pair(query, "gs_ssp=2")];
+  ASSERT_EQ(1297, match.relevance);
+  EXPECT_EQ("http://example.com/?gs_ssp=2&q=tom+cruise", match.destination_url);
+  EXPECT_EQ(match.destination_url, match.stripped_destination_url);
+  ASSERT_EQ(0U, match.duplicate_matches.size());
+
+  // Ensure that a duplicate match, with identical search terms and additional
+  // query params, and with a lower relevance is added as a duplicate of the
+  // existing match in the map.
+  SearchSuggestionParser::SuggestResult duplicate_1_entity_2 = BuildSuggestion(
+      query, AutocompleteMatchType::SEARCH_HISTORY, {omnibox::SUBTYPE_PERSONAL},
+      /*additional_query_params=*/"gs_ssp=2",
+      /*relevance=*/1296, /*should_prerender=*/false);
+  provider_->AddMatchToMap(
+      duplicate_1_entity_2, std::string(), AutocompleteInput(),
+      template_url.get(), client_->GetTemplateURLService()->search_terms_data(),
+      TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map);
+
+  ASSERT_EQ(3U, map.size());
+  match = map[std::make_pair(query, "gs_ssp=2")];
+  ASSERT_EQ(1297, match.relevance);
+  EXPECT_EQ("http://example.com/?gs_ssp=2&q=tom+cruise", match.destination_url);
+  EXPECT_EQ(match.destination_url, match.stripped_destination_url);
+  ASSERT_EQ(1U, match.duplicate_matches.size());
+  ASSERT_EQ(1296, match.duplicate_matches[0].relevance);
+
+  // Ensure that a duplicate match, with identical search terms and additional
+  // query params, and with a higher relevance replaces the existing match in
+  // the map with a pre-computed `stripped_destination_url`.
+  SearchSuggestionParser::SuggestResult duplicate_2_entity_2 = BuildSuggestion(
+      query, AutocompleteMatchType::SEARCH_HISTORY, {omnibox::SUBTYPE_PERSONAL},
+      /*additional_query_params=*/"gs_ssp=2",
+      /*relevance=*/1301, /*should_prerender=*/false);
+  provider_->AddMatchToMap(
+      duplicate_2_entity_2, std::string(), AutocompleteInput(),
+      template_url.get(), client_->GetTemplateURLService()->search_terms_data(),
+      TemplateURLRef::NO_SUGGESTION_CHOSEN, false, false, &map);
+
+  ASSERT_EQ(3U, map.size());
+  match = map[std::make_pair(query, "gs_ssp=2")];
+  ASSERT_EQ(1301, match.relevance);
+  EXPECT_EQ("http://example.com/?gs_ssp=2&q=tom+cruise", match.destination_url);
+  EXPECT_EQ(match.destination_url, match.stripped_destination_url);
+  ASSERT_EQ(2U, match.duplicate_matches.size());
+  ASSERT_EQ(1296, match.duplicate_matches[0].relevance);
+  ASSERT_EQ(1297, match.duplicate_matches[1].relevance);
+}
+
 TEST_F(BaseSearchProviderTest, MatchTailSuggestionProperly) {
   TemplateURLData data;
   data.SetURL("http://foo.com/url?bar={searchTerms}");
@@ -175,23 +338,10 @@
 
   std::u16string query = u"angeles now";
   std::u16string suggestion = u"weather los " + query;
-  SearchSuggestionParser::SuggestResult suggest_result(
-      suggestion, AutocompleteMatchType::SEARCH_SUGGEST_TAIL,
-      /*subtypes=*/{},
-      /*match_contents=*/query,
-      /*match_contents_prefix=*/u"...",
-      /*annotation=*/std::u16string(),
-      /*additional_query_params=*/std::string(),
-      /*entity_id=*/"",
-      /*deletion_url=*/std::string(),
-      /*image_dominant_color=*/std::string(),
-      /*image_url=*/std::string(),
-      /*from_keyword=*/false,
-      /*relevance=*/1300,
-      /*relevance_from_server=*/true,
-      /*should_prefetch=*/false,
-      /*should_prerender=*/false,
-      /*input_text=*/query);
+  SearchSuggestionParser::SuggestResult suggest_result =
+      BuildSuggestion(suggestion, AutocompleteMatchType::SEARCH_SUGGEST_TAIL,
+                      /*subtypes=*/{}, /*additional_query_params=*/"",
+                      /*relevance=*/1300, /*should_prerender=*/false);
 
   TestBaseSearchProvider::MatchMap map;
   provider_->AddMatchToMap(
@@ -249,29 +399,6 @@
   ASSERT_TRUE(provider_->matches()[0].duplicate_matches.empty());
 }
 
-namespace {
-SearchSuggestionParser::SuggestResult BuildPrerenderSuggestion(
-    std::u16string query) {
-  return SearchSuggestionParser::SuggestResult(
-      query, AutocompleteMatchType::SEARCH_SUGGEST,
-      /*subtypes=*/{},
-      /*match_contents=*/query,
-      /*match_contents_prefix=*/u"...",
-      /*annotation=*/std::u16string(),
-      /*additional_query_params=*/std::string(),
-      /*entity_id=*/"",
-      /*deletion_url=*/std::string(),
-      /*image_dominant_color=*/std::string(),
-      /*image_url=*/std::string(),
-      /*from_keyword=*/false,
-      /*relevance=*/850,
-      /*relevance_from_server=*/true,
-      /*should_prefetch=*/false,
-      /*should_prerender=*/true,
-      /*input_text=*/query);
-}
-}  // namespace
-
 // Tests that the prerender hint can be aggregated to another SuggestResult.
 TEST_F(BaseSearchProviderTest, PrerenderDefaultMatch) {
   TemplateURLData data;
@@ -294,7 +421,9 @@
       /*in_keyword_mode=*/false, &map);
 
   SearchSuggestionParser::SuggestResult prerender_suggestion =
-      BuildPrerenderSuggestion(query);
+      BuildSuggestion(query, AutocompleteMatchType::SEARCH_SUGGEST,
+                      /*subtypes=*/{}, /*additional_query_params=*/"",
+                      /*relevance=*/850, /*should_prerender=*/true);
   provider_->AddMatchToMap(
       prerender_suggestion, std::string(), AutocompleteInput(),
       template_url.get(), client_->GetTemplateURLService()->search_terms_data(),
diff --git a/components/omnibox/browser/in_memory_url_index.cc b/components/omnibox/browser/in_memory_url_index.cc
index 4f07205..03c4ca5 100644
--- a/components/omnibox/browser/in_memory_url_index.cc
+++ b/components/omnibox/browser/in_memory_url_index.cc
@@ -18,8 +18,10 @@
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/memory_usage_estimator.h"
 #include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/url_database.h"
+#include "components/keep_alive_registry/keep_alive_registry.h"
 #include "components/omnibox/browser/url_index_private_data.h"
 #include "components/omnibox/common/omnibox_features.h"
 
@@ -206,15 +208,21 @@
   shutdown_ = true;
   private_data_tracker_.TryCancelAll();
 
-#ifndef LEAK_SANITIZER
+#if !defined(LEAK_SANITIZER) && !BUILDFLAG(IS_ANDROID)
   // Intentionally create and then leak a scoped_refptr to private_data_. This
   // permanently raises the reference count so that the URLIndexPrivateData
   // destructor won't run during browser shutdown. This saves having to walk the
   // maps to free their memory, which saves time and avoids shutdown hangs,
-  // especially if some of the memory has been paged out.
-  base::NoDestructor<scoped_refptr<URLIndexPrivateData>> leak_reference(
-      private_data_);
-#endif
+  // especially if some of the memory has been paged out. Note that we only want
+  // to do this if the whole browser is shutting down. If it's just the Profile
+  // being destroyed, we don't want to leak the memory. Android doesn't have
+  // KeepAliveRegistry, and doesn't need this anyways, since it kills the
+  // process without shutdown whenever it needs to.
+  if (KeepAliveRegistry::GetInstance()->IsShuttingDown()) {
+    base::NoDestructor<scoped_refptr<URLIndexPrivateData>> leak_reference(
+        private_data_);
+  }
+#endif  // !defined(LEAK_SANITIZER) && !BUILDFLAG(IS_ANDROID)
 }
 
 // Restoring from the History DB -----------------------------------------------
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider.cc b/components/omnibox/browser/local_history_zero_suggest_provider.cc
index e0160fd4..55c2e2c9 100644
--- a/components/omnibox/browser/local_history_zero_suggest_provider.cc
+++ b/components/omnibox/browser/local_history_zero_suggest_provider.cc
@@ -239,10 +239,9 @@
         /*relevance_from_server=*/false,
         /*input_text=*/base::ASCIIToUTF16(std::string()));
 
-    // Only provide a group ID, as the client does not know the header or the
-    // omnibox::GroupSection for omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST. The
-    // suggestion group info will either be provided by the server (i.e., on
-    // SRP/Web) or this group ID will be dropped (i.e., on NTP).
+    // If the appropriate header text and section are not provided by the server
+    // the default omnibox::SECTION_LOCAL_HISTORY_ZPS will be used and the local
+    // history zero-prefix suggestions will be shown without a header.
     suggestion.set_suggestion_group_id(
         omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST);
 
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index c1980ef..f52bf17 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -646,6 +646,17 @@
   return base::FeatureList::IsEnabled(omnibox::kSiteSearchStarterPack);
 }
 
+// Omnibox UI simplification - Uniform Suggestion Row Heights
+
+bool IsUniformRowHeightEnabled() {
+  return base::FeatureList::IsEnabled(omnibox::kUniformRowHeight);
+}
+
+const base::FeatureParam<int> OmniboxFieldTrial::kSuggestionRowHeight(
+    &omnibox::kUniformRowHeight,
+    "OmniboxUniformRowHeight",
+    36);
+
 const char OmniboxFieldTrial::kBundledExperimentFieldTrialName[] =
     "OmniboxBundledExperimentV1";
 const char OmniboxFieldTrial::kDisableProvidersRule[] = "DisableProviders";
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index 93f3ee8d..530fb59 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -381,6 +381,12 @@
 // scopes for Site Search.
 bool IsSiteSearchStarterPackEnabled();
 
+// Omnibox UI simplification - uniform row heights.
+// Returns true if the feature to enable uniform row height is enabled.
+bool IsUniformRowHeightEnabled();
+// Specifies the row height in pixels for omnibox suggestions.
+extern const base::FeatureParam<int> kSuggestionRowHeight;
+
 // ---------------------------------------------------------
 // Clipboard URL suggestions:
 
diff --git a/components/omnibox/browser/suggestion_group_util.cc b/components/omnibox/browser/suggestion_group_util.cc
index 38d46f1..d9dee60 100644
--- a/components/omnibox/browser/suggestion_group_util.cc
+++ b/components/omnibox/browser/suggestion_group_util.cc
@@ -16,6 +16,8 @@
       omnibox::SECTION_MOBILE_MOST_VISITED);
   groups[omnibox::GROUP_MOBILE_CLIPBOARD].set_section(
       omnibox::SECTION_MOBILE_CLIPBOARD);
+  groups[omnibox::GROUP_PERSONALIZED_ZERO_SUGGEST].set_section(
+      omnibox::SECTION_LOCAL_HISTORY_ZPS);
   return groups;
 }
 
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index f27d8ba..422e38c9 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -4,6 +4,7 @@
 
 #include "components/omnibox/common/omnibox_features.h"
 
+#include "base/feature_list.h"
 #include "build/build_config.h"
 
 namespace omnibox {
@@ -143,6 +144,12 @@
              "OmniboxDynamicMaxAutocomplete",
              enabled_by_default_desktop_android);
 
+// If enabled, proactively sets the `stripped_destination_url` for the entity
+// suggestions with identical search terms so they are not erroneously deduped.
+BASE_FEATURE(kDisambiguateEntitySuggestions,
+             "DisambiguateEntitySuggestions",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Used to adjust the relevance for the local history zero-prefix suggestions.
 // If enabled, the relevance is determined by this feature's companion
 // parameter, OmniboxFieldTrial::kLocalHistoryZeroSuggestRelevanceScore.
@@ -411,6 +418,11 @@
              "OmniboxMostVisitedTilesOnSrp",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// If enabled, forces omnibox suggestion rows to be uniformly sized.
+BASE_FEATURE(kUniformRowHeight,
+             "OmniboxUniformRowHeight",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // When enabled, use Assistant for omnibox voice query recognition instead of
 // Android's built-in voice recognition service. Only works on Android.
 BASE_FEATURE(kOmniboxAssistantVoiceSearch,
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index b60987d..f3dfd2e 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -42,6 +42,9 @@
 BASE_DECLARE_FEATURE(kDynamicMaxAutocomplete);
 BASE_DECLARE_FEATURE(kRetainSuggestionsWithHeaders);
 
+// Entity suggestion disambiguation.
+BASE_DECLARE_FEATURE(kDisambiguateEntitySuggestions);
+
 // Local history zero-prefix (aka zero-suggest) and prefix suggestions.
 BASE_DECLARE_FEATURE(kAdjustLocalHistoryZeroSuggestRelevanceScore);
 BASE_DECLARE_FEATURE(kClobberTriggersContextualWebZeroSuggest);
@@ -96,6 +99,7 @@
 BASE_DECLARE_FEATURE(kOmniboxRemoveSuggestionHeaderChevron);
 BASE_DECLARE_FEATURE(kOmniboxMostVisitedTilesFadingOnTablet);
 BASE_DECLARE_FEATURE(kOmniboxMostVisitedTilesOnSrp);
+BASE_DECLARE_FEATURE(kUniformRowHeight);
 
 // Omnibox UI - these affect the UI or function of the location bar (not the
 // popup).
diff --git a/components/password_manager/content/browser/content_password_manager_driver_factory_unittest.cc b/components/password_manager/content/browser/content_password_manager_driver_factory_unittest.cc
index 71cf094..449454a13 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_factory_unittest.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver_factory_unittest.cc
@@ -28,7 +28,7 @@
       public ::testing::WithParamInterface<bool> {
  public:
   ContentPasswordManagerDriverFactoryFencedFramesTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled;
+    std::vector<base::test::FeatureRefAndParams> enabled;
     std::vector<base::test::FeatureRef> disabled;
     enabled.push_back(
         {blink::features::kFencedFrames, {{"implementation_type", "mparch"}}});
diff --git a/components/password_manager/core/browser/password_manager_util_unittest.cc b/components/password_manager/core/browser/password_manager_util_unittest.cc
index aaa094a..7a8f412 100644
--- a/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -300,6 +300,10 @@
               OpenPromoCodeOfferDetailsURL,
               (const GURL& url),
               (override));
+  MOCK_METHOD(autofill::FormInteractionsFlowId,
+              GetCurrentFormInteractionsFlowId,
+              (),
+              (override));
 };
 
 PasswordForm GetTestAndroidCredential() {
diff --git a/components/permissions/contexts/DEPS b/components/permissions/contexts/DEPS
index 74e6149b..4507688 100644
--- a/components/permissions/contexts/DEPS
+++ b/components/permissions/contexts/DEPS
@@ -10,9 +10,3 @@
   "+third_party/blink/public/mojom",
   "+services/device/public/cpp/geolocation",
 ]
-
-specific_include_rules = {
-  "window_placement_permission_context\.cc": [
-    "+content/public/browser",
-  ],
-}
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 204ac90..0a8dcb7 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -24342,6 +24342,36 @@
       Note: If the current input method is unsupported, it switches to the hardware keyboard layout (if allowed) or the first valid entry in this list. Invalid or unsupported methods are ignored.'''
     },
     {
+      'name': 'HindiInscriptLayoutEnabled',
+      'owners': ['jshin@chromium.org', 'tranbaoduy@chromium.org'],
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome_os:108-'],
+      'device_only': False,
+      'items': [
+        {
+          'value': True,
+          'caption': 'Enable Hindi Inscript Layout',
+        },
+        {
+          'value': False,
+          'caption': 'Disable Hindi Inscript Layout',
+        },
+      ],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+        'unlisted': True,
+        'cloud_only': True
+      },
+      'default': False,
+      'example_value': True,
+      'id': 1025,
+      'caption': '''Enable the Hindi Inscript Layout''',
+      'tags': [],
+      'desc': '''Setting the policy enables Hindi Inscript Layout on <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph>. If false or unset, the layout is not available.'''
+    },
+    {
       'name': 'ArcAppInstallEventLoggingEnabled',
       'owners': ['file://components/policy/resources/OWNERS', 'pastarmovj@chromium.org'],
       'type': 'main',
@@ -34513,7 +34543,7 @@
       'type': 'main',
       'schema': { 'type': 'boolean' },
       'features' : {
-        'dynamic_refresh': False,
+        'dynamic_refresh': True,
         'per_profile': True,
       },
       'items': [
@@ -36695,6 +36725,6 @@
   'placeholders': [],
   'deleted_policy_ids': [114, 115, 204, 205, 206, 341, 412, 438, 476, 544, 546, 562, 569, 578, 583, 585, 586, 587, 588, 589, 590, 591, 600, 668, 669, 872],
   'deleted_atomic_policy_group_ids': [19],
-  'highest_id_currently_used': 1024,
+  'highest_id_currently_used': 1025,
   'highest_atomic_group_id_currently_used': 43
 }
diff --git a/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc b/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
index eee4b2a..04a0a94 100644
--- a/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
+++ b/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
@@ -218,7 +218,7 @@
   }
 
   void EnableRealTimeUrlLookupWithParameters(
-      const std::vector<base::test::ScopedFeatureList::FeatureAndParams>&
+      const std::vector<base::test::FeatureRefAndParams>&
           enabled_features_and_params,
       const std::vector<base::test::FeatureRef>& disabled_features) {
     EnableMbb();
diff --git a/components/safe_browsing/core/common/features_unittest.cc b/components/safe_browsing/core/common/features_unittest.cc
index 67ec5d8..c9275dd 100644
--- a/components/safe_browsing/core/common/features_unittest.cc
+++ b/components/safe_browsing/core/common/features_unittest.cc
@@ -21,7 +21,7 @@
 
 TEST(SafeBrowsingFeatures, ClientSideDetectionTagAllUsers) {
   base::test::ScopedFeatureList feature_list;
-  base::test::ScopedFeatureList::FeatureAndParams all_users_feature(
+  base::test::FeatureRefAndParams all_users_feature(
       kClientSideDetectionModelTag, {{"reporter_omaha_tag", "all_users_tag"}});
   feature_list.InitWithFeaturesAndParameters({all_users_feature}, {});
   EXPECT_EQ(GetClientSideDetectionTag(), "all_users_tag");
@@ -35,8 +35,8 @@
 
 TEST(SafeBrowsingFeatures, FileTypePoliciesTagEnabled) {
   base::test::ScopedFeatureList feature_list;
-  base::test::ScopedFeatureList::FeatureAndParams feature_params(
-      kFileTypePoliciesTag, {{"policy_omaha_tag", "45"}});
+  base::test::FeatureRefAndParams feature_params(kFileTypePoliciesTag,
+                                                 {{"policy_omaha_tag", "45"}});
   feature_list.InitWithFeaturesAndParameters({feature_params}, {});
   EXPECT_EQ(GetFileTypePoliciesTag(), "45");
 }
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegateTest.java b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegateTest.java
index 9fd97dc..d74f42c3 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegateTest.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegateTest.java
@@ -29,7 +29,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.FlakyTest;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.components.signin.AccessTokenData;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
@@ -143,7 +143,7 @@
 
     @Test
     @SmallTest
-    @FlakyTest(message = "Test is flaky, see crbug.com/1291110")
+    @DisabledTest(message = "Test is flaky, see crbug.com/1291110")
     public void testHasOAuth2RefreshTokenWhenAccountIsOnDevice() {
         mAccountManagerFacade.addAccount(ACCOUNT);
         ThreadUtils.runOnUiThreadBlocking(
diff --git a/components/site_isolation/site_isolation_policy_unittest.cc b/components/site_isolation/site_isolation_policy_unittest.cc
index aa81b98..8d0e8bc 100644
--- a/components/site_isolation/site_isolation_policy_unittest.cc
+++ b/components/site_isolation/site_isolation_policy_unittest.cc
@@ -166,7 +166,7 @@
   void SetUp() override {
     // Set up the COOP isolation feature with persistence enabled and a maximum
     // of 3 stored sites.
-    base::test::ScopedFeatureList::FeatureAndParams coop_feature = {
+    base::test::FeatureRefAndParams coop_feature = {
         ::features::kSiteIsolationForCrossOriginOpenerPolicy,
         {{::features::kSiteIsolationForCrossOriginOpenerPolicyMaxSitesParam
               .name,
@@ -178,7 +178,7 @@
     // Some machines running this test may be below the default memory
     // threshold.  To ensure that COOP isolation is also enabled on those
     // machines, set a very low 128MB threshold.
-    base::test::ScopedFeatureList::FeatureAndParams memory_threshold_feature = {
+    base::test::FeatureRefAndParams memory_threshold_feature = {
         site_isolation::features::kSiteIsolationMemoryThresholds,
         {{site_isolation::features::
               kPartialSiteIsolationMemoryThresholdParamName,
diff --git a/components/speech/DIR_METADATA b/components/speech/DIR_METADATA
new file mode 100644
index 0000000..40e532640
--- /dev/null
+++ b/components/speech/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "Blink>Speech"
+}
+team_email: "media-dev@chromium.org"
diff --git a/components/speech/OWNERS b/components/speech/OWNERS
new file mode 100644
index 0000000..9bd1b988
--- /dev/null
+++ b/components/speech/OWNERS
@@ -0,0 +1 @@
+evliu@google.com
diff --git a/components/sync/protocol/autofill_specifics.proto b/components/sync/protocol/autofill_specifics.proto
index 5625c3c..1682c1a 100644
--- a/components/sync/protocol/autofill_specifics.proto
+++ b/components/sync/protocol/autofill_specifics.proto
@@ -240,6 +240,12 @@
     UNENROLLED_AND_ELIGIBLE = 4;
   }
 
+  enum VirtualCardEnrollmentType {
+    TYPE_UNSPECIFIED = 0;
+    ISSUER = 1;
+    NETWORK = 2;
+  }
+
   // Server-generated unique ID string. This is opaque to the client.
   // This is the legacy version of |instrument_id|.
   optional string id = 1;
@@ -285,11 +291,15 @@
   // The state of virtual card enrollment.
   optional VirtualCardEnrollmentState virtual_card_enrollment_state = 16;
 
-  // The URL for the client to fetche the card art image.
+  // The URL for the client to fetch the card art image.
   optional string card_art_url = 17;
 
   // The product description for the card. Used to be shown in the UI.
   optional string product_description = 18;
+
+  // The type of virtual card enrollment. TYPE_UNSPECIFIED indicates that the
+  // card is unenrolled.
+  optional VirtualCardEnrollmentType virtual_card_enrollment_type = 19;
 }
 
 // Different than an AutofillProfile because this represents some known address
diff --git a/components/sync/protocol/proto_enum_conversions.cc b/components/sync/protocol/proto_enum_conversions.cc
index 6ea6fb8..c49a97f 100644
--- a/components/sync/protocol/proto_enum_conversions.cc
+++ b/components/sync/protocol/proto_enum_conversions.cc
@@ -550,6 +550,20 @@
 }
 
 const char* ProtoEnumToString(
+    sync_pb::WalletMaskedCreditCard::VirtualCardEnrollmentType
+        virtual_card_enrollment_type) {
+  ASSERT_ENUM_BOUNDS(sync_pb::WalletMaskedCreditCard, VirtualCardEnrollmentType,
+                     TYPE_UNSPECIFIED, NETWORK);
+  switch (virtual_card_enrollment_type) {
+    ENUM_CASE(sync_pb::WalletMaskedCreditCard, TYPE_UNSPECIFIED);
+    ENUM_CASE(sync_pb::WalletMaskedCreditCard, ISSUER);
+    ENUM_CASE(sync_pb::WalletMaskedCreditCard, NETWORK);
+  }
+  NOTREACHED();
+  return "";
+}
+
+const char* ProtoEnumToString(
     sync_pb::WalletMaskedCreditCard::WalletCardStatus wallet_card_status) {
   ASSERT_ENUM_BOUNDS(sync_pb::WalletMaskedCreditCard, WalletCardStatus, VALID,
                      EXPIRED);
diff --git a/components/sync/protocol/proto_enum_conversions.h b/components/sync/protocol/proto_enum_conversions.h
index 8c3eb4f9..7465a3c 100644
--- a/components/sync/protocol/proto_enum_conversions.h
+++ b/components/sync/protocol/proto_enum_conversions.h
@@ -122,6 +122,10 @@
         virtual_card_enrollment_state);
 
 const char* ProtoEnumToString(
+    sync_pb::WalletMaskedCreditCard::VirtualCardEnrollmentType
+        virtual_card_enrollment_type);
+
+const char* ProtoEnumToString(
     sync_pb::WalletMaskedCreditCard::WalletCardStatus wallet_card_status);
 
 const char* ProtoEnumToString(
diff --git a/components/sync/protocol/proto_enum_conversions_unittest.cc b/components/sync/protocol/proto_enum_conversions_unittest.cc
index 427b0fe..39b9306a 100644
--- a/components/sync/protocol/proto_enum_conversions_unittest.cc
+++ b/components/sync/protocol/proto_enum_conversions_unittest.cc
@@ -96,5 +96,10 @@
   TestEnumStringsNonEmpty(sync_pb::UserConsentTypes::ConsentStatus);
 }
 
+TEST(ProtoEnumConversionsTest, GetVirtualCardEnrollmentTypeString) {
+  TestEnumStringsNonEmpty(
+      sync_pb::WalletMaskedCreditCard::VirtualCardEnrollmentType);
+}
+
 }  // namespace
 }  // namespace syncer
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h
index 9d13f28..b47302d 100644
--- a/components/sync/protocol/proto_visitors.h
+++ b/components/sync/protocol/proto_visitors.h
@@ -1340,6 +1340,7 @@
   VISIT_ENUM(virtual_card_enrollment_state);
   VISIT(card_art_url);
   VISIT(product_description);
+  VISIT_ENUM(virtual_card_enrollment_type);
 }
 
 VISIT_PROTO_FIELDS(const sync_pb::WalletMetadataSpecifics& proto) {
diff --git a/components/user_manager/user_image/user_image.h b/components/user_manager/user_image/user_image.h
index 17c9402..e3331cdb 100644
--- a/components/user_manager/user_image/user_image.h
+++ b/components/user_manager/user_image/user_image.h
@@ -26,6 +26,8 @@
     FORMAT_JPEG,
     FORMAT_PNG,
     FORMAT_UNKNOWN,
+    // Useful when the image is external and animated.
+    FORMAT_WEBP,
   };
 
   // Encodes the given bitmap to bytes representation in |image_format| for
diff --git a/components/viz/common/quads/compositor_frame_metadata_unittest.cc b/components/viz/common/quads/compositor_frame_metadata_unittest.cc
index e4e9cb95..22e2c33 100644
--- a/components/viz/common/quads/compositor_frame_metadata_unittest.cc
+++ b/components/viz/common/quads/compositor_frame_metadata_unittest.cc
@@ -47,8 +47,7 @@
 
 bool AreTransitionDirectivesEqual(const CompositorFrameTransitionDirective& a,
                                   const CompositorFrameTransitionDirective& b) {
-  return a.sequence_id() == b.sequence_id() && a.type() == b.type() &&
-         a.effect() == b.effect();
+  return a.sequence_id() == b.sequence_id() && a.type() == b.type();
 }
 
 TEST(CompositorFrameMetadata, Clone) {
@@ -83,8 +82,7 @@
       gfx::PointF(88.8, 44.4), 1.f, SK_ColorRED,
       base::TimeTicks() + base::Seconds(125), gfx::RectF(1, 2, 3, 4), true);
   metadata.transition_directives.emplace_back(
-      4u, CompositorFrameTransitionDirective::Type::kSave,
-      CompositorFrameTransitionDirective::Effect::kCoverUp);
+      4u, CompositorFrameTransitionDirective::Type::kSave);
 
   CompositorFrameMetadata clone = metadata.Clone();
   EXPECT_FLOAT_EQ(clone.device_scale_factor, metadata.device_scale_factor);
diff --git a/components/viz/common/quads/compositor_frame_transition_directive.cc b/components/viz/common/quads/compositor_frame_transition_directive.cc
index a65cf0d..beef14d 100644
--- a/components/viz/common/quads/compositor_frame_transition_directive.cc
+++ b/components/viz/common/quads/compositor_frame_transition_directive.cc
@@ -17,11 +17,9 @@
 CompositorFrameTransitionDirective::CompositorFrameTransitionDirective(
     uint32_t sequence_id,
     Type type,
-    Effect effect,
     std::vector<SharedElement> shared_elements)
     : sequence_id_(sequence_id),
       type_(type),
-      effect_(effect),
       shared_elements_(std::move(shared_elements)) {}
 
 CompositorFrameTransitionDirective::CompositorFrameTransitionDirective(
diff --git a/components/viz/common/quads/compositor_frame_transition_directive.h b/components/viz/common/quads/compositor_frame_transition_directive.h
index b51f2b86..ac6415b 100644
--- a/components/viz/common/quads/compositor_frame_transition_directive.h
+++ b/components/viz/common/quads/compositor_frame_transition_directive.h
@@ -29,34 +29,14 @@
   //   the renderer or Viz process. This directive must be followed by the
   //   Animate or AnimateRenderer directive.
   //
-  // - Animate means that this frame should be used as a (new) destination frame
-  //   of the animation, using the previously saved frame as the source.
-  //
   // - AnimateRenderer means that content in the current and subsequent frames
-  //   will use cached resources from the frame with the Save directive. This is
-  //   used when the content animation is driven by the renderer process.
+  //   will use cached resources from the frame with the Save directive.
   //   Ownership of the cached resources is passed to the renderer process. This
   //   directive must be followed by Release to delete the cached resources.
   //
   // - Release means that cached textures in the Viz process can be deleted.
   //   This is used in the mode where the renderer is driving this animation.
-  enum class Type { kSave, kAnimate, kAnimateRenderer, kRelease };
-
-  // The type of an effect that should be used in the animation.
-  enum class Effect {
-    kNone,
-    kCoverDown,
-    kCoverLeft,
-    kCoverRight,
-    kCoverUp,
-    kExplode,
-    kFade,
-    kImplode,
-    kRevealDown,
-    kRevealLeft,
-    kRevealRight,
-    kRevealUp
-  };
+  enum class Type { kSave, kAnimateRenderer, kRelease };
 
   struct VIZ_COMMON_EXPORT SharedElement {
     SharedElement();
@@ -85,7 +65,6 @@
   CompositorFrameTransitionDirective(
       uint32_t sequence_id,
       Type type,
-      Effect effect = Effect::kNone,
       std::vector<SharedElement> shared_elements = {});
 
   CompositorFrameTransitionDirective(const CompositorFrameTransitionDirective&);
@@ -102,9 +81,6 @@
   // The type of this directive.
   Type type() const { return type_; }
 
-  // The effect for the transition.
-  Effect effect() const { return effect_; }
-
   // Shared elements.
   const std::vector<SharedElement>& shared_elements() const {
     return shared_elements_;
@@ -115,8 +91,6 @@
 
   Type type_ = Type::kSave;
 
-  Effect effect_ = Effect::kNone;
-
   std::vector<SharedElement> shared_elements_;
 };
 
diff --git a/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc b/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc
index 214048ec..7027304 100644
--- a/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc
+++ b/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc
@@ -9,21 +9,19 @@
 namespace viz {
 namespace {
 
-using Effect = CompositorFrameTransitionDirective::Effect;
 using Type = CompositorFrameTransitionDirective::Type;
 
 TEST(CompositorFrameTransitionDirective, GettersReflectParameters) {
-  CompositorFrameTransitionDirective save_directive(1u, Type::kSave,
-                                                    Effect::kCoverLeft);
+  CompositorFrameTransitionDirective save_directive(1u, Type::kSave);
 
   EXPECT_EQ(1u, save_directive.sequence_id());
   EXPECT_EQ(Type::kSave, save_directive.type());
-  EXPECT_EQ(Effect::kCoverLeft, save_directive.effect());
 
-  CompositorFrameTransitionDirective animate_directive(2, Type::kAnimate);
+  CompositorFrameTransitionDirective animate_directive(2,
+                                                       Type::kAnimateRenderer);
 
   EXPECT_EQ(2u, animate_directive.sequence_id());
-  EXPECT_EQ(Type::kAnimate, animate_directive.type());
+  EXPECT_EQ(Type::kAnimateRenderer, animate_directive.type());
 }
 
 }  // namespace
diff --git a/components/viz/common/quads/render_pass_io.cc b/components/viz/common/quads/render_pass_io.cc
index 8b981f8..ddad591b 100644
--- a/components/viz/common/quads/render_pass_io.cc
+++ b/components/viz/common/quads/render_pass_io.cc
@@ -78,14 +78,12 @@
   return dict;
 }
 
-bool RectFromDict(const base::Value& dict, gfx::Rect* rect) {
+bool RectFromDict(const base::Value::Dict& dict, gfx::Rect* rect) {
   DCHECK(rect);
-  if (!dict.is_dict())
-    return false;
-  absl::optional<int> x = dict.FindIntKey("x");
-  absl::optional<int> y = dict.FindIntKey("y");
-  absl::optional<int> width = dict.FindIntKey("width");
-  absl::optional<int> height = dict.FindIntKey("height");
+  absl::optional<int> x = dict.FindInt("x");
+  absl::optional<int> y = dict.FindInt("y");
+  absl::optional<int> width = dict.FindInt("width");
+  absl::optional<int> height = dict.FindInt("height");
   if (!x || !y || !width || !height) {
     return false;
   }
@@ -226,13 +224,10 @@
   return PointFToDict(gfx::PointF(v.x(), v.y()));
 }
 
-bool Vector2dFFromDict(const base::Value& dict, gfx::Vector2dF* v) {
+bool Vector2dFFromDict(const base::Value::Dict& dict, gfx::Vector2dF* v) {
   DCHECK(v);
-  if (!dict.is_dict())
-    return false;
-
   gfx::PointF point;
-  if (!PointFFromDict(dict.GetDict(), &point))
+  if (!PointFFromDict(dict, &point))
     return false;
 
   v->set_x(point.x());
@@ -501,7 +496,10 @@
   cc::FilterOperation::ShapeRects data;
   data.resize(size);
   for (size_t ii = 0; ii < size; ++ii) {
-    if (!RectFromDict(list.GetList()[ii], &data[ii]))
+    const base::Value& dict_value = list.GetList()[ii];
+    if (!dict_value.is_dict())
+      return false;
+    if (!RectFromDict(dict_value.GetDict(), &data[ii]))
       return false;
   }
   *shape = data;
@@ -1139,17 +1137,18 @@
 };
 
 absl::optional<DrawQuadCommon> GetDrawQuadCommonFromDict(
-    const base::Value& dict,
+    const base::Value& dict_value,
     const SharedQuadStateList& shared_quad_state_list) {
-  if (!dict.is_dict())
+  if (!dict_value.is_dict())
     return absl::nullopt;
-  const std::string* material = dict.FindStringKey("material");
-  const base::Value* rect = dict.FindDictKey("rect");
-  const base::Value* visible_rect = dict.FindDictKey("visible_rect");
-  absl::optional<bool> needs_blending = dict.FindBoolKey("needs_blending");
+  const base::Value::Dict& dict = dict_value.GetDict();
+  const std::string* material = dict.FindString("material");
+  const base::Value::Dict* rect = dict.FindDict("rect");
+  const base::Value::Dict* visible_rect = dict.FindDict("visible_rect");
+  absl::optional<bool> needs_blending = dict.FindBool("needs_blending");
   absl::optional<int> shared_quad_state_index =
-      dict.FindIntKey("shared_quad_state_index");
-  const base::Value* resources = dict.FindListKey("resources");
+      dict.FindInt("shared_quad_state_index");
+  const base::Value* resources = dict_value.FindListKey("resources");
   if (!material || !rect || !visible_rect || !needs_blending ||
       !shared_quad_state_index || !resources) {
     return absl::nullopt;
@@ -1188,11 +1187,7 @@
 };
 
 absl::optional<ContentDrawQuadCommon> GetContentDrawQuadCommonFromDict(
-    const base::Value& dict_value) {
-  if (!dict_value.is_dict())
-    return absl::nullopt;
-
-  const base::Value::Dict& dict = dict_value.GetDict();
+    const base::Value::Dict& dict) {
   const base::Value::Dict* tex_coord_rect = dict.FindDict("tex_coord_rect");
   const base::Value::Dict* texture_size = dict.FindDict("texture_size");
   absl::optional<bool> is_premultiplied = dict.FindBool("is_premultiplied");
@@ -1415,7 +1410,7 @@
   const base::Value::Dict* mask_uv_rect = dict.FindDict("mask_uv_rect");
   const base::Value::Dict* mask_texture_size =
       dict.FindDict("mask_texture_size");
-  const base::Value* filters_scale = dict_value.FindDictKey("filters_scale");
+  const base::Value::Dict* filters_scale = dict.FindDict("filters_scale");
   const base::Value::Dict* filters_origin = dict.FindDict("filters_origin");
   const base::Value::Dict* tex_coord_rect = dict.FindDict("tex_coord_rect");
   absl::optional<double> backdrop_filter_quality =
@@ -1525,7 +1520,7 @@
   const base::Value::Dict* uv_top_left = dict.FindDict("uv_top_left");
   const base::Value::Dict* uv_bottom_right = dict.FindDict("uv_bottom_right");
   const base::Value* vertex_opacity = dict_value.FindListKey("vertex_opacity");
-  const base::Value* damage_rect = dict_value.FindDictKey("damage_rect");
+  const base::Value::Dict* damage_rect = dict.FindDict("damage_rect");
   absl::optional<bool> y_flipped = dict.FindBool("y_flipped");
   absl::optional<bool> nearest_neighbor = dict.FindBool("nearest_neighbor");
   absl::optional<bool> secure_output_only = dict.FindBool("secure_output_only");
@@ -1586,7 +1581,7 @@
     return false;
 
   absl::optional<ContentDrawQuadCommon> content_common =
-      GetContentDrawQuadCommonFromDict(dict);
+      GetContentDrawQuadCommonFromDict(dict.GetDict());
   if (!content_common)
     return false;
 
@@ -1617,7 +1612,7 @@
       dict.FindDict("uv_tex_coord_rect");
   const base::Value::Dict* ya_tex_size = dict.FindDict("ya_tex_size");
   const base::Value::Dict* uv_tex_size = dict.FindDict("uv_tex_size");
-  const base::Value* damage_rect = dict_value.FindDictKey("damage_rect");
+  const base::Value::Dict* damage_rect = dict.FindDict("damage_rect");
   absl::optional<double> resource_offset = dict.FindDouble("resource_offset");
   absl::optional<double> resource_multiplier =
       dict.FindDouble("resource_multiplier");
@@ -1822,28 +1817,30 @@
 }
 #undef MAP_STRING_TO_BLEND_MODE
 
-bool SharedQuadStateFromDict(const base::Value& dict, SharedQuadState* sqs) {
+bool SharedQuadStateFromDict(const base::Value& dict_value,
+                             SharedQuadState* sqs) {
   DCHECK(sqs);
-  if (!dict.is_dict())
+  if (!dict_value.is_dict())
     return false;
+
+  const base::Value::Dict& dict = dict_value.GetDict();
   const base::Value* quad_to_target_transform =
-      dict.FindListKey("quad_to_target_transform");
-  const base::Value* quad_layer_rect = dict.FindDictKey("quad_layer_rect");
-  const base::Value* visible_quad_layer_rect =
-      dict.FindDictKey("visible_quad_layer_rect");
-  const base::Value* mask_filter_info = dict.FindDictKey("mask_filter_info");
-  const base::Value* clip_rect = dict.FindDictKey("clip_rect");
-  absl::optional<bool> is_clipped = dict.FindBoolKey("is_clipped");
+      dict_value.FindListKey("quad_to_target_transform");
+  const base::Value::Dict* quad_layer_rect = dict.FindDict("quad_layer_rect");
+  const base::Value::Dict* visible_quad_layer_rect =
+      dict.FindDict("visible_quad_layer_rect");
+  const base::Value* mask_filter_info =
+      dict_value.FindDictKey("mask_filter_info");
+  const base::Value::Dict* clip_rect = dict.FindDict("clip_rect");
+  absl::optional<bool> is_clipped = dict.FindBool("is_clipped");
   absl::optional<bool> are_contents_opaque =
-      dict.FindBoolKey("are_contents_opaque");
-  absl::optional<double> opacity = dict.FindDoubleKey("opacity");
-  const std::string* blend_mode = dict.FindStringKey("blend_mode");
-  absl::optional<int> sorting_context_id =
-      dict.FindIntKey("sorting_context_id");
+      dict.FindBool("are_contents_opaque");
+  absl::optional<double> opacity = dict.FindDouble("opacity");
+  const std::string* blend_mode = dict.FindString("blend_mode");
+  absl::optional<int> sorting_context_id = dict.FindInt("sorting_context_id");
   absl::optional<bool> is_fast_rounded_corner =
-      dict.FindBoolKey("is_fast_rounded_corner");
-  absl::optional<double> de_jelly_delta_y =
-      dict.FindDoubleKey("de_jelly_delta_y");
+      dict.FindBool("is_fast_rounded_corner");
+  absl::optional<double> de_jelly_delta_y = dict.FindDouble("de_jelly_delta_y");
 
   if (!quad_to_target_transform || !quad_layer_rect ||
       !visible_quad_layer_rect || !are_contents_opaque || !opacity ||
@@ -2068,13 +2065,14 @@
 }
 
 std::unique_ptr<CompositorRenderPass> CompositorRenderPassFromDict(
-    const base::Value& dict) {
-  if (!dict.is_dict())
+    const base::Value& dict_value) {
+  if (!dict_value.is_dict())
     return nullptr;
+  const base::Value::Dict& dict = dict_value.GetDict();
   auto pass = CompositorRenderPass::Create();
 
   if (ProcessRenderPassField(kRenderPassID)) {
-    const std::string* id = dict.FindStringKey("id");
+    const std::string* id = dict.FindString("id");
     if (!id)
       return nullptr;
     uint64_t pass_id_as_int = 0;
@@ -2084,7 +2082,7 @@
   }
 
   if (ProcessRenderPassField(kRenderPassOutputRect)) {
-    const base::Value* output_rect = dict.FindDictKey("output_rect");
+    const base::Value::Dict* output_rect = dict.FindDict("output_rect");
     if (!output_rect)
       return nullptr;
     if (!RectFromDict(*output_rect, &(pass->output_rect)))
@@ -2092,7 +2090,7 @@
   }
 
   if (ProcessRenderPassField(kRenderPassDamageRect)) {
-    const base::Value* damage_rect = dict.FindDictKey("damage_rect");
+    const base::Value::Dict* damage_rect = dict.FindDict("damage_rect");
     if (!damage_rect)
       return nullptr;
     if (!RectFromDict(*damage_rect, &(pass->damage_rect)))
@@ -2101,7 +2099,7 @@
 
   if (ProcessRenderPassField(kRenderPassTransformToRootTarget)) {
     const base::Value* transform_to_root_target =
-        dict.FindListKey("transform_to_root_target");
+        dict_value.FindListKey("transform_to_root_target");
     if (!transform_to_root_target)
       return nullptr;
     if (!TransformFromList(*transform_to_root_target,
@@ -2111,7 +2109,7 @@
   }
 
   if (ProcessRenderPassField(kRenderPassFilters)) {
-    const base::Value* filters = dict.FindListKey("filters");
+    const base::Value* filters = dict_value.FindListKey("filters");
     if (!filters)
       return nullptr;
     if (!FilterOperationsFromList(*filters, &(pass->filters)))
@@ -2119,7 +2117,8 @@
   }
 
   if (ProcessRenderPassField(kRenderPassBackdropFilters)) {
-    const base::Value* backdrop_filters = dict.FindListKey("backdrop_filters");
+    const base::Value* backdrop_filters =
+        dict_value.FindListKey("backdrop_filters");
     if (!backdrop_filters)
       return nullptr;
     if (!FilterOperationsFromList(*backdrop_filters,
@@ -2130,7 +2129,7 @@
 
   if (ProcessRenderPassField(kRenderPassBackdropFilterBounds)) {
     const base::Value::Dict* backdrop_filter_bounds =
-        dict.GetDict().FindDict("backdrop_filter_bounds");
+        dict.FindDict("backdrop_filter_bounds");
     if (backdrop_filter_bounds) {
       gfx::RRectF bounds;
       if (!RRectFFromDict(*backdrop_filter_bounds, &bounds))
@@ -2140,7 +2139,7 @@
   }
 
   if (ProcessRenderPassField(kRenderPassColorSpace)) {
-    const base::Value* color_space = dict.FindDictKey("color_space");
+    const base::Value* color_space = dict_value.FindDictKey("color_space");
     if (!color_space)
       return nullptr;
 
@@ -2153,7 +2152,7 @@
 
   if (ProcessRenderPassField(kRenderPassHasTransparentBackground)) {
     const absl::optional<bool> has_transparent_background =
-        dict.FindBoolKey("has_transparent_background");
+        dict.FindBool("has_transparent_background");
     if (!has_transparent_background)
       return nullptr;
     pass->has_transparent_background = has_transparent_background.value();
@@ -2161,7 +2160,7 @@
 
   if (ProcessRenderPassField(kRenderPassCacheRenderPass)) {
     const absl::optional<bool> cache_render_pass =
-        dict.FindBoolKey("cache_render_pass");
+        dict.FindBool("cache_render_pass");
     if (!cache_render_pass)
       return nullptr;
     pass->cache_render_pass = cache_render_pass.value();
@@ -2169,14 +2168,14 @@
 
   if (ProcessRenderPassField(kRenderPassHasPreQuadDamage)) {
     const absl::optional<bool> has_per_quad_damage =
-        dict.FindBoolKey("has_per_quad_damage");
+        dict.FindBool("has_per_quad_damage");
     if (has_per_quad_damage)
       pass->has_per_quad_damage = has_per_quad_damage.value();
   }
 
   if (ProcessRenderPassField(kRenderPassHasDamageFromContributingContent)) {
     const absl::optional<bool> has_damage_from_contributing_content =
-        dict.FindBoolKey("has_damage_from_contributing_content");
+        dict.FindBool("has_damage_from_contributing_content");
     if (!has_damage_from_contributing_content)
       return nullptr;
     pass->has_damage_from_contributing_content =
@@ -2185,7 +2184,7 @@
 
   if (ProcessRenderPassField(kRenderPassGenerateMipmap)) {
     const absl::optional<bool> generate_mipmap =
-        dict.FindBoolKey("generate_mipmap");
+        dict.FindBool("generate_mipmap");
     if (!generate_mipmap)
       return nullptr;
     pass->generate_mipmap = generate_mipmap.value();
@@ -2198,7 +2197,7 @@
   // shared_quad_state_list has to be processed before quad_list.
   if (ProcessRenderPassField(kRenderPassSharedQuadStateList)) {
     const base::Value* shared_quad_state_list =
-        dict.FindListKey("shared_quad_state_list");
+        dict_value.FindListKey("shared_quad_state_list");
     if (!shared_quad_state_list)
       return nullptr;
     if (!SharedQuadStateListFromList(*shared_quad_state_list,
@@ -2208,7 +2207,7 @@
   }
 
   if (ProcessRenderPassField(kRenderPassQuadList)) {
-    const base::Value* quad_list = dict.FindListKey("quad_list");
+    const base::Value* quad_list = dict_value.FindListKey("quad_list");
     if (!quad_list)
       return nullptr;
     if (!QuadListFromList(*quad_list, &(pass->quad_list),
diff --git a/components/viz/host/host_gpu_memory_buffer_manager.cc b/components/viz/host/host_gpu_memory_buffer_manager.cc
index ebb935f..d745266 100644
--- a/components/viz/host/host_gpu_memory_buffer_manager.cc
+++ b/components/viz/host/host_gpu_memory_buffer_manager.cc
@@ -8,7 +8,9 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/bind_post_task.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/process_memory_dump.h"
@@ -29,14 +31,6 @@
 
 namespace {
 
-void OnGpuMemoryBufferDestroyed(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    gpu::GpuMemoryBufferImpl::DestructionCallback callback,
-    const gpu::SyncToken& sync_token) {
-  task_runner->PostTask(FROM_HERE,
-                        base::BindOnce(std::move(callback), sync_token));
-}
-
 bool WillGetGmbConfigFromGpu() {
 #if defined(USE_OZONE)
   // Ozone/X11 cannot get buffer formats in the browser process and requires gpu
@@ -56,12 +50,7 @@
 HostGpuMemoryBufferManager::PendingBufferInfo::PendingBufferInfo() = default;
 HostGpuMemoryBufferManager::PendingBufferInfo::PendingBufferInfo(
     PendingBufferInfo&&) = default;
-HostGpuMemoryBufferManager::PendingBufferInfo::~PendingBufferInfo() {
-  // Another thread may be blocked on WaitableEvent that is signalled by
-  // `callback` so ensure it gets run.
-  if (callback)
-    std::move(callback).Run(gfx::GpuMemoryBufferHandle());
-}
+HostGpuMemoryBufferManager::PendingBufferInfo::~PendingBufferInfo() = default;
 
 HostGpuMemoryBufferManager::HostGpuMemoryBufferManager(
     GpuServiceProvider gpu_service_provider,
@@ -74,6 +63,9 @@
       pool_(base::MakeRefCounted<base::UnsafeSharedMemoryPool>()),
       task_runner_(std::move(task_runner)) {
   DCHECK(task_runner_->BelongsToCurrentThread());
+
+  weak_ptr_ = weak_factory_.GetWeakPtr();
+
   if (!WillGetGmbConfigFromGpu()) {
     native_configurations_ = gpu::GetNativeGpuMemoryBufferConfigurations(
         gpu_memory_buffer_support_.get());
@@ -85,10 +77,21 @@
 
 HostGpuMemoryBufferManager::~HostGpuMemoryBufferManager() {
   DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(shutdown_event_.IsSignaled());
+
   base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
       this);
 }
 
+void HostGpuMemoryBufferManager::Shutdown() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  shutdown_event_.Signal();
+
+  // Invalidate weak pointers so that any in flight requests are dropped.
+  weak_factory_.InvalidateWeakPtrs();
+}
+
 void HostGpuMemoryBufferManager::DestroyGpuMemoryBuffer(
     gfx::GpuMemoryBufferId id,
     int client_id,
@@ -146,8 +149,6 @@
     base::OnceCallback<void(gfx::GpuMemoryBufferHandle)> callback,
     bool call_sync) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  if (!weak_ptr_)
-    weak_ptr_ = weak_factory_.GetWeakPtr();
   if (CreateBufferUsesGpuService(format, usage)) {
     if (auto* gpu_service = GetGpuService()) {
       PendingBufferInfo buffer_info;
@@ -221,12 +222,15 @@
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
     gpu::SurfaceHandle surface_handle,
-    base::WaitableEvent* shutdown_event) {
+    base::WaitableEvent* cancel_event) {
+  if (shutdown_event_.IsSignaled()) {
+    // After Shutdown() runs this can abort early.
+    return nullptr;
+  }
+
   gfx::GpuMemoryBufferId id(next_gpu_memory_id_++);
   gfx::GpuMemoryBufferHandle handle;
-  base::WaitableEvent wait_event(
-      base::WaitableEvent::ResetPolicy::MANUAL,
-      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  base::WaitableEvent completion_event;
   bool call_sync = task_runner_->BelongsToCurrentThread();
 
   // A refcounted wrapper around a bool so that if the thread waiting on a
@@ -246,31 +250,38 @@
         *handle = std::move(allocated_buffer_handle);
         wait_event->Signal();
       },
-      cancelled, &handle, &wait_event);
-  // We block with a WaitableEvent until the callback is run. So using
-  // base::Unretained() is safe here.
-  auto allocate_callback = base::BindOnce(
-      &HostGpuMemoryBufferManager::AllocateGpuMemoryBuffer,
-      base::Unretained(this), id, client_id_, size, format, usage,
-      surface_handle, std::move(reply_callback), call_sync);
+      cancelled, &handle, &completion_event);
+
+  auto allocate_callback =
+      base::BindOnce(&HostGpuMemoryBufferManager::AllocateGpuMemoryBuffer,
+                     weak_ptr_, id, client_id_, size, format, usage,
+                     surface_handle, std::move(reply_callback), call_sync);
   if (call_sync) {
     std::move(allocate_callback).Run();
   } else {
     task_runner_->PostTask(FROM_HERE, std::move(allocate_callback));
     base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope
         allow_base_sync_primitives;
-    if (shutdown_event) {
-      // This class runs on the UI thread so TileManager::FinishTasksAndCleanUp
-      // could block on the worker thread where this task is running. That could
-      // in turn block on a task posted to the UI thread. We avoid this deadlock
-      // by having an event that TileManager can set to cancel this wait.
-      base::WaitableEvent* waitables[] = {&wait_event, shutdown_event};
-      size_t index =
-          base::WaitableEvent::WaitMany(waitables, std::size(waitables));
-      if (index == 1)
-        cancelled->data = true;
-    } else {
-      wait_event.Wait();
+
+    // There are up to three events waited on here:
+    // 1. `completion_event` is signaled when UI thread is done with the request
+    //    and the result is in `handle`.
+    // 2. `shutdown_event_` is signaled when HostGpuMemoryBufferManager is being
+    //    destroyed on browser shutdown. The UI thread blocks on thread pool
+    //    threads stopping during shutdown. A thread pool thread could block
+    //    here waiting on UI thread to complete the request. This avoids
+    //    deadlock by cancelling the pending requests.
+    // 3. `cancel_event` which is optionally provided by caller. For example,
+    //    TileManager::FinishTasksAndCleanUp() could block on the worker thread
+    //    where this task is running. That could in turn block on a task posted
+    //    to the UI thread. This avoids deadlock by having an event that
+    //    TileManager cancel this wait.
+    base::WaitableEvent* waitables[3] = {&completion_event, &shutdown_event_,
+                                         cancel_event};
+    size_t index =
+        base::WaitableEvent::WaitMany(waitables, cancel_event ? 3 : 2);
+    if (index > 0) {
+      cancelled->data = true;
     }
   }
 
@@ -281,8 +292,8 @@
   // onto the |task_runner_| thread to do the real work.
   return gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle(
       std::move(handle), size, format, usage,
-      base::BindOnce(
-          &OnGpuMemoryBufferDestroyed, task_runner_,
+      base::BindPostTask(
+          task_runner_,
           base::BindOnce(&HostGpuMemoryBufferManager::DestroyGpuMemoryBuffer,
                          weak_ptr_, id, client_id_)),
       this, pool_);
diff --git a/components/viz/host/host_gpu_memory_buffer_manager.h b/components/viz/host/host_gpu_memory_buffer_manager.h
index 658b74c9..9d4bc1c 100644
--- a/components/viz/host/host_gpu_memory_buffer_manager.h
+++ b/components/viz/host/host_gpu_memory_buffer_manager.h
@@ -13,7 +13,6 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/unsafe_shared_memory_pool.h"
 #include "base/memory/weak_ptr.h"
-#include "base/synchronization/atomic_flag.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/trace_event/memory_dump_provider.h"
@@ -32,7 +31,14 @@
 }
 
 // This GpuMemoryBufferManager implementation is for [de]allocating GPU memory
-// from the GPU process over the mojom.GpuService api.
+// from the GPU process over the mojom.GpuService api. Parts of this class,
+// namely methods in gpu::GpuMemoryBufferManager, are usable from any thread but
+// this class must be created and destroyed on the UI thread.
+//
+// Note: `Shutdown()` must be called before the class is destroyed. Shutdown()
+// should be called while other threads are still running to cancel any pending
+// requests and unblock waiting threads. This class should only be destroyed
+// after other threads are stopped to guarantee nothing is using it.
 class VIZ_HOST_EXPORT HostGpuMemoryBufferManager
     : public gpu::GpuMemoryBufferManager,
       public base::trace_event::MemoryDumpProvider {
@@ -61,6 +67,11 @@
 
   ~HostGpuMemoryBufferManager() override;
 
+  // Shutdown GpuMemoryBufferManager before it's destroyed. This will cancel any
+  // pending requests to CreateGpuMemoryBuffer() and unblock any threads waiting
+  // on requests. Must be called from UI thread.
+  void Shutdown();
+
   void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
                               int client_id,
                               const gpu::SyncToken& sync_token);
@@ -154,6 +165,9 @@
   const int client_id_;
   int next_gpu_memory_id_ = 1;
 
+  // Used to cancel pending requests on shutdown.
+  base::WaitableEvent shutdown_event_;
+
   std::unordered_map<int, PendingBuffers> pending_buffers_;
   std::unordered_map<int, AllocatedBuffers> allocated_buffers_;
 
diff --git a/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc b/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
index 36fbcba..0f9ccb7 100644
--- a/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
+++ b/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
@@ -13,10 +13,13 @@
 #include "base/clang_profiling_buildflags.h"
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "gpu/ipc/host/gpu_memory_buffer_support.h"
 #include "media/media_buildflags.h"
 #include "services/viz/privileged/mojom/gl/gpu_service.mojom.h"
@@ -268,7 +271,10 @@
   HostGpuMemoryBufferManagerTest& operator=(
       const HostGpuMemoryBufferManagerTest&) = delete;
 
-  ~HostGpuMemoryBufferManagerTest() override = default;
+  ~HostGpuMemoryBufferManagerTest() override {
+    if (gpu_memory_buffer_manager_)
+      gpu_memory_buffer_manager_->Shutdown();
+  }
 
   void SetUp() override {
     gpu_service_ = std::make_unique<TestGpuService>();
@@ -334,7 +340,7 @@
     return gpu_memory_buffer_manager_.get();
   }
 
- private:
+ protected:
   std::unique_ptr<TestGpuService> gpu_service_;
   std::unique_ptr<HostGpuMemoryBufferManager> gpu_memory_buffer_manager_;
 };
@@ -478,4 +484,47 @@
   EXPECT_FALSE(allocated_handle.is_null());
 }
 
+// Test that any pending CreateGpuMemoryBuffer() requests are cancelled, so
+// blocked threads stop waiting, on shutdown.
+TEST_F(HostGpuMemoryBufferManagerTest, CancelRequestsForShutdown) {
+  base::Thread threads[2] = {base::Thread("Thread1"), base::Thread("Thread2")};
+
+  for (auto& thread : threads) {
+    ASSERT_TRUE(thread.Start());
+    base::WaitableEvent create_wait;
+
+    // Call CreateGpuMemoryBuffer() from each thread. This thread will be
+    // waiting inside CreateGpuMemoryBuffer() when `gpu_memory_buffer_manager_`
+    // is destroyed.
+    thread.task_runner()->PostTask(
+        FROM_HERE, base::BindLambdaForTesting([this, &create_wait]() {
+          create_wait.Signal();
+          // This should block.
+          gpu_memory_buffer_manager_->CreateGpuMemoryBuffer(
+              gfx::Size(100, 100), gfx::BufferFormat::RGBA_8888,
+              gfx::BufferUsage::SCANOUT, gpu::kNullSurfaceHandle, nullptr);
+        }));
+    create_wait.Wait();
+  }
+
+  // This should shutdown HostGpuMemoryBufferManager and unblock the other
+  // threads.
+  gpu_memory_buffer_manager_->Shutdown();
+
+  // Stop the other threads to verify they aren't waiting.
+  for (auto& thread : threads)
+    thread.Stop();
+
+  // HostGpuMemoryBufferManager should be able to be safely destroyed after
+  //
+  gpu_memory_buffer_manager_.reset();
+
+  // Flush tasks posted back to main thread from CreateGpuMemoryBuffer() to make
+  // sure they are harmless.
+  base::RunLoop loop;
+  base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                   loop.QuitClosure());
+  loop.Run();
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc
index b10314d..50d89471 100644
--- a/components/viz/service/display/display_unittest.cc
+++ b/components/viz/service/display/display_unittest.cc
@@ -4555,7 +4555,7 @@
   void EnablePrediction() {
     base::FieldTrialParams params;
     params["predicted_points"] = ::features::kDraw1Point12Ms;
-    base::test::ScopedFeatureList::FeatureAndParams prediction_params = {
+    base::test::FeatureRefAndParams prediction_params = {
         features::kDrawPredictedInkPoint, params};
 
     feature_list_.Reset();
diff --git a/components/viz/service/display/overlay_candidate.cc b/components/viz/service/display/overlay_candidate.cc
index 814d8fb7..29b73871 100644
--- a/components/viz/service/display/overlay_candidate.cc
+++ b/components/viz/service/display/overlay_candidate.cc
@@ -7,10 +7,13 @@
 #include "cc/base/math_util.h"
 #include "components/viz/common/quads/shared_quad_state.h"
 #include "components/viz/common/quads/solid_color_draw_quad.h"
+#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/quads/yuv_video_draw_quad.h"
 #include "components/viz/service/debugger/viz_debugger.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/overlay_transform_utils.h"
+#include "ui/gfx/video_types.h"
 
 namespace viz {
 
@@ -44,9 +47,8 @@
                                   QuadList::ConstIterator quad_list_end) {
   // The rects are rounded as they're snapped by the compositor to pixel unless
   // it is AA'ed, in which case, it won't be overlaid.
-  gfx::RectF target_rect_f = candidate.display_rect;
-  candidate.TransformRectToTargetSpace(target_rect_f);
-  gfx::Rect target_rect = gfx::ToRoundedRect(target_rect_f);
+  gfx::Rect target_rect =
+      gfx::ToRoundedRect(DisplayRectInTargetSpace(candidate));
 
   // Check that no visible quad overlaps the candidate.
   for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
@@ -87,11 +89,33 @@
   }
 }
 
-void OverlayCandidate::TransformRectToTargetSpace(
-    gfx::RectF& content_rect) const {
-  if (absl::holds_alternative<gfx::Transform>(transform)) {
-    content_rect = absl::get<gfx::Transform>(transform).MapRect(content_rect);
+// static
+bool OverlayCandidate::RequiresOverlay(const DrawQuad* quad) {
+  // Regular priority hint.
+  switch (quad->material) {
+    case DrawQuad::Material::kTextureContent:
+      return TextureDrawQuad::MaterialCast(quad)->protected_video_type ==
+                 gfx::ProtectedVideoType::kHardwareProtected ||
+             TextureDrawQuad::MaterialCast(quad)->overlay_priority_hint ==
+                 OverlayPriority::kRequired;
+    case DrawQuad::Material::kVideoHole:
+      return true;
+    case DrawQuad::Material::kYuvVideoContent:
+      return YUVVideoDrawQuad::MaterialCast(quad)->protected_video_type ==
+             gfx::ProtectedVideoType::kHardwareProtected;
+    default:
+      return false;
   }
 }
 
+// static
+gfx::RectF OverlayCandidate::DisplayRectInTargetSpace(
+    const OverlayCandidate& candidate) {
+  if (absl::holds_alternative<gfx::Transform>(candidate.transform)) {
+    return absl::get<gfx::Transform>(candidate.transform)
+        .MapRect(candidate.display_rect);
+  }
+  return candidate.display_rect;
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display/overlay_candidate.h b/components/viz/service/display/overlay_candidate.h
index f7c8338e..cce64824 100644
--- a/components/viz/service/display/overlay_candidate.h
+++ b/components/viz/service/display/overlay_candidate.h
@@ -83,16 +83,17 @@
   // will be shown via an overlay.
   static bool RequiresOverlay(const DrawQuad* quad);
 
+  // Returns |candidate|'s |display_rect| transformed to its target space.
+  // If |candidate| holds an arbitrary transform, this will be the smallest axis
+  // aligned bounding rect containing |transform| applied to |display_rect|.
+  // If |candidate| holds an overlay transform, this will just be
+  // |display_rect|, which is already in its target space.
+  static gfx::RectF DisplayRectInTargetSpace(const OverlayCandidate& candidate);
+
   OverlayCandidate();
   OverlayCandidate(const OverlayCandidate& other);
   ~OverlayCandidate();
 
-  // Transform |content_rect| to target space. I.e. with |transform| applied.
-  // |content_rect| will be the smallest axis aligned bounding rect containing
-  // the transformed rect.
-  // This is a no-op if |transform| is |gfx::OverlayTransform|.
-  void TransformRectToTargetSpace(gfx::RectF& content_rect) const;
-
   // Transformation to apply to layer during composition.
   // Note: A |gfx::OverlayTransform| transforms the buffer within its bounds and
   // does not affect |display_rect|.
diff --git a/components/viz/service/display/overlay_candidate_factory.cc b/components/viz/service/display/overlay_candidate_factory.cc
index dbe73e8..7e634cf 100644
--- a/components/viz/service/display/overlay_candidate_factory.cc
+++ b/components/viz/service/display/overlay_candidate_factory.cc
@@ -248,33 +248,14 @@
       0.f, quad_damage.size().GetArea() - occluded_damage_estimate_total);
 }
 
-// static
-bool OverlayCandidate::RequiresOverlay(const DrawQuad* quad) {
-  // Regular priority hint.
-  switch (quad->material) {
-    case DrawQuad::Material::kTextureContent:
-      return TextureDrawQuad::MaterialCast(quad)->protected_video_type ==
-                 gfx::ProtectedVideoType::kHardwareProtected ||
-             TextureDrawQuad::MaterialCast(quad)->overlay_priority_hint ==
-                 OverlayPriority::kRequired;
-    case DrawQuad::Material::kVideoHole:
-      return true;
-    case DrawQuad::Material::kYuvVideoContent:
-      return YUVVideoDrawQuad::MaterialCast(quad)->protected_video_type ==
-             gfx::ProtectedVideoType::kHardwareProtected;
-    default:
-      return false;
-  }
-}
-
 bool OverlayCandidateFactory::IsOccludedByFilteredQuad(
     const OverlayCandidate& candidate,
     QuadList::ConstIterator quad_list_begin,
     QuadList::ConstIterator quad_list_end,
     const base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>&
         render_pass_backdrop_filters) const {
-  gfx::RectF target_rect = candidate.display_rect;
-  candidate.TransformRectToTargetSpace(target_rect);
+  gfx::RectF target_rect =
+      OverlayCandidate::DisplayRectInTargetSpace(candidate);
   for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
        ++overlap_iter) {
     if (overlap_iter->material == DrawQuad::Material::kAggregatedRenderPass) {
@@ -680,8 +661,8 @@
     // original surface. Here the |unassigned_surface_damage_| will contain all
     // unassigned damage and we use it to conservatively estimate the damage for
     // this quad. We limit the damage to the candidates quad rect in question.
-    gfx::RectF intersection = candidate.display_rect;
-    candidate.TransformRectToTargetSpace(intersection);
+    gfx::RectF intersection =
+        OverlayCandidate::DisplayRectInTargetSpace(candidate);
     intersection.Intersect(gfx::RectF(unassigned_surface_damage_));
     return intersection;
   }
diff --git a/components/viz/service/display/overlay_processor_ozone_unittest.cc b/components/viz/service/display/overlay_processor_ozone_unittest.cc
index 7d0eb5ab..e0cbaa7 100644
--- a/components/viz/service/display/overlay_processor_ozone_unittest.cc
+++ b/components/viz/service/display/overlay_processor_ozone_unittest.cc
@@ -263,10 +263,9 @@
 TEST(OverlayProcessorOzoneTest, ObserveHardwareCapabilites) {
   OverlayCandidateList candidates;
   // Enable 4 overlays
-  const std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-      feature_and_params_list = {{features::kEnableOverlayPrioritization, {}},
-                                 {features::kUseMultipleOverlays,
-                                  {{features::kMaxOverlaysParam, "4"}}}};
+  const std::vector<base::test::FeatureRefAndParams> feature_and_params_list = {
+      {features::kEnableOverlayPrioritization, {}},
+      {features::kUseMultipleOverlays, {{features::kMaxOverlaysParam, "4"}}}};
   base::test::ScopedFeatureList scoped_features;
   scoped_features.InitWithFeaturesAndParameters(feature_and_params_list, {});
   // When overlay prioritization is explicitly disabled (Lacros) we should
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index 42825f54..64025d2 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -738,10 +738,9 @@
  public:
   UseMultipleOverlaysTest() {
     // To use more than one overlay, we need to enable some features.
-    const std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        featureAndParamsList = {{features::kEnableOverlayPrioritization, {}},
-                                {features::kUseMultipleOverlays,
-                                 {{features::kMaxOverlaysParam, "4"}}}};
+    const std::vector<base::test::FeatureRefAndParams> featureAndParamsList = {
+        {features::kEnableOverlayPrioritization, {}},
+        {features::kUseMultipleOverlays, {{features::kMaxOverlaysParam, "4"}}}};
     scoped_features.InitWithFeaturesAndParameters(featureAndParamsList, {});
   }
 
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index 1778ee1a..21d25319 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -5158,7 +5158,7 @@
   virtual void EnablePrediction() {
     base::FieldTrialParams params;
     params["predicted_points"] = ::features::kDraw1Point12Ms;
-    base::test::ScopedFeatureList::FeatureAndParams prediction_params = {
+    base::test::FeatureRefAndParams prediction_params = {
         features::kDrawPredictedInkPoint, params};
 
     feature_list_.Reset();
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index 2fdf655..f206bd9 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -9263,87 +9263,6 @@
               testing::Optional(gfx::Rect(10, 10, 90, 90)));
 }
 
-TEST_F(SurfaceAggregatorWithResourcesTest, TransitionDirectiveFrameBehind) {
-  LocalSurfaceId local_surface_id(7u, base::UnguessableToken::Create());
-  SurfaceId surface_id(root_sink_->frame_sink_id(), local_surface_id);
-
-  // Create and submit a 'save' frame.
-  SendBeginFrame(root_sink_.get(), 1);
-  {
-    auto frame = BuildCompositorFrameWithResources({}, true, SurfaceId());
-    frame.metadata.transition_directives.emplace_back(
-        1, CompositorFrameTransitionDirective::Type::kSave,
-        CompositorFrameTransitionDirective::Effect::kCoverLeft);
-
-    root_sink_->SubmitCompositorFrame(local_surface_id, std::move(frame));
-    root_sink_->GetSurfaceAnimationManagerForTesting()
-        ->GetSurfaceSavedFrameStorageForTesting()
-        ->CompleteForTesting();
-  }
-  AggregateFrame(surface_id);
-
-  // Create and submit an 'animate' frame.
-  SendBeginFrame(root_sink_.get(), 2);
-  {
-    auto frame = BuildCompositorFrameWithResources({}, true, SurfaceId());
-    frame.metadata.transition_directives.emplace_back(
-        2, CompositorFrameTransitionDirective::Type::kAnimate);
-    root_sink_->SubmitCompositorFrame(local_surface_id, std::move(frame));
-  }
-  AggregateFrame(surface_id);
-
-  // Create and submit a frame with some resources.
-  SendBeginFrame(root_sink_.get(), 3);
-  {
-    std::vector<ResourceId> ids = {ResourceId(11), ResourceId(12),
-                                   ResourceId(13)};
-    SubmitCompositorFrameWithResources(ids, true, SurfaceId(), root_sink_.get(),
-                                       surface_id);
-  }
-  auto frame = AggregateFrame(surface_id);
-  auto count_textures = [](const AggregatedFrame& frame) {
-    size_t result = 0;
-    for (auto& render_pass : frame.render_pass_list) {
-      for (auto* quad : render_pass->quad_list) {
-        if (quad->material == DrawQuad::Material::kTextureContent)
-          ++result;
-      }
-    }
-    return result;
-  };
-  // We should have 4 referenced textures (1 from interpolation and 3 from the
-  // original frame).
-  EXPECT_EQ(count_textures(frame), 4u);
-
-  // At this point we will interpolate with the above frame (resources 11, 12,
-  // 13).
-  SendBeginFrame(root_sink_.get(), 4);
-  {
-    std::vector<ResourceId> ids = {ResourceId(15), ResourceId(16),
-                                   ResourceId(17)};
-    // This will cause an activation which will unref 11, 12, 13. So, the
-    // activation must also interpolate a new frame.
-    SubmitCompositorFrameWithResources(ids, true, SurfaceId(), root_sink_.get(),
-                                       surface_id);
-  }
-  // Ensure that the interpolated frame is not using unreffed resources
-  // (otherwise this would DCHECK).
-  frame = AggregateFrame(surface_id);
-  // We should have 4 referenced textures (1 from interpolation and 3 (different
-  // ones) from the original frame).
-  EXPECT_EQ(count_textures(frame), 4u);
-
-  ASSERT_EQ(3u, fake_client_.returned_resources().size());
-  ResourceId returned_ids[3];
-  for (size_t i = 0; i < 3; ++i) {
-    returned_ids[i] = fake_client_.returned_resources()[i].id;
-  }
-  // We expect that 11, 12, and 13 are now returned.
-  EXPECT_THAT(returned_ids,
-              testing::WhenSorted(testing::ElementsAreArray(
-                  {ResourceId(11), ResourceId(12), ResourceId(13)})));
-}
-
 INSTANTIATE_TEST_SUITE_P(,
                          SurfaceAggregatorValidSurfaceWithMergingPassesTest,
                          testing::Bool());
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index 7c13ec4..92de1f2f 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -223,19 +223,8 @@
   const auto& transition_directives =
       surface->GetActiveFrameMetadata().transition_directives;
   if (!transition_directives.empty()) {
-    bool started_animation =
-        surface_animation_manager_.ProcessTransitionDirectives(
-            transition_directives, surface);
-
-    // If we started an animation, then we must need a begin frame for the code
-    // below to work properly.
-    DCHECK(!started_animation || surface_animation_manager_.NeedsBeginFrame());
-
-    // The above call can cause us to start an animation, meaning we need begin
-    // frames. If that's the case, make sure to update the begin frame
-    // observation.
-    if (surface_animation_manager_.NeedsBeginFrame())
-      UpdateNeedsBeginFramesInternal();
+    surface_animation_manager_.ProcessTransitionDirectives(
+        transition_directives, surface);
   }
 
   // The directives above generate TransferableResources which are required to
@@ -243,18 +232,6 @@
   // must be done after processing directives above.
   surface_animation_manager_.ReplaceSharedElementResources(surface);
 
-  // If surface animation manager needs a frame, then we should interpolate
-  // here. Note that we also interpolate in OnBeginFrame. The reason for two
-  // calls is that we might not receive and active a frame from the client in
-  // time to draw, which is why OnBeginFrame interpolates and damages the
-  // surface. Here, we only interpolate in case we did receive a new frame. We
-  // always use the latest frame, because it may have new resources that need to
-  // be reffed by SurfaceAggregator. If we don't do this, then they will be
-  // unreffed and cleaned up causing a DCHECK in subsequent frames that do use
-  // the frame.
-  if (surface_animation_manager_.NeedsBeginFrame())
-    surface_animation_manager_.InterpolateFrame(surface);
-
   if (surface->surface_id() == last_activated_surface_id_)
     return;
 
@@ -866,53 +843,6 @@
     frame_timing_details_.clear();
     UpdateNeedsBeginFramesInternal();
   }
-
-  // Notify surface animation manager of the latest time and advance a frame if
-  // it needs a begin frame.
-  surface_animation_manager_.UpdateFrameTime(adjusted_args.frame_time);
-  if (surface_animation_manager_.NeedsBeginFrame()) {
-    surface_animation_manager_.NotifyFrameAdvanced();
-
-    // Interpolate the frame here, since it is a reliable spot during the
-    // animation.
-    if (surface_animation_manager_.NeedsBeginFrame()) {
-      if (last_activated_surface_id_.is_valid()) {
-        if (!send_begin_frame_to_client)
-          frame_sink_manager_->DidBeginFrame(frame_sink_id_, adjusted_args);
-
-        auto* surface =
-            surface_manager_->GetSurfaceForId(last_activated_surface_id_);
-        surface_animation_manager_.InterpolateFrame(surface);
-
-        BeginFrameAck ack =
-            surface->GetActiveOrInterpolatedFrame().metadata.begin_frame_ack;
-        // Ensure to mark this as having damage, even if the above call gives us
-        // the non-interpolated active frame with no damage. We need this to
-        // ensure we do a DrawAndSwap.
-        ack.has_damage = true;
-
-        // TODO(crbug.com/1182882): If a client frame is expected, we would not
-        // wait for it as a result of the SurfaceModified() call. This means
-        // that the client may end up delaying every other frame (essentially
-        // dropping any frame rate by half).
-        surface_manager_->SurfaceModified(last_activated_surface_id_, ack);
-
-        // If we didn't send a begin frame to the client, we should still finish
-        // the frame. Since we already finished interpolating, we should do that
-        // now. In cases where we did send a begin frame to client, this will be
-        // called from either `MaybeSubmitCompositorFrame()` or
-        // `DidNotProduceFrame()`.
-        if (!send_begin_frame_to_client && begin_frame_source_) {
-          begin_frame_source_->DidFinishFrame(this);
-          frame_sink_manager_->DidFinishFrame(frame_sink_id_, adjusted_args);
-        }
-      }
-    } else {
-      // If notifying causes us to stop needing frames, then update needs begin
-      // frames, in case we no longer are interested in receiving begin frames.
-      UpdateNeedsBeginFramesInternal();
-    }
-  }
 }
 
 const BeginFrameArgs& CompositorFrameSinkSupport::LastUsedBeginFrameArgs()
@@ -934,8 +864,7 @@
   needs_begin_frame_ =
       (client_needs_begin_frame_ || !frame_timing_details_.empty() ||
        !pending_surfaces_.empty() ||
-       (compositor_frame_callback_ && !callback_received_begin_frame_) ||
-       surface_animation_manager_.NeedsBeginFrame());
+       (compositor_frame_callback_ && !callback_received_begin_frame_));
 
   if (bundle_id_.has_value()) {
     // When bundled with other sinks, observation of BeginFrame notifications is
diff --git a/components/viz/service/transitions/surface_animation_manager.cc b/components/viz/service/transitions/surface_animation_manager.cc
index 027cf1fd..aedd3d1 100644
--- a/components/viz/service/transitions/surface_animation_manager.cc
+++ b/components/viz/service/transitions/surface_animation_manager.cc
@@ -42,109 +42,6 @@
 namespace viz {
 namespace {
 
-// Scale the overall duration to produce the opacity duration. Opacity
-// transitions which reveal an element (i.e., transition opacity from 0 -> 1)
-// should finish ahead of a translation. This way, you'll see the next page fade
-// into view and settle while fully opaque. Similarly, transitions which hide an
-// element (i.e., transition opacity from 1 -> 0) should, for a brief period,
-// animate with full opacity so the user can get a sense of the motion before
-// the element disappears.
-constexpr float kOpacityTransitionDurationScaleFactor = 0.8f;
-
-// When transitioning two elements we perform a set of animations :
-// a) An interpolation between the size of the elements.
-// b) A cross-fade between the pixel content of the elements, which includes
-//    opacity inherited from ancestors.
-// c) A transform animation to interpolate the screen space transform of the
-//    elements.
-// The animation at b) starts at a delay and runs for a duration proportional to
-// the total duration of the animation. The following constants define that
-// proportion.
-constexpr float kSharedOpacityTransitionDurationScaleFactor = 0.24f;
-constexpr float kSharedOpacityTransitionDelayScaleFactor = 0.24f;
-
-// When performing slides, the amount moved is proportional to the minimum
-// viewport dimension -- this controls that proportion.
-constexpr float kTranslationProportion = 0.05f;
-
-// When performing implosions or explosions layers grow or shrink. This value
-// determines the scaling done to achieve the larger of the two sizes.
-constexpr float kScaleProportion = 1.1f;
-
-constexpr base::TimeDelta kDefaultTransitionDuration = base::Milliseconds(250);
-constexpr base::TimeDelta kDefaultTransitionDelay = base::Milliseconds(0);
-
-void CreateAndAppendSrcTextureQuad(CompositorRenderPass* render_pass,
-                                   const gfx::Rect& output_rect,
-                                   const gfx::Transform& src_transform,
-                                   SkBlendMode blend_mode,
-                                   float src_opacity,
-                                   bool y_flipped,
-                                   ResourceId id) {
-  auto* src_quad_state = render_pass->CreateAndAppendSharedQuadState();
-  src_quad_state->SetAll(
-      /*quad_to_target_transform=*/src_transform,
-      /*quad_layer_rect=*/output_rect,
-      /*visible_layer_rect=*/output_rect,
-      /*mask_filter_info=*/gfx::MaskFilterInfo(),
-      /*clip_rect=*/absl::nullopt, /*are_contents_opaque=*/false,
-      /*opacity=*/src_opacity,
-      /*blend_mode=*/blend_mode, /*sorting_context_id=*/0);
-
-  auto* src_quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
-  float vertex_opacity[] = {1.f, 1.f, 1.f, 1.f};
-  src_quad->SetNew(
-      /*shared_quad_state=*/src_quad_state,
-      /*rect=*/output_rect,
-      /*visible_rect=*/output_rect,
-      /*needs_blending=*/true,
-      /*resource_id=*/id,
-      /*premultiplied_alpha=*/true,
-      /*uv_top_left=*/gfx::PointF(0, 0),
-      /*uv_bottom_right=*/gfx::PointF(1, 1),
-      /*background_color=*/SkColors::kTransparent,
-      /*vertex_opacity=*/vertex_opacity, y_flipped,
-      /*nearest_neighbor=*/false,
-      /*secure_output_only=*/false,
-      /*protected_video_type=*/gfx::ProtectedVideoType::kClear);
-}
-
-void CreateAndAppendSharedRenderPassDrawQuad(
-    CompositorRenderPass* render_pass,
-    const gfx::Rect& rect,
-    gfx::Transform transform,
-    float opacity,
-    CompositorRenderPassId render_pass_id,
-    SkBlendMode blend_mode,
-    const CompositorRenderPassDrawQuad& sample_quad) {
-  auto* quad_state = render_pass->CreateAndAppendSharedQuadState();
-  quad_state->SetAll(
-      /*quad_to_target_transform=*/transform,
-      /*quad_layer_rect=*/rect,
-      /*visible_layer_rect=*/rect,
-      /*mask_filter_info=*/gfx::MaskFilterInfo(),
-      /*clip_rect=*/absl::nullopt,
-      /*are_contents_opaque=*/false,
-      /*opacity=*/opacity,
-      /*blend_mode=*/blend_mode, /*sorting_context_id=*/0);
-
-  auto* quad =
-      render_pass->CreateAndAppendDrawQuad<CompositorRenderPassDrawQuad>();
-  quad->SetNew(
-      /*shared_quad_state=*/quad_state,
-      /*rect=*/rect,
-      /*visible_rect=*/rect,
-      /*render_pass_id=*/render_pass_id,
-      /*mask_resource_id=*/sample_quad.mask_resource_id(),
-      /*mask_uv_rect=*/sample_quad.mask_uv_rect,
-      /*mask_texture_size=*/sample_quad.mask_texture_size,
-      /*filters_scale=*/sample_quad.filters_scale,
-      /*filters_origin=*/sample_quad.filters_origin,
-      /*tex_coord_rect=*/sample_quad.tex_coord_rect,
-      /*force_anti_aliasing_off=*/sample_quad.force_anti_aliasing_off,
-      /*backdrop_filter_quality*/ sample_quad.backdrop_filter_quality);
-}
-
 // This function swaps a SharedElementDrawQuad with a RenderPassDrawQuad.
 // |target_render_pass| is the render pass where the SharedElementDrawQuad is
 // drawn.
@@ -232,72 +129,6 @@
       /*protected_video_type=*/gfx::ProtectedVideoType::kClear);
 }
 
-std::unique_ptr<gfx::AnimationCurve> CreateOpacityCurve(
-    float start_opacity,
-    float end_opacity,
-    base::TimeDelta duration,
-    base::TimeDelta delay,
-    gfx::FloatAnimationCurve::Target* target) {
-  auto float_curve = gfx::KeyframedFloatAnimationCurve::Create();
-
-  // The curve starts at opacity delay and runs for opacity animation, so it
-  // potentially has 3 points:
-  // time 0 == start opacity
-  // time 'delay' == start opacity
-  // time 'delay' + 'opacity_duration' == end opacity
-  // Opacity transitions do not need to ease in or out. By passing nullptr for
-  // the timing function here, we are choosing the "linear" timing function.
-  float_curve->AddKeyframe(
-      gfx::FloatKeyframe::Create(base::TimeDelta(), start_opacity, nullptr));
-  if (!delay.is_zero()) {
-    float_curve->AddKeyframe(
-        gfx::FloatKeyframe::Create(delay, start_opacity, nullptr));
-  }
-  float_curve->AddKeyframe(
-      gfx::FloatKeyframe::Create(duration + delay, end_opacity, nullptr));
-  float_curve->set_target(target);
-  return float_curve;
-}
-
-std::unique_ptr<gfx::AnimationCurve> CreateSizeCurve(
-    const gfx::SizeF& start_size,
-    base::TimeDelta duration,
-    base::TimeDelta delay,
-    std::unique_ptr<gfx::TimingFunction> timing_function,
-    gfx::SizeAnimationCurve::Target* target) {
-  auto size_curve = gfx::KeyframedSizeAnimationCurve::Create();
-  size_curve->AddKeyframe(gfx::SizeKeyframe::Create(
-      base::TimeDelta(), start_size, timing_function->Clone()));
-  if (!delay.is_zero()) {
-    size_curve->AddKeyframe(
-        gfx::SizeKeyframe::Create(delay, start_size, timing_function->Clone()));
-  }
-  size_curve->AddKeyframe(gfx::SizeKeyframe::Create(
-      duration + delay, start_size, std::move(timing_function)));
-  size_curve->set_target(target);
-  return size_curve;
-}
-
-std::unique_ptr<gfx::AnimationCurve> CreateTransformCurve(
-    const gfx::TransformOperations& start_transform,
-    const gfx::TransformOperations& end_transform,
-    base::TimeDelta duration,
-    base::TimeDelta delay,
-    std::unique_ptr<gfx::TimingFunction> timing_function,
-    gfx::TransformAnimationCurve::Target* target) {
-  auto transform_curve = gfx::KeyframedTransformAnimationCurve::Create();
-  transform_curve->AddKeyframe(gfx::TransformKeyframe::Create(
-      base::TimeDelta(), start_transform, timing_function->Clone()));
-  if (!delay.is_zero()) {
-    transform_curve->AddKeyframe(gfx::TransformKeyframe::Create(
-        delay, start_transform, timing_function->Clone()));
-  }
-  transform_curve->AddKeyframe(gfx::TransformKeyframe::Create(
-      duration + delay, end_transform, std::move(timing_function)));
-  transform_curve->set_target(target);
-  return transform_curve;
-}
-
 }  // namespace
 
 class SurfaceAnimationManager::StorageWithSurface {
@@ -327,10 +158,9 @@
   sequence_id_finished_callback_ = std::move(sequence_id_finished_callback);
 }
 
-bool SurfaceAnimationManager::ProcessTransitionDirectives(
+void SurfaceAnimationManager::ProcessTransitionDirectives(
     const std::vector<CompositorFrameTransitionDirective>& directives,
     Surface* active_surface) {
-  bool started_animation = false;
   StorageWithSurface storage(&surface_saved_frame_storage_, active_surface);
   for (auto& directive : directives) {
     // Don't process directives with sequence ids smaller than or equal to the
@@ -346,10 +176,6 @@
       case CompositorFrameTransitionDirective::Type::kSave:
         handled = ProcessSaveDirective(directive, storage);
         break;
-      case CompositorFrameTransitionDirective::Type::kAnimate:
-        handled = ProcessAnimateDirective(directive, storage);
-        started_animation |= handled;
-        break;
       case CompositorFrameTransitionDirective::Type::kAnimateRenderer:
         handled = ProcessAnimateRendererDirective(directive, storage);
         break;
@@ -365,7 +191,6 @@
     if (!handled)
       sequence_id_finished_callback_.Run(directive.sequence_id());
   }
-  return started_animation;
 }
 
 bool SurfaceAnimationManager::ProcessSaveDirective(
@@ -386,44 +211,6 @@
   return true;
 }
 
-bool SurfaceAnimationManager::ProcessAnimateDirective(
-    const CompositorFrameTransitionDirective& directive,
-    StorageWithSurface& storage) {
-  // We can only begin an animate if we are currently idle.
-  if (state_ != State::kIdle)
-    return false;
-
-  // |saved_textures_| are created before the animate directive if we're in
-  // a mode where the animation is driven by the renderer.
-  if (saved_textures_.has_value()) {
-    return false;
-  }
-
-  auto saved_frame = storage->TakeSavedFrame();
-  // We can't animate if we don't have a saved frame.
-  if (!saved_frame || !saved_frame->IsValid())
-    return false;
-
-  // Take the save directive.
-  save_directive_.emplace(saved_frame->directive());
-  animate_directive_.emplace(directive);
-
-  // Import the saved frame, which converts it to a ResourceFrame -- a structure
-  // which has transferable resources.
-  saved_textures_.emplace(
-      transferable_resource_tracker_.ImportResources(std::move(saved_frame)));
-
-  CreateRootAnimationCurves(saved_textures_->root.draw_data.size);
-  CreateSharedElementCurves();
-  TickAnimations(latest_time_);
-  state_ = State::kAnimating;
-
-  // If all animations are set with a 0 duration, we can directly jump to the
-  // last frame.
-  FinishAnimationIfNeeded();
-  return true;
-}
-
 bool SurfaceAnimationManager::ProcessAnimateRendererDirective(
     const CompositorFrameTransitionDirective& directive,
     StorageWithSurface& storage) {
@@ -459,461 +246,6 @@
   return true;
 }
 
-bool SurfaceAnimationManager::NeedsBeginFrame() const {
-  // If we're animating we need to keep pumping frames to advance the animation.
-  // If we're done, we require one more frame to switch back to idle state.
-  return HasRunningAnimations() || state_ == State::kLastFrame;
-}
-
-void SurfaceAnimationManager::TickAnimations(base::TimeTicks new_time) {
-  root_animation_.driver().Tick(new_time);
-  for (auto& shared : shared_animations_)
-    shared.driver().Tick(new_time);
-}
-
-bool SurfaceAnimationManager::HasRunningAnimations() const {
-  // We need to check root and all shared animations here since any of these
-  // animations could finish last.
-  if (root_animation_.driver().IsAnimating())
-    return true;
-
-  for (const auto& animation : shared_animations_) {
-    if (animation.driver().IsAnimating())
-      return true;
-  }
-
-  return false;
-}
-
-void SurfaceAnimationManager::NotifyFrameAdvanced() {
-  TickAnimations(latest_time_);
-
-  switch (state_) {
-    case State::kIdle:
-      NOTREACHED() << "We should not advance frames when idle";
-      break;
-    case State::kAnimatingRenderer:
-      NOTREACHED()
-          << "We should not advance frames during renderer driven animations";
-      break;
-    case State::kAnimating:
-      FinishAnimationIfNeeded();
-      break;
-    case State::kLastFrame:
-      FinalizeAndDisposeOfState();
-      break;
-  }
-}
-
-void SurfaceAnimationManager::FinishAnimationIfNeeded() {
-  DCHECK_EQ(state_, State::kAnimating);
-  DCHECK(saved_textures_.has_value());
-  DCHECK(save_directive_.has_value());
-  DCHECK(animate_directive_.has_value());
-
-  if (HasRunningAnimations())
-    return;
-
-  state_ = State::kLastFrame;
-  sequence_id_finished_callback_.Run(animate_directive_->sequence_id());
-}
-
-void SurfaceAnimationManager::FinalizeAndDisposeOfState() {
-  DCHECK_EQ(state_, State::kLastFrame);
-  DCHECK(saved_textures_.has_value());
-  // Set state to idle.
-  state_ = State::kIdle;
-
-  // Ensure to return the texture / unref it.
-  transferable_resource_tracker_.ReturnFrame(*saved_textures_);
-  saved_textures_.reset();
-
-  save_directive_.reset();
-  animate_directive_.reset();
-}
-
-void SurfaceAnimationManager::InterpolateFrame(Surface* surface) {
-  DCHECK(saved_textures_);
-  if (state_ == State::kLastFrame) {
-    surface->ResetInterpolatedFrame();
-    return;
-  }
-
-  const auto& active_frame = surface->GetActiveFrame();
-
-  CompositorFrame interpolated_frame;
-  interpolated_frame.metadata = active_frame.metadata.Clone();
-  interpolated_frame.resource_list = active_frame.resource_list;
-  interpolated_frame.resource_list.push_back(saved_textures_->root.resource);
-
-  gfx::Rect output_rect = active_frame.render_pass_list.back()->output_rect;
-  auto animation_pass = CreateAnimationCompositorRenderPass(output_rect);
-
-  CopyAndInterpolateSharedElements(active_frame.render_pass_list,
-                                   animation_pass.get(), &interpolated_frame);
-
-  bool src_on_top = false;
-  switch (save_directive_->effect()) {
-    case CompositorFrameTransitionDirective::Effect::kRevealRight:
-    case CompositorFrameTransitionDirective::Effect::kRevealLeft:
-    case CompositorFrameTransitionDirective::Effect::kRevealUp:
-    case CompositorFrameTransitionDirective::Effect::kRevealDown:
-    case CompositorFrameTransitionDirective::Effect::kExplode:
-    case CompositorFrameTransitionDirective::Effect::kFade:
-      src_on_top = true;
-      break;
-    default:
-      break;
-  }
-
-  gfx::Transform src_transform = root_animation_.src_transform().Apply();
-  gfx::Transform dst_transform = root_animation_.dst_transform().Apply();
-
-  // GPU textures are flipped but software bitmaps are not.
-  bool y_flipped = !saved_textures_->root.resource.is_software;
-
-  if (src_on_top) {
-    CreateAndAppendSrcTextureQuad(animation_pass.get(), output_rect,
-                                  src_transform, SkBlendMode::kSrcOver,
-                                  root_animation_.src_opacity(), y_flipped,
-                                  saved_textures_->root.resource.id);
-  }
-
-  auto* dst_quad_state = animation_pass->CreateAndAppendSharedQuadState();
-  dst_quad_state->SetAll(
-      /*quad_to_target_transform=*/dst_transform,
-      /*quad_layer_rect=*/output_rect,
-      /*visible_layer_rect=*/output_rect,
-      /*mask_filter_info=*/gfx::MaskFilterInfo(),
-      /*clip_rect=*/absl::nullopt,
-      /*are_contents_opaque=*/false,
-      /*opacity=*/root_animation_.dst_opacity(),
-      /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
-
-  auto* dst_quad =
-      animation_pass->CreateAndAppendDrawQuad<CompositorRenderPassDrawQuad>();
-  dst_quad->SetNew(
-      /*shared_quad_state=*/dst_quad_state,
-      /*rect=*/output_rect,
-      /*visible_rect=*/output_rect,
-      /*render_pass_id=*/active_frame.render_pass_list.back()->id,
-      /*mask_resource_id=*/kInvalidResourceId,
-      /*mask_uv_rect=*/gfx::RectF(),
-      /*mask_texture_size=*/gfx::Size(),
-      /*filters_scale=*/gfx::Vector2dF(),
-      /*filters_origin=*/gfx::PointF(),
-      /*tex_coord_rect=*/gfx::RectF(output_rect),
-      /*force_anti_aliasing_off=*/false,
-      /*backdrop_filter_quality*/ 1.0f);
-
-  if (!src_on_top) {
-    CreateAndAppendSrcTextureQuad(animation_pass.get(), output_rect,
-                                  src_transform, SkBlendMode::kSrcOver,
-                                  root_animation_.src_opacity(), y_flipped,
-                                  saved_textures_->root.resource.id);
-  }
-
-  interpolated_frame.render_pass_list.push_back(std::move(animation_pass));
-  surface->SetInterpolatedFrame(std::move(interpolated_frame));
-}
-
-std::unique_ptr<CompositorRenderPass>
-SurfaceAnimationManager::CreateAnimationCompositorRenderPass(
-    const gfx::Rect& output_rect) const {
-  // One quad for the root render pass, and expect that each shared texture is
-  // non-nullopt. Then we double it: 1 for the source frame, one for the
-  // destination frame.
-  size_t quad_size_limit = 2 * (1 + saved_textures_->shared.size());
-  // Reserve the same number of shared quad states as there are quads, since we
-  // expect each quad to have a separate shared quad state.
-  auto animation_pass =
-      CompositorRenderPass::Create(quad_size_limit, quad_size_limit);
-
-  // We create an animation pass before copying the existing frame, since we'll
-  // do a smart copy -- interpolating shared elements as we encounter them
-  // during the copy. As a result, we use id 1 here, since we don't know what is
-  // the maximum id yet, we'll update it after we do the copy.
-  animation_pass->SetNew(CompositorRenderPassId(1), output_rect, output_rect,
-                         gfx::Transform());
-  return animation_pass;
-}
-
-void SurfaceAnimationManager::CopyAndInterpolateSharedElements(
-    const std::vector<std::unique_ptr<CompositorRenderPass>>& source_passes,
-    CompositorRenderPass* animation_pass,
-    CompositorFrame* interpolated_frame) {
-  // First create a placeholder for the shared render passes. We need this to
-  // quickly check whether a compositor render pass is shared (i.e. do we need
-  // to do something special for this).
-  base::flat_map<CompositorRenderPassId, RenderPassDrawData> shared_draw_data;
-  for (const auto& shared_element : animate_directive_->shared_elements()) {
-    shared_draw_data.emplace(shared_element.render_pass_id,
-                             RenderPassDrawData());
-  }
-
-  // Now run through all the source passes, making a 'smart' copy and filtering
-  // based on whether the pass is a shared element or not. After this loop, we
-  // should have populated `shared_render_passes` with the shared passes, and
-  // `animation_draw_quads` with draw quads for those render passes. All other
-  // passes would have been copied and added into the interpolated frame.
-  CompositorRenderPassId max_id = CompositorRenderPassId(0);
-  TransitionUtils::FilterCallback filter_callback = base::BindRepeating(
-      &FilterSharedElementQuads, base::Unretained(&shared_draw_data));
-  for (auto& render_pass : source_passes) {
-    // First, clear the copy requests.
-    // TODO(vmpstr): Can we preserve these in some situations?
-    render_pass->copy_requests.clear();
-
-    // Get the max_id for any render pass, since we'll need to create new passes
-    // with ids that don't conflict with existing passes.
-    if (render_pass->id > max_id)
-      max_id = render_pass->id;
-
-    // Now do the pass copy, filtering shared element quads into
-    // `shared_draw_data` instead of the render pass.
-    auto pass_copy = TransitionUtils::CopyPassWithQuadFiltering(
-        *render_pass, filter_callback);
-
-    // If this is a shared pass, store it in `shared_draw_data`. Otherwise,
-    // put it directly into the interpolated frame since we don't need to do
-    // anything special with it.
-    auto shared_it = shared_draw_data.find(pass_copy->id);
-    if (shared_it != shared_draw_data.end()) {
-      RenderPassDrawData& data = shared_it->second;
-      data.render_pass = std::move(pass_copy);
-      data.opacity = TransitionUtils::ComputeAccumulatedOpacity(
-          source_passes, data.render_pass->id);
-    } else {
-      interpolated_frame->render_pass_list.emplace_back(std::move(pass_copy));
-    }
-  }
-
-  // Update the animation pass id to avoid conflicts.
-  max_id = animation_pass->id = TransitionUtils::NextRenderPassId(max_id);
-
-  const auto& shared_elements = animate_directive_->shared_elements();
-  for (size_t i = 0; i < shared_elements.size(); ++i) {
-    const CompositorRenderPassId& shared_pass_id =
-        shared_elements[i].render_pass_id;
-    SharedAnimationState& animation = shared_animations_[i];
-    auto& draw_data = shared_draw_data[shared_pass_id];
-    const absl::optional<TransferableResourceTracker::PositionedResource>&
-        src_texture = saved_textures_->shared[i];
-
-    const bool has_destination_pass =
-        draw_data.render_pass && draw_data.draw_quad;
-    const bool should_have_destination_pass = !shared_pass_id.is_null();
-    DCHECK(!has_destination_pass || should_have_destination_pass);
-
-    // We have to retarget the animations, whether or not we have a destination
-    // pass. Ideally we should only need an opacity curve (to fade out the src
-    // element) if the dest element is missing but we try to handle the dest
-    // element getting added or removed during the transition gracefully by
-    // pausing the animation to it's current state.
-    auto* opacity_model = animation.driver().GetKeyframeModel(
-        SharedAnimationState::kCombinedOpacity);
-    float target_opacity = 0.f;
-    if (has_destination_pass)
-      target_opacity = draw_data.opacity;
-    else if (should_have_destination_pass)
-      target_opacity = animation.combined_opacity();
-
-    // The |opacity_model| may be null since this animation can finish before
-    // animations for other elements.
-    if (opacity_model) {
-      opacity_model->Retarget(
-          latest_time_, SharedAnimationState::kCombinedOpacity, target_opacity);
-    }
-
-    auto* size_model =
-        animation.driver().GetKeyframeModel(SharedAnimationState::kContentSize);
-    gfx::SizeF target_size =
-        has_destination_pass
-            ? gfx::SizeF(draw_data.render_pass->output_rect.size())
-            : animation.content_size();
-    if (size_model) {
-      size_model->Retarget(latest_time_, SharedAnimationState::kContentSize,
-                           target_size);
-    } else {
-      animation.OnSizeAnimated(target_size, SharedAnimationState::kContentSize,
-                               nullptr);
-    }
-
-    auto* transform_model = animation.driver().GetKeyframeModel(
-        SharedAnimationState::kCombinedTransform);
-    gfx::TransformOperations target_transform_ops;
-    gfx::Transform end_transform(gfx::Transform::kSkipInitialization);
-    if (has_destination_pass) {
-      end_transform = draw_data.render_pass->transform_to_root_target;
-      // The mapping from dest pass origin to target buffer is done when drawing
-      // the dest pass to the intermediate transition pass (if used). So we
-      // exclude this translation from the transform here and add it when
-      // drawing the dest pass.
-      auto origin = draw_data.render_pass->output_rect.origin();
-      end_transform.Translate(origin.x(), origin.y());
-    } else {
-      end_transform = animation.combined_transform().Apply();
-    }
-    target_transform_ops.AppendMatrix(end_transform);
-
-    if (transform_model) {
-      transform_model->Retarget(latest_time_,
-                                SharedAnimationState::kCombinedTransform,
-                                target_transform_ops);
-    } else {
-      animation.OnTransformAnimated(target_transform_ops,
-                                    SharedAnimationState::kCombinedTransform,
-                                    nullptr);
-    }
-
-    // Now that we have updated the animations, we can append the interpolations
-    // to the animation pass.
-    const float content_opacity = animation.content_opacity();
-    const gfx::Size content_size = gfx::ToFlooredSize(animation.content_size());
-    const float combined_opacity = animation.combined_opacity();
-    const gfx::Transform combined_transform =
-        animation.combined_transform().Apply();
-
-    std::unique_ptr<CompositorRenderPass> transition_pass;
-    if (src_texture.has_value() && has_destination_pass) {
-      size_t num_of_quads = 2;
-      transition_pass =
-          CompositorRenderPass::Create(num_of_quads, num_of_quads);
-      gfx::Rect output_rect(content_size);
-      max_id = TransitionUtils::NextRenderPassId(max_id);
-      transition_pass->SetNew(max_id, output_rect, output_rect,
-                              combined_transform);
-    }
-
-    // The quad list is in front to back order. So adding the src texture first
-    // makes it so it draws on top of the dest texture.
-    if (src_texture.has_value()) {
-      bool y_flipped = !src_texture->resource.is_software;
-      gfx::Transform src_transform;
-      src_transform.Scale(static_cast<float>(content_size.width()) /
-                              src_texture->draw_data.size.width(),
-                          static_cast<float>(content_size.height()) /
-                              src_texture->draw_data.size.height());
-      float src_opacity = 1.f - content_opacity;
-
-      // Use kPlus mode to add the pixel values from src and destination
-      // textures. This ensures the blending pass is a no-op if the 2 have the
-      // same content.
-      SkBlendMode blend_mode = SkBlendMode::kPlus;
-
-      auto* pass_for_draw = transition_pass.get();
-      if (!pass_for_draw) {
-        pass_for_draw = animation_pass;
-        src_transform.PostConcat(combined_transform);
-        src_opacity *= combined_opacity;
-        blend_mode = SkBlendMode::kSrcOver;
-      }
-
-      CreateAndAppendSrcTextureQuad(
-          pass_for_draw, gfx::Rect(src_texture->draw_data.size), src_transform,
-          blend_mode, src_opacity, y_flipped, src_texture->resource.id);
-      interpolated_frame->resource_list.push_back(src_texture->resource);
-    }
-
-    if (!has_destination_pass)
-      continue;
-
-    // Now that we know we have a render pass destination, create a copy of the
-    // shared render pass, and update it with all the right values.
-    auto pass_copy = draw_data.render_pass->DeepCopy();
-    max_id = pass_copy->id = TransitionUtils::NextRenderPassId(max_id);
-    gfx::Vector2dF dest_scale(static_cast<float>(content_size.width()) /
-                                  pass_copy->output_rect.width(),
-                              static_cast<float>(content_size.height()) /
-                                  pass_copy->output_rect.height());
-    gfx::Point dest_origin = pass_copy->output_rect.origin();
-    pass_copy->transform_to_root_target = combined_transform;
-    pass_copy->transform_to_root_target.Scale(dest_scale.x(), dest_scale.y());
-    pass_copy->transform_to_root_target.Translate(-dest_origin.x(),
-                                                  -dest_origin.y());
-
-    auto* pass_for_draw = transition_pass.get();
-    gfx::Transform dest_transform;
-    dest_transform.Scale(dest_scale.x(), dest_scale.y());
-    dest_transform.Translate(-dest_origin.x(), -dest_origin.y());
-    float dest_opacity = content_opacity;
-
-    // Use kSrc mode to clear the intermediate texture used for blending with
-    // dest content.
-    SkBlendMode blend_mode = SkBlendMode::kSrc;
-    if (!pass_for_draw) {
-      pass_for_draw = animation_pass;
-      dest_transform.PostConcat(combined_transform);
-      dest_opacity *= combined_opacity;
-      blend_mode = SkBlendMode::kSrcOver;
-    }
-
-    CreateAndAppendSharedRenderPassDrawQuad(
-        pass_for_draw, draw_data.render_pass->output_rect, dest_transform,
-        dest_opacity, pass_copy->id, blend_mode, *draw_data.draw_quad);
-
-    // Finally, add the pass into the interpolated frame. Make sure this comes
-    // after CreateAndAppend* call, because we use a pass id, so we need to
-    // access the pass before moving it here.
-    interpolated_frame->render_pass_list.emplace_back(std::move(pass_copy));
-
-    if (transition_pass) {
-      auto* quad_state = animation_pass->CreateAndAppendSharedQuadState();
-      gfx::Rect rect(content_size);
-      quad_state->SetAll(
-          /*quad_to_target_transform=*/combined_transform,
-          /*quad_layer_rect=*/rect,
-          /*visible_layer_rect=*/rect,
-          /*mask_filter_info=*/gfx::MaskFilterInfo(),
-          /*clip_rect=*/absl::nullopt,
-          /*are_contents_opaque=*/false,
-          /*opacity=*/combined_opacity,
-          /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
-
-      auto* quad =
-          animation_pass
-              ->CreateAndAppendDrawQuad<CompositorRenderPassDrawQuad>();
-      quad->SetNew(
-          /*shared_quad_state=*/quad_state,
-          /*rect=*/rect,
-          /*visible_rect=*/rect,
-          /*render_pass_id=*/transition_pass->id,
-          /*mask_resource_id=*/kInvalidResourceId,
-          /*mask_uv_rect=*/gfx::RectF(),
-          /*mask_texture_size=*/gfx::Size(),
-          /*filters_scale=*/gfx::Vector2dF(),
-          /*filters_origin=*/gfx::PointF(),
-          /*tex_coord_rect=*/gfx::RectF(rect),
-          /*force_anti_aliasing_off=*/
-          draw_data.draw_quad->force_anti_aliasing_off,
-          /*backdrop_filter_quality=*/0.f);
-
-      interpolated_frame->render_pass_list.emplace_back(
-          std::move(transition_pass));
-    }
-  }
-}
-
-// static
-bool SurfaceAnimationManager::FilterSharedElementQuads(
-    base::flat_map<CompositorRenderPassId, RenderPassDrawData>*
-        shared_draw_data,
-    const DrawQuad& quad,
-    CompositorRenderPass& copy_pass) {
-  if (quad.material != DrawQuad::Material::kCompositorRenderPass)
-    return false;
-
-  const auto& pass_quad = *CompositorRenderPassDrawQuad::MaterialCast(&quad);
-  auto shared_it = shared_draw_data->find(pass_quad.render_pass_id);
-  // If the quad is shared, then add it to the `shared_draw_data`.
-  // Otherwise, it will be added to the copy pass directly.
-  if (shared_it != shared_draw_data->end()) {
-    shared_it->second.draw_quad = pass_quad;
-    return true;
-  }
-  return false;
-}
-
 void SurfaceAnimationManager::RefResources(
     const std::vector<TransferableResource>& resources) {
   if (transferable_resource_tracker_.is_empty())
@@ -934,256 +266,6 @@
   }
 }
 
-void SurfaceAnimationManager::UpdateFrameTime(base::TimeTicks now) {
-  latest_time_ = now;
-}
-
-void SurfaceAnimationManager::CreateRootAnimationCurves(
-    const gfx::Size& output_size) {
-  // A small translation. We want to roughly scale this with screen size, but
-  // we choose the minimum screen dimension to keep horizontal and vertical
-  // transitions consistent and to avoid the impact of very oblong screen.
-  const float delta = std::min(output_size.width(), output_size.height()) *
-                      kTranslationProportion;
-
-  gfx::TransformOperations start_transform;
-  gfx::TransformOperations end_transform;
-  int transform_property_id = RootAnimationState::kDstTransform;
-
-  float start_opacity = 0.0f;
-  float end_opacity = 1.0f;
-  int opacity_property_id = RootAnimationState::kDstOpacity;
-
-  DCHECK(save_directive_.has_value());
-
-  switch (save_directive_->effect()) {
-    case CompositorFrameTransitionDirective::Effect::kCoverLeft: {
-      start_transform.AppendTranslate(delta, 0.0f, 0.0f);
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kCoverRight: {
-      start_transform.AppendTranslate(-delta, 0.0f, 0.0f);
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kCoverUp: {
-      start_transform.AppendTranslate(0.0f, delta, 0.0f);
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kCoverDown: {
-      start_transform.AppendTranslate(0.0f, -delta, 0.0f);
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kRevealLeft: {
-      end_transform.AppendTranslate(-delta, 0.0f, 0.0f);
-      transform_property_id = RootAnimationState::kSrcTransform;
-      std::swap(start_opacity, end_opacity);
-      opacity_property_id = RootAnimationState::kSrcOpacity;
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kRevealRight: {
-      end_transform.AppendTranslate(delta, 0.0f, 0.0f);
-      transform_property_id = RootAnimationState::kSrcTransform;
-      std::swap(start_opacity, end_opacity);
-      opacity_property_id = RootAnimationState::kSrcOpacity;
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kRevealUp: {
-      end_transform.AppendTranslate(0.0f, -delta, 0.0f);
-      transform_property_id = RootAnimationState::kSrcTransform;
-      std::swap(start_opacity, end_opacity);
-      opacity_property_id = RootAnimationState::kSrcOpacity;
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kRevealDown: {
-      end_transform.AppendTranslate(0.0f, delta, 0.0f);
-      transform_property_id = RootAnimationState::kSrcTransform;
-      std::swap(start_opacity, end_opacity);
-      opacity_property_id = RootAnimationState::kSrcOpacity;
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kExplode: {
-      start_transform.AppendTranslate(output_size.width() * 0.5f,
-                                      output_size.height() * 0.5f, 0.0f);
-      start_transform.AppendScale(1.0f, 1.0f, 1.0f);
-      start_transform.AppendTranslate(-output_size.width() * 0.5f,
-                                      -output_size.height() * 0.5f, 0.0f);
-
-      end_transform.AppendTranslate(output_size.width() * 0.5f,
-                                    output_size.height() * 0.5f, 0.0f);
-      end_transform.AppendScale(kScaleProportion, kScaleProportion, 1.0f);
-      end_transform.AppendTranslate(-output_size.width() * 0.5f,
-                                    -output_size.height() * 0.5f, 0.0f);
-      transform_property_id = RootAnimationState::kSrcTransform;
-      std::swap(start_opacity, end_opacity);
-      opacity_property_id = RootAnimationState::kSrcOpacity;
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kFade: {
-      // Fade is effectively an explode with no scaling.
-      transform_property_id = RootAnimationState::kSrcTransform;
-      std::swap(start_opacity, end_opacity);
-      opacity_property_id = RootAnimationState::kSrcOpacity;
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kNone: {
-      transform_property_id = RootAnimationState::kSrcTransform;
-      start_opacity = end_opacity = 0.0f;
-      opacity_property_id = RootAnimationState::kSrcOpacity;
-      break;
-    }
-    case CompositorFrameTransitionDirective::Effect::kImplode: {
-      start_transform.AppendTranslate(output_size.width() * 0.5f,
-                                      output_size.height() * 0.5f, 0.0f);
-      start_transform.AppendScale(kScaleProportion, kScaleProportion, 1.0f);
-      start_transform.AppendTranslate(-output_size.width() * 0.5f,
-                                      -output_size.height() * 0.5f, 0.0f);
-
-      end_transform.AppendTranslate(output_size.width() * 0.5f,
-                                    output_size.height() * 0.5f, 0.0f);
-      end_transform.AppendScale(1.0f, 1.0f, 1.0f);
-      end_transform.AppendTranslate(-output_size.width() * 0.5f,
-                                    -output_size.height() * 0.5f, 0.0f);
-      break;
-    }
-  }
-
-  // Ensure we have no conflicting animation.
-  root_animation_.driver().RemoveAllKeyframeModels();
-
-  // We will use the ease in or ease out timing function (used by CSS
-  // transitions) depending on whether the the new content is being covered or
-  // revealed. If it's being covered, then we want to immediately start moving,
-  // but ease into position, eg.
-  std::unique_ptr<gfx::CubicBezierTimingFunction> timing_function =
-      gfx::CubicBezierTimingFunction::CreatePreset(
-          opacity_property_id == RootAnimationState::kSrcOpacity
-              ? gfx::CubicBezierTimingFunction::EaseType::EASE_IN
-              : gfx::CubicBezierTimingFunction::EaseType::EASE_OUT);
-
-  // Create the transform curve.
-  base::TimeDelta total_duration = kDefaultTransitionDuration;
-  base::TimeDelta total_delay = kDefaultTransitionDelay;
-
-  // The transform animation runs for the entire duration of the root
-  // transition.
-  auto transform_curve = CreateTransformCurve(
-      start_transform, end_transform, total_duration, total_delay,
-      timing_function->Clone(), &root_animation_);
-  root_animation_.driver().AddKeyframeModel(gfx::KeyframeModel::Create(
-      std::move(transform_curve), gfx::KeyframeEffect::GetNextKeyframeModelId(),
-      transform_property_id));
-
-  // Create the opacity curve. Somewhat more complicated because it may be
-  // delayed wrt to the transform curve. See description of
-  // |kOpacityTransitionDurationScaleFactor| above.
-  base::TimeDelta opacity_duration =
-      total_duration * kOpacityTransitionDurationScaleFactor;
-  base::TimeDelta opacity_delay = start_opacity == 0.0f
-                                      ? base::TimeDelta()
-                                      : total_duration - opacity_duration;
-
-  // Add a delay to offset the opacity animation by the delay for the entire
-  // root transition.
-  opacity_delay += total_delay;
-
-  auto opacity_curve =
-      CreateOpacityCurve(start_opacity, end_opacity, opacity_duration,
-                         opacity_delay, &root_animation_);
-  root_animation_.driver().AddKeyframeModel(gfx::KeyframeModel::Create(
-      std::move(opacity_curve), gfx::KeyframeEffect::GetNextKeyframeModelId(),
-      opacity_property_id));
-
-  // We should now have animations queued up.
-  DCHECK(root_animation_.driver().IsAnimating());
-
-  // To ensure we don't flicker at the beginning of the animation, ensure that
-  // our initial state is correct before we start ticking.
-  root_animation_.Reset();
-  root_animation_.OnTransformAnimated(start_transform, transform_property_id,
-                                      nullptr);
-  root_animation_.OnFloatAnimated(start_opacity, opacity_property_id, nullptr);
-}
-
-void SurfaceAnimationManager::CreateSharedElementCurves() {
-  DCHECK(animate_directive_.has_value());
-  // Clear and resize, to reset the shared animations state if any.
-  shared_animations_.clear();
-  shared_animations_.resize(animate_directive_->shared_elements().size());
-
-  // Since we don't have a target state yet, create animations as if all of the
-  // shared elements are targeted to stay in place with opacity going to 0.
-  for (size_t i = 0; i < saved_textures_->shared.size(); ++i) {
-    auto& shared = saved_textures_->shared[i];
-    auto& state = shared_animations_[i];
-    const bool has_src_element = shared.has_value();
-
-    const auto total_duration = kDefaultTransitionDuration;
-    const auto total_delay = kDefaultTransitionDelay;
-
-    const auto opacity_duration =
-        total_duration * kSharedOpacityTransitionDurationScaleFactor;
-    const auto opacity_delay =
-        total_delay +
-        (total_duration * kSharedOpacityTransitionDelayScaleFactor);
-
-    // The kSrcOpacity curve animates the screen space opacity applied to the
-    // blended content from src and dest elements. The value goes from the
-    // src element's opacity value to dest element's opacity value.
-    // - If the src element is missing, the start opacity is 0 to allow the dest
-    //   element to gradually fade in.
-    // - If the dest element is missing, the end opacity is 0 to allow the src
-    //   element to gradually fade out.
-    // The animation is re-targeted once the dest element values are known.
-    float start_opacity = has_src_element ? shared->draw_data.opacity : 0.f;
-    auto opacity_curve = CreateOpacityCurve(
-        start_opacity, 1.f, opacity_duration, opacity_delay, &state);
-    state.driver().AddKeyframeModel(gfx::KeyframeModel::Create(
-        std::move(opacity_curve), gfx::KeyframeEffect::GetNextKeyframeModelId(),
-        SharedAnimationState::kCombinedOpacity));
-
-    if (!has_src_element)
-      continue;
-
-    // The specific timing function is fine tuned for these effects.
-    auto ease_timing =
-        gfx::CubicBezierTimingFunction::Create(0.4, 0.0, 0.2, 1.0);
-
-    // Interpolation between the 2 textures involves an opacity animation (to
-    // cross-fade the content) and a scale animation to transition the content
-    // size.
-    auto content_size_curve =
-        CreateSizeCurve(gfx::SizeF(shared->draw_data.size), total_duration,
-                        total_delay, ease_timing->Clone(), &state);
-    state.driver().AddKeyframeModel(gfx::KeyframeModel::Create(
-        std::move(content_size_curve),
-        gfx::KeyframeEffect::GetNextKeyframeModelId(),
-        SharedAnimationState::kContentSize));
-    auto content_opacity_curve = CreateOpacityCurve(
-        /*start_opacity=*/0.f, /*end_opacity=*/1.f, opacity_duration,
-        opacity_delay, &state);
-    state.driver().AddKeyframeModel(gfx::KeyframeModel::Create(
-        std::move(content_opacity_curve),
-        gfx::KeyframeEffect::GetNextKeyframeModelId(),
-        SharedAnimationState::kContentOpacity));
-
-    // The screen space transform for the interpolated texture is animated from
-    // src element to dest element value. The animation is re-targeted once the
-    // dest element values are known.
-    // We use the same value for start and end transform since this animation
-    // will be targeted on the first frame when the end state for each shared
-    // element is known.
-    gfx::TransformOperations start_transform_ops;
-    start_transform_ops.AppendMatrix(shared->draw_data.target_transform);
-    auto transform_curve = CreateTransformCurve(
-        start_transform_ops, start_transform_ops, total_duration, total_delay,
-        ease_timing->Clone(), &state);
-    state.driver().AddKeyframeModel(gfx::KeyframeModel::Create(
-        std::move(transform_curve),
-        gfx::KeyframeEffect::GetNextKeyframeModelId(),
-        SharedAnimationState::kCombinedTransform));
-  }
-}
-
 bool SurfaceAnimationManager::FilterSharedElementsWithRenderPassOrResource(
     std::vector<TransferableResource>* resource_list,
     const base::flat_map<SharedElementResourceId, const CompositorRenderPass*>*
@@ -1255,19 +337,6 @@
   if (!active_frame.metadata.has_shared_element_resources)
     return;
 
-  // Replacing shared elements with resources is done in the following states :
-  // 1) When a transition is initiated. Shared elements are displayed using a
-  //    render pass until copy requests to cache them finishes executing.
-  // 2) When a renderer driven animation is in progress. The old shared elements
-  //    are represented using cached copy results while elements in the new DOM
-  //    use a render pass from the same frame.
-  // We shouldn't need to replace elements during a Viz driven animation.
-  if (state_ == State::kAnimating || state_ == State::kLastFrame) {
-    LOG(ERROR) << "Unexpected frame with shared element resources during viz "
-                  "animation";
-    return;
-  }
-
   // A frame created by resolving SharedElementResourceIds to their
   // corresponding static or live snapshot.
   DCHECK(!surface->HasInterpolatedFrame())
@@ -1309,85 +378,4 @@
   return &surface_saved_frame_storage_;
 }
 
-// RootAnimationState
-SurfaceAnimationManager::RootAnimationState::RootAnimationState() = default;
-SurfaceAnimationManager::RootAnimationState::RootAnimationState(
-    RootAnimationState&&) = default;
-SurfaceAnimationManager::RootAnimationState::~RootAnimationState() = default;
-
-void SurfaceAnimationManager::RootAnimationState::OnFloatAnimated(
-    const float& value,
-    int target_property_id,
-    gfx::KeyframeModel* keyframe_model) {
-  if (target_property_id == kDstOpacity) {
-    dst_opacity_ = value;
-  } else {
-    src_opacity_ = value;
-  }
-}
-
-void SurfaceAnimationManager::RootAnimationState::OnTransformAnimated(
-    const gfx::TransformOperations& operations,
-    int target_property_id,
-    gfx::KeyframeModel* keyframe_model) {
-  if (target_property_id == kDstTransform) {
-    dst_transform_ = operations;
-  } else {
-    src_transform_ = operations;
-  }
-}
-
-void SurfaceAnimationManager::RootAnimationState::Reset() {
-  src_opacity_ = 1.0f;
-  dst_opacity_ = 1.0f;
-  src_transform_ = gfx::TransformOperations();
-  dst_transform_ = gfx::TransformOperations();
-}
-
-SurfaceAnimationManager::SharedAnimationState::SharedAnimationState() = default;
-SurfaceAnimationManager::SharedAnimationState::SharedAnimationState(
-    SharedAnimationState&&) = default;
-SurfaceAnimationManager::SharedAnimationState::~SharedAnimationState() =
-    default;
-
-void SurfaceAnimationManager::SharedAnimationState::OnFloatAnimated(
-    const float& value,
-    int target_property_id,
-    gfx::KeyframeModel* keyframe_model) {
-  if (target_property_id == kContentOpacity) {
-    content_opacity_ = value;
-  } else {
-    DCHECK_EQ(target_property_id, kCombinedOpacity);
-    combined_opacity_ = value;
-  }
-}
-
-void SurfaceAnimationManager::SharedAnimationState::OnTransformAnimated(
-    const gfx::TransformOperations& operations,
-    int target_property_id,
-    gfx::KeyframeModel* keyframe_model) {
-  DCHECK_EQ(target_property_id, kCombinedTransform);
-  combined_transform_ = operations;
-}
-
-void SurfaceAnimationManager::SharedAnimationState::OnSizeAnimated(
-    const gfx::SizeF& value,
-    int target_property_id,
-    gfx::KeyframeModel* keyframe_model) {
-  DCHECK_EQ(target_property_id, kContentSize);
-  content_size_ = value;
-}
-
-void SurfaceAnimationManager::SharedAnimationState::Reset() {
-  content_opacity_ = 1.0f;
-  content_size_ = gfx::SizeF();
-  combined_opacity_ = 1.0f;
-  combined_transform_ = gfx::TransformOperations();
-}
-
-SurfaceAnimationManager::RenderPassDrawData::RenderPassDrawData() = default;
-SurfaceAnimationManager::RenderPassDrawData::RenderPassDrawData(
-    RenderPassDrawData&&) = default;
-SurfaceAnimationManager::RenderPassDrawData::~RenderPassDrawData() = default;
-
 }  // namespace viz
diff --git a/components/viz/service/transitions/surface_animation_manager.h b/components/viz/service/transitions/surface_animation_manager.h
index f1b5ef1e..102ad9ba 100644
--- a/components/viz/service/transitions/surface_animation_manager.h
+++ b/components/viz/service/transitions/surface_animation_manager.h
@@ -28,15 +28,11 @@
 namespace viz {
 
 class Surface;
-class CompositorFrame;
 struct ReturnedResource;
 struct TransferableResource;
 
 // This class is responsible for processing CompositorFrameTransitionDirectives,
 // and keeping track of the animation state.
-// TODO(vmpstr): This class should also be responsible for interpolating frames
-// and providing the result back to the surface, but that is currently not
-// implemented.
 class VIZ_SERVICE_EXPORT SurfaceAnimationManager {
  public:
   using TransitionDirectiveCompleteCallback =
@@ -51,33 +47,14 @@
   // Process any new transitions on the compositor frame metadata. Note that
   // this keeps track of the latest processed sequence id and repeated calls
   // with same sequence ids will have no effect.
-  // Uses `storage` for saving or retrieving animation parameters and saved
-  // frames.
-  // Returns true if this call caused an animation to begin. This is a signal
-  // that we need to interpolate the current active frame, even if we would
-  // normally not do so in the middle of the animation.
-  bool ProcessTransitionDirectives(
+  void ProcessTransitionDirectives(
       const std::vector<CompositorFrameTransitionDirective>& directives,
       Surface* active_surface);
 
-  // Returns true if this manager needs to observe begin frames to advance
-  // animations.
-  bool NeedsBeginFrame() const;
-
-  // Notify when a begin frame happens and a frame is advanced.
-  void NotifyFrameAdvanced();
-
-  // Interpolates from the saved frame to the current active frame on the
-  // surface, storing the result back on the surface.
-  void InterpolateFrame(Surface* surface);
-
   // Resource ref count management.
   void RefResources(const std::vector<TransferableResource>& resources);
   void UnrefResources(const std::vector<ReturnedResource>& resources);
 
-  // Updates the current frame time, without doing anything else.
-  void UpdateFrameTime(base::TimeTicks now);
-
   // Replaced SharedElementResourceIds with corresponding ResourceIds if
   // necessary.
   void ReplaceSharedElementResources(Surface* surface);
@@ -86,66 +63,16 @@
 
  private:
   friend class SurfaceAnimationManagerTest;
-  FRIEND_TEST_ALL_PREFIXES(SurfaceAnimationManagerTest, CustomRootConfig);
-  FRIEND_TEST_ALL_PREFIXES(SurfaceAnimationManagerTest, CustomSharedConfig);
-
   class StorageWithSurface;
 
-  struct RenderPassDrawData {
-    RenderPassDrawData();
-    RenderPassDrawData(RenderPassDrawData&&);
-    ~RenderPassDrawData();
-
-    RenderPassDrawData& operator=(RenderPassDrawData&&) = default;
-
-    std::unique_ptr<CompositorRenderPass> render_pass;
-    absl::optional<CompositorRenderPassDrawQuad> draw_quad;
-    float opacity = 1.f;
-  };
-
-  void CreateRootAnimationCurves(const gfx::Size& output_size);
-  void CreateSharedElementCurves();
-
   // Helpers to process specific directives.
   bool ProcessSaveDirective(const CompositorFrameTransitionDirective& directive,
                             StorageWithSurface& storage);
-  // Returns true if the animation has started.
-  bool ProcessAnimateDirective(
-      const CompositorFrameTransitionDirective& directive,
-      StorageWithSurface& storage);
   bool ProcessAnimateRendererDirective(
       const CompositorFrameTransitionDirective& directive,
       StorageWithSurface& storage);
   bool ProcessReleaseDirective();
 
-  // Finishes the animation and advance state to kLastFrame if it's time to do
-  // so. This call is only valid if state is kAnimating.
-  void FinishAnimationIfNeeded();
-
-  // Disposes of any saved state and switches state to kIdle. This call is only
-  // valid if state is kLastFrame.
-  void FinalizeAndDisposeOfState();
-
-  // A helper function to copy render passes, while interpolating shared
-  // elements.
-  void CopyAndInterpolateSharedElements(
-      const std::vector<std::unique_ptr<CompositorRenderPass>>& source_passes,
-      CompositorRenderPass* animation_pass,
-      CompositorFrame* interpolated_frame);
-
-  // Helper function to create an animation pass which interpolates needed
-  // components.
-  std::unique_ptr<CompositorRenderPass> CreateAnimationCompositorRenderPass(
-      const gfx::Rect& output_rect) const;
-
-  // Given a render pass, this makes a copy of it while filtering animated
-  // render pass draw quads.
-  static bool FilterSharedElementQuads(
-      base::flat_map<CompositorRenderPassId, RenderPassDrawData>*
-          shared_draw_data,
-      const DrawQuad& quad,
-      CompositorRenderPass& copy_pass);
-
   bool FilterSharedElementsWithRenderPassOrResource(
       std::vector<TransferableResource>* resource_list,
       const base::flat_map<SharedElementResourceId,
@@ -153,147 +80,18 @@
       const DrawQuad& quad,
       CompositorRenderPass& copy_pass);
 
-  // Tick both the root and shared animations.
-  void TickAnimations(base::TimeTicks new_time);
-
-  // Returns true if we have a running animation for root or shared elements.
-  bool HasRunningAnimations() const;
-
-  // The state machine can take the following paths :
-  // 1) Viz driven animation : kIdle -> kAnimating -> kLastFrame -> kIdle
-  // 2) Renderer driven animation : kIdle -> kAnimatingRenderer -> kIdle
-  enum class State { kIdle, kAnimatingRenderer, kAnimating, kLastFrame };
+  enum class State { kIdle, kAnimatingRenderer };
 
   TransitionDirectiveCompleteCallback sequence_id_finished_callback_;
 
   uint32_t last_processed_sequence_id_ = 0;
 
   TransferableResourceTracker transferable_resource_tracker_;
-
-  absl::optional<TransferableResourceTracker::ResourceFrame> saved_textures_;
-  absl::optional<CompositorFrameTransitionDirective> save_directive_;
-  absl::optional<CompositorFrameTransitionDirective> animate_directive_;
-
-  // State represents the total state of the animation for this manager. It is
-  // adjusted in step with the root animation. In other words, if the root
-  // animation ends then the total animation is considered (almost) ended as
-  // well. We keep track of a separate state, since we need to produce a
-  // kLastFrame value after the root animation ends which is responsible for
-  // produce a clean active frame without any interpolations.
-  State state_ = State::kIdle;
-
-  // This is the animation state for the root elements.
-  class RootAnimationState : public gfx::FloatAnimationCurve::Target,
-                             public gfx::TransformAnimationCurve::Target {
-   public:
-    RootAnimationState();
-    RootAnimationState(RootAnimationState&&);
-    ~RootAnimationState() override;
-
-    enum TargetProperty : int {
-      kSrcOpacity = 1,
-      kDstOpacity,
-      kSrcTransform,
-      kDstTransform,
-    };
-
-    void OnFloatAnimated(const float& value,
-                         int target_property_id,
-                         gfx::KeyframeModel* keyframe_model) override;
-
-    void OnTransformAnimated(const gfx::TransformOperations& operations,
-                             int target_property_id,
-                             gfx::KeyframeModel* keyframe_model) override;
-
-    void Reset();
-
-    gfx::KeyframeEffect& driver() { return driver_; }
-    const gfx::KeyframeEffect& driver() const { return driver_; }
-
-    float src_opacity() const { return src_opacity_; }
-    float dst_opacity() const { return dst_opacity_; }
-    const gfx::TransformOperations& src_transform() const {
-      return src_transform_;
-    }
-    const gfx::TransformOperations& dst_transform() const {
-      return dst_transform_;
-    }
-
-   private:
-    gfx::KeyframeEffect driver_;
-    float src_opacity_ = 1.0f;
-    float dst_opacity_ = 1.0f;
-    gfx::TransformOperations src_transform_;
-    gfx::TransformOperations dst_transform_;
-  };
-
-  // This is the animation state for a pair of shared elements.
-  class SharedAnimationState : public gfx::FloatAnimationCurve::Target,
-                               public gfx::TransformAnimationCurve::Target,
-                               public gfx::SizeAnimationCurve::Target {
-   public:
-    SharedAnimationState();
-    SharedAnimationState(SharedAnimationState&&);
-    ~SharedAnimationState() override;
-
-    enum TargetProperty : int {
-      // The following properties are used to blend the content of src and dest
-      // textues to produce a combined image.
-      kContentOpacity = 1,
-      kContentSize,
-
-      // The following properties are used when drawing the combined image to
-      // the target buffer.
-      kCombinedOpacity,
-      kCombinedTransform,
-    };
-
-    void OnFloatAnimated(const float& value,
-                         int target_property_id,
-                         gfx::KeyframeModel* keyframe_model) override;
-
-    void OnTransformAnimated(const gfx::TransformOperations& operations,
-                             int target_property_id,
-                             gfx::KeyframeModel* keyframe_model) override;
-
-    void OnSizeAnimated(const gfx::SizeF& value,
-                        int target_property_id,
-                        gfx::KeyframeModel* keyframe_model) override;
-
-    void Reset();
-
-    gfx::KeyframeEffect& driver() { return driver_; }
-    const gfx::KeyframeEffect& driver() const { return driver_; }
-
-    float content_opacity() const { return content_opacity_; }
-    const gfx::SizeF& content_size() const { return content_size_; }
-    float combined_opacity() const { return combined_opacity_; }
-    const gfx::TransformOperations& combined_transform() const {
-      return combined_transform_;
-    }
-
-   private:
-    gfx::KeyframeEffect driver_;
-    float content_opacity_ = 1.0f;
-    gfx::SizeF content_size_;
-    float combined_opacity_ = 1.0f;
-    gfx::TransformOperations combined_transform_;
-  };
-
-  // This is responsible for keeping track of the saved frame, accumulating copy
-  // output results.
   SurfaceSavedFrameStorage surface_saved_frame_storage_;
 
-  // This is the root animation state.
-  RootAnimationState root_animation_;
+  absl::optional<TransferableResourceTracker::ResourceFrame> saved_textures_;
 
-  // This is a vector of animation states for each of the shared elements. Note
-  // that the position in the vector matches both the position of the shared
-  // texture in the saved_textures_->shared vector and the corresponding
-  // position in the animate_directive->shared_render_pass_ids() vector.
-  std::vector<SharedAnimationState> shared_animations_;
-
-  base::TimeTicks latest_time_;
+  State state_ = State::kIdle;
 
   base::flat_set<SharedElementResourceId> empty_resource_ids_;
 };
diff --git a/components/viz/service/transitions/surface_animation_manager_unittest.cc b/components/viz/service/transitions/surface_animation_manager_unittest.cc
index 5b450f2..8a56d71 100644
--- a/components/viz/service/transitions/surface_animation_manager_unittest.cc
+++ b/components/viz/service/transitions/surface_animation_manager_unittest.cc
@@ -37,20 +37,18 @@
 constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
 
 std::vector<CompositorFrameTransitionDirective> CreateSaveDirectiveAsVector(
-    uint32_t sequence_id,
-    CompositorFrameTransitionDirective::Effect effect =
-        CompositorFrameTransitionDirective::Effect::kCoverDown) {
-  std::vector<CompositorFrameTransitionDirective> result;
-  result.emplace_back(sequence_id,
-                      CompositorFrameTransitionDirective::Type::kSave, effect);
-  return result;
-}
-
-std::vector<CompositorFrameTransitionDirective> CreateAnimateDirectiveAsVector(
     uint32_t sequence_id) {
   std::vector<CompositorFrameTransitionDirective> result;
   result.emplace_back(sequence_id,
-                      CompositorFrameTransitionDirective::Type::kAnimate);
+                      CompositorFrameTransitionDirective::Type::kSave);
+  return result;
+}
+
+std::vector<CompositorFrameTransitionDirective>
+CreateAnimateRendererDirectiveAsVector(uint32_t sequence_id) {
+  std::vector<CompositorFrameTransitionDirective> result;
+  result.emplace_back(
+      sequence_id, CompositorFrameTransitionDirective::Type::kAnimateRenderer);
   return result;
 }
 
@@ -59,7 +57,6 @@
 class SurfaceAnimationManagerTest : public testing::Test {
  public:
   void SetUp() override {
-    current_time_ = base::TimeTicks() + base::Days(1);
     surface_manager_ = frame_sink_manager_.surface_manager();
     support_ = std::make_unique<CompositorFrameSinkSupport>(
         nullptr, &frame_sink_manager_, kArbitraryFrameSinkId, /*is_root=*/true);
@@ -71,7 +68,6 @@
 
     manager_.emplace(&shared_bitmap_manager_);
     manager_->SetDirectiveFinishedCallback(base::DoNothing());
-    manager_->UpdateFrameTime(current_time_);
   }
 
   void TearDown() override {
@@ -79,11 +75,6 @@
     manager_.reset();
   }
 
-  base::TimeTicks AdvanceTime(base::TimeDelta delta) {
-    current_time_ += delta;
-    return current_time_;
-  }
-
   Surface* surface() {
     Surface* surface = surface_manager_->GetSurfaceForId(surface_id_);
     // Can't ASSERT in a non-void function, so just CHECK instead.
@@ -95,127 +86,9 @@
     return manager().GetSurfaceSavedFrameStorageForTesting();
   }
 
-  void ValidateStartState(CompositorFrameTransitionDirective::Effect effect) {
-    switch (effect) {
-      case CompositorFrameTransitionDirective::Effect::kRevealRight:
-      case CompositorFrameTransitionDirective::Effect::kRevealLeft:
-      case CompositorFrameTransitionDirective::Effect::kRevealUp:
-      case CompositorFrameTransitionDirective::Effect::kRevealDown:
-      case CompositorFrameTransitionDirective::Effect::kExplode:
-      case CompositorFrameTransitionDirective::Effect::kFade:
-        EXPECT_EQ(manager().root_animation_.src_opacity(), 1.0f)
-            << static_cast<int>(effect);
-        break;
-      case CompositorFrameTransitionDirective::Effect::kNone:
-        EXPECT_EQ(manager().root_animation_.src_opacity(), 0.0f)
-            << static_cast<int>(effect);
-        break;
-      default:
-        EXPECT_EQ(manager().root_animation_.dst_opacity(), 0.0f)
-            << static_cast<int>(effect);
-        break;
-    }
-
-    switch (effect) {
-      case CompositorFrameTransitionDirective::Effect::kNone:
-      case CompositorFrameTransitionDirective::Effect::kFade:
-      case CompositorFrameTransitionDirective::Effect::kExplode:
-      case CompositorFrameTransitionDirective::Effect::kRevealDown:
-      case CompositorFrameTransitionDirective::Effect::kRevealLeft:
-      case CompositorFrameTransitionDirective::Effect::kRevealRight:
-      case CompositorFrameTransitionDirective::Effect::kRevealUp:
-        EXPECT_TRUE(
-            manager().root_animation_.src_transform().Apply().IsIdentity())
-            << static_cast<int>(effect);
-        EXPECT_TRUE(
-            manager().root_animation_.dst_transform().Apply().IsIdentity())
-            << static_cast<int>(effect);
-        break;
-      case CompositorFrameTransitionDirective::Effect::kCoverDown:
-      case CompositorFrameTransitionDirective::Effect::kCoverLeft:
-      case CompositorFrameTransitionDirective::Effect::kCoverRight:
-      case CompositorFrameTransitionDirective::Effect::kCoverUp:
-        EXPECT_TRUE(
-            manager().root_animation_.src_transform().Apply().IsIdentity())
-            << static_cast<int>(effect);
-        EXPECT_FALSE(
-            manager().root_animation_.dst_transform().Apply().IsIdentity())
-            << static_cast<int>(effect);
-        EXPECT_TRUE(manager()
-                        .root_animation_.dst_transform()
-                        .Apply()
-                        .IsIdentityOr2DTranslation());
-        break;
-      case CompositorFrameTransitionDirective::Effect::kImplode:
-        EXPECT_TRUE(
-            manager().root_animation_.src_transform().Apply().IsIdentity())
-            << static_cast<int>(effect);
-        EXPECT_FALSE(
-            manager().root_animation_.dst_transform().Apply().IsIdentity())
-            << static_cast<int>(effect);
-        EXPECT_TRUE(manager()
-                        .root_animation_.dst_transform()
-                        .Apply()
-                        .IsScaleOrTranslation())
-            << static_cast<int>(effect);
-        break;
-      default:
-        break;
-    }
-  }
-
-  void ValidateEndState(CompositorFrameTransitionDirective::Effect effect) {
-    EXPECT_EQ(manager().root_animation_.dst_opacity(), 1.0f);
-    EXPECT_TRUE(manager().root_animation_.dst_transform().Apply().IsIdentity());
-
-    switch (effect) {
-      case CompositorFrameTransitionDirective::Effect::kRevealRight:
-      case CompositorFrameTransitionDirective::Effect::kRevealLeft:
-      case CompositorFrameTransitionDirective::Effect::kRevealUp:
-      case CompositorFrameTransitionDirective::Effect::kRevealDown:
-      case CompositorFrameTransitionDirective::Effect::kExplode:
-      case CompositorFrameTransitionDirective::Effect::kFade:
-        EXPECT_EQ(manager().root_animation_.src_opacity(), 0.0f)
-            << static_cast<int>(effect);
-        break;
-      default:
-        break;
-    }
-
-    switch (effect) {
-      case CompositorFrameTransitionDirective::Effect::kRevealDown:
-      case CompositorFrameTransitionDirective::Effect::kRevealLeft:
-      case CompositorFrameTransitionDirective::Effect::kRevealRight:
-      case CompositorFrameTransitionDirective::Effect::kRevealUp:
-        EXPECT_FALSE(
-            manager().root_animation_.src_transform().Apply().IsIdentity())
-            << static_cast<int>(effect);
-        EXPECT_TRUE(manager()
-                        .root_animation_.src_transform()
-                        .Apply()
-                        .IsIdentityOr2DTranslation())
-            << static_cast<int>(effect);
-        break;
-      case CompositorFrameTransitionDirective::Effect::kExplode:
-        EXPECT_FALSE(
-            manager().root_animation_.src_transform().Apply().IsIdentity())
-            << static_cast<int>(effect);
-        EXPECT_TRUE(manager()
-                        .root_animation_.src_transform()
-                        .Apply()
-                        .IsScaleOrTranslation())
-            << static_cast<int>(effect);
-        break;
-      default:
-        break;
-    }
-  }
-
   SurfaceAnimationManager& manager() { return *manager_; }
 
  protected:
-  base::TimeTicks current_time_;
-
   ServerSharedBitmapManager shared_bitmap_manager_;
   FrameSinkManagerImpl frame_sink_manager_{
       FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)};
@@ -226,154 +99,27 @@
   absl::optional<SurfaceAnimationManager> manager_;
 };
 
-TEST_F(SurfaceAnimationManagerTest, DefaultState) {
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-
-  manager().ProcessTransitionDirectives({}, surface());
-
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-}
-
-TEST_F(SurfaceAnimationManagerTest, SaveAnimateNeedsBeginFrame) {
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-
-  manager().ProcessTransitionDirectives(CreateSaveDirectiveAsVector(1),
-                                        surface());
-
-  storage()->CompleteForTesting();
-
-  manager().ProcessTransitionDirectives(CreateAnimateDirectiveAsVector(2),
-                                        surface());
-
-  // Tick curves to set start time.
-  manager().UpdateFrameTime(AdvanceTime(base::TimeDelta()));
-  manager().NotifyFrameAdvanced();
-
-  EXPECT_TRUE(manager().NeedsBeginFrame());
-
-  manager().UpdateFrameTime(AdvanceTime(base::Milliseconds(50)));
-  manager().NotifyFrameAdvanced();
-  EXPECT_TRUE(manager().NeedsBeginFrame());
-
-  manager().UpdateFrameTime(AdvanceTime(base::Milliseconds(500)));
-  manager().NotifyFrameAdvanced();
-  // We should be at the done state, but still need a frame.
-  EXPECT_TRUE(manager().NeedsBeginFrame());
-
-  manager().UpdateFrameTime(AdvanceTime(base::Milliseconds(1)));
-  manager().NotifyFrameAdvanced();
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-}
-
-TEST_F(SurfaceAnimationManagerTest, AnimateWithoutSaveIsNoop) {
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-
-  manager().ProcessTransitionDirectives(CreateAnimateDirectiveAsVector(1),
-                                        surface());
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-}
-
 TEST_F(SurfaceAnimationManagerTest, SaveTimesOut) {
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-
   manager().ProcessTransitionDirectives(CreateSaveDirectiveAsVector(1),
                                         surface());
-  EXPECT_FALSE(manager().NeedsBeginFrame());
 
   storage()->ExpireForTesting();
 
-  AdvanceTime(base::Seconds(6));
-  manager().ProcessTransitionDirectives(CreateAnimateDirectiveAsVector(2),
-                                        surface());
-  EXPECT_FALSE(manager().NeedsBeginFrame());
+  manager().ProcessTransitionDirectives(
+      CreateAnimateRendererDirectiveAsVector(2), surface());
 }
 
 TEST_F(SurfaceAnimationManagerTest, RepeatedSavesAreOk) {
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-
   uint32_t sequence_id = 1;
   for (int i = 0; i < 200; ++i) {
     manager().ProcessTransitionDirectives(
         CreateSaveDirectiveAsVector(sequence_id), surface());
-
-    EXPECT_FALSE(manager().NeedsBeginFrame());
-
-    ++sequence_id;
-    manager().UpdateFrameTime(AdvanceTime(base::Milliseconds(50)));
   }
 
   storage()->CompleteForTesting();
 
   manager().ProcessTransitionDirectives(
-      CreateAnimateDirectiveAsVector(sequence_id), surface());
-
-  // Tick curves to set start time.
-  manager().UpdateFrameTime(AdvanceTime(base::TimeDelta()));
-  manager().NotifyFrameAdvanced();
-
-  EXPECT_TRUE(manager().NeedsBeginFrame());
-
-  manager().UpdateFrameTime(AdvanceTime(base::Milliseconds(500)));
-  manager().NotifyFrameAdvanced();
-  // We're at the done state now.
-  EXPECT_TRUE(manager().NeedsBeginFrame());
-
-  manager().UpdateFrameTime(AdvanceTime(base::Milliseconds(1)));
-  manager().NotifyFrameAdvanced();
-  // Now we're idle.
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-}
-
-TEST_F(SurfaceAnimationManagerTest, CheckStartEndStates) {
-  EXPECT_FALSE(manager().NeedsBeginFrame());
-
-  CompositorFrameTransitionDirective::Effect effects[] = {
-      CompositorFrameTransitionDirective::Effect::kNone,
-      CompositorFrameTransitionDirective::Effect::kCoverDown,
-      CompositorFrameTransitionDirective::Effect::kCoverLeft,
-      CompositorFrameTransitionDirective::Effect::kCoverRight,
-      CompositorFrameTransitionDirective::Effect::kCoverUp,
-      CompositorFrameTransitionDirective::Effect::kExplode,
-      CompositorFrameTransitionDirective::Effect::kFade,
-      CompositorFrameTransitionDirective::Effect::kImplode,
-      CompositorFrameTransitionDirective::Effect::kRevealDown,
-      CompositorFrameTransitionDirective::Effect::kRevealLeft,
-      CompositorFrameTransitionDirective::Effect::kRevealRight,
-      CompositorFrameTransitionDirective::Effect::kRevealUp};
-
-  uint32_t sequence_id = 1;
-  for (auto effect : effects) {
-    manager().ProcessTransitionDirectives(
-        CreateSaveDirectiveAsVector(sequence_id++, effect), surface());
-
-    storage()->CompleteForTesting();
-
-    manager().ProcessTransitionDirectives(
-        CreateAnimateDirectiveAsVector(sequence_id++), surface());
-
-    // Tick curves to set start time.
-    manager().UpdateFrameTime(AdvanceTime(base::TimeDelta()));
-    manager().NotifyFrameAdvanced();
-
-    ValidateStartState(effect);
-
-    EXPECT_TRUE(manager().NeedsBeginFrame());
-
-    manager().UpdateFrameTime(AdvanceTime(base::Milliseconds(200)));
-    manager().NotifyFrameAdvanced();
-    EXPECT_TRUE(manager().NeedsBeginFrame());
-
-    manager().UpdateFrameTime(AdvanceTime(base::Milliseconds(200)));
-    manager().NotifyFrameAdvanced();
-    // We should be at the done state, but still need a frame.
-    EXPECT_TRUE(manager().NeedsBeginFrame());
-
-    manager().UpdateFrameTime(AdvanceTime(base::Milliseconds(1)));
-    manager().NotifyFrameAdvanced();
-    EXPECT_FALSE(manager().NeedsBeginFrame());
-
-    ValidateEndState(effect);
-  }
+      CreateAnimateRendererDirectiveAsVector(sequence_id), surface());
 }
 
 }  // namespace viz
diff --git a/components/webapps/browser/banners/app_banner_manager.cc b/components/webapps/browser/banners/app_banner_manager.cc
index dfab321..1be3445 100644
--- a/components/webapps/browser/banners/app_banner_manager.cc
+++ b/components/webapps/browser/banners/app_banner_manager.cc
@@ -136,6 +136,25 @@
   }
 };
 
+void TrackBeforeInstallEventPrompt(AppBannerManager::State state) {
+  switch (state) {
+    case AppBannerManager::State::SENDING_EVENT_GOT_EARLY_PROMPT:
+      TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_EARLY_PROMPT);
+      break;
+    case AppBannerManager::State::PENDING_PROMPT_CANCELED:
+      TrackBeforeInstallEvent(
+          BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT);
+      break;
+    case AppBannerManager::State::PENDING_PROMPT_NOT_CANCELED:
+      TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PROMPT_CALLED_NOT_CANCELED);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  TrackBeforeInstallEvent(
+      BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT);
+}
 }  // anonymous namespace
 
 // static
@@ -338,7 +357,8 @@
     case State::PENDING_ENGAGEMENT:
     case State::SENDING_EVENT:
     case State::SENDING_EVENT_GOT_EARLY_PROMPT:
-    case State::PENDING_PROMPT:
+    case State::PENDING_PROMPT_CANCELED:
+    case State::PENDING_PROMPT_NOT_CANCELED:
     case State::COMPLETE:
       NOTREACHED();
       return false;
@@ -517,23 +537,34 @@
 }
 
 void AppBannerManager::Terminate() {
-  if (state_ == State::PENDING_PROMPT) {
-    TrackBeforeInstallEvent(
-        BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT);
+  switch (state_) {
+    case State::PENDING_PROMPT_CANCELED:
+      TrackBeforeInstallEvent(
+          BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT);
+      break;
+    case State::PENDING_PROMPT_NOT_CANCELED:
+      TrackBeforeInstallEvent(
+          BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_NOT_CANCELLED);
+      break;
+    case State::PENDING_WORKER:
+      if (!passed_worker_check_)
+        TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER);
+      break;
+    case State::PENDING_ENGAGEMENT:
+      if (!has_sufficient_engagement_)
+        TrackDisplayEvent(DISPLAY_EVENT_NOT_VISITED_ENOUGH);
+      break;
+    default:
+      break;
   }
 
-  if (state_ == State::PENDING_WORKER && !passed_worker_check_)
-    TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER);
-
-  if (state_ == State::PENDING_ENGAGEMENT && !has_sufficient_engagement_)
-    TrackDisplayEvent(DISPLAY_EVENT_NOT_VISITED_ENOUGH);
-
   Stop(TerminationCode());
 }
 
 InstallableStatusCode AppBannerManager::TerminationCode() const {
   switch (state_) {
-    case State::PENDING_PROMPT:
+    case State::PENDING_PROMPT_CANCELED:
+    case State::PENDING_PROMPT_NOT_CANCELED:
       return RENDERER_CANCELLED;
     case State::PENDING_WORKER:
       return passed_worker_check_ ? NO_ERROR_DETECTED
@@ -740,7 +771,8 @@
     case State::PENDING_ENGAGEMENT:
     case State::SENDING_EVENT:
     case State::SENDING_EVENT_GOT_EARLY_PROMPT:
-    case State::PENDING_PROMPT:
+    case State::PENDING_PROMPT_CANCELED:
+    case State::PENDING_PROMPT_NOT_CANCELED:
       Terminate();
       [[fallthrough]];
     case State::COMPLETE:
@@ -801,7 +833,8 @@
 bool AppBannerManager::IsRunning() const {
   switch (state_) {
     case State::INACTIVE:
-    case State::PENDING_PROMPT:
+    case State::PENDING_PROMPT_CANCELED:
+    case State::PENDING_PROMPT_NOT_CANCELED:
     case State::PENDING_ENGAGEMENT:
     case State::COMPLETE:
       return false;
@@ -946,9 +979,12 @@
   }
 
   if (state_ == State::SENDING_EVENT) {
-    if (!event_canceled)
+    if (!event_canceled) {
       MaybeShowAmbientBadge();
-    UpdateState(State::PENDING_PROMPT);
+      UpdateState(State::PENDING_PROMPT_NOT_CANCELED);
+    } else {
+      UpdateState(State::PENDING_PROMPT_CANCELED);
+    }
     return;
   }
 
@@ -966,8 +1002,8 @@
   content::WebContents* contents = web_contents();
   WebappInstallSource install_source;
 
-  TrackBeforeInstallEvent(
-      BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT);
+  TrackBeforeInstallEventPrompt(state_);
+
   install_source =
       status_reporter_->GetInstallSource(contents, InstallTrigger::API);
 
@@ -996,7 +1032,8 @@
   // Prevent this from being called multiple times on the same connection.
   receiver_.reset();
 
-  if (state_ == State::PENDING_PROMPT) {
+  if (state_ == State::PENDING_PROMPT_CANCELED ||
+      state_ == State::PENDING_PROMPT_NOT_CANCELED) {
     ShowBanner();
   } else if (state_ == State::SENDING_EVENT) {
     // Log that the prompt request was made for when we get the prompt reply.
diff --git a/components/webapps/browser/banners/app_banner_manager.h b/components/webapps/browser/banners/app_banner_manager.h
index 688d9512..17481877 100644
--- a/components/webapps/browser/banners/app_banner_manager.h
+++ b/components/webapps/browser/banners/app_banner_manager.h
@@ -97,7 +97,11 @@
 
     // The pipeline has finished running, but is waiting for the web page to
     // call prompt() on the event.
-    PENDING_PROMPT,
+    PENDING_PROMPT_NOT_CANCELED,
+
+    // The pipeline has finished running, web page called preventdefault(),
+    // pipeline is waiting for the web page to call prompt() on the event.
+    PENDING_PROMPT_CANCELED,
 
     // The pipeline has finished running for this page load and no more
     // processing is to be done.
diff --git a/components/webapps/browser/banners/app_banner_metrics.h b/components/webapps/browser/banners/app_banner_metrics.h
index 717476ab..b1ce601 100644
--- a/components/webapps/browser/banners/app_banner_metrics.h
+++ b/components/webapps/browser/banners/app_banner_metrics.h
@@ -71,9 +71,15 @@
   BEFORE_INSTALL_EVENT_COMPLETE = 2,
   BEFORE_INSTALL_EVENT_NO_ACTION = 3,
   BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED = 4,
-  BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT = 5,
-  BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT = 6,
-  BEFORE_INSTALL_EVENT_MAX = 7,
+  // Deprecated: BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT = 5,
+  // Deprecated: BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT =
+  // 6,
+  BEFORE_INSTALL_EVENT_EARLY_PROMPT = 7,
+  BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT = 8,
+  BEFORE_INSTALL_EVENT_PROMPT_CALLED_NOT_CANCELED = 9,
+  BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT = 10,
+  BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_NOT_CANCELLED = 11,
+  BEFORE_INSTALL_EVENT_MAX = 12,
 };
 
 extern const char kDismissEventHistogram[];
diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
index 1f5898124..22b03d5 100644
--- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
+++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
@@ -500,8 +500,6 @@
   replacementRange.location += _availableTextOffset;
   [self insertText:selectedResult.replacementString
       replacementRange:replacementRange];
-
-  ui::LogTouchBarUMA(ui::TouchBarAction::TEXT_SUGGESTION);
 }
 
 - (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem*)anItem
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 5a032fa..e74b0020 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2399,8 +2399,6 @@
 
   if (is_win) {
     sources += [
-      "accessibility/accessibility_tree_formatter_uia_win.cc",
-      "accessibility/accessibility_tree_formatter_uia_win.h",
       "accessibility/accessibility_tree_formatter_win.cc",
       "accessibility/accessibility_tree_formatter_win.h",
       "accessibility/browser_accessibility_com_win.cc",
diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.cc b/content/browser/accessibility/accessibility_tree_formatter_win.cc
index 5f6e16aa..f3429964 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -21,7 +21,6 @@
 #include "base/win/scoped_bstr.h"
 #include "base/win/scoped_variant.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
-#include "content/browser/accessibility/accessibility_tree_formatter_uia_win.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/public/browser/ax_inspect_factory.h"
 #include "third_party/iaccessible2/ia2_api_all.h"
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 55cce7f..1fa1711b 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -1258,11 +1258,17 @@
       return ret;
     }
 
-    // If this container is multi-selectable and the focused child is selected,
-    // add the focused child in the list of selected children first, because
-    // this is how VoiceOver determines where to draw the focus ring around the
-    // active item.
-    if (focusedChild->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
+    // If this container is multi-selectable, the focused child should be
+    // the first item in the list of selected children regardless of whether
+    // it is selected or not, because this is how VoiceOver determines where to
+    // draw the focus ring around the active item.
+    //
+    // Not appending this item when focused but not selected would result in
+    // VoiceOver's focus ring jumping to the first selected item. It's unclear
+    // if this is by design or not, but VoiceOver folks confirmed offline that
+    // Safari always append the focused item, whether selected or not, to the
+    // list of selected items.
+    if (GetState(_owner, ax::mojom::State::kMultiselectable))
       [ret addObject:focusedChild->GetNativeViewAccessible()];
   }
 
diff --git a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
index f9481bd8..d6f7249 100644
--- a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
@@ -32,7 +32,6 @@
 constexpr const char kMacMethods[]{"mac/methods"};
 constexpr const char kMacParameterizedAttributes[]{
     "mac/parameterized-attributes"};
-constexpr const char kRegression[]{"mac/regression"};
 
 #endif
 
@@ -377,10 +376,6 @@
   RunTypedTest<kMacAction>("ax-press-button.html");
 }
 
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXSelected) {
-  RunTypedTest<kMacAttributes>("ax-selected.html");
-}
-
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXRequired) {
   RunTypedTest<kMacAttributes>("ax-required.html");
 }
@@ -389,6 +384,14 @@
   RunTypedTest<kMacAttributes>("ax-rows.html");
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXSelected) {
+  RunTypedTest<kMacAttributes>("ax-selected.html");
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXSelectedChildren) {
+  RunTypedTest<kMacAttributes>("ax-selected-children.html");
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXSelectedRows) {
   RunTypedTest<kMacAttributes>("ax-selected-rows.html");
 }
@@ -530,12 +533,6 @@
   RunTypedTest<kMacParameterizedAttributes>("ax-string-for-range.html");
 }
 
-// Regression tests
-
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXSelectedChildren) {
-  RunTypedTest<kRegression>("ax-selected-children.html");
-}
-
 #endif
 
 }  // namespace content
diff --git a/content/browser/aggregation_service/aggregatable_report.cc b/content/browser/aggregation_service/aggregatable_report.cc
index 45c86cc..445fe473 100644
--- a/content/browser/aggregation_service/aggregatable_report.cc
+++ b/content/browser/aggregation_service/aggregatable_report.cc
@@ -344,7 +344,8 @@
 
   return AggregatableReportRequest::Create(
       std::move(payload_contents.value()), std::move(shared_info.value()),
-      std::move(*request_proto.mutable_reporting_path()), debug_key);
+      std::move(*request_proto.mutable_reporting_path()), debug_key,
+      request_proto.failed_send_attempts());
 }
 
 void ConvertPayloadContentsToProto(
@@ -414,6 +415,7 @@
   if (request.debug_key().has_value()) {
     request_proto.set_debug_key(request.debug_key().value());
   }
+  request_proto.set_failed_send_attempts(request.failed_send_attempts());
 
   return request_proto;
 }
@@ -511,12 +513,13 @@
     AggregationServicePayloadContents payload_contents,
     AggregatableReportSharedInfo shared_info,
     std::string reporting_path,
-    absl::optional<uint64_t> debug_key) {
+    absl::optional<uint64_t> debug_key,
+    int failed_send_attempts) {
   std::vector<GURL> processing_urls =
       GetDefaultProcessingUrls(payload_contents.aggregation_mode);
   return CreateInternal(std::move(processing_urls), std::move(payload_contents),
                         std::move(shared_info), std::move(reporting_path),
-                        debug_key);
+                        debug_key, failed_send_attempts);
 }
 
 // static
@@ -526,10 +529,11 @@
     AggregationServicePayloadContents payload_contents,
     AggregatableReportSharedInfo shared_info,
     std::string reporting_path,
-    absl::optional<uint64_t> debug_key) {
+    absl::optional<uint64_t> debug_key,
+    int failed_send_attempts) {
   return CreateInternal(std::move(processing_urls), std::move(payload_contents),
                         std::move(shared_info), std::move(reporting_path),
-                        debug_key);
+                        debug_key, failed_send_attempts);
 }
 
 // static
@@ -539,7 +543,8 @@
     AggregationServicePayloadContents payload_contents,
     AggregatableReportSharedInfo shared_info,
     std::string reporting_path,
-    absl::optional<uint64_t> debug_key) {
+    absl::optional<uint64_t> debug_key,
+    int failed_send_attempts) {
   if (!AggregatableReport::IsNumberOfProcessingUrlsValid(
           processing_urls.size(), payload_contents.aggregation_mode)) {
     return absl::nullopt;
@@ -573,13 +578,18 @@
     return absl::nullopt;
   }
 
+  if (failed_send_attempts < 0) {
+    return absl::nullopt;
+  }
+
   // Ensure the ordering of urls is deterministic. This is required for
   // AggregatableReport construction later.
   base::ranges::sort(processing_urls);
 
   return AggregatableReportRequest(
       std::move(processing_urls), std::move(payload_contents),
-      std::move(shared_info), std::move(reporting_path), debug_key);
+      std::move(shared_info), std::move(reporting_path), debug_key,
+      failed_send_attempts);
 }
 
 AggregatableReportRequest::AggregatableReportRequest(
@@ -587,12 +597,14 @@
     AggregationServicePayloadContents payload_contents,
     AggregatableReportSharedInfo shared_info,
     std::string reporting_path,
-    absl::optional<uint64_t> debug_key)
+    absl::optional<uint64_t> debug_key,
+    int failed_send_attempts)
     : processing_urls_(std::move(processing_urls)),
       payload_contents_(std::move(payload_contents)),
       shared_info_(std::move(shared_info)),
       reporting_path_(std::move(reporting_path)),
-      debug_key_(debug_key) {}
+      debug_key_(debug_key),
+      failed_send_attempts_(failed_send_attempts) {}
 
 AggregatableReportRequest::AggregatableReportRequest(
     AggregatableReportRequest&& other) = default;
diff --git a/content/browser/aggregation_service/aggregatable_report.h b/content/browser/aggregation_service/aggregatable_report.h
index b709f93..d14298a0 100644
--- a/content/browser/aggregation_service/aggregatable_report.h
+++ b/content/browser/aggregation_service/aggregatable_report.h
@@ -265,13 +265,15 @@
   // `IsNumberOfHistogramContributionsValid()` above). Also returns
   // `absl::nullopt` if any contribution has a negative value, if
   // `shared_info.report_id` is not valid, or if `debug_key.has_value()` but
-  // `shared_info.debug_mode` is `kDisabled`.
+  // `shared_info.debug_mode` is `kDisabled`. Also returns `absl::nullopt` if
+  // `failed_send_attempts` is negative.
   // TODO(alexmt): Add validation for scheduled_report_time being non-null/inf.
   static absl::optional<AggregatableReportRequest> Create(
       AggregationServicePayloadContents payload_contents,
       AggregatableReportSharedInfo shared_info,
       std::string reporting_path = std::string(),
-      absl::optional<uint64_t> debug_key = absl::nullopt);
+      absl::optional<uint64_t> debug_key = absl::nullopt,
+      int failed_send_attempts = 0);
 
   // Returns `absl::nullopt` if `payload_contents.contributions.size()` or
   // `processing_url.size()` is not valid for the
@@ -280,13 +282,15 @@
   // `IsNumberOfProcessingUrlsValid`, respectively). Also returns
   // `absl::nullopt` if any contribution has a negative value, if
   // `shared_info.report_id` is not valid, or if `debug_key.has_value()` but
-  // `shared_info.debug_mode` is `kDisabled`.
+  // `shared_info.debug_mode` is `kDisabled`. Also returns `absl::nullopt` if
+  // `failed_send_attempts` is negative
   static absl::optional<AggregatableReportRequest> CreateForTesting(
       std::vector<GURL> processing_urls,
       AggregationServicePayloadContents payload_contents,
       AggregatableReportSharedInfo shared_info,
       std::string reporting_path = std::string(),
-      absl::optional<uint64_t> debug_key = absl::nullopt);
+      absl::optional<uint64_t> debug_key = absl::nullopt,
+      int failed_send_attempts = 0);
 
   // Deserializes a bytestring generated by `Serialize()`. Returns
   // `absl::nullopt` in the case of a deserialization error.
@@ -316,19 +320,23 @@
   // empty vector in case of an error.
   std::vector<uint8_t> Serialize();
 
+  int failed_send_attempts() const { return failed_send_attempts_; }
+
  private:
   static absl::optional<AggregatableReportRequest> CreateInternal(
       std::vector<GURL> processing_urls,
       AggregationServicePayloadContents payload_contents,
       AggregatableReportSharedInfo shared_info,
       std::string reporting_path,
-      absl::optional<uint64_t> debug_key);
+      absl::optional<uint64_t> debug_key,
+      int failed_send_attempts);
 
   AggregatableReportRequest(std::vector<GURL> processing_urls,
                             AggregationServicePayloadContents payload_contents,
                             AggregatableReportSharedInfo shared_info,
                             std::string reporting_path,
-                            absl::optional<uint64_t> debug_key);
+                            absl::optional<uint64_t> debug_key,
+                            int failed_send_attempts);
 
   std::vector<GURL> processing_urls_;
   AggregationServicePayloadContents payload_contents_;
@@ -342,6 +350,11 @@
   // Can only be set if `shared_info_.debug_mode` is `kEnabled` (but can still
   // be empty). Used as part of the temporary debugging mechanism.
   absl::optional<uint64_t> debug_key_;
+
+  // Number of times the browser has tried and failed to send this report before
+  // this attempt. The value in this class is not incremented if this attempt
+  // fails (until a new object is requested from storage)
+  int failed_send_attempts_ = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/aggregation_service/aggregatable_report_scheduler.cc b/content/browser/aggregation_service/aggregatable_report_scheduler.cc
index a27c918..e5c8982 100644
--- a/content/browser/aggregation_service/aggregatable_report_scheduler.cc
+++ b/content/browser/aggregation_service/aggregatable_report_scheduler.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/check.h"
+#include "base/check_op.h"
 #include "base/command_line.h"
 #include "base/containers/cxx20_erase.h"
 #include "base/location.h"
@@ -60,20 +61,47 @@
   storage_context_->GetStorage()
       .AsyncCall(&AggregationServiceStorage::DeleteRequest)
       .WithArgs(request_id)
-      .Then(base::BindOnce(&TimerDelegate::NotifyRequestCompleted,
+      .Then(base::BindOnce(&TimerDelegate::NotifySendAttemptCompleted,
                            timer_delegate_->GetWeakPtr(), request_id));
 }
 
-void AggregatableReportScheduler::NotifyInProgressRequestFailed(
-    AggregationServiceStorage::RequestId request_id) {
-  // TODO(crbug.com/1340040): Implement retry handling. Ideally also handle
-  // different errors differently. Also, ensure this composes well with offline
-  // handling.
+bool AggregatableReportScheduler::NotifyInProgressRequestFailed(
+    AggregationServiceStorage::RequestId request_id,
+    int previous_failed_attempts) {
+  DCHECK_GE(previous_failed_attempts, 0);
+  absl::optional<base::TimeDelta> delay =
+      GetFailedReportDelay(previous_failed_attempts + 1);
+
+  if (delay.has_value()) {
+    base::Time next_report_time = base::Time::Now() + *delay;
+    storage_context_->GetStorage()
+        .AsyncCall(&AggregationServiceStorage::UpdateReportForSendFailure)
+        .WithArgs(request_id, next_report_time)
+        .Then(base::BindOnce(&TimerDelegate::NotifySendAttemptCompleted,
+                             timer_delegate_->GetWeakPtr(), request_id));
+
+    timer_.MaybeSet(next_report_time);
+    return true;
+  }
+
+  // no retries left, dropping request
   storage_context_->GetStorage()
       .AsyncCall(&AggregationServiceStorage::DeleteRequest)
       .WithArgs(request_id)
-      .Then(base::BindOnce(&TimerDelegate::NotifyRequestCompleted,
+      .Then(base::BindOnce(&TimerDelegate::NotifySendAttemptCompleted,
                            timer_delegate_->GetWeakPtr(), request_id));
+  return false;
+}
+
+absl::optional<base::TimeDelta>
+AggregatableReportScheduler::GetFailedReportDelay(int failed_send_attempts) {
+  DCHECK_GT(failed_send_attempts, 0);
+
+  if (failed_send_attempts > kMaxRetries)
+    return absl::nullopt;
+
+  return kInitialRetryDelay *
+         std::pow(kRetryDelayFactor, failed_send_attempts - 1);
 }
 
 AggregatableReportScheduler::TimerDelegate::TimerDelegate(
@@ -128,7 +156,7 @@
       .Then(std::move(maybe_set_timer_cb));
 }
 
-void AggregatableReportScheduler::TimerDelegate::NotifyRequestCompleted(
+void AggregatableReportScheduler::TimerDelegate::NotifySendAttemptCompleted(
     AggregationServiceStorage::RequestId request_id) {
   in_progress_requests_.erase(request_id);
 }
diff --git a/content/browser/aggregation_service/aggregatable_report_scheduler.h b/content/browser/aggregation_service/aggregatable_report_scheduler.h
index c61bd25a..239ec4c 100644
--- a/content/browser/aggregation_service/aggregatable_report_scheduler.h
+++ b/content/browser/aggregation_service/aggregatable_report_scheduler.h
@@ -46,6 +46,11 @@
   static constexpr base::TimeDelta kOfflineReportTimeMaximumDelay =
       base::Minutes(1);
 
+  // Configuration for retrying to send reports that failed to send
+  static constexpr int kMaxRetries = 2;
+  static constexpr base::TimeDelta kInitialRetryDelay = base::Minutes(5);
+  static constexpr int kRetryDelayFactor = 3;
+
   AggregatableReportScheduler(
       AggregationServiceStorageContext* storage_context,
       base::RepeatingCallback<
@@ -72,9 +77,14 @@
 
   // Notifies that the request to assemble and send the report with `request_id`
   // completed unsuccessfully. There must be an in-progress request stored with
-  // that `request_id`.
-  virtual void NotifyInProgressRequestFailed(
-      AggregationServiceStorage::RequestId request_id);
+  // that `request_id`.`failed_attemps_before_sending` is the number of times
+  // that this request previously failed. ie. not counting the failure being
+  // notified on.
+  // Returns true when the request will be scheduled to be retried.
+  // Returns false when the request is dropped. ie. it wont be retried.
+  virtual bool NotifyInProgressRequestFailed(
+      AggregationServiceStorage::RequestId request_id,
+      int previous_failed_attempts);
 
   // TODO(crbug.com/1340042): Implement offline and startup handling
 
@@ -93,7 +103,7 @@
     TimerDelegate& operator=(TimerDelegate&&) = delete;
 
     // Notifies that we no longer need to track `request_id` as in-progress.
-    void NotifyRequestCompleted(
+    void NotifySendAttemptCompleted(
         AggregationServiceStorage::RequestId request_id);
 
     base::WeakPtr<AggregatableReportScheduler::TimerDelegate> GetWeakPtr() {
@@ -136,6 +146,14 @@
         weak_ptr_factory_{this};
   };
 
+  // Returns how long to wait before attempting to send a report that has
+  // previously failed to be sent failed_send_attempts times. Returns
+  // `absl::nullopt` to indicate that no more attempts should be made.
+  // Otherwise, the return value must be positive. `failed_send_attempts`
+  // must be positive.
+  static absl::optional<base::TimeDelta> GetFailedReportDelay(
+      int failed_send_attempts);
+
   // Using a raw reference is safe because `storage_context_` is guaranteed to
   // outlive `this`.
   raw_ref<AggregationServiceStorageContext> storage_context_;
diff --git a/content/browser/aggregation_service/aggregatable_report_scheduler_unittest.cc b/content/browser/aggregation_service/aggregatable_report_scheduler_unittest.cc
index 0c93a82..3b37d59 100644
--- a/content/browser/aggregation_service/aggregatable_report_scheduler_unittest.cc
+++ b/content/browser/aggregation_service/aggregatable_report_scheduler_unittest.cc
@@ -213,9 +213,8 @@
   }
 }
 
-// TODO(crbug.com/1340040): Update when retry handling is added.
 TEST_F(AggregatableReportSchedulerTest,
-       InProgressRequestFailed_DeletedFromStorage) {
+       FinalSendAttemptFailed_DeletedFromStorage) {
   AggregatableReportRequest example_request =
       aggregation_service::CreateExampleRequest();
 
@@ -251,8 +250,10 @@
   }
 
   // Request IDs are incremented from 1.
-  scheduler_->NotifyInProgressRequestFailed(
-      AggregationServiceStorage::RequestId(1));
+  bool will_retry = scheduler_->NotifyInProgressRequestFailed(
+      AggregationServiceStorage::RequestId(1),
+      /*previous_failed_attempts=*/AggregatableReportScheduler::kMaxRetries);
+  EXPECT_FALSE(will_retry);
   {
     base::RunLoop run_loop;
 
@@ -271,6 +272,99 @@
 }
 
 TEST_F(AggregatableReportSchedulerTest,
+       InProgressRequestFailed_UpdateStorageAndReschedule) {
+  AggregatableReportRequest example_request =
+      aggregation_service::CreateExampleRequest();
+
+  AggregatableReportSharedInfo expected_shared_info =
+      example_request.shared_info().Clone();
+  expected_shared_info.scheduled_report_time = kExampleTime;
+
+  auto request = AggregatableReportRequest::Create(
+      example_request.payload_contents(), std::move(expected_shared_info),
+      /*reporting_path=*/"", /*debug_key=*/absl::nullopt,
+      /*failed_send_attempts=*/0);
+  scheduler_->ScheduleRequest(std::move(request.value()));
+
+  base::TimeDelta fast_forward_required = kExampleTime - base::Time::Now();
+
+  int before_first_notification = 0;
+  int before_first_retry = 1;
+  int after_first_retry = 2;
+  int before_second_retry = 3;
+  int after_second_retry = 4;
+
+  Checkpoint checkpoint;
+  {
+    testing::InSequence seq;
+
+    EXPECT_CALL(mock_callback_, Run)
+        .Times(1);  // Called once for the initial request
+    EXPECT_CALL(checkpoint, Call(before_first_notification));
+
+    // First delay not expired yet
+    EXPECT_CALL(mock_callback_, Run).Times(0);
+    EXPECT_CALL(checkpoint, Call(before_first_retry));
+
+    // First retry done
+    EXPECT_CALL(mock_callback_, Run).Times(1);
+    EXPECT_CALL(checkpoint, Call(after_first_retry));
+
+    // Second delay not expired yet
+    EXPECT_CALL(mock_callback_, Run).Times(0);
+    EXPECT_CALL(checkpoint, Call(before_second_retry));
+
+    // Second retry done
+    EXPECT_CALL(mock_callback_, Run).Times(1);
+    EXPECT_CALL(checkpoint, Call(after_second_retry));
+  }
+
+  task_environment_.FastForwardBy(fast_forward_required);
+
+  checkpoint.Call(before_first_notification);
+
+  // Request is still in storage and its number of failed attempts has been
+  // incremented.
+  EXPECT_TRUE(scheduler_->NotifyInProgressRequestFailed(
+      AggregationServiceStorage::RequestId(1), /*previous_failed_attempts=*/0));
+  {
+    base::RunLoop run_loop;
+
+    storage_context_.GetStorage()
+        .AsyncCall(&AggregationServiceStorage::GetRequestsReportingOnOrBefore)
+        .WithArgs(base::Time::Max(), /*limit=*/absl::nullopt)
+        .Then(base::BindLambdaForTesting(
+            [&run_loop](std::vector<AggregationServiceStorage::RequestAndId>
+                            requests_and_ids) {
+              EXPECT_EQ(requests_and_ids.size(), 1u);
+              EXPECT_EQ(requests_and_ids[0].request.failed_send_attempts(), 1);
+              run_loop.Quit();
+            }));
+
+    run_loop.Run();
+  }
+
+  task_environment_.FastForwardBy(base::Minutes(5) - base::Microseconds(1));
+  checkpoint.Call(before_first_retry);
+
+  task_environment_.FastForwardBy(base::Microseconds(1));
+  checkpoint.Call(after_first_retry);
+
+  EXPECT_TRUE(scheduler_->NotifyInProgressRequestFailed(
+      AggregationServiceStorage::RequestId(1), 1));
+
+  task_environment_.FastForwardBy(base::Minutes(15) - base::Microseconds(1));
+  checkpoint.Call(before_second_retry);
+
+  task_environment_.FastForwardBy(base::Microseconds(1));
+  checkpoint.Call(after_second_retry);
+
+  // It should not retry anymore
+  EXPECT_FALSE(scheduler_->NotifyInProgressRequestFailed(
+      AggregationServiceStorage::RequestId(1), /*previous_failed_attempts=*/2));
+}
+
+TEST_F(AggregatableReportSchedulerTest,
        MultipleRequests_RetrievedAtAppropriateTime) {
   // Test both simultaneous and non-simultaneous reports.
   std::vector<base::Time> scheduled_report_times = {
diff --git a/content/browser/aggregation_service/aggregatable_report_unittest.cc b/content/browser/aggregation_service/aggregatable_report_unittest.cc
index 51d4d5c..4bf44d80 100644
--- a/content/browser/aggregation_service/aggregatable_report_unittest.cc
+++ b/content/browser/aggregation_service/aggregatable_report_unittest.cc
@@ -587,6 +587,40 @@
             example_request.shared_info().reporting_origin.GetURL());
 }
 
+TEST(AggregatableReportTest, RequestCreatedWithInvalidFailedAttempt_Failed) {
+  AggregatableReportRequest example_request =
+      aggregation_service::CreateExampleRequest();
+  AggregatableReportSharedInfo shared_info =
+      example_request.shared_info().Clone();
+
+  absl::optional<AggregatableReportRequest> request =
+      AggregatableReportRequest::Create(
+          example_request.payload_contents(), std::move(shared_info),
+          /*reporting_path=*/"", /*debug_key=*/absl::nullopt,
+          /*failed_send_attempts=*/-1);
+
+  EXPECT_FALSE(request.has_value());
+}
+
+TEST(AggregatableReportTest, FailedSendAttempts) {
+  AggregatableReportRequest example_request =
+      aggregation_service::CreateExampleRequest();
+
+  // Requests are initialized with no failed attempts by default
+  EXPECT_EQ(example_request.failed_send_attempts(), 0);
+
+  AggregatableReportRequest example_request_with_failed_attempts =
+      aggregation_service::CreateExampleRequest(
+          /*aggregation_mode=*/mojom::AggregationServiceMode::kDefault,
+          /*failed_send_attempts=*/2);
+
+  // The failed attempts are correctly serialized & deserialized
+  std::vector<uint8_t> proto = example_request_with_failed_attempts.Serialize();
+  absl::optional<AggregatableReportRequest> parsed_request =
+      AggregatableReportRequest::Deserialize(proto);
+  EXPECT_EQ(parsed_request.value().failed_send_attempts(), 2);
+}
+
 TEST(AggregatableReportTest, ReportingPathEmpty_NotSetInRequest) {
   AggregatableReportRequest example_request =
       aggregation_service::CreateExampleRequest(
@@ -615,9 +649,10 @@
   EXPECT_EQ(report_json_string, kExpectedJsonString);
 }
 
-TEST(AggregatableReportProtoMigrationTest, NoDebugKey_ParsesCorrectly) {
+TEST(AggregatableReportProtoMigrationTest,
+     NoDebugKeyOrFailedSendAttempts_ParsesCorrectly) {
   // An `AggregatableReport` serialized before the addition of the `debug_key`
-  // field.
+  // field and `failed_send_attempts` field.
   const char kHexEncodedOldProto[] =
       "0A071205107B18C803126208D0DA8693FDBECF17122431323334353637382D393061622D"
       "346364652D386631322D3334353637383930616263641A1368747470733A2F2F6578616D"
@@ -648,7 +683,8 @@
               /*additional_fields=*/base::Value::Dict(),
               /*api_version=*/"example-version",
               /*api_identifier=*/"example-api"),
-          /*reporting_path=*/"example-path", /*debug_key=*/absl::nullopt)
+          /*reporting_path=*/"example-path", /*debug_key=*/absl::nullopt,
+          /*failed_send_attempts=*/0)
           .value();
 
   EXPECT_TRUE(aggregation_service::ReportRequestsEqual(
diff --git a/content/browser/aggregation_service/aggregation_service_impl.cc b/content/browser/aggregation_service/aggregation_service_impl.cc
index 7a97466e..82732a9 100644
--- a/content/browser/aggregation_service/aggregation_service_impl.cc
+++ b/content/browser/aggregation_service/aggregation_service_impl.cc
@@ -176,14 +176,17 @@
   if (!report.has_value()) {
     std::move(done).Run();
 
-    scheduler_->NotifyInProgressRequestFailed(request_id);
-    NotifyReportHandled(
-        AggregationServiceStorage::RequestAndId{
-            .request = std::move(report_request),
-            .id = request_id,
-        },
-        /*report=*/absl::nullopt,
-        AggregationServiceObserver::ReportStatus::kFailedToAssemble);
+    bool will_retry = scheduler_->NotifyInProgressRequestFailed(
+        request_id, report_request.failed_send_attempts());
+    if (!will_retry) {
+      NotifyReportHandled(
+          AggregationServiceStorage::RequestAndId{
+              .request = std::move(report_request),
+              .id = request_id,
+          },
+          /*report=*/absl::nullopt,
+          AggregationServiceObserver::ReportStatus::kFailedToAssemble);
+    }
     NotifyRequestStorageModified();
     return;
   }
@@ -213,20 +216,25 @@
   std::move(done).Run();
 
   AggregationServiceObserver::ReportStatus observer_status;
+  bool will_retry;
   switch (status) {
     case AggregatableReportSender::RequestStatus::kOk:
       observer_status = AggregationServiceObserver::ReportStatus::kSent;
       scheduler_->NotifyInProgressRequestSucceeded(request_and_id.id);
+      will_retry = false;
       break;
     case AggregatableReportSender::RequestStatus::kNetworkError:
     case AggregatableReportSender::RequestStatus::kServerError:
       observer_status = AggregationServiceObserver::ReportStatus::kFailedToSend;
-      scheduler_->NotifyInProgressRequestFailed(request_and_id.id);
+      will_retry = scheduler_->NotifyInProgressRequestFailed(
+          request_and_id.id, request_and_id.request.failed_send_attempts());
       break;
   }
+  if (!will_retry) {
+    NotifyReportHandled(std::move(request_and_id), std::move(report),
+                        observer_status);
+  }
 
-  NotifyReportHandled(std::move(request_and_id), std::move(report),
-                      observer_status);
   NotifyRequestStorageModified();
 }
 
@@ -310,4 +318,4 @@
   }
 }
 
-}  // namespace content
\ No newline at end of file
+}  // namespace content
diff --git a/content/browser/aggregation_service/aggregation_service_impl_unittest.cc b/content/browser/aggregation_service/aggregation_service_impl_unittest.cc
index cafeef7..cb2f0e8 100644
--- a/content/browser/aggregation_service/aggregation_service_impl_unittest.cc
+++ b/content/browser/aggregation_service/aggregation_service_impl_unittest.cc
@@ -146,9 +146,13 @@
     completed_requests_status_[request_id] = true;
   }
 
-  void NotifyInProgressRequestFailed(
-      AggregationServiceStorage::RequestId request_id) override {
+  bool NotifyInProgressRequestFailed(
+      AggregationServiceStorage::RequestId request_id,
+      int previous_failed_attempts) override {
     completed_requests_status_[request_id] = false;
+    failed_attempts_[request_id] = previous_failed_attempts + 1;
+
+    return previous_failed_attempts < kMaxRetries;
   }
 
   void TriggerReportingTime(
@@ -174,6 +178,13 @@
     return completed_requests_status_[request_id];
   }
 
+  int FailedAttempts(AggregationServiceStorage::RequestId request_id) {
+    if (!base::Contains(failed_attempts_, request_id)) {
+      return 0;
+    }
+    return failed_attempts_[request_id];
+  }
+
  private:
   base::RepeatingCallback<void(
       std::vector<AggregationServiceStorage::RequestAndId>)>
@@ -187,6 +198,10 @@
   // successfully.
   base::flat_map<AggregationServiceStorage::RequestId, bool>
       completed_requests_status_;
+  // Each failed request's ID is the key, with value the number of times it
+  // failed to send. Only contains entries for requests with at least one
+  // failure.
+  base::flat_map<AggregationServiceStorage::RequestId, int> failed_attempts_;
 };
 
 class MockAggregationServiceObserver : public AggregationServiceObserver {
@@ -400,8 +415,9 @@
 }
 
 TEST_F(AggregationServiceImplTest, ScheduleReport_FailedAssembly) {
-  AggregatableReportRequest request =
-      aggregation_service::CreateExampleRequest();
+  AggregatableReportRequest request = aggregation_service::CreateExampleRequest(
+      /*aggregation_mode=*/mojom::AggregationServiceMode::kDefault,
+      /*failed_send_attempts=*/AggregatableReportScheduler::kMaxRetries);
 
   ScheduleReport(std::move(request));
 
@@ -434,6 +450,7 @@
 
   ASSERT_TRUE(scheduler()->WasRequestSuccessful(request_id).has_value());
   EXPECT_FALSE(scheduler()->WasRequestSuccessful(request_id).value());
+  EXPECT_EQ(scheduler()->FailedAttempts(request_id), 3);
 }
 
 TEST_F(AggregationServiceImplTest, ScheduleReport_FailedSending) {
@@ -451,10 +468,13 @@
   AggregationServiceStorage::RequestId request_id(1);
 
   EXPECT_CALL(observer, OnRequestStorageModified);
+  // The report should not be considered handled when it is scheduled for a
+  // retry
   EXPECT_CALL(
       observer,
       OnReportHandled(RequestIdIs(request_id), _, _,
-                      AggregationServiceObserver::ReportStatus::kFailedToSend));
+                      AggregationServiceObserver::ReportStatus::kFailedToSend))
+      .Times(0);
 
   scheduler()->TriggerReportingTime(/*request_ids=*/{request_id});
 
@@ -474,6 +494,7 @@
 
   ASSERT_TRUE(scheduler()->WasRequestSuccessful(request_id).has_value());
   EXPECT_FALSE(scheduler()->WasRequestSuccessful(request_id).value());
+  EXPECT_EQ(scheduler()->FailedAttempts(request_id), 1);
 }
 
 TEST_F(AggregationServiceImplTest,
diff --git a/content/browser/aggregation_service/aggregation_service_storage.h b/content/browser/aggregation_service/aggregation_service_storage.h
index 95fb610..cc632c03 100644
--- a/content/browser/aggregation_service/aggregation_service_storage.h
+++ b/content/browser/aggregation_service/aggregation_service_storage.h
@@ -64,6 +64,12 @@
   // Deletes the report request with the given `request_id`, if any.
   virtual void DeleteRequest(RequestId request_id) = 0;
 
+  // Increments the number of failed send attempts associated with the given
+  // report, and sets its report time to the given value. Should be called after
+  // a transient failure to send the report so that it is retried later.
+  virtual void UpdateReportForSendFailure(RequestId request_id,
+                                          base::Time new_report_time) = 0;
+
   // Returns the earliest report time for a stored pending request strictly
   // after `strictly_after_time`. If there are no such requests stored, returns
   // `absl::nullopt`.
diff --git a/content/browser/aggregation_service/aggregation_service_storage_sql.cc b/content/browser/aggregation_service/aggregation_service_storage_sql.cc
index 9ca14a0..255c452 100644
--- a/content/browser/aggregation_service/aggregation_service_storage_sql.cc
+++ b/content/browser/aggregation_service/aggregation_service_storage_sql.cc
@@ -14,6 +14,7 @@
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/check_op.h"
+#include "base/containers/span.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
@@ -440,6 +441,60 @@
   return count < max_stored_requests_per_reporting_origin_;
 }
 
+void AggregationServiceStorageSql::UpdateReportForSendFailure(
+    AggregationServiceStorage::RequestId request_id,
+    base::Time new_report_time) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!EnsureDatabaseOpen(DbCreationPolicy::kCreateIfAbsent))
+    return;
+
+  sql::Transaction transaction(&db_);
+  if (!transaction.Begin())
+    return;
+
+  static constexpr char kGetRequestProtoSql[] =
+      "SELECT request_proto FROM report_requests WHERE request_id=?";
+  sql::Statement get_request_statement(
+      db_.GetCachedStatement(SQL_FROM_HERE, kGetRequestProtoSql));
+  get_request_statement.BindInt64(0, request_id.value());
+
+  if (!get_request_statement.Step())
+    return;
+
+  base::span<const uint8_t> blob = get_request_statement.ColumnBlob(0);
+  proto::AggregatableReportRequest request_proto;
+  if (!request_proto.ParseFromArray(blob.data(), blob.size()))
+    return;
+
+  if (request_proto.failed_send_attempts() < 0)
+    return;
+
+  request_proto.set_failed_send_attempts(request_proto.failed_send_attempts() +
+                                         1);
+
+  size_t size = request_proto.ByteSizeLong();
+  std::vector<uint8_t> serialized_proto(size);
+  if (!request_proto.SerializeToArray(serialized_proto.data(), size))
+    return;
+
+  static constexpr char kUpdateRequestSql[] =
+      "UPDATE report_requests SET report_time=?,request_proto=? "
+      "WHERE request_id=?";
+
+  sql::Statement update_request_statement(
+      db_.GetCachedStatement(SQL_FROM_HERE, kUpdateRequestSql));
+
+  update_request_statement.BindTime(0, new_report_time);
+  update_request_statement.BindBlob(1, serialized_proto);
+  update_request_statement.BindInt64(2, request_id.value());
+
+  if (!update_request_statement.Run())
+    return;
+
+  transaction.Commit();
+}
+
 void AggregationServiceStorageSql::StoreRequest(
     AggregatableReportRequest request) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/content/browser/aggregation_service/aggregation_service_storage_sql.h b/content/browser/aggregation_service/aggregation_service_storage_sql.h
index 6a6ba93..01147cb9 100644
--- a/content/browser/aggregation_service/aggregation_service_storage_sql.h
+++ b/content/browser/aggregation_service/aggregation_service_storage_sql.h
@@ -71,6 +71,9 @@
   void ClearPublicKeysExpiredBy(base::Time delete_end) override;
   void StoreRequest(AggregatableReportRequest request) override;
   void DeleteRequest(AggregationServiceStorage::RequestId request_id) override;
+  void UpdateReportForSendFailure(
+      AggregationServiceStorage::RequestId request_id,
+      base::Time new_report_time) override;
   absl::optional<base::Time> NextReportTimeAfter(
       base::Time strictly_after_time) override;
   std::vector<AggregationServiceStorage::RequestAndId>
diff --git a/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc b/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc
index 82d7264..a0eb222 100644
--- a/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc
+++ b/content/browser/aggregation_service/aggregation_service_storage_sql_unittest.cc
@@ -46,6 +46,7 @@
 using testing::ElementsAre;
 
 using RequestId = AggregationServiceStorage::RequestId;
+using RequestAndId = AggregationServiceStorage::RequestAndId;
 
 const char kExampleUrl[] =
     "https://helper.test/.well-known/aggregation-service/keys.json";
@@ -510,6 +511,43 @@
 }
 
 TEST_F(AggregationServiceStorageSqlTest,
+       UpdateReportForSendFailure_ExpectedResult) {
+  OpenDatabase();
+
+  // Trying to update an non-existing report should not crash
+  storage_->UpdateReportForSendFailure(RequestId(1),
+                                       /*new_report_time=*/base::Time::Now());
+
+  AggregatableReportRequest request =
+      aggregation_service::CreateExampleRequest();
+
+  storage_->StoreRequest(aggregation_service::CloneReportRequest(request));
+
+  base::Time next_run_time = base::Time::Now() + base::Minutes(5);
+
+  storage_->UpdateReportForSendFailure(RequestId(1), next_run_time);
+
+  // Report time is updated as expected
+  std::vector<RequestAndId> requests_before_next_run_time =
+      storage_->GetRequestsReportingOnOrBefore(next_run_time -
+                                               base::Microseconds(1));
+  EXPECT_EQ(requests_before_next_run_time.size(), 0u);
+  std::vector<RequestAndId> requests_at_run_time =
+      storage_->GetRequestsReportingOnOrBefore(next_run_time);
+  ASSERT_EQ(requests_at_run_time.size(), 1u);
+
+  // Failed send attempts has been increased
+  EXPECT_EQ(requests_at_run_time[0].request.failed_send_attempts(), 1);
+
+  // Fail again to ensure the number of failed attempts is increased
+  storage_->UpdateReportForSendFailure(RequestId(1), next_run_time);
+  requests_at_run_time =
+      storage_->GetRequestsReportingOnOrBefore(next_run_time);
+  ASSERT_EQ(requests_at_run_time.size(), 1u);
+  EXPECT_EQ(requests_at_run_time[0].request.failed_send_attempts(), 2);
+}
+
+TEST_F(AggregationServiceStorageSqlTest,
        RepeatGetPendingRequests_RequestReturnedAgain) {
   OpenDatabase();
 
diff --git a/content/browser/aggregation_service/aggregation_service_test_utils.cc b/content/browser/aggregation_service/aggregation_service_test_utils.cc
index 1ca394c..9e84f05 100644
--- a/content/browser/aggregation_service/aggregation_service_test_utils.cc
+++ b/content/browser/aggregation_service/aggregation_service_test_utils.cc
@@ -212,14 +212,17 @@
 }
 
 AggregatableReportRequest CreateExampleRequest(
-    mojom::AggregationServiceMode aggregation_mode) {
-  return CreateExampleRequestWithReportTime(base::Time::Now(),
-                                            aggregation_mode);
+    mojom::AggregationServiceMode aggregation_mode,
+    int failed_send_attempts) {
+  return CreateExampleRequestWithReportTime(
+      /*report_time=*/base::Time::Now(), aggregation_mode,
+      failed_send_attempts);
 }
 
 AggregatableReportRequest CreateExampleRequestWithReportTime(
     base::Time report_time,
-    mojom::AggregationServiceMode aggregation_mode) {
+    mojom::AggregationServiceMode aggregation_mode,
+    int failed_send_attempts) {
   return AggregatableReportRequest::Create(
              AggregationServicePayloadContents(
                  AggregationServicePayloadContents::Operation::kHistogram,
@@ -236,7 +239,8 @@
                  /*additional_fields=*/base::Value::Dict(),
                  /*api_version=*/"",
                  /*api_identifier=*/"example-api"),
-             /*reporting_path-*/ "example-path")
+             /*reporting_path=*/"example-path",
+             /*debug_key=*/absl::nullopt, failed_send_attempts)
       .value();
 }
 
diff --git a/content/browser/aggregation_service/aggregation_service_test_utils.h b/content/browser/aggregation_service/aggregation_service_test_utils.h
index c9b6ec8..f3018d6 100644
--- a/content/browser/aggregation_service/aggregation_service_test_utils.h
+++ b/content/browser/aggregation_service/aggregation_service_test_utils.h
@@ -67,12 +67,14 @@
 // Returns an example report request, using the given parameters.
 AggregatableReportRequest CreateExampleRequest(
     mojom::AggregationServiceMode aggregation_mode =
-        mojom::AggregationServiceMode::kDefault);
+        mojom::AggregationServiceMode::kDefault,
+    int failed_send_attempts = 0);
 
 AggregatableReportRequest CreateExampleRequestWithReportTime(
     base::Time report_time,
     mojom::AggregationServiceMode aggregation_mode =
-        mojom::AggregationServiceMode::kDefault);
+        mojom::AggregationServiceMode::kDefault,
+    int failed_send_attempts = 0);
 
 AggregatableReportRequest CloneReportRequest(
     const AggregatableReportRequest& request);
diff --git a/content/browser/aggregation_service/proto/aggregatable_report.proto b/content/browser/aggregation_service/proto/aggregatable_report.proto
index 4d09fc9..5684f72 100644
--- a/content/browser/aggregation_service/proto/aggregatable_report.proto
+++ b/content/browser/aggregation_service/proto/aggregatable_report.proto
@@ -58,4 +58,5 @@
   AggregatableReportSharedInfo shared_info = 2;
   string reporting_path = 3;
   optional uint64 debug_key = 4;
+  int32 failed_send_attempts = 5;
 }
diff --git a/content/browser/attribution_reporting/attribution_aggregation_keys.cc b/content/browser/attribution_reporting/attribution_aggregation_keys.cc
index d3a42d2..ecf80ffe 100644
--- a/content/browser/attribution_reporting/attribution_aggregation_keys.cc
+++ b/content/browser/attribution_reporting/attribution_aggregation_keys.cc
@@ -11,13 +11,19 @@
 #include "base/ranges/algorithm.h"
 #include "base/strings/abseil_string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/types/expected.h"
 #include "base/values.h"
+#include "content/browser/attribution_reporting/attribution_reporting.mojom.h"
 #include "content/browser/attribution_reporting/attribution_reporting.pb.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/attribution_reporting/constants.h"
 
 namespace content {
 
+namespace {
+using ::attribution_reporting::mojom::SourceRegistrationError;
+}  // namespace
+
 // static
 absl::optional<AttributionAggregationKeys> AttributionAggregationKeys::FromKeys(
     Keys keys) {
@@ -33,35 +39,44 @@
 }
 
 // static
-absl::optional<AttributionAggregationKeys> AttributionAggregationKeys::FromJSON(
-    const base::Value* value) {
+base::expected<AttributionAggregationKeys, SourceRegistrationError>
+AttributionAggregationKeys::FromJSON(const base::Value* value) {
   // TODO(johnidel): Consider logging registration JSON metrics here.
   if (!value)
     return AttributionAggregationKeys();
 
   const base::Value::Dict* dict = value->GetIfDict();
   if (!dict)
-    return absl::nullopt;
+    return base::unexpected(SourceRegistrationError::kAggregationKeysWrongType);
 
   const size_t num_keys = dict->size();
 
-  if (num_keys > blink::kMaxAttributionAggregationKeysPerSourceOrTrigger)
-    return absl::nullopt;
+  if (num_keys > blink::kMaxAttributionAggregationKeysPerSourceOrTrigger) {
+    return base::unexpected(
+        SourceRegistrationError::kAggregationKeysTooManyKeys);
+  }
 
   Keys::container_type keys;
   keys.reserve(num_keys);
 
   for (auto [key_id, maybe_string_value] : *dict) {
-    if (key_id.size() > blink::kMaxBytesPerAttributionAggregationKeyId)
-      return absl::nullopt;
+    if (key_id.size() > blink::kMaxBytesPerAttributionAggregationKeyId) {
+      return base::unexpected(
+          SourceRegistrationError::kAggregationKeysKeyTooLong);
+    }
 
     const std::string* s = maybe_string_value.GetIfString();
+    if (!s) {
+      return base::unexpected(
+          SourceRegistrationError::kAggregationKeysValueWrongType);
+    }
+
     absl::uint128 key;
 
-    if (!s ||
-        !base::StartsWith(*s, "0x", base::CompareCase::INSENSITIVE_ASCII) ||
+    if (!base::StartsWith(*s, "0x", base::CompareCase::INSENSITIVE_ASCII) ||
         !base::HexStringToUInt128(*s, &key)) {
-      return absl::nullopt;
+      return base::unexpected(
+          SourceRegistrationError::kAggregationKeysValueWrongFormat);
     }
 
     keys.emplace_back(key_id, key);
diff --git a/content/browser/attribution_reporting/attribution_aggregation_keys.h b/content/browser/attribution_reporting/attribution_aggregation_keys.h
index cf8251a..c18e86f 100644
--- a/content/browser/attribution_reporting/attribution_aggregation_keys.h
+++ b/content/browser/attribution_reporting/attribution_aggregation_keys.h
@@ -8,6 +8,8 @@
 #include <string>
 
 #include "base/containers/flat_map.h"
+#include "base/types/expected.h"
+#include "content/browser/attribution_reporting/attribution_reporting.mojom-forward.h"
 #include "content/common/content_export.h"
 #include "third_party/abseil-cpp/absl/numeric/int128.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -25,8 +27,9 @@
   // Returns `absl::nullopt` if `keys` is invalid.
   static absl::optional<AttributionAggregationKeys> FromKeys(Keys keys);
 
-  static absl::optional<AttributionAggregationKeys> FromJSON(
-      const base::Value*);
+  static base::expected<AttributionAggregationKeys,
+                        attribution_reporting::mojom::SourceRegistrationError>
+  FromJSON(const base::Value*);
 
   // Deserializes `str`, if valid. Returns `absl::nullopt` if not.
   static absl::optional<AttributionAggregationKeys> Deserialize(
diff --git a/content/browser/attribution_reporting/attribution_filter_data.cc b/content/browser/attribution_reporting/attribution_filter_data.cc
index e6b51d5..e936a55 100644
--- a/content/browser/attribution_reporting/attribution_filter_data.cc
+++ b/content/browser/attribution_reporting/attribution_filter_data.cc
@@ -11,7 +11,9 @@
 
 #include "base/check.h"
 #include "base/check_op.h"
+#include "base/types/expected.h"
 #include "base/values.h"
+#include "content/browser/attribution_reporting/attribution_reporting.mojom.h"
 #include "content/browser/attribution_reporting/attribution_reporting.pb.h"
 #include "third_party/blink/public/common/attribution_reporting/constants.h"
 
@@ -19,6 +21,8 @@
 
 namespace {
 
+using ::attribution_reporting::mojom::SourceRegistrationError;
+
 constexpr char kFilterSourceType[] = "source_type";
 
 }  // namespace
@@ -80,48 +84,56 @@
 }
 
 // static
-absl::optional<AttributionFilterData> AttributionFilterData::FromSourceJSON(
-    base::Value* input_value) {
+base::expected<AttributionFilterData, SourceRegistrationError>
+AttributionFilterData::FromSourceJSON(base::Value* input_value) {
   // TODO(johnidel): Consider logging registration JSON metrics here.
   if (!input_value)
     return AttributionFilterData();
 
   base::Value::Dict* dict = input_value->GetIfDict();
   if (!dict)
-    return absl::nullopt;
+    return base::unexpected(SourceRegistrationError::kFilterDataWrongType);
 
   const size_t num_filters = dict->size();
   if (num_filters > blink::kMaxAttributionFiltersPerSource)
-    return absl::nullopt;
+    return base::unexpected(SourceRegistrationError::kFilterDataTooManyKeys);
 
-  if (dict->contains(kFilterSourceType))
-    return absl::nullopt;
+  if (dict->contains(kFilterSourceType)) {
+    return base::unexpected(
+        SourceRegistrationError::kFilterDataHasSourceTypeKey);
+  }
 
   FilterValues::container_type filter_values;
   filter_values.reserve(dict->size());
 
   for (auto [filter, value] : *dict) {
     if (filter.size() > blink::kMaxBytesPerAttributionFilterString)
-      return absl::nullopt;
+      return base::unexpected(SourceRegistrationError::kFilterDataKeyTooLong);
 
     base::Value::List* list = value.GetIfList();
-    if (!list)
-      return absl::nullopt;
+    if (!list) {
+      return base::unexpected(
+          SourceRegistrationError::kFilterDataListWrongType);
+    }
 
     const size_t num_values = list->size();
     if (num_values > blink::kMaxValuesPerAttributionFilter)
-      return absl::nullopt;
+      return base::unexpected(SourceRegistrationError::kFilterDataListTooLong);
 
     std::vector<std::string> values;
     values.reserve(num_values);
 
     for (base::Value& item : *list) {
       std::string* string = item.GetIfString();
-      if (!string)
-        return absl::nullopt;
+      if (!string) {
+        return base::unexpected(
+            SourceRegistrationError::kFilterDataValueWrongType);
+      }
 
-      if (string->size() > blink::kMaxBytesPerAttributionFilterString)
-        return absl::nullopt;
+      if (string->size() > blink::kMaxBytesPerAttributionFilterString) {
+        return base::unexpected(
+            SourceRegistrationError::kFilterDataValueTooLong);
+      }
 
       values.push_back(std::move(*string));
     }
diff --git a/content/browser/attribution_reporting/attribution_filter_data.h b/content/browser/attribution_reporting/attribution_filter_data.h
index 92da7e16..659c486 100644
--- a/content/browser/attribution_reporting/attribution_filter_data.h
+++ b/content/browser/attribution_reporting/attribution_filter_data.h
@@ -11,6 +11,8 @@
 #include <vector>
 
 #include "base/containers/flat_map.h"
+#include "base/types/expected.h"
+#include "content/browser/attribution_reporting/attribution_reporting.mojom-forward.h"
 #include "content/browser/attribution_reporting/attribution_source_type.h"
 #include "content/common/content_export.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -43,8 +45,9 @@
   static absl::optional<AttributionFilterData> FromTriggerFilterValues(
       FilterValues&& filter_values);
 
-  static absl::optional<AttributionFilterData> FromSourceJSON(
-      base::Value* input_value);
+  static base::expected<AttributionFilterData,
+                        attribution_reporting::mojom::SourceRegistrationError>
+  FromSourceJSON(base::Value* input_value);
 
   // Returns filter data that matches only the given source type.
   static AttributionFilterData ForSourceType(AttributionSourceType source_type);
diff --git a/content/browser/attribution_reporting/attribution_header_utils.cc b/content/browser/attribution_reporting/attribution_header_utils.cc
index e294fdb..2a8c3b8 100644
--- a/content/browser/attribution_reporting/attribution_header_utils.cc
+++ b/content/browser/attribution_reporting/attribution_header_utils.cc
@@ -91,16 +91,16 @@
 
   absl::optional<uint64_t> debug_key = ParseDebugKey(registration);
 
-  absl::optional<AttributionFilterData> filter_data =
+  base::expected<AttributionFilterData, SourceRegistrationError> filter_data =
       AttributionFilterData::FromSourceJSON(registration.Find("filter_data"));
-  if (!filter_data)
-    return base::unexpected(SourceRegistrationError::kFilterDataInvalid);
+  if (!filter_data.has_value())
+    return base::unexpected(filter_data.error());
 
-  absl::optional<AttributionAggregationKeys> aggregation_keys =
-      AttributionAggregationKeys::FromJSON(
+  base::expected<AttributionAggregationKeys, SourceRegistrationError>
+      aggregation_keys = AttributionAggregationKeys::FromJSON(
           registration.Find("aggregation_keys"));
-  if (!aggregation_keys)
-    return base::unexpected(SourceRegistrationError::kAggregationKeysInvalid);
+  if (!aggregation_keys.has_value())
+    return base::unexpected(aggregation_keys.error());
 
   return StorableSource(CommonSourceInfo(
       source_event_id, std::move(source_origin), std::move(destination),
diff --git a/content/browser/attribution_reporting/attribution_header_utils_unittest.cc b/content/browser/attribution_reporting/attribution_header_utils_unittest.cc
index 0c7695e..4764e9c 100644
--- a/content/browser/attribution_reporting/attribution_header_utils_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_header_utils_unittest.cc
@@ -38,16 +38,21 @@
   const struct {
     const char* description;
     absl::optional<base::Value> json;
-    absl::optional<AttributionAggregationKeys> expected;
+    base::expected<AttributionAggregationKeys, SourceRegistrationError>
+        expected;
   } kTestCases[] = {
       {"Null", absl::nullopt, AttributionAggregationKeys()},
-      {"Not a dictionary", base::Value(base::Value::List()), absl::nullopt},
+      {"Not a dictionary", base::Value(base::Value::List()),
+       base::unexpected(SourceRegistrationError::kAggregationKeysWrongType)},
       {"key not a string", base::test::ParseJson(R"({"key":123})"),
-       absl::nullopt},
+       base::unexpected(
+           SourceRegistrationError::kAggregationKeysValueWrongType)},
       {"key doesn't start with 0x", base::test::ParseJson(R"({"key":"159"})"),
-       absl::nullopt},
+       base::unexpected(
+           SourceRegistrationError::kAggregationKeysValueWrongFormat)},
       {"Invalid key", base::test::ParseJson(R"({"key":"0xG59"})"),
-       absl::nullopt},
+       base::unexpected(
+           SourceRegistrationError::kAggregationKeysValueWrongFormat)},
       {"One valid key", base::test::ParseJson(R"({"key":"0x159"})"),
        *AttributionAggregationKeys::FromKeys(
            {{"key", absl::MakeUint128(/*high=*/0, /*low=*/345)}})},
@@ -59,7 +64,9 @@
            {"key2", absl::MakeUint128(/*high=*/5, /*low=*/345)},
        })},
       {"Second key invalid",
-       base::test::ParseJson(R"({"key1":"0x159","key2":""})"), absl::nullopt},
+       base::test::ParseJson(R"({"key1":"0x159","key2":""})"),
+       base::unexpected(
+           SourceRegistrationError::kAggregationKeysValueWrongFormat)},
   };
 
   for (const auto& test_case : kTestCases) {
@@ -119,8 +126,8 @@
 
   for (const auto& test_case : kTestCases) {
     base::Value value(test_case.GetHeader());
-    EXPECT_EQ(AttributionAggregationKeys::FromJSON(&value),
-              test_case.Expected())
+    EXPECT_EQ(AttributionAggregationKeys::FromJSON(&value).has_value(),
+              test_case.Expected().has_value())
         << test_case.description;
   }
 }
@@ -163,7 +170,7 @@
   struct {
     const char* description;
     absl::optional<base::Value> json;
-    absl::optional<AttributionFilterData> expected;
+    base::expected<AttributionFilterData, SourceRegistrationError> expected;
   } kTestCases[] = {
       {
           "Null",
@@ -193,42 +200,43 @@
           base::test::ParseJson(R"json({
           "source_type": ["a"]
         })json"),
-          absl::nullopt,
+          base::unexpected(
+              SourceRegistrationError::kFilterDataHasSourceTypeKey),
       },
       {
           "not_dictionary",
           base::Value(base::Value::List()),
-          absl::nullopt,
+          base::unexpected(SourceRegistrationError::kFilterDataWrongType),
       },
       {
           "value_not_array",
           base::test::ParseJson(R"json({"a": true})json"),
-          absl::nullopt,
+          base::unexpected(SourceRegistrationError::kFilterDataListWrongType),
       },
       {
           "array_element_not_string",
           base::test::ParseJson(R"json({"a": [true]})json"),
-          absl::nullopt,
+          base::unexpected(SourceRegistrationError::kFilterDataValueWrongType),
       },
       {
           "too_many_keys",
           make_filter_data_with_keys(51),
-          absl::nullopt,
+          base::unexpected(SourceRegistrationError::kFilterDataTooManyKeys),
       },
       {
           "key_too_long",
           make_filter_data_with_key_length(26),
-          absl::nullopt,
+          base::unexpected(SourceRegistrationError::kFilterDataKeyTooLong),
       },
       {
           "too_many_values",
           make_filter_data_with_values(51),
-          absl::nullopt,
+          base::unexpected(SourceRegistrationError::kFilterDataListTooLong),
       },
       {
           "value_too_long",
           make_filter_data_with_value_length(26),
-          absl::nullopt,
+          base::unexpected(SourceRegistrationError::kFilterDataValueTooLong),
       },
   };
 
@@ -241,22 +249,22 @@
 
   {
     base::Value json = make_filter_data_with_keys(50);
-    EXPECT_TRUE(AttributionFilterData::FromSourceJSON(&json));
+    EXPECT_TRUE(AttributionFilterData::FromSourceJSON(&json).has_value());
   }
 
   {
     base::Value json = make_filter_data_with_key_length(25);
-    EXPECT_TRUE(AttributionFilterData::FromSourceJSON(&json));
+    EXPECT_TRUE(AttributionFilterData::FromSourceJSON(&json).has_value());
   }
 
   {
     base::Value json = make_filter_data_with_values(50);
-    EXPECT_TRUE(AttributionFilterData::FromSourceJSON(&json));
+    EXPECT_TRUE(AttributionFilterData::FromSourceJSON(&json).has_value());
   }
 
   {
     base::Value json = make_filter_data_with_value_length(25);
-    EXPECT_TRUE(AttributionFilterData::FromSourceJSON(&json));
+    EXPECT_TRUE(AttributionFilterData::FromSourceJSON(&json).has_value());
   }
 }
 
@@ -432,7 +440,7 @@
       {
           "filter_data_wrong_type",
           R"json({"filter_data":5,"destination":"https://d.example"})json",
-          base::unexpected(SourceRegistrationError::kFilterDataInvalid),
+          base::unexpected(SourceRegistrationError::kFilterDataWrongType),
       },
       {
           "aggregation_keys_valid",
@@ -448,7 +456,7 @@
       {
           "aggregation_keys_wrong_type",
           R"json({"aggregation_keys":5,"destination":"https://d.example"})json",
-          base::unexpected(SourceRegistrationError::kAggregationKeysInvalid),
+          base::unexpected(SourceRegistrationError::kAggregationKeysWrongType),
       },
   };
 
diff --git a/content/browser/attribution_reporting/attribution_internals_browsertest.cc b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
index 924dec1..6524d97 100644
--- a/content/browser/attribution_reporting/attribution_internals_browsertest.cc
+++ b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
@@ -350,15 +350,21 @@
   auto reporter1 = url::Origin::Create(GURL("https://a.test"));
 
   static constexpr char wait_script[] = R"(
-    let table = document.querySelector('#logTable')
+    const table = document.querySelector('#logTable')
         .shadowRoot.querySelector('tbody');
 
+    const logType = 'FailedSourceRegistration';
+    const metadata = '<dl><dt>Failure Reason</dt><dd>invalid JSON</dd>' +
+                     '<dt>Report To</dt><dd>https://a.test</dd>' +
+                     '<dt>Attribution-Reporting-Register-Source Header</dt>'+
+                     '<dd>!</dd></dl>';
+
     let obs = new MutationObserver((_, obs) => {
       if (table.children.length === 1 &&
-          table.children[0].children.length >= 4 &&
-          table.children[0].children[1].innerText === 'invalid JSON' &&
-          table.children[0].children[2].innerText === 'https://a.test' &&
-          table.children[0].children[3].innerText === '!')  {
+          table.children[0].children.length >= 3 &&
+          table.children[0].children[1].innerText === logType &&
+          table.children[0].children[2].innerHTML === metadata
+      )  {
         obs.disconnect();
         document.title = $1;
       }
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.cc b/content/browser/attribution_reporting/attribution_manager_impl.cc
index d667235..25e9a406 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl.cc
+++ b/content/browser/attribution_reporting/attribution_manager_impl.cc
@@ -209,6 +209,10 @@
           report.report_time() - attribution_info.time;
       UMA_HISTOGRAM_COUNTS_1000("Conversions.TimeFromConversionToReportSend",
                                 time_from_conversion_to_report_send.InHours());
+
+      UMA_HISTOGRAM_CUSTOM_TIMES("Conversions.SchedulerReportDelay",
+                                 now - report.report_time(), base::Seconds(1),
+                                 base::Days(1), 50);
       break;
     }
     case AttributionReport::Type::kAggregatableAttribution: {
@@ -218,6 +222,18 @@
           "Conversions.AggregatableReport.TimeFromTriggerToReportAssembly2",
           time_from_conversion_to_report_assembly, base::Minutes(1),
           base::Days(24), 50);
+
+      auto* data = absl::get_if<AttributionReport::AggregatableAttributionData>(
+          &report.data());
+      DCHECK(data);
+      UMA_HISTOGRAM_CUSTOM_TIMES(
+          "Conversions.AggregatableReport.ExtraReportDelay",
+          now - data->initial_report_time, base::Seconds(1), base::Days(24),
+          50);
+
+      UMA_HISTOGRAM_CUSTOM_TIMES(
+          "Conversions.AggregatableReport.SchedulerReportDelay",
+          now - report.report_time(), base::Seconds(1), base::Days(1), 50);
       break;
     }
   }
diff --git a/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc b/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
index 65437b8..d396a77 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
@@ -1457,9 +1457,12 @@
 TEST_F(AttributionManagerImplTest, SendReport_RecordsExtraReportDelay2) {
   base::HistogramTester histograms;
 
-  attribution_manager_->HandleSource(
-      SourceBuilder().SetExpiry(kImpressionExpiry).Build());
-  attribution_manager_->HandleTrigger(DefaultTrigger());
+  attribution_manager_->HandleSource(TestAggregatableSourceProvider()
+                                         .GetBuilder()
+                                         .SetExpiry(kImpressionExpiry)
+                                         .Build());
+  attribution_manager_->HandleTrigger(
+      DefaultAggregatableTriggerBuilder().Build());
 
   // Prevent the report from being sent until after its original report time.
   SetConnectionTypeAndWaitForObserversToBeNotified(
@@ -1476,6 +1479,34 @@
   histograms.ExpectUniqueTimeSample(
       "Conversions.ExtraReportDelay2",
       base::Days(3) + kDefaultOfflineReportDelay.min, 1);
+  histograms.ExpectUniqueTimeSample(
+      "Conversions.AggregatableReport.ExtraReportDelay",
+      base::Days(3) + kDefaultOfflineReportDelay.min, 1);
+}
+
+TEST_F(AttributionManagerImplTest, SendReport_RecordsSchedulerReportDelay) {
+  base::HistogramTester histograms;
+
+  attribution_manager_->HandleSource(TestAggregatableSourceProvider()
+                                         .GetBuilder()
+                                         .SetExpiry(kImpressionExpiry)
+                                         .Build());
+  attribution_manager_->HandleTrigger(
+      DefaultAggregatableTriggerBuilder().Build());
+
+  EXPECT_THAT(StoredReports(), SizeIs(2));
+
+  // Deliberately avoid running tasks so that the scheduler is delayed.
+  task_environment_.AdvanceClock(kFirstReportingWindow + base::Seconds(1));
+
+  // Cause any scheduled tasks to run.
+  task_environment_.FastForwardBy(base::TimeDelta());
+
+  histograms.ExpectUniqueTimeSample("Conversions.SchedulerReportDelay",
+                                    base::Seconds(1), 1);
+  histograms.ExpectUniqueTimeSample(
+      "Conversions.AggregatableReport.SchedulerReportDelay", base::Seconds(1),
+      1);
 }
 
 TEST_F(AttributionManagerImplTest, SendReportsFromWebUI_DoesNotRecordMetrics) {
diff --git a/content/browser/attribution_reporting/attribution_reporting.mojom b/content/browser/attribution_reporting/attribution_reporting.mojom
index e9d9bce..86079ca 100644
--- a/content/browser/attribution_reporting/attribution_reporting.mojom
+++ b/content/browser/attribution_reporting/attribution_reporting.mojom
@@ -23,10 +23,24 @@
 enum SourceRegistrationError {
   kInvalidJson,
   kRootWrongType,
+
   kDestinationMissing,
   kDestinationWrongType,
   kDestinationUntrustworthy,
   kDestinationMismatched,
-  kFilterDataInvalid,
-  kAggregationKeysInvalid,
+
+  kFilterDataWrongType,
+  kFilterDataTooManyKeys,
+  kFilterDataHasSourceTypeKey,
+  kFilterDataKeyTooLong,
+  kFilterDataListWrongType,
+  kFilterDataListTooLong,
+  kFilterDataValueWrongType,
+  kFilterDataValueTooLong,
+
+  kAggregationKeysWrongType,
+  kAggregationKeysTooManyKeys,
+  kAggregationKeysKeyTooLong,
+  kAggregationKeysValueWrongType,
+  kAggregationKeysValueWrongFormat,
 };
diff --git a/content/browser/attribution_reporting/attributions_browsertest.cc b/content/browser/attribution_reporting/attributions_browsertest.cc
index aa8e4ca..5212d775 100644
--- a/content/browser/attribution_reporting/attributions_browsertest.cc
+++ b/content/browser/attribution_reporting/attributions_browsertest.cc
@@ -848,8 +848,13 @@
   expected_report.WaitForReport();
 }
 
+// TODO(https://crbug.com/1374121): This is failing flakily because clicking the
+// link will cause a navigation. It is possible that the navigation will
+// complete before the attributionsSrc resource has been received. In this case,
+// the browser will mark the page as "frozen", causing MojoURLLoaderClient to
+// store the message and never dispatch it.
 IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest,
-                       ImpressionConversionSameDomain_ReportSent) {
+                       DISABLED_ImpressionConversionSameDomain_ReportSent) {
   // Expected reports must be registered before the server starts.
   ExpectedReportWaiter expected_report(
       GURL("https://d.test/.well-known/attribution-reporting/"
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 2b0c6233..fd0c5a4 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -200,7 +200,7 @@
 }
 
 void BackForwardCacheBrowserTest::SetupFeaturesAndParameters() {
-  std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled_features;
+  std::vector<base::test::FeatureRefAndParams> enabled_features;
 
   for (const auto& [feature_ref, params] : features_with_params_) {
     enabled_features.emplace_back(*feature_ref, params);
diff --git a/content/browser/direct_sockets/direct_sockets_open_browsertest.cc b/content/browser/direct_sockets/direct_sockets_open_browsertest.cc
index ee4a76bc..4e27e196 100644
--- a/content/browser/direct_sockets/direct_sockets_open_browsertest.cc
+++ b/content/browser/direct_sockets/direct_sockets_open_browsertest.cc
@@ -10,20 +10,12 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram.h"
-#include "base/run_loop.h"
-#include "base/stl_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
-#include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "content/browser/direct_sockets/direct_sockets_service_impl.h"
 #include "content/browser/direct_sockets/direct_sockets_test_utils.h"
-#include "content/browser/direct_sockets/resolve_host_and_open_socket.h"
-#include "content/browser/renderer_host/frame_tree_node.h"
-#include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/public/browser/browser_context.h"
-#include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -36,15 +28,9 @@
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/dns/host_resolver.h"
-#include "net/http/http_request_headers.h"
 #include "net/net_buildflags.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/embedded_test_server/http_response.h"
-#include "net/test/embedded_test_server/request_handler_util.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "services/network/public/cpp/cors/cors.h"
 #include "services/network/public/mojom/host_resolver.mojom.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/tcp_socket.mojom.h"
@@ -572,129 +558,4 @@
   EXPECT_EQ(1234, call.receive_buffer_size);
 }
 
-class DirectSocketsOpenCorsBrowserTest
-    : public DirectSocketsOpenBrowserTest,
-      public testing::WithParamInterface<bool> {
- public:
-  DirectSocketsOpenCorsBrowserTest()
-      : https_server_(net::test_server::EmbeddedTestServer::TYPE_HTTPS) {}
-
-  void SetUp() override {
-    https_server()->RegisterDefaultHandler(base::BindRepeating(
-        &net::test_server::HandlePrefixedRequest, "/",
-        base::BindRepeating(
-            &DirectSocketsOpenCorsBrowserTest::HandleCORSRequest,
-            base::Unretained(this), GetParam())));
-    ASSERT_TRUE(https_server()->Start(4344));
-    DirectSocketsOpenBrowserTest::SetUp();
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    ContentBrowserTest::SetUpCommandLine(command_line);
-
-    command_line->AppendSwitchASCII(switches::kIsolatedAppOrigins,
-                                    GetTestOpenPageURL().spec());
-  }
-
- protected:
-  std::unique_ptr<net::test_server::HttpResponse> HandleCORSRequest(
-      bool cors_success,
-      const net::test_server::HttpRequest& request) {
-    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
-
-    if (request.method == net::test_server::METHOD_OPTIONS) {
-      if (cors_success) {
-        response->AddCustomHeader(
-            network::cors::header_names::kAccessControlAllowOrigin, "*");
-
-        response->AddCustomHeader(
-            network::cors::header_names::kAccessControlAllowHeaders, "*");
-      }
-    } else {
-      response->AddCustomHeader(
-          network::cors::header_names::kAccessControlAllowOrigin, "*");
-      response->set_content("OK");
-    }
-
-    return response;
-  }
-
-  net::test_server::EmbeddedTestServer* https_server() {
-    return &https_server_;
-  }
-
- private:
-  net::test_server::EmbeddedTestServer https_server_;
-};
-
-IN_PROC_BROWSER_TEST_P(DirectSocketsOpenCorsBrowserTest, OpenTcp) {
-  MockOpenNetworkContext mock_network_context(net::OK);
-  DirectSocketsServiceImpl::SetNetworkContextForTesting(&mock_network_context);
-  // HTTPS uses port 443. We cannot really start a server on port 443,
-  // therefore we mock the behavior.
-  ResolveHostAndOpenSocket::SetHttpsPortForTesting(https_server()->port());
-
-  base::HistogramTester histogram_tester;
-  histogram_tester.ExpectBucketCount(
-      kPermissionDeniedHistogramName,
-      blink::mojom::DirectSocketFailureType::kCORS, 0);
-
-  const std::string script =
-      JsReplace("openTcp($1, $2)", kLocalhostAddress, https_server()->port());
-
-  bool cors_success = GetParam();
-
-  auto script_result = EvalJs(shell(), script).ExtractString();
-  if (cors_success) {
-    EXPECT_THAT(script_result, ::testing::HasSubstr("openTcp succeeded"));
-  } else {
-    EXPECT_THAT(
-        script_result,
-        ::testing::AllOf(::testing::HasSubstr("InvalidAccessError"),
-                         ::testing::HasSubstr("blocked by cross-origin")));
-  }
-
-  histogram_tester.ExpectBucketCount(
-      kPermissionDeniedHistogramName,
-      blink::mojom::DirectSocketFailureType::kCORS, cors_success ? 0 : 1);
-}
-
-IN_PROC_BROWSER_TEST_P(DirectSocketsOpenCorsBrowserTest, OpenUdp) {
-  MockOpenNetworkContext mock_network_context(net::OK);
-  DirectSocketsServiceImpl::SetNetworkContextForTesting(&mock_network_context);
-
-  // HTTPS uses port 443. We cannot really start a server on port 443,
-  // therefore we mock the behavior.
-  ResolveHostAndOpenSocket::SetHttpsPortForTesting(https_server()->port());
-
-  base::HistogramTester histogram_tester;
-  histogram_tester.ExpectBucketCount(
-      kPermissionDeniedHistogramName,
-      blink::mojom::DirectSocketFailureType::kCORS, 0);
-
-  const std::string script =
-      JsReplace("openUdp({ remoteAddress: $1, remotePort: $2 })",
-                kLocalhostAddress, https_server()->port());
-
-  bool cors_success = GetParam();
-
-  auto script_result = EvalJs(shell(), script).ExtractString();
-  if (cors_success) {
-    EXPECT_THAT(script_result, ::testing::HasSubstr("openUdp succeeded"));
-  } else {
-    EXPECT_THAT(
-        script_result,
-        ::testing::AllOf(::testing::HasSubstr("InvalidAccessError"),
-                         ::testing::HasSubstr("blocked by cross-origin")));
-  }
-
-  histogram_tester.ExpectBucketCount(
-      kPermissionDeniedHistogramName,
-      blink::mojom::DirectSocketFailureType::kCORS, cors_success ? 0 : 1);
-}
-
-INSTANTIATE_TEST_SUITE_P(/*no prefix*/,
-                         DirectSocketsOpenCorsBrowserTest,
-                         testing::Bool());
-
 }  // namespace content
diff --git a/content/browser/direct_sockets/direct_sockets_service_impl.cc b/content/browser/direct_sockets/direct_sockets_service_impl.cc
index b96a0a3e..f9777e33 100644
--- a/content/browser/direct_sockets/direct_sockets_service_impl.cc
+++ b/content/browser/direct_sockets/direct_sockets_service_impl.cc
@@ -4,45 +4,29 @@
 
 #include "content/browser/direct_sockets/direct_sockets_service_impl.h"
 
-#include "base/bind.h"
-#include "base/callback_forward.h"
-#include "base/feature_list.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/no_destructor.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "content/browser/direct_sockets/direct_udp_socket_impl.h"
 #include "content/browser/direct_sockets/resolve_host_and_open_socket.h"
-#include "content/browser/renderer_host/frame_tree_node.h"
-#include "content/browser/url_loader_factory_params_helper.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/direct_sockets_delegate.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_client.h"
-#include "content/public/common/content_features.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "mojo/public/cpp/system/data_pipe.h"
-#include "net/base/address_list.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
-#include "net/http/http_request_headers.h"
-#include "net/net_buildflags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/resolve_host_client_base.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/tcp_socket.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom-shared.h"
-#include "url/url_constants.h"
-
-using blink::mojom::DirectSocketFailureType;
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-shared.h"
 
 namespace content {
 
@@ -74,15 +58,63 @@
 
 bool IsFrameSufficientlyIsolated(content::RenderFrameHost* frame) {
   return frame->GetWebExposedIsolationLevel() >=
-         content::RenderFrameHost::WebExposedIsolationLevel::
-             kMaybeIsolatedApplication;
+             content::RenderFrameHost::WebExposedIsolationLevel::
+                 kMaybeIsolatedApplication &&
+         frame->IsFeatureEnabled(
+             blink::mojom::PermissionsPolicyFeature::kDirectSockets);
+}
+
+network::mojom::TCPConnectedSocketOptionsPtr CreateTCPConnectedSocketOptions(
+    blink::mojom::DirectSocketOptionsPtr options) {
+  network::mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options =
+      network::mojom::TCPConnectedSocketOptions::New();
+  if (options->send_buffer_size > 0) {
+    tcp_connected_socket_options->send_buffer_size =
+        std::min(options->send_buffer_size, kMaxBufferSize);
+  }
+  if (options->receive_buffer_size > 0) {
+    tcp_connected_socket_options->receive_buffer_size =
+        std::min(options->receive_buffer_size, kMaxBufferSize);
+  }
+  tcp_connected_socket_options->no_delay = options->no_delay;
+  if (options->keep_alive_options) {
+    // options->keep_alive_options will be invalidated.
+    tcp_connected_socket_options->keep_alive_options =
+        std::move(options->keep_alive_options);
+  }
+  return tcp_connected_socket_options;
+}
+
+network::mojom::UDPSocketOptionsPtr CreateUDPSocketOptions(
+    blink::mojom::DirectSocketOptionsPtr options) {
+  network::mojom::UDPSocketOptionsPtr udp_socket_options =
+      network::mojom::UDPSocketOptions::New();
+  if (options->send_buffer_size > 0) {
+    udp_socket_options->send_buffer_size =
+        std::min(options->send_buffer_size, kMaxBufferSize);
+  }
+  if (options->receive_buffer_size > 0) {
+    udp_socket_options->receive_buffer_size =
+        std::min(options->receive_buffer_size, kMaxBufferSize);
+  }
+  return udp_socket_options;
+}
+
+absl::optional<net::IPEndPoint> GetLocalAddress(
+    const blink::mojom::DirectSocketOptions& options) {
+  if (net::IPAddress address;
+      options.local_hostname &&
+      address.AssignFromIPLiteral(*options.local_hostname)) {
+    return net::IPEndPoint{std::move(address), options.local_port};
+  }
+  return {};
 }
 
 }  // namespace
 
-DirectSocketsServiceImpl::DirectSocketsServiceImpl(RenderFrameHost& frame_host)
-    : WebContentsObserver(WebContents::FromRenderFrameHost(&frame_host)),
-      frame_host_(&frame_host) {}
+DirectSocketsServiceImpl::DirectSocketsServiceImpl(RenderFrameHost* frame_host)
+    : WebContentsObserver(WebContents::FromRenderFrameHost(frame_host)),
+      frame_host_(frame_host) {}
 
 DirectSocketsServiceImpl::~DirectSocketsServiceImpl() = default;
 
@@ -95,7 +127,8 @@
     return;
   }
   mojo::MakeSelfOwnedReceiver(
-      std::make_unique<DirectSocketsServiceImpl>(*frame), std::move(receiver));
+      base::WrapUnique(new DirectSocketsServiceImpl(frame)),
+      std::move(receiver));
 }
 
 content::DirectSocketsDelegate* DirectSocketsServiceImpl::GetDelegate() {
@@ -128,10 +161,16 @@
     return;
   }
 
-  ResolveHostAndOpenSocket* resolver = new ResolveHostAndOpenTCPSocket(
-      weak_ptr_factory_.GetWeakPtr(), std::move(options), std::move(receiver),
-      std::move(observer), std::move(callback));
-  resolver->Start();
+  const std::string remote_host = options->remote_hostname;
+  const uint16_t remote_port = options->remote_port;
+
+  auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
+  ResolveHostAndOpenSocket::Create(
+      weak_ptr, remote_host, remote_port,
+      base::BindOnce(&DirectSocketsServiceImpl::OnResolveCompleteForTcpSocket,
+                     weak_ptr, std::move(options), std::move(receiver),
+                     std::move(observer), std::move(callback)))
+      ->Start();
 }
 
 void DirectSocketsServiceImpl::OpenUdpSocket(
@@ -159,17 +198,22 @@
     return;
   }
 
-  ResolveHostAndOpenSocket* resolver = new ResolveHostAndOpenUDPSocket(
-      weak_ptr_factory_.GetWeakPtr(), std::move(options), std::move(receiver),
-      std::move(listener), std::move(callback));
-  resolver->Start();
+  const std::string remote_host = options->remote_hostname;
+  const uint16_t remote_port = options->remote_port;
+
+  auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
+  ResolveHostAndOpenSocket::Create(
+      weak_ptr, remote_host, remote_port,
+      base::BindOnce(&DirectSocketsServiceImpl::OnResolveCompleteForUdpSocket,
+                     weak_ptr, std::move(options), std::move(receiver),
+                     std::move(listener), std::move(callback)))
+      ->Start();
 }
 
 // static
 net::MutableNetworkTrafficAnnotationTag
 DirectSocketsServiceImpl::MutableTrafficAnnotation() {
-  return net::MutableNetworkTrafficAnnotationTag(
-      kDirectSocketsTrafficAnnotation);
+  return net::MutableNetworkTrafficAnnotationTag{TrafficAnnotation()};
 }
 
 // static
@@ -178,41 +222,32 @@
 }
 
 // static
-int32_t DirectSocketsServiceImpl::GetMaxBufferSize() {
-  return kMaxBufferSize;
-}
-
-// static
 void DirectSocketsServiceImpl::SetNetworkContextForTesting(
     network::mojom::NetworkContext* network_context) {
   GetNetworkContextForTesting() = network_context;
 }
 
-// static
-absl::optional<net::IPEndPoint>
-DirectSocketsServiceImpl::GetLocalAddrForTesting(
-    const blink::mojom::DirectSocketOptions& options) {
-  if (!options.local_hostname) {
-    return {};
-  }
-  if (net::IPAddress address;
-      address.AssignFromIPLiteral(*options.local_hostname)) {
-    return net::IPEndPoint(std::move(address), options.local_port);
-  }
-  return {};
-}
-
 void DirectSocketsServiceImpl::RenderFrameDeleted(
     RenderFrameHost* render_frame_host) {
-  if (render_frame_host == frame_host_)
+  if (render_frame_host == frame_host_) {
     frame_host_ = nullptr;
+  }
+}
+
+void DirectSocketsServiceImpl::RenderFrameHostChanged(
+    RenderFrameHost* old_host,
+    RenderFrameHost* new_host) {
+  if (old_host == frame_host_) {
+    frame_host_ = nullptr;
+  }
 }
 
 void DirectSocketsServiceImpl::WebContentsDestroyed() {
   frame_host_ = nullptr;
 }
 
-network::mojom::NetworkContext* DirectSocketsServiceImpl::GetNetworkContext() {
+network::mojom::NetworkContext* DirectSocketsServiceImpl::GetNetworkContext()
+    const {
   if (GetNetworkContextForTesting())
     return GetNetworkContextForTesting();
 
@@ -222,14 +257,74 @@
   return frame_host_->GetStoragePartition()->GetNetworkContext();
 }
 
-RenderFrameHost* DirectSocketsServiceImpl::GetFrameHost() {
+RenderFrameHost* DirectSocketsServiceImpl::GetFrameHost() const {
   return frame_host_;
 }
 
-void DirectSocketsServiceImpl::AddDirectUDPSocketReceiver(
-    std::unique_ptr<DirectUDPSocketImpl> socket,
-    mojo::PendingReceiver<blink::mojom::DirectUDPSocket> receiver) {
-  direct_udp_socket_receivers_.Add(std::move(socket), std::move(receiver));
+void DirectSocketsServiceImpl::OnResolveCompleteForTcpSocket(
+    blink::mojom::DirectSocketOptionsPtr options,
+    mojo::PendingReceiver<network::mojom::TCPConnectedSocket> socket,
+    mojo::PendingRemote<network::mojom::SocketObserver> observer,
+    OpenTcpSocketCallback callback,
+    int result,
+    const absl::optional<net::AddressList>& resolved_addresses) {
+  if (result != net::OK) {
+    std::move(callback).Run(result, absl::nullopt, absl::nullopt,
+                            mojo::ScopedDataPipeConsumerHandle(),
+                            mojo::ScopedDataPipeProducerHandle());
+    return;
+  }
+
+  auto* network_context = GetNetworkContext();
+  if (!network_context) {
+    return;
+  }
+
+  DCHECK(resolved_addresses && !resolved_addresses->empty());
+  absl::optional<net::IPEndPoint> local_addr = GetLocalAddress(*options);
+
+  network_context->CreateTCPConnectedSocket(
+      std::move(local_addr), *resolved_addresses,
+      CreateTCPConnectedSocketOptions(std::move(options)),
+      DirectSocketsServiceImpl::MutableTrafficAnnotation(), std::move(socket),
+      std::move(observer), std::move(callback));
+}
+
+void DirectSocketsServiceImpl::OnResolveCompleteForUdpSocket(
+    blink::mojom::DirectSocketOptionsPtr options,
+    mojo::PendingReceiver<blink::mojom::DirectUDPSocket>
+        direct_udp_socket_receiver,
+    mojo::PendingRemote<network::mojom::UDPSocketListener> listener,
+    OpenUdpSocketCallback callback,
+    int result,
+    const absl::optional<net::AddressList>& resolved_addresses) {
+  if (result != net::OK) {
+    std::move(callback).Run(result, absl::nullopt, absl::nullopt);
+    return;
+  }
+
+  auto* network_context = GetNetworkContext();
+  if (!network_context) {
+    return;
+  }
+
+  DCHECK(resolved_addresses && !resolved_addresses->empty());
+
+  net::IPEndPoint peer_addr = resolved_addresses->front();
+  auto direct_udp_socket = std::make_unique<DirectUDPSocketImpl>(
+      network_context, std::move(listener));
+
+  direct_udp_socket->Connect(
+      resolved_addresses->front(), CreateUDPSocketOptions(std::move(options)),
+      base::BindOnce(
+          [](OpenUdpSocketCallback callback, net::IPEndPoint peer_addr,
+             int result, const absl::optional<net::IPEndPoint>& local_addr) {
+            std::move(callback).Run(result, local_addr, peer_addr);
+          },
+          std::move(callback), resolved_addresses->front()));
+
+  direct_udp_socket_receivers_.Add(std::move(direct_udp_socket),
+                                   std::move(direct_udp_socket_receiver));
 }
 
 }  // namespace content
\ No newline at end of file
diff --git a/content/browser/direct_sockets/direct_sockets_service_impl.h b/content/browser/direct_sockets/direct_sockets_service_impl.h
index 3b8d8ea..9c2837a 100644
--- a/content/browser/direct_sockets/direct_sockets_service_impl.h
+++ b/content/browser/direct_sockets/direct_sockets_service_impl.h
@@ -5,31 +5,22 @@
 #ifndef CONTENT_BROWSER_DIRECT_SOCKETS_DIRECT_SOCKETS_SERVICE_IMPL_H_
 #define CONTENT_BROWSER_DIRECT_SOCKETS_DIRECT_SOCKETS_SERVICE_IMPL_H_
 
-#include "base/callback.h"
 #include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/run_loop.h"
-#include "content/browser/direct_sockets/direct_udp_socket_impl.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/direct_sockets_delegate.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/unique_receiver_set.h"
-#include "net/base/ip_address.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_response_headers.h"
+#include "net/base/address_list.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-#include "services/network/public/mojom/udp_socket.mojom.h"
 #include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom.h"
 
-namespace network {
-namespace mojom {
+namespace network::mojom {
 class NetworkContext;
-}
-}  // namespace network
+}  // namespace network::mojom
 
 namespace content {
 
@@ -38,19 +29,15 @@
     : public blink::mojom::DirectSocketsService,
       public WebContentsObserver {
  public:
-  explicit DirectSocketsServiceImpl(RenderFrameHost& frame_host);
   ~DirectSocketsServiceImpl() override;
 
-  DirectSocketsServiceImpl(const DirectSocketsServiceImpl&) = delete;
-  DirectSocketsServiceImpl& operator=(const DirectSocketsServiceImpl&) = delete;
-
   static void CreateForFrame(
-      RenderFrameHost* frame,
+      RenderFrameHost*,
       mojo::PendingReceiver<blink::mojom::DirectSocketsService> receiver);
 
   static content::DirectSocketsDelegate* GetDelegate();
 
-  // blink::mojom::DirectSocketsService override:
+  // blink::mojom::DirectSocketsService:
   void OpenTcpSocket(
       blink::mojom::DirectSocketOptionsPtr options,
       mojo::PendingReceiver<network::mojom::TCPConnectedSocket> socket,
@@ -62,36 +49,44 @@
       mojo::PendingRemote<network::mojom::UDPSocketListener> listener,
       OpenUdpSocketCallback callback) override;
 
-  // WebContentsObserver override:
+  // WebContentsObserver:
   void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+  void RenderFrameHostChanged(RenderFrameHost* old_host,
+                              RenderFrameHost* new_host) override;
   void WebContentsDestroyed() override;
 
-  network::mojom::NetworkContext* GetNetworkContext();
-  RenderFrameHost* GetFrameHost();
-
-  void AddDirectUDPSocketReceiver(
-      std::unique_ptr<DirectUDPSocketImpl> socket,
-      mojo::PendingReceiver<blink::mojom::DirectUDPSocket> receiver);
+  network::mojom::NetworkContext* GetNetworkContext() const;
+  RenderFrameHost* GetFrameHost() const;
 
   static net::MutableNetworkTrafficAnnotationTag MutableTrafficAnnotation();
   static net::NetworkTrafficAnnotationTag TrafficAnnotation();
-  static int32_t GetMaxBufferSize();
 
-  static void SetEnterpriseManagedForTesting(bool enterprise_managed);
-
+  // Testing:
   static void SetNetworkContextForTesting(network::mojom::NetworkContext*);
 
-  static absl::optional<net::IPEndPoint> GetLocalAddrForTesting(
-      const blink::mojom::DirectSocketOptions& options);
-
  private:
-  friend class DirectSocketsUnitTest;
+  explicit DirectSocketsServiceImpl(RenderFrameHost*);
+
+  void OnResolveCompleteForTcpSocket(
+      blink::mojom::DirectSocketOptionsPtr,
+      mojo::PendingReceiver<network::mojom::TCPConnectedSocket>,
+      mojo::PendingRemote<network::mojom::SocketObserver>,
+      OpenTcpSocketCallback,
+      int result,
+      const absl::optional<net::AddressList>& resolved_addresses);
+
+  void OnResolveCompleteForUdpSocket(
+      blink::mojom::DirectSocketOptionsPtr,
+      mojo::PendingReceiver<blink::mojom::DirectUDPSocket>,
+      mojo::PendingRemote<network::mojom::UDPSocketListener>,
+      OpenUdpSocketCallback,
+      int result,
+      const absl::optional<net::AddressList>& resolved_addresses);
 
   raw_ptr<RenderFrameHost> frame_host_;
   mojo::UniqueReceiverSet<blink::mojom::DirectUDPSocket>
       direct_udp_socket_receivers_;
 
-  std::unique_ptr<network::SimpleURLLoader> loader_;
   base::WeakPtrFactory<DirectSocketsServiceImpl> weak_ptr_factory_{this};
 };
 
diff --git a/content/browser/direct_sockets/direct_sockets_unittest.cc b/content/browser/direct_sockets/direct_sockets_unittest.cc
index 1b61c281..a7ed2490 100644
--- a/content/browser/direct_sockets/direct_sockets_unittest.cc
+++ b/content/browser/direct_sockets/direct_sockets_unittest.cc
@@ -13,6 +13,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_renderer_host.h"
 #include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
 #include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom.h"
 
@@ -29,7 +30,12 @@
 
   absl::optional<net::IPEndPoint> GetLocalAddr(
       const blink::mojom::DirectSocketOptions& options) {
-    return DirectSocketsServiceImpl::GetLocalAddrForTesting(options);
+    if (net::IPAddress address;
+        options.local_hostname &&
+        address.AssignFromIPLiteral(*options.local_hostname)) {
+      return net::IPEndPoint{std::move(address), options.local_port};
+    }
+    return {};
   }
 
  private:
diff --git a/content/browser/direct_sockets/resolve_host_and_open_socket.cc b/content/browser/direct_sockets/resolve_host_and_open_socket.cc
index d11ecbf..bb23d60 100644
--- a/content/browser/direct_sockets/resolve_host_and_open_socket.cc
+++ b/content/browser/direct_sockets/resolve_host_and_open_socket.cc
@@ -4,31 +4,25 @@
 
 #include "content/browser/direct_sockets/resolve_host_and_open_socket.h"
 
-#include "base/memory/scoped_refptr.h"
+#include "base/functional/bind.h"
+#include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/time/time.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/direct_sockets/direct_sockets_service_impl.h"
 #include "content/public/browser/direct_sockets_delegate.h"
+#include "content/public/browser/render_frame_host.h"
+#include "net/base/address_list.h"
+#include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
-#include "net/http/http_response_headers.h"
 #include "net/net_buildflags.h"
-#include "services/network/public/cpp/resource_request.h"
-#include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/network_context.mojom.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.h"
-#include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom-shared.h"
 
+namespace content {
 namespace {
 
 constexpr char kPermissionDeniedHistogramName[] =
     "DirectSockets.PermissionDeniedFailures";
 
-constexpr base::TimeDelta kCorsRequestTimeout = base::Seconds(15);
-
-constexpr int kHttpsPort = 443;
-
 #if BUILDFLAG(ENABLE_MDNS)
 bool ResemblesMulticastDNSName(const std::string& hostname) {
   return base::EndsWith(hostname, ".local") ||
@@ -36,72 +30,72 @@
 }
 #endif  // !BUILDFLAG(ENABLE_MDNS)
 
+bool IsRawIPAddress(const std::string& address) {
+  net::IPAddress ip;
+  return ip.AssignFromIPLiteral(address);
+}
+
 bool ContainNonPubliclyRoutableAddress(const net::AddressList& addresses) {
   DCHECK(!addresses.empty());
-  for (auto ip : addresses) {
-    if (!ip.address().IsPubliclyRoutable())
-      return true;
-  }
-  return false;
+  return !base::ranges::all_of(addresses, &net::IPAddress::IsPubliclyRoutable,
+                               &net::IPEndPoint::address);
 }
 
-absl::optional<net::IPEndPoint> GetLocalAddr(
-    const blink::mojom::DirectSocketOptions& options) {
-  absl::optional<net::IPEndPoint> local_addr = absl::nullopt;
-  if (!options.local_hostname) {
-    return {};
+RenderFrameHost* GetFrameHostFromService(
+    base::WeakPtr<DirectSocketsServiceImpl> service) {
+  if (!service) {
+    return nullptr;
   }
-
-  if (net::IPAddress local_address;
-      local_address.AssignFromIPLiteral(*options.local_hostname)) {
-    return net::IPEndPoint(local_address, options.local_port);
-  }
-
-  return {};
+  return service->GetFrameHost();
 }
 
-absl::optional<int> g_https_port_for_testing = {};
-
 }  // namespace
 
-namespace content {
-
-// ResolveHostAndOpenSocket implementation.
-
 ResolveHostAndOpenSocket::ResolveHostAndOpenSocket(
     base::WeakPtr<DirectSocketsServiceImpl> service,
-    blink::mojom::DirectSocketOptionsPtr options)
-    : service_(std::move(service)), options_(std::move(options)) {}
+    const std::string& host,
+    uint16_t port,
+    OpenSocketCallback callback)
+    : service_(service),
+      host_(host),
+      port_(port),
+      callback_(std::move(callback)) {}
 
 ResolveHostAndOpenSocket::~ResolveHostAndOpenSocket() = default;
 
+// static
+ResolveHostAndOpenSocket* ResolveHostAndOpenSocket::Create(
+    base::WeakPtr<DirectSocketsServiceImpl> service,
+    const std::string& host,
+    uint16_t port,
+    OpenSocketCallback callback) {
+  return new ResolveHostAndOpenSocket(std::move(service), host, port,
+                                      std::move(callback));
+}
+
 void ResolveHostAndOpenSocket::Start() {
   auto* network_context = service_->GetNetworkContext();
   DCHECK(network_context);
   DCHECK(!receiver_.is_bound());
   DCHECK(!resolver_.is_bound());
 
-  if (net::IPAddress().AssignFromIPLiteral(options_->remote_hostname)) {
-    is_raw_address_ = true;
-  }
-
-  network_context->CreateHostResolver(absl::nullopt,
+  network_context->CreateHostResolver(/*config_overrides=*/absl::nullopt,
                                       resolver_.BindNewPipeAndPassReceiver());
 
   network::mojom::ResolveHostParametersPtr parameters =
       network::mojom::ResolveHostParameters::New();
 #if BUILDFLAG(ENABLE_MDNS)
-  if (ResemblesMulticastDNSName(options_->remote_hostname)) {
+  if (ResemblesMulticastDNSName(host_)) {
     parameters->source = net::HostResolverSource::MULTICAST_DNS;
     is_mdns_name_ = true;
   }
 #endif  // !BUILDFLAG(ENABLE_MDNS)
   // Intentionally using a HostPortPair because scheme isn't specified.
-  resolver_->ResolveHost(
-      network::mojom::HostResolverHost::NewHostPortPair(
-          net::HostPortPair(options_->remote_hostname, options_->remote_port)),
-      net::NetworkAnonymizationKey::CreateTransient(), std::move(parameters),
-      receiver_.BindNewPipeAndPassRemote());
+  resolver_->ResolveHost(network::mojom::HostResolverHost::NewHostPortPair(
+                             net::HostPortPair{host_, port_}),
+                         net::NetworkAnonymizationKey::CreateTransient(),
+                         std::move(parameters),
+                         receiver_.BindNewPipeAndPassRemote());
   receiver_.set_disconnect_handler(base::BindOnce(
       &ResolveHostAndOpenSocket::OnComplete, base::Unretained(this),
       net::ERR_NAME_NOT_RESOLVED, net::ResolveErrorInfo(net::ERR_FAILED),
@@ -109,20 +103,6 @@
       /*endpoint_results_with_metadata=*/absl::nullopt));
 }
 
-// static
-int ResolveHostAndOpenSocket::GetHttpsPort() {
-  if (g_https_port_for_testing) {
-    return *g_https_port_for_testing;
-  }
-  return kHttpsPort;
-}
-
-// static
-void ResolveHostAndOpenSocket::SetHttpsPortForTesting(
-    absl::optional<int> https_port) {
-  g_https_port_for_testing = https_port;
-}
-
 void ResolveHostAndOpenSocket::OnComplete(
     int result,
     const net::ResolveErrorInfo& resolve_error_info,
@@ -132,12 +112,7 @@
   DCHECK(receiver_.is_bound());
   receiver_.reset();
 
-  if (!service_) {
-    OpenSocket(net::ERR_UNEXPECTED, {});
-    return;
-  }
-
-  auto* frame = service_->GetFrameHost();
+  auto* frame = GetFrameHostFromService(service_);
   if (!frame) {
     OpenSocket(net::ERR_UNEXPECTED, {});
     return;
@@ -151,7 +126,7 @@
 
   // Reject hostnames that resolve to non-public exception unless a raw IP
   // address or a *.local hostname is entered by the user.
-  if (!is_raw_address_ && !is_mdns_name_ && resolved_addresses &&
+  if (!IsRawIPAddress(host_) && !is_mdns_name_ && resolved_addresses &&
       ContainNonPubliclyRoutableAddress(*resolved_addresses)) {
     base::UmaHistogramEnumeration(
         kPermissionDeniedHistogramName,
@@ -160,211 +135,13 @@
     return;
   }
 
-  if (result == net::OK && resolved_addresses) {
-    if (options_->remote_port == GetHttpsPort()) {
-      // Delegates to OpenSocket(...) after the check.
-      // We cannot use the resolved address here since it causes problems
-      // with SSL :(
-      PerformCORSCheck(options_->remote_hostname, *resolved_addresses);
-      return;
-    }
-  }
-
   OpenSocket(result, resolved_addresses);
 }
 
-void ResolveHostAndOpenSocket::PerformCORSCheck(
-    const std::string& address,
-    net::AddressList resolved_addresses) {
-  auto* frame = service_->GetFrameHost();
-
-  mojo::Remote<network::mojom::URLLoaderFactory> factory;
-  frame->CreateNetworkServiceDefaultFactory(
-      factory.BindNewPipeAndPassReceiver());
-
-  auto resource_request = std::make_unique<network::ResourceRequest>();
-
-  resource_request->url =
-      url::SchemeHostPort(url::kHttpsScheme, address, GetHttpsPort()).GetURL();
-  if (!resource_request->url.is_valid()) {
-    OpenSocket(net::ERR_INVALID_URL, {});
-    return;
-  }
-
-  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
-  resource_request->method = net::HttpRequestHeaders::kGetMethod;
-  resource_request->mode =
-      network::mojom::RequestMode::kCorsWithForcedPreflight;
-  resource_request->request_initiator = frame->GetLastCommittedOrigin();
-
-  auto loader = network::SimpleURLLoader::Create(
-      std::move(resource_request),
-      DirectSocketsServiceImpl::TrafficAnnotation());
-  auto* loader_ptr = loader.get();
-
-  loader_ptr->SetTimeoutDuration(kCorsRequestTimeout);
-
-  loader_ptr->DownloadHeadersOnly(
-      factory.get(),
-      base::BindOnce(&ResolveHostAndOpenSocket::OnCORSCheckComplete,
-                     base::Unretained(this), std::move(loader),
-                     std::move(resolved_addresses)));
-}
-
-void ResolveHostAndOpenSocket::OnCORSCheckComplete(
-    std::unique_ptr<network::SimpleURLLoader> loader,
-    net::AddressList resolved_addresses,
-    scoped_refptr<net::HttpResponseHeaders>) {
-  if (const auto& completion_status = loader->CompletionStatus()) {
-    if (auto status = completion_status->cors_error_status) {
-      LOG(ERROR) << "Preflight failed: " << *status;
-      base::UmaHistogramEnumeration(
-          kPermissionDeniedHistogramName,
-          blink::mojom::DirectSocketFailureType::kCORS);
-      OpenSocket(net::ERR_BLOCKED_BY_RESPONSE, {});
-      return;
-    }
-    if (completion_status->error_code != net::OK) {
-      OpenSocket(completion_status->error_code, {});
-      return;
-    }
-    OpenSocket(net::OK, std::move(resolved_addresses));
-    return;
-  }
-
-  OpenSocket(net::ERR_TIMED_OUT, {});
-}
-
-// ResolveHostAndOpenTCPSocket implementation.
-
-ResolveHostAndOpenTCPSocket::ResolveHostAndOpenTCPSocket(
-    base::WeakPtr<DirectSocketsServiceImpl> service,
-    blink::mojom::DirectSocketOptionsPtr options,
-    mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver,
-    mojo::PendingRemote<network::mojom::SocketObserver> observer,
-    OpenTcpSocketCallback callback)
-    : ResolveHostAndOpenSocket(std::move(service), std::move(options)),
-      receiver_(std::move(receiver)),
-      observer_(std::move(observer)),
-      callback_(std::move(callback)) {}
-
-ResolveHostAndOpenTCPSocket::~ResolveHostAndOpenTCPSocket() = default;
-
-void ResolveHostAndOpenTCPSocket::OpenSocket(
+void ResolveHostAndOpenSocket::OpenSocket(
     int result,
     const absl::optional<net::AddressList>& resolved_addresses) {
-  network::mojom::NetworkContext* network_context = nullptr;
-  if (service_) {
-    network_context = service_->GetNetworkContext();
-  }
-  if (!network_context) {
-    delete this;
-    return;
-  }
-
-  if (result != net::OK) {
-    std::move(callback_).Run(result, absl::nullopt, absl::nullopt,
-                             mojo::ScopedDataPipeConsumerHandle(),
-                             mojo::ScopedDataPipeProducerHandle());
-    delete this;
-    return;
-  }
-
-  DCHECK(resolved_addresses && !resolved_addresses->empty());
-  const absl::optional<net::IPEndPoint> local_addr = GetLocalAddr(*options_);
-
-  network::mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options =
-      network::mojom::TCPConnectedSocketOptions::New();
-  if (options_->send_buffer_size > 0) {
-    tcp_connected_socket_options->send_buffer_size =
-        std::min(options_->send_buffer_size,
-                 DirectSocketsServiceImpl::GetMaxBufferSize());
-  }
-  if (options_->receive_buffer_size > 0) {
-    tcp_connected_socket_options->receive_buffer_size =
-        std::min(options_->receive_buffer_size,
-                 DirectSocketsServiceImpl::GetMaxBufferSize());
-  }
-  tcp_connected_socket_options->no_delay = options_->no_delay;
-  if (options_->keep_alive_options) {
-    // options_->keep_alive_options will be invalidated.
-    tcp_connected_socket_options->keep_alive_options =
-        std::move(options_->keep_alive_options);
-  }
-  // invalidate options_.
-  options_.reset();
-
-  network_context->CreateTCPConnectedSocket(
-      local_addr, *resolved_addresses, std::move(tcp_connected_socket_options),
-      DirectSocketsServiceImpl::MutableTrafficAnnotation(),
-      std::move(receiver_), std::move(observer_), std::move(callback_));
-  delete this;
-}
-
-// ResolveHostAndOpenUDPSocket implementation.
-
-ResolveHostAndOpenUDPSocket::ResolveHostAndOpenUDPSocket(
-    base::WeakPtr<DirectSocketsServiceImpl> service,
-    blink::mojom::DirectSocketOptionsPtr options,
-    mojo::PendingReceiver<blink::mojom::DirectUDPSocket> receiver,
-    mojo::PendingRemote<network::mojom::UDPSocketListener> listener,
-    OpenUdpSocketCallback callback)
-    : ResolveHostAndOpenSocket(std::move(service), std::move(options)),
-      receiver_(std::move(receiver)),
-      listener_(std::move(listener)),
-      callback_(std::move(callback)) {}
-
-ResolveHostAndOpenUDPSocket::~ResolveHostAndOpenUDPSocket() = default;
-
-void ResolveHostAndOpenUDPSocket::OpenSocket(
-    int result,
-    const absl::optional<net::AddressList>& resolved_addresses) {
-  network::mojom::NetworkContext* network_context = nullptr;
-  if (service_) {
-    network_context = service_->GetNetworkContext();
-  }
-  if (!network_context) {
-    delete this;
-    return;
-  }
-
-  if (result != net::OK) {
-    std::move(callback_).Run(result, absl::nullopt, absl::nullopt);
-    delete this;
-    return;
-  }
-
-  DCHECK(resolved_addresses && !resolved_addresses->empty());
-
-  network::mojom::UDPSocketOptionsPtr udp_socket_options =
-      network::mojom::UDPSocketOptions::New();
-  if (options_->send_buffer_size > 0) {
-    udp_socket_options->send_buffer_size =
-        std::min(options_->send_buffer_size,
-                 DirectSocketsServiceImpl::GetMaxBufferSize());
-  }
-  if (options_->receive_buffer_size > 0) {
-    udp_socket_options->receive_buffer_size =
-        std::min(options_->receive_buffer_size,
-                 DirectSocketsServiceImpl::GetMaxBufferSize());
-  }
-
-  net::IPEndPoint peer_addr = resolved_addresses->front();
-  auto direct_udp_socket = std::make_unique<DirectUDPSocketImpl>(
-      network_context, std::move(listener_));
-  direct_udp_socket->Connect(
-      peer_addr, std::move(udp_socket_options),
-      base::BindOnce(&ResolveHostAndOpenUDPSocket::OnUdpConnectCompleted,
-                     base::Unretained(this), peer_addr));
-  service_->AddDirectUDPSocketReceiver(std::move(direct_udp_socket),
-                                       std::move(receiver_));
-}
-
-void ResolveHostAndOpenUDPSocket::OnUdpConnectCompleted(
-    net::IPEndPoint peer_addr,
-    int result,
-    const absl::optional<net::IPEndPoint>& local_addr) {
-  std::move(callback_).Run(result, local_addr, peer_addr);
+  std::move(callback_).Run(result, resolved_addresses);
   delete this;
 }
 
diff --git a/content/browser/direct_sockets/resolve_host_and_open_socket.h b/content/browser/direct_sockets/resolve_host_and_open_socket.h
index 549d08bc..0d778ce 100644
--- a/content/browser/direct_sockets/resolve_host_and_open_socket.h
+++ b/content/browser/direct_sockets/resolve_host_and_open_socket.h
@@ -12,112 +12,58 @@
 #include "net/base/address_list.h"
 #include "net/dns/public/host_resolver_results.h"
 #include "services/network/public/cpp/resolve_host_client_base.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-#include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom.h"
 
 namespace content {
 
 class DirectSocketsServiceImpl;
 
-// Resolves the host/port pair provided in options and opens the requested
-// socket on success. For calls to https port (443) an additional cors check is
-// performed to ensure compliance. This class is self-owned: inheritors must
-// call "delete this" at some point in OpenSocket(...).
+// Resolves the host/port pair provided in options. Upon completion invokes the
+// supplied callback and deletes |this|.
 class CONTENT_EXPORT ResolveHostAndOpenSocket
     : public network::ResolveHostClientBase {
  public:
-  ResolveHostAndOpenSocket(base::WeakPtr<DirectSocketsServiceImpl> service,
-                           blink::mojom::DirectSocketOptionsPtr options);
+  using OpenSocketCallback =
+      base::OnceCallback<void(int result,
+                              const absl::optional<net::AddressList>&)>;
 
   ~ResolveHostAndOpenSocket() override;
 
+  static ResolveHostAndOpenSocket* Create(
+      base::WeakPtr<DirectSocketsServiceImpl>,
+      const std::string& host,
+      uint16_t port,
+      OpenSocketCallback);
+
   void Start();
 
-  static int GetHttpsPort();
-  static void SetHttpsPortForTesting(absl::optional<int> port);
+ private:
+  ResolveHostAndOpenSocket(base::WeakPtr<DirectSocketsServiceImpl>,
+                           const std::string& host,
+                           uint16_t port,
+                           OpenSocketCallback);
 
- protected:
   void OnComplete(int result,
                   const net::ResolveErrorInfo& resolve_error_info,
                   const absl::optional<net::AddressList>& resolved_addresses,
                   const absl::optional<net::HostResolverEndpointResults>&
                       endpoint_results_with_metadata) override;
 
-  void PerformCORSCheck(const std::string& address,
-                        net::AddressList resolved_addresses);
-
-  void OnCORSCheckComplete(std::unique_ptr<network::SimpleURLLoader> loader,
-                           net::AddressList resolved_addresses,
-                           scoped_refptr<net::HttpResponseHeaders>);
-
-  virtual void OpenSocket(
-      int result,
-      const absl::optional<net::AddressList>& resolved_addresses) = 0;
+  void OpenSocket(int result,
+                  const absl::optional<net::AddressList>& resolved_addresses);
 
   base::WeakPtr<DirectSocketsServiceImpl> service_;
-  blink::mojom::DirectSocketOptionsPtr options_;
+
+  const std::string host_;
+  uint16_t port_;
+
+  OpenSocketCallback callback_;
 
   bool is_mdns_name_ = false;
-  bool is_raw_address_ = false;
 
   mojo::Receiver<network::mojom::ResolveHostClient> receiver_{this};
   mojo::Remote<network::mojom::HostResolver> resolver_;
 };
 
-using OpenTcpSocketCallback =
-    blink::mojom::DirectSocketsService::OpenTcpSocketCallback;
-
-// Overrides OpenSocket(...) to open a TCP connection.
-class ResolveHostAndOpenTCPSocket final : public ResolveHostAndOpenSocket {
- public:
-  ResolveHostAndOpenTCPSocket(
-      base::WeakPtr<DirectSocketsServiceImpl> service,
-      blink::mojom::DirectSocketOptionsPtr options,
-      mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver,
-      mojo::PendingRemote<network::mojom::SocketObserver> observer,
-      OpenTcpSocketCallback callback);
-
-  ~ResolveHostAndOpenTCPSocket() override;
-
- private:
-  void OpenSocket(
-      int result,
-      const absl::optional<net::AddressList>& resolved_addresses) override;
-
-  mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver_;
-  mojo::PendingRemote<network::mojom::SocketObserver> observer_;
-  OpenTcpSocketCallback callback_;
-};
-
-using OpenUdpSocketCallback =
-    blink::mojom::DirectSocketsService::OpenUdpSocketCallback;
-
-// Overrides OpenSocket(...) to open a UDP connection.
-class ResolveHostAndOpenUDPSocket final : public ResolveHostAndOpenSocket {
- public:
-  ResolveHostAndOpenUDPSocket(
-      base::WeakPtr<DirectSocketsServiceImpl> service,
-      blink::mojom::DirectSocketOptionsPtr options,
-      mojo::PendingReceiver<blink::mojom::DirectUDPSocket> receiver,
-      mojo::PendingRemote<network::mojom::UDPSocketListener> listener,
-      OpenUdpSocketCallback callback);
-
-  ~ResolveHostAndOpenUDPSocket() override;
-
- private:
-  void OpenSocket(
-      int result,
-      const absl::optional<net::AddressList>& resolved_addresses) override;
-
-  void OnUdpConnectCompleted(net::IPEndPoint peer_addr,
-                             int result,
-                             const absl::optional<net::IPEndPoint>& local_addr);
-
-  mojo::PendingReceiver<blink::mojom::DirectUDPSocket> receiver_;
-  mojo::PendingRemote<network::mojom::UDPSocketListener> listener_;
-  OpenUdpSocketCallback callback_;
-};
-
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_DIRECT_SOCKETS_RESOLVE_HOST_AND_OPEN_SOCKET_H_
\ No newline at end of file
diff --git a/content/browser/first_party_sets/database/first_party_sets_database.cc b/content/browser/first_party_sets/database/first_party_sets_database.cc
index fc68894..f37854b 100644
--- a/content/browser/first_party_sets/database/first_party_sets_database.cc
+++ b/content/browser/first_party_sets/database/first_party_sets_database.cc
@@ -22,6 +22,7 @@
 #include "content/browser/first_party_sets/first_party_set_parser.h"
 #include "net/base/schemeful_site.h"
 #include "net/first_party_sets/first_party_set_entry.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
 #include "net/first_party_sets/first_party_sets_context_config.h"
 #include "net/first_party_sets/global_first_party_sets.h"
 #include "sql/database.h"
@@ -416,13 +417,43 @@
   return global_sets;
 }
 
+std::pair<std::vector<net::SchemefulSite>, net::FirstPartySetsCacheFilter>
+FirstPartySetsDatabase::GetSitesToClearFilters(
+    const std::string& browser_context_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!browser_context_id.empty());
+  if (!LazyInit())
+    return {};
+
+  DCHECK_GT(run_count_, 0);
+
+  sql::Transaction transaction(db_.get());
+  if (!transaction.Begin())
+    return {};
+
+  std::vector<net::SchemefulSite> sites_to_clear =
+      FetchSitesToClear(browser_context_id);
+
+  base::flat_map<net::SchemefulSite, int64_t> all_sites_to_clear =
+      FetchAllSitesToClearFilter(browser_context_id);
+
+  net::FirstPartySetsCacheFilter cache_filter =
+      all_sites_to_clear.empty()
+          ? net::FirstPartySetsCacheFilter()
+          : net::FirstPartySetsCacheFilter(std::move(all_sites_to_clear),
+                                           run_count_);
+
+  if (!transaction.Commit())
+    return {};
+
+  return std::make_pair(std::move(sites_to_clear), std::move(cache_filter));
+}
+
 std::vector<net::SchemefulSite> FirstPartySetsDatabase::FetchSitesToClear(
     const std::string& browser_context_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!browser_context_id.empty());
-
-  if (!LazyInit())
-    return {};
+  DCHECK_EQ(db_status_, InitStatus::kSuccess);
 
   // Gets the sites that were marked to clear but haven't been cleared yet for
   // the given `browser_context_id`. Use 0 as the default
@@ -461,10 +492,7 @@
 FirstPartySetsDatabase::FetchAllSitesToClearFilter(
     const std::string& browser_context_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!browser_context_id.empty());
-
-  if (!LazyInit())
-    return {};
+  DCHECK_EQ(db_status_, InitStatus::kSuccess);
 
   std::vector<std::pair<net::SchemefulSite, int64_t>> results;
   static constexpr char kSelectSql[] =
diff --git a/content/browser/first_party_sets/database/first_party_sets_database.h b/content/browser/first_party_sets/database/first_party_sets_database.h
index 05d5a97..ffb0288 100644
--- a/content/browser/first_party_sets/database/first_party_sets_database.h
+++ b/content/browser/first_party_sets/database/first_party_sets_database.h
@@ -26,6 +26,7 @@
 
 namespace net {
 class FirstPartySetEntry;
+class FirstPartySetsCacheFilter;
 class FirstPartySetsContextConfig;
 class GlobalFirstPartySets;
 class SchemefulSite;
@@ -101,15 +102,14 @@
   [[nodiscard]] net::GlobalFirstPartySets GetGlobalSets(
       const std::string& browser_context_id);
 
-  // Gets the list of sites to clear for the `browser_context_id`.
-  [[nodiscard]] std::vector<net::SchemefulSite> FetchSitesToClear(
-      const std::string& browser_context_id);
-
-  // Gets all the sites and mapped to the value of `run_count_`, which
-  // represents the site was added into DB to be cleared in a certain browser
-  // run, for the `browser_context_id`.
-  [[nodiscard]] base::flat_map<net::SchemefulSite, int64_t>
-  FetchAllSitesToClearFilter(const std::string& browser_context_id);
+  // Gets the sites to clear filters. The first filter holds the list of sites
+  // that haven't had their cookies/storage cleared, the second filter is the
+  // cache filter that holds the current `run_count_` and a map of sites to
+  // their `marked_at_run`, containing all the sites that were added into DB to
+  // be cleared in a certain browser run, for the `browser_context_id`.
+  [[nodiscard]] std::pair<std::vector<net::SchemefulSite>,
+                          net::FirstPartySetsCacheFilter>
+  GetSitesToClearFilters(const std::string& browser_context_id);
 
   // Gets the previously-stored policy modifications for the
   // `browser_context_id`.
@@ -149,6 +149,16 @@
   [[nodiscard]] base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>
   FetchManualSets(const std::string& browser_context_id);
 
+  // Gets the list of sites to clear for the `browser_context_id`.
+  [[nodiscard]] std::vector<net::SchemefulSite> FetchSitesToClear(
+      const std::string& browser_context_id);
+
+  // Gets all the sites and mapped to the value of `run_count_`, which
+  // represents the site was added into DB to be cleared in a certain browser
+  // run, for the `browser_context_id`.
+  [[nodiscard]] base::flat_map<net::SchemefulSite, int64_t>
+  FetchAllSitesToClearFilter(const std::string& browser_context_id);
+
   // Called at the start of each public operation, and initializes the database
   // if it isn't already initialized.
   [[nodiscard]] bool LazyInit() VALID_CONTEXT_REQUIRED(sequence_checker_);
diff --git a/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc b/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc
index c4d2db5..f6accc8f 100644
--- a/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc
+++ b/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -16,6 +17,7 @@
 #include "base/version.h"
 #include "net/base/schemeful_site.h"
 #include "net/first_party_sets/first_party_set_entry.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
 #include "net/first_party_sets/first_party_sets_context_config.h"
 #include "net/first_party_sets/global_first_party_sets.h"
 #include "sql/database.h"
@@ -810,101 +812,21 @@
   EXPECT_FALSE(s.Step());
 }
 
-TEST_F(FirstPartySetsDatabaseTest, FetchSitesToClear_NoPreExistingDB) {
+TEST_F(FirstPartySetsDatabaseTest, GetSitesToClearFilters_NoPreExistingDB) {
   OpenDatabase();
-  EXPECT_EQ(std::vector<net::SchemefulSite>(), db()->FetchSitesToClear("b"));
+  std::pair<std::vector<net::SchemefulSite>, net::FirstPartySetsCacheFilter>
+      res = db()->GetSitesToClearFilters("b");
+  EXPECT_THAT(res.first, std::vector<net::SchemefulSite>());
+  EXPECT_EQ(res.second, net::FirstPartySetsCacheFilter());
 }
 
-TEST_F(FirstPartySetsDatabaseTest, FetchSitesToClear_BrowserContextNotExist) {
-  ASSERT_TRUE(
-      sql::test::CreateDatabaseFromSQL(db_path(), GetSqlFilePath("v1.sql")));
-
-  std::string browser_context_id = "b";
-  // Verify data in the pre-existing DB.
-  {
-    sql::Database db;
-    EXPECT_TRUE(db.Open(db_path()));
-    EXPECT_EQ(kTableCount, sql::test::CountSQLTables(&db));
-    EXPECT_EQ(1u, CountBrowserContextsClearedEntries(&db));
-
-    // b hasn't been cleared before.
-    const char kSelectSql[] =
-        "SELECT browser_context_id FROM browser_contexts_cleared";
-    sql::Statement s(db.GetUniqueStatement(kSelectSql));
-    EXPECT_TRUE(s.Step());
-    EXPECT_EQ("b0", s.ColumnString(0));
-    EXPECT_FALSE(s.Step());
-  }
-
-  OpenDatabase();
-  EXPECT_EQ(std::vector<net::SchemefulSite>(),
-            db()->FetchSitesToClear(browser_context_id));
-}
-
-// b1 has sites to clear but hasn't been cleared before.
-TEST_F(FirstPartySetsDatabaseTest, FetchSitesToClear_BrowserContextNotCleared) {
-  ASSERT_TRUE(
-      sql::test::CreateDatabaseFromSQL(db_path(), GetSqlFilePath("v1.sql")));
-
-  const std::string browser_context_id = "b1";
-  // Verify data in the pre-existing DB.
-  {
-    sql::Database db;
-    EXPECT_TRUE(db.Open(db_path()));
-    EXPECT_EQ(kTableCount, sql::test::CountSQLTables(&db));
-    EXPECT_EQ(2u, CountBrowserContextSitesToClearEntries(&db));
-    EXPECT_EQ(1u, CountBrowserContextsClearedEntries(&db));
-
-    const char kSelectSql[] =
-        "SELECT 1 FROM browser_contexts_cleared "
-        "WHERE browser_context_id=?";
-    sql::Statement s(db.GetUniqueStatement(kSelectSql));
-    s.BindString(0, browser_context_id);
-    EXPECT_FALSE(s.Step());
-  }
-
-  OpenDatabase();
-  EXPECT_EQ(std::vector<net::SchemefulSite>(
-                {net::SchemefulSite(GURL("https://example.test"))}),
-            db()->FetchSitesToClear(browser_context_id));
-}
-
-TEST_F(FirstPartySetsDatabaseTest, FetchSitesToClear) {
+TEST_F(FirstPartySetsDatabaseTest, GetSitesToClearFilters) {
   ASSERT_TRUE(
       sql::test::CreateDatabaseFromSQL(db_path(), GetSqlFilePath("v1.sql")));
 
   const std::string browser_context_id = "b0";
-  // Verify data in the pre-existing DB.
-  {
-    sql::Database db;
-    EXPECT_TRUE(db.Open(db_path()));
-    EXPECT_EQ(kTableCount, sql::test::CountSQLTables(&db));
-    EXPECT_EQ(2u, CountBrowserContextSitesToClearEntries(&db));
-    EXPECT_EQ(1u, CountBrowserContextsClearedEntries(&db));
+  const int64_t expected_run_count = 2;
 
-    const char kSelectSql[] =
-        "SELECT browser_context_id FROM browser_contexts_cleared";
-    sql::Statement s(db.GetUniqueStatement(kSelectSql));
-    EXPECT_TRUE(s.Step());
-    EXPECT_EQ(browser_context_id, s.ColumnString(0));
-    EXPECT_FALSE(s.Step());
-  }
-  // Insert new sites to be cleared.
-  std::vector<net::SchemefulSite> input = {
-      net::SchemefulSite(GURL("https://example1.test")),
-      net::SchemefulSite(GURL("https://example2.test")),
-  };
-
-  OpenDatabase();
-  EXPECT_TRUE(db()->InsertSitesToClear(browser_context_id, input));
-  EXPECT_EQ(input, db()->FetchSitesToClear(browser_context_id));
-}
-
-TEST_F(FirstPartySetsDatabaseTest, FetchAllSitesToClearFilter) {
-  ASSERT_TRUE(
-      sql::test::CreateDatabaseFromSQL(db_path(), GetSqlFilePath("v1.sql")));
-
-  const std::string browser_context_id = "b0";
   // Verify data in the pre-existing DB.
   {
     sql::Database db;
@@ -921,20 +843,23 @@
     ASSERT_FALSE(s.Step());
   }
 
+  net::SchemefulSite example(GURL("https://example.test"));
+  net::SchemefulSite example1(GURL("https://example1.test"));
+  net::SchemefulSite example2(GURL("https://example2.test"));
+
+  std::vector<net::SchemefulSite> input = {example1, example2};
+
   // Insert new sites to be cleared.
   OpenDatabase();
-  EXPECT_TRUE(db()->InsertSitesToClear(
-      browser_context_id, {
-                              net::SchemefulSite(GURL("https://example1.test")),
-                              net::SchemefulSite(GURL("https://example2.test")),
-                          }));
+  EXPECT_TRUE(db()->InsertSitesToClear(browser_context_id, input));
 
-  base::flat_map<net::SchemefulSite, int64_t> result = {
-      {net::SchemefulSite(GURL("https://example.test")), 1},
-      {net::SchemefulSite(GURL("https://example1.test")), 2},
-      {net::SchemefulSite(GURL("https://example2.test")), 2}};
+  net::FirstPartySetsCacheFilter cache_filter(
+      {{example, 1}, {example1, 2}, {example2, 2}}, expected_run_count);
 
-  EXPECT_THAT(db()->FetchAllSitesToClearFilter(browser_context_id), result);
+  std::pair<std::vector<net::SchemefulSite>, net::FirstPartySetsCacheFilter>
+      res = db()->GetSitesToClearFilters(browser_context_id);
+  EXPECT_THAT(res.first, input);
+  EXPECT_EQ(res.second, cache_filter);
 }
 
 TEST_F(FirstPartySetsDatabaseTest, FetchPolicyModifications_NoPreExistingDB) {
diff --git a/content/browser/first_party_sets/first_party_sets_handler_database_helper.cc b/content/browser/first_party_sets/first_party_sets_handler_database_helper.cc
index 11595b31..20fa2d65 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_database_helper.cc
+++ b/content/browser/first_party_sets/first_party_sets_handler_database_helper.cc
@@ -10,6 +10,7 @@
 #include "content/browser/first_party_sets/database/first_party_sets_database.h"
 #include "net/base/schemeful_site.h"
 #include "net/first_party_sets/first_party_set_entry.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
 #include "net/first_party_sets/first_party_sets_context_config.h"
 #include "net/first_party_sets/global_first_party_sets.h"
 
@@ -69,7 +70,7 @@
   return result;
 }
 
-std::vector<net::SchemefulSite>
+std::pair<std::vector<net::SchemefulSite>, net::FirstPartySetsCacheFilter>
 FirstPartySetsHandlerDatabaseHelper::UpdateAndGetSitesToClearForContext(
     const std::string& browser_context_id,
     const net::GlobalFirstPartySets& current_sets,
@@ -86,7 +87,7 @@
              << browser_context_id;
     return {};
   }
-  return db_->FetchSitesToClear(browser_context_id);
+  return db_->GetSitesToClearFilters(browser_context_id);
 }
 
 void FirstPartySetsHandlerDatabaseHelper::UpdateClearStatusForContext(
diff --git a/content/browser/first_party_sets/first_party_sets_handler_database_helper.h b/content/browser/first_party_sets/first_party_sets_handler_database_helper.h
index f0e52a4..85faf0f 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_database_helper.h
+++ b/content/browser/first_party_sets/first_party_sets_handler_database_helper.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/containers/flat_map.h"
@@ -21,6 +22,7 @@
 }  // namespace base
 
 namespace net {
+class FirstPartySetsCacheFilter;
 class FirstPartySetsContextConfig;
 class GlobalFirstPartySets;
 class SchemefulSite;
@@ -70,7 +72,8 @@
   // compute the list of sites to clear, stores the sites into DB, then reads
   // the final list of sites to be cleared from DB, which can include sites
   // stored during previous browser runs that did not have state cleared.
-  std::vector<net::SchemefulSite> UpdateAndGetSitesToClearForContext(
+  std::pair<std::vector<net::SchemefulSite>, net::FirstPartySetsCacheFilter>
+  UpdateAndGetSitesToClearForContext(
       const std::string& browser_context_id,
       const net::GlobalFirstPartySets& current_sets,
       const net::FirstPartySetsContextConfig& current_config);
diff --git a/content/browser/first_party_sets/first_party_sets_handler_database_helper_unittest.cc b/content/browser/first_party_sets/first_party_sets_handler_database_helper_unittest.cc
index 36a3a73..5bd5914 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_database_helper_unittest.cc
+++ b/content/browser/first_party_sets/first_party_sets_handler_database_helper_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/version.h"
 #include "net/base/schemeful_site.h"
 #include "net/first_party_sets/first_party_set_entry.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
 #include "net/first_party_sets/first_party_sets_context_config.h"
 #include "net/first_party_sets/global_first_party_sets.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
@@ -455,14 +456,17 @@
                                  example, net::SiteType::kAssociated, 0)}},
       /*aliases=*/{});
 
-  std::vector<net::SchemefulSite> res =
-      db_helper_->UpdateAndGetSitesToClearForContext(
+  std::pair<std::vector<net::SchemefulSite>, net::FirstPartySetsCacheFilter>
+      res = db_helper_->UpdateAndGetSitesToClearForContext(
           browser_context_id, current_sets,
           /*current_config=*/net::FirstPartySetsContextConfig());
 
   // Expected diff: "https://foo.test", "https://member2.test" and
   // "https://member3.test" left FPSs.
-  EXPECT_THAT(res, UnorderedElementsAre(foo, member2, member3));
+  EXPECT_THAT(res.first, UnorderedElementsAre(foo, member2, member3));
+  EXPECT_EQ(res.second, net::FirstPartySetsCacheFilter(
+                            /*filter=*/{{foo, 1}, {member2, 1}, {member3, 1}},
+                            /*browser_run_id=*/1));
 }
 
 }  // namespace content
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.cc b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
index 3fafdd8..d3b24c41 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl.cc
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
@@ -62,10 +62,22 @@
       "FirstPartySets.Initialization.ClearSiteDataOutcomeType", outcome);
 }
 
+// Global FirstPartySetsHandler instance for testing.
+FirstPartySetsHandler* g_test_instance = nullptr;
+
 }  // namespace
 
 // static
+void FirstPartySetsHandler::SetInstanceForTesting(
+    FirstPartySetsHandler* test_instance) {
+  g_test_instance = test_instance;
+}
+
+// static
 FirstPartySetsHandler* FirstPartySetsHandler::GetInstance() {
+  if (g_test_instance)
+    return g_test_instance;
+
   return FirstPartySetsHandlerImpl::GetInstance();
 }
 
@@ -309,11 +321,13 @@
     base::RepeatingCallback<BrowserContext*()> browser_context_getter,
     const std::string& browser_context_id,
     net::FirstPartySetsContextConfig context_config,
-    base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
+    base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                            net::FirstPartySetsCacheFilter)> callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!enabled_ || !features::kFirstPartySetsClearSiteDataOnChangedSets.Get()) {
-    std::move(callback).Run(std::move(context_config));
+    std::move(callback).Run(std::move(context_config),
+                            net::FirstPartySetsCacheFilter());
     return;
   }
 
@@ -335,7 +349,8 @@
     base::RepeatingCallback<BrowserContext*()> browser_context_getter,
     const std::string& browser_context_id,
     net::FirstPartySetsContextConfig context_config,
-    base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
+    base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                            net::FirstPartySetsCacheFilter)> callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(global_sets_.has_value());
   DCHECK(!browser_context_id.empty());
@@ -345,7 +360,8 @@
     VLOG(1) << "Invalid First-Party Sets database. Failed to clear site data "
                "for browser_context_id="
             << browser_context_id;
-    std::move(callback).Run(std::move(context_config));
+    std::move(callback).Run(std::move(context_config),
+                            net::FirstPartySetsCacheFilter());
     return;
   }
 
@@ -353,7 +369,8 @@
   // to prevent the case that `context_config` gets used after it's moved. This
   // is because C++ does not have a defined evaluation order for function
   // parameters.
-  base::OnceCallback<void(std::vector<net::SchemefulSite>)>
+  base::OnceCallback<void(std::pair<std::vector<net::SchemefulSite>,
+                                    net::FirstPartySetsCacheFilter>)>
       on_get_sites_to_clear = base::BindOnce(
           &FirstPartySetsHandlerImpl::OnGetSitesToClear,
           // base::Unretained(this) is safe here because this
@@ -373,8 +390,10 @@
     base::RepeatingCallback<BrowserContext*()> browser_context_getter,
     const std::string& browser_context_id,
     net::FirstPartySetsContextConfig context_config,
-    base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback,
-    std::vector<net::SchemefulSite> sites_to_clear) const {
+    base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                            net::FirstPartySetsCacheFilter)> callback,
+    std::pair<std::vector<net::SchemefulSite>, net::FirstPartySetsCacheFilter>
+        sites_to_clear) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   BrowserContext* browser_context = browser_context_getter.Run();
@@ -383,24 +402,28 @@
                 "browser_context_id="
              << browser_context_id;
 
-    std::move(callback).Run(std::move(context_config));
+    std::move(callback).Run(std::move(context_config),
+                            net::FirstPartySetsCacheFilter());
     return;
   }
 
   FirstPartySetsSiteDataRemover::RemoveSiteData(
-      *browser_context->GetBrowsingDataRemover(), std::move(sites_to_clear),
+      *browser_context->GetBrowsingDataRemover(),
+      std::move(sites_to_clear.first),
       base::BindOnce(
           &FirstPartySetsHandlerImpl::DidClearSiteDataOnChangedSetsForContext,
           // base::Unretained(this) is safe here because
           // this is a static singleton.
           base::Unretained(this), browser_context_id, std::move(context_config),
-          std::move(callback)));
+          std::move(sites_to_clear.second), std::move(callback)));
 }
 
 void FirstPartySetsHandlerImpl::DidClearSiteDataOnChangedSetsForContext(
     const std::string& browser_context_id,
     net::FirstPartySetsContextConfig context_config,
-    base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback,
+    net::FirstPartySetsCacheFilter cache_filter,
+    base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                            net::FirstPartySetsCacheFilter)> callback,
     uint64_t failed_data_types) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!db_helper_.is_null());
@@ -418,7 +441,7 @@
   db_helper_.AsyncCall(&FirstPartySetsHandlerDatabaseHelper::PersistSets)
       .WithArgs(browser_context_id, version_, global_sets_->Clone(),
                 context_config.Clone());
-  std::move(callback).Run(std::move(context_config));
+  std::move(callback).Run(std::move(context_config), std::move(cache_filter));
 }
 
 net::FirstPartySetsContextConfig
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.h b/content/browser/first_party_sets/first_party_sets_handler_impl.h
index 81fc869..5ea1af2 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl.h
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_FIRST_PARTY_SETS_FIRST_PARTY_SETS_HANDLER_IMPL_H_
 
 #include <string>
+#include <utility>
 
 #include "base/callback.h"
 #include "base/containers/circular_deque.h"
@@ -24,6 +25,7 @@
 #include "content/browser/first_party_sets/local_set_declaration.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/first_party_sets_handler.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
 #include "net/first_party_sets/first_party_sets_context_config.h"
 #include "net/first_party_sets/global_first_party_sets.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -121,7 +123,8 @@
       base::RepeatingCallback<BrowserContext*()> browser_context_getter,
       const std::string& browser_context_id,
       net::FirstPartySetsContextConfig context_config,
-      base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback)
+      base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                              net::FirstPartySetsCacheFilter)> callback)
       override;
 
   // Sets whether FPS is enabled (for testing).
@@ -178,7 +181,8 @@
       base::RepeatingCallback<BrowserContext*()> browser_context_getter,
       const std::string& browser_context_id,
       net::FirstPartySetsContextConfig context_config,
-      base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback);
+      base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                              net::FirstPartySetsCacheFilter)> callback);
 
   // Parses the policy and computes the config that represents the changes
   // needed to apply `policy` to `global_sets_`.
@@ -189,8 +193,10 @@
       base::RepeatingCallback<BrowserContext*()> browser_context_getter,
       const std::string& browser_context_id,
       net::FirstPartySetsContextConfig context_config,
-      base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback,
-      std::vector<net::SchemefulSite> sites_to_clear) const;
+      base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                              net::FirstPartySetsCacheFilter)> callback,
+      std::pair<std::vector<net::SchemefulSite>, net::FirstPartySetsCacheFilter>
+          sites_to_clear) const;
 
   // `failed_data_types` is a bitmask used to indicate data types from
   // BrowsingDataRemover::DataType enum that were failed to remove. 0 indicates
@@ -198,7 +204,9 @@
   void DidClearSiteDataOnChangedSetsForContext(
       const std::string& browser_context_id,
       net::FirstPartySetsContextConfig context_config,
-      base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback,
+      net::FirstPartySetsCacheFilter cache_filter,
+      base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                              net::FirstPartySetsCacheFilter)> callback,
       uint64_t failed_data_types) const;
 
   // Whether Init has been called already or not.
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl_unittest.cc b/content/browser/first_party_sets/first_party_sets_handler_impl_unittest.cc
index ce7156c..ec2dc9a 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl_unittest.cc
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl_unittest.cc
@@ -25,6 +25,7 @@
 #include "content/public/test/test_browser_context.h"
 #include "net/base/schemeful_site.h"
 #include "net/first_party_sets/first_party_set_entry.h"
+#include "net/first_party_sets/first_party_sets_cache_filter.h"
 #include "net/first_party_sets/first_party_sets_context_config.h"
 #include "net/first_party_sets/global_first_party_sets.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
@@ -264,7 +265,8 @@
           base::BindLambdaForTesting([&]() { return context(); }),
           browser_context_id, net::FirstPartySetsContextConfig(),
           base::BindLambdaForTesting(
-              [&](net::FirstPartySetsContextConfig) { run_loop.Quit(); }));
+              [&](net::FirstPartySetsContextConfig,
+                  net::FirstPartySetsCacheFilter) { run_loop.Quit(); }));
   run_loop.Run();
 
   EXPECT_THAT(
@@ -318,7 +320,8 @@
           base::BindLambdaForTesting([&]() { return context(); }),
           browser_context_id, net::FirstPartySetsContextConfig(),
           base::BindLambdaForTesting(
-              [&](net::FirstPartySetsContextConfig) { run_loop.Quit(); }));
+              [&](net::FirstPartySetsContextConfig,
+                  net::FirstPartySetsCacheFilter) { run_loop.Quit(); }));
   run_loop.Run();
 
   EXPECT_THAT(
@@ -375,7 +378,8 @@
           base::BindLambdaForTesting([&]() { return context(); }),
           browser_context_id, net::FirstPartySetsContextConfig(),
           base::BindLambdaForTesting(
-              [&](net::FirstPartySetsContextConfig) { run_loop.Quit(); }));
+              [&](net::FirstPartySetsContextConfig,
+                  net::FirstPartySetsCacheFilter) { run_loop.Quit(); }));
   run_loop.Run();
 
   EXPECT_EQ(GetPersistedGlobalSetsAndWait(browser_context_id), absl::nullopt);
@@ -398,7 +402,9 @@
                                                  LocalSetDeclaration());
 
   const std::string browser_context_id = "profile";
-  base::test::TestFuture<net::FirstPartySetsContextConfig> future;
+  base::test::TestFuture<net::FirstPartySetsContextConfig,
+                         net::FirstPartySetsCacheFilter>
+      future;
   FirstPartySetsHandlerImpl::GetInstance()
       ->ClearSiteDataOnChangedSetsForContext(
           base::BindLambdaForTesting([&]() { return context(); }),
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index 05d0c0c3..e82085f 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -17,11 +17,9 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/timer/timer.h"
-#include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
-#include "components/viz/common/features.h"
 #include "components/viz/host/gpu_host_impl.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/gpu/gpu_disk_cache_factory.h"
@@ -34,7 +32,6 @@
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
-#include "gpu/config/gpu_finch_features.h"
 #include "gpu/ipc/common/gpu_client_ids.h"
 #include "gpu/ipc/common/gpu_watchdog_timeout.h"
 #include "services/resource_coordinator/public/mojom/memory_instrumentation/constants.mojom.h"
@@ -281,7 +278,10 @@
     gpu_channel_ = nullptr;
   }
 
-  gpu_memory_buffer_manager_.reset();
+  // This will unblock any other threads waiting on CreateGpuMemoryBuffer()
+  // requests. It runs before IO and thread pool threads are stopped to avoid
+  // shutdown hangs.
+  gpu_memory_buffer_manager_->Shutdown();
 }
 
 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.h b/content/browser/gpu/browser_gpu_channel_host_factory.h
index 76fdbfa..6f70466 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.h
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.h
@@ -18,12 +18,15 @@
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
-#include "ipc/message_filter.h"
 
 namespace gpu {
 class GpuMemoryBufferManager;
 }
 
+namespace viz {
+class HostGpuMemoryBufferManager;
+}
+
 namespace content {
 
 class BrowserGpuChannelHostFactory : public gpu::GpuChannelEstablishFactory {
@@ -77,7 +80,7 @@
   const int gpu_client_id_;
   const uint64_t gpu_client_tracing_id_;
   scoped_refptr<gpu::GpuChannelHost> gpu_channel_;
-  std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
+  std::unique_ptr<viz::HostGpuMemoryBufferManager> gpu_memory_buffer_manager_;
   scoped_refptr<EstablishRequest> pending_request_;
   bool is_visible_ = true;
 
diff --git a/content/browser/media/session/media_session_impl_browsertest.cc b/content/browser/media/session/media_session_impl_browsertest.cc
index 8c3a9202..f30dafe 100644
--- a/content/browser/media/session/media_session_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_impl_browsertest.cc
@@ -3306,8 +3306,7 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     MediaSessionImplBrowserTest::SetUpCommandLine(command_line);
 
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features;
+    std::vector<base::test::FeatureRefAndParams> enabled_features;
     std::map<std::string, std::string> params;
 #if BUILDFLAG(IS_ANDROID)
     params["process_binding_strength"] = "NORMAL";
diff --git a/content/browser/renderer_host/document_service_browsertest.cc b/content/browser/renderer_host/document_service_browsertest.cc
index 7e88f28..ae86739 100644
--- a/content/browser/renderer_host/document_service_browsertest.cc
+++ b/content/browser/renderer_host/document_service_browsertest.cc
@@ -99,8 +99,8 @@
 class DocumentServiceBFCacheBrowserTest : public DocumentServiceBrowserTest {
  public:
   DocumentServiceBFCacheBrowserTest() {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        additional_features = {{features::kBackForwardCache, {}}};
+    std::vector<base::test::FeatureRefAndParams> additional_features = {
+        {features::kBackForwardCache, {}}};
     feature_list_.InitWithFeaturesAndParameters(
         DefaultEnabledBackForwardCacheParametersForTests(additional_features),
         DefaultDisabledBackForwardCacheParametersForTests());
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index 174db29..da50e39 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -159,7 +159,7 @@
 void InitBackForwardCacheFeature(base::test::ScopedFeatureList* feature_list,
                                  bool enable_back_forward_cache) {
   if (enable_back_forward_cache) {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> features;
+    std::vector<base::test::FeatureRefAndParams> features;
     features.push_back({features::kBackForwardCache, {}});
     features.push_back({kBackForwardCacheNoTimeEviction, {}});
     features.push_back({features::kBackForwardCacheMemoryControls, {}});
@@ -17455,6 +17455,79 @@
   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
 }
 
+// Tests that when a navigation entry is not marked as skippable the first time
+// it redirects because of user activation, that entry will be marked skippable
+// if it does another redirect without user activation after the user has come
+// back to that document again. This implies that a single user activation does
+// not mean that the user can be infintely trapped.
+IN_PROC_BROWSER_TEST_P(NavigationControllerHistoryInterventionBrowserTest,
+                       NoUserActivationAfterReturningSetsSkippable) {
+  GURL non_skippable_url(
+      embedded_test_server()->GetURL("/frame_tree/top.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), non_skippable_url));
+
+  GURL initially_non_skippable_url(
+      embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), initially_non_skippable_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetPrimaryFrameTree()
+                            .root();
+
+  EXPECT_FALSE(root->HasStickyUserActivation());
+  EXPECT_FALSE(root->HasTransientUserActivation());
+
+  // Get a user activation and navigate to a new same-site document from the
+  // renderer with a user gesture.
+  GURL redirected_url(embedded_test_server()->GetURL("/title2.html"));
+  EXPECT_TRUE(NavigateToURLFromRenderer(shell(), redirected_url));
+
+  NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
+      shell()->web_contents()->GetController());
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
+
+  // Last entry should have not been marked as skippable.
+  EXPECT_FALSE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui());
+  EXPECT_FALSE(
+      controller.GetLastCommittedEntry()->should_skip_on_back_forward_ui());
+
+  // Navigate back to the earlier document's entry.
+  {
+    TestNavigationObserver back_load_observer(shell()->web_contents());
+    controller.GoBack();
+    back_load_observer.Wait();
+  }
+  EXPECT_EQ(initially_non_skippable_url,
+            controller.GetLastCommittedEntry()->GetURL());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+
+  // Navigate to a new same-site document from the renderer without a user
+  // gesture.
+  EXPECT_TRUE(
+      NavigateToURLFromRendererWithoutUserGesture(shell(), redirected_url));
+
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
+
+  // Last entry should have been marked as skippable due to the lack of
+  // activation on this visit, despite not being marked skippable last time.
+  EXPECT_TRUE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui());
+  EXPECT_FALSE(
+      controller.GetLastCommittedEntry()->should_skip_on_back_forward_ui());
+
+  // Going back now should skip the entry at [1].
+  ASSERT_TRUE(controller.CanGoBack());
+  {
+    TestNavigationObserver back_load_observer(shell()->web_contents());
+    controller.GoBack();
+    back_load_observer.Wait();
+  }
+  EXPECT_EQ(non_skippable_url, controller.GetLastCommittedEntry()->GetURL());
+  EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+}
+
 // Tests that the navigation entry is marked as skippable on back button if it
 // does a renderer initiated navigation without ever getting a user activation.
 // Also tests this for an entry added using history.pushState.
diff --git a/content/browser/renderer_host/pending_beacon_browsertest.cc b/content/browser/renderer_host/pending_beacon_browsertest.cc
index d5cecea..6e9476ec 100644
--- a/content/browser/renderer_host/pending_beacon_browsertest.cc
+++ b/content/browser/renderer_host/pending_beacon_browsertest.cc
@@ -45,8 +45,7 @@
 
 class PendingBeaconTimeoutBrowserTestBase : public ContentBrowserTest {
  protected:
-  using FeaturesType =
-      std::vector<base::test::ScopedFeatureList::FeatureAndParams>;
+  using FeaturesType = std::vector<base::test::FeatureRefAndParams>;
 
   void SetUp() override {
     feature_list_.InitWithFeaturesAndParameters(GetEnabledFeatures(), {});
diff --git a/content/browser/renderer_host/pending_beacon_host_unittest.cc b/content/browser/renderer_host/pending_beacon_host_unittest.cc
index 4468f0e..1cd99b5 100644
--- a/content/browser/renderer_host/pending_beacon_host_unittest.cc
+++ b/content/browser/renderer_host/pending_beacon_host_unittest.cc
@@ -141,9 +141,8 @@
 class PendingBeaconHostTest : public PendingBeaconHostTestBase {
  protected:
   void SetUp() override {
-    const std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features = {{blink::features::kPendingBeaconAPI,
-                             {{"send_on_pagehide", "true"}}}};
+    const std::vector<base::test::FeatureRefAndParams> enabled_features = {
+        {blink::features::kPendingBeaconAPI, {{"send_on_pagehide", "true"}}}};
     feature_list_.InitWithFeaturesAndParameters(enabled_features, {});
     PendingBeaconHostTestBase::SetUp();
   }
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index e4e16cc..3841145 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -1140,8 +1140,8 @@
          !IsAvoidUnnecessaryBeforeUnloadCheckSyncEnabled();
 }
 
-// Returns true if `host` has the Window Placement permission granted.
-bool IsWindowPlacementGranted(RenderFrameHost* host) {
+// Returns true if `host` has the Window Management permission granted.
+bool IsWindowManagementGranted(RenderFrameHost* host) {
   content::PermissionController* permission_controller =
       host->GetBrowserContext()->GetPermissionController();
   DCHECK(permission_controller);
@@ -6644,7 +6644,7 @@
   // CanEnterFullscreenWithoutUserActivation is only ever true in tests, to
   // allow fullscreen when mocking screen orientation changes.
   if (!delegate_->HasSeenRecentScreenOrientationChange() &&
-      !WindowPlacementAllowsFullscreen() && !HasSeenRecentXrOverlaySetup() &&
+      !WindowManagementAllowsFullscreen() && !HasSeenRecentXrOverlaySetup() &&
       !GetContentClient()
            ->browser()
            ->CanEnterFullscreenWithoutUserActivation()) {
@@ -6683,7 +6683,7 @@
           blink::features::kWindowPlacementFullscreenCompanionWindow) &&
       screen && screen->GetNumDisplays() > 1 &&
       screen->GetDisplayWithDisplayId(options->display_id, &display) &&
-      IsWindowPlacementGranted(this)) {
+      IsWindowManagementGranted(this)) {
     transient_allow_popup_.Activate();
   }
 
@@ -10191,8 +10191,8 @@
     GrantFileAccessFromResourceRequestBody(*request->common_params().post_data);
 }
 
-bool RenderFrameHostImpl::WindowPlacementAllowsFullscreen() {
-  return IsWindowPlacementGranted(this) &&
+bool RenderFrameHostImpl::WindowManagementAllowsFullscreen() {
+  return IsWindowManagementGranted(this) &&
          delegate_->IsTransientAllowFullscreenActive();
 }
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 246afde..559a598 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -3048,8 +3048,8 @@
   void UpdatePermissionsForNavigation(NavigationRequest* request);
 
   // Returns true if there is an active transient fullscreen allowance for the
-  // Window Placement feature (i.e. on screen configuration changes).
-  bool WindowPlacementAllowsFullscreen();
+  // Window Management feature (i.e. on screen configuration changes).
+  bool WindowManagementAllowsFullscreen();
 
   // Returns the latest NavigationRequest that has resulted in sending a Commit
   // IPC to the renderer process that hasn't yet been acked by the DidCommit IPC
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc
index 1bb203f..c5f7d455 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc
@@ -432,10 +432,10 @@
   // done in `WebFrameWidgetImpl`.
   const base::Value eval_result =
       EvalJs(wc, "getSelectionBounds();").ExtractList();
-  const int x = floor(eval_result.GetListDeprecated()[0].GetDouble());
-  const int right = ceil(eval_result.GetListDeprecated()[1].GetDouble());
-  const int y = floor(eval_result.GetListDeprecated()[2].GetDouble());
-  const int bottom = ceil(eval_result.GetListDeprecated()[3].GetDouble());
+  const int x = floor(eval_result.GetList()[0].GetDouble());
+  const int right = ceil(eval_result.GetList()[1].GetDouble());
+  const int y = floor(eval_result.GetList()[2].GetDouble());
+  const int bottom = ceil(eval_result.GetList()[3].GetDouble());
   const int expected_dip_width = floor(right / scale()) - ceil(x / scale());
   const int expected_dip_height = floor(bottom / scale()) - ceil(y / scale());
 
diff --git a/content/browser/renderer_host/unassigned_site_instance_browsertest.cc b/content/browser/renderer_host/unassigned_site_instance_browsertest.cc
index ef015cd..922cd74 100644
--- a/content/browser/renderer_host/unassigned_site_instance_browsertest.cc
+++ b/content/browser/renderer_host/unassigned_site_instance_browsertest.cc
@@ -95,7 +95,7 @@
 void InitBackForwardCacheFeature(base::test::ScopedFeatureList* feature_list,
                                  bool enable_back_forward_cache) {
   if (enable_back_forward_cache) {
-    std::vector<base::test::ScopedFeatureList::FeatureAndParams> features;
+    std::vector<base::test::FeatureRefAndParams> features;
     features.push_back({features::kBackForwardCache, {}});
     features.push_back({kBackForwardCacheNoTimeEviction, {}});
     features.push_back({features::kBackForwardCacheMemoryControls, {}});
diff --git a/content/browser/resources/attribution_reporting/attribution_internals.ts b/content/browser/resources/attribution_reporting/attribution_internals.ts
index 6d3a4f4..f222397 100644
--- a/content/browser/resources/attribution_reporting/attribution_internals.ts
+++ b/content/browser/resources/attribution_reporting/attribution_internals.ts
@@ -83,6 +83,27 @@
   }
 }
 
+class StructuredColumn<T> extends ValueColumn<T, Record<string, string>> {
+  constructor(header: string, getValue: (p: T) => Record<string, string>) {
+    super(header, getValue);
+  }
+
+  override render(td: HTMLElement, row: T) {
+    const dl = td.ownerDocument.createElement('dl');
+    for (const [key, value] of Object.entries(this.getValue(row))) {
+      const dt = td.ownerDocument.createElement('dt');
+      dt.innerText = key;
+      const dd = td.ownerDocument.createElement('dd');
+      dd.innerText = value;
+
+      dl.appendChild(dt);
+      dl.appendChild(dd);
+    }
+
+    td.appendChild(dl);
+  }
+}
+
 const debugPathPattern: RegExp =
     /(?<=\/\.well-known\/attribution-reporting\/)debug(?=\/)/;
 
@@ -652,48 +673,105 @@
   }
 }
 
-class Log {
-  json: string;
-  failureReason: string;
-  time: Date;
-  reportingOrigin: string;
+
+enum LogType {
+  FAILED_SOURCE_REGISTRATION = 'FailedSourceRegistration',
+}
+interface Log {
+  timestamp: Date;
+  type: LogType;
+  metadata: Record<string, string>;
+}
+
+class FailedSourceRegistrationLog implements Log {
+  public readonly type: LogType = LogType.FAILED_SOURCE_REGISTRATION;
+
+  private readonly timestamp_: Date;
+  private readonly metadata_: Record<string, string>;
 
   constructor(mojo: FailedSourceRegistration) {
-    this.time = new Date(mojo.time);
-    this.json = mojo.headerValue;
-    this.reportingOrigin = originToText(mojo.reportingOrigin);
-
+    let failureReason;
     switch (mojo.error) {
       case SourceRegistrationError.kInvalidJson:
-        this.failureReason = 'invalid JSON';
+        failureReason = 'invalid JSON';
         break;
       case SourceRegistrationError.kRootWrongType:
-        this.failureReason =
-            'root JSON value has wrong type (should be a dictionary)';
+        failureReason = 'root JSON value has wrong type (must be a dictionary)';
         break;
       case SourceRegistrationError.kDestinationMissing:
-        this.failureReason = 'destination missing';
+        failureReason = 'destination missing';
         break;
       case SourceRegistrationError.kDestinationWrongType:
-        this.failureReason = 'destination has wrong type (should be a string)';
+        failureReason = 'destination has wrong type (must be a string)';
         break;
       case SourceRegistrationError.kDestinationUntrustworthy:
-        this.failureReason = 'destination not potentially trustworthy';
+        failureReason = 'destination not potentially trustworthy';
         break;
       case SourceRegistrationError.kDestinationMismatched:
-        this.failureReason =
+        failureReason =
             'destination differs from that of previous source in redirect chain';
         break;
-      case SourceRegistrationError.kFilterDataInvalid:
-        this.failureReason = 'filter_data invalid';
+      case SourceRegistrationError.kFilterDataWrongType:
+        failureReason = 'filter_data has wrong type (must be a dictionary)';
         break;
-      case SourceRegistrationError.kAggregationKeysInvalid:
-        this.failureReason = 'aggregation_keys invalid';
+      case SourceRegistrationError.kFilterDataTooManyKeys:
+        failureReason = 'filter_data has too many keys';
+        break;
+      case SourceRegistrationError.kFilterDataHasSourceTypeKey:
+        failureReason = 'filter_data must not have a source_type key';
+        break;
+      case SourceRegistrationError.kFilterDataKeyTooLong:
+        failureReason = 'filter_data key too long';
+        break;
+      case SourceRegistrationError.kFilterDataListWrongType:
+        failureReason = 'filter_data value has wrong type (must be a list)';
+        break;
+      case SourceRegistrationError.kFilterDataListTooLong:
+        failureReason = 'filter_data list too long';
+        break;
+      case SourceRegistrationError.kFilterDataValueWrongType:
+        failureReason =
+            'filter_data list value has wrong type (must be a string)';
+        break;
+      case SourceRegistrationError.kFilterDataValueTooLong:
+        failureReason = 'filter_data list value too long';
+        break;
+      case SourceRegistrationError.kAggregationKeysWrongType:
+        failureReason =
+            'aggregation_keys has wrong type (must be a dictionary)';
+        break;
+      case SourceRegistrationError.kAggregationKeysTooManyKeys:
+        failureReason = 'aggregation_keys has too many keys';
+        break;
+      case SourceRegistrationError.kAggregationKeysKeyTooLong:
+        failureReason = 'aggregation_keys key too long';
+        break;
+      case SourceRegistrationError.kAggregationKeysValueWrongType:
+        failureReason =
+            'aggregation_keys value has wrong type (must be a string)';
+        break;
+      case SourceRegistrationError.kAggregationKeysValueWrongFormat:
+        failureReason =
+            'aggregation_keys value must be a base-16 integer starting with 0x';
         break;
       default:
-        this.failureReason = 'unknown error';
+        failureReason = 'unknown error';
         break;
     }
+
+    this.timestamp_ = new Date(mojo.time);
+    this.metadata_ = {
+      'Failure Reason': failureReason,
+      'Report To': originToText(mojo.reportingOrigin),
+      'Attribution-Reporting-Register-Source Header': mojo.headerValue,
+    };
+  }
+
+  get timestamp(): Date {
+    return this.timestamp_;
+  }
+  get metadata(): Record<string, string> {
+    return this.metadata_;
   }
 }
 
@@ -704,11 +782,9 @@
     super();
 
     this.cols = [
-      new DateColumn<Log>('Time', (e) => e.time),
-      new CodeColumn<Log>('Failure Reason', (e) => e.failureReason),
-      new ValueColumn<Log, string>('Report To', (e) => e.reportingOrigin),
-      new CodeColumn<Log>(
-          'Attribution-Reporting-Register-Source Header', (e) => e.json),
+      new DateColumn<Log>('Timestamp', (e) => e.timestamp),
+      new ValueColumn<Log, string>('Type', (e) => e.type),
+      new StructuredColumn<Log>('Metadata', (e) => e.metadata),
     ];
 
     this.emptyRowText = 'No logs.';
@@ -978,7 +1054,7 @@
 
   onFailedSourceRegistration(mojo: FailedSourceRegistration) {
     assert(logTableModel);
-    logTableModel.addLog(new Log(mojo));
+    logTableModel.addLog(new FailedSourceRegistrationLog(mojo));
   }
 }
 
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index fb6190922..f712630 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -235,6 +235,10 @@
     ukm::SourceId source_id = main_frame->GetPageUkmSourceId();
     LogMixedContentMetrics(MixedContentType::kOptionallyBlockableMixedContent,
                            source_id, ukm::UkmRecorder::Get());
+    WebContents* contents = WebContents::FromRenderFrameHost(main_frame);
+    if (contents) {
+      GetContentClient()->browser()->OnDisplayInsecureContent(contents);
+    }
   }
   UpdateLastCommittedEntry(SSLStatus::DISPLAYED_INSECURE_CONTENT, 0);
 }
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 04bd4519..c1200d6 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -442,8 +442,8 @@
   return set_holder->set();
 }
 
-// Returns true if `host` has the Window Placement permission granted.
-bool IsWindowPlacementGranted(RenderFrameHost* host) {
+// Returns true if `host` has the Window Management permission granted.
+bool IsWindowManagementGranted(RenderFrameHost* host) {
   content::PermissionController* permission_controller =
       host->GetBrowserContext()->GetPermissionController();
   DCHECK(permission_controller);
@@ -470,7 +470,7 @@
   // Check, but do not prompt, for permission to place windows on other screens.
   // Sites generally need permission to get such bounds in the first place.
   // Also clamp offscreen bounds to the window's current screen.
-  if (!bounds->Intersects(display.bounds()) || !IsWindowPlacementGranted(host))
+  if (!bounds->Intersects(display.bounds()) || !IsWindowManagementGranted(host))
     display = screen->GetDisplayNearestView(host->GetNativeView());
 
   bounds->AdjustToFit(display.work_area());
@@ -4199,7 +4199,7 @@
 
   // Drop fullscreen when opening a WebContents to prohibit deceptive behavior.
   // Only drop fullscreen on the specific destination display, if it is known.
-  // This supports sites using cross-screen window placement capabilities to
+  // This supports sites using cross-screen window management capabilities to
   // retain fullscreen and open a window on another screen.
   ForSecurityDropFullscreen(display_id).RunAndReset();
 
@@ -7411,7 +7411,7 @@
 
   // Drop fullscreen when placing a WebContents to prohibit deceptive behavior.
   // Only drop fullscreen on the specific destination display, which is known.
-  // This supports sites using cross-screen window placement capabilities to
+  // This supports sites using cross-screen window management capabilities to
   // retain fullscreen and place a window on another screen.
   ForSecurityDropFullscreen(display_id).RunAndReset();
 
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index bd3fb9a..49597bc 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -8771,7 +8771,8 @@
   auto credentials = GetCredentials(kTestRelyingPartyId);
   EXPECT_EQ(credentials.size(), 1u);
   const CredentialMetadata& metadata = credentials.at(0).metadata;
-  EXPECT_FALSE(metadata.is_resident);
+  // New credentials are always created discoverable.
+  EXPECT_TRUE(metadata.is_resident);
   auto expected_user = GetTestPublicKeyCredentialUserEntity();
   EXPECT_EQ(metadata.ToPublicKeyCredentialUserEntity(), expected_user);
 }
@@ -8798,18 +8799,6 @@
   mojo::Remote<blink::mojom::Authenticator> authenticator =
       ConnectToAuthenticator();
 
-  // Non-resident credentials with the same user ID will overwrite each other.
-  touch_id_test_environment_.SimulateTouchIdPromptSuccess();
-  EXPECT_EQ(AuthenticatorMakeCredential().status, AuthenticatorStatus::SUCCESS);
-  EXPECT_EQ(GetCredentials(kTestRelyingPartyId).size(), 1u);
-  const std::vector<uint8_t> credential_id =
-      GetCredentials(kTestRelyingPartyId).at(0).credential_id;
-  touch_id_test_environment_.SimulateTouchIdPromptSuccess();
-  EXPECT_EQ(AuthenticatorMakeCredential().status, AuthenticatorStatus::SUCCESS);
-  EXPECT_EQ(GetCredentials(kTestRelyingPartyId).size(), 1u);
-  EXPECT_NE(GetCredentials(kTestRelyingPartyId).at(0).credential_id,
-            credential_id);
-
   // A resident credential will overwrite the non-resident one.
   auto options = GetTestPublicKeyCredentialCreationOptions();
   options->authenticator_selection->authenticator_attachment =
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index 73fb61c..0ab9f47 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -584,9 +584,7 @@
                                                   const std::string& endpoint) {
   if (endpoint.empty())
     return GURL();
-  GURL manifest_url =
-      idp.config_url.Resolve(IdpNetworkRequestManager::kManifestFilePath);
-  return manifest_url.Resolve(endpoint);
+  return idp.config_url.Resolve(endpoint);
 }
 
 bool FederatedAuthRequestImpl::IsEndpointUrlValid(const IdentityProvider& idp,
@@ -609,12 +607,8 @@
       base::BindOnce(&FederatedAuthRequestImpl::OnManifestListFetched,
                      weak_ptr_factory_.GetWeakPtr(), idp);
 
-  if (IsFedCmManifestValidationEnabled()) {
-    network_manager_->FetchManifestList(idp.config_url,
-                                        std::move(manifest_list_callback));
-  } else {
-    idp_info_[idp.config_url].manifest_list_checked = true;
-  }
+  network_manager_->FetchManifestList(idp.config_url,
+                                      std::move(manifest_list_callback));
   network_manager_->FetchManifest(idp.config_url, icon_ideal_size,
                                   icon_minimum_size,
                                   std::move(manifest_callback));
@@ -624,29 +618,33 @@
     const IdentityProvider& idp,
     IdpNetworkRequestManager::FetchStatus status,
     const std::set<GURL>& urls) {
-  switch (status) {
-    case IdpNetworkRequestManager::FetchStatus::kHttpNotFoundError: {
+  constexpr char kWellKnownFileStr[] = "well-known file";
+  switch (status.parse_status) {
+    case IdpNetworkRequestManager::ParseStatus::kHttpNotFoundError: {
+      MaybeAddResponseCodeToConsole(kWellKnownFileStr, status.response_code);
       CompleteRequestWithError(
           FederatedAuthRequestResult::kErrorFetchingManifestListHttpNotFound,
           TokenStatus::kManifestListHttpNotFound,
           /*should_delay_callback=*/true);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kNoResponseError: {
+    case IdpNetworkRequestManager::ParseStatus::kNoResponseError: {
+      MaybeAddResponseCodeToConsole(kWellKnownFileStr, status.response_code);
       CompleteRequestWithError(
           FederatedAuthRequestResult::kErrorFetchingManifestListNoResponse,
           TokenStatus::kManifestListNoResponse,
           /*should_delay_callback=*/true);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kInvalidResponseError: {
+    case IdpNetworkRequestManager::ParseStatus::kInvalidResponseError: {
+      MaybeAddResponseCodeToConsole(kWellKnownFileStr, status.response_code);
       CompleteRequestWithError(
           FederatedAuthRequestResult::kErrorFetchingManifestListInvalidResponse,
           TokenStatus::kManifestListInvalidResponse,
           /*should_delay_callback=*/true);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kSuccess: {
+    case IdpNetworkRequestManager::ParseStatus::kSuccess: {
       // Intentional fall-through.
     }
   }
@@ -694,29 +692,33 @@
     IdpNetworkRequestManager::FetchStatus status,
     IdpNetworkRequestManager::Endpoints endpoints,
     IdentityProviderMetadata idp_metadata) {
-  switch (status) {
-    case IdpNetworkRequestManager::FetchStatus::kHttpNotFoundError: {
+  constexpr char kConfigFileStr[] = "config file";
+  switch (status.parse_status) {
+    case IdpNetworkRequestManager::ParseStatus::kHttpNotFoundError: {
+      MaybeAddResponseCodeToConsole(kConfigFileStr, status.response_code);
       CompleteRequestWithError(
           FederatedAuthRequestResult::kErrorFetchingManifestHttpNotFound,
           TokenStatus::kManifestHttpNotFound,
           /*should_delay_callback=*/true);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kNoResponseError: {
+    case IdpNetworkRequestManager::ParseStatus::kNoResponseError: {
+      MaybeAddResponseCodeToConsole(kConfigFileStr, status.response_code);
       CompleteRequestWithError(
           FederatedAuthRequestResult::kErrorFetchingManifestNoResponse,
           TokenStatus::kManifestNoResponse,
           /*should_delay_callback=*/true);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kInvalidResponseError: {
+    case IdpNetworkRequestManager::ParseStatus::kInvalidResponseError: {
+      MaybeAddResponseCodeToConsole(kConfigFileStr, status.response_code);
       CompleteRequestWithError(
           FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse,
           TokenStatus::kManifestInvalidResponse,
           /*should_delay_callback=*/true);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kSuccess: {
+    case IdpNetworkRequestManager::ParseStatus::kSuccess: {
       // Intentional fall-through.
     }
   }
@@ -759,31 +761,7 @@
         /*should_delay_callback=*/true);
     return;
   }
-  if (IsEndpointUrlValid(idp_info.provider,
-                         idp_info.endpoints.client_metadata)) {
-    network_manager_->FetchClientMetadata(
-        idp_info.endpoints.client_metadata, idp_info.provider.client_id,
-        base::BindOnce(
-            &FederatedAuthRequestImpl::OnClientMetadataResponseReceived,
-            weak_ptr_factory_.GetWeakPtr(),
-            idp_info_[idp_info.provider.config_url]));
-  } else {
-    MaybeFetchAccounts(idp_info);
-  }
-}
 
-void FederatedAuthRequestImpl::OnClientMetadataResponseReceived(
-    const IdentityProviderInfo& idp_info,
-    IdpNetworkRequestManager::FetchStatus status,
-    IdpNetworkRequestManager::ClientMetadata data) {
-  // TODO(yigu): Clean up the client metadata related errors for metrics and
-  // console logs.
-  client_metadata_ = data;
-  MaybeFetchAccounts(idp_info);
-}
-
-void FederatedAuthRequestImpl::MaybeFetchAccounts(
-    const IdentityProviderInfo& idp_info) {
   // Make sure that we don't fetch accounts if the IDP sign-in bit is reset to
   // false during the API call. e.g. by the login/logout HEADER.
   if (ShouldFailIfNotSignedInWithIdp(idp_info.provider.config_url,
@@ -801,6 +779,89 @@
                      idp_info_[idp_info.provider.config_url]));
 }
 
+void FederatedAuthRequestImpl::OnClientMetadataResponseReceived(
+    const IdentityProviderInfo& idp_info,
+    const IdpNetworkRequestManager::AccountList& accounts,
+    IdpNetworkRequestManager::FetchStatus status,
+    IdpNetworkRequestManager::ClientMetadata client_metadata) {
+  MaybeShowAccountsDialog(idp_info, accounts, client_metadata);
+}
+
+void FederatedAuthRequestImpl::MaybeShowAccountsDialog(
+    const IdentityProviderInfo& idp_info,
+    const IdpNetworkRequestManager::AccountList& accounts,
+    const IdpNetworkRequestManager::ClientMetadata& client_metadata) {
+  // TODO(yigu): Clean up the client metadata related errors for metrics and
+  // console logs.
+
+  bool is_visible = (render_frame_host().IsActive() &&
+                     render_frame_host().GetVisibilityState() ==
+                         content::PageVisibilityState::kVisible);
+  fedcm_metrics_->RecordWebContentsVisibilityUponReadyToShowDialog(is_visible);
+  // Does not show the dialog if the user has left the page. e.g. they may
+  // open a new tab before browser is ready to show the dialog.
+  if (!is_visible) {
+    CompleteRequestWithError(FederatedAuthRequestResult::kErrorRpPageNotVisible,
+                             TokenStatus::kRpPageNotVisible,
+                             /*should_delay_callback=*/true);
+    return;
+  }
+
+  WebContents* rp_web_contents =
+      WebContents::FromRenderFrameHost(&render_frame_host());
+  DCHECK(render_frame_host().GetMainFrame()->IsInPrimaryMainFrame());
+
+  bool screen_reader_is_on = rp_web_contents->GetAccessibilityMode().has_mode(
+      ui::AXMode::kScreenReader);
+  // Auto signs in returning users if they have a single account and are
+  // signing in.
+  // TODO(yigu): Add additional controls for RP/IDP/User for this flow.
+  // https://crbug.com/1236678.
+  bool is_auto_sign_in = prefer_auto_sign_in_ && accounts.size() == 1 &&
+                         accounts[0].login_state == LoginState::kSignIn &&
+                         !screen_reader_is_on;
+  ClientIdData client_id_data{GURL(client_metadata.terms_of_service_url),
+                              GURL(client_metadata.privacy_policy_url)};
+
+  show_accounts_dialog_time_ = base::TimeTicks::Now();
+  fedcm_metrics_->RecordShowAccountsDialogTime(show_accounts_dialog_time_ -
+                                               start_time_);
+
+  std::string idp_for_display =
+      FormatUrlForDisplay(idp_info.provider.config_url);
+  IdentityProviderData idp_data(idp_for_display, accounts, *idp_info.metadata,
+                                client_id_data);
+  idp_data_.insert({idp_info.provider.config_url, idp_data});
+
+  pending_idps_.erase(idp_info.provider.config_url);
+  if (!pending_idps_.empty())
+    return;
+
+  std::string rp_url_for_display =
+      FormatUrlForDisplay(rp_web_contents->GetLastCommittedURL());
+
+  std::vector<IdentityProviderData> idp_data_for_display;
+  for (const auto& idp : idp_order_) {
+    if (idp_data_.count(idp))
+      idp_data_for_display.push_back(idp_data_.at(idp));
+  }
+
+  absl::optional<std::string> iframe_url_for_display = absl::nullopt;
+  if (IsFedCmIframeSupportEnabled() && show_iframe_requester_) {
+    iframe_url_for_display =
+        FormatUrlForDisplay(render_frame_host().GetLastCommittedURL());
+  }
+
+  request_dialog_controller_->ShowAccountsDialog(
+      rp_web_contents, rp_url_for_display, iframe_url_for_display,
+      idp_data_for_display,
+      is_auto_sign_in ? SignInMode::kAuto : SignInMode::kExplicit,
+      base::BindOnce(&FederatedAuthRequestImpl::OnAccountSelected,
+                     weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&FederatedAuthRequestImpl::OnDialogDismissed,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
 void FederatedAuthRequestImpl::HandleAccountsFetchFailure(
     const GURL& idp_url,
     blink::mojom::FederatedAuthRequestResult result,
@@ -845,107 +906,62 @@
     const IdentityProviderInfo& idp_info,
     IdpNetworkRequestManager::FetchStatus status,
     IdpNetworkRequestManager::AccountList accounts) {
-  switch (status) {
-    case IdpNetworkRequestManager::FetchStatus::kHttpNotFoundError: {
+  constexpr char kAccountsUrl[] = "accounts endpoint";
+  switch (status.parse_status) {
+    case IdpNetworkRequestManager::ParseStatus::kHttpNotFoundError: {
+      MaybeAddResponseCodeToConsole(kAccountsUrl, status.response_code);
       HandleAccountsFetchFailure(
           idp_info.provider.config_url,
           FederatedAuthRequestResult::kErrorFetchingAccountsHttpNotFound,
           TokenStatus::kAccountsHttpNotFound);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kNoResponseError: {
+    case IdpNetworkRequestManager::ParseStatus::kNoResponseError: {
+      MaybeAddResponseCodeToConsole(kAccountsUrl, status.response_code);
       HandleAccountsFetchFailure(
           idp_info.provider.config_url,
           FederatedAuthRequestResult::kErrorFetchingAccountsNoResponse,
           TokenStatus::kAccountsNoResponse);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kInvalidResponseError: {
+    case IdpNetworkRequestManager::ParseStatus::kInvalidResponseError: {
+      MaybeAddResponseCodeToConsole(kAccountsUrl, status.response_code);
       HandleAccountsFetchFailure(
           idp_info.provider.config_url,
           FederatedAuthRequestResult::kErrorFetchingAccountsInvalidResponse,
           TokenStatus::kAccountsInvalidResponse);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kSuccess: {
+    case IdpNetworkRequestManager::ParseStatus::kSuccess: {
+      ComputeLoginStateAndReorderAccounts(idp_info.provider, accounts);
+
       const url::Origin idp_origin =
           url::Origin::Create(idp_info.provider.config_url);
       sharing_permission_delegate_->SetIdpSigninStatus(idp_origin, true);
 
-      bool is_visible = (render_frame_host().IsActive() &&
-                         render_frame_host().GetVisibilityState() ==
-                             content::PageVisibilityState::kVisible);
-      fedcm_metrics_->RecordWebContentsVisibilityUponReadyToShowDialog(
-          is_visible);
-      // Does not show the dialog if the user has left the page. e.g. they may
-      // open a new tab before browser is ready to show the dialog.
-      if (!is_visible) {
-        CompleteRequestWithError(
-            FederatedAuthRequestResult::kErrorRpPageNotVisible,
-            TokenStatus::kRpPageNotVisible,
-            /*should_delay_callback=*/true);
-        return;
+      bool need_client_metadata = false;
+      for (const IdentityRequestAccount& account : accounts) {
+        // ComputeLoginStateAndReorderAccounts() should have populated
+        // IdentityRequestAccount::login_state.
+        DCHECK(account.login_state);
+        if (*account.login_state == LoginState::kSignUp) {
+          need_client_metadata = true;
+          break;
+        }
       }
 
-      WebContents* rp_web_contents =
-          WebContents::FromRenderFrameHost(&render_frame_host());
-      DCHECK(render_frame_host().GetMainFrame()->IsInPrimaryMainFrame());
-
-      ComputeLoginStateAndReorderAccounts(idp_info.provider, accounts);
-
-      bool screen_reader_is_on =
-          rp_web_contents->GetAccessibilityMode().has_mode(
-              ui::AXMode::kScreenReader);
-      // Auto signs in returning users if they have a single account and are
-      // signing in.
-      // TODO(yigu): Add additional controls for RP/IDP/User for this flow.
-      // https://crbug.com/1236678.
-      bool is_auto_sign_in = prefer_auto_sign_in_ && accounts.size() == 1 &&
-                             accounts[0].login_state == LoginState::kSignIn &&
-                             !screen_reader_is_on;
-      // TODO(cbiesinger): Check that the URLs are valid.
-      ClientIdData client_id_data{GURL(client_metadata_.terms_of_service_url),
-                                  GURL(client_metadata_.privacy_policy_url)};
-
-      show_accounts_dialog_time_ = base::TimeTicks::Now();
-      fedcm_metrics_->RecordShowAccountsDialogTime(show_accounts_dialog_time_ -
-                                                   start_time_);
-
-      std::string idp_for_display =
-          FormatUrlForDisplay(idp_info.provider.config_url);
-      IdentityProviderData idp_data(idp_for_display, accounts,
-                                    *idp_info.metadata, client_id_data);
-      idp_data_.insert({idp_info.provider.config_url, idp_data});
-
-      pending_idps_.erase(idp_info.provider.config_url);
-      if (!pending_idps_.empty())
-        return;
-
-      std::string rp_url_for_display =
-          FormatUrlForDisplay(rp_web_contents->GetLastCommittedURL());
-
-      std::vector<IdentityProviderData> idp_data_for_display;
-      for (const auto& idp : idp_order_) {
-        if (idp_data_.count(idp))
-          idp_data_for_display.push_back(idp_data_.at(idp));
+      if (need_client_metadata &&
+          IsEndpointUrlValid(idp_info.provider,
+                             idp_info.endpoints.client_metadata)) {
+        network_manager_->FetchClientMetadata(
+            idp_info.endpoints.client_metadata, idp_info.provider.client_id,
+            base::BindOnce(
+                &FederatedAuthRequestImpl::OnClientMetadataResponseReceived,
+                weak_ptr_factory_.GetWeakPtr(), idp_info, std::move(accounts)));
+      } else {
+        MaybeShowAccountsDialog(idp_info, accounts,
+                                IdpNetworkRequestManager::ClientMetadata());
       }
-
-      absl::optional<std::string> iframe_url_for_display = absl::nullopt;
-
-      if (IsFedCmIframeSupportEnabled() && show_iframe_requester_) {
-        iframe_url_for_display =
-            FormatUrlForDisplay(render_frame_host().GetLastCommittedURL());
-      }
-
-      request_dialog_controller_->ShowAccountsDialog(
-          rp_web_contents, rp_url_for_display, iframe_url_for_display,
-          idp_data_for_display,
-          is_auto_sign_in ? SignInMode::kAuto : SignInMode::kExplicit,
-          base::BindOnce(&FederatedAuthRequestImpl::OnAccountSelected,
-                         weak_ptr_factory_.GetWeakPtr()),
-          base::BindOnce(&FederatedAuthRequestImpl::OnDialogDismissed,
-                         weak_ptr_factory_.GetWeakPtr()));
-      return;
     }
   }
 }
@@ -1110,29 +1126,33 @@
     IdpNetworkRequestManager::FetchStatus status,
     const std::string& token) {
   DCHECK(!start_time_.is_null());
-  switch (status) {
-    case IdpNetworkRequestManager::FetchStatus::kHttpNotFoundError: {
+  constexpr char kIdAssertionUrl[] = "id assertion endpoint";
+  switch (status.parse_status) {
+    case IdpNetworkRequestManager::ParseStatus::kHttpNotFoundError: {
+      MaybeAddResponseCodeToConsole(kIdAssertionUrl, status.response_code);
       CompleteRequestWithError(
           FederatedAuthRequestResult::kErrorFetchingIdTokenHttpNotFound,
           TokenStatus::kIdTokenHttpNotFound,
           /*should_delay_callback=*/true);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kNoResponseError: {
+    case IdpNetworkRequestManager::ParseStatus::kNoResponseError: {
+      MaybeAddResponseCodeToConsole(kIdAssertionUrl, status.response_code);
       CompleteRequestWithError(
           FederatedAuthRequestResult::kErrorFetchingIdTokenNoResponse,
           TokenStatus::kIdTokenNoResponse,
           /*should_delay_callback=*/true);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kInvalidResponseError: {
+    case IdpNetworkRequestManager::ParseStatus::kInvalidResponseError: {
+      MaybeAddResponseCodeToConsole(kIdAssertionUrl, status.response_code);
       CompleteRequestWithError(
           FederatedAuthRequestResult::kErrorFetchingIdTokenInvalidResponse,
           TokenStatus::kIdTokenInvalidResponse,
           /*should_delay_callback=*/true);
       return;
     }
-    case IdpNetworkRequestManager::FetchStatus::kSuccess: {
+    case IdpNetworkRequestManager::ParseStatus::kSuccess: {
       // Grant sharing permission specific to *this account*.
       //
       // TODO(majidvp): But wait which account?
@@ -1157,7 +1177,7 @@
           token_response_time_ - select_account_time_,
           token_response_time_ - start_time_);
 
-      if (endpoints_.metrics.is_valid()) {
+      if (endpoints_.metrics.is_valid() && IsFedCmMetricsEndpointEnabled()) {
         network_manager_->SendSuccessfulTokenRequestMetrics(
             endpoints_.metrics, show_accounts_dialog_time_ - start_time_,
             select_account_time_ - show_accounts_dialog_time_,
@@ -1244,7 +1264,7 @@
     AddInspectorIssue(result);
     AddConsoleErrorMessage(result);
 
-    if (endpoints_.metrics.is_valid()) {
+    if (endpoints_.metrics.is_valid() && IsFedCmMetricsEndpointEnabled()) {
       network_manager_->SendFailedTokenRequestMetrics(
           endpoints_.metrics,
           FederatedAuthRequestResultToMetricsEndpointErrorCode(result));
@@ -1306,6 +1326,30 @@
       blink::mojom::ConsoleMessageLevel::kError, message);
 }
 
+void FederatedAuthRequestImpl::MaybeAddResponseCodeToConsole(
+    const char* fetch_description,
+    int response_code) {
+  // Do not add error message for OK response status.
+  if (response_code >= 200 && response_code <= 299)
+    return;
+
+  std::ostringstream message;
+  if (response_code < 0) {
+    // In this case, the |response_code| represents a NET_ERROR, so we should
+    // use a helper function to ensure we use a meaningful message.
+    message << "The fetch of " << fetch_description
+            << " resulted in a network error: "
+            << net::ErrorToShortString(response_code);
+  } else {
+    // In this case, the |response_code| represents an HTTP error code, which is
+    // standard and hence the number by itself should be understood.
+    message << "When fetching the " << fetch_description << ", a "
+            << response_code << " HTTP response code was received.";
+  }
+  render_frame_host().AddMessageToConsole(
+      blink::mojom::ConsoleMessageLevel::kError, message.str());
+}
+
 bool FederatedAuthRequestImpl::ShouldCompleteRequestImmediately() {
   return api_permission_delegate_->ShouldCompleteRequestImmediately();
 }
diff --git a/content/browser/webid/federated_auth_request_impl.h b/content/browser/webid/federated_auth_request_impl.h
index bdcca7b..16f575a 100644
--- a/content/browser/webid/federated_auth_request_impl.h
+++ b/content/browser/webid/federated_auth_request_impl.h
@@ -126,12 +126,14 @@
   void OnManifestReady(const IdentityProviderInfo& idp_info);
   void OnClientMetadataResponseReceived(
       const IdentityProviderInfo& idp_info,
+      const IdpNetworkRequestManager::AccountList& accounts,
       IdpNetworkRequestManager::FetchStatus status,
-      IdpNetworkRequestManager::ClientMetadata data);
+      IdpNetworkRequestManager::ClientMetadata client_metadata);
+  void MaybeShowAccountsDialog(
+      const IdentityProviderInfo& idp_info,
+      const IdpNetworkRequestManager::AccountList& accounts,
+      const IdpNetworkRequestManager::ClientMetadata& client_metadata);
 
-  // Only send accounts fetch request if the user is signed in with the IDP or
-  // the IDP is used in FedCM for the first time.
-  void MaybeFetchAccounts(const IdentityProviderInfo& idp_info);
   // Updates the IdpSigninStatus in case of accounts fetch failure and shows a
   // failure UI if applicable.
   void HandleAccountsFetchFailure(
@@ -190,6 +192,9 @@
   // information and then we can remove the console error messages.
   void AddConsoleErrorMessage(blink::mojom::FederatedAuthRequestResult result);
 
+  void MaybeAddResponseCodeToConsole(const char* fetch_description,
+                                     int response_code);
+
   bool ShouldCompleteRequestImmediately();
 
   // Computes the login state of accounts. It uses the IDP-provided signal, if
@@ -234,7 +239,6 @@
   raw_ptr<FederatedIdentitySharingPermissionContextDelegate>
       sharing_permission_delegate_ = nullptr;
 
-  IdpNetworkRequestManager::ClientMetadata client_metadata_;
   // The account that was selected by the user. This is only applicable to the
   // mediation flow.
   std::string account_id_;
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc
index 8baa5159..2d02295 100644
--- a/content/browser/webid/federated_auth_request_impl_unittest.cc
+++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -32,6 +32,7 @@
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_web_contents.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "net/http/http_status_code.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -53,6 +54,7 @@
 using FedCmEntry = ukm::builders::Blink_FedCm;
 using FedCmIdpEntry = ukm::builders::Blink_FedCmIdp;
 using FetchStatus = content::IdpNetworkRequestManager::FetchStatus;
+using ParseStatus = content::IdpNetworkRequestManager::ParseStatus;
 using TokenStatus = content::FedCmRequestIdTokenStatus;
 using LoginState = content::IdentityRequestAccount::LoginState;
 using SignInMode = content::IdentityRequestAccount::SignInMode;
@@ -196,7 +198,9 @@
 };
 
 static const MockClientIdConfiguration kDefaultClientMetadata{
-    FetchStatus::kSuccess, kPrivacyPolicyUrl, kTermsOfServiceUrl};
+    {ParseStatus::kSuccess, net::HTTP_OK},
+    kPrivacyPolicyUrl,
+    kTermsOfServiceUrl};
 
 static const IdentityProviderParameters kDefaultIdentityProvider{
     kProviderUrlFull, kClientId, kNonce};
@@ -208,14 +212,14 @@
 static const MockIdpInfo kDefaultIdentityProviderInfo{
     {kManifestList},
     {
-        FetchStatus::kSuccess,
+        {ParseStatus::kSuccess, net::HTTP_OK},
         kAccountsEndpoint,
         kTokenEndpoint,
         kClientMetadataEndpoint,
         kRevocationEndpoint,
     },
     kDefaultClientMetadata,
-    FetchStatus::kSuccess,
+    {ParseStatus::kSuccess, net::HTTP_OK},
     kAccounts,
 };
 
@@ -226,34 +230,34 @@
 static const MockIdpInfo kProviderOneInfo{
     {{kProviderOneUrlFull}},
     {
-        FetchStatus::kSuccess,
+        {ParseStatus::kSuccess, net::HTTP_OK},
         "https://idp1.example/accounts",
         "https://idp1.example/token",
         "https://idp1.example/client_metadata",
         "https://idp1.example/revoke",
     },
     kDefaultClientMetadata,
-    FetchStatus::kSuccess,
+    {ParseStatus::kSuccess, net::HTTP_OK},
     kAccounts};
 
 constexpr char kProviderTwoUrlFull[] = "https://idp2.example/fedcm.json";
 static const MockIdpInfo kProviderTwoInfo{
     {{kProviderTwoUrlFull}},
     {
-        FetchStatus::kSuccess,
+        {ParseStatus::kSuccess, net::HTTP_OK},
         "https://idp2.example/accounts",
         "https://idp2.example/token",
         "https://idp2.example/client_metadata",
         "https://idp2.example/revoke",
     },
     kDefaultClientMetadata,
-    FetchStatus::kSuccess,
+    {ParseStatus::kSuccess, net::HTTP_OK},
     kMultipleAccounts};
 
 static const MockConfiguration kConfigurationValid{
     kToken,
     kSingleProviderInfo,
-    FetchStatus::kSuccess,
+    {ParseStatus::kSuccess, net::HTTP_OK},
     false /* delay_token_response */,
     false /* customized_dialog */,
     true /* wait_for_callback */};
@@ -447,9 +451,9 @@
     std::set<GURL> url_set(
         config_.idp_info[provider_key].manifest_list.provider_urls.begin(),
         config_.idp_info[provider_key].manifest_list.provider_urls.end());
+    FetchStatus success{ParseStatus::kSuccess, net::HTTP_OK};
     base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(callback), FetchStatus::kSuccess, url_set));
+        FROM_HERE, base::BindOnce(std::move(callback), success, url_set));
   }
 
   void FetchManifest(const GURL& provider,
@@ -523,8 +527,9 @@
     fetched_endpoints_ |= FetchedEndpoint::TOKEN;
 
     std::string delivered_token =
-        config_.token_response == FetchStatus::kSuccess ? config_.token
-                                                        : std::string();
+        config_.token_response.parse_status == ParseStatus::kSuccess
+            ? config_.token
+            : std::string();
     base::OnceCallback bound_callback = base::BindOnce(
         std::move(callback), config_.token_response, delivered_token);
     if (config_.delay_token_response) {
@@ -856,7 +861,8 @@
                            const MockConfiguration& config) {
     bool is_all_accounts_response_successful{true};
     for (const auto& idp_info : config.idp_info) {
-      if (idp_info.second.accounts_response != FetchStatus::kSuccess) {
+      if (idp_info.second.accounts_response.parse_status !=
+          ParseStatus::kSuccess) {
         is_all_accounts_response_successful = false;
         break;
       }
@@ -1065,9 +1071,6 @@
 
 // Test successful manifest list fetching.
 TEST_F(FederatedAuthRequestImplTest, ManifestListSuccess) {
-  base::test::ScopedFeatureList list;
-  list.InitAndEnableFeature(features::kFedCmManifestValidation);
-
   // Use IdpNetworkRequestManagerParamChecker to validate passed-in parameters
   // to IdpNetworkRequestManager methods.
   std::unique_ptr<IdpNetworkRequestManagerParamChecker> checker =
@@ -1081,9 +1084,6 @@
 
 // Test the provider url is not in the manifest list.
 TEST_F(FederatedAuthRequestImplTest, ManifestListNotInList) {
-  base::test::ScopedFeatureList list;
-  list.InitAndEnableFeature(features::kFedCmManifestValidation);
-
   RequestExpectations request_not_in_list = {
       RequestTokenStatus::kError,
       FederatedAuthRequestResult::kErrorManifestNotInManifestList,
@@ -1100,9 +1100,6 @@
 
 // Test that not having the filename in the manifest list fails.
 TEST_F(FederatedAuthRequestImplTest, ManifestListHasNoFilename) {
-  base::test::ScopedFeatureList list;
-  list.InitAndEnableFeature(features::kFedCmManifestValidation);
-
   IdentityProviderParameters identity_provider{"https://idp.example/foo",
                                                kClientId, kNonce};
   RequestParameters parameters{
@@ -1212,28 +1209,28 @@
 // Test that request fails if accounts endpoint cannot be reached.
 TEST_F(FederatedAuthRequestImplTest, AccountEndpointCannotBeReached) {
   MockConfiguration configuration = kConfigurationValid;
-  configuration.idp_info[kProviderUrlFull].accounts_response =
-      FetchStatus::kNoResponseError;
+  configuration.idp_info[kProviderUrlFull].accounts_response.parse_status =
+      ParseStatus::kNoResponseError;
   RequestExpectations expectations = {
       RequestTokenStatus::kError,
       FederatedAuthRequestResult::kErrorFetchingAccountsNoResponse,
       /* selected_idp_config_url=*/absl::nullopt,
-      FetchedEndpoint::MANIFEST | FetchedEndpoint::CLIENT_METADATA |
-          FetchedEndpoint::ACCOUNTS | FetchedEndpoint::MANIFEST_LIST};
+      FetchedEndpoint::MANIFEST | FetchedEndpoint::ACCOUNTS |
+          FetchedEndpoint::MANIFEST_LIST};
   RunAuthTest(kDefaultRequestParameters, expectations, configuration);
 }
 
 // Test that request fails if account endpoint response cannot be parsed.
 TEST_F(FederatedAuthRequestImplTest, AccountsCannotBeParsed) {
   MockConfiguration configuration = kConfigurationValid;
-  configuration.idp_info[kProviderUrlFull].accounts_response =
-      FetchStatus::kInvalidResponseError;
+  configuration.idp_info[kProviderUrlFull].accounts_response.parse_status =
+      ParseStatus::kInvalidResponseError;
   RequestExpectations expectations = {
       RequestTokenStatus::kError,
       FederatedAuthRequestResult::kErrorFetchingAccountsInvalidResponse,
       /* selected_idp_config_url=*/absl::nullopt,
-      FetchedEndpoint::MANIFEST | FetchedEndpoint::CLIENT_METADATA |
-          FetchedEndpoint::ACCOUNTS | FetchedEndpoint::MANIFEST_LIST};
+      FetchedEndpoint::MANIFEST | FetchedEndpoint::ACCOUNTS |
+          FetchedEndpoint::MANIFEST_LIST};
   RunAuthTest(kDefaultRequestParameters, expectations, configuration);
 }
 
@@ -1370,8 +1367,14 @@
       HasSharingPermission(OriginFromString(kRpUrl), OriginFromString(kRpUrl),
                            OriginFromString(kProviderUrlFull), kAccountId))
       .WillOnce(Return(true));
-  RunAuthTest(kDefaultRequestParameters, kExpectationSuccess,
-              kConfigurationValid);
+
+  RequestExpectations expectations = kExpectationSuccess;
+  // CLIENT_METADATA only needs to be fetched for obtaining links to display in
+  // the disclosure text. The disclosure text is not displayed for returning
+  // users, thus fetching the client metadata endpoint should be skipped.
+  expectations.fetched_endpoints &= ~FetchedEndpoint::CLIENT_METADATA;
+
+  RunAuthTest(kDefaultRequestParameters, expectations, kConfigurationValid);
   EXPECT_EQ(LoginState::kSignIn, displayed_accounts()[0].login_state);
 }
 
@@ -1399,7 +1402,8 @@
       .Times(0);
 
   MockConfiguration configuration = kConfigurationValid;
-  configuration.token_response = FetchStatus::kInvalidResponseError;
+  configuration.token_response.parse_status =
+      ParseStatus::kInvalidResponseError;
   RequestExpectations expectations = {
       RequestTokenStatus::kError,
       FederatedAuthRequestResult::kErrorFetchingIdTokenInvalidResponse,
@@ -1449,7 +1453,9 @@
   }
   RequestParameters request_parameters = kDefaultRequestParameters;
   request_parameters.prefer_auto_sign_in = true;
-  RunAuthTest(request_parameters, kExpectationSuccess, kConfigurationValid);
+  RequestExpectations expectations = kExpectationSuccess;
+  expectations.fetched_endpoints &= ~FetchedEndpoint::CLIENT_METADATA;
+  RunAuthTest(request_parameters, expectations, kConfigurationValid);
 
   ASSERT_FALSE(displayed_accounts.empty());
   EXPECT_EQ(displayed_accounts[0].login_state, LoginState::kSignIn);
@@ -1536,7 +1542,9 @@
   }
   RequestParameters request_parameters = kDefaultRequestParameters;
   request_parameters.prefer_auto_sign_in = true;
-  RunAuthTest(request_parameters, kExpectationSuccess, kConfigurationValid);
+  RequestExpectations expectations = kExpectationSuccess;
+  expectations.fetched_endpoints &= ~FetchedEndpoint::CLIENT_METADATA;
+  RunAuthTest(request_parameters, expectations, kConfigurationValid);
 
   ASSERT_FALSE(displayed_accounts.empty());
   EXPECT_EQ(displayed_accounts[0].login_state, LoginState::kSignIn);
@@ -1553,8 +1561,9 @@
   ukm_recorder()->SetOnAddEntryCallback(FedCmEntry::kEntryName,
                                         ukm_loop.QuitClosure());
 
-  RunAuthTest(kDefaultRequestParameters, kExpectationSuccess,
-              kConfigurationValid);
+  RequestExpectations expectations = kExpectationSuccess;
+  expectations.fetched_endpoints &= ~FetchedEndpoint::CLIENT_METADATA;
+  RunAuthTest(kDefaultRequestParameters, expectations, kConfigurationValid);
   EXPECT_EQ(LoginState::kSignIn, displayed_accounts()[0].login_state);
 
   ukm_loop.Run();
@@ -1713,8 +1722,9 @@
                                    kAccountId))
       .WillOnce(Return(true));
 
-  RunAuthTest(kDefaultRequestParameters, kExpectationSuccess,
-              kConfigurationValid);
+  RequestExpectations expectations = kExpectationSuccess;
+  expectations.fetched_endpoints &= ~FetchedEndpoint::CLIENT_METADATA;
+  RunAuthTest(kDefaultRequestParameters, expectations, kConfigurationValid);
   EXPECT_EQ(LoginState::kSignIn, displayed_accounts()[0].login_state);
 
   histogram_tester_.ExpectUniqueSample("Blink.FedCm.WebContentsVisible", 1, 1);
@@ -1851,7 +1861,9 @@
       AccountList(kAccounts.begin(), kAccounts.end());
   displayed_accounts[0].login_state = LoginState::kSignIn;
   configuration.idp_info[kProviderUrlFull].accounts = displayed_accounts;
-  RunAuthTest(kDefaultRequestParameters, kExpectationSuccess, configuration);
+  RequestExpectations expectations = kExpectationSuccess;
+  expectations.fetched_endpoints &= ~FetchedEndpoint::CLIENT_METADATA;
+  RunAuthTest(kDefaultRequestParameters, expectations, configuration);
 
   ukm_loop.Run();
 
@@ -1907,7 +1919,9 @@
       AccountList(kAccounts.begin(), kAccounts.end());
   displayed_accounts[0].login_state = LoginState::kSignIn;
   configuration.idp_info[kProviderUrlFull].accounts = displayed_accounts;
-  RunAuthTest(kDefaultRequestParameters, kExpectationSuccess, configuration);
+  RequestExpectations expectations = kExpectationSuccess;
+  expectations.fetched_endpoints &= ~FetchedEndpoint::CLIENT_METADATA;
+  RunAuthTest(kDefaultRequestParameters, expectations, configuration);
 
   ukm_loop.Run();
 
@@ -1933,8 +1947,9 @@
                                         ukm_loop.QuitClosure());
 
   // By default, IDP claims user is not signed in.
-  RunAuthTest(kDefaultRequestParameters, kExpectationSuccess,
-              kConfigurationValid);
+  RequestExpectations expectations = kExpectationSuccess;
+  expectations.fetched_endpoints &= ~FetchedEndpoint::CLIENT_METADATA;
+  RunAuthTest(kDefaultRequestParameters, expectations, kConfigurationValid);
 
   ukm_loop.Run();
 
@@ -2148,8 +2163,9 @@
                                     "&disclosure_text_shown=false");
   SetNetworkRequestManager(std::move(checker));
 
-  RunAuthTest(kDefaultRequestParameters, kExpectationSuccess,
-              kConfigurationValid);
+  RequestExpectations expectations = kExpectationSuccess;
+  expectations.fetched_endpoints &= ~FetchedEndpoint::CLIENT_METADATA;
+  RunAuthTest(kDefaultRequestParameters, expectations, kConfigurationValid);
 }
 
 // Test that the values in the token post data are escaped according to the
@@ -2173,29 +2189,29 @@
 
 // TestIdpNetworkRequestManager subclass which runs the `account_list_task`
 // passed-in to the constructor prior to the accounts endpoint returning.
-class IdpNetworkRequestManagerAccountListTaskRunner
+class IdpNetworkRequestManagerClientMetadataTaskRunner
     : public TestIdpNetworkRequestManager {
  public:
-  explicit IdpNetworkRequestManagerAccountListTaskRunner(
-      base::OnceClosure account_list_task)
-      : account_list_task_(std::move(account_list_task)) {}
+  explicit IdpNetworkRequestManagerClientMetadataTaskRunner(
+      base::OnceClosure client_metadata_task)
+      : client_metadata_task_(std::move(client_metadata_task)) {}
 
-  IdpNetworkRequestManagerAccountListTaskRunner(
-      const IdpNetworkRequestManagerAccountListTaskRunner&) = delete;
-  IdpNetworkRequestManagerAccountListTaskRunner& operator=(
-      const IdpNetworkRequestManagerAccountListTaskRunner&) = delete;
+  IdpNetworkRequestManagerClientMetadataTaskRunner(
+      const IdpNetworkRequestManagerClientMetadataTaskRunner&) = delete;
+  IdpNetworkRequestManagerClientMetadataTaskRunner& operator=(
+      const IdpNetworkRequestManagerClientMetadataTaskRunner&) = delete;
 
-  void SendAccountsRequest(const GURL& accounts_url,
+  void FetchClientMetadata(const GURL& client_metadata_endpoint_url,
                            const std::string& client_id,
-                           AccountsRequestCallback callback) override {
-    if (account_list_task_)
-      std::move(account_list_task_).Run();
-    TestIdpNetworkRequestManager::SendAccountsRequest(accounts_url, client_id,
-                                                      std::move(callback));
+                           FetchClientMetadataCallback callback) override {
+    if (client_metadata_task_)
+      std::move(client_metadata_task_).Run();
+    TestIdpNetworkRequestManager::FetchClientMetadata(
+        client_metadata_endpoint_url, client_id, std::move(callback));
   }
 
  private:
-  base::OnceClosure account_list_task_;
+  base::OnceClosure client_metadata_task_;
 };
 
 void NavigateToUrl(content::WebContents* web_contents, const GURL& url) {
@@ -2206,8 +2222,9 @@
 }  // namespace
 
 // Test that the account chooser is not shown if the page navigates prior to the
-// accounts endpoint request completing and BFCache is enabled.
-TEST_F(FederatedAuthRequestImplTest, NavigateDuringAccountFetchBFCacheEnabled) {
+// client metadata endpoint request completing and BFCache is enabled.
+TEST_F(FederatedAuthRequestImplTest,
+       NavigateDuringClientMetadataFetchBFCacheEnabled) {
   base::test::ScopedFeatureList list;
   list.InitWithFeatures(
       /*enabled_features=*/{features::kBackForwardCache},
@@ -2215,7 +2232,7 @@
   ASSERT_TRUE(content::IsBackForwardCacheEnabled());
 
   SetNetworkRequestManager(
-      std::make_unique<IdpNetworkRequestManagerAccountListTaskRunner>(
+      std::make_unique<IdpNetworkRequestManagerClientMetadataTaskRunner>(
           base::BindOnce(&NavigateToUrl, web_contents(), GURL(kRpOtherUrl))));
 
   EXPECT_CALL(*mock_dialog_controller_, ShowAccountsDialog(_, _, _, _, _, _, _))
@@ -2241,7 +2258,7 @@
   ASSERT_FALSE(content::IsBackForwardCacheEnabled());
 
   SetNetworkRequestManager(
-      std::make_unique<IdpNetworkRequestManagerAccountListTaskRunner>(
+      std::make_unique<IdpNetworkRequestManagerClientMetadataTaskRunner>(
           base::BindOnce(&NavigateToUrl, web_contents(), GURL(kRpOtherUrl))));
 
   EXPECT_CALL(*mock_dialog_controller_, ShowAccountsDialog(_, _, _, _, _, _, _))
@@ -2314,14 +2331,14 @@
   EXPECT_CALL(*mock_dialog_controller_, ShowFailureDialog(_, _, _, _, _))
       .Times(0);
   MockConfiguration configuration = kConfigurationValid;
-  configuration.idp_info[kProviderUrlFull].accounts_response =
-      FetchStatus::kInvalidResponseError;
+  configuration.idp_info[kProviderUrlFull].accounts_response.parse_status =
+      ParseStatus::kInvalidResponseError;
   RequestExpectations expectations = {
       RequestTokenStatus::kError,
       FederatedAuthRequestResult::kErrorFetchingAccountsInvalidResponse,
       /* selected_idp_config_url=*/absl::nullopt,
-      FetchedEndpoint::MANIFEST | FetchedEndpoint::CLIENT_METADATA |
-          FetchedEndpoint::ACCOUNTS | FetchedEndpoint::MANIFEST_LIST};
+      FetchedEndpoint::MANIFEST | FetchedEndpoint::ACCOUNTS |
+          FetchedEndpoint::MANIFEST_LIST};
   RunAuthTest(kDefaultRequestParameters, expectations, configuration);
 }
 
@@ -2348,13 +2365,13 @@
       .WillRepeatedly(Return(true));
 
   MockConfiguration configuration = kConfigurationValid;
-  configuration.idp_info[kProviderUrlFull].accounts_response =
-      FetchStatus::kInvalidResponseError;
+  configuration.idp_info[kProviderUrlFull].accounts_response.parse_status =
+      ParseStatus::kInvalidResponseError;
   RequestExpectations expectations = {
       RequestTokenStatus::kError, FederatedAuthRequestResult::kError,
       /* selected_idp_config_url=*/absl::nullopt,
-      FetchedEndpoint::MANIFEST | FetchedEndpoint::CLIENT_METADATA |
-          FetchedEndpoint::ACCOUNTS | FetchedEndpoint::MANIFEST_LIST};
+      FetchedEndpoint::MANIFEST | FetchedEndpoint::ACCOUNTS |
+          FetchedEndpoint::MANIFEST_LIST};
   RunAuthTest(kDefaultRequestParameters, expectations, configuration);
 }
 
@@ -2417,7 +2434,7 @@
   MockConfiguration configuration{kToken,
                                   {{kProviderOneUrlFull, kProviderOneInfo},
                                    {kProviderTwoUrlFull, kProviderTwoInfo}},
-                                  FetchStatus::kSuccess,
+                                  {ParseStatus::kSuccess, net::HTTP_OK},
                                   false /* delay_token_response */,
                                   false /* customized_dialog */,
                                   true /* wait_for_callback */};
@@ -2449,7 +2466,7 @@
   MockConfiguration configuration{kToken,
                                   {{kProviderOneUrlFull, kProviderOneInfo},
                                    {kProviderTwoUrlFull, kProviderTwoInfo}},
-                                  FetchStatus::kSuccess,
+                                  {ParseStatus::kSuccess, net::HTTP_OK},
                                   false /* delay_token_response */,
                                   true /* customized_dialog */,
                                   true /* wait_for_callback */};
diff --git a/content/browser/webid/flags.cc b/content/browser/webid/flags.cc
index 5a0f070..65a362a 100644
--- a/content/browser/webid/flags.cc
+++ b/content/browser/webid/flags.cc
@@ -21,10 +21,6 @@
       features::kFedCm, features::kFedCmIdpSignoutFieldTrialParamName, false);
 }
 
-bool IsFedCmManifestValidationEnabled() {
-  return base::FeatureList::IsEnabled(features::kFedCmManifestValidation);
-}
-
 bool IsFedCmMultipleIdentityProvidersEnabled() {
   return base::FeatureList::IsEnabled(
       features::kFedCmMultipleIdentityProviders);
@@ -42,4 +38,8 @@
       false);
 }
 
+bool IsFedCmMetricsEndpointEnabled() {
+  return base::FeatureList::IsEnabled(features::kFedCmMetricsEndpoint);
+}
+
 }  // namespace content
diff --git a/content/browser/webid/flags.h b/content/browser/webid/flags.h
index 5eb0e58df..dbb72b9 100644
--- a/content/browser/webid/flags.h
+++ b/content/browser/webid/flags.h
@@ -15,9 +15,6 @@
 // Whether FedCM IDP sign-out is enabled.
 bool IsFedCmIdpSignoutEnabled();
 
-// Whether manifest list fetching and validation is enabled.
-bool IsFedCmManifestValidationEnabled();
-
 // Whether multiple identity providers are enabled.
 bool IsFedCmMultipleIdentityProvidersEnabled();
 
@@ -27,6 +24,9 @@
 // Whether FedCM iframe support is enabled.
 bool IsFedCmIframeSupportEnabled();
 
+// Whether metrics endpoint is enabled.
+bool IsFedCmMetricsEndpointEnabled();
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_WEBID_FLAGS_H_
diff --git a/content/browser/webid/idp_network_request_manager.cc b/content/browser/webid/idp_network_request_manager.cc
index bfc686c0..b8810fa 100644
--- a/content/browser/webid/idp_network_request_manager.cc
+++ b/content/browser/webid/idp_network_request_manager.cc
@@ -40,6 +40,7 @@
 using ClientMetadata = IdpNetworkRequestManager::ClientMetadata;
 using Endpoints = IdpNetworkRequestManager::Endpoints;
 using FetchStatus = content::IdpNetworkRequestManager::FetchStatus;
+using ParseStatus = content::IdpNetworkRequestManager::ParseStatus;
 
 // TODO(kenrb): These need to be defined in the explainer or draft spec and
 // referenced here.
@@ -263,51 +264,55 @@
   }
 }
 
-FetchStatus GetResponseError(std::string* response_body, int response_code) {
+ParseStatus GetResponseError(std::string* response_body, int response_code) {
   if (response_code == net::HTTP_NOT_FOUND)
-    return FetchStatus::kHttpNotFoundError;
+    return ParseStatus::kHttpNotFoundError;
 
   if (!response_body)
-    return FetchStatus::kNoResponseError;
+    return ParseStatus::kNoResponseError;
 
-  return FetchStatus::kSuccess;
+  return ParseStatus::kSuccess;
 }
 
-FetchStatus GetParsingError(
+ParseStatus GetParsingError(
     const data_decoder::DataDecoder::ValueOrError& result) {
   if (!result.has_value())
-    return FetchStatus::kInvalidResponseError;
+    return ParseStatus::kInvalidResponseError;
 
   auto& response = *result;
   if (!response.is_dict())
-    return FetchStatus::kInvalidResponseError;
+    return ParseStatus::kInvalidResponseError;
 
-  return FetchStatus::kSuccess;
+  return ParseStatus::kSuccess;
 }
 
 void OnJsonParsed(
     IdpNetworkRequestManager::ParseJsonCallback parse_json_callback,
+    int response_code,
     data_decoder::DataDecoder::ValueOrError result) {
-  FetchStatus parsing_error = GetParsingError(result);
-  std::move(parse_json_callback).Run(parsing_error, std::move(result));
+  ParseStatus parse_status = GetParsingError(result);
+  std::move(parse_json_callback)
+      .Run({parse_status, response_code}, std::move(result));
 }
 
 void OnDownloadedJson(
     IdpNetworkRequestManager::ParseJsonCallback parse_json_callback,
     std::unique_ptr<std::string> response_body,
     int response_code) {
-  FetchStatus response_error =
+  ParseStatus parse_status =
       GetResponseError(response_body.get(), response_code);
 
-  if (response_error != FetchStatus::kSuccess) {
+  if (parse_status != ParseStatus::kSuccess) {
     std::move(parse_json_callback)
-        .Run(response_error, data_decoder::DataDecoder::ValueOrError());
+        .Run({parse_status, response_code},
+             data_decoder::DataDecoder::ValueOrError());
     return;
   }
 
   data_decoder::DataDecoder::ParseJsonIsolated(
       *response_body,
-      base::BindOnce(&OnJsonParsed, std::move(parse_json_callback)));
+      base::BindOnce(&OnJsonParsed, std::move(parse_json_callback),
+                     response_code));
 }
 
 void OnManifestListParsed(
@@ -320,28 +325,31 @@
 
   std::set<GURL> urls;
 
-  if (fetch_status != FetchStatus::kSuccess) {
+  if (fetch_status.parse_status != ParseStatus::kSuccess) {
     std::move(callback).Run(fetch_status, urls);
     return;
   }
 
   const base::Value::Dict* dict = result->GetIfDict();
   if (!dict) {
-    std::move(callback).Run(FetchStatus::kInvalidResponseError, urls);
+    std::move(callback).Run(
+        {ParseStatus::kInvalidResponseError, fetch_status.response_code}, urls);
     return;
   }
 
   const base::Value::List* list = dict->FindList(kProviderUrlListKey);
   if (!list) {
-    std::move(callback).Run(FetchStatus::kInvalidResponseError, urls);
+    std::move(callback).Run(
+        {ParseStatus::kInvalidResponseError, fetch_status.response_code}, urls);
     return;
   }
 
   for (const auto& value : *list) {
     const std::string* url_str = value.GetIfString();
     if (!url_str) {
-      std::move(callback).Run(FetchStatus::kInvalidResponseError,
-                              std::set<GURL>());
+      std::move(callback).Run(
+          {ParseStatus::kInvalidResponseError, fetch_status.response_code},
+          std::set<GURL>());
       return;
     }
     GURL url(*url_str);
@@ -351,7 +359,8 @@
     urls.insert(url);
   }
 
-  std::move(callback).Run(FetchStatus::kSuccess, urls);
+  std::move(callback).Run({ParseStatus::kSuccess, fetch_status.response_code},
+                          urls);
 }
 
 void OnManifestParsed(const GURL& provider,
@@ -360,7 +369,7 @@
                       IdpNetworkRequestManager::FetchManifestCallback callback,
                       FetchStatus fetch_status,
                       data_decoder::DataDecoder::ValueOrError result) {
-  if (fetch_status != FetchStatus::kSuccess) {
+  if (fetch_status.parse_status != ParseStatus::kSuccess) {
     std::move(callback).Run(fetch_status, Endpoints(),
                             IdentityProviderMetadata());
     return;
@@ -391,15 +400,15 @@
                                   idp_brand_icon_minimum_size, idp_metadata);
   }
 
-  std::move(callback).Run(FetchStatus::kSuccess, endpoints,
-                          std::move(idp_metadata));
+  std::move(callback).Run({ParseStatus::kSuccess, fetch_status.response_code},
+                          endpoints, std::move(idp_metadata));
 }
 
 void OnClientMetadataParsed(
     IdpNetworkRequestManager::FetchClientMetadataCallback callback,
     FetchStatus fetch_status,
     data_decoder::DataDecoder::ValueOrError result) {
-  if (fetch_status != FetchStatus::kSuccess) {
+  if (fetch_status.parse_status != ParseStatus::kSuccess) {
     std::move(callback).Run(fetch_status, ClientMetadata());
     return;
   }
@@ -417,7 +426,8 @@
   data.privacy_policy_url = ExtractUrl(kPrivacyPolicyKey);
   data.terms_of_service_url = ExtractUrl(kTermsOfServiceKey);
 
-  std::move(callback).Run(FetchStatus::kSuccess, data);
+  std::move(callback).Run({ParseStatus::kSuccess, fetch_status.response_code},
+                          data);
 }
 
 void OnAccountsRequestParsed(
@@ -425,7 +435,7 @@
     IdpNetworkRequestManager::AccountsRequestCallback callback,
     FetchStatus fetch_status,
     data_decoder::DataDecoder::ValueOrError result) {
-  if (fetch_status != FetchStatus::kSuccess) {
+  if (fetch_status.parse_status != ParseStatus::kSuccess) {
     std::move(callback).Run(fetch_status, AccountList());
     return;
   }
@@ -437,18 +447,21 @@
       accounts && ParseAccounts(accounts, account_list, client_id);
 
   if (!accounts_present) {
-    std::move(callback).Run(FetchStatus::kInvalidResponseError, AccountList());
+    std::move(callback).Run(
+        {ParseStatus::kInvalidResponseError, fetch_status.response_code},
+        AccountList());
     return;
   }
 
-  std::move(callback).Run(FetchStatus::kSuccess, std::move(account_list));
+  std::move(callback).Run({ParseStatus::kSuccess, fetch_status.response_code},
+                          std::move(account_list));
 }
 
 void OnTokenRequestParsed(
     IdpNetworkRequestManager::TokenRequestCallback callback,
     FetchStatus fetch_status,
     data_decoder::DataDecoder::ValueOrError result) {
-  if (fetch_status != FetchStatus::kSuccess) {
+  if (fetch_status.parse_status != ParseStatus::kSuccess) {
     std::move(callback).Run(fetch_status, std::string());
     return;
   }
@@ -458,10 +471,13 @@
   bool token_present = token && token->is_string();
 
   if (!token_present) {
-    std::move(callback).Run(FetchStatus::kInvalidResponseError, std::string());
+    std::move(callback).Run(
+        {ParseStatus::kInvalidResponseError, fetch_status.response_code},
+        std::string());
     return;
   }
-  std::move(callback).Run(FetchStatus::kSuccess, token->GetString());
+  std::move(callback).Run({ParseStatus::kSuccess, fetch_status.response_code},
+                          token->GetString());
 }
 
 void OnLogoutCompleted(IdpNetworkRequestManager::LogoutCallback callback,
@@ -478,9 +494,6 @@
     default;
 
 // static
-constexpr char IdpNetworkRequestManager::kManifestFilePath[];
-
-// static
 std::unique_ptr<IdpNetworkRequestManager> IdpNetworkRequestManager::Create(
     RenderFrameHostImpl* host) {
   // Use the browser process URL loader factory because it has cross-origin
@@ -542,10 +555,12 @@
       IdpNetworkRequestManager::ComputeManifestListUrl(provider);
 
   if (!manifest_list_url) {
+    // Pass net::HTTP_OK as the |response_code| so we do not add a console error
+    // message about a fetch we didn't even attempt.
+    FetchStatus fetch_status = {ParseStatus::kHttpNotFoundError, net::HTTP_OK};
     base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(&OnManifestListParsed, std::move(callback),
-                                  /*manifest_list_url=*/GURL(),
-                                  FetchStatus::kHttpNotFoundError,
+                                  /*manifest_list_url=*/GURL(), fetch_status,
                                   data_decoder::DataDecoder::ValueOrError()));
     return;
   }
@@ -566,11 +581,8 @@
     absl::optional<int> idp_brand_icon_ideal_size,
     absl::optional<int> idp_brand_icon_minimum_size,
     FetchManifestCallback callback) {
-  GURL target_url =
-      provider.Resolve(IdpNetworkRequestManager::kManifestFilePath);
-
   std::unique_ptr<network::ResourceRequest> resource_request =
-      CreateUncredentialedResourceRequest(target_url,
+      CreateUncredentialedResourceRequest(provider,
                                           /* send_referrer= */ false);
   DownloadJsonAndParse(
       std::move(resource_request),
@@ -732,9 +744,12 @@
     IdpNetworkRequestManager::DownloadCallback callback,
     std::unique_ptr<std::string> response_body) {
   auto* response_info = url_loader->ResponseInfo();
+  // Use the HTTP response code, if available. If it is not available, use the
+  // NetError(). Note that it is acceptable to put these in the same int because
+  // NetErrors are not positive, so they do not conflict with HTTP error codes.
   int response_code = response_info && response_info->headers
                           ? response_info->headers->response_code()
-                          : -1;
+                          : url_loader->NetError();
 
   url_loader.reset();
   std::move(callback).Run(std::move(response_body), response_code);
diff --git a/content/browser/webid/idp_network_request_manager.h b/content/browser/webid/idp_network_request_manager.h
index 1c3cd9b3..6225a48a1 100644
--- a/content/browser/webid/idp_network_request_manager.h
+++ b/content/browser/webid/idp_network_request_manager.h
@@ -62,12 +62,19 @@
 // the user to interact with the IDP.
 class CONTENT_EXPORT IdpNetworkRequestManager {
  public:
-  enum class FetchStatus {
+  enum class ParseStatus {
     kSuccess,
     kHttpNotFoundError,
     kNoResponseError,
     kInvalidResponseError,
   };
+  struct FetchStatus {
+    ParseStatus parse_status;
+    // The HTTP response code, if one was received, otherwise the net error. It
+    // is possible to distinguish which it is since HTTP response codes are
+    // positive and net errors are negative.
+    int response_code;
+  };
 
   enum class LogoutResponse {
     kSuccess,
@@ -117,8 +124,6 @@
     kTokenEndpointInvalidResponse = 402,
   };
 
-  static constexpr char kManifestFilePath[] = "fedcm.json";
-
   using AccountList = std::vector<content::IdentityRequestAccount>;
   using AccountsRequestCallback =
       base::OnceCallback<void(FetchStatus, AccountList)>;
@@ -133,7 +138,7 @@
       base::OnceCallback<void(FetchStatus, ClientMetadata)>;
   using LogoutCallback = base::OnceCallback<void()>;
   using ParseJsonCallback =
-      base::OnceCallback<void(FetchStatus fetch_status,
+      base::OnceCallback<void(FetchStatus,
                               data_decoder::DataDecoder::ValueOrError)>;
   using RevokeCallback = base::OnceCallback<void(RevokeResponse)>;
   using TokenRequestCallback =
diff --git a/content/browser/webid/idp_network_request_manager_unittest.cc b/content/browser/webid/idp_network_request_manager_unittest.cc
index e7187470..9e324da 100644
--- a/content/browser/webid/idp_network_request_manager_unittest.cc
+++ b/content/browser/webid/idp_network_request_manager_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/values.h"
 #include "content/public/browser/identity_request_dialog_controller.h"
 #include "content/public/browser/manifest_icon_downloader.h"
+#include "net/http/http_status_code.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/public/mojom/client_security_state.mojom.h"
@@ -29,6 +30,7 @@
 using ClientMetadata = content::IdpNetworkRequestManager::ClientMetadata;
 using Endpoints = content::IdpNetworkRequestManager::Endpoints;
 using FetchStatus = content::IdpNetworkRequestManager::FetchStatus;
+using ParseStatus = content::IdpNetworkRequestManager::ParseStatus;
 using AccountsRequestCallback =
     content::IdpNetworkRequestManager::AccountsRequestCallback;
 using RevokeResponse = content::IdpNetworkRequestManager::RevokeResponse;
@@ -99,9 +101,12 @@
   }
 
   std::tuple<FetchStatus, std::set<GURL>>
-  SendManifestListRequestAndWaitForResponse(const char* test_data) {
+  SendManifestListRequestAndWaitForResponse(
+      const char* test_data,
+      net::HttpStatusCode http_status = net::HTTP_OK) {
     GURL manifest_list_url(kTestManifestListUrl);
-    test_url_loader_factory().AddResponse(manifest_list_url.spec(), test_data);
+    test_url_loader_factory().AddResponse(manifest_list_url.spec(), test_data,
+                                          http_status);
 
     base::RunLoop run_loop;
     FetchStatus parsed_fetch_status;
@@ -121,9 +126,12 @@
   }
 
   std::tuple<FetchStatus, IdentityProviderMetadata>
-  SendManifestRequestAndWaitForResponse(const char* test_data) {
+  SendManifestRequestAndWaitForResponse(
+      const char* test_data,
+      net::HttpStatusCode http_status = net::HTTP_OK) {
     GURL manifest_url(kTestManifestUrl);
-    test_url_loader_factory().AddResponse(manifest_url.spec(), test_data);
+    test_url_loader_factory().AddResponse(manifest_url.spec(), test_data,
+                                          http_status);
 
     base::RunLoop run_loop;
     FetchStatus parsed_fetch_status;
@@ -137,7 +145,7 @@
         });
 
     std::unique_ptr<IdpNetworkRequestManager> manager = CreateTestManager();
-    manager->FetchManifest(GURL(kTestIdpUrl), kTestIdpBrandIconIdealSize,
+    manager->FetchManifest(GURL(kTestManifestUrl), kTestIdpBrandIconIdealSize,
                            kTestIdpBrandIconMinimumSize, std::move(callback));
     run_loop.Run();
 
@@ -147,10 +155,10 @@
   std::tuple<FetchStatus, AccountList> SendAccountsRequestAndWaitForResponse(
       const std::string& test_accounts,
       const char* client_id = "",
-      bool send_id_and_referrer = false) {
+      net::HttpStatusCode response_code = net::HTTP_OK) {
     GURL accounts_endpoint(kTestAccountsEndpoint);
     test_url_loader_factory().AddResponse(accounts_endpoint.spec(),
-                                          test_accounts);
+                                          test_accounts, response_code);
 
     base::RunLoop run_loop;
     FetchStatus parsed_accounts_response;
@@ -170,7 +178,7 @@
     return {parsed_accounts_response, parsed_accounts};
   }
 
-  std::string SendTokenRequestAndWaitForResponse(
+  std::tuple<FetchStatus, std::string> SendTokenRequestAndWaitForResponse(
       const char* account,
       const char* request,
       net::HttpStatusCode http_status = net::HTTP_OK) {
@@ -179,10 +187,12 @@
     test_url_loader_factory().AddResponse(token_endpoint.spec(), response,
                                           http_status);
 
+    FetchStatus fetch_status;
     std::string token;
     base::RunLoop run_loop;
     auto callback = base::BindLambdaForTesting(
         [&](FetchStatus status, const std::string& token_response) {
+          fetch_status = status;
           token = token_response;
           run_loop.Quit();
         });
@@ -191,7 +201,7 @@
     manager->SendTokenRequest(token_endpoint, account, request,
                               std::move(callback));
     run_loop.Run();
-    return token;
+    return {fetch_status, token};
   }
 
   ClientMetadata SendClientMetadataRequestAndWaitForResponse(
@@ -238,7 +248,8 @@
   std::tie(accounts_response, accounts) =
       SendAccountsRequestAndWaitForResponse(test_empty_account_json);
 
-  EXPECT_EQ(FetchStatus::kInvalidResponseError, accounts_response);
+  EXPECT_EQ(ParseStatus::kInvalidResponseError, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   EXPECT_TRUE(accounts.empty());
 }
 
@@ -250,7 +261,8 @@
   std::tie(accounts_response, accounts) =
       SendAccountsRequestAndWaitForResponse(test_single_account_json);
 
-  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+  EXPECT_EQ(ParseStatus::kSuccess, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   EXPECT_EQ(1UL, accounts.size());
   EXPECT_EQ("1234", accounts[0].id);
 }
@@ -279,7 +291,8 @@
   std::tie(accounts_response, accounts) =
       SendAccountsRequestAndWaitForResponse(test_accounts_json);
 
-  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+  EXPECT_EQ(ParseStatus::kSuccess, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   EXPECT_EQ(2UL, accounts.size());
   EXPECT_EQ("1234", accounts[0].id);
   EXPECT_EQ("5678", accounts[1].id);
@@ -302,7 +315,8 @@
   std::tie(accounts_response, accounts) =
       SendAccountsRequestAndWaitForResponse(test_accounts_json);
 
-  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+  EXPECT_EQ(ParseStatus::kSuccess, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   EXPECT_EQ("1234", accounts[0].id);
 }
 
@@ -316,7 +330,9 @@
         SendAccountsRequestAndWaitForResponse(
             test_account_missing_account_id_json);
 
-    EXPECT_EQ(FetchStatus::kInvalidResponseError, accounts_response);
+    EXPECT_EQ(ParseStatus::kInvalidResponseError,
+              accounts_response.parse_status);
+    EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
     EXPECT_TRUE(accounts.empty());
   }
   {
@@ -327,7 +343,9 @@
     std::tie(accounts_response, accounts) =
         SendAccountsRequestAndWaitForResponse(test_account_missing_email_json);
 
-    EXPECT_EQ(FetchStatus::kInvalidResponseError, accounts_response);
+    EXPECT_EQ(ParseStatus::kInvalidResponseError,
+              accounts_response.parse_status);
+    EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
     EXPECT_TRUE(accounts.empty());
   }
   {
@@ -338,7 +356,9 @@
     std::tie(accounts_response, accounts) =
         SendAccountsRequestAndWaitForResponse(test_account_missing_name_json);
 
-    EXPECT_EQ(FetchStatus::kInvalidResponseError, accounts_response);
+    EXPECT_EQ(ParseStatus::kInvalidResponseError,
+              accounts_response.parse_status);
+    EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
     EXPECT_TRUE(accounts.empty());
   }
 }
@@ -365,7 +385,8 @@
   std::tie(accounts_response, accounts) =
       SendAccountsRequestAndWaitForResponse(accounts_json);
 
-  EXPECT_EQ(FetchStatus::kInvalidResponseError, accounts_response);
+  EXPECT_EQ(ParseStatus::kInvalidResponseError, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   EXPECT_TRUE(accounts.empty());
 
   // Test that JSON is valid with exception of duplicate id.
@@ -375,7 +396,8 @@
 
   std::tie(accounts_response, accounts) = SendAccountsRequestAndWaitForResponse(
       accounts_json_different_account_ids);
-  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+  EXPECT_EQ(ParseStatus::kSuccess, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
 }
 
 TEST_F(IdpNetworkRequestManagerTest, ParseAccountPictureUrl) {
@@ -401,7 +423,8 @@
   std::tie(accounts_response, accounts) =
       SendAccountsRequestAndWaitForResponse(test_accounts_json);
 
-  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+  EXPECT_EQ(ParseStatus::kSuccess, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   EXPECT_TRUE(accounts[0].picture.is_valid());
   EXPECT_EQ(GURL("https://idp.test/profile/1234"), accounts[0].picture);
   EXPECT_FALSE(accounts[1].picture.is_valid());
@@ -445,7 +468,8 @@
   std::tie(accounts_response, accounts) =
       SendAccountsRequestAndWaitForResponse(test_invalid_account_json);
 
-  EXPECT_EQ(FetchStatus::kInvalidResponseError, accounts_response);
+  EXPECT_EQ(ParseStatus::kInvalidResponseError, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   EXPECT_TRUE(accounts.empty());
 }
 
@@ -457,7 +481,8 @@
   std::tie(accounts_response, accounts) =
       SendAccountsRequestAndWaitForResponse(test_invalid_account_json);
 
-  EXPECT_EQ(FetchStatus::kInvalidResponseError, accounts_response);
+  EXPECT_EQ(ParseStatus::kInvalidResponseError, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   EXPECT_TRUE(accounts.empty());
 }
 
@@ -488,13 +513,13 @@
           &test_url_loader_factory),
       network::mojom::ClientSecurityState::New());
 
-  std::string manifest_list_contents =
-      "({\"provider_urls\": [\"" + illegal_idp_url.spec() + "\"]})";
-
   base::RunLoop run_loop;
   auto callback = base::BindLambdaForTesting(
       [&](FetchStatus fetch_status, const std::set<GURL>& urls) {
-        EXPECT_EQ(FetchStatus::kHttpNotFoundError, fetch_status);
+        EXPECT_EQ(ParseStatus::kHttpNotFoundError, fetch_status.parse_status);
+        // We receive OK here because
+        // IdpNetworkRequestManager::ComputeManifestListUrl() fails.
+        EXPECT_EQ(net::HTTP_OK, fetch_status.response_code);
         run_loop.Quit();
       });
   network_manager->FetchManifestList(illegal_idp_url, std::move(callback));
@@ -511,50 +536,50 @@
   std::tie(fetch_status, urls) = SendManifestListRequestAndWaitForResponse(R"({
   "provider_urls": ["https://idp.test/fedcm.json"]
   })");
-  EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
   EXPECT_EQ(std::set<GURL>{GURL("https://idp.test/fedcm.json")}, urls);
 
   std::tie(fetch_status, urls) = SendManifestListRequestAndWaitForResponse(R"({
   "provider_urls": ["https://idp.test/path/fedcm.json"]
   })");
-  EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
   EXPECT_EQ(std::set<GURL>{GURL("https://idp.test/path/fedcm.json")}, urls);
 
   // Value not a list
   std::tie(fetch_status, urls) = SendManifestListRequestAndWaitForResponse(R"({
   "provider_urls": "https://idp.test/fedcm.json"
   })");
-  EXPECT_EQ(FetchStatus::kInvalidResponseError, fetch_status);
+  EXPECT_EQ(ParseStatus::kInvalidResponseError, fetch_status.parse_status);
 
   // Toplevel not a dictionary
   std::tie(fetch_status, urls) = SendManifestListRequestAndWaitForResponse(R"(
   ["https://idp.test/fedcm.json"]
   )");
-  EXPECT_EQ(FetchStatus::kInvalidResponseError, fetch_status);
+  EXPECT_EQ(ParseStatus::kInvalidResponseError, fetch_status.parse_status);
 
   // Incorrect key
   std::tie(fetch_status, urls) = SendManifestListRequestAndWaitForResponse(R"({
   "providers": ["https://idp.test/fedcm.json"]
   })");
-  EXPECT_EQ(FetchStatus::kInvalidResponseError, fetch_status);
+  EXPECT_EQ(ParseStatus::kInvalidResponseError, fetch_status.parse_status);
 
   // Array entry not a string
   std::tie(fetch_status, urls) = SendManifestListRequestAndWaitForResponse(R"({
   "provider_urls": [1]
   })");
-  EXPECT_EQ(FetchStatus::kInvalidResponseError, fetch_status);
+  EXPECT_EQ(ParseStatus::kInvalidResponseError, fetch_status.parse_status);
 
   // Relative URLs
   std::tie(fetch_status, urls) = SendManifestListRequestAndWaitForResponse(R"({
   "provider_urls": ["/fedcm.json"]
   })");
-  EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
   EXPECT_EQ(std::set<GURL>{GURL("https://idp.test/fedcm.json")}, urls);
 
   std::tie(fetch_status, urls) = SendManifestListRequestAndWaitForResponse(R"({
   "provider_urls": ["fedcm.json"]
   })");
-  EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
   EXPECT_EQ(std::set<GURL>{GURL("https://idp.test/.well-known/fedcm.json")},
             urls);
 }
@@ -572,7 +597,8 @@
   std::tie(fetch_status, idp_metadata) =
       SendManifestRequestAndWaitForResponse(test_json);
 
-  EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_OK, fetch_status.response_code);
   EXPECT_EQ(SkColorSetARGB(0xff, 0x20, 0x20, 0x20),
             idp_metadata.brand_background_color);
 }
@@ -589,7 +615,8 @@
   std::tie(fetch_status, idp_metadata) =
       SendManifestRequestAndWaitForResponse(test_json);
 
-  EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_OK, fetch_status.response_code);
   EXPECT_EQ(absl::nullopt, idp_metadata.brand_background_color);
 }
 
@@ -607,7 +634,8 @@
   std::tie(fetch_status, idp_metadata) =
       SendManifestRequestAndWaitForResponse(test_json);
 
-  EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_OK, fetch_status.response_code);
   EXPECT_EQ(SkColorSetRGB(0, 0, 0), idp_metadata.brand_background_color);
   EXPECT_EQ(absl::nullopt, idp_metadata.brand_text_color);
 }
@@ -625,7 +653,8 @@
   std::tie(fetch_status, idp_metadata) =
       SendManifestRequestAndWaitForResponse(test_json);
 
-  EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_OK, fetch_status.response_code);
   EXPECT_EQ(absl::nullopt, idp_metadata.brand_background_color);
   EXPECT_EQ(absl::nullopt, idp_metadata.brand_text_color);
 }
@@ -665,7 +694,8 @@
   std::tie(fetch_status, idp_metadata) =
       SendManifestRequestAndWaitForResponse(test_json);
 
-  EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_OK, fetch_status.response_code);
   EXPECT_EQ("https://example.com/32.png", idp_metadata.brand_icon_url.spec());
 }
 
@@ -692,7 +722,8 @@
     std::tie(fetch_status, idp_metadata) =
         SendManifestRequestAndWaitForResponse(test_json);
 
-    EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+    EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
+    EXPECT_EQ(net::HTTP_OK, fetch_status.response_code);
     EXPECT_EQ(GURL(), idp_metadata.brand_icon_url);
   }
 
@@ -713,7 +744,8 @@
     std::tie(fetch_status, idp_metadata) =
         SendManifestRequestAndWaitForResponse(test_json);
 
-    EXPECT_EQ(FetchStatus::kSuccess, fetch_status);
+    EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
+    EXPECT_EQ(net::HTTP_OK, fetch_status.response_code);
     EXPECT_EQ("https://example.com/16.png", idp_metadata.brand_icon_url.spec());
   }
 }
@@ -746,7 +778,8 @@
       SendAccountsRequestAndWaitForResponse(test_accounts_json);
 
   ASSERT_TRUE(called);
-  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+  EXPECT_EQ(ParseStatus::kSuccess, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
 }
 
 // Verifies that we correctly check the signed-in status.
@@ -801,7 +834,8 @@
       SendAccountsRequestAndWaitForResponse(test_accounts_json, "xxx");
 
   EXPECT_TRUE(called);
-  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+  EXPECT_EQ(ParseStatus::kSuccess, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   ASSERT_EQ(5ul, accounts.size());
   ASSERT_TRUE(accounts[0].login_state.has_value());
   EXPECT_EQ(LoginState::kSignIn, *accounts[0].login_state);
@@ -834,8 +868,13 @@
         EXPECT_EQ("request", byte_elem.AsStringPiece());
       });
   test_url_loader_factory().SetInterceptor(interceptor);
-  std::string token = SendTokenRequestAndWaitForResponse("account", "request");
+  std::string token;
+  FetchStatus fetch_status;
+  std::tie(fetch_status, token) =
+      SendTokenRequestAndWaitForResponse("account", "request");
   ASSERT_TRUE(called);
+  EXPECT_EQ(ParseStatus::kSuccess, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_OK, fetch_status.response_code);
   ASSERT_EQ("token", token);
 }
 
@@ -905,7 +944,8 @@
       SendAccountsRequestAndWaitForResponse(test_accounts_json, "xxx");
 
   EXPECT_TRUE(called);
-  EXPECT_EQ(FetchStatus::kSuccess, accounts_response);
+  EXPECT_EQ(ParseStatus::kSuccess, accounts_response.parse_status);
+  EXPECT_EQ(net::HTTP_OK, accounts_response.response_code);
   ASSERT_EQ(4ul, accounts.size());
 
   histogram_tester.ExpectTotalCount("Blink.FedCm.ApprovedClientsExistence", 4);
@@ -955,6 +995,55 @@
   EXPECT_FALSE(callback_called);
 }
 
+TEST_F(IdpNetworkRequestManagerTest, ErrorFetchingManifestList) {
+  FetchStatus fetch_status;
+  std::set<GURL> urls;
+  std::tie(fetch_status, urls) =
+      SendManifestListRequestAndWaitForResponse(R"({
+  "provider_urls": ["https://idp.test/fedcm.json"]
+  })",
+                                                net::HTTP_REQUEST_TIMEOUT);
+  EXPECT_EQ(ParseStatus::kNoResponseError, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_REQUEST_TIMEOUT, fetch_status.response_code);
+  EXPECT_EQ(std::set<GURL>{}, urls);
+}
+
+TEST_F(IdpNetworkRequestManagerTest, ErrorFetchingManifest) {
+  FetchStatus fetch_status;
+  IdentityProviderMetadata idp_metadata;
+  std::tie(fetch_status, idp_metadata) =
+      SendManifestRequestAndWaitForResponse(R"({
+  "branding" : {
+    "color": "blue"
+  }
+  })",
+                                            net::HTTP_NOT_FOUND);
+  EXPECT_EQ(ParseStatus::kHttpNotFoundError, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_NOT_FOUND, fetch_status.response_code);
+}
+
+TEST_F(IdpNetworkRequestManagerTest, ErrorFetchingAccounts) {
+  FetchStatus fetch_status;
+  AccountList accounts;
+  std::tie(fetch_status, accounts) =
+      SendAccountsRequestAndWaitForResponse(R"({
+  "accounts" : []
+  })",
+                                            "", net::HTTP_BAD_REQUEST);
+  EXPECT_EQ(ParseStatus::kNoResponseError, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_BAD_REQUEST, fetch_status.response_code);
+}
+
+TEST_F(IdpNetworkRequestManagerTest, ErrorFetchingToken) {
+  std::string token;
+  FetchStatus fetch_status;
+  std::tie(fetch_status, token) = SendTokenRequestAndWaitForResponse(
+      "account", "request", net::HTTP_INTERNAL_SERVER_ERROR);
+  EXPECT_EQ("", token);
+  EXPECT_EQ(ParseStatus::kNoResponseError, fetch_status.parse_status);
+  EXPECT_EQ(net::HTTP_INTERNAL_SERVER_ERROR, fetch_status.response_code);
+}
+
 }  // namespace
 
 }  // namespace content
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityEventDispatcher.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityEventDispatcher.java
index 5a487d9..23bbd8d 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityEventDispatcher.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityEventDispatcher.java
@@ -152,6 +152,16 @@
     }
 
     /**
+     * Helper method to cancel all posted Runnables if the Client object is being destroyed early.
+     */
+    public void clearQueue() {
+        for (Long uuid : mPendingEvents.keySet()) {
+            mClient.removeRunnable(mPendingEvents.get(uuid));
+        }
+        mPendingEvents.clear();
+    }
+
+    /**
      * Helper method to update the list of relevant event types to be dispatched.
      * @param relevantEventTypes        Set<Integer> relevant event types
      */
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
index 8f8f4fc..79db08e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -63,6 +63,7 @@
 import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ViewStructure;
 import android.view.accessibility.AccessibilityEvent;
@@ -95,6 +96,7 @@
 import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsAccessibility;
+import org.chromium.ui.base.ViewAndroidDelegate;
 import org.chromium.ui.base.WindowAndroid;
 
 import java.util.ArrayList;
@@ -119,7 +121,8 @@
 @JNINamespace("content")
 public class WebContentsAccessibilityImpl extends AccessibilityNodeProviderCompat
         implements AccessibilityStateChangeListener, WebContentsAccessibility, WindowEventObserver,
-                   UserData, BrowserAccessibilityState.Listener {
+                   UserData, BrowserAccessibilityState.Listener,
+                   ViewAndroidDelegate.ContainerViewObserver {
     // Public catch-all TAG for logging in the accessibility component.
     public static final String TAG = "ClankAccessibility";
 
@@ -179,7 +182,7 @@
 
     private final AccessibilityDelegate mDelegate;
     protected AccessibilityManager mAccessibilityManager;
-    protected final Context mContext;
+    protected Context mContext;
     private String mProductVersion;
     protected long mNativeObj;
     private Rect mAccessibilityFocusRect;
@@ -290,9 +293,12 @@
         mProductVersion = mDelegate.getProductVersion();
         mAccessibilityManager =
                 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
-        if (mDelegate.getWebContents() != null) {
-            mCaptioningController = new CaptioningController(mDelegate.getWebContents());
-            WindowEventObserverManager.from(mDelegate.getWebContents()).addObserver(this);
+
+        WebContents webContents = mDelegate.getWebContents();
+        if (webContents != null) {
+            mCaptioningController = new CaptioningController(webContents);
+            WindowEventObserverManager.from(webContents).addObserver(this);
+            webContents.getViewAndroidDelegate().addObserver(this);
         } else {
             refreshState();
         }
@@ -412,7 +418,9 @@
         // Register a broadcast receiver for locale change.
         if (mView.isAttachedToWindow()) registerLocaleChangeReceiver();
 
-        // Define an initial set of relevant events if OnDemand feature is enabled.
+        // TODO(mschillaci,jacklynch): Move into {refreshNativeState} or similar method once
+        //                            {BrowserAccessibilityState.Listener} has more granularity.
+        // Define a set of relevant AccessibilityEvents if the OnDemand feature is enabled.
         if (ContentFeatureList.isEnabled(ContentFeatureList.ON_DEMAND_ACCESSIBILITY_EVENTS)) {
             Runnable serviceMaskRunnable = () -> {
                 int serviceEventMask =
@@ -424,6 +432,9 @@
             mView.post(serviceMaskRunnable);
         }
 
+        // Send state values set by embedders to native-side objects.
+        refreshNativeState();
+
         TraceEvent.end("WebContentsAccessibilityImpl.onNativeInit");
     }
 
@@ -527,6 +538,7 @@
         TraceEvent.begin("WebContentsAccessibilityImpl.onAttachedToWindow");
         mAccessibilityManager.addAccessibilityStateChangeListener(this);
         refreshState();
+        refreshNativeState();
         mCaptioningController.startListening();
         registerLocaleChangeReceiver();
         TraceEvent.end("WebContentsAccessibilityImpl.onAttachedToWindow");
@@ -547,21 +559,44 @@
     @Override
     public void onWindowAndroidChanged(WindowAndroid windowAndroid) {
         TraceEvent.begin("WebContentsAccessibilityImpl.onWindowAndroidChanged");
-        // Delete this object when switching between WindowAndroids/Activities.
-        if (mDelegate.getWebContents() != null) {
-            WindowEventObserverManager.from(mDelegate.getWebContents()).removeObserver(this);
-            ((WebContentsImpl) mDelegate.getWebContents())
-                    .removeUserData(WebContentsAccessibilityImpl.class);
+        // When the WindowAndroid changes, we must update our Context reference to the new value.
+        // We also need to remove all references to the previous context, which in this case would
+        // be the reference in any existing SuggestionSpans. To remove these, clear our cache to
+        // recycle all nodes. Any other AccessibilityNodeInfo objects that were created would have
+        // been passed to the Framework, which can handle clean-up on its end. We do not want to
+        // delete |this| because the object is (largely) not WindowAndroid dependent.
+        mNodeInfoCache.clear();
+        if (windowAndroid != null && windowAndroid.getContext().get() != null) {
+            mContext = windowAndroid.getContext().get();
         }
 
-        deleteEarly();
         TraceEvent.end("WebContentsAccessibilityImpl.onWindowAndroidChanged");
     }
 
     @Override
+    public void onUpdateContainerView(ViewGroup view) {
+        // When the ContainerView is updated, we must update the |mView| variable and remove all
+        // previous references to it. We clear the AccessibilityEventDispatcher queue, which may
+        // have posted Runnable(s) to the old view. We also clear the AccessibilityNodeInfo cache
+        // since some objects may still be referencing the old view as their parent or source. We
+        // do not want to delete |this| because the object is (largely) not ContainerView dependent.
+        mEventDispatcher.clearQueue();
+        mNodeInfoCache.clear();
+        mView = view;
+    }
+
+    @Override
     public void destroy() {
         TraceEvent.begin("WebContentsAccessibilityImpl.destroy");
-        if (mDelegate.getWebContents() == null) deleteEarly();
+        mNodeInfoCache.clear();
+        mEventDispatcher.clearQueue();
+        if (mDelegate.getWebContents() == null) {
+            deleteEarly();
+        } else {
+            WindowEventObserverManager.from(mDelegate.getWebContents()).removeObserver(this);
+            ((WebContentsImpl) mDelegate.getWebContents())
+                    .removeUserData(WebContentsAccessibilityImpl.class);
+        }
         TraceEvent.end("WebContentsAccessibilityImpl.destroy");
     }
 
@@ -581,6 +616,27 @@
         setState(mAccessibilityManager.isEnabled());
     }
 
+    private void refreshNativeState() {
+        try (TraceEvent te = TraceEvent.scoped("WebContentsAccessibilityImpl.refreshNativeState")) {
+            if (!isNativeInitialized()) return;
+
+            // Update the AXMode based on screen reader status.
+            WebContentsAccessibilityImplJni.get().setAXMode(mNativeObj,
+                    BrowserAccessibilityState.screenReaderMode(),
+                    /* isAccessibilityEnabled= */ true);
+
+            // Update the state of how passwords are exposed based on user settings.
+            WebContentsAccessibilityImplJni.get().setPasswordRules(mNativeObj,
+                    AccessibilityAutofillHelper.shouldRespectDisplayedPasswordText(),
+                    AccessibilityAutofillHelper.shouldExposePasswordText());
+
+            // Update the state of enabling/disabling the image descriptions feature. To enable the
+            // feature, this instance must be a candidate and a screen reader must be enabled.
+            WebContentsAccessibilityImplJni.get().setAllowImageDescriptions(mNativeObj,
+                    mIsImageDescriptionsCandidate && BrowserAccessibilityState.screenReaderMode());
+        }
+    }
+
     // AccessibilityNodeProvider
 
     @Override
@@ -760,24 +816,14 @@
 
     @Override
     public void onBrowserAccessibilityStateChanged(boolean newScreenReaderEnabledState) {
-        if (!isNativeInitialized()) return;
+        refreshNativeState();
 
-        // Update the AXMode based on screen reader status.
-        WebContentsAccessibilityImplJni.get().setAXMode(mNativeObj, newScreenReaderEnabledState,
-                /* isAccessibilityEnabled= */ true);
-
-        // Update the state of how passwords are exposed based on user settings.
-        WebContentsAccessibilityImplJni.get().setPasswordRules(mNativeObj,
-                AccessibilityAutofillHelper.shouldRespectDisplayedPasswordText(),
-                AccessibilityAutofillHelper.shouldExposePasswordText());
-
-        // Update the state of enabling/disabling the image descriptions feature. To enable the
-        // feature, this instance must be a candidate and a screen reader must be enabled.
-        WebContentsAccessibilityImplJni.get().setAllowImageDescriptions(
-                mNativeObj, mIsImageDescriptionsCandidate && newScreenReaderEnabledState);
-
+        // TODO(mschillaci,jacklynch): Move into {refreshNativeState} or similar method once
+        //                            {BrowserAccessibilityState.Listener} has more granularity.
         // Update the list of events we dispatch to enabled services.
-        if (ContentFeatureList.isEnabled(ContentFeatureList.ON_DEMAND_ACCESSIBILITY_EVENTS)) {
+        if (isNativeInitialized()
+                && ContentFeatureList.isEnabled(
+                        ContentFeatureList.ON_DEMAND_ACCESSIBILITY_EVENTS)) {
             int serviceEventMask = BrowserAccessibilityState.getAccessibilityServiceEventTypeMask();
             mEventDispatcher.updateRelevantEventTypes(convertMaskToEventTypes(serviceEventMask));
         }
@@ -1073,6 +1119,8 @@
         }
     }
 
+    // TODO(mschillaci,jacklynch): Move into {refreshNativeState} once {BrowserAccessibilityState.
+    //                             Listener} provides more granularity.
     public void updateAXModeFromNativeAccessibilityState() {
         if (!isNativeInitialized()) return;
         // Update the AXMode based on screen reader status.
diff --git a/content/public/browser/ax_inspect_factory_win.cc b/content/public/browser/ax_inspect_factory_win.cc
index cc07f53..2aac3f0 100644
--- a/content/public/browser/ax_inspect_factory_win.cc
+++ b/content/public/browser/ax_inspect_factory_win.cc
@@ -8,11 +8,11 @@
 #include "base/notreached.h"
 #include "base/win/com_init_util.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
-#include "content/browser/accessibility/accessibility_tree_formatter_uia_win.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_win.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "ui/accessibility/platform/inspect/ax_event_recorder_win.h"
 #include "ui/accessibility/platform/inspect/ax_event_recorder_win_uia.h"
+#include "ui/accessibility/platform/inspect/ax_tree_formatter_uia_win.h"
 
 namespace content {
 
@@ -47,7 +47,7 @@
       return std::make_unique<AccessibilityTreeFormatterWin>();
     case ui::AXApiType::kWinUIA:
       base::win::AssertComInitialized();
-      return std::make_unique<AccessibilityTreeFormatterUia>();
+      return std::make_unique<ui::AXTreeFormatterUia>();
     default:
       NOTREACHED() << "Unsupported API type " << static_cast<std::string>(type);
   }
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 65d57c0..9b6c2b8b 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -2339,6 +2339,10 @@
   virtual bool IsFileSystemURLNavigationAllowed(
       content::BrowserContext* browser_context,
       const GURL& url);
+
+  // Called when optionally blockable insecure content is displayed on a secure
+  // page (resulting in mixed content).
+  virtual void OnDisplayInsecureContent(WebContents* web_contents) {}
 };
 
 }  // namespace content
diff --git a/content/public/browser/desktop_capture.cc b/content/public/browser/desktop_capture.cc
index 8ca1f99..1a7301d 100644
--- a/content/public/browser/desktop_capture.cc
+++ b/content/public/browser/desktop_capture.cc
@@ -18,6 +18,11 @@
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #endif
 
+#if defined(WEBRTC_USE_PIPEWIRE)
+#include "base/environment.h"
+#include "base/nix/xdg_util.h"
+#endif
+
 namespace content::desktop_capture {
 
 webrtc::DesktopCaptureOptions CreateDesktopCaptureOptions() {
@@ -85,7 +90,13 @@
 
 bool CanUsePipeWire() {
 #if defined(WEBRTC_USE_PIPEWIRE)
-  return webrtc::DesktopCapturer::IsRunningUnderWayland() &&
+  static base::nix::SessionType session_type = base::nix::SessionType::kUnset;
+  if (session_type == base::nix::SessionType::kUnset) {
+    std::unique_ptr<base::Environment> env = base::Environment::Create();
+    session_type = base::nix::GetSessionType(*env);
+  }
+
+  return session_type == base::nix::SessionType::kWayland &&
          base::FeatureList::IsEnabled(features::kWebRtcPipeWireCapturer);
 #else
   return false;
diff --git a/content/public/browser/first_party_sets_handler.h b/content/public/browser/first_party_sets_handler.h
index 4e83e14..15a5206 100644
--- a/content/public/browser/first_party_sets_handler.h
+++ b/content/public/browser/first_party_sets_handler.h
@@ -13,11 +13,12 @@
 #include "base/values.h"
 #include "base/version.h"
 #include "content/common/content_export.h"
-#include "net/first_party_sets/first_party_sets_context_config.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace net {
 class FirstPartySetEntry;
+class FirstPartySetsCacheFilter;
+class FirstPartySetsContextConfig;
 class GlobalFirstPartySets;
 class SchemefulSite;
 }
@@ -95,6 +96,10 @@
   using ParseWarning = IssueWithMetadata<ParseWarningType>;
   virtual ~FirstPartySetsHandler() = default;
 
+  // Overrides the singleton with caller-owned |test_instance|. Callers in tests
+  // are responsible for resetting this to null on cleanup.
+  static void SetInstanceForTesting(FirstPartySetsHandler* test_instance);
+
   // Returns the singleton instance.
   static FirstPartySetsHandler* GetInstance();
 
@@ -179,7 +184,8 @@
       base::RepeatingCallback<BrowserContext*()> browser_context_getter,
       const std::string& browser_context_id,
       net::FirstPartySetsContextConfig context_config,
-      base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) = 0;
+      base::OnceCallback<void(net::FirstPartySetsContextConfig,
+                              net::FirstPartySetsCacheFilter)> callback) = 0;
 };
 
 }  // namespace content
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index d204699..a18ddfb 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -373,10 +373,10 @@
 // cross-origin iframes.
 const char kFedCmIframeSupportFieldTrialParamName[] = "IframeSupport";
 
-// Kill switch for FedCm manifest validation.
-BASE_FEATURE(kFedCmManifestValidation,
-             "FedCmManifestValidation",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+// Enables usage of the FedCM API with metrics endpoint at the same time.
+BASE_FEATURE(kFedCmMetricsEndpoint,
+             "FedCmMetricsEndpoint",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Enables usage of the FedCM API with multiple identity providers at the same
 // time.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 242ede64..c4b38936 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -83,7 +83,7 @@
 CONTENT_EXPORT extern const char kFedCmIdpSignoutFieldTrialParamName[];
 CONTENT_EXPORT extern const char kFedCmIframeSupportFieldTrialParamName[];
 CONTENT_EXPORT extern const char kFedCmIdpSigninStatusFieldTrialParamName[];
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmManifestValidation);
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmMetricsEndpoint);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFedCmMultipleIdentityProviders);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kFirstPartySets);
 CONTENT_EXPORT extern const base::FeatureParam<bool>
diff --git a/content/public/test/back_forward_cache_util.h b/content/public/test/back_forward_cache_util.h
index 63aa1be..50dfb7a 100644
--- a/content/public/test/back_forward_cache_util.h
+++ b/content/public/test/back_forward_cache_util.h
@@ -63,13 +63,12 @@
 // testing (enables the cache, sets timeouts, etc.)
 // Optionally, |additional_params| can be passed to specify additional
 // features and parameters that will be in the returned structure.
-std::vector<base::test::ScopedFeatureList::FeatureAndParams>
+std::vector<base::test::FeatureRefAndParams>
 DefaultEnabledBackForwardCacheParametersForTests();
 
-std::vector<base::test::ScopedFeatureList::FeatureAndParams>
+std::vector<base::test::FeatureRefAndParams>
 DefaultEnabledBackForwardCacheParametersForTests(
-    const std::vector<base::test::ScopedFeatureList::FeatureAndParams>&
-        additional_params);
+    const std::vector<base::test::FeatureRefAndParams>& additional_params);
 
 // Returns a vector of features to disable by default when testing with the
 // BackForwardCache.
diff --git a/content/renderer/java/gin_java_bridge_value_converter_unittest.cc b/content/renderer/java/gin_java_bridge_value_converter_unittest.cc
index c748f39..04fa1fd0 100644
--- a/content/renderer/java/gin_java_bridge_value_converter_unittest.cc
+++ b/content/renderer/java/gin_java_bridge_value_converter_unittest.cc
@@ -140,9 +140,9 @@
         converter->FromV8Value(v8_typed_array, context));
     ASSERT_TRUE(list_value.get()) << typed_array_type;
     ASSERT_TRUE(list_value->is_list()) << typed_array_type;
-    EXPECT_EQ(1u, list_value->GetListDeprecated().size()) << typed_array_type;
+    EXPECT_EQ(1u, list_value->GetList().size()) << typed_array_type;
 
-    const auto value = list_value->GetListDeprecated().cbegin();
+    const auto value = list_value->GetList().cbegin();
     if (value->type() == base::Value::Type::BINARY) {
       std::unique_ptr<const GinJavaBridgeValue> gin_value(
           GinJavaBridgeValue::FromValue(&*value));
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
index 889d40f..b843376 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
@@ -29,7 +29,6 @@
         boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":");
         ContextUtils.initApplicationContext(this);
         ResourceBundle.setNoAvailableLocalePaks();
-        LibraryLoader.getInstance().enableJniChecks();
         LibraryLoader.getInstance().setLibraryProcessType(isBrowserProcess
                         ? LibraryProcessType.PROCESS_BROWSER
                         : LibraryProcessType.PROCESS_CHILD);
diff --git a/content/test/attribution_simulator_input_parser_unittest.cc b/content/test/attribution_simulator_input_parser_unittest.cc
index 633df48..218b1d2 100644
--- a/content/test/attribution_simulator_input_parser_unittest.cc
+++ b/content/test/attribution_simulator_input_parser_unittest.cc
@@ -737,7 +737,7 @@
         }]})json",
     },
     {
-        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kFilterDataInvalid)",
+        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kFilterDataWrongType)",
         R"json({"sources": [{
           "timestamp": "1643235574000",
           "source_type": "navigation",
@@ -751,7 +751,7 @@
         }]})json",
     },
     {
-        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kFilterDataInvalid)",
+        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kFilterDataListWrongType)",
         R"json({"sources": [{
           "timestamp": "1643235574000",
           "source_type": "navigation",
@@ -767,7 +767,7 @@
         }]})json",
     },
     {
-        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kFilterDataInvalid)",
+        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kFilterDataValueWrongType)",
         R"json({"sources": [{
           "timestamp": "1643235574000",
           "source_type": "navigation",
@@ -783,7 +783,7 @@
         }]})json",
     },
     {
-        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kAggregationKeysInvalid)",
+        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kAggregationKeysWrongType)",
         R"json({"sources": [{
           "timestamp": "1643235574000",
           "source_type": "event",
@@ -797,7 +797,7 @@
         }]})json",
     },
     {
-        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kAggregationKeysInvalid)",
+        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kAggregationKeysValueWrongFormat)",
         R"json({"sources": [{
           "timestamp": "1643235574000",
           "source_type": "event",
@@ -813,7 +813,7 @@
         }]})json",
     },
     {
-        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kAggregationKeysInvalid)",
+        R"(["sources"][0]["Attribution-Reporting-Register-Source"]: kAggregationKeysValueWrongFormat)",
         R"json({"sources": [{
           "timestamp": "1643235574000",
           "source_type": "event",
diff --git a/content/test/data/accessibility/mac/regression/ax-selected-children-expected.txt b/content/test/data/accessibility/mac/attributes/ax-selected-children-expected.txt
similarity index 72%
rename from content/test/data/accessibility/mac/regression/ax-selected-children-expected.txt
rename to content/test/data/accessibility/mac/attributes/ax-selected-children-expected.txt
index d8d962e..a540731 100644
--- a/content/test/data/accessibility/mac/regression/ax-selected-children-expected.txt
+++ b/content/test/data/accessibility/mac/attributes/ax-selected-children-expected.txt
@@ -1,3 +1,4 @@
+list.accessibilityAttributeValue(selectedChildren)=[:4, :3, :5]
 button.accessibilityAttributeValue(AXSelected)=0
 div.accessibilityAttributeNames.has(AXSelectedChildren)='no'
 div.accessibilityAttributeValue(AXSelectedChildren)=[]
diff --git a/content/test/data/accessibility/mac/attributes/ax-selected-children.html b/content/test/data/accessibility/mac/attributes/ax-selected-children.html
new file mode 100644
index 0000000..8e256db
--- /dev/null
+++ b/content/test/data/accessibility/mac/attributes/ax-selected-children.html
@@ -0,0 +1,24 @@
+<!--
+@SCRIPT:
+  list.accessibilityAttributeValue(selectedChildren)
+  button.accessibilityAttributeValue(AXSelected)
+  div.accessibilityAttributeNames.has(AXSelectedChildren)
+  div.accessibilityAttributeValue(AXSelectedChildren)
+-->
+<!DOCTYPE html>
+<!-- The focused element should always be the first item in the list of selected
+      children, regardless of whether it's selected or not. -->
+<ul id="list" role="listbox" aria-multiselectable="true">
+  <li id="item1" role="option" aria-selected="true" tabindex="-1">Item 1</li>
+  <li id="item2" role="option" aria-selected="false" tabindex="-1" autofocus>Item 2</li>
+  <li id="item3" role="option" aria-selected="true" tabindex="-1">Item 3</li>
+</ul>
+
+<!--
+  This is a regression test for bug: 1276763
+  before the fix (3359801), when focus is on the button, the result was:
+  div.accessibilityAttributeValue(AXSelectedChildren)=[:3]
+-->
+<div id="div">
+  <button autofocus id="button"></button>
+</div>
\ No newline at end of file
diff --git a/content/test/data/accessibility/mac/regression/ax-selected-children.html b/content/test/data/accessibility/mac/regression/ax-selected-children.html
deleted file mode 100644
index f849e9a..0000000
--- a/content/test/data/accessibility/mac/regression/ax-selected-children.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!--
-@SCRIPT:
-  button.accessibilityAttributeValue(AXSelected)
-  div.accessibilityAttributeNames.has(AXSelectedChildren)
-  div.accessibilityAttributeValue(AXSelectedChildren)
--->
-<!--
-  This is a regression test for bug: 1276763
-  before the fix (3359801), when focus is on the button, the result was:
-  div.accessibilityAttributeValue(AXSelectedChildren)=[:3]
--->
-<!DOCTYPE html>
-<div id="div">
-  <button autofocus id="button"></button>
-</div>
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 3a9be73..0b96724 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -906,10 +906,15 @@
 crbug.com/1284804 [ chromeos chromeos-board-kevin passthrough ] deqp/functional/gles3/transformfeedback/random_separate_points.html [ Failure ]
 crbug.com/1284804 [ chromeos chromeos-board-kevin passthrough ] deqp/functional/gles3/transformfeedback/random_separate_triangles.html [ Failure ]
 crbug.com/1285109 [ chromeos chromeos-board-kevin passthrough ] conformance/canvas/render-after-resize-test.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/context/context-hidden-alpha.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/ogles/GL/functions/functions_033_to_040.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/ogles/GL/refract/refract_001_to_006.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/renderbuffers/renderbuffer-initialization.html [ Failure ]
 crbug.com/1285111 [ chromeos chromeos-board-kevin passthrough ] conformance/textures/misc/copy-tex-image-and-sub-image-2d.html [ Failure ]
 crbug.com/1285112 [ chromeos chromeos-board-kevin passthrough ] conformance2/rendering/blitframebuffer-multisampled-readbuffer.html [ Failure ]
 crbug.com/1285114 [ chromeos chromeos-board-kevin passthrough ] conformance2/transform_feedback/transform_feedback.html [ Failure ]
 crbug.com/1286099 [ chromeos chromeos-board-kevin passthrough ] conformance2/rendering/blitframebuffer-r11f-g11f-b10f.html [ Failure ]
+crbug.com/1374291 [ chromeos chromeos-board-kevin passthrough ] conformance2/textures/video/tex-3d-rgba8-rgba-unsigned_byte.html [ Failure ]
 
 crbug.com/1328444 [ chromeos chromeos-board-kevin ] conformance/context/context-size-change.html [ Failure ]
 crbug.com/1328444 [ chromeos chromeos-board-kevin ] conformance/rendering/color-mask-preserved-during-implicit-clears.html [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index e6690fc7..ddeeebb 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -798,6 +798,8 @@
 crbug.com/1080380 [ chromeos chromeos-board-kevin ] conformance/offscreencanvas/context-lost-restored.html [ Failure ]
 crbug.com/1108368 [ chromeos chromeos-board-kevin ] conformance/misc/shader-precision-format.html [ Failure ]
 crbug.com/1357064 [ chromeos chromeos-board-kevin no-passthrough ] conformance/rendering/blending.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin no-passthrough ] conformance/ogles/GL/default/default_001_to_001.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin no-passthrough ] conformance/ogles/GL/mix/mix_001_to_006.html [ Failure ]
 
 # Failing on chromeos-amd64-generic-rel.
 crbug.com/1232446 [ chromeos chromeos-board-amd64-generic ] conformance/rendering/gl-scissor-test.html [ Failure ]
diff --git a/device/bluetooth/floss/bluetooth_device_floss.cc b/device/bluetooth/floss/bluetooth_device_floss.cc
index 5ce92fa3..c44eb03 100644
--- a/device/bluetooth/floss/bluetooth_device_floss.cc
+++ b/device/bluetooth/floss/bluetooth_device_floss.cc
@@ -102,9 +102,7 @@
 }
 
 uint16_t BluetoothDeviceFloss::GetAppearance() const {
-  NOTIMPLEMENTED();
-
-  return 0;
+  return appearance_;
 }
 
 absl::optional<std::string> BluetoothDeviceFloss::GetName() const {
@@ -149,12 +147,6 @@
   return device_uuids_.GetUUIDs();
 }
 
-absl::optional<int8_t> BluetoothDeviceFloss::GetInquiryRSSI() const {
-  NOTIMPLEMENTED();
-
-  return absl::nullopt;
-}
-
 absl::optional<int8_t> BluetoothDeviceFloss::GetInquiryTxPower() const {
   NOTIMPLEMENTED();
 
@@ -449,6 +441,16 @@
   cod_ = *ret;
 }
 
+void BluetoothDeviceFloss::OnGetRemoteAppearance(DBusResult<uint16_t> ret) {
+  TriggerInitDevicePropertiesCallback();
+  if (!ret.has_value()) {
+    BLUETOOTH_LOG(ERROR) << "OnGetRemoteAppearance() failed: " << ret.error();
+    return;
+  }
+
+  appearance_ = *ret;
+}
+
 void BluetoothDeviceFloss::OnGetRemoteUuids(DBusResult<UUIDList> ret) {
   TriggerInitDevicePropertiesCallback();
   if (!ret.has_value()) {
@@ -525,7 +527,7 @@
   // This must be incremented when adding more properties below
   // and followed up with a TriggerInitDevicePropertiesCallback()
   // in the callback.
-  num_pending_properties_ += 3;
+  num_pending_properties_ += 4;
   // TODO(b/204708206): Update with property framework when available
   FlossDBusManager::Get()->GetAdapterClient()->GetRemoteType(
       base::BindOnce(&BluetoothDeviceFloss::OnGetRemoteType,
@@ -535,6 +537,10 @@
       base::BindOnce(&BluetoothDeviceFloss::OnGetRemoteClass,
                      weak_ptr_factory_.GetWeakPtr()),
       AsFlossDeviceId());
+  FlossDBusManager::Get()->GetAdapterClient()->GetRemoteAppearance(
+      base::BindOnce(&BluetoothDeviceFloss::OnGetRemoteAppearance,
+                     weak_ptr_factory_.GetWeakPtr()),
+      AsFlossDeviceId());
   FlossDBusManager::Get()->GetAdapterClient()->GetRemoteUuids(
       base::BindOnce(&BluetoothDeviceFloss::OnGetRemoteUuids,
                      weak_ptr_factory_.GetWeakPtr()),
diff --git a/device/bluetooth/floss/bluetooth_device_floss.h b/device/bluetooth/floss/bluetooth_device_floss.h
index 76ae2634..b252c66 100644
--- a/device/bluetooth/floss/bluetooth_device_floss.h
+++ b/device/bluetooth/floss/bluetooth_device_floss.h
@@ -58,7 +58,6 @@
   bool IsConnectable() const override;
   bool IsConnecting() const override;
   UUIDSet GetUUIDs() const override;
-  absl::optional<int8_t> GetInquiryRSSI() const override;
   absl::optional<int8_t> GetInquiryTxPower() const override;
   bool ExpectingPinCode() const override;
   bool ExpectingPasskey() const override;
@@ -131,6 +130,7 @@
  private:
   void OnGetRemoteType(DBusResult<FlossAdapterClient::BluetoothDeviceType> ret);
   void OnGetRemoteClass(DBusResult<uint32_t> ret);
+  void OnGetRemoteAppearance(DBusResult<uint16_t> ret);
   void OnGetRemoteUuids(DBusResult<UUIDList> ret);
   void OnConnectAllEnabledProfiles(DBusResult<Void> ret);
   void OnDisconnectAllEnabledProfiles(base::OnceClosure callback,
@@ -166,6 +166,10 @@
   // TODO(b/204708206): Update with property framework when available
   uint32_t cod_ = 0;
 
+  // Appearance of device.
+  // TODO(b/204708206): Update with property framework when available
+  uint16_t appearance_ = 0;
+
   // Whether the device is bonded/paired.
   FlossAdapterClient::BondState bond_state_ =
       FlossAdapterClient::BondState::kNotBonded;
diff --git a/device/bluetooth/floss/fake_floss_adapter_client.cc b/device/bluetooth/floss/fake_floss_adapter_client.cc
index 97b4ae0..db875a18 100644
--- a/device/bluetooth/floss/fake_floss_adapter_client.cc
+++ b/device/bluetooth/floss/fake_floss_adapter_client.cc
@@ -129,6 +129,13 @@
       FROM_HERE, base::BindOnce(std::move(callback), kHeadsetClassOfDevice));
 }
 
+void FakeFlossAdapterClient::GetRemoteAppearance(
+    ResponseCallback<uint16_t> callback,
+    FlossDeviceId device) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), 1));
+}
+
 void FakeFlossAdapterClient::GetConnectionState(
     ResponseCallback<uint32_t> callback,
     const FlossDeviceId& device) {
diff --git a/device/bluetooth/floss/fake_floss_adapter_client.h b/device/bluetooth/floss/fake_floss_adapter_client.h
index ede4836..47610f6c 100644
--- a/device/bluetooth/floss/fake_floss_adapter_client.h
+++ b/device/bluetooth/floss/fake_floss_adapter_client.h
@@ -45,6 +45,8 @@
                      FlossDeviceId device) override;
   void GetRemoteClass(ResponseCallback<uint32_t> callback,
                       FlossDeviceId device) override;
+  void GetRemoteAppearance(ResponseCallback<uint16_t> callback,
+                           FlossDeviceId device) override;
   void GetConnectionState(ResponseCallback<uint32_t> callback,
                           const FlossDeviceId& device) override;
   void GetRemoteUuids(
diff --git a/device/bluetooth/floss/floss_adapter_client.cc b/device/bluetooth/floss/floss_adapter_client.cc
index f52d09a..9021515 100644
--- a/device/bluetooth/floss/floss_adapter_client.cc
+++ b/device/bluetooth/floss/floss_adapter_client.cc
@@ -85,6 +85,13 @@
                               device);
 }
 
+void FlossAdapterClient::GetRemoteAppearance(
+    ResponseCallback<uint16_t> callback,
+    FlossDeviceId device) {
+  CallAdapterMethod<uint16_t>(std::move(callback),
+                              adapter::kGetRemoteAppearance, device);
+}
+
 void FlossAdapterClient::GetConnectionState(ResponseCallback<uint32_t> callback,
                                             const FlossDeviceId& device) {
   CallAdapterMethod<uint32_t>(std::move(callback), adapter::kGetConnectionState,
diff --git a/device/bluetooth/floss/floss_adapter_client.h b/device/bluetooth/floss/floss_adapter_client.h
index 6cf3ef8a..bb6f26d1 100644
--- a/device/bluetooth/floss/floss_adapter_client.h
+++ b/device/bluetooth/floss/floss_adapter_client.h
@@ -191,6 +191,10 @@
   virtual void GetRemoteClass(ResponseCallback<uint32_t> callback,
                               FlossDeviceId device);
 
+  // Gets appearance of a device.
+  virtual void GetRemoteAppearance(ResponseCallback<uint16_t> callback,
+                                   FlossDeviceId device);
+
   // Get connection state of a device.
   // TODO(b/202334519): Change return type to enum instead of u32
   virtual void GetConnectionState(ResponseCallback<uint32_t> callback,
diff --git a/device/bluetooth/floss/floss_dbus_client.cc b/device/bluetooth/floss/floss_dbus_client.cc
index db8e145..95d3b4d 100644
--- a/device/bluetooth/floss/floss_dbus_client.cc
+++ b/device/bluetooth/floss/floss_dbus_client.cc
@@ -42,6 +42,7 @@
 const char kRemoveBond[] = "RemoveBond";
 const char kGetRemoteType[] = "GetRemoteType";
 const char kGetRemoteClass[] = "GetRemoteClass";
+const char kGetRemoteAppearance[] = "GetRemoteAppearance";
 const char kGetConnectionState[] = "GetConnectionState";
 const char kGetRemoteUuids[] = "GetRemoteUuids";
 const char kGetBondState[] = "GetBondState";
diff --git a/device/bluetooth/floss/floss_dbus_client.h b/device/bluetooth/floss/floss_dbus_client.h
index f71112b..73f581ad 100644
--- a/device/bluetooth/floss/floss_dbus_client.h
+++ b/device/bluetooth/floss/floss_dbus_client.h
@@ -51,6 +51,7 @@
 extern DEVICE_BLUETOOTH_EXPORT const char kRemoveBond[];
 extern DEVICE_BLUETOOTH_EXPORT const char kGetRemoteType[];
 extern DEVICE_BLUETOOTH_EXPORT const char kGetRemoteClass[];
+extern DEVICE_BLUETOOTH_EXPORT const char kGetRemoteAppearance[];
 extern DEVICE_BLUETOOTH_EXPORT const char kGetConnectionState[];
 extern DEVICE_BLUETOOTH_EXPORT const char kGetRemoteUuids[];
 extern DEVICE_BLUETOOTH_EXPORT const char kGetBondState[];
diff --git a/device/fido/mac/make_credential_operation.mm b/device/fido/mac/make_credential_operation.mm
index f71050e..d6ac86c 100644
--- a/device/fido/mac/make_credential_operation.mm
+++ b/device/fido/mac/make_credential_operation.mm
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/containers/contains.h"
+#include "base/feature_list.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/mac_logging.h"
 #include "base/mac/scoped_cftyperef.h"
@@ -19,6 +20,7 @@
 #include "device/fido/attestation_statement_formats.h"
 #include "device/fido/attested_credential_data.h"
 #include "device/fido/authenticator_data.h"
+#include "device/fido/features.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/fido_parsing_utils.h"
 #include "device/fido/fido_transport_protocol.h"
@@ -103,13 +105,19 @@
     return;
   }
 
+  // New credentials are always discoverable. But older non-discoverable
+  // credentials may exist.
+  const bool resident_key =
+      base::FeatureList::IsEnabled(kWebAuthnNewDiscoverableCredentialsUi)
+          ? true
+          : request_.resident_key_required;
+
   // Generate the new key pair.
   absl::optional<std::pair<Credential, base::ScopedCFTypeRef<SecKeyRef>>>
       credential_result = credential_store_->CreateCredential(
           request_.rp.id, request_.user,
-          request_.resident_key_required
-              ? TouchIdCredentialStore::kDiscoverable
-              : TouchIdCredentialStore::kNonDiscoverable);
+          resident_key ? TouchIdCredentialStore::kDiscoverable
+                       : TouchIdCredentialStore::kNonDiscoverable);
   if (!credential_result) {
     FIDO_LOG(ERROR) << "CreateCredential() failed";
     std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther,
@@ -147,7 +155,7 @@
           std::make_unique<PackedAttestationStatement>(
               CoseAlgorithmIdentifier::kEs256, std::move(*signature),
               /*x509_certificates=*/std::vector<std::vector<uint8_t>>())));
-  response.is_resident_key = request_.resident_key_required;
+  response.is_resident_key = resident_key;
   response.transports.emplace();
   response.transports->insert(FidoTransportProtocol::kInternal);
   std::move(callback_).Run(CtapDeviceResponseCode::kSuccess,
diff --git a/docs/security/rule-of-2.md b/docs/security/rule-of-2.md
index 6c01135..a8cebd4c9 100644
--- a/docs/security/rule-of-2.md
+++ b/docs/security/rule-of-2.md
@@ -61,7 +61,7 @@
 
 Unfortunately, it is very rare to find a grammar trivial enough that we can
 trust ourselves to parse it successfully or fail safely. (But see
-[Normalization](#Normalization) for a potential example.) Therefore, we do need
+[Normalization](#normalization) for a potential example.) Therefore, we do need
 to concern ourselves with the provenance of such inputs.
 
 Any arbitrary peer on the Internet is an untrustworthy source, unless we get
diff --git a/docs/static_initializers.md b/docs/static_initializers.md
index 19c038fb..3b96079ff 100644
--- a/docs/static_initializers.md
+++ b/docs/static_initializers.md
@@ -25,30 +25,21 @@
 
 ## Listing Static Initializers
 
-### Step 1 - Use objdump to report them
+### Option 1 - dump-static-initializers.py
 For Linux:
 
     tools/linux/dump-static-initializers.py out/Release/chrome
 
-For Android (from easiest to hardest):
+For Android:
 
     # Build with: is_official_build=true is_chrome_branded=true
     # This will dump the list of SI's only when they don't match the expected
     # number in static_initializers.gni (this is what the bots use).
     ninja chrome/android:monochrome_static_initializers
-    # or:
-    tools/binary_size/diagnose_bloat.py HEAD  # See README.md for flags.
-    # or (the other two use this under the hood):
-    tools/linux/dump-static-initializers.py --toolchain-prefix third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi- out/Release/lib.unstripped/libmonochrome.so
-    # arm32 ^^ vv arm64
-    tools/linux/dump-static-initializers.py --toolchain-prefix third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android- out/Release/lib.unstripped/libmonochrome.so
-    # Note: For arm64, having use_thin_lto=true seems to dump a couple extra
-    #     initializers that don't actually exist.
+    # or, to dump directly:
+    tools/linux/dump-static-initializers.py out/Release/lib.unstripped/libmonochrome.so
 
-The last one may actually be the easiest if you've already properly built
-`libmonochrome.so` with `is_official_build=true`.
-
-### Step 2 - Ask compiler to report them
+### Option 2 - Ask compiler to report them
 
 If the source of the new initializers is not obvious from Step 1, you can ask the
 compiler to pinpoint the exact source line.
@@ -68,11 +59,9 @@
 * For more information about `diagnose_bloat.py`, refer to its [README.md](/tools/binary_size/README.md#diagnose_bloat.py)
 * List of existing static initializers documented in [static_initializers.gni](/chrome/android/static_initializers.gni)
 
-### Step 3 - Manual Verification
+### Option 3 - Manual Verification
 
-If the source of the new initializers is not revealed with
-`dump-static-initializers.py` (e.g. for static initializers introduced in
-compiler-rt), there's a manual option.
+You can manually go through the steps that `dump-static-initializers.py` does.
 
 1. Locate the address range of the .init_array section with:
 ```
@@ -104,19 +93,3 @@
     --relocations out/Release/lib.unstripped/libmonochrome.so | grep 0x04064624
 03dfb7b0  00000017 R_ARM_RELATIVE                    0
 ```
-
-### Step 4 - Compiler Naming Heuristics
-
-You might be able to find the static initialzer functions by listing symbols:
-
-```sh
-nm out/Release/lib.unstripped/libmonochrome.so | grep " _GLOBAL__"
-```
-
-This currently yields:
-```
-0214ea45 t _GLOBAL__I_000101
-00cb2315 t _GLOBAL__sub_I_base_logging.cc
-0214eca5 t _GLOBAL__sub_I_iostream.cpp
-01c01219 t _GLOBAL__sub_I_token.cc
-```
diff --git a/docs/webui_explainer.md b/docs/webui_explainer.md
index 5f30e05d..64c6f4d 100644
--- a/docs/webui_explainer.md
+++ b/docs/webui_explainer.md
@@ -961,6 +961,135 @@
    error message includes the name of a network, each network name will be its
    own signature.
 
+## Common TypeScript build issue: Missing dependencies
+Similar to how builds can flakily fail when a C++ file adds an include without
+updating the DEPS file appropriately, builds can flakily (or consistently) fail
+if TypeScript code adds an import but doesn't update the dependencies for its
+`ts_library()` target to include the library that contains that import. This
+has caused confusion for both developers and sheriffs in the past.
+
+### Example Failure
+The following is an example build flake that occurred due to the file
+`personalization_app.ts` adding an import of `colors_css_updater.js`, but not
+updating its dependencies appropriately:
+
+```
+gen/ash/webui/personalization_app/resources/preprocessed/js/personalization_app.ts:38:39 - error TS2792: Cannot find module 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?
+
+38 import {startColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js';
+                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+Found 1 error in gen/ash/webui/personalization_app/resources/preprocessed/js/personalization_app.ts:38
+```
+
+### For Chromium Sheriffs
+If you see a failure like the one in the example, there is a high chance that
+the regression range given by automated tools will not include the CL that is
+the root cause of the failure. There are 2 possible approaches to take to fix
+the build. One is described below at "fixing the error" - typically these are 1
+line fixes, but do require a few steps to identify the exact fix. An
+alternative workaround is as follows:
+1. Note that the file that failed ("1 error in") is `personalization_app.ts`.
+   Find this file in the repo: in this case, it was at
+   `ash/webui/personalization_app/resources/js/personalization_app.ts`.
+2. Find the failed import in the repo (line 38, as noted by the bot failure).
+3. Use "Blame" in Chromium code search to find out what CL added this import
+   line.
+4. Either contact the CL owner or try reverting the CL that made the addition.
+
+### Fixing the error
+The [fix](https://chromium-review.googlesource.com/c/chromium/src/+/3952957)
+for this example was just 1 line and was identified as follows:
+
+1. Observe from this failure that the module that can't be found is
+   `chrome://resources/cr_components/color_change_listener/colors_css_updater.js`.
+2. Find `colors_css_updater.ts` in the repository at
+   `ui/webui/resources/cr_components/color_change_listener/colors_css_updater.ts`.
+3. Find the BUILD.gn file that compiles this TS file. The BUILD.gn file will in
+   most cases be in the same folder as the TS file or one of its ancestors. In
+   this case, it was
+   `ui/webui/resources/cr_components/color_change_listener/BUILD.gn`.
+4. Observe the target name for the `ts_library()` target that compiled the file
+   is `"build_ts"`, so the full target path is
+   `//ui/webui/resources/cr_components/color_change_listener:build_ts`.
+5. Observe that the file where the import failed is `personalization_app.ts`,
+   which is `ash/webui/personalization_app/resourcesjs/personalization_app.ts` in
+   the repo.
+6. Find the `ts_library` target that compiles `personalization_app.ts` at
+   `ash/webui/personalization_app/resources/BUILD.gn`.
+7. Observe that this target doesn't have the
+   `//ui/webui/resources/cr_components/color_change_listener:build_ts` target
+   listed in `deps`. Add the missing dependency there.
+
+Note that if `colors_css_updater.js` was actually checked into the repo as a
+JavaScript file, steps 3, 4, and 7 would be slightly different as follows:
+
+3. Find the BUILD.gn file that either copies or generates a
+   `colors_css_updater.d.ts`. Generally, this will contain a
+   `ts_definitions()` target, where the JS file is either passed as an input,
+   or a target copying the checked in definitions file is a dependency.
+4. Observe the name of the target - usually `"generate_definitions"`.
+7. Look for this target in the `extra_deps` of the `ts_library()` target that
+   depends on it. Add it to `extra_deps` if it's missing.
+
+### For developers - Prevent missing dependency build errors
+When adding a new import (e.g. `import {FooSharedClass} from 'chrome://resources/foo/foo_shared.js';`) to a TypeScript file in your project:
+1. If the file in the repo is TypeScript (e.g.
+   `ui/webui/resources/foo/foo_shared.ts`), find which `ts_library()` target
+   compiles this file.
+2. If, for example, `ui/webui/resources/foo/BUILD.gn` contains:
+   `ts_library("library")`, which has `foo_shared.ts` listed in its `in_files`,
+   then add `//ui/webui/resources/foo:library` to your `ts_library()` target's
+   deps as follows:
+
+```
+ts_library("build_ts") {
+  root_dir = my_root_dir
+  out_dir = "$target_gen_dir/tsc"
+  tsconfig_base = "tsconfig_base.json"
+  deps = [
+    "//ui/webui/resources:library",
+    "//ui/webui/resources/foo:library", # This line is new
+  ]
+  in_files = my_project_ts_files
+}
+```
+
+Alternatively:
+1. If the file in the repo is JavaScript (i.e.
+   `ui/webui/resources/foo/foo_shared.js`), look for which `ts_definitions()`
+   target generates the corresponding `.d.ts` file or depends on a target
+   copying a manually checked in `foo_shared.d.ts` file.
+2. If, for example, `ui/webui/resources/foo/BUILD.gn` contains
+   `ts_definitions("generate_definitions")`, which lists `foo_shared.js` in
+   `js_files` or alternatively depends on `:copy_definitions` which copies
+   `foo_shared.d.ts`, then add `//ui/webui/resources/foo:generate_definitions`
+   to your `ts_library()` target's `extra_deps` as follows:
+
+```
+ts_library("build_ts") {
+  root_dir = my_root_dir
+  out_dir = "$target_gen_dir/tsc"
+  tsconfig_base = "tsconfig_base.json"
+  deps = [ "//ui/webui/resources:library" ]
+
+  # This line is new
+  extra_deps = [ "//ui/webui/resources/foo:generate_definitions" ]
+
+  in_files = my_project_ts_files
+}
+```
+
+Note: If using the `build_webui()` wrapper rule, add the new dependency to
+`ts_deps` (for a TypeScript file) or `ts_extra_deps` (for a JavaScript file
+with definitions).
+
+Failure to follow these steps can lead to other developers hitting flaky build
+errors and/or having their unrelated CLs reverted by sheriffs who aren't always
+aware that the regression range given in automated tools may not contain the
+true culprit for TypeScript related build flakes.
+
 ## See also
 
 * WebUI's C++ code follows the [Chromium C++ styleguide](../styleguide/c++/c++.md).
diff --git a/extensions/browser/api/web_request/upload_data_presenter.cc b/extensions/browser/api/web_request/upload_data_presenter.cc
index 11a89fa..7ace7a2 100644
--- a/extensions/browser/api/web_request/upload_data_presenter.cc
+++ b/extensions/browser/api/web_request/upload_data_presenter.cc
@@ -15,22 +15,18 @@
 #include "extensions/browser/api/web_request/web_request_api_constants.h"
 #include "net/base/upload_file_element_reader.h"
 
-using base::DictionaryValue;
-using base::ListValue;
-using base::Value;
-
 namespace keys = extension_web_request_api_constants;
 
 namespace {
 
 // Takes |dictionary| of <string, list of strings> pairs, and gets the list
 // for |key|, creating it if necessary.
-base::Value* GetOrCreateList(base::DictionaryValue* dictionary,
-                             const std::string& key) {
-  base::Value* list = dictionary->FindKeyOfType(key, base::Value::Type::LIST);
+base::Value::List& GetOrCreateList(base::Value::Dict& dictionary,
+                                   const std::string& key) {
+  base::Value::List* list = dictionary.FindList(key);
   if (list)
-    return list;
-  return dictionary->SetKey(key, base::Value(base::Value::Type::LIST));
+    return *list;
+  return dictionary.Set(key, base::Value::List())->GetList();
 }
 
 }  // namespace
@@ -41,66 +37,57 @@
 
 void AppendKeyValuePair(const char* key,
                         base::Value value,
-                        base::ListValue* list) {
+                        base::Value::List& list) {
   base::Value::Dict dictionary;
   dictionary.Set(key, std::move(value));
-  list->Append(base::Value(std::move(dictionary)));
+  list.Append(std::move(dictionary));
 }
 
 }  // namespace subtle
 
 UploadDataPresenter::~UploadDataPresenter() {}
 
-RawDataPresenter::RawDataPresenter()
-  : success_(true),
-    list_(new base::ListValue) {
-}
-RawDataPresenter::~RawDataPresenter() {}
+RawDataPresenter::RawDataPresenter() = default;
+
+RawDataPresenter::~RawDataPresenter() = default;
 
 void RawDataPresenter::FeedBytes(base::StringPiece bytes) {
-  if (!success_)
-    return;
-
   FeedNextBytes(bytes.data(), bytes.size());
 }
 
 void RawDataPresenter::FeedFile(const base::FilePath& path) {
-  if (!success_)
-    return;
-
   FeedNextFile(path.AsUTF8Unsafe());
 }
 
 bool RawDataPresenter::Succeeded() {
-  return success_;
+  return true;
 }
 
-std::unique_ptr<base::Value> RawDataPresenter::Result() {
-  if (!success_)
-    return nullptr;
-
-  return std::move(list_);
+absl::optional<base::Value> RawDataPresenter::TakeResult() {
+  return base::Value(std::move(list_));
 }
 
 void RawDataPresenter::FeedNextBytes(const char* bytes, size_t size) {
   subtle::AppendKeyValuePair(
       keys::kRequestBodyRawBytesKey,
-      base::Value(base::as_bytes(base::make_span(bytes, size))), list_.get());
+      base::Value(base::as_bytes(base::make_span(bytes, size))), list_);
 }
 
 void RawDataPresenter::FeedNextFile(const std::string& filename) {
   // Insert the file path instead of the contents, which may be too large.
   subtle::AppendKeyValuePair(keys::kRequestBodyRawFileKey,
-                             base::Value(filename), list_.get());
+                             base::Value(filename), list_);
 }
 
 ParsedDataPresenter::ParsedDataPresenter(
     const net::HttpRequestHeaders& request_headers)
     : parser_(FormDataParser::Create(request_headers)),
-      success_(parser_ != nullptr),
-      dictionary_(success_ ? new base::DictionaryValue() : nullptr) {}
+      success_(parser_ != nullptr) {
+  if (success_)
+    dictionary_.emplace();
+}
 
-ParsedDataPresenter::~ParsedDataPresenter() {}
+ParsedDataPresenter::~ParsedDataPresenter() = default;
 
 void ParsedDataPresenter::FeedBytes(base::StringPiece bytes) {
   if (!success_)
@@ -113,8 +100,9 @@
 
   FormDataParser::Result result;
   while (parser_->GetNextNameValue(&result)) {
-    base::Value* list = GetOrCreateList(dictionary_.get(), result.name());
-    list->Append(result.take_value());
+    base::Value::List& list =
+        GetOrCreateList(dictionary_.value(), result.name());
+    list.Append(result.take_value());
   }
 }
 
@@ -126,11 +114,10 @@
   return success_;
 }
 
-std::unique_ptr<base::Value> ParsedDataPresenter::Result() {
+absl::optional<base::Value> ParsedDataPresenter::TakeResult() {
   if (!success_)
-    return nullptr;
-
-  return std::move(dictionary_);
+    return absl::nullopt;
+  return base::Value(std::move(dictionary_.value()));
 }
 
 // static
@@ -141,8 +128,10 @@
 
 ParsedDataPresenter::ParsedDataPresenter(const std::string& form_type)
     : parser_(FormDataParser::CreateFromContentTypeHeader(&form_type)),
-      success_(parser_.get() != nullptr),
-      dictionary_(success_ ? new base::DictionaryValue() : nullptr) {}
+      success_(parser_.get() != nullptr) {
+  if (success_)
+    dictionary_.emplace();
+}
 
 void ParsedDataPresenter::Abort() {
   success_ = false;
diff --git a/extensions/browser/api/web_request/upload_data_presenter.h b/extensions/browser/api/web_request/upload_data_presenter.h
index 5fa17c8..9df9cfd 100644
--- a/extensions/browser/api/web_request/upload_data_presenter.h
+++ b/extensions/browser/api/web_request/upload_data_presenter.h
@@ -13,12 +13,11 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/strings/string_piece.h"
+#include "base/values.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
-class DictionaryValue;
 class FilePath;
-class ListValue;
-class Value;
 }
 
 namespace extensions {
@@ -38,7 +37,7 @@
 // Appends a dictionary {'key': 'value'} to |list|.
 void AppendKeyValuePair(const char* key,
                         base::Value value,
-                        base::ListValue* list);
+                        base::Value::List& list);
 
 }  // namespace subtle
 
@@ -60,7 +59,7 @@
   virtual void FeedBytes(base::StringPiece bytes) = 0;
   virtual void FeedFile(const base::FilePath& path) = 0;
   virtual bool Succeeded() = 0;
-  virtual std::unique_ptr<base::Value> Result() = 0;
+  virtual absl::optional<base::Value> TakeResult() = 0;
 
  protected:
   UploadDataPresenter() {}
@@ -82,15 +81,14 @@
   void FeedBytes(base::StringPiece bytes) override;
   void FeedFile(const base::FilePath& path) override;
   bool Succeeded() override;
-  std::unique_ptr<base::Value> Result() override;
+  absl::optional<base::Value> TakeResult() override;
 
  private:
   void FeedNextBytes(const char* bytes, size_t size);
   void FeedNextFile(const std::string& filename);
   FRIEND_TEST_ALL_PREFIXES(WebRequestUploadDataPresenterTest, RawData);
 
-  const bool success_;
-  std::unique_ptr<base::ListValue> list_;
+  base::Value::List list_;
 };
 
 // This class inspects the contents of bytes elements. It uses the
@@ -115,7 +113,7 @@
   void FeedBytes(base::StringPiece bytes) override;
   void FeedFile(const base::FilePath& path) override;
   bool Succeeded() override;
-  std::unique_ptr<base::Value> Result() override;
+  absl::optional<base::Value> TakeResult() override;
 
   // Allows to create ParsedDataPresenter without request headers. Uses the
   // parser for "application/x-www-form-urlencoded" form encoding. Only use this
@@ -131,7 +129,7 @@
 
   std::unique_ptr<FormDataParser> parser_;
   bool success_;
-  std::unique_ptr<base::DictionaryValue> dictionary_;
+  absl::optional<base::Value::Dict> dictionary_;
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/api/web_request/upload_data_presenter_unittest.cc b/extensions/browser/api/web_request/upload_data_presenter_unittest.cc
index dc4a1bfc..411b1f0 100644
--- a/extensions/browser/api/web_request/upload_data_presenter_unittest.cc
+++ b/extensions/browser/api/web_request/upload_data_presenter_unittest.cc
@@ -38,10 +38,8 @@
   parsed_data_presenter->FeedBytes(
       base::StringPiece(element.bytes(), element.length()));
   EXPECT_TRUE(parsed_data_presenter->Succeeded());
-  std::unique_ptr<base::Value> result = parsed_data_presenter->Result();
-  ASSERT_TRUE(result.get() != nullptr);
-
-  EXPECT_EQ(*result, expected_form);
+  absl::optional<base::Value> result = parsed_data_presenter->TakeResult();
+  EXPECT_EQ(result, expected_form);
 }
 
 TEST(WebRequestUploadDataPresenterTest, RawData) {
@@ -57,13 +55,13 @@
   base::Value expected_b(kFilename);
   base::Value expected_c(base::as_bytes(base::make_span(block2, block2_size)));
 
-  base::ListValue expected_list;
+  base::Value::List expected_list;
   subtle::AppendKeyValuePair(keys::kRequestBodyRawBytesKey,
-                             std::move(expected_a), &expected_list);
+                             std::move(expected_a), expected_list);
   subtle::AppendKeyValuePair(keys::kRequestBodyRawFileKey,
-                             std::move(expected_b), &expected_list);
+                             std::move(expected_b), expected_list);
   subtle::AppendKeyValuePair(keys::kRequestBodyRawBytesKey,
-                             std::move(expected_c), &expected_list);
+                             std::move(expected_c), expected_list);
 
   // Real output.
   RawDataPresenter raw_presenter;
@@ -71,9 +69,8 @@
   raw_presenter.FeedNextFile(kFilename);
   raw_presenter.FeedNextBytes(block2, block2_size);
   EXPECT_TRUE(raw_presenter.Succeeded());
-  std::unique_ptr<base::Value> result = raw_presenter.Result();
-  ASSERT_TRUE(result);
-  EXPECT_EQ(expected_list, *result);
+  absl::optional<base::Value> result = raw_presenter.TakeResult();
+  EXPECT_EQ(expected_list, result);
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/api/web_request/web_request_info.cc b/extensions/browser/api/web_request/web_request_info.cc
index a9e8edb4..3e201f3 100644
--- a/extensions/browser/api/web_request/web_request_info.cc
+++ b/extensions/browser/api/web_request/web_request_info.cc
@@ -136,7 +136,8 @@
       for (auto& source : data_sources)
         source->FeedToPresenter(presenters[i]);
       if (presenters[i]->Succeeded()) {
-        request_body_data->Set(kKeys[i], presenters[i]->Result());
+        request_body_data->GetDict().Set(kKeys[i],
+                                         presenters[i]->TakeResult().value());
         some_succeeded = true;
         break;
       }
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index a427252..eefe960 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1785,6 +1785,7 @@
   AUTOTESTPRIVATE_MAKEFUSEBOXTEMPDIR = 1722,
   AUTOTESTPRIVATE_REMOVEFUSEBOXTEMPDIR = 1723,
   AUTOTESTPRIVATE_GETTHROUGHPUTTRACKERDATA = 1724,
+  ENTERPRISE_REMOTEAPPS_SORTLAUNCHER = 1725,
   // Last entry: Add new entries above, then run:
   // tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index 4866cb2..d66baf3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -3368,7 +3368,6 @@
   MOCK_METHOD3(CopyTexSubImage,
                bool(unsigned, const gfx::Point&, const gfx::Rect&));
   MOCK_METHOD1(SetColorSpace, void(const gfx::ColorSpace&));
-  MOCK_METHOD0(Flush, void());
   MOCK_METHOD3(OnMemoryDump,
                void(base::trace_event::ProcessMemoryDump*,
                     uint64_t,
diff --git a/gpu/command_buffer/tests/texture_image_factory.cc b/gpu/command_buffer/tests/texture_image_factory.cc
index 17f18bf..34fbd2a66 100644
--- a/gpu/command_buffer/tests/texture_image_factory.cc
+++ b/gpu/command_buffer/tests/texture_image_factory.cc
@@ -37,7 +37,6 @@
     return false;
   }
   void SetColorSpace(const gfx::ColorSpace& color_space) override {}
-  void Flush() override {}
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override {}
diff --git a/gpu/ipc/service/stream_texture_android.h b/gpu/ipc/service/stream_texture_android.h
index f237cf1..79eb65a 100644
--- a/gpu/ipc/service/stream_texture_android.h
+++ b/gpu/ipc/service/stream_texture_android.h
@@ -75,7 +75,6 @@
                        const gfx::Point& offset,
                        const gfx::Rect& rect) override;
   void SetColorSpace(const gfx::ColorSpace& color_space) override {}
-  void Flush() override {}
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
diff --git a/infra/config/dev/subprojects/chromium/ci.star b/infra/config/dev/subprojects/chromium/ci.star
index 73a16488..b324ea5e 100644
--- a/infra/config/dev/subprojects/chromium/ci.star
+++ b/infra/config/dev/subprojects/chromium/ci.star
@@ -50,9 +50,6 @@
     "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com",
 )
 
-# TODO(crbug.com/1362440): remove this.
-defaults.omit_python2.set(False)
-
 def ci_builder(*, name, resultdb_bigquery_exports = None, **kwargs):
     resultdb_bigquery_exports = resultdb_bigquery_exports or []
     resultdb_bigquery_exports.extend([
diff --git a/infra/config/generated/builders/ci/fuchsia-fyi-arm64-dbg/properties.json b/infra/config/generated/builders/ci/fuchsia-fyi-arm64-dbg/properties.json
index 087c778..f60f93c 100644
--- a/infra/config/generated/builders/ci/fuchsia-fyi-arm64-dbg/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-fyi-arm64-dbg/properties.json
@@ -32,8 +32,7 @@
               },
               "legacy_test_results_config": {
                 "config": "staging_server"
-              },
-              "run_tests_serially": true
+              }
             }
           }
         ]
diff --git a/infra/config/generated/builders/ci/fuchsia-fyi-x64-asan/properties.json b/infra/config/generated/builders/ci/fuchsia-fyi-x64-asan/properties.json
index c741980..a214b60 100644
--- a/infra/config/generated/builders/ci/fuchsia-fyi-x64-asan/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-fyi-x64-asan/properties.json
@@ -30,8 +30,7 @@
               },
               "legacy_test_results_config": {
                 "config": "staging_server"
-              },
-              "run_tests_serially": true
+              }
             }
           }
         ]
diff --git a/infra/config/generated/builders/ci/fuchsia-fyi-x64-dbg/properties.json b/infra/config/generated/builders/ci/fuchsia-fyi-x64-dbg/properties.json
index db44f64..dd901ddf 100644
--- a/infra/config/generated/builders/ci/fuchsia-fyi-x64-dbg/properties.json
+++ b/infra/config/generated/builders/ci/fuchsia-fyi-x64-dbg/properties.json
@@ -30,8 +30,7 @@
               },
               "legacy_test_results_config": {
                 "config": "staging_server"
-              },
-              "run_tests_serially": true
+              }
             }
           }
         ]
diff --git a/infra/config/generated/builders/reclient/Mac Builder reclient test untrusted/properties.json b/infra/config/generated/builders/reclient/Mac Builder reclient test untrusted/properties.json
index 1e65700..a6d0939 100644
--- a/infra/config/generated/builders/reclient/Mac Builder reclient test untrusted/properties.json
+++ b/infra/config/generated/builders/reclient/Mac Builder reclient test untrusted/properties.json
@@ -50,7 +50,8 @@
       "RBE_ip_timeout": "-1s"
     },
     "instance": "rbe-chromium-untrusted-test",
-    "metrics_project": "chromium-reclient-metrics"
+    "metrics_project": "chromium-reclient-metrics",
+    "profiler_service": "reclient-mac"
   },
   "$recipe_engine/resultdb/test_presentation": {
     "column_keys": [],
diff --git a/infra/config/generated/builders/reclient/Mac Builder reclient test/properties.json b/infra/config/generated/builders/reclient/Mac Builder reclient test/properties.json
index ca4019d..e832b58 100644
--- a/infra/config/generated/builders/reclient/Mac Builder reclient test/properties.json
+++ b/infra/config/generated/builders/reclient/Mac Builder reclient test/properties.json
@@ -50,7 +50,8 @@
       "RBE_ip_timeout": "-1s"
     },
     "instance": "rbe-chromium-trusted-test",
-    "metrics_project": "chromium-reclient-metrics"
+    "metrics_project": "chromium-reclient-metrics",
+    "profiler_service": "reclient-mac"
   },
   "$recipe_engine/resultdb/test_presentation": {
     "column_keys": [],
diff --git a/infra/config/generated/builders/try/fuchsia-fyi-arm64-dbg/properties.json b/infra/config/generated/builders/try/fuchsia-fyi-arm64-dbg/properties.json
index e341c5e..439350d79 100644
--- a/infra/config/generated/builders/try/fuchsia-fyi-arm64-dbg/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-fyi-arm64-dbg/properties.json
@@ -32,8 +32,7 @@
               },
               "legacy_test_results_config": {
                 "config": "staging_server"
-              },
-              "run_tests_serially": true
+              }
             }
           }
         ]
diff --git a/infra/config/generated/builders/try/fuchsia-fyi-x64-dbg/properties.json b/infra/config/generated/builders/try/fuchsia-fyi-x64-dbg/properties.json
index adef3c1..7b24403 100644
--- a/infra/config/generated/builders/try/fuchsia-fyi-x64-dbg/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-fyi-x64-dbg/properties.json
@@ -30,8 +30,7 @@
               },
               "legacy_test_results_config": {
                 "config": "staging_server"
-              },
-              "run_tests_serially": true
+              }
             }
           }
         ]
diff --git a/infra/config/generated/luci/cr-buildbucket-dev.cfg b/infra/config/generated/luci/cr-buildbucket-dev.cfg
index f5b923df..b1db6aa 100644
--- a/infra/config/generated/luci/cr-buildbucket-dev.cfg
+++ b/infra/config/generated/luci/cr-buildbucket-dev.cfg
@@ -39,6 +39,10 @@
       build_numbers: YES
       service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -93,6 +97,10 @@
       build_numbers: YES
       service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -149,6 +157,10 @@
       build_numbers: YES
       service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -203,6 +215,10 @@
       build_numbers: YES
       service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -256,6 +272,10 @@
       build_numbers: YES
       service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -310,6 +330,10 @@
       build_numbers: YES
       service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -364,6 +388,10 @@
       build_numbers: YES
       service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 398f697..4cce0f0 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -29092,6 +29092,10 @@
         value: 10
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -29174,6 +29178,10 @@
         value: 10
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -40303,6 +40311,10 @@
         value: 10
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -40385,6 +40397,10 @@
         value: 10
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -58854,6 +58870,10 @@
         value: 100
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -58959,6 +58979,10 @@
         value: 100
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -65204,7 +65228,7 @@
       }
       experiments {
         key: "chromium_swarming.expose_merge_script_failures"
-        value: 20
+        value: 0
       }
       experiments {
         key: "enable_weetbix_queries"
@@ -78990,6 +79014,10 @@
         value: 100
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -79095,6 +79123,10 @@
         value: 100
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -79200,6 +79232,10 @@
         value: 100
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -84721,6 +84757,10 @@
         value: 100
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -84825,6 +84865,10 @@
         value: 100
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -89750,6 +89794,10 @@
         value: 100
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
@@ -89856,6 +89904,10 @@
         value: 100
       }
       experiments {
+        key: "luci.buildbucket.omit_python2"
+        value: 100
+      }
+      experiments {
         key: "luci.recipes.use_python3"
         value: 100
       }
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
index d6f5def6..dc93367 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fuchsia.fyi.star
@@ -119,7 +119,6 @@
             config = "staging_server",
         ),
         build_gs_bucket = "chromium-fyi-archive",
-        run_tests_serially = True,
     ),
 )
 
@@ -157,7 +156,6 @@
             config = "staging_server",
         ),
         build_gs_bucket = "chromium-fyi-archive",
-        run_tests_serially = True,
     ),
 )
 
@@ -195,7 +193,6 @@
             config = "staging_server",
         ),
         build_gs_bucket = "chromium-fyi-archive",
-        run_tests_serially = True,
     ),
 )
 
diff --git a/infra/config/subprojects/chromium/ci/chromium.rust.star b/infra/config/subprojects/chromium/ci/chromium.rust.star
index d5fa1e0..977f1a1 100644
--- a/infra/config/subprojects/chromium/ci/chromium.rust.star
+++ b/infra/config/subprojects/chromium/ci/chromium.rust.star
@@ -19,9 +19,6 @@
     service_account = ci.DEFAULT_SERVICE_ACCOUNT,
     os = os.LINUX_DEFAULT,
     notifies = ["chrome-rust-experiments"],
-
-    # TODO(crbug.com/1362440): remove this.
-    omit_python2 = False,
 )
 
 consoles.console_view(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
index ee68ca9e..5caa742 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
@@ -160,6 +160,8 @@
         "ci/fuchsia-x64-cast-receiver-rel",
     ],
     experiments = {
+        # TODO(crbug.com/1374440): Re-enable merge script failure exposure.
+        "chromium_swarming.expose_merge_script_failures": 0,
         "enable_weetbix_queries": 100,
         "weetbix.retry_weak_exonerations": 100,
         "weetbix.enable_weetbix_exonerations": 100,
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.rust.star b/infra/config/subprojects/chromium/try/tryserver.chromium.rust.star
index 8d94738d..9c75985 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.rust.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.rust.star
@@ -17,9 +17,6 @@
     os = os.LINUX_DEFAULT,
     pool = try_.DEFAULT_POOL,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-
-    # TODO(crbug.com/1362440): remove this.
-    omit_python2 = False,
 )
 
 consoles.list_view(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.updater.star b/infra/config/subprojects/chromium/try/tryserver.chromium.updater.star
index 608c79b1..59e8e49 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.updater.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.updater.star
@@ -15,9 +15,6 @@
     goma_backend = goma.backend.RBE_PROD,
     pool = try_.DEFAULT_POOL,
     service_account = try_.DEFAULT_SERVICE_ACCOUNT,
-
-    # TODO(crbug.com/1362440): remove this.
-    omit_python2 = False,
 )
 
 consoles.list_view(
diff --git a/infra/config/subprojects/reclient/reclient.star b/infra/config/subprojects/reclient/reclient.star
index 2d0d266..579856a 100644
--- a/infra/config/subprojects/reclient/reclient.star
+++ b/infra/config/subprojects/reclient/reclient.star
@@ -195,6 +195,7 @@
         "RBE_ip_timeout": "-1s",
         "GLOG_vmodule": "bridge*=2",
     },
+    reclient_profiler_service = "reclient-mac",
 )
 
 fyi_reclient_staging_builder(
diff --git a/ios/chrome/app/post_restore_app_agent_unittest.mm b/ios/chrome/app/post_restore_app_agent_unittest.mm
index 2fe3c955..25c1b46 100644
--- a/ios/chrome/app/post_restore_app_agent_unittest.mm
+++ b/ios/chrome/app/post_restore_app_agent_unittest.mm
@@ -100,7 +100,7 @@
 
   void EnableFeatureVariationAlert() {
     scoped_feature_list_.InitWithFeaturesAndParameters(
-        {base::test::ScopedFeatureList::FeatureAndParams(
+        {base::test::FeatureRefAndParams(
             post_restore_signin::features::kIOSNewPostRestoreExperience,
             {{post_restore_signin::features::kIOSNewPostRestoreExperienceParam,
               "true"}})},
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd
index 612e53c0..f6a671a 100644
--- a/ios/chrome/app/strings/ios_chromium_strings.grd
+++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -326,9 +326,6 @@
       <message name="IDS_IOS_FIRST_RUN_UMA_DIALOG_TITLE" desc="In Title Case: Title of the dialog where users can change their Chrome metrics sharing settings, like usage data. The title communicates that allowing Chrome to see this data can improve Chrome; this happens because we can better invent/improve features based on usage. This appears when they open the Chrome app for the first time on their phone. [iOS only]">
         Make Chromium Better
         </message>
-      <message name="IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT" desc="The label next to the metrics reporting consent checkbox of the welcome screen presented to the user on First Run [iOS only]">
-        Help improve Chromium by sending usage statistics and crash reports to Google
-      </message>
       <message name="IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TITLE_ENTERPRISE" desc="The title of the welcome screen presented to the user on First Run when the browser is managed [iOS only]">
         Get More Done with Chromium
       </message>
diff --git a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT.png.sha1 b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT.png.sha1
deleted file mode 100644
index af25099..0000000
--- a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-293be6fe4529e4632aa5689246c27292d5605c17
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd
index a69ed7a3..a2238c19 100644
--- a/ios/chrome/app/strings/ios_google_chrome_strings.grd
+++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -326,9 +326,6 @@
       <message name="IDS_IOS_FIRST_RUN_UMA_DIALOG_TITLE" desc="In Title Case: Title of the dialog where users can change their Chrome metrics sharing settings, like usage data. The title communicates that allowing Chrome to see this data can improve Chrome; this happens because we can better invent/improve features based on usage. This appears when they open the Chrome app for the first time on their phone. [iOS only]">
         Make Chrome Better
         </message>
-      <message name="IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT" desc="The label next to the metrics reporting consent checkbox of the welcome screen presented to the user on First Run [iOS only]">
-        Help improve Chrome by sending usage statistics and crash reports to Google
-      </message>
       <message name="IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TITLE_ENTERPRISE" desc="The title of the welcome screen presented to the user on First Run when the browser is managed [iOS only]">
         Get More Done with Chrome
       </message>
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT.png.sha1 b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT.png.sha1
deleted file mode 100644
index 861aed4..0000000
--- a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-816caf3f4ae7e9383dc5b2ce4a0783aa1102cbb0
\ No newline at end of file
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index af1199e..f778419 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -480,9 +480,6 @@
      std::size(kTrendingQueriesEnableFeedDisabled), nullptr},
 };
 
-const FeatureEntry::FeatureParam kNewMICEFREWithUMADialog[] = {
-    {kNewMobileIdentityConsistencyFREParam,
-     kNewMobileIdentityConsistencyFREParamUMADialog}};
 const FeatureEntry::FeatureParam kNewMICEFREWithTangibleSyncA[] = {
     {kNewMobileIdentityConsistencyFREParam,
      kNewMobileIdentityConsistencyFREParamTangibleSyncA}};
@@ -497,8 +494,6 @@
      kNewMobileIdentityConsistencyFREParamTwoSteps}};
 const FeatureEntry::FeatureVariation
     kNewMobileIdentityConsistencyFREVariations[] = {
-        {"New FRE with UMA dialog", kNewMICEFREWithUMADialog,
-         std::size(kNewMICEFREWithUMADialog), nullptr},
         {"new FRE with tangible sync A", kNewMICEFREWithTangibleSyncA,
          std::size(kNewMICEFREWithTangibleSyncA), nullptr},
         {"new FRE with tangible sync B", kNewMICEFREWithTangibleSyncB,
@@ -1267,6 +1262,16 @@
     {"keyboard-shortcuts-menu", flag_descriptions::kKeyboardShortcutsMenuName,
      flag_descriptions::kKeyboardShortcutsMenuDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kKeyboardShortcutsMenu)},
+    {"enable-check-visibility-on-attention-log-start",
+     flag_descriptions::kEnableCheckVisibilityOnAttentionLogStartName,
+     flag_descriptions::kEnableCheckVisibilityOnAttentionLogStartDescription,
+     flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kEnableCheckVisibilityOnAttentionLogStart)},
+    {"enable-refine-data-source-reload-reporting",
+     flag_descriptions::kEnableRefineDataSourceReloadReportingName,
+     flag_descriptions::kEnableRefineDataSourceReloadReportingDescription,
+     flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kEnableRefineDataSourceReloadReporting)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index fbb3a7b..8aea288 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -254,6 +254,11 @@
 const char kEnableCBDSignOutDescription[] =
     "Offer signed-in user to sign-out from Clear Browsing Data settings.";
 
+const char kEnableCheckVisibilityOnAttentionLogStartName[] =
+    "Enable Check Feed Visibility On Attention Log Start";
+const char kEnableCheckVisibilityOnAttentionLogStartDescription[] =
+    "Enable checking feed visibility on attention log start.";
+
 const char kEnableDiscoverFeedDiscoFeedEndpointName[] =
     "Enable discover feed discofeed";
 const char kEnableDiscoverFeedDiscoFeedEndpointDescription[] =
@@ -310,6 +315,12 @@
 const char kEnableOpenInDownloadDescription[] =
     "Enable new download for Open In menu (iOS 14.5+).";
 
+const char kEnableRefineDataSourceReloadReportingName[] =
+    "Enable Refine Data Source Reload Reporting";
+const char kEnableRefineDataSourceReloadReportingDescription[] =
+    "Enable refining data source reload reporting when having a very short "
+    "attention log";
+
 const char kEnableUnicornAccountSupportName[] =
     "Enable Unicorn account support";
 const char kEnableUnicornAccountSupportDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 529f536..b0afa820 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -193,6 +193,11 @@
 extern const char kDiscoverFeedInNtpName[];
 extern const char kDiscoverFeedInNtpDescription[];
 
+// Title and description for the flag to enable checking feed visibility on
+// attention log start.
+extern const char kEnableCheckVisibilityOnAttentionLogStartName[];
+extern const char kEnableCheckVisibilityOnAttentionLogStartDescription[];
+
 // Title and description for the flag to enable the sync promotion on top of the
 // discover feed.
 extern const char kEnableDiscoverFeedTopSyncPromoName[];
@@ -288,6 +293,11 @@
 extern const char kEnableOpenInDownloadName[];
 extern const char kEnableOpenInDownloadDescription[];
 
+// Title and description for the flag to enable refining data source reload
+// reporting when having a very short attention log.
+extern const char kEnableRefineDataSourceReloadReportingName[];
+extern const char kEnableRefineDataSourceReloadReportingDescription[];
+
 // Title and description for the flag to enable omnibox suggestions scrolling on
 // iPad.
 extern const char kEnableSuggestionsScrollingOnIPadName[];
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/tailored_security/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/tailored_security/BUILD.gn
index 754df0b1..abb8e049 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/tailored_security/BUILD.gn
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/tailored_security/BUILD.gn
@@ -29,11 +29,19 @@
   deps = [
     ":tailored_security",
     "//base",
+    "//components/safe_browsing/core/common:safe_browsing_prefs",
+    "//components/sync_preferences",
+    "//components/sync_preferences:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/infobars",
     "//ios/chrome/browser/infobars/overlays",
     "//ios/chrome/browser/infobars/test",
     "//ios/chrome/browser/overlays/public/infobar_banner",
+    "//ios/chrome/browser/prefs:browser_prefs",
+    "//ios/chrome/browser/safe_browsing",
     "//ios/chrome/browser/safe_browsing/tailored_security/test",
+    "//ios/components/security_interstitials/safe_browsing",
+    "//ios/web/public/test",
     "//ios/web/public/test/fakes",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/tailored_security/tailored_security_infobar_banner_interaction_handler_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/tailored_security/tailored_security_infobar_banner_interaction_handler_unittest.mm
index 62f2158..5d4bbf6 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/tailored_security/tailored_security_infobar_banner_interaction_handler_unittest.mm
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/tailored_security/tailored_security_infobar_banner_interaction_handler_unittest.mm
@@ -4,14 +4,24 @@
 
 #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/tailored_security/tailored_security_infobar_banner_interaction_handler.h"
 
+#import "components/safe_browsing/core/common/safe_browsing_prefs.h"
+#import "components/sync_preferences/pref_service_mock_factory.h"
+#import "components/sync_preferences/pref_service_syncable.h"
+#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/infobars/infobar_manager_impl.h"
 #import "ios/chrome/browser/infobars/overlays/default_infobar_overlay_request_factory.h"
 #import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h"
 #import "ios/chrome/browser/infobars/test/fake_infobar_ios.h"
 #import "ios/chrome/browser/overlays/public/infobar_banner/tailored_security_service_infobar_banner_overlay_request_config.h"
+#import "ios/chrome/browser/prefs/browser_prefs.h"
+#import "ios/chrome/browser/safe_browsing/safe_browsing_client_factory.h"
 #import "ios/chrome/browser/safe_browsing/tailored_security/test/mock_tailored_security_service_infobar_delegate.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_client.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_query_manager.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_tab_helper.h"
 #import "ios/web/public/test/fakes/fake_navigation_manager.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
+#import "ios/web/public/test/web_task_environment.h"
 #import "testing/platform_test.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -23,22 +33,30 @@
     : public PlatformTest {
  public:
   TailoredSecurityInfobarBannerInteractionHandlerTest()
-      : handler_(
+      : task_environment_(web::WebTaskEnvironment::IO_MAINLOOP),
+        handler_(
             tailored_security_service_infobar_overlays::
                 TailoredSecurityServiceBannerRequestConfig::RequestSupport()) {
+    scoped_refptr<user_prefs::PrefRegistrySyncable> registry =
+        base::MakeRefCounted<user_prefs::PrefRegistrySyncable>();
+    RegisterBrowserStatePrefs(registry.get());
+    sync_preferences::PrefServiceMockFactory factory;
+
     web_state_.SetNavigationManager(
         std::make_unique<web::FakeNavigationManager>());
     InfobarOverlayRequestInserter::CreateForWebState(
         &web_state_, &DefaultInfobarOverlayRequestFactory);
     InfoBarManagerImpl::CreateForWebState(&web_state_);
-    std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
-        InfobarType::kInfobarTypeTailoredSecurityService,
-        safe_browsing::MockTailoredSecurityServiceInfobarDelegate::Create(
-            /*message_state*/ safe_browsing::
-                TailoredSecurityServiceMessageState::kConsentedAndFlowEnabled));
-    infobar_ = infobar.get();
-    InfoBarManagerImpl::FromWebState(&web_state_)
-        ->AddInfoBar(std::move(infobar));
+
+    TestChromeBrowserState::Builder test_cbs_builder;
+    test_cbs_builder.SetPrefService(factory.CreateSyncable(registry.get()));
+    chrome_browser_state_ = test_cbs_builder.Build();
+    web_state_.SetBrowserState(chrome_browser_state_.get());
+
+    SafeBrowsingClient* client = SafeBrowsingClientFactory::GetForBrowserState(
+        chrome_browser_state_.get());
+    SafeBrowsingQueryManager::CreateForWebState(&web_state_, client);
+    SafeBrowsingTabHelper::CreateForWebState(&web_state_, client);
   }
 
   safe_browsing::MockTailoredSecurityServiceInfobarDelegate& mock_delegate() {
@@ -47,17 +65,49 @@
         infobar_->delegate());
   }
 
+  // Creates an infobar with a specific TailoredSecurityServiceMessageState.
+  void CreateInfobarWithMessageState(
+      safe_browsing::TailoredSecurityServiceMessageState message_state) {
+    std::unique_ptr<InfoBarIOS> infobar = std::make_unique<InfoBarIOS>(
+        InfobarType::kInfobarTypeTailoredSecurityService,
+        safe_browsing::MockTailoredSecurityServiceInfobarDelegate::Create(
+            message_state, &web_state_));
+    infobar_ = infobar.get();
+    InfoBarManagerImpl::FromWebState(&web_state_)
+        ->AddInfoBar(std::move(infobar));
+  }
+
  protected:
+  web::WebTaskEnvironment task_environment_;
   TailoredSecurityInfobarBannerInteractionHandler handler_;
   web::FakeWebState web_state_;
   InfoBarIOS* infobar_;
+  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
 };
 
 // Tests MainButtonTapped() calls Accept() on the mock delegate and resets
-// the infobar to be accepted.
-TEST_F(TailoredSecurityInfobarBannerInteractionHandlerTest, MainButton) {
+// the infobar to be accepted for consented message prompt.
+TEST_F(TailoredSecurityInfobarBannerInteractionHandlerTest,
+       ConsentedMessagePromptButtonTapped) {
+  CreateInfobarWithMessageState(
+      safe_browsing::TailoredSecurityServiceMessageState::
+          kConsentedAndFlowEnabled);
   ASSERT_FALSE(infobar_->accepted());
-  EXPECT_CALL(mock_delegate(), Accept()).WillOnce(testing::Return(true));
   handler_.MainButtonTapped(infobar_);
   EXPECT_TRUE(infobar_->accepted());
 }
+
+// Tests MainButtonTapped() calls Accept() on the mock delegate and resets
+// the infobar to be accepted for unconsented message prompt.
+TEST_F(TailoredSecurityInfobarBannerInteractionHandlerTest,
+       UnconsentedMessagePromptButtonTapped) {
+  CreateInfobarWithMessageState(
+      safe_browsing::TailoredSecurityServiceMessageState::
+          kUnconsentedAndFlowEnabled);
+  ASSERT_FALSE(infobar_->accepted());
+  handler_.MainButtonTapped(infobar_);
+  EXPECT_TRUE(infobar_->accepted());
+  EXPECT_TRUE(
+      safe_browsing::GetSafeBrowsingState(*chrome_browser_state_->GetPrefs()) ==
+      safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION);
+}
diff --git a/ios/chrome/browser/infobars/overlays/default_infobar_overlay_request_factory_unittest.mm b/ios/chrome/browser/infobars/overlays/default_infobar_overlay_request_factory_unittest.mm
index fb081316..83b55bac 100644
--- a/ios/chrome/browser/infobars/overlays/default_infobar_overlay_request_factory_unittest.mm
+++ b/ios/chrome/browser/infobars/overlays/default_infobar_overlay_request_factory_unittest.mm
@@ -193,7 +193,8 @@
   std::unique_ptr<InfoBarDelegate> delegate =
       safe_browsing::MockTailoredSecurityServiceInfobarDelegate::Create(
           /*message_state*/ TailoredSecurityServiceMessageState::
-              kConsentedAndFlowEnabled);
+              kConsentedAndFlowEnabled,
+          nullptr);
   InfoBarIOS infobar(InfobarType::kInfobarTypeTailoredSecurityService,
                      std::move(delegate));
 
diff --git a/ios/chrome/browser/safe_browsing/tailored_security/BUILD.gn b/ios/chrome/browser/safe_browsing/tailored_security/BUILD.gn
index d89a5d4f..2a6fbc6 100644
--- a/ios/chrome/browser/safe_browsing/tailored_security/BUILD.gn
+++ b/ios/chrome/browser/safe_browsing/tailored_security/BUILD.gn
@@ -32,7 +32,13 @@
     "tailored_security_service_infobar_delegate.mm",
   ]
 
-  deps = [ "//components/infobars/core" ]
+  deps = [
+    "//components/infobars/core",
+    "//components/safe_browsing/core/common:safe_browsing_prefs",
+    "//ios/chrome/browser/browser_state",
+    "//ios/components/security_interstitials/safe_browsing",
+    "//ios/web/public",
+  ]
 }
 
 source_set("unit_tests") {
diff --git a/ios/chrome/browser/safe_browsing/tailored_security/tailored_security_service_infobar_delegate.h b/ios/chrome/browser/safe_browsing/tailored_security/tailored_security_service_infobar_delegate.h
index c32735e..be28f4d 100644
--- a/ios/chrome/browser/safe_browsing/tailored_security/tailored_security_service_infobar_delegate.h
+++ b/ios/chrome/browser/safe_browsing/tailored_security/tailored_security_service_infobar_delegate.h
@@ -9,6 +9,12 @@
 
 #import <string>
 
+#import "base/memory/weak_ptr.h"
+
+namespace web {
+class WebState;
+}  // namespace web
+
 namespace safe_browsing {
 
 enum class TailoredSecurityServiceMessageState {
@@ -26,11 +32,13 @@
 class TailoredSecurityServiceInfobarDelegate : public ConfirmInfoBarDelegate {
  public:
   explicit TailoredSecurityServiceInfobarDelegate(
-      TailoredSecurityServiceMessageState message_state);
+      TailoredSecurityServiceMessageState message_state,
+      web::WebState* web_state);
   TailoredSecurityServiceInfobarDelegate(
       const TailoredSecurityServiceInfobarDelegate&) = delete;
   TailoredSecurityServiceInfobarDelegate& operator=(
       const TailoredSecurityServiceInfobarDelegate&) = delete;
+  ~TailoredSecurityServiceInfobarDelegate() override;
 
   // Returns |delegate| as an TailoredSecurityServiceInfobarDelegate, or
   // nullptr if it is of another type.
@@ -50,11 +58,15 @@
   std::u16string GetMessageText() const override;
   infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
   bool EqualsDelegate(infobars::InfoBarDelegate* delegate) const override;
+  bool Accept() override;
 
  private:
   // Stores the state of the consent flow and is used to
   // return appropriate messages for the prompt.
   TailoredSecurityServiceMessageState message_state_;
+
+  // Stores associated WebState.
+  base::WeakPtr<web::WebState> web_state_;
 };
 
 }  // namespace safe_browsing
diff --git a/ios/chrome/browser/safe_browsing/tailored_security/tailored_security_service_infobar_delegate.mm b/ios/chrome/browser/safe_browsing/tailored_security/tailored_security_service_infobar_delegate.mm
index 3637bc7..9041645 100644
--- a/ios/chrome/browser/safe_browsing/tailored_security/tailored_security_service_infobar_delegate.mm
+++ b/ios/chrome/browser/safe_browsing/tailored_security/tailored_security_service_infobar_delegate.mm
@@ -4,6 +4,11 @@
 
 #import "ios/chrome/browser/safe_browsing/tailored_security/tailored_security_service_infobar_delegate.h"
 
+#import "components/safe_browsing/core/common/safe_browsing_prefs.h"
+#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_tab_helper.h"
+#import "ios/web/public/web_state.h"
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -22,8 +27,13 @@
 
 namespace safe_browsing {
 TailoredSecurityServiceInfobarDelegate::TailoredSecurityServiceInfobarDelegate(
-    TailoredSecurityServiceMessageState message_state)
-    : message_state_(message_state) {}
+    TailoredSecurityServiceMessageState message_state,
+    web::WebState* web_state)
+    : message_state_(message_state),
+      web_state_(web_state ? web_state->GetWeakPtr() : nullptr) {}
+
+TailoredSecurityServiceInfobarDelegate::
+    ~TailoredSecurityServiceInfobarDelegate() = default;
 
 TailoredSecurityServiceInfobarDelegate*
 TailoredSecurityServiceInfobarDelegate::FromInfobarDelegate(
@@ -82,6 +92,27 @@
   return delegate->GetIdentifier() == GetIdentifier();
 }
 
+bool TailoredSecurityServiceInfobarDelegate::Accept() {
+  if (web_state_) {
+    switch (message_state_) {
+      case TailoredSecurityServiceMessageState::kConsentedAndFlowEnabled:
+      case TailoredSecurityServiceMessageState::kConsentedAndFlowDisabled:
+        SafeBrowsingTabHelper::FromWebState(web_state_.get())
+            ->OpenSafeBrowsingSettings();
+        break;
+      case TailoredSecurityServiceMessageState::kUnconsentedAndFlowEnabled:
+        ChromeBrowserState* browser_state =
+            ChromeBrowserState::FromBrowserState(web_state_->GetBrowserState());
+        SetSafeBrowsingState(
+            browser_state->GetPrefs(),
+            safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION,
+            /*is_esb_enabled_in_sync=*/false);
+        break;
+    }
+  }
+  return true;
+}
+
 infobars::InfoBarDelegate::InfoBarIdentifier
 TailoredSecurityServiceInfobarDelegate::GetIdentifier() const {
   return TAILORED_SECURITY_SERVICE_INFOBAR_DELEGATE;
diff --git a/ios/chrome/browser/safe_browsing/tailored_security/test/mock_tailored_security_service_infobar_delegate.h b/ios/chrome/browser/safe_browsing/tailored_security/test/mock_tailored_security_service_infobar_delegate.h
index c768a6bf..c58a12b 100644
--- a/ios/chrome/browser/safe_browsing/tailored_security/test/mock_tailored_security_service_infobar_delegate.h
+++ b/ios/chrome/browser/safe_browsing/tailored_security/test/mock_tailored_security_service_infobar_delegate.h
@@ -16,15 +16,16 @@
 class MockTailoredSecurityServiceInfobarDelegate
     : public TailoredSecurityServiceInfobarDelegate {
  public:
-  explicit MockTailoredSecurityServiceInfobarDelegate(
-      TailoredSecurityServiceMessageState message_state);
+  MockTailoredSecurityServiceInfobarDelegate(
+      TailoredSecurityServiceMessageState message_state,
+      web::WebState* web_state);
   ~MockTailoredSecurityServiceInfobarDelegate() override;
 
   // Factory method that creates a mock tailored security service delegate..
   static std::unique_ptr<MockTailoredSecurityServiceInfobarDelegate> Create(
-      TailoredSecurityServiceMessageState message_state);
+      TailoredSecurityServiceMessageState message_state,
+      web::WebState* web_state);
   MOCK_METHOD0(InfoBarDismissed, void());
-  MOCK_METHOD0(Accept, bool());
   MOCK_METHOD0(Cancel, bool());
   MOCK_METHOD1(InfobarPresenting, void(bool automatic));
   MOCK_METHOD0(InfobarDismissed, void());
diff --git a/ios/chrome/browser/safe_browsing/tailored_security/test/mock_tailored_security_service_infobar_delegate.mm b/ios/chrome/browser/safe_browsing/tailored_security/test/mock_tailored_security_service_infobar_delegate.mm
index 7a11d7a2..6aa4193 100644
--- a/ios/chrome/browser/safe_browsing/tailored_security/test/mock_tailored_security_service_infobar_delegate.mm
+++ b/ios/chrome/browser/safe_browsing/tailored_security/test/mock_tailored_security_service_infobar_delegate.mm
@@ -15,15 +15,17 @@
 // static
 std::unique_ptr<MockTailoredSecurityServiceInfobarDelegate>
 MockTailoredSecurityServiceInfobarDelegate::Create(
-    TailoredSecurityServiceMessageState message_state) {
+    TailoredSecurityServiceMessageState message_state,
+    web::WebState* web_state) {
   return std::make_unique<MockTailoredSecurityServiceInfobarDelegate>(
-      message_state);
+      message_state, web_state);
 }
 
 MockTailoredSecurityServiceInfobarDelegate::
     MockTailoredSecurityServiceInfobarDelegate(
-        TailoredSecurityServiceMessageState message_state)
-    : TailoredSecurityServiceInfobarDelegate(message_state) {}
+        TailoredSecurityServiceMessageState message_state,
+        web::WebState* web_state)
+    : TailoredSecurityServiceInfobarDelegate(message_state, web_state) {}
 
 MockTailoredSecurityServiceInfobarDelegate::
     ~MockTailoredSecurityServiceInfobarDelegate() = default;
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_screen_provider.mm b/ios/chrome/browser/ui/authentication/signin/signin_screen_provider.mm
index ea5f905..831e921 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_screen_provider.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_screen_provider.mm
@@ -23,7 +23,6 @@
     case NewMobileIdentityConsistencyFRE::kTangibleSyncC:
       [screens addObject:@(kSignIn)];
       break;
-    case NewMobileIdentityConsistencyFRE::kUMADialog:
     case NewMobileIdentityConsistencyFRE::kOld:
       [screens addObject:@(kLegacySignIn)];
       break;
diff --git a/ios/chrome/browser/ui/authentication/tangible_sync/tangible_sync_view_controller.mm b/ios/chrome/browser/ui/authentication/tangible_sync/tangible_sync_view_controller.mm
index bba61bf9..ec318a8e4 100644
--- a/ios/chrome/browser/ui/authentication/tangible_sync/tangible_sync_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/tangible_sync/tangible_sync_view_controller.mm
@@ -59,7 +59,6 @@
       subtitleStringID = IDS_IOS_TANGIBLE_SYNC_SUBTITLE_SYNC;
       break;
     case NewMobileIdentityConsistencyFRE::kTwoSteps:
-    case NewMobileIdentityConsistencyFRE::kUMADialog:
     case NewMobileIdentityConsistencyFRE::kOld:
       NOTREACHED();
       break;
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
index 0ac7cff1..b1eecfb 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
@@ -141,6 +141,7 @@
   bool AreServerCardsSupported() const override;
   void ExecuteCommand(int id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
+  FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
 
   // RiskDataLoader:
   void LoadRiskData(
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
index 00eadb7..b7de837 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
@@ -487,6 +487,13 @@
       /*is_renderer_initiated=*/false));
 }
 
+autofill::FormInteractionsFlowId
+ChromeAutofillClientIOS::GetCurrentFormInteractionsFlowId() {
+  // Currently not in use here. See `ChromeAutofillClient` for a proper
+  // implementation.
+  return {};
+}
+
 void ChromeAutofillClientIOS::LoadRiskData(
     base::OnceCallback<void(const std::string&)> callback) {
   std::move(callback).Run(
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index 30b88e8..4fae6b71 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -1402,6 +1402,11 @@
   [self.whatsNewCoordinator start];
 }
 
+- (void)dismissWhatsNew {
+  [self.whatsNewCoordinator stop];
+  self.whatsNewCoordinator = nil;
+}
+
 #pragma mark - DefaultPromoCommands
 
 - (void)showTailoredPromoStaySafe {
diff --git a/ios/chrome/browser/ui/commands/browser_coordinator_commands.h b/ios/chrome/browser/ui/commands/browser_coordinator_commands.h
index 5099d5e..98a6fcf13 100644
--- a/ios/chrome/browser/ui/commands/browser_coordinator_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_coordinator_commands.h
@@ -95,6 +95,9 @@
 // Shows what's new.
 - (void)showWhatsNew;
 
+// Dismisses what's new.
+- (void)dismissWhatsNew;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_BROWSER_COORDINATOR_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/first_run/field_trial_constants.cc b/ios/chrome/browser/ui/first_run/field_trial_constants.cc
index a1cf47a0e..2de3bb4 100644
--- a/ios/chrome/browser/ui/first_run/field_trial_constants.cc
+++ b/ios/chrome/browser/ui/first_run/field_trial_constants.cc
@@ -18,7 +18,6 @@
 
 // Parameters for new Mobile Identity Consistency FRE.
 const char kNewMobileIdentityConsistencyFREParam[] = "variant_new_mice_fre";
-const char kNewMobileIdentityConsistencyFREParamUMADialog[] = "umadialog";
 const char kNewMobileIdentityConsistencyFREParamTangibleSyncA[] =
     "tangiblesyncA";
 const char kNewMobileIdentityConsistencyFREParamTangibleSyncB[] =
diff --git a/ios/chrome/browser/ui/first_run/field_trial_constants.h b/ios/chrome/browser/ui/first_run/field_trial_constants.h
index 1f80f38..ea371a82 100644
--- a/ios/chrome/browser/ui/first_run/field_trial_constants.h
+++ b/ios/chrome/browser/ui/first_run/field_trial_constants.h
@@ -25,7 +25,6 @@
 
 // Indicates which variant of the new MICE FRE to use.
 extern const char kNewMobileIdentityConsistencyFREParam[];
-extern const char kNewMobileIdentityConsistencyFREParamUMADialog[];
 extern const char kNewMobileIdentityConsistencyFREParamTangibleSyncA[];
 extern const char kNewMobileIdentityConsistencyFREParamTangibleSyncB[];
 extern const char kNewMobileIdentityConsistencyFREParamTangibleSyncC[];
diff --git a/ios/chrome/browser/ui/first_run/first_run_egtest.mm b/ios/chrome/browser/ui/first_run/first_run_egtest.mm
index 6d3565d..76a7452 100644
--- a/ios/chrome/browser/ui/first_run/first_run_egtest.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_egtest.mm
@@ -47,17 +47,9 @@
 
 namespace {
 
-NSString* const kMetricsConsentCheckboxAccessibilityIdentifier =
-    @"kMetricsConsentCheckboxAccessibilityIdentifier";
-
 NSString* const kBeginBoldTag = @"BEGIN_BOLD[ \t]*";
 NSString* const kEndBoldTag = @"[ \t]*END_BOLD";
 
-// Returns a matcher for the welcome screen UMA checkbox button.
-id<GREYMatcher> GetUMACheckboxButton() {
-  return grey_accessibilityID(kMetricsConsentCheckboxAccessibilityIdentifier);
-}
-
 // Returns a matcher for the welcome screen accept button.
 id<GREYMatcher> GetAcceptButton() {
   return grey_allOf(grey_text(l10n_util::GetNSString(
@@ -259,11 +251,6 @@
       l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_SUBTITLE));
   [self scrollToElementAndAssertVisibility:subtitle];
 
-  // Validate the Metrics Consent box.
-  id<GREYMatcher> metricsConsent = grey_text(
-      l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT));
-  [self scrollToElementAndAssertVisibility:metricsConsent];
-
   // Validate the Accept box.
   [self scrollToElementAndAssertVisibility:GetAcceptButton()];
 }
@@ -304,11 +291,6 @@
       l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_MANAGED));
   [self scrollToElementAndAssertVisibility:managed];
 
-  // Validate the Metrics Consent box.
-  id<GREYMatcher> metricsConsent = grey_text(
-      l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT));
-  [self scrollToElementAndAssertVisibility:metricsConsent];
-
   // Validate the Accept box.
   [self scrollToElementAndAssertVisibility:GetAcceptButton()];
 }
@@ -996,68 +978,6 @@
   [[self class] removeAnyOpenMenusAndInfoBars];
 }
 
-// Tests that metrics collection is enabled when the checkmark is checked on
-// the Welcome screen.
-- (void)testMetricsEnabled {
-  // Verify the metrics collection pref is disabled prior to going through the
-  // Welcome screen.
-  GREYAssertFalse(
-      [FirstRunAppInterface isUMACollectionEnabled],
-      @"kMetricsReportingEnabled pref was unexpectedly true by default.");
-
-  // Verify the metrics checkbox is checked by default.
-  [[EarlGrey selectElementWithMatcher:GetUMACheckboxButton()]
-      assertWithMatcher:grey_selected()];
-
-  // Verify the metrics checkbox is checked after tapping it twice.
-  [self scrollToElementAndAssertVisibility:GetUMACheckboxButton()];
-  [[EarlGrey selectElementWithMatcher:GetUMACheckboxButton()]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:GetUMACheckboxButton()]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:GetUMACheckboxButton()]
-      assertWithMatcher:grey_selected()];
-
-  // Verify the metrics collection pref is enabled after going through the
-  // Welcome screen with the UMA checkbox checked.
-  [self scrollToElementAndAssertVisibility:GetAcceptButton()];
-  [[EarlGrey selectElementWithMatcher:GetAcceptButton()]
-      performAction:grey_tap()];
-  GREYAssertTrue([FirstRunAppInterface isUMACollectionEnabled],
-                 @"kMetricsReportingEnabled pref was unexpectedly false after "
-                 @"checking the UMA checkbox.");
-}
-
-// Tests that metrics collection is disabled when the checkmark is unchecked on
-// the Welcome screen.
-- (void)testMetricsDisabled {
-  // Verify the metrics collection pref is disabled prior to going through the
-  // Welcome screen.
-  GREYAssertFalse(
-      [FirstRunAppInterface isUMACollectionEnabled],
-      @"kMetricsReportingEnabled pref was unexpectedly true by default.");
-
-  // Verify the metrics checkbox is checked by default.
-  [[EarlGrey selectElementWithMatcher:GetUMACheckboxButton()]
-      assertWithMatcher:grey_selected()];
-
-  // Verify the metrics checkbox is unchecked after tapping it.
-  [self scrollToElementAndAssertVisibility:GetUMACheckboxButton()];
-  [[EarlGrey selectElementWithMatcher:GetUMACheckboxButton()]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:GetUMACheckboxButton()]
-      assertWithMatcher:grey_not(grey_selected())];
-
-  // Verify the metrics collection pref is disabled after going through the
-  // Welcome screen with the checkmark unchecked.
-  [self scrollToElementAndAssertVisibility:GetAcceptButton()];
-  [[EarlGrey selectElementWithMatcher:GetAcceptButton()]
-      performAction:grey_tap()];
-  GREYAssertFalse([FirstRunAppInterface isUMACollectionEnabled],
-                  @"kMetricsReportingEnabled pref was unexpectedly true after "
-                  @"leaving the UMA checkbox unchecked.");
-}
-
 // Checks that the sync screen doesn't appear when the SyncDisabled policy is
 // enabled.
 - (void)testSyncDisabled {
diff --git a/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm b/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm
index 844747e6..b1379c8 100644
--- a/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm
@@ -30,7 +30,6 @@
       [screens addObject:@(kSignIn)];
       [screens addObject:@(kTangibleSync)];
       break;
-    case NewMobileIdentityConsistencyFRE::kUMADialog:
     case NewMobileIdentityConsistencyFRE::kOld:
       [screens addObject:@(kWelcomeAndConsent)];
       [screens addObject:@(kSignInAndSync)];
diff --git a/ios/chrome/browser/ui/first_run/first_run_uma_dialog_egtest.mm b/ios/chrome/browser/ui/first_run/first_run_uma_dialog_egtest.mm
index 1039756..1e88c81c5 100644
--- a/ios/chrome/browser/ui/first_run/first_run_uma_dialog_egtest.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_uma_dialog_egtest.mm
@@ -95,19 +95,6 @@
   AppLaunchConfiguration config;
   config.additional_args.push_back(std::string("-") +
                                    test_switches::kSignInAtStartup);
-  // Enable UMA dialog MICe FRe.
-  config.additional_args.push_back(
-      "--enable-features=" +
-      std::string(signin::kNewMobileIdentityConsistencyFRE.name) + "<" +
-      std::string(signin::kNewMobileIdentityConsistencyFRE.name));
-  config.additional_args.push_back(
-      "--force-fieldtrials=" +
-      std::string(signin::kNewMobileIdentityConsistencyFRE.name) + "/Test");
-  config.additional_args.push_back(
-      "--force-fieldtrial-params=" +
-      std::string(signin::kNewMobileIdentityConsistencyFRE.name) +
-      ".Test:" + std::string(kNewMobileIdentityConsistencyFREParam) + "/" +
-      kNewMobileIdentityConsistencyFREParamUMADialog);
   // Disable default browser promo.
   config.features_disabled.push_back(kEnableFREDefaultBrowserPromoScreen);
   // Show the First Run UI at startup.
diff --git a/ios/chrome/browser/ui/first_run/fre_field_trial.cc b/ios/chrome/browser/ui/first_run/fre_field_trial.cc
index b2205a2e..fd01f8f 100644
--- a/ios/chrome/browser/ui/first_run/fre_field_trial.cc
+++ b/ios/chrome/browser/ui/first_run/fre_field_trial.cc
@@ -53,8 +53,6 @@
          kNewMobileIdentityConsistencyFREParamTangibleSyncC},
         {NewMobileIdentityConsistencyFRE::kTwoSteps,
          kNewMobileIdentityConsistencyFREParamTwoSteps},
-        {NewMobileIdentityConsistencyFRE::kUMADialog,
-         kNewMobileIdentityConsistencyFREParamUMADialog},
 };
 
 // Parameter for signin::kNewMobileIdentityConsistencyFRE feature.
diff --git a/ios/chrome/browser/ui/first_run/fre_field_trial.h b/ios/chrome/browser/ui/first_run/fre_field_trial.h
index c1a9334d..a70cfee 100644
--- a/ios/chrome/browser/ui/first_run/fre_field_trial.h
+++ b/ios/chrome/browser/ui/first_run/fre_field_trial.h
@@ -29,13 +29,11 @@
 
 // Version of the new MICE FRE to show.
 enum class NewMobileIdentityConsistencyFRE {
-  // Old FRE with UMA dialog.
-  kUMADialog = 0,
   // New MICE FRE with tangible sync (welcome with sign-in + tangible sync
   // screens).
   // Strings in TangibleSyncViewController are set according to the A, B or C
   // variants.
-  kTangibleSyncA,
+  kTangibleSyncA = 0,
   kTangibleSyncB,
   kTangibleSyncC,
   // New MICE FRE with 2 steps (welcome with sign-in + sync screens).
diff --git a/ios/chrome/browser/ui/first_run/welcome/tos_coordinator.mm b/ios/chrome/browser/ui/first_run/welcome/tos_coordinator.mm
index 57c4fde..27332a97 100644
--- a/ios/chrome/browser/ui/first_run/welcome/tos_coordinator.mm
+++ b/ios/chrome/browser/ui/first_run/welcome/tos_coordinator.mm
@@ -67,8 +67,7 @@
     case NewMobileIdentityConsistencyFRE::kTwoSteps:
     case NewMobileIdentityConsistencyFRE::kTangibleSyncA:
     case NewMobileIdentityConsistencyFRE::kTangibleSyncB:
-    case NewMobileIdentityConsistencyFRE::kTangibleSyncC:
-    case NewMobileIdentityConsistencyFRE::kUMADialog: {
+    case NewMobileIdentityConsistencyFRE::kTangibleSyncC: {
       TOSURL =
           net::NSURLWithGURL(GetUnifiedTermsOfServiceURL(/*embbeded=*/true));
       break;
diff --git a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_coordinator.mm b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_coordinator.mm
index aa53877d..dc2f82e 100644
--- a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_coordinator.mm
+++ b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_coordinator.mm
@@ -99,14 +99,8 @@
   // TODO(crbug.com/1189815): Remember that the welcome screen has been shown in
   // NSUserDefaults.
   [self.mediator acceptToS];
-  if (fre_field_trial::GetNewMobileIdentityConsistencyFRE() ==
-      NewMobileIdentityConsistencyFRE::kOld) {
-    [self.mediator
-        setMetricsReportingEnabled:self.viewController.checkBoxSelected];
-  } else {
-    [self.mediator
-        setMetricsReportingEnabled:self.mediator.UMAReportingUserChoice];
-  }
+  [self.mediator
+      setMetricsReportingEnabled:self.mediator.UMAReportingUserChoice];
   if (self.TOSLinkWasTapped) {
     base::RecordAction(base::UserMetricsAction("MobileFreTOSLinkTapped"));
   }
diff --git a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.h b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.h
index 733d3f2..4390b060 100644
--- a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.h
+++ b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.h
@@ -14,10 +14,6 @@
 // continue" button.
 @protocol WelcomeScreenViewControllerDelegate <PromoStyleViewControllerDelegate>
 
-// Returns whether the metrics reporting consent checkbox should be selected or
-// not by default.
-- (BOOL)isCheckboxSelectedByDefault;
-
 // Called when the user taps on "Manage" related to metric reporting.
 - (void)showUMADialog;
 
@@ -33,9 +29,6 @@
 
 @property(nonatomic, weak) id<WelcomeScreenViewControllerDelegate> delegate;
 
-// Whether the metrics reporting checkbox is selected.
-@property(nonatomic, readonly, assign) BOOL checkBoxSelected;
-
 // Init with the handler used to manage the display of TOS.
 - (instancetype)initWithTOSHandler:(id<TOSCommands>)TOSHandler
     NS_DESIGNATED_INITIALIZER;
diff --git a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.mm b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.mm
index 81d8e66..af8557f 100644
--- a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.mm
+++ b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.mm
@@ -39,14 +39,10 @@
 
 NSString* const kEnterpriseIconImageName = @"enterprise_icon";
 
-NSString* const kMetricsConsentCheckboxAccessibilityIdentifier =
-    @"kMetricsConsentCheckboxAccessibilityIdentifier";
-
 }  // namespace
 
 @interface WelcomeScreenViewController () <UITextViewDelegate>
 
-@property(nonatomic, strong) CheckboxButton* metricsConsentButton;
 @property(nonatomic, strong) UITextView* footerTextView;
 @property(nonatomic, weak) id<TOSCommands> TOSHandler;
 
@@ -78,13 +74,7 @@
   self.primaryActionString =
       l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_ACCEPT_BUTTON);
 
-  self.metricsConsentButton = [self createMetricsConsentButton];
-  UIView* footerView = nil;
-  BOOL showUMAReportingCheckBox =
-      fre_field_trial::GetNewMobileIdentityConsistencyFRE() ==
-      NewMobileIdentityConsistencyFRE::kOld;
-  self.footerTextView =
-      [self createFooterTextViewWithUMAReportingLink:!showUMAReportingCheckBox];
+  self.footerTextView = [self createFooterTextView];
   [self.specificContentView addSubview:self.footerTextView];
 
   [NSLayoutConstraint activateConstraints:@[
@@ -96,23 +86,6 @@
         constraintEqualToAnchor:self.specificContentView.bottomAnchor],
   ]];
 
-  if (!showUMAReportingCheckBox) {
-    footerView = self.footerTextView;
-  } else {
-    self.metricsConsentButton = [self createMetricsConsentButton];
-    [self.specificContentView addSubview:self.metricsConsentButton];
-    footerView = self.metricsConsentButton;
-    [NSLayoutConstraint activateConstraints:@[
-      [self.metricsConsentButton.centerXAnchor
-          constraintEqualToAnchor:self.specificContentView.centerXAnchor],
-      [self.metricsConsentButton.widthAnchor
-          constraintEqualToAnchor:self.specificContentView.widthAnchor],
-      [self.footerTextView.topAnchor
-          constraintEqualToAnchor:self.metricsConsentButton.bottomAnchor
-                         constant:kDefaultMargin]
-    ]];
-  }
-
   if (self.isManaged) {
     UILabel* managedLabel = [self createManagedLabel];
     UIView* managedIcon = [self createManagedIcon];
@@ -136,13 +109,13 @@
 
     // Put the footer below the header in the content area with a margin, when
     // the header is not empty.
-    [footerView.topAnchor
+    [self.footerTextView.topAnchor
         constraintGreaterThanOrEqualToAnchor:managedIcon.bottomAnchor
                                     constant:kDefaultMargin]
         .active = YES;
   } else {
     // Put the footer at the top of the content area when there is no header.
-    [footerView.topAnchor
+    [self.footerTextView.topAnchor
         constraintGreaterThanOrEqualToAnchor:self.specificContentView.topAnchor]
         .active = YES;
   }
@@ -159,12 +132,6 @@
                      NewMobileIdentityConsistencyFRE::kOld];
 }
 
-#pragma mark - Accessors
-
-- (BOOL)checkBoxSelected {
-  return self.metricsConsentButton.selected;
-}
-
 #pragma mark - Private
 
 // Configures the text for the title and subtitle based on whether the browser
@@ -231,40 +198,26 @@
   return iconContainer;
 }
 
-// Creates and configures the UMA consent checkbox button.
-- (CheckboxButton*)createMetricsConsentButton {
-  CheckboxButton* button = [[CheckboxButton alloc] initWithFrame:CGRectZero];
-  button.accessibilityIdentifier =
-      kMetricsConsentCheckboxAccessibilityIdentifier;
-  button.translatesAutoresizingMaskIntoConstraints = NO;
-  button.labelText =
-      l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRICS_CONSENT);
-  button.selected = YES;
-  [button addTarget:self
-                action:@selector(didTapMetricsButton)
-      forControlEvents:UIControlEventTouchUpInside];
-
-  button.pointerInteractionEnabled = YES;
-  button.pointerStyleProvider = CreateOpaqueButtonPointerStyleProvider();
-
-  return button;
-}
-
 // Creates and configures the text view for the terms of service, with a
 // formatted link to the full text of the terms of service.
-- (UITextView*)createFooterTextViewWithUMAReportingLink:
-    (BOOL)UMAReportingLink {
-  UIFontTextStyle fontTextStyle =
-      (UMAReportingLink) ? UIFontTextStyleCaption2 : UIFontTextStyleFootnote;
+- (UITextView*)createFooterTextView {
   NSAttributedString* termsOfServiceString =
-      [self createTermsOfServiceStringWithFontTextStyle:fontTextStyle];
-  NSMutableAttributedString* footerString = [[NSMutableAttributedString alloc]
-      initWithAttributedString:termsOfServiceString];
-  if (UMAReportingLink) {
-    NSAttributedString* manageMetricsReported =
-        [self createManageMetricsReportedString];
-    [footerString appendAttributedString:manageMetricsReported];
-  }
+      [self createFooterAttributedStringWithString:
+                l10n_util::GetNSString(
+                    IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TERMS_OF_SERVICE)
+                                        linkString:kTermsOfServiceURL];
+  NSAttributedString* endOfLine =
+      [self createFooterAttributedStringWithString:@"\n" linkString:nil];
+  NSAttributedString* manageMetricsReported =
+      [self createFooterAttributedStringWithString:
+                l10n_util::GetNSString(
+                    IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRIC_REPORTING)
+                                        linkString:kManageMetricsReportedURL];
+  NSMutableAttributedString* footerString =
+      [[NSMutableAttributedString alloc] init];
+  [footerString appendAttributedString:termsOfServiceString];
+  [footerString appendAttributedString:endOfLine];
+  [footerString appendAttributedString:manageMetricsReported];
 
   UITextView* textView = CreateUITextViewWithTextKit1();
   textView.scrollEnabled = NO;
@@ -280,26 +233,11 @@
   return textView;
 }
 
-- (NSAttributedString*)createTermsOfServiceStringWithFontTextStyle:
-    (UIFontTextStyle)fontTextStyle {
-  NSMutableParagraphStyle* paragraphStyle =
-      [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
-  paragraphStyle.alignment = NSTextAlignmentCenter;
-
-  NSDictionary* textAttributes = @{
-    NSForegroundColorAttributeName : [UIColor colorNamed:kTextSecondaryColor],
-    NSFontAttributeName : [UIFont preferredFontForTextStyle:fontTextStyle],
-    NSParagraphStyleAttributeName : paragraphStyle
-  };
-  NSDictionary* linkAttributes =
-      @{NSLinkAttributeName : [NSURL URLWithString:kTermsOfServiceURL]};
-  return AttributedStringFromStringWithLink(
-      l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TERMS_OF_SERVICE),
-      textAttributes, linkAttributes);
-}
-
-//  Returns a NSAttributedString for UMA reporting with a link.
-- (NSAttributedString*)createManageMetricsReportedString {
+// Returns a NSAttributedString using a `string` and `linkString`.
+// `linkString` should be nil, if `string` doesn't contain any link.
+- (NSAttributedString*)createFooterAttributedStringWithString:(NSString*)string
+                                                   linkString:
+                                                       (NSString*)linkString {
   NSMutableParagraphStyle* paragraphStyle =
       [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
   paragraphStyle.alignment = NSTextAlignmentCenter;
@@ -310,22 +248,16 @@
         [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2],
     NSParagraphStyleAttributeName : paragraphStyle
   };
+  if (!linkString) {
+    return [[NSAttributedString alloc] initWithString:string
+                                           attributes:textAttributes];
+  }
   NSDictionary* linkAttributes =
-      @{NSLinkAttributeName : [NSURL URLWithString:kManageMetricsReportedURL]};
-  NSMutableString* string = [[NSMutableString alloc] initWithString:@"\n"];
-  NSString* manageString =
-      l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_METRIC_REPORTING);
-  [string appendString:manageString];
+      @{NSLinkAttributeName : [NSURL URLWithString:linkString]};
   return AttributedStringFromStringWithLink(string, textAttributes,
                                             linkAttributes);
 }
 
-// Handler for when the metrics button gets tapped. Toggles the button's
-// selected state.
-- (void)didTapMetricsButton {
-  self.metricsConsentButton.selected = !self.metricsConsentButton.selected;
-}
-
 #pragma mark - UITextViewDelegate
 
 - (BOOL)textView:(UITextView*)textView
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_feature.h b/ios/chrome/browser/ui/ntp/new_tab_page_feature.h
index dd7ccab..e3988673 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_feature.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_feature.h
@@ -27,6 +27,13 @@
 // Feature flag to enable the sync promo on top of the discover feed.
 BASE_DECLARE_FEATURE(kEnableDiscoverFeedTopSyncPromo);
 
+// Feature flag to enable checking feed visibility on attention log start.
+BASE_DECLARE_FEATURE(kEnableCheckVisibilityOnAttentionLogStart);
+
+// Feature flag to enable refining data source reload reporting when having a
+// very short attention log.
+BASE_DECLARE_FEATURE(kEnableRefineDataSourceReloadReporting);
+
 // A parameter to indicate whether Reconstructed Templates is enabled for static
 // resource serving.
 extern const char kDiscoverFeedSRSReconstructedTemplatesEnabled[];
@@ -74,4 +81,11 @@
 // Whether content suggestions are enabled for supervised users.
 bool IsContentSuggestionsForSupervisedUserEnabled(PrefService* pref_service);
 
+// YES if enabled checking feed visibility on attention log start.
+bool IsCheckVisibilityOnAttentionLogStartEnabled();
+
+// YES if enabled refining data source reload reporting when having a very short
+// attention log.
+bool IsRefineDataSourceReloadReportingEnabled();
+
 #endif  // IOS_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_FEATURE_H_
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_feature.mm b/ios/chrome/browser/ui/ntp/new_tab_page_feature.mm
index 1a487934..2ed90e09 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_feature.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_feature.mm
@@ -50,6 +50,14 @@
              "FeedAblationEnabled",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kEnableCheckVisibilityOnAttentionLogStart,
+             "EnableCheckVisibilityOnAttentionLogStart",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kEnableRefineDataSourceReloadReporting,
+             "EnableRefineDataSourceReloadReporting",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 bool IsDiscoverFeedPreviewEnabled() {
   return base::FeatureList::IsEnabled(kEnableDiscoverFeedPreview);
 }
@@ -80,3 +88,12 @@
   return pref_service->GetBoolean(
       prefs::kNTPContentSuggestionsForSupervisedUserEnabled);
 }
+
+bool IsCheckVisibilityOnAttentionLogStartEnabled() {
+  return base::FeatureList::IsEnabled(
+      kEnableCheckVisibilityOnAttentionLogStart);
+}
+
+bool IsRefineDataSourceReloadReportingEnabled() {
+  return base::FeatureList::IsEnabled(kEnableRefineDataSourceReloadReporting);
+}
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/tailored_security/tailored_security_infobar_banner_overlay_mediator_unittest.mm b/ios/chrome/browser/ui/overlays/infobar_banner/tailored_security/tailored_security_infobar_banner_overlay_mediator_unittest.mm
index dac99d8..74729237 100644
--- a/ios/chrome/browser/ui/overlays/infobar_banner/tailored_security/tailored_security_infobar_banner_overlay_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/overlays/infobar_banner/tailored_security/tailored_security_infobar_banner_overlay_mediator_unittest.mm
@@ -33,7 +33,8 @@
   std::unique_ptr<TailoredSecurityServiceInfobarDelegate> passed_delegate =
       MockTailoredSecurityServiceInfobarDelegate::Create(
           /*message_state*/ TailoredSecurityServiceMessageState::
-              kConsentedAndFlowEnabled);
+              kConsentedAndFlowEnabled,
+          nullptr);
   TailoredSecurityServiceInfobarDelegate* delegate = passed_delegate.get();
   InfoBarIOS infobar(InfobarType::kInfobarTypeTailoredSecurityService,
                      std::move(passed_delegate));
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/destination_usage_history/destination_usage_history.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/destination_usage_history/destination_usage_history.mm
index 4b8cbfa..703b72c 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/destination_usage_history/destination_usage_history.mm
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/destination_usage_history/destination_usage_history.mm
@@ -40,20 +40,16 @@
 
 // The default destinations ranking, based on statistical usage of the old
 // overflow menu.
-std::vector<overflow_menu::Destination> DefaultDestinationsRanking() {
-  std::vector<overflow_menu::Destination> default_ranking = {
-      overflow_menu::Destination::Bookmarks,
-      overflow_menu::Destination::History,
-      overflow_menu::Destination::ReadingList,
-      overflow_menu::Destination::Passwords,
-      overflow_menu::Destination::Downloads,
-      overflow_menu::Destination::RecentTabs,
-      overflow_menu::Destination::SiteInfo,
-      overflow_menu::Destination::Settings,
-  };
-
-  return default_ranking;
-}
+const overflow_menu::Destination kDefaultRanking[] = {
+    overflow_menu::Destination::Bookmarks,
+    overflow_menu::Destination::History,
+    overflow_menu::Destination::ReadingList,
+    overflow_menu::Destination::Passwords,
+    overflow_menu::Destination::Downloads,
+    overflow_menu::Destination::RecentTabs,
+    overflow_menu::Destination::SiteInfo,
+    overflow_menu::Destination::Settings,
+};
 
 // The number of days since the Unix epoch; one day, in this context, runs from
 // UTC midnight to UTC midnight.
@@ -154,9 +150,10 @@
   return vec;
 }
 
-// Converts std::vector<overflow_menu::Destination> ranking into
+// Converts iterable of overflow_menu::Destination `ranking` into
 // base::Value::List ranking.
-base::Value::List List(std::vector<overflow_menu::Destination>& ranking) {
+template <typename Range>
+base::Value::List List(Range&& ranking) {
   base::Value::List list;
 
   for (overflow_menu::Destination destination : ranking) {
@@ -283,10 +280,7 @@
   const base::Value::Dict& history =
       self.prefService->GetDict(prefs::kOverflowMenuDestinationUsageHistory);
 
-  std::vector<overflow_menu::Destination> defaultRanking =
-      DefaultDestinationsRanking();
-
-  for (overflow_menu::Destination destination : defaultRanking) {
+  for (overflow_menu::Destination destination : kDefaultRanking) {
     const std::string path =
         today + "." + overflow_menu::StringNameForDestination(destination);
     update->SetByDottedPath(
@@ -339,10 +333,7 @@
                                (const base::Value::List*)previousRanking
                       numAboveFoldDestinations:(int)numAboveFoldDestinations {
   if (!previousRanking) {
-    std::vector<overflow_menu::Destination> defaultRanking =
-        DefaultDestinationsRanking();
-
-    return List(defaultRanking);
+    return List(kDefaultRanking);
   }
 
   if (numAboveFoldDestinations >= static_cast<int>(previousRanking->size()))
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination.swift b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination.swift
index a756df7..1a965fc 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination.swift
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination.swift
@@ -6,8 +6,17 @@
 
 /// Represents a destination in the overflow menu.
 @objcMembers public class OverflowMenuDestination: OverflowMenuItem {
-  // Whether the destination should show a badge.
-  public var showBadge: Bool = false
+
+  @objc public enum BadgeType: Int {
+    // Whether the destination should show a badge.
+    case blueDot
+    // Whether the destination should show a "New" badge
+    // indicating a new destination.
+    case newLabel
+    case none
+  }
+
+  public var badge: BadgeType = .none
 
   /// The uniquely-identifying name of the destination.
   public var destinationName: String = ""
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_view.swift b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_view.swift
index 1fd60597..1236ead 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_view.swift
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_destination_view.swift
@@ -130,6 +130,21 @@
     )
   }
 
+  var newBadgeOffsetX: CGFloat {
+    return Dimensions.iconWidth - (Dimensions.badgeWidth - 2)
+  }
+
+  var newBadgeOffsetY: CGFloat {
+    return -Dimensions.iconWidth + (Dimensions.badgeWidth - 2)
+  }
+
+  var newLabelString: String {
+    if let newString = L10NUtils.string(forMessageId: IDS_IOS_TOOLS_MENU_CELL_NEW_FEATURE_BADGE) {
+      return String(newString.prefix(1))
+    }
+    return ""
+  }
+
   /// Build the image to be displayed, based on the configuration of the item.
   /// TODO(crbug.com/1315544): Remove this once only the symbols are present.
   @ViewBuilder
@@ -139,7 +154,7 @@
     let configuredImage =
       image
       .overlay {
-        if destination.showBadge {
+        if destination.badge == .blueDot {
           Circle()
             .strokeBorder(
               backgroundColor(configuration: configuration), lineWidth: Dimensions.badgeBorderWidth
@@ -149,6 +164,20 @@
             .background(Circle().foregroundColor(.blue500).padding(0.5))
             .frame(width: Dimensions.badgeWidth, height: Dimensions.badgeWidth)
             .offset(x: Dimensions.iconWidth / 2, y: -Dimensions.iconWidth / 2)
+        } else if destination.badge == .newLabel {
+          Image(systemName: "seal.fill")
+            .foregroundColor(.blue600)
+            .frame(width: Dimensions.badgeWidth, height: Dimensions.badgeWidth)
+            .offset(x: newBadgeOffsetX, y: newBadgeOffsetY)
+            .overlay {
+              if !newLabelString.isEmpty {
+                Text(newLabelString)
+                  .font(.system(size: 10, weight: .bold, design: .rounded))
+                  .offset(x: newBadgeOffsetX, y: newBadgeOffsetY)
+                  .scaledToFit()
+                  .foregroundColor(.primaryBackground)
+              }
+            }
         }
       }
       .frame(width: Dimensions.imageWidth, height: Dimensions.imageWidth)
@@ -221,6 +250,10 @@
     /// The addition to the `accessibilityIdentfier` for this element if it
     /// has a badge.
     static let badgeAddition = "badge"
+
+    /// The addition to the `accessibilityIdentfier` for this element if it
+    /// has a "New" badge.
+    static let newBadgeAddition = "newBadge"
   }
 
   /// The destination for this view.
@@ -250,7 +283,7 @@
   var accessibilityLabel: String {
     return [
       destination.name,
-      destination.showBadge
+      destination.badge != .none
         ? L10NUtils.stringWithFixup(forMessageId: IDS_IOS_TOOLS_MENU_CELL_NEW_FEATURE_BADGE) : nil,
     ].compactMap { $0 }.joined(separator: ", ")
   }
@@ -258,7 +291,8 @@
   var accessibilityIdentifier: String {
     return [
       destination.accessibilityIdentifier,
-      destination.showBadge ? AccessibilityIdentifier.badgeAddition : nil,
+      destination.badge == .blueDot ? AccessibilityIdentifier.badgeAddition : nil,
+      destination.badge == .newLabel ? AccessibilityIdentifier.newBadgeAddition : nil,
     ].compactMap { $0 }.joined(separator: "-")
   }
 
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
index 0a4a6db..23ace8fb 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
@@ -12,6 +12,7 @@
 #import "base/strings/utf_string_conversions.h"
 #import "components/bookmarks/browser/bookmark_model.h"
 #import "components/bookmarks/common/bookmark_pref_names.h"
+#import "components/feature_engagement/public/event_constants.h"
 #import "components/feature_engagement/public/feature_constants.h"
 #import "components/feature_engagement/public/tracker.h"
 #import "components/language/ios/browser/ios_language_detection_tab_helper.h"
@@ -261,11 +262,16 @@
   self.webContentAreaOverlayPresenter = nullptr;
 
   if (_engagementTracker) {
-    if (self.readingListDestination.showBadge) {
+    if (self.readingListDestination.badge != BadgeTypeNone) {
       _engagementTracker->Dismissed(
           feature_engagement::kIPHBadgedReadingListFeature);
     }
 
+    if (self.whatsNewDestination.badge != BadgeTypeNone) {
+      _engagementTracker->Dismissed(
+          feature_engagement::kIPHBadgedWhatsNewFeature);
+    }
+
     _engagementTracker = nullptr;
   }
 
@@ -990,6 +996,14 @@
   // Place What's New at the top of the overflow menucarousel.
   [newDestinations addObject:self.whatsNewDestination];
   [newDestinations addObjectsFromArray:destinations];
+
+  // Set the new label badge.
+  if (self.engagementTracker &&
+      self.engagementTracker->ShouldTriggerHelpUI(
+          feature_engagement::kIPHBadgedWhatsNewFeature)) {
+    self.whatsNewDestination.badge = BadgeTypeNewLabel;
+  }
+
   return newDestinations;
 }
 
@@ -1164,10 +1178,11 @@
       IsIncognitoModeDisabled(self.browserStatePrefs);
 
   // Set badges if necessary
-  self.readingListDestination.showBadge =
-      self.engagementTracker &&
+  if (self.engagementTracker &&
       self.engagementTracker->ShouldTriggerHelpUI(
-          feature_engagement::kIPHBadgedReadingListFeature);
+          feature_engagement::kIPHBadgedReadingListFeature)) {
+    self.readingListDestination.badge = BadgeTypeBlueDot;
+  }
 }
 
 // Returns whether the page can be manually translated. If `forceMenuLogging` is
@@ -1718,6 +1733,8 @@
 // Dismisses the menu and opens What's New.
 - (void)openWhatsNew {
   SetWhatsNewOverflowMenuUsed();
+  self.engagementTracker->NotifyEvent(
+      feature_engagement::events::kViewedWhatsNew);
   [self.popupMenuCommandsHandler dismissPopupMenuAnimated:YES];
   [self.dispatcher showWhatsNew];
 }
diff --git a/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_provider_unittest.mm b/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_provider_unittest.mm
index 4426426..f3c8404 100644
--- a/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_provider_unittest.mm
+++ b/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_provider_unittest.mm
@@ -63,7 +63,7 @@
 
   void EnableFeatureVariationAlert() {
     scoped_feature_list_.InitWithFeaturesAndParameters(
-        {base::test::ScopedFeatureList::FeatureAndParams(
+        {base::test::FeatureRefAndParams(
             post_restore_signin::features::kIOSNewPostRestoreExperience,
             {{post_restore_signin::features::kIOSNewPostRestoreExperienceParam,
               "true"}})},
diff --git a/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_view_controller.mm b/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_view_controller.mm
index 3e7f348..a15f6521 100644
--- a/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/post_restore_signin/post_restore_signin_view_controller.mm
@@ -94,6 +94,9 @@
         IDS_IOS_POST_RESTORE_SIGN_IN_FULLSCREEN_NOTE_IPHONE);
   }
 
+  // This view does not have a subtitle, so a bottom margin is not needed.
+  self.subtitleBottomMargin = 0;
+
   // Set up the identity control to be centered horizontally, and at the to of
   // the specificContentView.
   [self.specificContentView addSubview:self.identityControl];
diff --git a/ios/chrome/browser/ui/settings/about_chrome_table_view_controller.mm b/ios/chrome/browser/ui/settings/about_chrome_table_view_controller.mm
index c4c14047..4c6db55 100644
--- a/ios/chrome/browser/ui/settings/about_chrome_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/about_chrome_table_view_controller.mm
@@ -16,7 +16,6 @@
 #import "components/version_info/version_info.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/snackbar_commands.h"
-#import "ios/chrome/browser/ui/first_run/fre_field_trial.h"
 #import "ios/chrome/browser/ui/settings/cells/version_item.h"
 #import "ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h"
 #import "ios/chrome/browser/ui/settings/utils/settings_utils.h"
@@ -150,18 +149,7 @@
       [self openURL:GURL(kChromeUICreditsURL)];
       break;
     case ItemTypeLinksTerms:
-      switch (fre_field_trial::GetNewMobileIdentityConsistencyFRE()) {
-        case NewMobileIdentityConsistencyFRE::kTwoSteps:
-        case NewMobileIdentityConsistencyFRE::kTangibleSyncA:
-        case NewMobileIdentityConsistencyFRE::kTangibleSyncB:
-        case NewMobileIdentityConsistencyFRE::kTangibleSyncC:
-        case NewMobileIdentityConsistencyFRE::kUMADialog:
-          [self openURL:GetUnifiedTermsOfServiceURL(false)];
-          break;
-        case NewMobileIdentityConsistencyFRE::kOld:
-          [self openURL:GURL(kChromeUITermsURL)];
-          break;
-      }
+      [self openURL:GetUnifiedTermsOfServiceURL(false)];
       break;
     case ItemTypeLinksPrivacy:
       [self openURL:GURL(l10n_util::GetStringUTF8(IDS_IOS_PRIVACY_POLICY_URL))];
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm
index bf57142..3dcb96e 100644
--- a/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm
@@ -249,6 +249,9 @@
   // Boolean containing whether `self` should be updated after dismissing
   // the Search Controller.
   BOOL _shouldUpdateAfterSearchControllerDismissed;
+  // Whether the table view is in search mode. That is, it only has the search
+  // bar potentially saved passwords and blocked sites.
+  BOOL _tableIsInSearchMode;
 }
 
 // Object handling passwords export operations.
@@ -508,7 +511,7 @@
   if (ShouldShowSettingsUI()) {
     // Save passwords switch and manage account message. Only show this section
     // when the searchController is not active.
-    if (!self.navigationItem.searchController.active) {
+    if (!_tableIsInSearchMode) {
       [model addSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch];
 
       if (_browserState->GetPrefs()->IsManagedPreference(
@@ -606,6 +609,7 @@
       forSectionWithIdentifier:[self sectionForManageAccountLinkHeader]];
 
   [self filterItems:self.searchTerm];
+  _tableIsInSearchMode = NO;
 }
 
 - (void)deleteItems:(NSArray<NSIndexPath*>*)indexPaths {
@@ -1111,7 +1115,7 @@
 
   // During searching Password Check section is hidden so cells should not be
   // reconfigured.
-  if (self.navigationItem.searchController.active) {
+  if (_tableIsInSearchMode) {
     _passwordCheckState = state;
     return;
   }
@@ -1205,7 +1209,7 @@
 }
 
 - (void)updateOnDeviceEncryptionSessionAndUpdateTableView {
-  if (!self.navigationItem.searchController.active) {
+  if (!_tableIsInSearchMode) {
     [self
         updateOnDeviceEncryptionSessionWithUpdateTableView:YES
                                           withRowAnimation:
@@ -1227,6 +1231,7 @@
   // Remove save passwords switch section, password check section and
   // on device encryption.
 
+  _tableIsInSearchMode = YES;
   [self
       performBatchTableViewUpdates:^{
         // Sections must be removed from bottom to top, otherwise it crashes
@@ -1373,6 +1378,7 @@
         [self updateOnDeviceEncryptionSessionWithUpdateTableView:YES
                                                 withRowAnimation:
                                                     UITableViewRowAnimationTop];
+        _tableIsInSearchMode = NO;
       }
                completion:nil];
 }
@@ -1791,7 +1797,7 @@
   [self presentViewController:exportConfirmation animated:YES completion:nil];
 }
 
-// Removes the given section if it exists and if isEmpty is true.
+// Removes the given section if it exists.
 - (void)clearSectionWithIdentifier:(NSInteger)sectionIdentifier
                   withRowAnimation:(UITableViewRowAnimation)animation {
   TableViewModel* model = self.tableViewModel;
diff --git a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_mediator.mm b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_mediator.mm
index 2423fe9..dcad44c 100644
--- a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_mediator.mm
+++ b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_mediator.mm
@@ -124,7 +124,7 @@
   // correct initial value for `canExportPasswords` or else the export button
   // will not behave correctly on load.
   self.exporterIsReady = self.passwordExporter.exportState == ExportState::IDLE;
-  [self savedPasswordsDidChanged:_savedPasswordsPresenter->GetSavedPasswords()];
+  [self savedPasswordsDidChange:_savedPasswordsPresenter->GetSavedPasswords()];
 
   [self.consumer setSavePasswordsEnabled:_passwordManagerEnabled.value];
 
@@ -208,7 +208,7 @@
 
 #pragma mark - SavedPasswordsPresenterObserver
 
-- (void)savedPasswordsDidChanged:
+- (void)savedPasswordsDidChange:
     (password_manager::SavedPasswordsPresenter::SavedPasswordsView)passwords {
   self.hasSavedPasswords = !passwords.empty();
   [self pushExportStateToConsumerAndUpdate];
diff --git a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
index 3c7476c..62e9b45 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
@@ -363,7 +363,7 @@
 
 #pragma mark - SavedPasswordsPresenterObserver
 
-- (void)savedPasswordsDidChanged:
+- (void)savedPasswordsDidChange:
     (password_manager::SavedPasswordsPresenter::SavedPasswordsView)passwords {
   [self providePasswordsToConsumer];
 }
diff --git a/ios/chrome/browser/ui/settings/password/saved_passwords_presenter_observer.h b/ios/chrome/browser/ui/settings/password/saved_passwords_presenter_observer.h
index 4a09bfe..17ee1967 100644
--- a/ios/chrome/browser/ui/settings/password/saved_passwords_presenter_observer.h
+++ b/ios/chrome/browser/ui/settings/password/saved_passwords_presenter_observer.h
@@ -12,7 +12,7 @@
 
 @protocol SavedPasswordsPresenterObserver
 
-- (void)savedPasswordsDidChanged:
+- (void)savedPasswordsDidChange:
     (password_manager::SavedPasswordsPresenter::SavedPasswordsView)passwords;
 
 @end
diff --git a/ios/chrome/browser/ui/settings/password/saved_passwords_presenter_observer.mm b/ios/chrome/browser/ui/settings/password/saved_passwords_presenter_observer.mm
index 1cb77f36..4538a49 100644
--- a/ios/chrome/browser/ui/settings/password/saved_passwords_presenter_observer.mm
+++ b/ios/chrome/browser/ui/settings/password/saved_passwords_presenter_observer.mm
@@ -21,5 +21,5 @@
 
 void SavedPasswordsPresenterObserverBridge::OnSavedPasswordsChanged(
     password_manager::SavedPasswordsPresenter::SavedPasswordsView passwords) {
-  [delegate_ savedPasswordsDidChanged:passwords];
+  [delegate_ savedPasswordsDidChange:passwords];
 }
diff --git a/ios/chrome/browser/ui/whats_new/BUILD.gn b/ios/chrome/browser/ui/whats_new/BUILD.gn
index 0ba60ea..a78c9ee 100644
--- a/ios/chrome/browser/ui/whats_new/BUILD.gn
+++ b/ios/chrome/browser/ui/whats_new/BUILD.gn
@@ -7,19 +7,25 @@
   sources = [
     "whats_new_coordinator.h",
     "whats_new_coordinator.mm",
+    "whats_new_detail_coordinator.h",
+    "whats_new_detail_coordinator.mm",
+    "whats_new_detail_view_action_handler.h",
     "whats_new_detail_view_controller.h",
     "whats_new_detail_view_controller.mm",
+    "whats_new_detail_view_delegate.h",
     "whats_new_mediator.h",
     "whats_new_mediator.mm",
     "whats_new_mediator_consumer.h",
-    "whats_new_primary_action_handler.h",
     "whats_new_table_view_action_handler.h",
     "whats_new_table_view_controller.h",
     "whats_new_table_view_controller.mm",
+    "whats_new_table_view_delegate.h",
   ]
   deps = [
     ":feature_flags",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser/main:public",
+    "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/default_promo:utils",
     "//ios/chrome/browser/ui/elements",
@@ -27,11 +33,14 @@
     "//ios/chrome/browser/ui/table_view:utils",
     "//ios/chrome/browser/ui/whats_new/cells",
     "//ios/chrome/browser/ui/whats_new/data_source",
+    "//ios/chrome/browser/url_loading",
+    "//ios/chrome/browser/url_loading:url_loading",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/elements",
     "//ios/chrome/common/ui/util",
     "//ui/base",
     "//ui/strings",
+    "//url",
   ]
   frameworks = [ "UIKit.framework" ]
 }
diff --git a/ios/chrome/browser/ui/whats_new/cells/whats_new_table_view_banner_item.mm b/ios/chrome/browser/ui/whats_new/cells/whats_new_table_view_banner_item.mm
index c42e4d1..5a9c135f 100644
--- a/ios/chrome/browser/ui/whats_new/cells/whats_new_table_view_banner_item.mm
+++ b/ios/chrome/browser/ui/whats_new/cells/whats_new_table_view_banner_item.mm
@@ -20,7 +20,7 @@
 // The size of the leading margin between content view and the text labels.
 const CGFloat kItemLeadingMargin = 16.0;
 // The height of the image.
-const CGFloat kImageViewHeight = 200.0;
+const CGFloat kImageViewHeight = 220.0;
 // The size of the space between each items in the stack view.
 const CGFloat kStackViewVerticalSpacings = 10.0;
 
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_coordinator.h b/ios/chrome/browser/ui/whats_new/whats_new_coordinator.h
index 3442e2e..eea14c6 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_coordinator.h
+++ b/ios/chrome/browser/ui/whats_new/whats_new_coordinator.h
@@ -6,8 +6,9 @@
 #define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_COORDINATOR_H_
 
 #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_table_view_delegate.h"
 
-@interface WhatsNewCoordinator : ChromeCoordinator
+@interface WhatsNewCoordinator : ChromeCoordinator <WhatsNewTableViewDelegate>
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_COORDINATOR_H_
\ No newline at end of file
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_coordinator.mm b/ios/chrome/browser/ui/whats_new/whats_new_coordinator.mm
index ba013f42..93f238b9 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_coordinator.mm
+++ b/ios/chrome/browser/ui/whats_new/whats_new_coordinator.mm
@@ -4,9 +4,16 @@
 
 #import "ios/chrome/browser/ui/whats_new/whats_new_coordinator.h"
 
+#import "base/check_op.h"
+#import "base/mac/foundation_util.h"
+#import "ios/chrome/browser/ui/commands/browser_coordinator_commands.h"
+#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_coordinator.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.h"
 #import "ios/chrome/browser/ui/whats_new/whats_new_mediator.h"
 #import "ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.h"
+#import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -28,6 +35,9 @@
     TableViewNavigationController* navigationController;
 // The view controller used to display the What's New features and chrome tips.
 @property(nonatomic, strong) WhatsNewTableViewController* tableViewController;
+// The coordinator used for What's New feature.
+@property(nonatomic, strong)
+    WhatsNewDetailCoordinator* whatsNewDetailCoordinator;
 
 @end
 
@@ -37,11 +47,14 @@
 
 - (void)start {
   self.mediator = [[WhatsNewMediator alloc] init];
+  self.mediator.urlLoadingAgent =
+      UrlLoadingBrowserAgent::FromBrowser(self.browser);
   self.tableViewController = [[WhatsNewTableViewController alloc] init];
   self.tableViewController.navigationItem.rightBarButtonItem =
       [self dismissButton];
 
-  self.tableViewController.delegate = self.mediator;
+  self.tableViewController.delegate = self;
+  self.tableViewController.actionHandler = self.mediator;
   self.mediator.consumer = self.tableViewController;
 
   [self.tableViewController reloadData];
@@ -56,10 +69,35 @@
 }
 
 - (void)stop {
+  if (self.whatsNewDetailCoordinator) {
+    [self.whatsNewDetailCoordinator stop];
+    self.whatsNewDetailCoordinator = nil;
+  }
   self.mediator = nil;
+  [self.navigationController.presentingViewController
+      dismissViewControllerAnimated:YES
+                         completion:nil];
+  self.tableViewController = nil;
+  self.navigationController = nil;
+
   [super stop];
 }
 
+#pragma mark - WhatsNewTableViewDelegate
+
+- (void)detailViewController:
+            (WhatsNewTableViewController*)whatsNewTableviewController
+    openDetailViewControllerForItem:(WhatsNewItem*)item {
+  DCHECK_EQ(self.tableViewController, whatsNewTableviewController);
+
+  self.whatsNewDetailCoordinator = [[WhatsNewDetailCoordinator alloc]
+      initWithBaseNavigationController:self.navigationController
+                               browser:self.browser
+                                  item:item
+                         actionHandler:self.mediator];
+  [self.whatsNewDetailCoordinator start];
+}
+
 #pragma mark Private
 
 - (UIBarButtonItem*)dismissButton {
@@ -72,13 +110,15 @@
 }
 
 - (void)dismissButtonTapped {
-  [self.navigationController.presentingViewController
-      dismissViewControllerAnimated:YES
-                         completion:nil];
-  self.tableViewController = nil;
-  self.navigationController = nil;
+  [self dismiss];
+}
 
-  [self stop];
+- (void)dismiss {
+  id<BrowserCoordinatorCommands> handler = HandlerForProtocol(
+      self.browser->GetCommandDispatcher(), BrowserCoordinatorCommands);
+  DCHECK(handler);
+
+  [handler dismissWhatsNew];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_detail_coordinator.h b/ios/chrome/browser/ui/whats_new/whats_new_detail_coordinator.h
new file mode 100644
index 0000000..d4ad6d6
--- /dev/null
+++ b/ios/chrome/browser/ui/whats_new/whats_new_detail_coordinator.h
@@ -0,0 +1,34 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_DETAIL_COORDINATOR_H_
+#define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_DETAIL_COORDINATOR_H_
+
+#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_view_delegate.h"
+
+@protocol WhatsNewDetailViewActionHandler;
+
+@class WhatsNewItem;
+
+@interface WhatsNewDetailCoordinator
+    : ChromeCoordinator <WhatsNewDetailViewDelegate>
+
+// `navigationController`: Handles user movement to check subpages.
+// `browser`: browser state for preferences and password check.
+- (instancetype)initWithBaseNavigationController:
+                    (UINavigationController*)navigationController
+                                         browser:(Browser*)browser
+                                            item:(WhatsNewItem*)item
+                                   actionHandler:
+                                       (id<WhatsNewDetailViewActionHandler>)
+                                           actionHandler
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithBaseViewController:(UIViewController*)viewController
+                                   browser:(Browser*)browser NS_UNAVAILABLE;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_DETAIL_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_detail_coordinator.mm b/ios/chrome/browser/ui/whats_new/whats_new_detail_coordinator.mm
new file mode 100644
index 0000000..cd856651
--- /dev/null
+++ b/ios/chrome/browser/ui/whats_new/whats_new_detail_coordinator.mm
@@ -0,0 +1,86 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_coordinator.h"
+
+#import "base/check_op.h"
+#import "base/mac/foundation_util.h"
+#import "ios/chrome/browser/main/browser.h"
+#import "ios/chrome/browser/ui/commands/browser_coordinator_commands.h"
+#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_view_action_handler.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_view_delegate.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface WhatsNewDetailCoordinator ()
+
+// The view controller used to display the What's New features and chrome tips.
+@property(nonatomic, strong) WhatsNewDetailViewController* viewController;
+
+@end
+
+@implementation WhatsNewDetailCoordinator
+
+@synthesize baseNavigationController = _baseNavigationController;
+@synthesize browser = _browser;
+
+- (instancetype)initWithBaseNavigationController:
+                    (UINavigationController*)navigationController
+                                         browser:(Browser*)browser
+                                            item:(WhatsNewItem*)item
+                                   actionHandler:
+                                       (id<WhatsNewDetailViewActionHandler>)
+                                           actionHandler {
+  self = [super initWithBaseViewController:navigationController
+                                   browser:browser];
+  if (self) {
+    _browser = browser;
+    _baseNavigationController = navigationController;
+    self.viewController = [[WhatsNewDetailViewController alloc]
+            initWithParams:item.bannerImage
+                     title:item.title
+                  subtitle:item.subtitle
+        primaryActionTitle:item.primaryActionTitle
+          instructionSteps:item.instructionSteps
+          hasPrimaryAction:item.hasPrimaryAction
+                      type:item.type
+              learnMoreURL:item.learnMoreURL];
+    self.viewController.actionHandler = actionHandler;
+    self.viewController.delegate = self;
+  }
+  return self;
+}
+
+#pragma mark - ChromeCoordinator
+
+- (void)start {
+  [self.baseNavigationController pushViewController:self.viewController
+                                           animated:YES];
+  [super start];
+}
+
+- (void)stop {
+  [self.baseNavigationController popToViewController:self.viewController
+                                            animated:NO];
+  [super stop];
+}
+
+#pragma mark - WhatsNewDetailViewDelegate
+
+- (void)dismissWhatsNewDetailView:
+    (WhatsNewDetailViewController*)whatsNewDetailViewController {
+  DCHECK_EQ(self.viewController, whatsNewDetailViewController);
+
+  id<BrowserCoordinatorCommands> handler = HandlerForProtocol(
+      self.browser->GetCommandDispatcher(), BrowserCoordinatorCommands);
+  DCHECK(handler);
+
+  [handler dismissWhatsNew];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_detail_view_action_handler.h b/ios/chrome/browser/ui/whats_new/whats_new_detail_view_action_handler.h
new file mode 100644
index 0000000..18bd091
--- /dev/null
+++ b/ios/chrome/browser/ui/whats_new/whats_new_detail_view_action_handler.h
@@ -0,0 +1,26 @@
+// Copyright 2022 The Chromium Authors
+// 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_WHATS_NEW_WHATS_NEW_DETAIL_VIEW_ACTION_HANDLER_H_
+#define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_DETAIL_VIEW_ACTION_HANDLER_H_
+
+#include "ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h"
+
+class GURL;
+
+// Delegate protocol to handle communication from the detail view to the
+// mediator.
+@protocol WhatsNewDetailViewActionHandler
+
+// Invoked when a user interacts with the primary button for a specific
+// `WhatsNewEntryId`.
+- (void)didTapActionButton:(WhatsNewType)type;
+
+// Invoked when a user interacts with the learn more button for a specific
+// `WhatsNewEntryId`, which will open a new tab with the learn more url loaded.
+- (void)didTapLearnMoreButton:(const GURL&)learnMoreURL;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_DETAIL_VIEW_ACTION_HANDLER_H_
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.h b/ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.h
index b9764330..ed4894d0 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.h
+++ b/ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.h
@@ -6,6 +6,12 @@
 #define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_DETAIL_VIEW_CONTROLLER_H_
 
 #import <UIKit/UIKit.h>
+#import "ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h"
+
+@protocol WhatsNewDetailViewDelegate;
+@protocol WhatsNewDetailViewActionHandler;
+
+class GURL;
 
 // A base view controller for showing a What's New feature or chrome tip in
 // detail.
@@ -18,7 +24,10 @@
                       subtitle:(NSString*)subtitle
             primaryActionTitle:(NSString*)primaryAction
               instructionSteps:(NSArray<NSString*>*)instructionSteps
-              hasPrimaryAction:(BOOL)hasPrimaryAction NS_DESIGNATED_INITIALIZER;
+              hasPrimaryAction:(BOOL)hasPrimaryAction
+                          type:(WhatsNewType)type
+                  learnMoreURL:(const GURL&)learnMoreURL
+    NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithNibName:(NSString*)nibNameOrNil
                          bundle:(NSBundle*)nibBundleOrNil NS_UNAVAILABLE;
@@ -26,6 +35,12 @@
 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
+// The delegate object that manages interactions with the primary action.
+@property(nonatomic, weak) id<WhatsNewDetailViewActionHandler> actionHandler;
+
+// The delegate object to the main coordinator (`WhatsNewCoordinator`).
+@property(nonatomic, weak) id<WhatsNewDetailViewDelegate> delegate;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_DETAIL_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.mm b/ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.mm
index fa8111ee6..96ede8d 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.mm
+++ b/ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.mm
@@ -6,12 +6,15 @@
 
 #import "ios/chrome/browser/ui/elements/instruction_view.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_view_action_handler.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_view_delegate.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/elements/highlight_button.h"
 #import "ios/chrome/common/ui/util/button_util.h"
 #import "ios/chrome/common/ui/util/pointer_interaction_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util.h"
+#import "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -57,6 +60,8 @@
 @property(nonatomic, copy) NSString* primaryActionString;
 @property(nonatomic, copy) NSArray<NSString*>* instructionSteps;
 @property(nonatomic, assign) BOOL hasPrimaryAction;
+@property(nonatomic, assign) WhatsNewType type;
+@property(nonatomic, assign) GURL learnMoreURL;
 
 // The navigation bar at the top of the view.
 @property(nonatomic, strong) UINavigationBar* navigationBar;
@@ -70,7 +75,9 @@
                       subtitle:(NSString*)subtitle
             primaryActionTitle:(NSString*)primaryAction
               instructionSteps:(NSArray<NSString*>*)instructionSteps
-              hasPrimaryAction:(BOOL)hasPrimaryAction {
+              hasPrimaryAction:(BOOL)hasPrimaryAction
+                          type:(WhatsNewType)type
+                  learnMoreURL:(const GURL&)learnMoreURL {
   self = [super initWithNibName:nil bundle:nil];
   if (self) {
     _bannerImage = image;
@@ -79,6 +86,8 @@
     _primaryActionString = primaryAction;
     _instructionSteps = instructionSteps;
     _hasPrimaryAction = hasPrimaryAction;
+    _type = type;
+    _learnMoreURL = learnMoreURL;
   }
   return self;
 }
@@ -222,6 +231,7 @@
     self.navigationBar.translucent = NO;
     self.navigationBar = nil;
   }
+  self.actionHandler = nil;
   [super viewDidDisappear:animated];
 }
 
@@ -380,9 +390,13 @@
 #pragma mark - Private
 
 - (void)didTapPrimaryActionButton {
+  [self.actionHandler didTapActionButton:self.type];
+  [self.delegate dismissWhatsNewDetailView:self];
 }
 
 - (void)didTaplearnMoreActionButton {
+  [self.actionHandler didTapLearnMoreButton:_learnMoreURL];
+  [self.delegate dismissWhatsNewDetailView:self];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_detail_view_delegate.h b/ios/chrome/browser/ui/whats_new/whats_new_detail_view_delegate.h
new file mode 100644
index 0000000..91dd3b3
--- /dev/null
+++ b/ios/chrome/browser/ui/whats_new/whats_new_detail_view_delegate.h
@@ -0,0 +1,20 @@
+// Copyright 2022 The Chromium Authors
+// 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_WHATS_NEW_WHATS_NEW_DETAIL_VIEW_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_DETAIL_VIEW_DELEGATE_H_
+
+@class WhatsNewDetailViewController;
+
+// Delegate protocol to handle communication from the detail view to the
+// parent coordinator.
+@protocol WhatsNewDetailViewDelegate
+
+// Invoked to request the delegate to dismiss the detail view.
+- (void)dismissWhatsNewDetailView:
+    (WhatsNewDetailViewController*)whatsNewDetailViewController;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_DETAIL_VIEW_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_mediator.h b/ios/chrome/browser/ui/whats_new/whats_new_mediator.h
index 74b827fb..b1ad47b 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_mediator.h
+++ b/ios/chrome/browser/ui/whats_new/whats_new_mediator.h
@@ -5,20 +5,24 @@
 #ifndef IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_MEDIATOR_H_
 #define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_MEDIATOR_H_
 
-#import "ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h"
-#import "ios/chrome/browser/ui/whats_new/whats_new_mediator_consumer.h"
-#import "ios/chrome/browser/ui/whats_new/whats_new_primary_action_handler.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_detail_view_action_handler.h"
 #import "ios/chrome/browser/ui/whats_new/whats_new_table_view_action_handler.h"
 
+@protocol WhatsNewMediatorConsumer;
+
+class UrlLoadingBrowserAgent;
+
 // Mediator between the Model and the UI.
 // What's New mediator between `WhatsNewModel` and the view layers
 // `WhatsNewTableViewController` and `WhatsNewDetailViewController`.
 @interface WhatsNewMediator
-    : NSObject <WhatsNewPrimaryActionHandler, WhatsNewTableViewActionHandler>
+    : NSObject <WhatsNewDetailViewActionHandler, WhatsNewTableViewActionHandler>
 
 // The delegate object that manages interactions with What's New table view.
 @property(nonatomic, weak) id<WhatsNewMediatorConsumer> consumer;
 
+@property(nonatomic, assign) UrlLoadingBrowserAgent* urlLoadingAgent;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_mediator.mm b/ios/chrome/browser/ui/whats_new/whats_new_mediator.mm
index 7f4a8f4..2f6078c 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_mediator.mm
+++ b/ios/chrome/browser/ui/whats_new/whats_new_mediator.mm
@@ -10,6 +10,9 @@
 #import "ios/chrome/browser/ui/whats_new/data_source/whats_new_data_source.h"
 #import "ios/chrome/browser/ui/whats_new/feature_flags.h"
 #import "ios/chrome/browser/ui/whats_new/whats_new_mediator_consumer.h"
+#import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
+#import "ios/chrome/browser/url_loading/url_loading_params.h"
+#import "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -62,14 +65,10 @@
   return self;
 }
 
-#pragma mark - WhatsNewPrimaryActionHandler
+#pragma mark - WhatsNewDetailViewActionHandler
 
-- (void)didTapActionButton:(WhatsNewItem*)item {
-  if (!item.hasPrimaryAction) {
-    return;
-  }
-
-  switch (item.type) {
+- (void)didTapActionButton:(WhatsNewType)type {
+  switch (type) {
     case WhatsNewType::kAddPasswordManually:
     case WhatsNewType::kUseChromeByDefault:
     case WhatsNewType::kPasswordsInOtherApps:
@@ -81,6 +80,12 @@
   };
 }
 
+- (void)didTapLearnMoreButton:(const GURL&)learnMoreURL {
+  UrlLoadParams params = UrlLoadParams::InNewTab(learnMoreURL);
+  params.web_params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
+  self.urlLoadingAgent->Load(params);
+}
+
 #pragma mark - WhatsNewTableViewActionHandler
 
 - (void)recordWhatsNewInteraction:(WhatsNewItem*)item {
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_mediator_consumer.h b/ios/chrome/browser/ui/whats_new/whats_new_mediator_consumer.h
index f47ad60..bee6b1f 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_mediator_consumer.h
+++ b/ios/chrome/browser/ui/whats_new/whats_new_mediator_consumer.h
@@ -5,9 +5,9 @@
 #ifndef IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_MEDIATOR_CONSUMER_H_
 #define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_MEDIATOR_CONSUMER_H_
 
-#import "ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h"
+@class WhatsNewItem;
 
-// Handles `WhatsNewTableViewController` updates.
+// Handles updates from the mediator to the UI.
 @protocol WhatsNewMediatorConsumer <NSObject>
 
 // Sets the highlighted What's New feature item, the array of other What's New
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_primary_action_handler.h b/ios/chrome/browser/ui/whats_new/whats_new_primary_action_handler.h
deleted file mode 100644
index a0cd796..0000000
--- a/ios/chrome/browser/ui/whats_new/whats_new_primary_action_handler.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// 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_WHATS_NEW_WHATS_NEW_PRIMARY_ACTION_HANDLER_H_
-#define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_PRIMARY_ACTION_HANDLER_H_
-
-#include "ios/chrome/browser/ui/whats_new/data_source/whats_new_data_source.h"
-
-// Delegate protocol for `WhatsNewDetailViewController`
-// to communicate with `WhatsNewMediator`.
-@protocol WhatsNewPrimaryActionHandler
-
-// Invoked when a user interacts with the primary button for a specific
-// `WhatsNewEntryId`.
-- (void)didTapActionButton:(WhatsNewItem*)item;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_PRIMARY_ACTION_HANDLER_H_
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_table_view_action_handler.h b/ios/chrome/browser/ui/whats_new/whats_new_table_view_action_handler.h
index 086a4d5..1921f791 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_table_view_action_handler.h
+++ b/ios/chrome/browser/ui/whats_new/whats_new_table_view_action_handler.h
@@ -5,14 +5,14 @@
 #ifndef IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_TABLE_VIEW_ACTION_HANDLER_H_
 #define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_TABLE_VIEW_ACTION_HANDLER_H_
 
-#include "ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h"
+@class WhatsNewItem;
 
-// Delegate protocol for `WhatsNewTableViewController`
-// to communicate with `WhatsNewMediator`.
+// Delegate protocol to handle communication from the table view to the
+// mediator.
 @protocol WhatsNewTableViewActionHandler
 
 // Invoked when a user interacts with a cell item (`WhatsNewItem`) in What's
-// New.
+// New to record user actions.
 - (void)recordWhatsNewInteraction:(WhatsNewItem*)item;
 
 @end
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.h b/ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.h
index 47a8d7e3..d1fb4aa0 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.h
+++ b/ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.h
@@ -6,9 +6,10 @@
 #define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_TABLE_VIEW_CONTROLLER_H_
 
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
-#import "ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h"
 #import "ios/chrome/browser/ui/whats_new/whats_new_mediator_consumer.h"
-#import "ios/chrome/browser/ui/whats_new/whats_new_table_view_action_handler.h"
+
+@protocol WhatsNewTableViewDelegate;
+@protocol WhatsNewTableViewActionHandler;
 
 // View controller that displays What's New features and chrome tips in a table
 // view.
@@ -20,9 +21,12 @@
 - (instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE;
 
 // The delegate object that manages interactions with What's New table view.
-@property(nonatomic, weak) id<WhatsNewTableViewActionHandler> delegate;
+@property(nonatomic, weak) id<WhatsNewTableViewActionHandler> actionHandler;
+
+// The delegate object to the parent coordinator (`WhatsNewCoordinator`).
+@property(nonatomic, weak) id<WhatsNewTableViewDelegate> delegate;
 
 - (void)reloadData;
 
 @end
-#endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_TABLE_VIEW_CONTROLLER_H_
\ No newline at end of file
+#endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_TABLE_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.mm b/ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.mm
index 4e4d00b..d05e04b8 100644
--- a/ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.mm
+++ b/ios/chrome/browser/ui/whats_new/whats_new_table_view_controller.mm
@@ -12,6 +12,8 @@
 #import "ios/chrome/browser/ui/whats_new/cells/whats_new_table_view_item.h"
 #import "ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h"
 #import "ios/chrome/browser/ui/whats_new/whats_new_detail_view_controller.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_table_view_action_handler.h"
+#import "ios/chrome/browser/ui/whats_new/whats_new_table_view_delegate.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util.h"
@@ -100,7 +102,7 @@
   self.tableView.sectionFooterHeight = kEstimatedsectionFooterHeight;
 }
 
-#pragma mark - UITableViewDelegate
+#pragma mark - UITableViewactionHandler
 
 - (UITableViewCell*)tableView:(UITableView*)tableView
         cellForRowAtIndexPath:(NSIndexPath*)indexPath {
@@ -136,8 +138,10 @@
       [self.tableViewModel sectionIdentifierForSectionIndex:indexPath.section];
   switch (sectionID) {
     case SectionFeatureBannerIdentifier: {
-      [self.delegate recordWhatsNewInteraction:self.highlightedFeatureItem];
-      [self openWhatsNewDetailView:self.highlightedFeatureItem];
+      [self.actionHandler
+          recordWhatsNewInteraction:self.highlightedFeatureItem];
+      [self.delegate detailViewController:self
+          openDetailViewControllerForItem:self.highlightedFeatureItem];
       break;
     }
     case SectionFeaturesIdentifier: {
@@ -145,13 +149,15 @@
       if (self.isModuleTableView) {
         index--;
       }
-      [self.delegate recordWhatsNewInteraction:self.featureItems[index]];
-      [self openWhatsNewDetailView:self.featureItems[index]];
+      [self.actionHandler recordWhatsNewInteraction:self.featureItems[index]];
+      [self.delegate detailViewController:self
+          openDetailViewControllerForItem:self.featureItems[index]];
       break;
     }
     case SectionChromeTipIdenfitier: {
-      [self.delegate recordWhatsNewInteraction:self.chromeTipItem];
-      [self openWhatsNewDetailView:self.chromeTipItem];
+      [self.actionHandler recordWhatsNewInteraction:self.chromeTipItem];
+      [self.delegate detailViewController:self
+          openDetailViewControllerForItem:self.chromeTipItem];
       break;
     }
   }
@@ -295,16 +301,4 @@
   return header;
 }
 
-- (void)openWhatsNewDetailView:(WhatsNewItem*)item {
-  WhatsNewDetailViewController* detailView =
-      [[WhatsNewDetailViewController alloc]
-              initWithParams:item.bannerImage
-                       title:item.title
-                    subtitle:item.subtitle
-          primaryActionTitle:item.primaryActionTitle
-            instructionSteps:item.instructionSteps
-            hasPrimaryAction:item.hasPrimaryAction];
-  [self.navigationController pushViewController:detailView animated:YES];
-}
-
 @end
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_table_view_delegate.h b/ios/chrome/browser/ui/whats_new/whats_new_table_view_delegate.h
new file mode 100644
index 0000000..7841044
--- /dev/null
+++ b/ios/chrome/browser/ui/whats_new/whats_new_table_view_delegate.h
@@ -0,0 +1,23 @@
+// Copyright 2022 The Chromium Authors
+// 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_WHATS_NEW_WHATS_NEW_TABLE_VIEW_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_TABLE_VIEW_DELEGATE_H_
+
+@class WhatsNewItem;
+@class WhatsNewTableViewController;
+
+// Delegate protocol to handle communication from the table view to the
+// parent coordinator.
+@protocol WhatsNewTableViewDelegate
+
+// Invoked when a user interacts with a cell item to create the
+// detail view from the main coordinator.
+- (void)detailViewController:
+            (WhatsNewTableViewController*)whatsNewTableviewController
+    openDetailViewControllerForItem:(WhatsNewItem*)item;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_WHATS_NEW_WHATS_NEW_TABLE_VIEW_DELEGATE_H_
diff --git a/ios/chrome/browser/variations/BUILD.gn b/ios/chrome/browser/variations/BUILD.gn
index 607250d..a025b1de 100644
--- a/ios/chrome/browser/variations/BUILD.gn
+++ b/ios/chrome/browser/variations/BUILD.gn
@@ -127,3 +127,19 @@
   ]
   frameworks = [ "UIKit.framework" ]
 }
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [ "ios_chrome_first_run_variations_seed_manager_unittest.mm" ]
+  deps = [
+    ":first_run",
+    "//base",
+    "//base/test:test_support",
+    "//components/variations",
+    "//components/version_info:version_info",
+    "//net",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
diff --git a/ios/chrome/browser/variations/ios_chrome_first_run_variations_seed_manager.mm b/ios/chrome/browser/variations/ios_chrome_first_run_variations_seed_manager.mm
index 1db0ecb..744e1b9 100644
--- a/ios/chrome/browser/variations/ios_chrome_first_run_variations_seed_manager.mm
+++ b/ios/chrome/browser/variations/ios_chrome_first_run_variations_seed_manager.mm
@@ -72,7 +72,7 @@
 #endif
     _variationsDomain = variations::kDefaultServerUrl;
     _forcedChannel = std::string();
-    [self applySwitchesFromCommandLine];
+    [self applySwitchesFromArguments:[[NSProcessInfo processInfo] arguments]];
   }
   return self;
 }
@@ -129,8 +129,7 @@
 #pragma mark - Private
 
 // Parse custom values from the command line and apply them to the seed manager.
-- (void)applySwitchesFromCommandLine {
-  NSArray<NSString*>* arguments = [[NSProcessInfo processInfo] arguments];
+- (void)applySwitchesFromArguments:(NSArray<NSString*>*)arguments {
   std::string url_switch =
       "--" + std::string(variations::switches::kVariationsServerURL) + "=";
   std::string channel_switch =
@@ -152,7 +151,7 @@
 // Helper method for `startSeedFetch` that initiates an HTTPS request to the
 // Finch server in the static serial queue.
 - (void)startSeedFetchHelper {
-  DCHECK(g_seed_fetching_in_progress)
+  DCHECK(!g_seed_fetching_in_progress)
       << "SeedFetch started while already in progress";
 
   // Stops executing if seed fetching is disabled.
@@ -219,25 +218,29 @@
   NSString* country = [httpResponse valueForHTTPHeaderField:@"X-Country"];
 
   // Returned seed should have been gzip compressed.
-  NSArray<NSString*>* instanceManipulations = [[httpResponse
-      valueForHTTPHeaderField:@"IM"] componentsSeparatedByString:@","];
   NSCharacterSet* whitespace = [NSCharacterSet whitespaceCharacterSet];
+  NSPredicate* nonEmpty = [NSPredicate
+      predicateWithBlock:^BOOL(NSString* im, NSDictionary* bindings) {
+        return [[im stringByTrimmingCharactersInSet:whitespace] length] > 0;
+      }];
+  NSArray<NSString*>* instanceManipulations = [[[httpResponse
+      valueForHTTPHeaderField:@"IM"] componentsSeparatedByString:@","]
+      filteredArrayUsingPredicate:nonEmpty];
   // Only gzip compressed data is supported on first run seed fetching with
   // "gzip" specified in the request.
-  if ([instanceManipulations count] != 1 ||
-      ![[instanceManipulations[0] stringByTrimmingCharactersInSet:whitespace]
+  if ([instanceManipulations count] == 1 &&
+      [[instanceManipulations[0] stringByTrimmingCharactersInSet:whitespace]
           isEqualToString:@"gzip"]) {
+    IOSChromeSeedResponse* seed =
+        [[IOSChromeSeedResponse alloc] initWithSignature:signature
+                                                 country:country
+                                                    time:[NSDate now]
+                                                    data:data
+                                              compressed:YES];
+    return seed;
+  }
     [self recordSeedFetchResult];
     return nil;
-  }
-
-  IOSChromeSeedResponse* seed =
-      [[IOSChromeSeedResponse alloc] initWithSignature:signature
-                                               country:country
-                                                  time:[NSDate now]
-                                                  data:data
-                                            compressed:YES];
-  return seed;
 }
 
 // Records the seed fetch result on UMA.
@@ -266,4 +269,10 @@
   }
 }
 
+// Invoked by the testing code to reset the fetching status after each test. DO
+// NOT INVOKE IN PRODUCTION CODE.
++ (void)resetFetchingStatusForTesting {
+  g_seed_fetching_in_progress = NO;
+}
+
 @end
diff --git a/ios/chrome/browser/variations/ios_chrome_first_run_variations_seed_manager_unittest.mm b/ios/chrome/browser/variations/ios_chrome_first_run_variations_seed_manager_unittest.mm
new file mode 100644
index 0000000..55ad466
--- /dev/null
+++ b/ios/chrome/browser/variations/ios_chrome_first_run_variations_seed_manager_unittest.mm
@@ -0,0 +1,396 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/variations/ios_chrome_first_run_variations_seed_manager.h"
+
+#import "base/run_loop.h"
+#import "base/strings/sys_string_conversions.h"
+#import "base/test/ios/wait_util.h"
+#import "components/variations/variations_switches.h"
+#import "components/variations/variations_url_constants.h"
+#import "components/version_info/version_info.h"
+#import "ios/chrome/browser/variations/ios_chrome_seed_response.h"
+#import "net/http/http_status_code.h"
+#import "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#import "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#import "third_party/ocmock/gtest_support.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+using variations::kDefaultServerUrl;
+using variations::switches::kFakeVariationsChannel;
+using variations::switches::kVariationsServerURL;
+
+// Fake server url.
+const NSString* testServer = @"https://test.finch.server";
+
+// Type definition of a block that retrieves the value of an HTTP header from a
+// custom NSDictionary instead of actual NSURLHTTPRequest header.
+typedef void (^MockValueForHTTPHeaderField)(NSInvocation*);
+
+// Retrieve the block that could substitute for -[NSHTTPURLResponse
+// valueForHTTPHeaderField:].
+MockValueForHTTPHeaderField GetMockMethodWithHeader(
+    NSDictionary<NSString*, NSString*>* headers) {
+  void (^outputBlock)(NSInvocation*) = ^(NSInvocation* invocation) {
+    __weak NSString* arg;
+    [invocation getArgument:&arg atIndex:2];
+    __weak NSString* value = headers[arg];
+    [invocation setReturnValue:&value];
+  };
+  return outputBlock;
+}
+
+}  // namespace
+
+#pragma mark - Test Models
+
+// Extraction of private properties and methods in
+// IOSChromeFirstRunVariationsSeedManager to be tested.
+@interface IOSChromeFirstRunVariationsSeedManager (Testing)
+
+@property(nonatomic, readonly) NSURL* variationsUrl;
+
+@property(nonatomic, strong) NSDate* startTimeOfOngoingSeedRequest;
+
+- (void)applySwitchesFromArguments:(NSArray<NSString*>*)arguments;
+
+- (void)onSeedRequestCompletedWithData:(NSData*)data
+                              response:(NSHTTPURLResponse*)httpResponse
+                                 error:(NSError*)error;
+
+- (IOSChromeSeedResponse*)seedResponseForHTTPResponse:
+                              (NSHTTPURLResponse*)httpResponse
+                                                 data:(NSData*)data;
+
++ (void)resetFetchingStatusForTesting;
+
+@end
+
+// A test implementation of IOSChromeFirstRunVariationsSeedManager to be used by
+// test cases. This avoids writing to global variable for the downloaded seed.
+@interface TestVariationsSeedManager : IOSChromeFirstRunVariationsSeedManager {
+  // Variations seed fetched that is stored in a TestVariationsSeedManager,
+  // instead of globally.
+  IOSChromeSeedResponse* _seedResponseForTesting;
+}
+
+// Initializer with designated arguments that substitutes for command line args.
+- (instancetype)initWithCommandLineArgsForTesting:
+    (NSArray<NSString*>*)arguments;
+
+@end
+
+@implementation TestVariationsSeedManager
+
+- (instancetype)initWithCommandLineArgsForTesting:
+    (NSArray<NSString*>*)arguments {
+  self = [super init];
+  if (self) {
+    _seedResponseForTesting = nil;
+    [self applySwitchesFromArguments:arguments];
+  }
+  return self;
+}
+
+- (IOSChromeSeedResponse*)seed {
+  return _seedResponseForTesting;
+}
+
+// Overrides IOSChromeFirstRunVariationsSeedManager where the seed is stored to
+// a global variable.
+- (void)updateSharedSeed:(IOSChromeSeedResponse*)seed {
+  _seedResponseForTesting = seed;
+}
+
+@end
+
+// Tests the IOSChromeFirstRunVariationsSeedManager.
+class IOSChromeFirstRunVariationsSeedManagerTest : public PlatformTest {
+ protected:
+  void TearDown() override {
+    [IOSChromeFirstRunVariationsSeedManager resetFetchingStatusForTesting];
+    PlatformTest::TearDown();
+  }
+};
+
+#pragma mark - Tests
+
+// Tests that the variations url is correct under different inputs in the
+// command line.
+TEST_F(IOSChromeFirstRunVariationsSeedManagerTest, TestVariationsUrl) {
+  NSString* testChannel = @"fake_channel";
+  NSString* testServerArgument =
+      [NSString stringWithFormat:@"--%@=%@",
+                                 base::SysUTF8ToNSString(kVariationsServerURL),
+                                 testServer];
+  NSString* testChannelArgument = [NSString
+      stringWithFormat:@"--%@=%@",
+                       base::SysUTF8ToNSString(kFakeVariationsChannel),
+                       testChannel];
+  // No arguments; use default value.
+  TestVariationsSeedManager* managerWithDefaultArgs =
+      [[TestVariationsSeedManager alloc] initWithCommandLineArgsForTesting:@[]];
+  NSString* expectedUrlPrefix =
+      [NSString stringWithFormat:@"%@?osname=ios&milestone=",
+                                 base::SysUTF8ToNSString(kDefaultServerUrl)];
+  EXPECT_TRUE([managerWithDefaultArgs.variationsUrl.absoluteString
+      hasPrefix:expectedUrlPrefix]);
+  // Valid server url and channel arguments.
+  NSString* expectedUrl = [NSString
+      stringWithFormat:@"%@?osname=ios&milestone=%@&channel=%@", testServer,
+                       base::SysUTF8ToNSString(
+                           version_info::GetMajorVersionNumber()),
+                       testChannel];
+  TestVariationsSeedManager* managerWithValidArgs =
+      [[TestVariationsSeedManager alloc] initWithCommandLineArgsForTesting:@[
+        testServerArgument, testChannelArgument
+      ]];
+  EXPECT_NSEQ(managerWithValidArgs.variationsUrl.absoluteString, expectedUrl);
+  // Valid server url argument; no channel argument.
+  expectedUrlPrefix = [NSString stringWithFormat:@"%@?osname=ios", testServer];
+  managerWithValidArgs = [[TestVariationsSeedManager alloc]
+      initWithCommandLineArgsForTesting:@[ testServerArgument ]];
+  EXPECT_TRUE([managerWithValidArgs.variationsUrl.absoluteString
+      hasPrefix:expectedUrlPrefix]);
+  EXPECT_FALSE([managerWithValidArgs.variationsUrl.absoluteString
+      containsString:testChannel]);
+  // Valid channel argument; no server url argument.
+  expectedUrl =
+      [NSString stringWithFormat:@"%@?osname=ios&milestone=%@&channel=%@",
+                                 base::SysUTF8ToNSString(kDefaultServerUrl),
+                                 base::SysUTF8ToNSString(
+                                     version_info::GetMajorVersionNumber()),
+                                 testChannel];
+  managerWithValidArgs = [[TestVariationsSeedManager alloc]
+      initWithCommandLineArgsForTesting:@[ testChannelArgument ]];
+  EXPECT_NSEQ(managerWithValidArgs.variationsUrl.absoluteString, expectedUrl);
+}
+
+// Tests that the request to the finch server would not be made when seed
+// fetching is not enabled.
+TEST_F(IOSChromeFirstRunVariationsSeedManagerTest,
+       testThatRequestIsNotMadeWhenFetchSeedNotEnabled) {
+  // Attach mock delegate.
+  id delegate = OCMProtocolMock(
+      @protocol(IOSChromeFirstRunVariationsSeedManagerDelegate));
+  OCMExpect([delegate didFetchSeedSuccess:NO]);
+  // Start fetching seed from manager. Seed fetching is disabled by default in
+  // tests.
+  TestVariationsSeedManager* manager =
+      [[TestVariationsSeedManager alloc] initWithCommandLineArgsForTesting:@[]];
+  manager.delegate = delegate;
+  [manager startSeedFetch];
+  base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(0.05));
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that the request to the finch server would be made when seed fetching
+// is enabled.
+TEST_F(IOSChromeFirstRunVariationsSeedManagerTest,
+       testThatRequestIsMadeWhenFetchSeedEnabled) {
+  // Instantiate mocks.
+  BOOL (^requestMatcher)(NSMutableURLRequest* request) =
+      ^BOOL(NSMutableURLRequest* request) {
+        // The NSString method `hasPrefix` does not take parameter of type
+        // 'const NSString *__strong`.
+        NSString* prefix = [NSString stringWithFormat:@"%@", testServer];
+        return [request.URL.absoluteString hasPrefix:prefix] &&
+               [request.allHTTPHeaderFields[@"A-IM"] isEqualToString:@"gzip"];
+      };
+  id mockURLSession = OCMClassMock([NSURLSession class]);
+  OCMStub([mockURLSession sharedSession]).andReturn(mockURLSession);
+  OCMExpect([mockURLSession
+      dataTaskWithRequest:[OCMArg checkWithBlock:requestMatcher]
+        completionHandler:[OCMArg any]]);
+  // Start fetching seed from manager. Pass a fake value for
+  // `kVariationsServerURL` to enable testing.
+  NSString* argument =
+      [NSString stringWithFormat:@"--%@=%@",
+                                 base::SysUTF8ToNSString(kVariationsServerURL),
+                                 testServer];
+  TestVariationsSeedManager* manager = [[TestVariationsSeedManager alloc]
+      initWithCommandLineArgsForTesting:@[ argument ]];
+  [manager startSeedFetch];
+  base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(0.05));
+  EXPECT_OCMOCK_VERIFY(mockURLSession);
+}
+
+// Tests that the seed would not be created when there is a request with the
+// HTTP response, and that the delegate would be notified so.
+TEST_F(IOSChromeFirstRunVariationsSeedManagerTest, testHTTPResponseError) {
+  // Instantiate mocks and expectation.
+  id error = OCMClassMock([NSError class]);
+  id responseOk = OCMClassMock([NSHTTPURLResponse class]);
+  OCMStub([responseOk statusCode]).andReturn(net::HTTP_OK);
+  id responseError = OCMClassMock([NSHTTPURLResponse class]);
+  OCMStub([responseError statusCode]).andReturn(net::HTTP_NOT_FOUND);
+  id delegate = OCMProtocolMock(
+      @protocol(IOSChromeFirstRunVariationsSeedManagerDelegate));
+  OCMExpect([delegate didFetchSeedSuccess:NO]);
+  OCMExpect([delegate didFetchSeedSuccess:NO]);
+  // Test if onSeedRequestCompletedWithData:response:error correctly handles
+  // NSError and unexpected response code.
+  TestVariationsSeedManager* manager =
+      [[TestVariationsSeedManager alloc] initWithCommandLineArgsForTesting:@[]];
+  manager.delegate = delegate;
+  manager.startTimeOfOngoingSeedRequest = [NSDate now];
+  [manager onSeedRequestCompletedWithData:nil response:responseOk error:error];
+  base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(0.05));
+  EXPECT_EQ(manager.seed, nil);
+  EXPECT_EQ(manager.startTimeOfOngoingSeedRequest, nil);
+  manager.startTimeOfOngoingSeedRequest = [NSDate now];
+  [manager onSeedRequestCompletedWithData:nil response:responseError error:nil];
+  base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(0.05));
+  EXPECT_EQ(manager.seed, nil);
+  EXPECT_EQ(manager.startTimeOfOngoingSeedRequest, nil);
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that the seed creation would be attempted when there is a request with
+// the HTTP response, and that the delegate would be notified if it succeeds.
+TEST_F(IOSChromeFirstRunVariationsSeedManagerTest,
+       testValidHTTPResponseWithSuccessfulSeedCreation) {
+  // Setup.
+  id delegate = OCMProtocolMock(
+      @protocol(IOSChromeFirstRunVariationsSeedManagerDelegate));
+  TestVariationsSeedManager* rawManager =
+      [[TestVariationsSeedManager alloc] initWithCommandLineArgsForTesting:@[]];
+  rawManager.delegate = delegate;
+  rawManager.startTimeOfOngoingSeedRequest = [NSDate now];
+  id response = OCMClassMock([NSHTTPURLResponse class]);
+  OCMStub([response statusCode]).andReturn(net::HTTP_OK);
+  IOSChromeSeedResponse* expectedSeed =
+      [[IOSChromeSeedResponse alloc] initWithSignature:@""
+                                               country:@""
+                                                  time:[NSDate now]
+                                                  data:nil
+                                            compressed:YES];
+  // Execute test.
+  id managerWithSeed = OCMPartialMock(rawManager);
+  OCMStub([managerWithSeed seedResponseForHTTPResponse:response data:nil])
+      .andReturn(expectedSeed);
+  OCMExpect([delegate didFetchSeedSuccess:YES]);
+  [managerWithSeed onSeedRequestCompletedWithData:nil
+                                         response:response
+                                            error:nil];
+  base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(0.05));
+  EXPECT_EQ([managerWithSeed startTimeOfOngoingSeedRequest], nil);
+  EXPECT_EQ([managerWithSeed seed], expectedSeed);
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that the seed creation would be attempted when there is a request with
+// the HTTP response, and that the delegate would be notified if it fails.
+TEST_F(IOSChromeFirstRunVariationsSeedManagerTest,
+       testValidHTTPResponseWithFailingSeedCreation) {
+  // Setup.
+  id delegate = OCMProtocolMock(
+      @protocol(IOSChromeFirstRunVariationsSeedManagerDelegate));
+  TestVariationsSeedManager* rawManager =
+      [[TestVariationsSeedManager alloc] initWithCommandLineArgsForTesting:@[]];
+  rawManager.delegate = delegate;
+  rawManager.startTimeOfOngoingSeedRequest = [NSDate now];
+  id response = OCMClassMock([NSHTTPURLResponse class]);
+  OCMStub([response statusCode]).andReturn(net::HTTP_OK);
+  // Execute test.
+  id managerWithSeed = OCMPartialMock(rawManager);
+  OCMStub([managerWithSeed seedResponseForHTTPResponse:response data:nil])
+      .andDo(nil);
+  OCMExpect([delegate didFetchSeedSuccess:NO]);
+  [managerWithSeed onSeedRequestCompletedWithData:nil
+                                         response:response
+                                            error:nil];
+  base::test::ios::SpinRunLoopWithMinDelay(base::Seconds(0.05));
+  EXPECT_EQ([managerWithSeed startTimeOfOngoingSeedRequest], nil);
+  EXPECT_EQ([managerWithSeed seed], nil);
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that the seed would not be created when the instance manipulation
+// header format is wrong.
+TEST_F(IOSChromeFirstRunVariationsSeedManagerTest,
+       testInvalidInstanceManipulation) {
+  NSString* signature = [NSDate now].description;
+  NSString* country = @"US";
+  NSDictionary<NSString*, NSString*>* headersWithoutIM = @{
+    @"X-Seed-Signature" : signature,
+    @"X-Country" : country,
+  };
+  TestVariationsSeedManager* manager =
+      [[TestVariationsSeedManager alloc] initWithCommandLineArgsForTesting:@[]];
+  // No IM.
+  id responseNoIM = OCMClassMock([NSHTTPURLResponse class]);
+  OCMStub([responseNoIM valueForHTTPHeaderField:[OCMArg any]])
+      .andDo(GetMockMethodWithHeader(headersWithoutIM));
+  IOSChromeSeedResponse* seed =
+      [manager seedResponseForHTTPResponse:responseNoIM data:nil];
+  EXPECT_EQ(seed, nil);
+  // Incorrect IM.
+  NSMutableDictionary<NSString*, NSString*>* headerWithBadIM =
+      [NSMutableDictionary dictionaryWithDictionary:headersWithoutIM];
+  headerWithBadIM[@"IM"] = @"not_gzip";
+  id responseBadIM = OCMClassMock([NSHTTPURLResponse class]);
+  OCMStub([responseBadIM valueForHTTPHeaderField:[OCMArg any]])
+      .andDo(GetMockMethodWithHeader(headerWithBadIM));
+  seed = [manager seedResponseForHTTPResponse:responseBadIM data:nil];
+  EXPECT_EQ(seed, nil);
+  // More IM than expected.
+  NSMutableDictionary<NSString*, NSString*>* headerWithTwoIMs =
+      [NSMutableDictionary dictionaryWithDictionary:headersWithoutIM];
+  headerWithTwoIMs[@"IM"] = @"gzip,somethingelse";
+  id responseTwoIMs = OCMClassMock([NSHTTPURLResponse class]);
+  OCMStub([responseTwoIMs valueForHTTPHeaderField:[OCMArg any]])
+      .andDo(GetMockMethodWithHeader(headerWithTwoIMs));
+  seed = [manager seedResponseForHTTPResponse:responseTwoIMs data:nil];
+  EXPECT_EQ(seed, nil);
+}
+
+// Tests that the seed would be created with property values extracted from the
+// HTTP response with expected header format.
+TEST_F(IOSChromeFirstRunVariationsSeedManagerTest, testValidSeedResponse) {
+  NSString* signature = [NSDate now].description;
+  NSString* country = @"US";
+  NSDictionary<NSString*, NSString*>* headers = @{
+    @"X-Seed-Signature" : signature,
+    @"X-Country" : country,
+    @"IM" : @" gzip , ,"  // Test with comma and surrounding whitespaces and
+                          // make sure they are eliminated.
+  };
+  id response = OCMClassMock([NSHTTPURLResponse class]);
+  OCMStub([response valueForHTTPHeaderField:[OCMArg any]])
+      .andDo(GetMockMethodWithHeader(headers));
+  TestVariationsSeedManager* manager =
+      [[TestVariationsSeedManager alloc] initWithCommandLineArgsForTesting:@[]];
+  IOSChromeSeedResponse* seed = [manager seedResponseForHTTPResponse:response
+                                                                data:nil];
+  EXPECT_NE(seed, nil);
+  EXPECT_EQ(seed.signature, signature);
+  EXPECT_EQ(seed.country, country);
+  EXPECT_EQ(seed.data, nil);
+}
+
+// Tests that `popSeed` correctly returns the seed and deletes it from the
+// manager.
+TEST_F(IOSChromeFirstRunVariationsSeedManagerTest, testPopSeed) {
+  TestVariationsSeedManager* manager =
+      [[TestVariationsSeedManager alloc] initWithCommandLineArgsForTesting:@[]];
+  IOSChromeSeedResponse* expectedSeed =
+      [[IOSChromeSeedResponse alloc] initWithSignature:@""
+                                               country:@""
+                                                  time:[NSDate now]
+                                                  data:nil
+                                            compressed:YES];
+  [manager updateSharedSeed:expectedSeed];
+  ASSERT_EQ(manager.seed, expectedSeed);
+  IOSChromeSeedResponse* poppedSeed = [manager popSeed];
+  EXPECT_EQ(manager.seed, nil);
+  EXPECT_EQ(poppedSeed, expectedSeed);
+}
diff --git a/ios/chrome/common/ui/promo_style/promo_style_view_controller.h b/ios/chrome/common/ui/promo_style/promo_style_view_controller.h
index df8b4f9..5684c5a8 100644
--- a/ios/chrome/common/ui/promo_style/promo_style_view_controller.h
+++ b/ios/chrome/common/ui/promo_style/promo_style_view_controller.h
@@ -63,6 +63,11 @@
 // The subtitle below the title. Must be set before the view is loaded.
 @property(nonatomic, copy) NSString* subtitleText;
 
+// The margin between the subtitle and the specificContentView. In cases where
+// subtitle is blank, views may want to set this to zero to avoid adding extra
+// spacing.
+@property(nonatomic, assign) CGFloat subtitleBottomMargin;
+
 // The disclaimer that shows at the bottom of the view, above the action items.
 // The disclaimer does not move on scroll.
 @property(nonatomic, copy) NSString* disclaimerText;
diff --git a/ios/chrome/common/ui/promo_style/promo_style_view_controller.mm b/ios/chrome/common/ui/promo_style/promo_style_view_controller.mm
index fe55d14..c73a8936 100644
--- a/ios/chrome/common/ui/promo_style/promo_style_view_controller.mm
+++ b/ios/chrome/common/ui/promo_style/promo_style_view_controller.mm
@@ -105,6 +105,7 @@
   self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
   if (self) {
     _titleHorizontalMargin = kTitleHorizontalMargin;
+    _subtitleBottomMargin = kDefaultMargin;
   }
 
   return self;
@@ -252,7 +253,7 @@
     [subtitleMarginLayoutGuide.topAnchor
         constraintEqualToAnchor:self.subtitleLabel.bottomAnchor],
     [subtitleMarginLayoutGuide.heightAnchor
-        constraintEqualToConstant:kDefaultMargin],
+        constraintEqualToConstant:_subtitleBottomMargin],
     [self.specificContentView.topAnchor
         constraintEqualToAnchor:subtitleMarginLayoutGuide.bottomAnchor],
     [self.specificContentView.leadingAnchor
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index cabd927..2ebad004 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -390,6 +390,7 @@
     "//ios/chrome/browser/update_client:unit_tests",
     "//ios/chrome/browser/upgrade:unit_tests",
     "//ios/chrome/browser/url_loading:unit_tests",
+    "//ios/chrome/browser/variations:unit_tests",
     "//ios/chrome/browser/voice:unit_tests",
     "//ios/chrome/browser/web:unit_tests",
     "//ios/chrome/browser/web:unit_tests_internal",
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 3316760..cbd5ee0a 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-8f9e575561648606810a508060503d0a841dc382
\ No newline at end of file
+a3fe971fb0733e846a567add87aba4effe81ae53
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index fc98b25..3b4d393a 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-da483199a88088cd28026b595b346ab87c087fa2
\ No newline at end of file
+6483fbb724f291ee997db8c3a17d65f33edd050c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 3c2c491..c750546 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-fa65e1c3d3b76791443fee4093a1038c054d579a
\ No newline at end of file
+0df38fcb9de73a1be2b04756158e87173658f829
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 59c3a09..cb715f71 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-ada436cf15817b1ba57ce6126d4d2deaa539bae2
\ No newline at end of file
+ab2b4c851b30d539feaaa81c5f5ea44cd6526263
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 2748866..ba70ec8 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-d85a6e7c3af34ddaf89a7b72358452e1a0967f04
\ No newline at end of file
+e2e06bc716faaf5b773255ceea05a6df51bb569e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 0d92c05..3e36841 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-65bd43f04270d0bd07d7cb01b7f4199a875b6ca1
\ No newline at end of file
+4e3150fb6d2888b44b912382a61e40ad46161e05
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index 61dc3cb6..3fa957f 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-1e1219ee63990e991ee291e83138e8d9a059af91
\ No newline at end of file
+29b8cb97eb775ab021d77115376e2c1c664665d6
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 7aca710..3b4de13 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-809cb95468e7fc3075e281d1b070a57dd3990721
\ No newline at end of file
+75457c235f2251c89754087bb3ded0c82100f85f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index 98bfe57a..5eb9d91 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-65dd5ec7a281225a6d54301c7465a9a210815e6f
\ No newline at end of file
+535aee9cf5fdc02991b20d4e2bd7ba11f2bc0d98
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index da0f700..123c88d 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-1bce7af84b7f07a54260a4cc4f9432084e99127d
\ No newline at end of file
+52f4eb12bc6561895ff0d8d4faab31c29fbb5df8
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index a022f8b..5e3fd7d 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-a55b8ce7f4fa12ea13f029e954e7239867667c13
\ No newline at end of file
+d2d620f0c1adb7e1e5362ddb3ad764ec7e5d3ffe
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index d3bc735..3e3534a0 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-f429faa8a9ab57531796efe1349f34727d60c555
\ No newline at end of file
+34d3ba77cfec53cc78d50970dad20c52a299f625
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index ac4a308c..d0281e9 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-abe924b1e87cb5bd71a8c0c31326c6d261215006
\ No newline at end of file
+1eb00450bff0317a7325a53cdbb0da83926a2639
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 4875eb9..795b4458 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-5a5ab89d7981a8997b2e4c097624c5b014d35cbb
\ No newline at end of file
+12757247afceccf0e0462dfe837416603f9b2d59
\ No newline at end of file
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
index b74deff..b45cf454 100644
--- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
+++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
@@ -133,6 +133,7 @@
   bool AreServerCardsSupported() const override;
   void ExecuteCommand(int id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
+  autofill::FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
 
   // RiskDataLoader:
   void LoadRiskData(
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
index 002f13f2..19a330ca 100644
--- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
+++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
@@ -383,6 +383,13 @@
       /*is_renderer_initiated=*/false));
 }
 
+autofill::FormInteractionsFlowId
+WebViewAutofillClientIOS::GetCurrentFormInteractionsFlowId() {
+  // Currently not in use here. See `ChromeAutofillClient` for a proper
+  // implementation.
+  return {};
+}
+
 void WebViewAutofillClientIOS::LoadRiskData(
     base::OnceCallback<void(const std::string&)> callback) {
   [bridge_ loadRiskData:std::move(callback)];
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm
index bf3b770..a720385 100644
--- a/ios/web_view/internal/cwv_web_view.mm
+++ b/ios/web_view/internal/cwv_web_view.mm
@@ -183,10 +183,6 @@
                                base::CallbackListSubscription>>
       _scriptCommandCallbacks;
   CRWSessionStorage* _cachedSessionStorage;
-
-  // Stores the last NavigationContext::IsSameDocument() value from
-  // |webState:didFinishNavigation:|.
-  BOOL _lastDidFinishNavigationContextIsSameDocument;
 }
 
 // Redefine these properties as readwrite to define setters, which send KVO
@@ -490,10 +486,6 @@
   // TODO(crbug.com/898357): Remove this once crbug.com/898357 is fixed.
   [self updateVisibleSSLStatus];
 
-  // Store NavigationContext::IsSameDocument() for later use in
-  // |webState:didLoadPageWithSuccess:|.
-  _lastDidFinishNavigationContextIsSameDocument = navigation->IsSameDocument();
-
   if (navigation->HasCommitted() && !navigation->IsSameDocument() &&
       [_navigationDelegate
           respondsToSelector:@selector(webViewDidCommitNavigation:)]) {
@@ -514,18 +506,11 @@
     return;
   }
 
-  // We do not want to call -[CWVNavigationDelegate webViewDidFinishNavigation:]
-  // for same document navigations because we also exclude them for others like
-  // -[CWVNavigationDelegate webViewDidStartNavigation:] and
-  // -[CWVNavigationDelegate webViewDidCommitNavigation:].
-  // It is guaranteed that |webState:didLoadPageWithSuccess:| is only called
-  // after |webState:didFinishNavigation:|, so we will always have an up to date
-  // value to use here.
-  // TODO(crbug.com/1196799): Remove this work around once a NavigationContext
-  // is passed in to this method.
+  // TODO(crbug.com/1374071): Fragment navigations currently skip calling
+  // `webViewDidStartNavigation:` and `webViewDidCommitNavigation:`, and instead
+  // only calls `webViewDidFinishNavigation:` below. Fix this inconsistency.
   SEL selector = @selector(webViewDidFinishNavigation:);
-  if (!_lastDidFinishNavigationContextIsSameDocument &&
-      [_navigationDelegate respondsToSelector:selector]) {
+  if ([_navigationDelegate respondsToSelector:selector]) {
     [_navigationDelegate webViewDidFinishNavigation:self];
   }
 }
diff --git a/media/capture/content/screen_enumerator.h b/media/capture/content/screen_enumerator.h
index 69d7b2d..2e73dbe 100644
--- a/media/capture/content/screen_enumerator.h
+++ b/media/capture/content/screen_enumerator.h
@@ -28,7 +28,7 @@
   // |getScreenDetails| API.
   // https://w3c.github.io/window-placement/#api-window-getScreenDetails-method
   // TODO(crbug.com/1339802): Introduce matching IDs between screens returned
-  // by this function and by the window placement API to make sure the screen
+  // by this function and by the ScreenDetails API to make sure the screen
   // matching is not getting out of sync.
   virtual void EnumerateScreens(
       blink::mojom::MediaStreamType stream_type,
diff --git a/media/gpu/android/codec_image.h b/media/gpu/android/codec_image.h
index 39888744..a922660 100644
--- a/media/gpu/android/codec_image.h
+++ b/media/gpu/android/codec_image.h
@@ -79,7 +79,6 @@
                        const gfx::Point& offset,
                        const gfx::Rect& rect) override;
   void SetColorSpace(const gfx::ColorSpace& color_space) override {}
-  void Flush() override {}
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
diff --git a/media/gpu/windows/dxva_picture_buffer_win.cc b/media/gpu/windows/dxva_picture_buffer_win.cc
index 726bd6a..daf6833 100644
--- a/media/gpu/windows/dxva_picture_buffer_win.cc
+++ b/media/gpu/windows/dxva_picture_buffer_win.cc
@@ -46,7 +46,6 @@
     return false;
   }
   void SetColorSpace(const gfx::ColorSpace& color_space) override {}
-  void Flush() override {}
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override {}
diff --git a/mojo/core/ipcz_driver/driver_for_ipcz_tests.cc b/mojo/core/ipcz_driver/driver_for_ipcz_tests.cc
index 9b1fe21..4c86e38 100644
--- a/mojo/core/ipcz_driver/driver_for_ipcz_tests.cc
+++ b/mojo/core/ipcz_driver/driver_for_ipcz_tests.cc
@@ -176,9 +176,9 @@
       parent_process = base::Process(LongToHandle(parent_handle_value));
     }
 #endif  // BUILDFLAG(IS_WIN)
+    const bool is_broker = parent_process.IsValid();
     return Transport::ReleaseAsHandle(Transport::Create(
-        {.source = parent_process.IsValid() ? Transport::kBroker
-                                            : Transport::kNonBroker,
+        {.source = is_broker ? Transport::kBroker : Transport::kNonBroker,
          .destination = Transport::kBroker},
         std::move(endpoint), std::move(parent_process)));
   }
diff --git a/mojo/core/ipcz_driver/mojo_trap.cc b/mojo/core/ipcz_driver/mojo_trap.cc
index 3fa79310..33267745 100644
--- a/mojo/core/ipcz_driver/mojo_trap.cc
+++ b/mojo/core/ipcz_driver/mojo_trap.cc
@@ -444,7 +444,9 @@
     TranslateIpczToMojoEvent(trigger->signals, trigger->trigger_context,
                              trigger->data_pipe.get(), event.condition_flags,
                              *event.status, &mojo_event);
-    mojo_event.flags |= MOJO_TRAP_EVENT_FLAG_WITHIN_API_CALL;
+    if (event.condition_flags & IPCZ_TRAP_WITHIN_API_CALL) {
+      mojo_event.flags |= MOJO_TRAP_EVENT_FLAG_WITHIN_API_CALL;
+    }
   }
 
   MaybeFlushMojoEvents();
diff --git a/mojo/core/ipcz_driver/transport.cc b/mojo/core/ipcz_driver/transport.cc
index 5ff1f72..ebf2e9a1 100644
--- a/mojo/core/ipcz_driver/transport.cc
+++ b/mojo/core/ipcz_driver/transport.cc
@@ -631,8 +631,8 @@
 #if BUILDFLAG(IS_WIN)
   // On Windows, we can transmit handles only if at least one endpoint is a
   // broker, or if we have a handle to the remote process.
-  return remote_process_.IsValid() || destination_type() == kBroker ||
-         source_type() == kBroker;
+  return destination_type() == kBroker ||
+         (remote_process_.IsValid() && source_type() == kBroker);
 #else
   return true;
 #endif
diff --git a/net/BUILD.gn b/net/BUILD.gn
index e58c3ba..e12e5b6 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1257,6 +1257,8 @@
       "base/net_errors_win.cc",
       "base/network_change_notifier_win.cc",
       "base/network_change_notifier_win.h",
+      "base/network_cost_change_notifier_win.cc",
+      "base/network_cost_change_notifier_win.h",
       "base/network_interfaces_win.cc",
       "base/network_interfaces_win.h",
       "base/platform_mime_util_win.cc",
@@ -2172,6 +2174,8 @@
     "test/ssl_test_util.cc",
     "test/ssl_test_util.h",
     "test/test_certificate_data.h",
+    "test/test_connection_cost_observer.cc",
+    "test/test_connection_cost_observer.h",
     "test/test_data_directory.cc",
     "test/test_data_directory.h",
     "test/test_doh_server.cc",
@@ -2191,6 +2195,13 @@
     "url_request/url_request_test_util.h",
   ]
 
+  if (is_win) {
+    sources += [
+      "test/win/fake_network_cost_manager.cc",
+      "test/win/fake_network_cost_manager.h",
+    ]
+  }
+
   if (is_mac) {
     sources += [
       "test/keychain_test_util_mac.cc",
@@ -4401,6 +4412,7 @@
   if (is_win) {
     sources += [
       "base/network_change_notifier_win_unittest.cc",
+      "base/network_cost_change_notifier_win_unittest.cc",
       "base/network_interfaces_win_unittest.cc",
       "cert/cert_verify_proc_win_unittest.cc",
       "http/http_auth_sspi_win_unittest.cc",
diff --git a/net/base/network_change_notifier.cc b/net/base/network_change_notifier.cc
index 233bb3d..cc8d2bcb 100644
--- a/net/base/network_change_notifier.cc
+++ b/net/base/network_change_notifier.cc
@@ -248,11 +248,6 @@
   const scoped_refptr<
       base::ObserverListThreadSafe<DefaultNetworkActiveObserver>>
       default_network_active_observer_list_;
-
-  // Indicates if connection cost observer was added before
-  // network_change_notifier was initialized, if so ConnectionCostObserverAdded
-  // is invoked from constructor.
-  std::atomic_bool connection_cost_observers_added_ = false;
 };
 
 class NetworkChangeNotifier::SystemDnsConfigObserver
@@ -687,13 +682,8 @@
 void NetworkChangeNotifier::AddConnectionCostObserver(
     ConnectionCostObserver* observer) {
   DCHECK(!observer->observer_list_);
-  GetObserverList().connection_cost_observers_added_ = true;
   observer->observer_list_ = GetObserverList().connection_cost_observer_list_;
   observer->observer_list_->AddObserver(observer);
-  base::AutoLock auto_lock(NetworkChangeNotifierCreationLock());
-  if (g_network_change_notifier) {
-    g_network_change_notifier->ConnectionCostObserverAdded();
-  }
 }
 
 void NetworkChangeNotifier::AddDefaultNetworkActiveObserver(
@@ -852,9 +842,6 @@
     g_network_change_notifier = this;
 
     system_dns_config_notifier_->AddObserver(system_dns_config_observer_.get());
-    if (GetObserverList().connection_cost_observers_added_) {
-      g_network_change_notifier->ConnectionCostObserverAdded();
-    }
   }
   if (!omit_observers_in_constructor_for_testing) {
     network_change_calculator_ =
diff --git a/net/base/network_change_notifier.h b/net/base/network_change_notifier.h
index 93108a8..c79374c 100644
--- a/net/base/network_change_notifier.h
+++ b/net/base/network_change_notifier.h
@@ -670,13 +670,6 @@
   // as early as possible in the destructor to prevent races.
   void ClearGlobalPointer();
 
-  // Called whenever a new ConnectionCostObserver is added. This method is
-  // needed so that the implementation class can be notified and
-  // potentially take action when an observer gets added. Since the act of
-  // adding an observer and the observer list itself are both static, the
-  // implementation class has no direct capability to watch for changes.
-  virtual void ConnectionCostObserverAdded() {}
-
   // Listening for notifications of this type is expensive as they happen
   // frequently. For this reason, we report {de}registration to the
   // implementation class, so that it can decide to only listen to this type of
diff --git a/net/base/network_change_notifier_unittest.cc b/net/base/network_change_notifier_unittest.cc
index 3f3fbd6..89013ac4 100644
--- a/net/base/network_change_notifier_unittest.cc
+++ b/net/base/network_change_notifier_unittest.cc
@@ -8,6 +8,7 @@
 #include "build/build_config.h"
 #include "net/base/mock_network_change_notifier.h"
 #include "net/base/network_interfaces.h"
+#include "net/test/test_connection_cost_observer.h"
 #include "net/test/test_with_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -226,37 +227,17 @@
   NetworkChangeNotifier::RemoveDNSObserver(&observer);
 }
 
-class TestConnectionCostObserver
-    : public NetworkChangeNotifier::ConnectionCostObserver {
- public:
-  void OnConnectionCostChanged(
-      NetworkChangeNotifier::ConnectionCost cost) override {
-    cost_changed_inputs_.push_back(cost);
-    ++cost_changed_calls_;
-  }
-
-  int cost_changed_calls() const { return cost_changed_calls_; }
-  std::vector<NetworkChangeNotifier::ConnectionCost> cost_changed_inputs()
-      const {
-    return cost_changed_inputs_;
-  }
-
- private:
-  int cost_changed_calls_ = 0;
-  std::vector<NetworkChangeNotifier::ConnectionCost> cost_changed_inputs_;
-};
-
 TEST_F(NetworkChangeNotifierMockedTest, TriggerConnectionCostChange) {
   TestConnectionCostObserver observer;
   NetworkChangeNotifier::AddConnectionCostObserver(&observer);
 
-  ASSERT_EQ(0, observer.cost_changed_calls());
+  ASSERT_EQ(0u, observer.cost_changed_calls());
 
   NetworkChangeNotifier::NotifyObserversOfConnectionCostChangeForTests(
       NetworkChangeNotifier::CONNECTION_COST_METERED);
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(1, observer.cost_changed_calls());
+  EXPECT_EQ(1u, observer.cost_changed_calls());
   EXPECT_EQ(NetworkChangeNotifier::CONNECTION_COST_METERED,
             observer.cost_changed_inputs()[0]);
 
@@ -265,7 +246,7 @@
       NetworkChangeNotifier::CONNECTION_COST_UNMETERED);
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(1, observer.cost_changed_calls());
+  EXPECT_EQ(1u, observer.cost_changed_calls());
 }
 
 TEST_F(NetworkChangeNotifierMockedTest, ConnectionCostDefaultsToCellular) {
diff --git a/net/base/network_change_notifier_win.cc b/net/base/network_change_notifier_win.cc
index 234a662c..e12985b 100644
--- a/net/base/network_change_notifier_win.cc
+++ b/net/base/network_change_notifier_win.cc
@@ -21,7 +21,7 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "base/win/windows_version.h"
+#include "net/base/network_cost_change_notifier_win.h"
 #include "net/base/winsock_init.h"
 #include "net/base/winsock_util.h"
 
@@ -32,88 +32,8 @@
 // Time between NotifyAddrChange retries, on failure.
 const int kWatchForAddressChangeRetryIntervalMs = 500;
 
-HRESULT GetConnectionPoints(IUnknown* manager,
-                            REFIID IIDSyncInterface,
-                            IConnectionPoint** connection_point_raw) {
-  *connection_point_raw = nullptr;
-  Microsoft::WRL::ComPtr<IConnectionPointContainer> connection_point_container;
-  HRESULT hr =
-      manager->QueryInterface(IID_PPV_ARGS(&connection_point_container));
-  if (FAILED(hr))
-    return hr;
-
-  // Find the interface
-  Microsoft::WRL::ComPtr<IConnectionPoint> connection_point;
-  hr = connection_point_container->FindConnectionPoint(IIDSyncInterface,
-                                                       &connection_point);
-  if (FAILED(hr))
-    return hr;
-
-  *connection_point_raw = connection_point.Get();
-  (*connection_point_raw)->AddRef();
-
-  return hr;
-}
-
 }  // namespace
 
-// This class is used as an event sink to register for notifications from the
-// INetworkCostManagerEvents interface. In particular, we are focused on getting
-// notified when the Connection Cost changes. This is only supported on Win10+.
-class NetworkCostManagerEventSink
-    : public Microsoft::WRL::RuntimeClass<
-          Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
-          INetworkCostManagerEvents> {
- public:
-  using CostChangedCallback = base::RepeatingCallback<void()>;
-
-  NetworkCostManagerEventSink(INetworkCostManager* cost_manager,
-                              const CostChangedCallback& callback)
-      : network_cost_manager_(cost_manager), cost_changed_callback_(callback) {}
-  ~NetworkCostManagerEventSink() override = default;
-
-  // INetworkCostManagerEvents members
-  IFACEMETHODIMP CostChanged(_In_ DWORD cost,
-                             _In_opt_ NLM_SOCKADDR* /*pSockAddr*/) override {
-    cost_changed_callback_.Run();
-    return S_OK;
-  }
-
-  IFACEMETHODIMP DataPlanStatusChanged(
-      _In_opt_ NLM_SOCKADDR* /*pSockAddr*/) override {
-    return S_OK;
-  }
-
-  HRESULT RegisterForNotifications() {
-    Microsoft::WRL::ComPtr<IUnknown> unknown;
-    HRESULT hr = QueryInterface(IID_PPV_ARGS(&unknown));
-    if (hr != S_OK)
-      return hr;
-
-    hr = GetConnectionPoints(network_cost_manager_.Get(),
-                             IID_INetworkCostManagerEvents, &connection_point_);
-    if (hr != S_OK)
-      return hr;
-
-    hr = connection_point_->Advise(unknown.Get(), &cookie_);
-    return hr;
-  }
-
-  void UnRegisterForNotifications() {
-    if (connection_point_) {
-      connection_point_->Unadvise(cookie_);
-      connection_point_ = nullptr;
-      cookie_ = 0;
-    }
-  }
-
- private:
-  Microsoft::WRL::ComPtr<INetworkCostManager> network_cost_manager_;
-  Microsoft::WRL::ComPtr<IConnectionPoint> connection_point_;
-  DWORD cookie_ = 0;
-  CostChangedCallback cost_changed_callback_;
-};
-
 NetworkChangeNotifierWin::NetworkChangeNotifierWin()
     : NetworkChangeNotifier(NetworkChangeCalculatorParamsWin()),
       blocking_task_runner_(
@@ -125,6 +45,10 @@
           base::SequencedTaskRunnerHandle::Get()) {
   memset(&addr_overlapped_, 0, sizeof addr_overlapped_);
   addr_overlapped_.hEvent = WSACreateEvent();
+
+  cost_change_notifier_ = NetworkCostChangeNotifierWin::CreateInstance(
+      base::BindRepeating(&NetworkChangeNotifierWin::OnCostChanged,
+                          weak_factory_.GetWeakPtr()));
 }
 
 NetworkChangeNotifierWin::~NetworkChangeNotifierWin() {
@@ -135,11 +59,6 @@
     addr_watcher_.StopWatching();
   }
   WSACloseEvent(addr_overlapped_.hEvent);
-
-  if (network_cost_manager_event_sink_) {
-    network_cost_manager_event_sink_->UnRegisterForNotifications();
-    network_cost_manager_event_sink_ = nullptr;
-  }
 }
 
 // static
@@ -281,115 +200,23 @@
 
 NetworkChangeNotifier::ConnectionCost
 NetworkChangeNotifierWin::GetCurrentConnectionCost() {
-  InitializeConnectionCost();
-
-  // Pre-Win10 use the default logic.
-  if (base::win::GetVersion() < base::win::Version::WIN10)
+  if (last_computed_connection_cost_ ==
+      ConnectionCost::CONNECTION_COST_UNKNOWN) {
+    // Use the default logic when the Windows OS APIs do not have a cost for the
+    // current connection.
     return NetworkChangeNotifier::GetCurrentConnectionCost();
-
-  // If we don't have the event sink we aren't registered for automatic updates.
-  // In that case, we need to update the value at the time it is requested.
-  if (!network_cost_manager_event_sink_)
-    UpdateConnectionCostFromCostManager();
-
+  }
   return last_computed_connection_cost_;
 }
 
-bool NetworkChangeNotifierWin::InitializeConnectionCostOnce() {
-  // Pre-Win10 this information cannot be retrieved and cached.
-  if (base::win::GetVersion() < base::win::Version::WIN10) {
-    SetCurrentConnectionCost(CONNECTION_COST_UNKNOWN);
-    return true;
-  }
+void NetworkChangeNotifierWin::OnCostChanged(
+    NetworkChangeNotifier::ConnectionCost new_cost) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  HRESULT hr =
-      ::CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_ALL,
-                         IID_INetworkCostManager, &network_cost_manager_);
-  if (FAILED(hr)) {
-    SetCurrentConnectionCost(CONNECTION_COST_UNKNOWN);
-    return true;
-  }
-
-  UpdateConnectionCostFromCostManager();
-
-  return true;
-}
-
-void NetworkChangeNotifierWin::InitializeConnectionCost() {
-  static bool g_connection_cost_initialized = InitializeConnectionCostOnce();
-  DCHECK(g_connection_cost_initialized);
-}
-
-HRESULT NetworkChangeNotifierWin::UpdateConnectionCostFromCostManager() {
-  if (!network_cost_manager_)
-    return E_ABORT;
-
-  DWORD cost = NLM_CONNECTION_COST_UNKNOWN;
-  HRESULT hr = network_cost_manager_->GetCost(&cost, nullptr);
-  if (FAILED(hr)) {
-    SetCurrentConnectionCost(CONNECTION_COST_UNKNOWN);
-  } else {
-    SetCurrentConnectionCost(
-        ConnectionCostFromNlmCost((NLM_CONNECTION_COST)cost));
-  }
-  return hr;
-}
-
-// static
-NetworkChangeNotifier::ConnectionCost
-NetworkChangeNotifierWin::ConnectionCostFromNlmCost(NLM_CONNECTION_COST cost) {
-  if (cost == NLM_CONNECTION_COST_UNKNOWN)
-    return CONNECTION_COST_UNKNOWN;
-  else if ((cost & NLM_CONNECTION_COST_UNRESTRICTED) != 0)
-    return CONNECTION_COST_UNMETERED;
-  else
-    return CONNECTION_COST_METERED;
-}
-
-void NetworkChangeNotifierWin::SetCurrentConnectionCost(
-    ConnectionCost connection_cost) {
-  last_computed_connection_cost_ = connection_cost;
-}
-
-void NetworkChangeNotifierWin::OnCostChanged() {
-  ConnectionCost old_cost = last_computed_connection_cost_;
-  // It is possible to get multiple notifications in a short period of time.
-  // Rather than worrying about whether this notification represents the latest,
-  // just get the current value from the CostManager so we know that we're
-  // actually getting the correct value.
-  UpdateConnectionCostFromCostManager();
   // Only notify if there's actually a change.
-  if (old_cost != GetCurrentConnectionCost())
+  if (last_computed_connection_cost_ != new_cost) {
+    last_computed_connection_cost_ = new_cost;
     NotifyObserversOfConnectionCostChange();
-}
-
-void NetworkChangeNotifierWin::ConnectionCostObserverAdded() {
-  sequence_runner_for_registration_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&NetworkChangeNotifierWin::OnConnectionCostObserverAdded,
-                     weak_factory_.GetWeakPtr()));
-}
-
-void NetworkChangeNotifierWin::OnConnectionCostObserverAdded() {
-  DCHECK(sequence_runner_for_registration_->RunsTasksInCurrentSequence());
-  InitializeConnectionCost();
-
-  // No need to register if we don't have a cost manager or if we're already
-  // registered.
-  if (!network_cost_manager_ || network_cost_manager_event_sink_)
-    return;
-
-  network_cost_manager_event_sink_ =
-      Microsoft::WRL::Make<net::NetworkCostManagerEventSink>(
-          network_cost_manager_.Get(),
-          base::BindRepeating(&NetworkChangeNotifierWin::OnCostChanged,
-                              weak_factory_.GetWeakPtr()));
-  HRESULT hr = network_cost_manager_event_sink_->RegisterForNotifications();
-  if (hr != S_OK) {
-    // If registration failed for any reason, just destroy the event sink. The
-    // observer will remain connected but will not receive any updates. If
-    // another observer gets added later, we can re-attempt registration.
-    network_cost_manager_event_sink_ = nullptr;
   }
 }
 
@@ -491,8 +318,8 @@
   offline_polls_++;
   // If we continue to appear offline, delay sending out the notification in
   // case we appear to go online within 20 seconds.  UMA histogram data shows
-  // we may not detect the transition to online state after 1 second but within
-  // 20 seconds we generally do.
+  // we may not detect the transition to online state after 1 second but
+  // within 20 seconds we generally do.
   if (last_announced_offline_ && current_offline && offline_polls_ <= 20) {
     timer_.Start(FROM_HERE, base::Seconds(1), this,
                  &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange);
diff --git a/net/base/network_change_notifier_win.h b/net/base/network_change_notifier_win.h
index 0d88afa..c89af03 100644
--- a/net/base/network_change_notifier_win.h
+++ b/net/base/network_change_notifier_win.h
@@ -5,13 +5,9 @@
 #ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
 #define NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
 
-#include <netlistmgr.h>
-#include <ocidl.h>
 #include <windows.h>
-#include <wrl.h>
-#include <wrl/client.h>
 
-#include <memory>
+#include <atomic>
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
@@ -19,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/thread_annotations.h"
+#include "base/threading/sequence_bound.h"
 #include "base/timer/timer.h"
 #include "base/win/object_watcher.h"
 #include "net/base/net_export.h"
@@ -30,7 +27,7 @@
 
 namespace net {
 
-class NetworkCostManagerEventSink;
+class NetworkCostChangeNotifierWin;
 
 // NetworkChangeNotifierWin uses a SequenceChecker, as all its internal
 // notification code must be called on the sequence it is created and destroyed
@@ -100,25 +97,7 @@
 
   static NetworkChangeCalculatorParams NetworkChangeCalculatorParamsWin();
 
-  // Gets the current network connection cost (if possible) and caches it.
-  void InitializeConnectionCost();
-  // Does the work of initializing for thread safety.
-  bool InitializeConnectionCostOnce();
-  // Retrieves the current network connection cost from the OS's Cost Manager.
-  HRESULT UpdateConnectionCostFromCostManager();
-  // Converts the OS enum values to the enum values used in our code.
-  static ConnectionCost ConnectionCostFromNlmCost(NLM_CONNECTION_COST cost);
-  // Sets the cached network connection cost value.
-  void SetCurrentConnectionCost(ConnectionCost connection_cost);
-  // Callback method for the notification event sink.
-  void OnCostChanged();
-  // Tells this class that an observer was added and therefore this class needs
-  // to register for notifications.
-  void ConnectionCostObserverAdded() override;
-  // Since ConnectionCostObserverAdded() can be called on any thread and we
-  // don't want to do a bunch of work on an arbitrary thread, this method used
-  // to post task to do the work.
-  void OnConnectionCostObserverAdded();
+  void OnCostChanged(NetworkChangeNotifier::ConnectionCost new_cost);
 
   // All member variables may only be accessed on the sequence |this| was
   // created on.
@@ -141,8 +120,13 @@
   mutable base::Lock last_computed_connection_type_lock_;
   ConnectionType last_computed_connection_type_;
 
-  std::atomic<ConnectionCost> last_computed_connection_cost_ =
-      ConnectionCost::CONNECTION_COST_UNKNOWN;
+  std::atomic<NetworkChangeNotifier::ConnectionCost>
+      last_computed_connection_cost_ =
+          NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN;
+
+  // Provides the cost of the current connection.  Uses the Windows OS APIs to
+  // monitor and determine cost.
+  base::SequenceBound<NetworkCostChangeNotifierWin> cost_change_notifier_;
 
   // Result of IsOffline() when NotifyObserversOfConnectionTypeChange()
   // was last called.
@@ -150,10 +134,6 @@
   // Number of times polled to check if still offline.
   int offline_polls_;
 
-  Microsoft::WRL::ComPtr<INetworkCostManager> network_cost_manager_;
-  Microsoft::WRL::ComPtr<NetworkCostManagerEventSink>
-      network_cost_manager_event_sink_;
-
   // Used to ensure that all registration actions are properly sequenced on the
   // same thread regardless of which thread was used to call into the
   // NetworkChangeNotifier API.
diff --git a/net/base/network_change_notifier_win_unittest.cc b/net/base/network_change_notifier_win_unittest.cc
index 9abe200..cbb1b24 100644
--- a/net/base/network_change_notifier_win_unittest.cc
+++ b/net/base/network_change_notifier_win_unittest.cc
@@ -4,16 +4,22 @@
 
 #include "net/base/network_change_notifier_win.h"
 
+#include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/run_loop.h"
+#include "base/sequence_checker.h"
 #include "base/task/single_thread_task_runner.h"
+#include "base/test/scoped_os_info_override_win.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/win/windows_version.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/network_change_notifier_factory.h"
+#include "net/test/test_connection_cost_observer.h"
 #include "net/test/test_with_task_environment.h"
+#include "net/test/win/fake_network_cost_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -31,7 +37,6 @@
   TestNetworkChangeNotifierWin() {
     last_computed_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
     last_announced_offline_ = false;
-    last_computed_connection_cost_ = ConnectionCost::CONNECTION_COST_UNKNOWN;
     sequence_runner_for_registration_ = base::SequencedTaskRunnerHandle::Get();
   }
 
@@ -55,13 +60,18 @@
 
   // From NetworkChangeNotifierWin.
   MOCK_METHOD0(WatchForAddressChangeInternal, bool());
+
+  // Allow tests to compare results with the default implementation that does
+  // not depend on the INetworkCostManager Windows OS API.  The default
+  // implementation is used as a fall back when INetworkCostManager fails.
+  ConnectionCost GetCurrentConnectionCostFromDefaultImplementation() {
+    return NetworkChangeNotifier::GetCurrentConnectionCost();
+  }
 };
 
 class TestIPAddressObserver : public NetworkChangeNotifier::IPAddressObserver {
  public:
-  TestIPAddressObserver() {
-    NetworkChangeNotifier::AddIPAddressObserver(this);
-  }
+  TestIPAddressObserver() { NetworkChangeNotifier::AddIPAddressObserver(this); }
 
   TestIPAddressObserver(const TestIPAddressObserver&) = delete;
   TestIPAddressObserver& operator=(const TestIPAddressObserver&) = delete;
@@ -182,7 +192,8 @@
         .Times(1)
         .WillOnce(Invoke(&run_loop, &base::RunLoop::QuitWhenIdle));
     EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
-        .Times(1).WillOnce(Return(true));
+        .Times(1)
+        .WillOnce(Return(true));
 
     run_loop.Run();
 
@@ -219,23 +230,19 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  bool HasNetworkCostManager() {
-    return network_change_notifier_.network_cost_manager_.Get() != nullptr;
-  }
-
-  bool HasNetworkCostManagerEventSink() {
-    return network_change_notifier_.network_cost_manager_event_sink_.Get() !=
-           nullptr;
-  }
-
-  NetworkChangeNotifier::ConnectionCost LastComputedConnectionCost() {
-    return network_change_notifier_.last_computed_connection_cost_;
-  }
-
   NetworkChangeNotifier::ConnectionCost GetCurrentConnectionCost() {
     return network_change_notifier_.GetCurrentConnectionCost();
   }
 
+  NetworkChangeNotifier::ConnectionCost
+  GetCurrentConnectionCostFromDefaultImplementation() {
+    return network_change_notifier_
+        .GetCurrentConnectionCostFromDefaultImplementation();
+  }
+
+ protected:
+  FakeNetworkCostManagerEnvironment fake_network_cost_manager_environment_;
+
  private:
   // Note that the order of declaration here is important.
 
@@ -287,58 +294,102 @@
   RetryAndSucceed();
 }
 
-class TestConnectionCostObserver
-    : public NetworkChangeNotifier::ConnectionCostObserver {
- public:
-  TestConnectionCostObserver() {}
-
-  TestConnectionCostObserver(const TestConnectionCostObserver&) = delete;
-  TestConnectionCostObserver& operator=(const TestConnectionCostObserver&) =
-      delete;
-
-  ~TestConnectionCostObserver() override {
-    NetworkChangeNotifier::RemoveConnectionCostObserver(this);
-  }
-
-  void OnConnectionCostChanged(NetworkChangeNotifier::ConnectionCost) override {
-  }
-
-  void Register() { NetworkChangeNotifier::AddConnectionCostObserver(this); }
-};
-
-TEST_F(NetworkChangeNotifierWinTest, NetworkCostManagerIntegration) {
-  // NetworkCostManager integration only exist on Win10+.
+TEST_F(NetworkChangeNotifierWinTest, GetCurrentCost) {
   if (base::win::GetVersion() < base::win::Version::WIN10)
     return;
 
-  // Upon creation, none of the NetworkCostManager integration should be
-  // initialized yet.
-  ASSERT_FALSE(HasNetworkCostManager());
-  ASSERT_FALSE(HasNetworkCostManagerEventSink());
-  ASSERT_EQ(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
-            LastComputedConnectionCost());
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
 
-  // Asking for the current connection cost should initialize the
-  // NetworkCostManager integration, but not the event sink.
-  // Note that the actual ConnectionCost value return is irrelevant beyond the
-  // fact that it shouldn't be UNKNOWN anymore if the integration is initialized
-  // properly.
-  NetworkChangeNotifier::ConnectionCost current_connection_cost =
-      GetCurrentConnectionCost();
-  EXPECT_NE(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
-            current_connection_cost);
-  EXPECT_EQ(current_connection_cost, LastComputedConnectionCost());
-  EXPECT_TRUE(HasNetworkCostManager());
-  EXPECT_FALSE(HasNetworkCostManagerEventSink());
+  // Wait for NetworkCostChangeNotifierWin to finish initializing.
+  RunUntilIdle();
 
-  // Adding a ConnectionCostObserver should initialize the event sink. If the
-  // subsequent registration for updates fails, the event sink will get
-  // destroyed.
-  TestConnectionCostObserver test_connection_cost_observer;
-  test_connection_cost_observer.Register();
-  // The actual registration happens on a callback, so need to run until idle.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(HasNetworkCostManagerEventSink());
+  EXPECT_EQ(GetCurrentConnectionCost(),
+            NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
+
+  // Wait for NetworkCostChangeNotifierWin to handle the cost changed event.
+  RunUntilIdle();
+
+  EXPECT_EQ(GetCurrentConnectionCost(),
+            NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
+}
+
+TEST_F(NetworkChangeNotifierWinTest, CostChangeObserver) {
+  if (base::win::GetVersion() < base::win::Version::WIN10)
+    return;
+
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+
+  // Wait for NetworkCostChangeNotifierWin to finish initializing.
+  RunUntilIdle();
+
+  TestConnectionCostObserver cost_observer;
+  NetworkChangeNotifier::AddConnectionCostObserver(&cost_observer);
+
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
+
+  cost_observer.WaitForConnectionCostChanged();
+
+  ASSERT_EQ(cost_observer.cost_changed_calls(), 1u);
+  EXPECT_EQ(cost_observer.last_cost_changed_input(),
+            NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
+
+  NetworkChangeNotifier::RemoveConnectionCostObserver(&cost_observer);
+}
+
+// Uses the fake implementation of INetworkCostManager to simulate GetCost()
+// returning an error HRESULT.
+class NetworkChangeNotifierWinCostErrorTest
+    : public NetworkChangeNotifierWinTest {
+  void SetUp() override {
+    if (base::win::GetVersion() < base::win::Version::WIN10) {
+      GTEST_SKIP();
+    }
+
+    fake_network_cost_manager_environment_.SimulateError(
+        NetworkCostManagerStatus::kErrorGetCostFailed);
+
+    NetworkChangeNotifierWinTest::SetUp();
+  }
+};
+
+TEST_F(NetworkChangeNotifierWinCostErrorTest, CostError) {
+  // Wait for NetworkCostChangeNotifierWin to finish initializing, which should
+  // fail with an error.
+  RunUntilIdle();
+
+  // NetworkChangeNotifierWin must use the default implementation when
+  // NetworkCostChangeNotifierWin returns an unknown cost.
+  EXPECT_EQ(GetCurrentConnectionCost(),
+            GetCurrentConnectionCostFromDefaultImplementation());
+}
+
+// Override the Windows OS version to simulate running on an OS that does not
+// support INetworkCostManager.
+class NetworkChangeNotifierWinCostUnsupportedOsTest
+    : public NetworkChangeNotifierWinTest {
+ public:
+  NetworkChangeNotifierWinCostUnsupportedOsTest()
+      : os_override_(base::test::ScopedOSInfoOverride::Type::kWin81Pro) {}
+
+ protected:
+  base::test::ScopedOSInfoOverride os_override_;
+};
+
+TEST_F(NetworkChangeNotifierWinCostUnsupportedOsTest, CostWithUnsupportedOS) {
+  // Wait for NetworkCostChangeNotifierWin to finish initializing, which should
+  // initialize with an unknown cost on an unsupported OS.
+  RunUntilIdle();
+
+  // NetworkChangeNotifierWin must use the default implementation when
+  // NetworkCostChangeNotifierWin returns an unknown cost.
+  EXPECT_EQ(GetCurrentConnectionCost(),
+            GetCurrentConnectionCostFromDefaultImplementation());
 }
 
 }  // namespace net
diff --git a/net/base/network_cost_change_notifier_win.cc b/net/base/network_cost_change_notifier_win.cc
new file mode 100644
index 0000000..abc56a41
--- /dev/null
+++ b/net/base/network_cost_change_notifier_win.cc
@@ -0,0 +1,271 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/network_cost_change_notifier_win.h"
+
+#include <wrl.h>
+#include <wrl/client.h>
+
+#include "base/check.h"
+#include "base/no_destructor.h"
+#include "base/task/bind_post_task.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/scoped_thread_priority.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/win/com_init_util.h"
+#include "base/win/windows_version.h"
+
+using Microsoft::WRL::ComPtr;
+
+namespace net {
+
+namespace {
+
+NetworkChangeNotifier::ConnectionCost ConnectionCostFromNlmConnectionCost(
+    DWORD connection_cost_flags) {
+  if (connection_cost_flags == NLM_CONNECTION_COST_UNKNOWN)
+    return NetworkChangeNotifier::CONNECTION_COST_UNKNOWN;
+  else if ((connection_cost_flags & NLM_CONNECTION_COST_UNRESTRICTED) != 0)
+    return NetworkChangeNotifier::CONNECTION_COST_UNMETERED;
+  else
+    return NetworkChangeNotifier::CONNECTION_COST_METERED;
+}
+
+NetworkCostChangeNotifierWin::CoCreateInstanceCallback&
+GetCoCreateInstanceOverride() {
+  static base::NoDestructor<
+      NetworkCostChangeNotifierWin::CoCreateInstanceCallback>
+      callback_for_testing;
+  return *callback_for_testing;
+}
+
+}  // namespace
+
+// This class is used as an event sink to register for notifications from the
+// INetworkCostManagerEvents interface. In particular, we are focused on getting
+// notified when the connection cost changes. This is only supported on Win10+.
+class NetworkCostManagerEventSinkWin final
+    : public Microsoft::WRL::RuntimeClass<
+          Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+          INetworkCostManagerEvents> {
+ public:
+  static HRESULT CreateInstance(
+      INetworkCostManager* network_cost_manager,
+      base::RepeatingClosure cost_changed_callback,
+      ComPtr<NetworkCostManagerEventSinkWin>* result) {
+    ComPtr<NetworkCostManagerEventSinkWin> instance =
+        Microsoft::WRL::Make<net::NetworkCostManagerEventSinkWin>(
+            cost_changed_callback);
+    HRESULT hr = instance->RegisterForNotifications(network_cost_manager);
+    if (hr != S_OK) {
+      return hr;
+    }
+
+    *result = instance;
+    return S_OK;
+  }
+
+  void UnRegisterForNotifications() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+    if (event_sink_connection_point_) {
+      event_sink_connection_point_->Unadvise(event_sink_connection_cookie_);
+      event_sink_connection_point_.Reset();
+    }
+  }
+
+  // Implement the INetworkCostManagerEvents interface.
+  HRESULT __stdcall CostChanged(DWORD /*cost*/,
+                                NLM_SOCKADDR* /*socket_address*/) final {
+    // It is possible to get multiple notifications in a short period of time.
+    // Rather than worrying about whether this notification represents the
+    // latest, just notify the owner who can get the current value from the
+    // INetworkCostManager so we know that we're actually getting the correct
+    // value.
+    cost_changed_callback_.Run();
+    return S_OK;
+  }
+
+  HRESULT __stdcall DataPlanStatusChanged(
+      NLM_SOCKADDR* /*socket_address*/) final {
+    return S_OK;
+  }
+
+  NetworkCostManagerEventSinkWin(base::RepeatingClosure cost_changed_callback)
+      : cost_changed_callback_(cost_changed_callback) {}
+
+  NetworkCostManagerEventSinkWin(const NetworkCostManagerEventSinkWin&) =
+      delete;
+  NetworkCostManagerEventSinkWin& operator=(
+      const NetworkCostManagerEventSinkWin&) = delete;
+
+ private:
+  ~NetworkCostManagerEventSinkWin() final = default;
+
+  HRESULT RegisterForNotifications(INetworkCostManager* cost_manager) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    DCHECK_GE(base::win::GetVersion(), base::win::Version::WIN10);
+
+    base::win::AssertComInitialized();
+    base::win::AssertComApartmentType(base::win::ComApartmentType::STA);
+
+    ComPtr<IUnknown> this_event_sink_unknown;
+    HRESULT hr = QueryInterface(IID_PPV_ARGS(&this_event_sink_unknown));
+
+    // `NetworkCostManagerEventSinkWin::QueryInterface` for `IUnknown` must
+    // succeed since it is implemented by this class.
+    DCHECK_EQ(hr, S_OK);
+
+    ComPtr<IConnectionPointContainer> connection_point_container;
+    hr =
+        cost_manager->QueryInterface(IID_PPV_ARGS(&connection_point_container));
+    if (hr != S_OK) {
+      return hr;
+    }
+
+    Microsoft::WRL::ComPtr<IConnectionPoint> event_sink_connection_point;
+    hr = connection_point_container->FindConnectionPoint(
+        IID_INetworkCostManagerEvents, &event_sink_connection_point);
+    if (hr != S_OK) {
+      return hr;
+    }
+
+    hr = event_sink_connection_point->Advise(this_event_sink_unknown.Get(),
+                                             &event_sink_connection_cookie_);
+    if (hr != S_OK) {
+      return hr;
+    }
+
+    DCHECK_EQ(event_sink_connection_point_, nullptr);
+    event_sink_connection_point_ = event_sink_connection_point;
+    return S_OK;
+  }
+
+  base::RepeatingClosure cost_changed_callback_;
+
+  // The following members must be accessed on the sequence from
+  // `sequence_checker_`
+  SEQUENCE_CHECKER(sequence_checker_);
+  DWORD event_sink_connection_cookie_ = 0;
+  Microsoft::WRL::ComPtr<IConnectionPoint> event_sink_connection_point_;
+};
+
+// static
+base::SequenceBound<NetworkCostChangeNotifierWin>
+NetworkCostChangeNotifierWin::CreateInstance(
+    CostChangedCallback cost_changed_callback) {
+  scoped_refptr<base::SequencedTaskRunner> com_best_effort_task_runner =
+      base::ThreadPool::CreateCOMSTATaskRunner(
+          {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+           base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
+
+  return base::SequenceBound<NetworkCostChangeNotifierWin>(
+      com_best_effort_task_runner,
+      // Ensure `cost_changed_callback` runs on the sequence of the creator and
+      // owner of `NetworkCostChangeNotifierWin`.
+      base::BindPostTask(base::SequencedTaskRunnerHandle::Get(),
+                         cost_changed_callback));
+}
+
+NetworkCostChangeNotifierWin::NetworkCostChangeNotifierWin(
+    CostChangedCallback cost_changed_callback)
+    : cost_changed_callback_(cost_changed_callback) {
+  StartWatching();
+}
+
+NetworkCostChangeNotifierWin::~NetworkCostChangeNotifierWin() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  StopWatching();
+}
+
+void NetworkCostChangeNotifierWin::StartWatching() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (base::win::GetComApartmentTypeForThread() ==
+      base::win::ComApartmentType::NONE) {
+    // TODO(crbug.com/1367360): INetworkCostManager inaccessible in network
+    // sandbox.  Currently, the network sandbox does not allow COM.
+    return;
+  }
+
+  base::win::AssertComInitialized();
+  base::win::AssertComApartmentType(base::win::ComApartmentType::STA);
+
+  if (base::win::GetVersion() < base::win::Version::WIN10) {
+    // INetworkCostManager requires Win10 or higher.
+    return;
+  }
+
+  SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
+
+  // Create INetworkListManager using CoCreateInstance, but allow tests to
+  // provide an fake implementation of INetworkListManager through an override.
+  CoCreateInstanceCallback co_create_instance_callback =
+      base::BindRepeating(&CoCreateInstance);
+  if (GetCoCreateInstanceOverride()) {
+    co_create_instance_callback = GetCoCreateInstanceOverride();
+  }
+
+  ComPtr<INetworkCostManager> cost_manager;
+  HRESULT hr = co_create_instance_callback.Run(
+      CLSID_NetworkListManager, /*unknown_outer=*/nullptr, CLSCTX_ALL,
+      IID_INetworkCostManager, &cost_manager);
+  if (hr != S_OK) {
+    return;
+  }
+
+  // Subscribe to cost changed events.
+  hr = NetworkCostManagerEventSinkWin::CreateInstance(
+      cost_manager.Get(),
+      // Cost changed callbacks must run on this sequence to get the new cost
+      // from `INetworkCostManager`.
+      base::BindPostTask(
+          base::SequencedTaskRunnerHandle::Get(),
+          base::BindRepeating(&NetworkCostChangeNotifierWin::HandleCostChanged,
+                              weak_ptr_factory_.GetWeakPtr())),
+      &cost_manager_event_sink_);
+
+  if (hr != S_OK) {
+    return;
+  }
+
+  // Set the initial cost and inform observers of the initial value.
+  cost_manager_ = cost_manager;
+  HandleCostChanged();
+}
+
+void NetworkCostChangeNotifierWin::StopWatching() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (cost_manager_event_sink_) {
+    cost_manager_event_sink_->UnRegisterForNotifications();
+    cost_manager_event_sink_.Reset();
+  }
+
+  cost_manager_.Reset();
+}
+
+void NetworkCostChangeNotifierWin::HandleCostChanged() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  DWORD connection_cost_flags;
+  HRESULT hr = cost_manager_->GetCost(&connection_cost_flags,
+                                      /*destination_ip_address=*/nullptr);
+  if (hr != S_OK) {
+    connection_cost_flags = NLM_CONNECTION_COST_UNKNOWN;
+  }
+
+  NetworkChangeNotifier::ConnectionCost changed_cost =
+      ConnectionCostFromNlmConnectionCost(connection_cost_flags);
+
+  cost_changed_callback_.Run(changed_cost);
+}
+
+// static
+void NetworkCostChangeNotifierWin::OverrideCoCreateInstanceForTesting(
+    CoCreateInstanceCallback callback_for_testing) {
+  GetCoCreateInstanceOverride() = callback_for_testing;
+}
+
+}  // namespace net
diff --git a/net/base/network_cost_change_notifier_win.h b/net/base/network_cost_change_notifier_win.h
new file mode 100644
index 0000000..7868cd2
--- /dev/null
+++ b/net/base/network_cost_change_notifier_win.h
@@ -0,0 +1,83 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NETWORK_COST_CHANGE_NOTIFIER_WIN_H_
+#define NET_BASE_NETWORK_COST_CHANGE_NOTIFIER_WIN_H_
+
+#include <netlistmgr.h>
+#include <wrl/client.h>
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/threading/sequence_bound.h"
+#include "net/base/net_export.h"
+#include "net/base/network_change_notifier.h"
+
+namespace net {
+class NetworkCostManagerEventSinkWin;
+
+// Uses the `INetworkCostManager` Windows OS API to monitor the cost of the
+// current connection.  `INetworkCostManager` performs blocking IO and
+// synchronous RPC and must be accessed through a thread pool COM STA single
+// threaded task runner.  NetworkCostChangeNotifierWin uses
+// `base::SequenceBound` to prevent these expensive operations from happening on
+// the UI thread.
+class NET_EXPORT_PRIVATE NetworkCostChangeNotifierWin final {
+ public:
+  using CostChangedCallback =
+      base::RepeatingCallback<void(NetworkChangeNotifier::ConnectionCost)>;
+
+  // Constructs a new instance using a new COM STA single threaded task runner
+  // to post the task that creates NetworkCostChangeNotifierWin and subscribes
+  // to cost change events.
+  static base::SequenceBound<NetworkCostChangeNotifierWin> CreateInstance(
+      CostChangedCallback cost_changed_callback);
+
+  // Tests use this hook to provide a fake implementation of the OS APIs.
+  // The fake implementation enables tests to simulate different cost values,
+  // cost changed events and OS errors.
+  using CoCreateInstanceCallback = base::RepeatingCallback<
+      HRESULT(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*)>;
+  static void OverrideCoCreateInstanceForTesting(
+      CoCreateInstanceCallback callback_for_testing);
+
+  NetworkCostChangeNotifierWin(const NetworkCostChangeNotifierWin&) = delete;
+  NetworkCostChangeNotifierWin& operator=(const NetworkCostChangeNotifierWin&) =
+      delete;
+
+ private:
+  friend class base::SequenceBound<NetworkCostChangeNotifierWin>;
+
+  explicit NetworkCostChangeNotifierWin(
+      CostChangedCallback cost_changed_callback);
+  ~NetworkCostChangeNotifierWin();
+
+  // Creates `INetworkCostManager` and subscribe to cost change events.
+  void StartWatching();
+
+  // Stops monitoring the cost of the current connection by unsubscribing to
+  // `INetworkCostManager` events and releasing all members.
+  void StopWatching();
+
+  // Gets the current cost from `cost_manager_` and then runs
+  // `cost_changed_callback_`.
+  void HandleCostChanged();
+
+  // All members must be accessed on the sequence from `sequence_checker_`
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  CostChangedCallback cost_changed_callback_;
+
+  Microsoft::WRL::ComPtr<INetworkCostManager> cost_manager_;
+
+  Microsoft::WRL::ComPtr<NetworkCostManagerEventSinkWin>
+      cost_manager_event_sink_;
+
+  base::WeakPtrFactory<NetworkCostChangeNotifierWin> weak_ptr_factory_{this};
+};
+
+}  // namespace net
+
+#endif  // NET_BASE_NETWORK_COST_CHANGE_NOTIFIER_WIN_H_
diff --git a/net/base/network_cost_change_notifier_win_unittest.cc b/net/base/network_cost_change_notifier_win_unittest.cc
new file mode 100644
index 0000000..ae35acc
--- /dev/null
+++ b/net/base/network_cost_change_notifier_win_unittest.cc
@@ -0,0 +1,236 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/network_cost_change_notifier_win.h"
+
+#include "base/run_loop.h"
+#include "base/sequence_checker.h"
+#include "base/test/scoped_os_info_override_win.h"
+#include "base/win/windows_version.h"
+#include "net/base/network_change_notifier.h"
+#include "net/test/test_connection_cost_observer.h"
+#include "net/test/test_with_task_environment.h"
+#include "net/test/win/fake_network_cost_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+class NetworkCostChangeNotifierWinTest : public TestWithTaskEnvironment {
+ public:
+  void SetUp() override {
+    if (base::win::GetVersion() < base::win::Version::WIN10) {
+      GTEST_SKIP();
+    }
+  }
+
+ protected:
+  FakeNetworkCostManagerEnvironment fake_network_cost_manager_environment_;
+};
+
+TEST_F(NetworkCostChangeNotifierWinTest, InitialCostUnknown) {
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN);
+
+  TestConnectionCostObserver cost_change_observer;
+  auto cost_change_callback =
+      base::BindRepeating(&TestConnectionCostObserver::OnConnectionCostChanged,
+                          base::Unretained(&cost_change_observer));
+
+  base::SequenceBound<NetworkCostChangeNotifierWin> cost_change_notifier =
+      NetworkCostChangeNotifierWin::CreateInstance(cost_change_callback);
+
+  // Wait for `NetworkCostChangeNotifierWin` to finish initializing.
+  cost_change_observer.WaitForConnectionCostChanged();
+
+  // `NetworkCostChangeNotifierWin` must report an unknown cost after
+  // initializing.
+  EXPECT_EQ(cost_change_observer.cost_changed_calls(), 1u);
+  EXPECT_EQ(cost_change_observer.last_cost_changed_input(),
+            NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN);
+}
+
+TEST_F(NetworkCostChangeNotifierWinTest, InitialCostKnown) {
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+
+  TestConnectionCostObserver cost_change_observer;
+  auto cost_change_callback =
+      base::BindRepeating(&TestConnectionCostObserver::OnConnectionCostChanged,
+                          base::Unretained(&cost_change_observer));
+
+  base::SequenceBound<NetworkCostChangeNotifierWin> cost_change_notifier =
+      NetworkCostChangeNotifierWin::CreateInstance(cost_change_callback);
+
+  // Initializing changes the cost from unknown to unmetered.
+  cost_change_observer.WaitForConnectionCostChanged();
+
+  ASSERT_EQ(cost_change_observer.cost_changed_calls(), 1u);
+  EXPECT_EQ(cost_change_observer.last_cost_changed_input(),
+            NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+}
+
+TEST_F(NetworkCostChangeNotifierWinTest, MultipleCostChangedEvents) {
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+
+  TestConnectionCostObserver cost_change_observer;
+  auto cost_change_callback =
+      base::BindRepeating(&TestConnectionCostObserver::OnConnectionCostChanged,
+                          base::Unretained(&cost_change_observer));
+
+  base::SequenceBound<NetworkCostChangeNotifierWin> cost_change_notifier =
+      NetworkCostChangeNotifierWin::CreateInstance(cost_change_callback);
+
+  // Initializing changes the cost from unknown to unmetered.
+  cost_change_observer.WaitForConnectionCostChanged();
+
+  ASSERT_EQ(cost_change_observer.cost_changed_calls(), 1u);
+  EXPECT_EQ(cost_change_observer.last_cost_changed_input(),
+            NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
+
+  // The simulated event changes the cost from unmetered to metered.
+  cost_change_observer.WaitForConnectionCostChanged();
+
+  ASSERT_EQ(cost_change_observer.cost_changed_calls(), 2u);
+  EXPECT_EQ(cost_change_observer.last_cost_changed_input(),
+            NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
+
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN);
+
+  // The simulated event changes the cost from metered to unknown.
+  cost_change_observer.WaitForConnectionCostChanged();
+
+  ASSERT_EQ(cost_change_observer.cost_changed_calls(), 3u);
+  EXPECT_EQ(cost_change_observer.last_cost_changed_input(),
+            NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN);
+}
+
+TEST_F(NetworkCostChangeNotifierWinTest, DuplicateEvents) {
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+
+  TestConnectionCostObserver cost_change_observer;
+  auto cost_change_callback =
+      base::BindRepeating(&TestConnectionCostObserver::OnConnectionCostChanged,
+                          base::Unretained(&cost_change_observer));
+
+  base::SequenceBound<NetworkCostChangeNotifierWin> cost_change_notifier =
+      NetworkCostChangeNotifierWin::CreateInstance(cost_change_callback);
+
+  // Initializing changes the cost from unknown to unmetered.
+  cost_change_observer.WaitForConnectionCostChanged();
+  ASSERT_EQ(cost_change_observer.cost_changed_calls(), 1u);
+
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+
+  cost_change_observer.WaitForConnectionCostChanged();
+
+  // Changing from unmetered to unmetered must dispatch a cost changed event.
+  ASSERT_EQ(cost_change_observer.cost_changed_calls(), 2u);
+  EXPECT_EQ(cost_change_observer.last_cost_changed_input(),
+            NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+}
+
+TEST_F(NetworkCostChangeNotifierWinTest, ShutdownImmediately) {
+  TestConnectionCostObserver cost_change_observer;
+  auto cost_change_callback =
+      base::BindRepeating(&TestConnectionCostObserver::OnConnectionCostChanged,
+                          base::Unretained(&cost_change_observer));
+
+  base::SequenceBound<NetworkCostChangeNotifierWin> cost_change_notifier =
+      NetworkCostChangeNotifierWin::CreateInstance(cost_change_callback);
+
+  // Shutting down immediately must not crash.
+  cost_change_notifier.Reset();
+
+  // Wait for `NetworkCostChangeNotifierWin` to finish initializing and shutting
+  // down.
+  RunUntilIdle();
+
+  // `NetworkCostChangeNotifierWin` reports a connection change after
+  // initializing.
+  EXPECT_EQ(cost_change_observer.cost_changed_calls(), 1u);
+
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED);
+
+  // Wait for `NetworkCostChangeNotifierWin` to handle the cost changed event.
+  RunUntilIdle();
+
+  // After shutdown, cost changed events must have no effect.
+  EXPECT_EQ(cost_change_observer.cost_changed_calls(), 1u);
+}
+
+TEST_F(NetworkCostChangeNotifierWinTest, ErrorHandling) {
+  // Simulate the failure of each OS API while initializing
+  // `NetworkCostChangeNotifierWin`.
+  constexpr const NetworkCostManagerStatus kErrorList[] = {
+      NetworkCostManagerStatus::kErrorCoCreateInstanceFailed,
+      NetworkCostManagerStatus::kErrorQueryInterfaceFailed,
+      NetworkCostManagerStatus::kErrorFindConnectionPointFailed,
+      NetworkCostManagerStatus::kErrorAdviseFailed,
+      NetworkCostManagerStatus::kErrorGetCostFailed,
+  };
+  for (auto error : kErrorList) {
+    fake_network_cost_manager_environment_.SetCost(
+        NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+
+    fake_network_cost_manager_environment_.SimulateError(error);
+
+    TestConnectionCostObserver cost_change_observer;
+    auto cost_change_callback = base::BindRepeating(
+        &TestConnectionCostObserver::OnConnectionCostChanged,
+        base::Unretained(&cost_change_observer));
+
+    base::SequenceBound<NetworkCostChangeNotifierWin> cost_change_notifier =
+        NetworkCostChangeNotifierWin::CreateInstance(cost_change_callback);
+
+    if (error == NetworkCostManagerStatus::kErrorGetCostFailed) {
+      // `NetworkCostChangeNotifierWin` must report an unknown cost after
+      // `INetworkCostManager::GetCost()` fails.
+      cost_change_observer.WaitForConnectionCostChanged();
+
+      EXPECT_EQ(cost_change_observer.cost_changed_calls(), 1u);
+      EXPECT_EQ(cost_change_observer.last_cost_changed_input(),
+                NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN);
+    } else {
+      // Wait for `NetworkCostChangeNotifierWin` to finish initializing.
+      RunUntilIdle();
+
+      // `NetworkCostChangeNotifierWin` must NOT report a changed cost after
+      // failing to initialize.
+      EXPECT_EQ(cost_change_observer.cost_changed_calls(), 0u);
+    }
+  }
+}
+
+TEST_F(NetworkCostChangeNotifierWinTest, UnsupportedOS) {
+  base::test::ScopedOSInfoOverride os_override(
+      base::test::ScopedOSInfoOverride::Type::kWin81Pro);
+
+  fake_network_cost_manager_environment_.SetCost(
+      NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED);
+
+  TestConnectionCostObserver cost_change_observer;
+  auto cost_change_callback =
+      base::BindRepeating(&TestConnectionCostObserver::OnConnectionCostChanged,
+                          base::Unretained(&cost_change_observer));
+
+  base::SequenceBound<NetworkCostChangeNotifierWin> cost_change_notifier =
+      NetworkCostChangeNotifierWin::CreateInstance(cost_change_callback);
+
+  // Wait for `NetworkCostChangeNotifierWin` to finish initializing.
+  RunUntilIdle();
+
+  // `NetworkCostChangeNotifierWin` must NOT report a changed cost for
+  // unsupported OSes.
+  EXPECT_EQ(cost_change_observer.cost_changed_calls(), 0u);
+}
+
+}  // namespace net
diff --git a/net/cert/pki/cert_error_params.cc b/net/cert/pki/cert_error_params.cc
index b1edfb5..392e2be 100644
--- a/net/cert/pki/cert_error_params.cc
+++ b/net/cert/pki/cert_error_params.cc
@@ -6,8 +6,7 @@
 
 #include <memory>
 
-#include "base/check.h"
-#include "base/strings/string_number_conversions.h"
+#include "net/cert/pki/string_util.h"
 #include "net/der/input.h"
 
 namespace net {
@@ -45,7 +44,9 @@
                         const std::string& der,
                         std::string* out) {
     *out += name;
-    *out += ": " + base::HexEncode(der.data(), der.size());
+    *out +=
+        ": " + net::string_util::HexEncode(
+                   reinterpret_cast<const uint8_t*>(der.data()), der.size());
   }
 
   const char* name1_;
@@ -65,7 +66,8 @@
   CertErrorParams1SizeT& operator=(const CertErrorParams1SizeT&) = delete;
 
   std::string ToDebugString() const override {
-    return name_ + std::string(": ") + base::NumberToString(value_);
+    return name_ + std::string(": ") +
+           net::string_util::NumberToDecimalString(value_);
   }
 
  private:
@@ -87,8 +89,9 @@
   CertErrorParams2SizeT& operator=(const CertErrorParams2SizeT&) = delete;
 
   std::string ToDebugString() const override {
-    return name1_ + std::string(": ") + base::NumberToString(value1_) + "\n" +
-           name2_ + std::string(": ") + base::NumberToString(value2_);
+    return name1_ + std::string(": ") +
+           net::string_util::NumberToDecimalString(value1_) + "\n" + name2_ +
+           std::string(": ") + net::string_util::NumberToDecimalString(value2_);
   }
 
  private:
diff --git a/net/cert/pki/general_names.cc b/net/cert/pki/general_names.cc
index ec62869..d2bbd25 100644
--- a/net/cert/pki/general_names.cc
+++ b/net/cert/pki/general_names.cc
@@ -4,7 +4,6 @@
 
 #include "net/cert/pki/general_names.h"
 
-#include "base/check_op.h"
 #include "net/cert/pki/cert_error_params.h"
 #include "net/cert/pki/cert_errors.h"
 #include "net/cert/pki/string_util.h"
diff --git a/net/cert/pki/name_constraints.cc b/net/cert/pki/name_constraints.cc
index 4a4e100..eed0741 100644
--- a/net/cert/pki/name_constraints.cc
+++ b/net/cert/pki/name_constraints.cc
@@ -8,7 +8,6 @@
 
 #include <memory>
 
-#include "base/check.h"
 #include "base/numerics/clamped_math.h"
 #include "net/cert/pki/cert_errors.h"
 #include "net/cert/pki/common_cert_errors.h"
diff --git a/net/cert/pki/parse_certificate_fuzzer.cc b/net/cert/pki/parse_certificate_fuzzer.cc
index 4f1f42e..95ddc39 100644
--- a/net/cert/pki/parse_certificate_fuzzer.cc
+++ b/net/cert/pki/parse_certificate_fuzzer.cc
@@ -5,7 +5,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/check_op.h"
 #include "net/cert/pki/cert_errors.h"
 #include "net/cert/pki/parsed_certificate.h"
 #include "net/cert/x509_util.h"
diff --git a/net/cert/pki/parse_name.cc b/net/cert/pki/parse_name.cc
index f83246f..d2b928c 100644
--- a/net/cert/pki/parse_name.cc
+++ b/net/cert/pki/parse_name.cc
@@ -4,8 +4,7 @@
 
 #include "net/cert/pki/parse_name.h"
 
-#include "base/check_op.h"
-#include "base/strings/string_number_conversions.h"
+#include "net/cert/pki/string_util.h"
 #include "net/der/parse_values.h"
 #include "third_party/boringssl/src/include/openssl/bytestring.h"
 #include "third_party/boringssl/src/include/openssl/mem.h"
@@ -102,7 +101,8 @@
     type_string = OidToString(type);
     if (type_string.empty())
       return false;
-    value_string = "#" + base::HexEncode(value.UnsafeData(), value.Length());
+    value_string =
+        "#" + net::string_util::HexEncode(value.UnsafeData(), value.Length());
   }
 
   if (value_string.empty()) {
@@ -127,7 +127,9 @@
         nonprintable = true;
         std::string h;
         h += c;
-        value_string += "\\" + base::HexEncode(h.data(), h.length());
+        value_string +=
+            "\\" + net::string_util::HexEncode(
+                       reinterpret_cast<const uint8_t*>(h.data()), h.length());
       } else {
         value_string += c;
       }
@@ -136,7 +138,8 @@
     // If we have non-printable characters in a TeletexString, we hex encode
     // since we don't handle Teletex control codes.
     if (nonprintable && value_tag == der::kTeletexString)
-      value_string = "#" + base::HexEncode(value.UnsafeData(), value.Length());
+      value_string =
+          "#" + net::string_util::HexEncode(value.UnsafeData(), value.Length());
   }
 
   *out = type_string + "=" + value_string;
diff --git a/net/cert/pki/parsed_certificate.h b/net/cert/pki/parsed_certificate.h
index 5b70893..e777228 100644
--- a/net/cert/pki/parsed_certificate.h
+++ b/net/cert/pki/parsed_certificate.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/check.h"
 #include "base/memory/ref_counted.h"
 #include "net/base/net_export.h"
 #include "net/cert/pki/certificate_policies.h"
diff --git a/net/cert/pki/path_builder.cc b/net/cert/pki/path_builder.cc
index c73d033..93c4661e 100644
--- a/net/cert/pki/path_builder.cc
+++ b/net/cert/pki/path_builder.cc
@@ -11,13 +11,13 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/strings/string_number_conversions.h"
 #include "net/base/net_errors.h"
 #include "net/cert/pki/cert_issuer_source.h"
 #include "net/cert/pki/certificate_policies.h"
 #include "net/cert/pki/common_cert_errors.h"
 #include "net/cert/pki/parse_certificate.h"
 #include "net/cert/pki/parse_name.h"  // For CertDebugString.
+#include "net/cert/pki/string_util.h"
 #include "net/cert/pki/trust_store.h"
 #include "net/cert/pki/verify_certificate_chain.h"
 #include "net/cert/pki/verify_name_match.h"
@@ -36,7 +36,7 @@
   uint8_t digest[SHA256_DIGEST_LENGTH];
   SHA256(cert->der_cert().AsSpan().data(), cert->der_cert().AsSpan().size(),
          digest);
-  return base::HexEncode(digest, sizeof(digest));
+  return net::string_util::HexEncode(digest, sizeof(digest));
 }
 
 // TODO(mattm): decide how much debug logging to keep.
diff --git a/net/cert/pki/signature_algorithm.cc b/net/cert/pki/signature_algorithm.cc
index 685231e6..0b913bb 100644
--- a/net/cert/pki/signature_algorithm.cc
+++ b/net/cert/pki/signature_algorithm.cc
@@ -4,7 +4,6 @@
 
 #include "net/cert/pki/signature_algorithm.h"
 
-#include "base/check.h"
 #include "net/cert/pki/cert_error_params.h"
 #include "net/cert/pki/cert_errors.h"
 #include "net/der/input.h"
diff --git a/net/cert/pki/string_util.cc b/net/cert/pki/string_util.cc
index 4fc00a6..87e28c6 100644
--- a/net/cert/pki/string_util.cc
+++ b/net/cert/pki/string_util.cc
@@ -7,6 +7,8 @@
 #include "third_party/boringssl/src/include/openssl/mem.h"
 
 #include <algorithm>
+#include <iomanip>
+#include <sstream>
 #include <string>
 
 namespace net::string_util {
@@ -72,4 +74,21 @@
   return prefix.size() <= str.size() && prefix == str.substr(0, prefix.size());
 }
 
+std::string HexEncode(const uint8_t* data, size_t length) {
+  std::ostringstream out;
+  for (size_t i = 0; i < length; i++) {
+    out << std::hex << std::setfill('0') << std::setw(2) << std::uppercase
+        << int{data[i]};
+  }
+  return out.str();
+}
+
+// TODO(bbe) get rid of this once extracted to boringssl. Everything else
+// in third_party uses std::to_string
+std::string NumberToDecimalString(int i) {
+  std::ostringstream out;
+  out << std::dec << i;
+  return out.str();
+}
+
 }  // namespace net::string_util
diff --git a/net/cert/pki/string_util.h b/net/cert/pki/string_util.h
index da3a72af..46550f5 100644
--- a/net/cert/pki/string_util.h
+++ b/net/cert/pki/string_util.h
@@ -44,6 +44,12 @@
 // Compares |str1| and |suffix|. Returns true if |str1| ends with |suffix|.
 NET_EXPORT_PRIVATE bool EndsWith(std::string_view str, std::string_view suffix);
 
+// Returns a hexadecimal string encoding |data| of length |length|.
+NET_EXPORT_PRIVATE std::string HexEncode(const uint8_t* data, size_t length);
+
+// Returns a decimal string representation of |i|.
+NET_EXPORT_PRIVATE std::string NumberToDecimalString(int i);
+
 }  // namespace net::string_util
 
 #endif  // NET_CERT_PKI_STRING_UTIL_H_
diff --git a/net/cert/pki/string_util_unittest.cc b/net/cert/pki/string_util_unittest.cc
index 5a376321..a54b707e3 100644
--- a/net/cert/pki/string_util_unittest.cc
+++ b/net/cert/pki/string_util_unittest.cc
@@ -98,6 +98,25 @@
                                                   "1mail.google.com"));
 }
 
+TEST(StringUtilTest, HexEncode) {
+  std::string hex(net::string_util::HexEncode(nullptr, 0));
+  EXPECT_EQ(hex.length(), 0U);
+  uint8_t bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81};
+  hex = net::string_util::HexEncode(bytes, sizeof(bytes));
+  EXPECT_EQ(hex, "01FF02FE038081");
+}
+
+TEST(StringUtilTest, NumberToDecimalString) {
+  std::string number(net::string_util::NumberToDecimalString(42));
+  EXPECT_EQ(number, "42");
+  number = net::string_util::NumberToDecimalString(-1);
+  EXPECT_EQ(number, "-1");
+  number = net::string_util::NumberToDecimalString(0);
+  EXPECT_EQ(number, "0");
+  number = net::string_util::NumberToDecimalString(0xFF);
+  EXPECT_EQ(number, "255");
+}
+
 }  // namespace
 
 }  // namespace net
diff --git a/net/cert/pki/verify_certificate_chain.cc b/net/cert/pki/verify_certificate_chain.cc
index 416cf31b..216d830 100644
--- a/net/cert/pki/verify_certificate_chain.cc
+++ b/net/cert/pki/verify_certificate_chain.cc
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 
-#include "base/check.h"
 #include "base/memory/raw_ptr.h"
 #include "net/cert/pki/cert_error_params.h"
 #include "net/cert/pki/cert_errors.h"
diff --git a/net/cert/pki/verify_name_match.cc b/net/cert/pki/verify_name_match.cc
index 5a7b2af9..9fa1043 100644
--- a/net/cert/pki/verify_name_match.cc
+++ b/net/cert/pki/verify_name_match.cc
@@ -4,7 +4,6 @@
 
 #include "net/cert/pki/verify_name_match.h"
 
-#include "base/check.h"
 #include "net/cert/pki/cert_error_params.h"
 #include "net/cert/pki/cert_errors.h"
 #include "net/cert/pki/parse_name.h"
diff --git a/net/cert/pki/verify_name_match_unittest.cc b/net/cert/pki/verify_name_match_unittest.cc
index 75e84071..a65a513 100644
--- a/net/cert/pki/verify_name_match_unittest.cc
+++ b/net/cert/pki/verify_name_match_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "net/cert/pki/verify_name_match.h"
 
-#include "base/strings/string_number_conversions.h"
+#include "net/cert/pki/string_util.h"
 #include "net/cert/pki/test_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -328,7 +328,7 @@
   size_t replace_location = der.find("0123456789");
   ASSERT_NE(std::string::npos, replace_location);
   for (int c = 0; c < 256; ++c) {
-    SCOPED_TRACE(base::NumberToString(c));
+    SCOPED_TRACE(c);
     if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
         (c >= '0' && c <= '9')) {
       continue;
@@ -368,7 +368,7 @@
   size_t replace_location = der.find("eXaMple");
   ASSERT_NE(std::string::npos, replace_location);
   for (int c = 0; c < 256; ++c) {
-    SCOPED_TRACE(base::NumberToString(c));
+    SCOPED_TRACE(c);
     der.replace(replace_location, 1, 1, c);
     bool expected_result = (c <= 127);
     EXPECT_EQ(expected_result, VerifyNameMatch(SequenceValueFromString(&der),
diff --git a/net/first_party_sets/first_party_sets_cache_filter.cc b/net/first_party_sets/first_party_sets_cache_filter.cc
index 9f5fda3..402dbdf 100644
--- a/net/first_party_sets/first_party_sets_cache_filter.cc
+++ b/net/first_party_sets/first_party_sets_cache_filter.cc
@@ -42,6 +42,10 @@
          std::tie(other.filter_, other.browser_run_id_);
 }
 
+FirstPartySetsCacheFilter FirstPartySetsCacheFilter::Clone() const {
+  return FirstPartySetsCacheFilter(filter_, browser_run_id_);
+}
+
 FirstPartySetsCacheFilter::MatchInfo FirstPartySetsCacheFilter::GetMatchInfo(
     const net::SchemefulSite& site) const {
   FirstPartySetsCacheFilter::MatchInfo res;
diff --git a/net/first_party_sets/first_party_sets_cache_filter.h b/net/first_party_sets/first_party_sets_cache_filter.h
index ffc38b16..81ad165d 100644
--- a/net/first_party_sets/first_party_sets_cache_filter.h
+++ b/net/first_party_sets/first_party_sets_cache_filter.h
@@ -52,6 +52,8 @@
 
   bool operator==(const FirstPartySetsCacheFilter& other) const;
 
+  FirstPartySetsCacheFilter Clone() const;
+
   MatchInfo GetMatchInfo(const SchemefulSite& site) const;
 
  private:
diff --git a/net/test/test_connection_cost_observer.cc b/net/test/test_connection_cost_observer.cc
new file mode 100644
index 0000000..7967e63e
--- /dev/null
+++ b/net/test/test_connection_cost_observer.cc
@@ -0,0 +1,51 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/test/test_connection_cost_observer.h"
+
+namespace net {
+
+TestConnectionCostObserver::TestConnectionCostObserver() = default;
+
+TestConnectionCostObserver::~TestConnectionCostObserver() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void TestConnectionCostObserver::OnConnectionCostChanged(
+    NetworkChangeNotifier::ConnectionCost cost) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  cost_changed_inputs_.push_back(cost);
+
+  if (run_loop_) {
+    run_loop_->Quit();
+  }
+}
+
+void TestConnectionCostObserver::WaitForConnectionCostChanged() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  run_loop_ = std::make_unique<base::RunLoop>();
+  run_loop_->Run();
+  run_loop_.reset();
+}
+
+size_t TestConnectionCostObserver::cost_changed_calls() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return cost_changed_inputs_.size();
+}
+
+std::vector<NetworkChangeNotifier::ConnectionCost>
+TestConnectionCostObserver::cost_changed_inputs() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return cost_changed_inputs_;
+}
+
+NetworkChangeNotifier::ConnectionCost
+TestConnectionCostObserver::last_cost_changed_input() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CHECK_GT(cost_changed_inputs_.size(), 0u);
+  return cost_changed_inputs_.back();
+}
+
+}  // namespace net
diff --git a/net/test/test_connection_cost_observer.h b/net/test/test_connection_cost_observer.h
new file mode 100644
index 0000000..913368a
--- /dev/null
+++ b/net/test/test_connection_cost_observer.h
@@ -0,0 +1,47 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TEST_TEST_CONNECTION_COST_OBSERVER_H_
+#define NET_TEST_TEST_CONNECTION_COST_OBSERVER_H_
+
+#include "base/run_loop.h"
+#include "base/sequence_checker.h"
+#include "net/base/network_change_notifier.h"
+
+namespace net {
+
+class TestConnectionCostObserver final
+    : public NetworkChangeNotifier::ConnectionCostObserver {
+ public:
+  TestConnectionCostObserver();
+  ~TestConnectionCostObserver() final;
+
+  void OnConnectionCostChanged(
+      NetworkChangeNotifier::ConnectionCost cost) final;
+
+  void WaitForConnectionCostChanged();
+
+  size_t cost_changed_calls() const;
+  std::vector<NetworkChangeNotifier::ConnectionCost> cost_changed_inputs()
+      const;
+  NetworkChangeNotifier::ConnectionCost last_cost_changed_input() const;
+
+  TestConnectionCostObserver(const TestConnectionCostObserver&) = delete;
+  TestConnectionCostObserver& operator=(const TestConnectionCostObserver&) =
+      delete;
+
+ private:
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  // Set and used to block in `WaitForConnectionCostChanged()` until the next
+  // cost changed event occurs.
+  std::unique_ptr<base::RunLoop> run_loop_;
+
+  // Record each `OnConnectionCostChanged()` call.
+  std::vector<NetworkChangeNotifier::ConnectionCost> cost_changed_inputs_;
+};
+
+}  // namespace net
+
+#endif  // NET_TEST_TEST_CONNECTION_COST_OBSERVER_H_
diff --git a/net/test/win/fake_network_cost_manager.cc b/net/test/win/fake_network_cost_manager.cc
new file mode 100644
index 0000000..7c053ff
--- /dev/null
+++ b/net/test/win/fake_network_cost_manager.cc
@@ -0,0 +1,309 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/test/win/fake_network_cost_manager.h"
+
+#include <netlistmgr.h>
+#include <wrl/implements.h>
+
+#include <map>
+
+#include "net/base/network_cost_change_notifier_win.h"
+
+using Microsoft::WRL::ClassicCom;
+using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::RuntimeClass;
+using Microsoft::WRL::RuntimeClassFlags;
+
+namespace net {
+
+namespace {
+
+DWORD NlmConnectionCostFlagsFromConnectionCost(
+    NetworkChangeNotifier::ConnectionCost source_cost) {
+  switch (source_cost) {
+    case NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNMETERED:
+      return (NLM_CONNECTION_COST_UNRESTRICTED | NLM_CONNECTION_COST_CONGESTED);
+    case NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_METERED:
+      return (NLM_CONNECTION_COST_VARIABLE | NLM_CONNECTION_COST_ROAMING |
+              NLM_CONNECTION_COST_APPROACHINGDATALIMIT);
+    case NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN:
+    default:
+      return NLM_CONNECTION_COST_UNKNOWN;
+  }
+}
+
+void DispatchCostChangedEvent(ComPtr<INetworkCostManagerEvents> event_target,
+                              DWORD cost) {
+  std::ignore =
+      event_target->CostChanged(cost, /*destination_address=*/nullptr);
+}
+
+}  // namespace
+
+// A fake implementation of INetworkCostManager that can simulate costs, changed
+// costs and errors.
+class FakeNetworkCostManager final
+    : public RuntimeClass<RuntimeClassFlags<ClassicCom>,
+                          INetworkCostManager,
+                          IConnectionPointContainer,
+                          IConnectionPoint> {
+ public:
+  FakeNetworkCostManager(NetworkChangeNotifier::ConnectionCost connection_cost,
+                         NetworkCostManagerStatus error_status)
+      : error_status_(error_status), connection_cost_(connection_cost) {}
+
+  // For each event sink in `event_sinks_`, call
+  // `INetworkCostManagerEvents::CostChanged` with `changed_cost` on the event
+  // sink's task runner.
+  void PostCostChangedEvents(
+      NetworkChangeNotifier::ConnectionCost changed_cost) {
+    DWORD cost_for_changed_event;
+    std::map</*event_sink_cookie=*/DWORD, EventSinkRegistration>
+        event_sinks_for_changed_event;
+    {
+      base::AutoLock auto_lock(member_lock_);
+      connection_cost_ = changed_cost;
+      cost_for_changed_event =
+          NlmConnectionCostFlagsFromConnectionCost(changed_cost);
+
+      // Get the snapshot of event sinks to notify.  The snapshot collection
+      // creates a new ComPtr for each event sink, which increments each the
+      // event sink's reference count, ensuring that each event sink
+      // remains alive to receive the cost changed event notification.
+      event_sinks_for_changed_event = event_sinks_;
+    }
+
+    for (const auto& pair : event_sinks_for_changed_event) {
+      const auto& registration = pair.second;
+      registration.event_sink_task_runner_->PostTask(
+          FROM_HERE,
+          base::BindOnce(&DispatchCostChangedEvent, registration.event_sink_,
+                         cost_for_changed_event));
+    }
+  }
+
+  // Implement the INetworkCostManager interface.
+  HRESULT
+  __stdcall GetCost(DWORD* cost,
+                    NLM_SOCKADDR* destination_ip_address) override {
+    if (error_status_ == NetworkCostManagerStatus::kErrorGetCostFailed) {
+      return E_FAIL;
+    }
+
+    if (destination_ip_address != nullptr) {
+      NOTIMPLEMENTED();
+      return E_NOTIMPL;
+    }
+
+    {
+      base::AutoLock auto_lock(member_lock_);
+      *cost = NlmConnectionCostFlagsFromConnectionCost(connection_cost_);
+    }
+    return S_OK;
+  }
+
+  HRESULT __stdcall GetDataPlanStatus(
+      NLM_DATAPLAN_STATUS* data_plan_status,
+      NLM_SOCKADDR* destination_ip_address) override {
+    NOTIMPLEMENTED();
+    return E_NOTIMPL;
+  }
+
+  HRESULT __stdcall SetDestinationAddresses(
+      UINT32 length,
+      NLM_SOCKADDR* destination_ip_address_list,
+      VARIANT_BOOL append) override {
+    NOTIMPLEMENTED();
+    return E_NOTIMPL;
+  }
+
+  // Implement the IConnectionPointContainer interface.
+  HRESULT __stdcall FindConnectionPoint(REFIID connection_point_id,
+                                        IConnectionPoint** result) override {
+    if (error_status_ ==
+        NetworkCostManagerStatus::kErrorFindConnectionPointFailed) {
+      return E_ABORT;
+    }
+
+    if (connection_point_id != IID_INetworkCostManagerEvents) {
+      return E_NOINTERFACE;
+    }
+
+    *result = static_cast<IConnectionPoint*>(this);
+    AddRef();
+    return S_OK;
+  }
+
+  HRESULT __stdcall EnumConnectionPoints(
+      IEnumConnectionPoints** results) override {
+    NOTIMPLEMENTED();
+    return E_NOTIMPL;
+  }
+
+  // Implement the IConnectionPoint interface.
+  HRESULT __stdcall Advise(IUnknown* event_sink,
+                           DWORD* event_sink_cookie) override {
+    if (error_status_ == NetworkCostManagerStatus::kErrorAdviseFailed) {
+      return E_NOT_VALID_STATE;
+    }
+
+    ComPtr<INetworkCostManagerEvents> cost_manager_event_sink;
+    HRESULT hr =
+        event_sink->QueryInterface(IID_PPV_ARGS(&cost_manager_event_sink));
+    if (hr != S_OK) {
+      return hr;
+    }
+
+    base::AutoLock auto_lock(member_lock_);
+
+    event_sinks_[next_event_sink_cookie_] = {
+        cost_manager_event_sink, base::SequencedTaskRunnerHandle::Get()};
+
+    *event_sink_cookie = next_event_sink_cookie_;
+    ++next_event_sink_cookie_;
+
+    return S_OK;
+  }
+
+  HRESULT __stdcall Unadvise(DWORD event_sink_cookie) override {
+    base::AutoLock auto_lock(member_lock_);
+
+    auto it = event_sinks_.find(event_sink_cookie);
+    if (it == event_sinks_.end()) {
+      return ERROR_NOT_FOUND;
+    }
+
+    event_sinks_.erase(it);
+    return S_OK;
+  }
+
+  HRESULT __stdcall GetConnectionInterface(IID* result) override {
+    NOTIMPLEMENTED();
+    return E_NOTIMPL;
+  }
+
+  HRESULT __stdcall GetConnectionPointContainer(
+      IConnectionPointContainer** result) override {
+    NOTIMPLEMENTED();
+    return E_NOTIMPL;
+  }
+
+  HRESULT __stdcall EnumConnections(IEnumConnections** result) override {
+    NOTIMPLEMENTED();
+    return E_NOTIMPL;
+  }
+
+  // Implement the IUnknown interface.
+  HRESULT __stdcall QueryInterface(REFIID interface_id,
+                                   void** result) override {
+    if (error_status_ == NetworkCostManagerStatus::kErrorQueryInterfaceFailed) {
+      return E_NOINTERFACE;
+    }
+    return RuntimeClass<RuntimeClassFlags<ClassicCom>, INetworkCostManager,
+                        IConnectionPointContainer,
+                        IConnectionPoint>::QueryInterface(interface_id, result);
+  }
+
+  FakeNetworkCostManager(const FakeNetworkCostManager&) = delete;
+  FakeNetworkCostManager& operator=(const FakeNetworkCostManager&) = delete;
+
+ private:
+  // The error state for this FakeNetworkCostManager to simulate.  Cannot be
+  // changed.
+  const NetworkCostManagerStatus error_status_;
+
+  // Synchronizes access to all members below.
+  base::Lock member_lock_;
+
+  NetworkChangeNotifier::ConnectionCost connection_cost_
+      GUARDED_BY(member_lock_);
+
+  DWORD next_event_sink_cookie_ GUARDED_BY(member_lock_) = 0;
+
+  struct EventSinkRegistration {
+    ComPtr<INetworkCostManagerEvents> event_sink_;
+    scoped_refptr<base::SequencedTaskRunner> event_sink_task_runner_;
+  };
+  std::map</*event_sink_cookie=*/DWORD, EventSinkRegistration> event_sinks_
+      GUARDED_BY(member_lock_);
+};
+
+FakeNetworkCostManagerEnvironment::FakeNetworkCostManagerEnvironment() {
+  // Set up NetworkCostChangeNotifierWin to use the fake OS APIs.
+  NetworkCostChangeNotifierWin::OverrideCoCreateInstanceForTesting(
+      base::BindRepeating(
+          &FakeNetworkCostManagerEnvironment::FakeCoCreateInstance,
+          base::Unretained(this)));
+}
+
+FakeNetworkCostManagerEnvironment::~FakeNetworkCostManagerEnvironment() {
+  // Restore NetworkCostChangeNotifierWin to use the real OS APIs.
+  NetworkCostChangeNotifierWin::OverrideCoCreateInstanceForTesting(
+      NetworkCostChangeNotifierWin::CoCreateInstanceCallback());
+}
+
+HRESULT FakeNetworkCostManagerEnvironment::FakeCoCreateInstance(
+    REFCLSID class_id,
+    LPUNKNOWN outer_aggregate,
+    DWORD context_flags,
+    REFIID interface_id,
+    LPVOID* result) {
+  NetworkChangeNotifier::ConnectionCost connection_cost_for_new_instance;
+  NetworkCostManagerStatus error_status_for_new_instance;
+  {
+    base::AutoLock auto_lock(member_lock_);
+    connection_cost_for_new_instance = connection_cost_;
+    error_status_for_new_instance = error_status_;
+  }
+
+  if (error_status_for_new_instance ==
+      NetworkCostManagerStatus::kErrorCoCreateInstanceFailed) {
+    return E_ACCESSDENIED;
+  }
+
+  if (class_id != CLSID_NetworkListManager) {
+    return E_NOINTERFACE;
+  }
+
+  if (interface_id != IID_INetworkCostManager) {
+    return E_NOINTERFACE;
+  }
+
+  ComPtr<FakeNetworkCostManager> instance =
+      Microsoft::WRL::Make<FakeNetworkCostManager>(
+          connection_cost_for_new_instance, error_status_for_new_instance);
+  {
+    base::AutoLock auto_lock(member_lock_);
+    fake_network_cost_managers_.push_back(instance);
+  }
+  *result = instance.Detach();
+  return S_OK;
+}
+
+void FakeNetworkCostManagerEnvironment::SetCost(
+    NetworkChangeNotifier::ConnectionCost value) {
+  // Update the cost for each `INetworkCostManager` instance in
+  // `fake_network_cost_managers_`.
+  std::vector<Microsoft::WRL::ComPtr<FakeNetworkCostManager>>
+      fake_network_cost_managers_for_change_event;
+  {
+    base::AutoLock auto_lock(member_lock_);
+    connection_cost_ = value;
+    fake_network_cost_managers_for_change_event = fake_network_cost_managers_;
+  }
+
+  for (const auto& network_cost_manager :
+       fake_network_cost_managers_for_change_event) {
+    network_cost_manager->PostCostChangedEvents(/*connection_cost=*/value);
+  }
+}
+
+void FakeNetworkCostManagerEnvironment::SimulateError(
+    NetworkCostManagerStatus error_status) {
+  base::AutoLock auto_lock(member_lock_);
+  error_status_ = error_status;
+}
+
+}  // namespace net
diff --git a/net/test/win/fake_network_cost_manager.h b/net/test/win/fake_network_cost_manager.h
new file mode 100644
index 0000000..fd6348e
--- /dev/null
+++ b/net/test/win/fake_network_cost_manager.h
@@ -0,0 +1,84 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TEST_WIN_FAKE_NETWORK_COST_MANAGER_H_
+#define NET_TEST_WIN_FAKE_NETWORK_COST_MANAGER_H_
+
+#include <windows.h>
+#include <wrl/client.h>
+
+#include <vector>
+
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
+#include "net/base/network_change_notifier.h"
+
+namespace net {
+class FakeNetworkCostManager;
+
+// Each value represents a different Windows OS API that can fail when
+// monitoring the cost of network connections.  Use with
+// `FakeNetworkCostManagerEnvironment::SimulateError` to simulate Windows OS API
+// failures that return error HRESULTS.
+enum class NetworkCostManagerStatus {
+  kOk,
+  kErrorCoCreateInstanceFailed,
+  kErrorQueryInterfaceFailed,
+  kErrorFindConnectionPointFailed,
+  kErrorAdviseFailed,
+  kErrorGetCostFailed,
+};
+
+// Provides a fake implementation of the INetworkCostManager Windows OS API for
+// NetworkCostChangeNotifierWin.  Must be constructed before any
+// NetworkCostChangeNotifierWin instances exist.  Sets up the fake OS API in the
+// constructor and restores the real OS API in the destructor.  Tests should use
+// this class to simulate different network costs, cost changed events and
+// errors without depending on the actual OS APIs or current network
+// environment.
+class FakeNetworkCostManagerEnvironment {
+ public:
+  FakeNetworkCostManagerEnvironment();
+  ~FakeNetworkCostManagerEnvironment();
+
+  void SetCost(NetworkChangeNotifier::ConnectionCost value);
+  void SimulateError(NetworkCostManagerStatus error_status);
+
+  FakeNetworkCostManagerEnvironment(const FakeNetworkCostManagerEnvironment&) =
+      delete;
+  FakeNetworkCostManagerEnvironment& operator=(
+      const FakeNetworkCostManagerEnvironment&) = delete;
+
+ private:
+  // Creates a fake implementation of INetworkCostManager.
+  HRESULT FakeCoCreateInstance(REFCLSID class_id,
+                               LPUNKNOWN outer_aggregate,
+                               DWORD context_flags,
+                               REFIID interface_id,
+                               LPVOID* result);
+
+  // Members must be accessed while holding this lock to support the creation
+  // and use of `FakeNetworkCostManager` instances on any thread.
+  base::Lock member_lock_;
+
+  // The connection cost to simulate.
+  NetworkChangeNotifier::ConnectionCost connection_cost_
+      GUARDED_BY(member_lock_) =
+          NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN;
+
+  // When FakeNetworkCostManagerEnvironment creates a new
+  // FakeNetworkCostManager, the new FakeNetworkCostManager will simulate this
+  // error.
+  NetworkCostManagerStatus error_status_ GUARDED_BY(member_lock_) =
+      NetworkCostManagerStatus::kOk;
+
+  // Holds the fake implementations of INetworkCostManager constructed through
+  // FakeCoCreateInstance.
+  std::vector<Microsoft::WRL::ComPtr<FakeNetworkCostManager>>
+      fake_network_cost_managers_ GUARDED_BY(member_lock_);
+};
+
+}  // namespace net
+
+#endif  // NET_TEST_WIN_FAKE_NETWORK_COST_MANAGER_H_
diff --git a/printing/BUILD.gn b/printing/BUILD.gn
index 93ed16c2..a32beaa 100644
--- a/printing/BUILD.gn
+++ b/printing/BUILD.gn
@@ -194,7 +194,7 @@
     ]
   }
 
-  if (is_chromeos) {
+  if (!enable_basic_print_dialog) {
     sources += [
       "printing_context_no_system_dialog.cc",
       "printing_context_no_system_dialog.h",
diff --git a/printing/buildflags/BUILD.gn b/printing/buildflags/BUILD.gn
index 0e84856..fa102406 100644
--- a/printing/buildflags/BUILD.gn
+++ b/printing/buildflags/BUILD.gn
@@ -15,6 +15,7 @@
   flags = [
     "ENABLE_PRINTING=$enable_basic_printing",
     "ENABLE_PRINT_PREVIEW=$enable_print_preview",
+    "ENABLE_BASIC_PRINT_DIALOG=$enable_basic_print_dialog",
     "ENABLE_TAGGED_PDF=$enable_tagged_pdf",
     "ENABLE_OOP_PRINTING=$enable_oop_printing",
     "ENABLE_PRINT_CONTENT_ANALYSIS=$enable_print_content_analysis",
diff --git a/printing/buildflags/buildflags.gni b/printing/buildflags/buildflags.gni
index 4c7f9e2..6be6708 100644
--- a/printing/buildflags/buildflags.gni
+++ b/printing/buildflags/buildflags.gni
@@ -20,6 +20,10 @@
   # The is_android condition is currently redundant but left for clarity.
   enable_print_preview = enable_basic_printing && enable_pdf && !is_android
 
+  # Enable the printing system dialog for platforms that support printing
+  # and have a system dialog.
+  enable_basic_print_dialog = enable_basic_printing && !is_chromeos
+
   if (use_fuzzing_engine && (is_linux || is_chromeos)) {
     # For fuzzing, just restrict to chromeos and linux.
     use_cups = true
diff --git a/remoting/host/desktop_capturer_proxy.cc b/remoting/host/desktop_capturer_proxy.cc
index 6e0a3b4..dd845d0 100644
--- a/remoting/host/desktop_capturer_proxy.cc
+++ b/remoting/host/desktop_capturer_proxy.cc
@@ -32,6 +32,8 @@
 #endif
 
 #if defined(REMOTING_USE_WAYLAND)
+#include "base/environment.h"
+#include "base/nix/xdg_util.h"
 #include "remoting/host/linux/wayland_desktop_capturer.h"
 #endif
 
@@ -96,7 +98,14 @@
         std::make_unique<AuraDesktopCapturer>());
   }
 #elif defined(REMOTING_USE_WAYLAND)
-  if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
+  static base::nix::SessionType session_type = base::nix::SessionType::kUnset;
+  if (session_type == base::nix::SessionType::kUnset) {
+    std::unique_ptr<base::Environment> env = base::Environment::Create();
+    session_type = base::nix::GetSessionType(*env);
+  }
+
+  if (options.allow_pipewire() &&
+      session_type == base::nix::SessionType::kWayland) {
     // Even though wayland itself has mechanism to detect surface damage in a
     // fine grained fashion, the framebuffer handed over by the compositor over
     // to the pipewire stream contains the entire scene (and not just the delta)
diff --git a/remoting/host/desktop_resizer_x11.cc b/remoting/host/desktop_resizer_x11.cc
index 1ff28cd..922be16 100644
--- a/remoting/host/desktop_resizer_x11.cc
+++ b/remoting/host/desktop_resizer_x11.cc
@@ -421,9 +421,18 @@
                                                int height) {
   std::string mode_name = GetModeNameForOutput(output);
   DeleteMode(output, mode_name);
+
+  // Set some clock values so that the computed refresh-rate is a realistic
+  // number:
+  // 60Hz = dot_clock / (htotal * vtotal).
+  // This allows GNOME's Display Settings tool to apply new settings for
+  // resolution/scaling - see crbug.com/1374488.
   x11::RandR::ModeInfo mode;
   mode.width = width;
   mode.height = height;
+  mode.dot_clock = 60;
+  mode.htotal = 1;
+  mode.vtotal = 1;
   mode.name_len = mode_name.size();
   if (auto reply =
           randr_->CreateMode({root_, mode, mode_name.c_str()}).Sync()) {
diff --git a/remoting/host/linux/linux_me2me_host.py b/remoting/host/linux/linux_me2me_host.py
index b715ab4..8bce3906 100755
--- a/remoting/host/linux/linux_me2me_host.py
+++ b/remoting/host/linux/linux_me2me_host.py
@@ -1211,9 +1211,12 @@
     # the "-screen" option.
     if self.randr_add_sizes:
       for width, height in self.sizes:
+        # This sets dot-clock, vtotal and htotal such that the computed
+        # refresh-rate will have a realistic value:
+        # 60Hz = dot-clock / (vtotal * htotal).
         label = "%dx%d" % (width, height)
-        args = ["xrandr", "--newmode", label, "0", str(width), "0", "0", "0",
-                str(height), "0", "0", "0"]
+        args = ["xrandr", "--newmode", label, "60", str(width), "0", "0",
+                "1000", str(height), "0", "0", "1000"]
         subprocess.call(args, env=self.child_env, stdout=subprocess.DEVNULL,
                         stderr=subprocess.DEVNULL)
         output_name = "screen" if self.use_xvfb else "DUMMY0"
diff --git a/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.cc b/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.cc
index 296abdf..1ec9d44 100644
--- a/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.cc
+++ b/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.cc
@@ -25,8 +25,6 @@
   switch (type) {
     case viz::CompositorFrameTransitionDirective::Type::kSave:
       return viz::mojom::CompositorFrameTransitionDirectiveType::kSave;
-    case viz::CompositorFrameTransitionDirective::Type::kAnimate:
-      return viz::mojom::CompositorFrameTransitionDirectiveType::kAnimate;
     case viz::CompositorFrameTransitionDirective::Type::kAnimateRenderer:
       return viz::mojom::CompositorFrameTransitionDirectiveType::
           kAnimateRenderer;
@@ -46,9 +44,6 @@
     case viz::mojom::CompositorFrameTransitionDirectiveType::kSave:
       *out = viz::CompositorFrameTransitionDirective::Type::kSave;
       return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveType::kAnimate:
-      *out = viz::CompositorFrameTransitionDirective::Type::kAnimate;
-      return true;
     case viz::mojom::CompositorFrameTransitionDirectiveType::kAnimateRenderer:
       *out = viz::CompositorFrameTransitionDirective::Type::kAnimateRenderer;
       return true;
@@ -60,87 +55,6 @@
 }
 
 // static
-viz::mojom::CompositorFrameTransitionDirectiveEffect
-EnumTraits<viz::mojom::CompositorFrameTransitionDirectiveEffect,
-           viz::CompositorFrameTransitionDirective::Effect>::
-    ToMojom(viz::CompositorFrameTransitionDirective::Effect effect) {
-  switch (effect) {
-    case viz::CompositorFrameTransitionDirective::Effect::kNone:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kNone;
-    case viz::CompositorFrameTransitionDirective::Effect::kCoverDown:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverDown;
-    case viz::CompositorFrameTransitionDirective::Effect::kCoverLeft:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverLeft;
-    case viz::CompositorFrameTransitionDirective::Effect::kCoverRight:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverRight;
-    case viz::CompositorFrameTransitionDirective::Effect::kCoverUp:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverUp;
-    case viz::CompositorFrameTransitionDirective::Effect::kExplode:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kExplode;
-    case viz::CompositorFrameTransitionDirective::Effect::kFade:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kFade;
-    case viz::CompositorFrameTransitionDirective::Effect::kImplode:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kImplode;
-    case viz::CompositorFrameTransitionDirective::Effect::kRevealDown:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealDown;
-    case viz::CompositorFrameTransitionDirective::Effect::kRevealLeft:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealLeft;
-    case viz::CompositorFrameTransitionDirective::Effect::kRevealRight:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealRight;
-    case viz::CompositorFrameTransitionDirective::Effect::kRevealUp:
-      return viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealUp;
-  }
-  NOTREACHED();
-  return viz::mojom::CompositorFrameTransitionDirectiveEffect::kNone;
-}
-
-// static
-bool EnumTraits<viz::mojom::CompositorFrameTransitionDirectiveEffect,
-                viz::CompositorFrameTransitionDirective::Effect>::
-    FromMojom(viz::mojom::CompositorFrameTransitionDirectiveEffect input,
-              viz::CompositorFrameTransitionDirective::Effect* out) {
-  switch (input) {
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kNone:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kNone;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverDown:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kCoverDown;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverLeft:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kCoverLeft;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverRight:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kCoverRight;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverUp:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kCoverUp;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kExplode:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kExplode;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kFade:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kFade;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kImplode:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kImplode;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealDown:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kRevealDown;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealLeft:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kRevealLeft;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealRight:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kRevealRight;
-      return true;
-    case viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealUp:
-      *out = viz::CompositorFrameTransitionDirective::Effect::kRevealUp;
-      return true;
-  }
-  return false;
-}
-
-// static
 bool StructTraits<
     viz::mojom::CompositorFrameTransitionDirectiveSharedElementDataView,
     viz::CompositorFrameTransitionDirective::SharedElement>::
@@ -159,15 +73,13 @@
   uint32_t sequence_id = data.sequence_id();
 
   viz::CompositorFrameTransitionDirective::Type type;
-  viz::CompositorFrameTransitionDirective::Effect effect;
   std::vector<viz::CompositorFrameTransitionDirective::SharedElement>
       shared_elements;
-  if (!data.ReadType(&type) || !data.ReadEffect(&effect) ||
-      !data.ReadSharedElements(&shared_elements)) {
+  if (!data.ReadType(&type) || !data.ReadSharedElements(&shared_elements)) {
     return false;
   }
 
-  *out = viz::CompositorFrameTransitionDirective(sequence_id, type, effect,
+  *out = viz::CompositorFrameTransitionDirective(sequence_id, type,
                                                  std::move(shared_elements));
   return true;
 }
diff --git a/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h b/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h
index a6f3b12..8760ce3 100644
--- a/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h
+++ b/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h
@@ -26,17 +26,6 @@
 };
 
 template <>
-struct EnumTraits<viz::mojom::CompositorFrameTransitionDirectiveEffect,
-                  viz::CompositorFrameTransitionDirective::Effect> {
-  static viz::mojom::CompositorFrameTransitionDirectiveEffect ToMojom(
-      viz::CompositorFrameTransitionDirective::Effect type);
-
-  static bool FromMojom(
-      viz::mojom::CompositorFrameTransitionDirectiveEffect input,
-      viz::CompositorFrameTransitionDirective::Effect* out);
-};
-
-template <>
 struct StructTraits<
     viz::mojom::CompositorFrameTransitionDirectiveSharedElementDataView,
     viz::CompositorFrameTransitionDirective::SharedElement> {
@@ -68,11 +57,6 @@
     return directive.type();
   }
 
-  static viz::CompositorFrameTransitionDirective::Effect effect(
-      const viz::CompositorFrameTransitionDirective& directive) {
-    return directive.effect();
-  }
-
   static std::vector<viz::CompositorFrameTransitionDirective::SharedElement>
   shared_elements(const viz::CompositorFrameTransitionDirective& directive) {
     return directive.shared_elements();
diff --git a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
index f341884..948979a 100644
--- a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
@@ -623,8 +623,7 @@
   element.render_pass_id = frame.render_pass_list.front()->id;
   frame.metadata.transition_directives.push_back(
       CompositorFrameTransitionDirective(
-          1u, CompositorFrameTransitionDirective::Type::kSave,
-          CompositorFrameTransitionDirective::Effect::kNone, {element}));
+          1u, CompositorFrameTransitionDirective::Type::kSave, {element}));
 
   // This ensures de-serialization succeeds if all passes are present.
   CompositorFrame output;
@@ -635,8 +634,7 @@
       frame.render_pass_list.back()->id.GetUnsafeValue() + 1);
   frame.metadata.transition_directives.push_back(
       CompositorFrameTransitionDirective(
-          1u, CompositorFrameTransitionDirective::Type::kSave,
-          CompositorFrameTransitionDirective::Effect::kNone, {element}));
+          1u, CompositorFrameTransitionDirective::Type::kSave, {element}));
 
   // This ensures de-serialization fails if a pass is missing.
   ASSERT_FALSE(mojo::test::SerializeAndDeserialize<mojom::CompositorFrame>(
diff --git a/services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom b/services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom
index 78dbce45b..351577d 100644
--- a/services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom
+++ b/services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom
@@ -9,26 +9,10 @@
 
 enum CompositorFrameTransitionDirectiveType {
   kSave,
-  kAnimate,
   kAnimateRenderer,
   kRelease
 };
 
-enum CompositorFrameTransitionDirectiveEffect {
-  kNone,
-  kCoverDown,
-  kCoverLeft,
-  kCoverRight,
-  kCoverUp,
-  kExplode,
-  kFade,
-  kImplode,
-  kRevealDown,
-  kRevealLeft,
-  kRevealRight,
-  kRevealUp
-};
-
 // This struct identifes a shared element.
 struct CompositorFrameTransitionDirectiveSharedElement {
   CompositorRenderPassId render_pass_id;
@@ -46,9 +30,6 @@
   // The type of this directive.
   CompositorFrameTransitionDirectiveType type;
 
-  // The effect for the transition.
-  CompositorFrameTransitionDirectiveEffect effect;
-
   // A collection of shared elements.
   array<CompositorFrameTransitionDirectiveSharedElement> shared_elements;
 };
diff --git a/storage/browser/file_system/file_system_quota_client.cc b/storage/browser/file_system/file_system_quota_client.cc
index 87114511..85ef854 100644
--- a/storage/browser/file_system/file_system_quota_client.cc
+++ b/storage/browser/file_system/file_system_quota_client.cc
@@ -35,8 +35,6 @@
     kFileSystemTypeTemporary,
     kFileSystemTypePersistent,
 };
-static const FileSystemType kTemporary[] = {kFileSystemTypeTemporary};
-static const FileSystemType kPersistent[] = {kFileSystemTypePersistent};
 static const FileSystemType kSyncable[] = {kFileSystemTypeSyncable};
 
 template <typename T>
@@ -63,19 +61,13 @@
     blink::mojom::StorageType storage_type) {
   using StorageType = blink::mojom::StorageType;
 
-  if (blink::features::IsPersistentQuotaIsTemporaryQuota()) {
-    DCHECK_NE(storage_type, StorageType::kPersistent);
-    if (storage_type == StorageType::kTemporary)
-      return kTemporaryAndPersistent;
-  }
   switch (storage_type) {
     case StorageType::kTemporary:
-      return kTemporary;
-    case StorageType::kPersistent:
-      return kPersistent;
+      return kTemporaryAndPersistent;
     case StorageType::kSyncable:
       return kSyncable;
     case StorageType::kDeprecatedQuotaNotManaged:
+    case StorageType::kPersistent:
     case StorageType::kUnknown:
       NOTREACHED();
       return {};
diff --git a/storage/browser/file_system/file_system_quota_client_unittest.cc b/storage/browser/file_system/file_system_quota_client_unittest.cc
index e86eefc..aabe667 100644
--- a/storage/browser/file_system/file_system_quota_client_unittest.cc
+++ b/storage/browser/file_system/file_system_quota_client_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
 #include "base/threading/sequenced_task_runner_handle.h"
@@ -34,7 +33,6 @@
 #include "storage/common/file_system/file_system_util.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/storage_key/storage_key.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 #include "url/gurl.h"
@@ -52,11 +50,10 @@
 
 // Declared to shorten the variable names.
 const StorageType kTemporary = StorageType::kTemporary;
-const StorageType kPersistent = StorageType::kPersistent;
 
 }  // namespace
 
-class FileSystemQuotaClientTest : public testing::TestWithParam<bool> {
+class FileSystemQuotaClientTest : public testing::Test {
  public:
   FileSystemQuotaClientTest()
       : special_storage_policy_(
@@ -65,13 +62,6 @@
   ~FileSystemQuotaClientTest() override = default;
 
   void SetUp() override {
-    if (persistent_quota_is_temporary_quota()) {
-      feature_list_.InitAndEnableFeature(
-          blink::features::kPersistentQuotaIsTemporaryQuota);
-    } else {
-      feature_list_.InitAndDisableFeature(
-          blink::features::kPersistentQuotaIsTemporaryQuota);
-    }
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
 
     quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
@@ -84,8 +74,6 @@
         quota_manager_proxy_, data_dir_.GetPath());
   }
 
-  bool persistent_quota_is_temporary_quota() const { return GetParam(); }
-
   struct TestFile {
     bool isDirectory;
     const char* name;
@@ -261,7 +249,6 @@
  protected:
   scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
 
-  base::test::ScopedFeatureList feature_list_;
   base::ScopedTempDir data_dir_;
   base::test::TaskEnvironment task_environment_;
 
@@ -275,14 +262,14 @@
   base::WeakPtrFactory<FileSystemQuotaClientTest> weak_factory_{this};
 };
 
-TEST_P(FileSystemQuotaClientTest, NoFileSystemTest) {
+TEST_F(FileSystemQuotaClientTest, NoFileSystemTest) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
 
   auto bucket = GetOrCreateBucket(kDummyURL1, kDefaultBucketName, kTemporary);
   EXPECT_EQ(0, GetBucketUsage(quota_client, bucket));
 }
 
-TEST_P(FileSystemQuotaClientTest, NoFileTest) {
+TEST_F(FileSystemQuotaClientTest, NoFileTest) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
 
   InitializeOriginFiles(quota_client,
@@ -294,7 +281,7 @@
   }
 }
 
-TEST_P(FileSystemQuotaClientTest, NonDefaultBucket) {
+TEST_F(FileSystemQuotaClientTest, NonDefaultBucket) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
   auto bucket = GetOrCreateBucket(kDummyURL1, "logs_bucket", kTemporary);
   ASSERT_FALSE(bucket.is_default);
@@ -302,7 +289,7 @@
   DeleteBucketData(&quota_client, bucket);
 }
 
-TEST_P(FileSystemQuotaClientTest, OneFileTest) {
+TEST_F(FileSystemQuotaClientTest, OneFileTest) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
 
   const std::vector<TestFile> kFiles = {
@@ -319,7 +306,7 @@
   }
 }
 
-TEST_P(FileSystemQuotaClientTest, TwoFilesTest) {
+TEST_F(FileSystemQuotaClientTest, TwoFilesTest) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
   const std::vector<TestFile> kFiles = {
       {true, "", 0, kDummyURL1, kFileSystemTypeTemporary},
@@ -337,7 +324,7 @@
   }
 }
 
-TEST_P(FileSystemQuotaClientTest, EmptyFilesTest) {
+TEST_F(FileSystemQuotaClientTest, EmptyFilesTest) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
   const std::vector<TestFile> kFiles = {
       {true, "", 0, kDummyURL1, kFileSystemTypeTemporary},
@@ -355,7 +342,7 @@
   }
 }
 
-TEST_P(FileSystemQuotaClientTest, SubDirectoryTest) {
+TEST_F(FileSystemQuotaClientTest, SubDirectoryTest) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
   const std::vector<TestFile> kFiles = {
       {true, "", 0, kDummyURL1, kFileSystemTypeTemporary},
@@ -374,7 +361,7 @@
   }
 }
 
-TEST_P(FileSystemQuotaClientTest, MultiTypeTest) {
+TEST_F(FileSystemQuotaClientTest, MultiTypeTest) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
   const std::vector<TestFile> kFiles = {
       {true, "", 0, kDummyURL1, kFileSystemTypeTemporary},
@@ -395,23 +382,14 @@
                                            kFileSystemTypePersistent);
 
   for (int i = 0; i < 2; i++) {
-    if (persistent_quota_is_temporary_quota()) {
-      auto bucket = GetBucket(kDummyURL1, kDefaultBucketName, kTemporary);
-      EXPECT_EQ(133 + 14 + file_paths_cost_temporary + 193 + 9 +
-                    file_paths_cost_persistent,
-                GetBucketUsage(quota_client, bucket));
-    } else {
-      auto bucket_temp = GetBucket(kDummyURL1, kDefaultBucketName, kTemporary);
-      auto bucket_perm = GetBucket(kDummyURL1, kDefaultBucketName, kPersistent);
-      EXPECT_EQ(133 + 14 + file_paths_cost_temporary,
-                GetBucketUsage(quota_client, bucket_temp));
-      EXPECT_EQ(193 + 9 + file_paths_cost_persistent,
-                GetBucketUsage(quota_client, bucket_perm));
-    }
+    auto bucket = GetBucket(kDummyURL1, kDefaultBucketName, kTemporary);
+    EXPECT_EQ(133 + 14 + file_paths_cost_temporary + 193 + 9 +
+                  file_paths_cost_persistent,
+              GetBucketUsage(quota_client, bucket));
   }
 }
 
-TEST_P(FileSystemQuotaClientTest, MultiDomainTest) {
+TEST_F(FileSystemQuotaClientTest, MultiDomainTest) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
   const std::vector<TestFile> kFiles = {
       {true, "", 0, kDummyURL1, kFileSystemTypeTemporary},
@@ -446,35 +424,18 @@
                                            kFileSystemTypePersistent);
 
   for (int i = 0; i < 2; i++) {
-    if (persistent_quota_is_temporary_quota()) {
-      auto bucket1 = GetBucket(kDummyURL1, kDefaultBucketName, kTemporary);
-      auto bucket2 = GetBucket(kDummyURL2, kDefaultBucketName, kTemporary);
-      EXPECT_EQ(1331 + 134 + file_paths_cost_temporary1 + 1903 + 19 +
-                    file_paths_cost_persistent1,
-                GetBucketUsage(quota_client, bucket1));
-      EXPECT_EQ(1319 + 113 + file_paths_cost_temporary2 + 2013 + 18 +
-                    file_paths_cost_persistent2,
-                GetBucketUsage(quota_client, bucket2));
-    } else {
-      auto bucket1_temp = GetBucket(kDummyURL1, kDefaultBucketName, kTemporary);
-      auto bucket1_perm =
-          GetBucket(kDummyURL1, kDefaultBucketName, kPersistent);
-      auto bucket2_temp = GetBucket(kDummyURL2, kDefaultBucketName, kTemporary);
-      auto bucket2_perm =
-          GetBucket(kDummyURL2, kDefaultBucketName, kPersistent);
-      EXPECT_EQ(1331 + 134 + file_paths_cost_temporary1,
-                GetBucketUsage(quota_client, bucket1_temp));
-      EXPECT_EQ(1903 + 19 + file_paths_cost_persistent1,
-                GetBucketUsage(quota_client, bucket1_perm));
-      EXPECT_EQ(1319 + 113 + file_paths_cost_temporary2,
-                GetBucketUsage(quota_client, bucket2_temp));
-      EXPECT_EQ(2013 + 18 + file_paths_cost_persistent2,
-                GetBucketUsage(quota_client, bucket2_perm));
-    }
+    auto bucket1 = GetBucket(kDummyURL1, kDefaultBucketName, kTemporary);
+    auto bucket2 = GetBucket(kDummyURL2, kDefaultBucketName, kTemporary);
+    EXPECT_EQ(1331 + 134 + file_paths_cost_temporary1 + 1903 + 19 +
+                  file_paths_cost_persistent1,
+              GetBucketUsage(quota_client, bucket1));
+    EXPECT_EQ(1319 + 113 + file_paths_cost_temporary2 + 2013 + 18 +
+                  file_paths_cost_persistent2,
+              GetBucketUsage(quota_client, bucket2));
   }
 }
 
-TEST_P(FileSystemQuotaClientTest, GetUsage_MultipleTasks) {
+TEST_F(FileSystemQuotaClientTest, GetUsage_MultipleTasks) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
   const std::vector<TestFile> kFiles = {
       {true, "", 0, kDummyURL1, kFileSystemTypeTemporary},
@@ -505,7 +466,7 @@
   EXPECT_EQ(2, additional_callback_count());
 }
 
-TEST_P(FileSystemQuotaClientTest, GetStorageKeysForType) {
+TEST_F(FileSystemQuotaClientTest, GetStorageKeysForType) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
   InitializeOriginFiles(
       quota_client, {
@@ -514,21 +475,14 @@
                         {true, "", 0, kDummyURL3, kFileSystemTypePersistent},
                     });
 
-  if (persistent_quota_is_temporary_quota()) {
-    EXPECT_THAT(GetStorageKeysForType(quota_client, kTemporary),
-                testing::UnorderedElementsAre(
-                    StorageKey::CreateFromStringForTesting(kDummyURL1),
-                    StorageKey::CreateFromStringForTesting(kDummyURL2),
-                    StorageKey::CreateFromStringForTesting(kDummyURL3)));
-  } else {
-    EXPECT_THAT(GetStorageKeysForType(quota_client, kTemporary),
-                testing::UnorderedElementsAre(
-                    StorageKey::CreateFromStringForTesting(kDummyURL1),
-                    StorageKey::CreateFromStringForTesting(kDummyURL2)));
-  }
+  EXPECT_THAT(GetStorageKeysForType(quota_client, kTemporary),
+              testing::UnorderedElementsAre(
+                  StorageKey::CreateFromStringForTesting(kDummyURL1),
+                  StorageKey::CreateFromStringForTesting(kDummyURL2),
+                  StorageKey::CreateFromStringForTesting(kDummyURL3)));
 }
 
-TEST_P(FileSystemQuotaClientTest, DeleteOriginTest) {
+TEST_F(FileSystemQuotaClientTest, DeleteOriginTest) {
   FileSystemQuotaClient quota_client(GetFileSystemContext());
   const std::vector<TestFile> kFiles = {
       {true, "", 0, "http://foo.com/", kFileSystemTypeTemporary},
@@ -567,12 +521,6 @@
       GetBucket("http://foo.com/", kDefaultBucketName, kTemporary);
   DeleteBucketData(&quota_client, foo_temp_bucket);
 
-  if (!persistent_quota_is_temporary_quota()) {
-    auto foo_perm_bucket =
-        GetBucket("http://bar.com/", kDefaultBucketName, kPersistent);
-    DeleteBucketData(&quota_client, foo_perm_bucket);
-  }
-
   auto buz_temp_bucket =
       GetOrCreateBucket("http://buz.com/", kDefaultBucketName, kTemporary);
   DeleteBucketData(&quota_client, buz_temp_bucket);
@@ -587,23 +535,15 @@
 
   auto bar_temp_bucket =
       GetBucket("http://bar.com/", kDefaultBucketName, kTemporary);
-  EXPECT_EQ(8 + file_paths_cost_temporary_bar +
-                (persistent_quota_is_temporary_quota()
-                     ? 16 + file_paths_cost_persistent_bar
-                     : 0),
-            GetBucketUsage(quota_client, bar_temp_bucket));
+  EXPECT_EQ(
+      8 + file_paths_cost_temporary_bar + 16 + file_paths_cost_persistent_bar,
+      GetBucketUsage(quota_client, bar_temp_bucket));
 
   auto bar_https_temp_bucket =
       GetBucket("https://bar.com/", kDefaultBucketName, kTemporary);
-  EXPECT_EQ(64 + file_paths_cost_temporary_bar_https +
-                (persistent_quota_is_temporary_quota()
-                     ? 32 + file_paths_cost_persistent_bar_https
-                     : 0),
+  EXPECT_EQ(64 + file_paths_cost_temporary_bar_https + 32 +
+                file_paths_cost_persistent_bar_https,
             GetBucketUsage(quota_client, bar_https_temp_bucket));
 }
 
-INSTANTIATE_TEST_SUITE_P(FileSystemQuotaClientTests,
-                         FileSystemQuotaClientTest,
-                         testing::Bool());
-
 }  // namespace storage
diff --git a/storage/browser/file_system/file_system_util.cc b/storage/browser/file_system/file_system_util.cc
index f0d091c..e5d776e 100644
--- a/storage/browser/file_system/file_system_util.cc
+++ b/storage/browser/file_system/file_system_util.cc
@@ -5,22 +5,16 @@
 #include "storage/browser/file_system/file_system_util.h"
 
 #include "storage/common/file_system/file_system_types.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
 
 namespace storage {
 
 blink::mojom::StorageType FileSystemTypeToQuotaStorageType(
     FileSystemType type) {
-  if (blink::features::IsPersistentQuotaIsTemporaryQuota() &&
-      (type == kFileSystemTypeTemporary || type == kFileSystemTypePersistent)) {
-    return blink::mojom::StorageType::kTemporary;
-  }
   switch (type) {
     case kFileSystemTypeTemporary:
-      return blink::mojom::StorageType::kTemporary;
     case kFileSystemTypePersistent:
-      return blink::mojom::StorageType::kPersistent;
+      return blink::mojom::StorageType::kTemporary;
     case kFileSystemTypeSyncable:
     case kFileSystemTypeSyncableForInternalSync:
       return blink::mojom::StorageType::kSyncable;
diff --git a/testing/BUILD.gn b/testing/BUILD.gn
index 3d5423a..8f6c446 100644
--- a/testing/BUILD.gn
+++ b/testing/BUILD.gn
@@ -61,13 +61,12 @@
   ]
 }
 
-# Could be changed to "testing_pytype" if type hinting is ever added to other
-# code in the directory.
-group("unexpected_passes_common_pytype") {
+group("testing_pytype") {
   data = [
     "//testing/run_pytype.py",
 
     "//testing/unexpected_passes_common/",
+    "//testing/flake_suppressor_common/",
     "//third_party/catapult/third_party/typ/",
   ]
 
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 7186b0a..18bebcc 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -28669,7 +28669,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
+          "shards": 4
         },
         "test": "chrome_public_unit_test_apk",
         "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 4bbb59b..708ac6a 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -104786,13 +104786,13 @@
         "test_id_prefix": "ninja://chrome/test:telemetry_unittests/"
       },
       {
-        "isolate_name": "unexpected_passes_common_pytype",
+        "isolate_name": "testing_pytype",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "unexpected_passes_common_pytype",
+        "name": "testing_pytype",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -104808,7 +104808,7 @@
           "expiration": 43200,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test_id_prefix": "ninja://testing:unexpected_passes_common_pytype/"
+        "test_id_prefix": "ninja://testing:testing_pytype/"
       },
       {
         "args": [
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 0f39f23..ed2a7898 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -4028,13 +4028,13 @@
         "test_id_prefix": "ninja://chrome/test:telemetry_unittests/"
       },
       {
-        "isolate_name": "unexpected_passes_common_pytype",
+        "isolate_name": "testing_pytype",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "unexpected_passes_common_pytype",
+        "name": "testing_pytype",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -4048,7 +4048,7 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test_id_prefix": "ninja://testing:unexpected_passes_common_pytype/"
+        "test_id_prefix": "ninja://testing:testing_pytype/"
       },
       {
         "args": [
diff --git a/testing/buildbot/filters/mac.mac12-arm64-rel.browser_tests.filter b/testing/buildbot/filters/mac.mac12-arm64-rel.browser_tests.filter
index 1285ad1f..a0409ce0 100644
--- a/testing/buildbot/filters/mac.mac12-arm64-rel.browser_tests.filter
+++ b/testing/buildbot/filters/mac.mac12-arm64-rel.browser_tests.filter
@@ -114,8 +114,6 @@
 -ProfilePickerLocalProfileCreationDialogBrowserTest.CancelLocalProfileCreation
 -ReaderModeIconViewBrowserTest.NonSecurePagesNotDistillable
 -RealboxSearchPreloadBrowserTest.SearchPreloadSuccess
--RegionCaptureBrowserTest.CropToAllowedIfEmbeddedFrameCropsToElementInEmbedded
--RegionCaptureClonesBrowserTest.CannotUncropClone
 -RegionCaptureBrowserCropTestInstantiation/RegionCaptureBrowserCropTest.CanCropTo/0
 -RegionCaptureBrowserCropTestInstantiation/RegionCaptureBrowserCropTest.CanCropTo/5
 -RegionCaptureBrowserCropTestInstantiation/RegionCaptureBrowserCropTest.CanCropTo/6
@@ -132,6 +130,10 @@
 -RegionCaptureBrowserCropTestInstantiation/RegionCaptureBrowserCropTest.CanCropTo/17
 -RegionCaptureBrowserTest.CropToAllowedIfEmbeddedFrameCropsToElementInEmbedded
 -RegionCaptureBrowserTest.CropToAllowedIfTopLevelCropsToElementInTopLevel
+-RegionCaptureClonesBrowserTest.CanCloneCroppedTracks
+-RegionCaptureClonesBrowserTest.CannotRecropClone
+-RegionCaptureClonesBrowserTest.CannotRecropTrackThatHasClone
+-RegionCaptureClonesBrowserTest.CannotUncropClone
 -RestoreOnStartupPolicyTestInstance/RestoreOnStartupPolicyTest.RunTest/3
 -SaveAsMhtml/SavePageOriginalVsSavedComparisonTest.NestedFrames/0
 -SavePageOriginalVsSavedComparisonTest.AboutBlank/0
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 8ace46e..e462da3 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1851,8 +1851,8 @@
     "label": "//ui/touch_selection:ui_touch_selection_unittests",
     "type": "windowed_test_launcher",
   },
-  "unexpected_passes_common_pytype": {
-    "label": "//testing:unexpected_passes_common_pytype",
+  "testing_pytype": {
+    "label": "//testing:testing_pytype",
     "script": "//testing/run_pytype.py",
     "type": "script",
   },
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 088fdc75..0f80817 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1233,6 +1233,16 @@
       },
     },
   },
+  # TODO(crbug/1239300): Remove when experiment is done.
+  'chrome_public_persistent_shell_unit_test_apk': {
+    'modifications': {
+      'android-nougat-x86-rel': {
+        'swarming': {
+          'shards': 4,
+        },
+      },
+    },
+  },
   'chrome_public_smoke_test': {
     'remove_from': [
       'android-code-coverage-native', # Does not generate profraw data.
@@ -3426,6 +3436,11 @@
       'linux_optional_gpu_tests_rel',  # crbug.com/1080749
     ],
   },
+  'testing_pytype': {
+    'remove_from': [
+      'linux-code-coverage',
+    ],
+  },
   'trace_test': {
     'remove_from': [
       # Trace tests currently don't work on non-rooted devices due to a private
@@ -3441,11 +3456,6 @@
       },
     },
   },
-  'unexpected_passes_common_pytype': {
-    'remove_from': [
-      'linux-code-coverage',
-    ],
-  },
   'unit_tests': {
     'remove_from': [
       'android-pie-arm64-rel',  # https://crbug.com/1010211
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 8997b6c..31eb8afa 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4277,7 +4277,7 @@
           'has_native_resultdb_integration',
         ],
       },
-      'unexpected_passes_common_pytype': {
+      'testing_pytype': {
         'mixins': [
           'has_native_resultdb_integration',
         ],
diff --git a/testing/run_pytype.py b/testing/run_pytype.py
index c235b8cc..fdb0b0ce 100755
--- a/testing/run_pytype.py
+++ b/testing/run_pytype.py
@@ -22,6 +22,7 @@
 
 FILES_AND_DIRECTORIES_TO_CHECK = [
     'unexpected_passes_common',
+    'flake_suppressor_common',
 ]
 FILES_AND_DIRECTORIES_TO_CHECK = [
     os.path.join(TESTING_DIR, f) for f in FILES_AND_DIRECTORIES_TO_CHECK
diff --git a/testing/scripts/check_static_initializers.py b/testing/scripts/check_static_initializers.py
index dee16012..7627090c 100755
--- a/testing/scripts/check_static_initializers.py
+++ b/testing/scripts/check_static_initializers.py
@@ -23,8 +23,8 @@
     'chrome': [
         'InstrProfilingRuntime.cpp',  # Only in coverage builds, not production.
         'atomicops_internals_x86.cc',  # TODO(crbug.com/973551): Remove.
-        'iostream.cpp:',  # TODO(crbug.com/973554): Remove.
-        '000100',   # libc++ uses init_priority 100 for iostreams.
+        'crtstuff.c',  # Added by libgcc due to USE_EH_FRAME_REGISTRY.
+        'iostream.cpp',  # TODO(crbug.com/973554): Remove.
         'spinlock.cc',  # TODO(crbug.com/973556): Remove.
     ],
     'nacl_helper_bootstrap': [],
@@ -168,32 +168,24 @@
 
     dump_static_initializers = os.path.join(src_dir, 'tools', 'linux',
                                             'dump-static-initializers.py')
-    stdout = run_process([dump_static_initializers, '-d', binary_name])
-    # The output has the following format:
-    # First lines: '# <file_name> <si_name>'
-    # Last line: '# Found <num> static initializers in <num> files.'
-    #
-    # For example:
-    # # spinlock.cc GetSystemCPUsCount()
-    # # spinlock.cc adaptive_spin_count
-    # # Found 2 static initializers in 1 files.
+    stdout = run_process([dump_static_initializers, '--json', binary_name])
+    entries = json.loads(stdout)['entries']
 
-    files_with_si = set()
-    for line in stdout.splitlines()[:-1]:
-      parts = line.split(' ', 2)
-      assert len(parts) == 3 and parts[0] == '#'
-
-      files_with_si.add(parts[1])
-
-    for f in files_with_si:
-      if f not in allowlist[binary_name]:
+    for e in entries:
+      # Also remove line number suffix.
+      basename = os.path.basename(e['filename']).split(':')[0]
+      if basename not in allowlist[binary_name]:
         ret = 1
         print(('Error: file "%s" is not expected to have static initializers in'
-              ' binary "%s"') % (f, binary_name))
+               ' binary "%s", but found "%s"') % (e['filename'], binary_name,
+                                                  e['symbol_name']))
 
     print('\n# Static initializers in %s:' % binary_name)
-    print(stdout)
+    for e in entries:
+      print('# 0x%x %s %s' % (e['address'], e['filename'], e['symbol_name']))
+      print(e['disassembly'])
 
+    print('Found %d files containing static initializers.' % len(entries))
   return ret
 
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 2c10681..e214748 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -413,12 +413,13 @@
             ],
             "experiments": [
                 {
-                    "name": "Holdback_20221012",
+                    "name": "Holdback_20221013",
                     "enable_features": [
                         "AndroidBatteryMetricsReportOnUIThread"
                     ],
                     "disable_features": [
-                        "AndroidScrollOptimizations"
+                        "AndroidScrollOptimizations",
+                        "ToolbarPhoneOptimizations"
                     ]
                 }
             ]
@@ -1314,29 +1315,6 @@
             ]
         }
     ],
-    "AutofillParseMerchantPromoCodeFields": [
-        {
-            "platforms": [
-                "android",
-                "android_webview",
-                "chromeos",
-                "chromeos_lacros",
-                "fuchsia",
-                "ios",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "AutofillParseMerchantPromoCodeFields"
-                    ]
-                }
-            ]
-        }
-    ],
     "AutofillPreventOverridingPrefilledFieldValue": [
         {
             "platforms": [
@@ -2034,6 +2012,21 @@
             ]
         }
     ],
+    "BluetoothQualityReport": [
+        {
+            "platforms": [
+                "chromeos"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_20221013",
+                    "enable_features": [
+                        "BluetoothQualityReport"
+                    ]
+                }
+            ]
+        }
+    ],
     "BrowserPeriodicYieldingToNative": [
         {
             "platforms": [
@@ -3124,26 +3117,6 @@
             ]
         }
     ],
-    "ConsolidatedSiteStorageControls": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "fuchsia",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "ConsolidatedSiteStorageControls"
-                    ]
-                }
-            ]
-        }
-    ],
     "ContentCaptureExperiment": [
         {
             "platforms": [
@@ -3400,6 +3373,7 @@
                 "chromeos",
                 "chromeos_lacros",
                 "fuchsia",
+                "ios",
                 "linux",
                 "mac",
                 "windows"
@@ -4214,26 +4188,6 @@
             ]
         }
     ],
-    "DnsHttpsSvcbSchemeUpgrade": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "fuchsia",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_20221001",
-                    "enable_features": [
-                        "UseDnsHttpsSvcbAlpn"
-                    ]
-                }
-            ]
-        }
-    ],
     "DnsOverHttpsCox": [
         {
             "platforms": [
@@ -5533,21 +5487,6 @@
             ]
         }
     ],
-    "IOSCrashReportBreadcrumbs": [
-        {
-            "platforms": [
-                "ios"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "LogBreadcrumbs"
-                    ]
-                }
-            ]
-        }
-    ],
     "IOSDefaultBrowserFullscreenPromoExperiment": [
         {
             "platforms": [
@@ -6955,6 +6894,25 @@
             ]
         }
     ],
+    "MojoIpcz": [
+        {
+            "platforms": [
+                "android",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "MojoIpcz"
+                    ]
+                }
+            ]
+        }
+    ],
     "MuteCompromisedPasswords": [
         {
             "platforms": [
@@ -8021,6 +7979,30 @@
             ]
         }
     ],
+    "PartitionAllocUnretainedDanglingPtr": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "chromeos_lacros",
+                "fuchsia",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "mode": "dump_without_crashing"
+                    },
+                    "enable_features": [
+                        "PartitionAllocUnretainedDanglingPtr"
+                    ]
+                }
+            ]
+        }
+    ],
     "PartitionAllocUseAlternateDistribution": [
         {
             "platforms": [
@@ -8047,7 +8029,7 @@
             ]
         }
     ],
-    "PartitionNetworkStateByDoubleKey": [
+    "PartitionNetworkStateByNetworkAnonymizationKey": [
         {
             "platforms": [
                 "android",
@@ -8061,7 +8043,7 @@
             ],
             "experiments": [
                 {
-                    "name": "enabled_doublekey",
+                    "name": "enabled_double_key",
                     "enable_features": [
                         "EnableDoubleKeyNetworkAnonymizationKey",
                         "ForceIsolationInfoFrameOriginToTopLevelFrame",
@@ -8075,7 +8057,7 @@
                     ]
                 },
                 {
-                    "name": "enabled_triplekey",
+                    "name": "enabled_triple_key",
                     "enable_features": [
                         "PartitionConnectionsByNetworkIsolationKey",
                         "PartitionDomainReliabilityByNetworkIsolationKey",
@@ -8087,7 +8069,7 @@
                     ]
                 },
                 {
-                    "name": "enabled_triple_double_key",
+                    "name": "enabled_triple_nik_double_nak",
                     "enable_features": [
                         "EnableDoubleKeyNetworkAnonymizationKey",
                         "PartitionConnectionsByNetworkIsolationKey",
@@ -8100,7 +8082,7 @@
                     ]
                 },
                 {
-                    "name": "enabled_triple_double_cross_site_key",
+                    "name": "enabled_triple_nik_cross_site_flag_nak",
                     "enable_features": [
                         "PartitionConnectionsByNetworkIsolationKey",
                         "PartitionDomainReliabilityByNetworkIsolationKey",
@@ -10673,21 +10655,6 @@
             ]
         }
     ],
-    "ToolbarPhoneOptimizations": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "ToolbarPhoneOptimizations"
-                    ]
-                }
-            ]
-        }
-    ],
     "TopChromeWebUIUsesSpareRenderer": [
         {
             "platforms": [
@@ -10978,6 +10945,26 @@
             ]
         }
     ],
+    "UseDnsHttpsSvcbAlpn": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "fuchsia",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_20221013",
+                    "enable_features": [
+                        "UseDnsHttpsSvcbAlpn"
+                    ]
+                }
+            ]
+        }
+    ],
     "UseGetrandomForRandBytes": [
         {
             "platforms": [
diff --git a/third_party/android_build_tools/lint/rebuild_baselines.py b/third_party/android_build_tools/lint/rebuild_baselines.py
index 8c708d86..5832dd3 100755
--- a/third_party/android_build_tools/lint/rebuild_baselines.py
+++ b/third_party/android_build_tools/lint/rebuild_baselines.py
@@ -16,7 +16,7 @@
 _AUTONINJA_PATH = _SRC_PATH / 'third_party' / 'depot_tools' / 'autoninja'
 _NINJA_PATH = _SRC_PATH / 'third_party' / 'depot_tools' / 'ninja'
 _GN_PATH = _SRC_PATH / 'third_party' / 'depot_tools' / 'gn'
-_CHROMECAST_EXTRA_ARGS = ['is_chromecast=true']
+_CHROMECAST_EXTRA_ARGS = ['is_cast_android=true', 'enable_cast_receiver=true']
 
 
 def gen_args_gn_content(use_goma: bool = False,
diff --git a/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc b/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc
index 68c9b1f..053d68b 100644
--- a/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc
+++ b/third_party/blink/common/input/web_coalesced_input_event_mojom_traits.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/containers/contains.h"
 #include "base/i18n/char_iterator.h"
 #include "base/time/time.h"
 #include "mojo/public/cpp/base/time_mojom_traits.h"
@@ -378,11 +379,8 @@
       static_cast<const blink::WebKeyboardEvent*>(event->EventPointer());
   // Assure char16_t[N] filds are null-terminated before converting
   // them to std::u16string.
-  CHECK(std::find(std::begin(key_event->text), std::end(key_event->text), 0) <
-        std::end(key_event->text));
-  CHECK(std::find(std::begin(key_event->unmodified_text),
-                  std::end(key_event->unmodified_text),
-                  0) < std::end(key_event->unmodified_text));
+  CHECK(base::Contains(key_event->text, 0));
+  CHECK(base::Contains(key_event->unmodified_text, 0));
   return blink::mojom::KeyData::New(
       key_event->dom_key, key_event->dom_code, key_event->windows_key_code,
       key_event->native_key_code, key_event->is_system_key,
diff --git a/third_party/blink/common/unique_name/unique_name_helper_unittest.cc b/third_party/blink/common/unique_name/unique_name_helper_unittest.cc
index 4c1927d7..483659e 100644
--- a/third_party/blink/common/unique_name/unique_name_helper_unittest.cc
+++ b/third_party/blink/common/unique_name/unique_name_helper_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/auto_reset.h"
 #include "base/memory/raw_ptr.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -42,8 +43,7 @@
 
   ~TestFrameAdapter() override {
     if (parent_) {
-      parent_->children_.erase(std::find(parent_->children_.begin(),
-                                         parent_->children_.end(), this));
+      parent_->children_.erase(base::ranges::find(parent_->children_, this));
     }
   }
 
diff --git a/third_party/blink/common/web_package/web_package_request_matcher.cc b/third_party/blink/common/web_package/web_package_request_matcher.cc
index ed4ef73..e2c8e4f4 100644
--- a/third_party/blink/common/web_package/web_package_request_matcher.cc
+++ b/third_party/blink/common/web_package/web_package_request_matcher.cc
@@ -11,6 +11,7 @@
 #include "base/containers/contains.h"
 #include "base/containers/span.h"
 #include "base/numerics/checked_math.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "net/base/mime_util.h"
@@ -369,8 +370,7 @@
   DCHECK_EQ(variant_key.size(), sorted_variants.size());
   size_t index = 0;
   for (size_t i = 0; i < sorted_variants.size(); ++i) {
-    auto found = std::find(sorted_variants[i].begin(), sorted_variants[i].end(),
-                           variant_key[i]);
+    auto found = base::ranges::find(sorted_variants[i], variant_key[i]);
     if (found == sorted_variants[i].end())
       return absl::nullopt;
 
@@ -552,9 +552,7 @@
     DCHECK_EQ(vk.size(), sorted_variants.size());
     size_t i = 0;
     for (; i < sorted_variants.size(); ++i) {
-      auto found = std::find(sorted_variants[i].begin(),
-                             sorted_variants[i].end(), vk[i]);
-      if (found == sorted_variants[i].end())
+      if (!base::Contains(sorted_variants[i], vk[i]))
         break;
     }
     if (i == sorted_variants.size())
@@ -636,8 +634,7 @@
         negotiation_algorithm->run(variant_axis.second, request_value);
     if (sorted_values.empty())
       return absl::nullopt;
-    auto it = std::find(variant_axis.second.begin(), variant_axis.second.end(),
-                        sorted_values.front());
+    auto it = base::ranges::find(variant_axis.second, sorted_values.front());
     if (it == variant_axis.second.end())
       return absl::nullopt;
     size_t best_value_index = it - variant_axis.second.begin();
diff --git a/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom b/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom
index f80ec017..4a53eec 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom
@@ -784,6 +784,7 @@
     kViewTimelineName = 731,
     kToggleVisibility = 732,
     kInitialLetter = 733,
+    kHyphenateLimitChars = 734,
     // 1. Add new features above this line (don't change the assigned numbers of
     //    the existing items).
     // 2. Run the src/tools/metrics/histograms/update_use_counter_css.py script
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc b/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
index b9185a1..21e4a3f 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.cc
@@ -30,9 +30,9 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 
-#include <algorithm>
 #include <memory>
 
+#include "base/containers/contains.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/sys_byteorder.h"
@@ -186,8 +186,7 @@
     // support for SSV version 0 by then.
     static constexpr uint8_t version0Tags[] = {35, 64, 68, 73,  78,  82, 83,
                                                85, 91, 98, 102, 108, 123};
-    return std::find(std::begin(version0Tags), std::end(version0Tags),
-                     data[1]) != std::end(version0Tags);
+    return base::Contains(version0Tags, data[1]);
   }
 
   if (data[1] == kVersionTag) {
diff --git a/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py b/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
index 4adcf81b..4660d4a 100755
--- a/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
+++ b/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
@@ -79,6 +79,7 @@
     'StyleColor',
     'StyleAutoColor',
     'Color',
+    'StyleHyphenateLimitChars',
     'LayoutUnit',
     'LineClampValue',
     'OutlineValue',
diff --git a/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc b/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
index 26fd2ec..633f946 100644
--- a/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
+++ b/third_party/blink/renderer/core/animation/css/css_scroll_timeline.cc
@@ -45,9 +45,7 @@
                      options.reference_element_.value_or(
                          document->ScrollingElementNoLayout()),
                      options.direction_),
-      name_(options.name_) {
-  SnapshotState();
-}
+      name_(options.name_) {}
 
 bool CSSScrollTimeline::Matches(const Options& options) const {
   return (GetReferenceType() == options.reference_type_) &&
diff --git a/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc b/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
index 6e03f60..32bc954 100644
--- a/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
+++ b/third_party/blink/renderer/core/animation/css/css_scroll_timeline_test.cc
@@ -214,27 +214,4 @@
             GetDocumentAnimations().GetUnvalidatedTimelinesForTesting().size());
 }
 
-TEST_F(CSSScrollTimelineTest, DocumentScrollerInQuirksMode) {
-  GetDocument().SetCompatibilityMode(Document::kQuirksMode);
-
-  SetBodyInnerHTML(R"HTML(
-    <style>
-    @keyframes anim {
-      from { z-index: 100; }
-      to { z-index: 100; }
-    }
-    #element {
-      animation: anim 10s forwards scroll(root);
-    }
-    </style>
-    <div id=element></div>
-  )HTML");
-
-  Element* element = GetDocument().getElementById("element");
-  ASSERT_TRUE(element);
-
-  EXPECT_EQ(100, element->GetComputedStyle()->ZIndex());
-  // Don't crash.
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/css/css_view_timeline.cc b/third_party/blink/renderer/core/animation/css/css_view_timeline.cc
index a4ff48b..8eb78d67 100644
--- a/third_party/blink/renderer/core/animation/css/css_view_timeline.cc
+++ b/third_party/blink/renderer/core/animation/css/css_view_timeline.cc
@@ -20,9 +20,7 @@
     : ViewTimeline(document,
                    options.subject_,
                    options.direction_,
-                   options.inset_) {
-  SnapshotState();
-}
+                   options.inset_) {}
 
 bool CSSViewTimeline::Matches(const Options& options) const {
   return (subject() == options.subject_) &&
diff --git a/third_party/blink/renderer/core/css/clip_path_paint_image_generator.h b/third_party/blink/renderer/core/css/clip_path_paint_image_generator.h
index 8f3235d..cb6c5c1 100644
--- a/third_party/blink/renderer/core/css/clip_path_paint_image_generator.h
+++ b/third_party/blink/renderer/core/css/clip_path_paint_image_generator.h
@@ -33,6 +33,9 @@
                                      const gfx::RectF& reference_box,
                                      const gfx::SizeF& clip_area_size,
                                      const Node&) = 0;
+  virtual gfx::RectF ClipAreaRect(const Node& node,
+                                  const gfx::RectF& reference_box,
+                                  float zoom) const = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 80d08cb..b565a6c 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -2813,6 +2813,19 @@
       valid_for_position_fallback: true,
     },
     {
+      name: "hyphenate-limit-chars",
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
+      inherited: true,
+      field_group: "*",
+      field_template: "external",
+      keywords: ["auto"],
+      type_name: "StyleHyphenateLimitChars",
+      default_value: "StyleHyphenateLimitChars()",
+      include_paths: ["third_party/blink/renderer/core/style/style_hyphenate_limit_chars.h"],
+      converter: "ConvertHyphenateLimitChars",
+      runtime_flag: "CSSHyphenateLimitChars",
+    },
+    {
       name: "hyphens",
       property_methods: ["CSSValueFromComputedStyleInternal"],
       inherited: true,
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index fbff6a1..ddfb0ff3 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -5378,6 +5378,27 @@
       template_areas);
 }
 
+CSSValue* ConsumeHyphenateLimitChars(CSSParserTokenRange& range,
+                                     const CSSParserContext& context) {
+  CSSValueList* const list = CSSValueList::CreateSpaceSeparated();
+  while (!range.AtEnd() && list->length() < 3) {
+    if (const CSSPrimitiveValue* value = ConsumeIntegerOrNumberCalc(
+            range, context, CSSPrimitiveValue::ValueRange::kPositiveInteger)) {
+      list->Append(*value);
+      continue;
+    }
+    if (const CSSIdentifierValue* ident =
+            ConsumeIdent<CSSValueID::kAuto>(range)) {
+      list->Append(*ident);
+      continue;
+    }
+    return nullptr;
+  }
+  if (list->length())
+    return list;
+  return nullptr;
+}
+
 bool ConsumeFromPageBreakBetween(CSSParserTokenRange& range,
                                  CSSValueID& value) {
   if (!ConsumeCSSValueId(range, value)) {
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
index f8fb1917..e5d00d5 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -455,6 +455,9 @@
                                   const CSSValue*& template_columns,
                                   const CSSValue*& template_areas);
 
+CSSValue* ConsumeHyphenateLimitChars(CSSParserTokenRange&,
+                                     const CSSParserContext&);
+
 // The fragmentation spec says that page-break-(after|before|inside) are to be
 // treated as shorthands for their break-(after|before|inside) counterparts.
 // We'll do the same for the non-standard properties
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index dee76f26..048f97c9 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -73,6 +73,20 @@
 // Implementations of methods in Longhand subclasses that aren't generated.
 
 namespace blink {
+
+namespace {
+
+void AppendIntegerOrAutoIfZero(unsigned value, CSSValueList* list) {
+  if (!value) {
+    list->Append(*CSSIdentifierValue::Create(CSSValueID::kAuto));
+    return;
+  }
+  list->Append(*CSSNumericLiteralValue::Create(
+      value, CSSPrimitiveValue::UnitType::kInteger));
+}
+
+}  // namespace
+
 namespace css_longhand {
 
 const CSSValue* AlignContent::ParseSingleValue(
@@ -3644,6 +3658,32 @@
                                                              style);
 }
 
+const CSSValue* HyphenateLimitChars::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const LayoutObject*,
+    bool allow_visited_style) const {
+  const StyleHyphenateLimitChars& value = style.HyphenateLimitChars();
+  if (value.IsAuto())
+    return CSSIdentifierValue::Create(CSSValueID::kAuto);
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  AppendIntegerOrAutoIfZero(value.MinWordChars(), list);
+  if (value.MinBeforeChars() || value.MinAfterChars()) {
+    AppendIntegerOrAutoIfZero(value.MinBeforeChars(), list);
+    if (value.MinAfterChars()) {
+      list->Append(*CSSNumericLiteralValue::Create(
+          value.MinAfterChars(), CSSPrimitiveValue::UnitType::kInteger));
+    }
+  }
+  return list;
+}
+
+const CSSValue* HyphenateLimitChars::ParseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&) const {
+  return css_parsing_utils::ConsumeHyphenateLimitChars(range, context);
+}
+
 const CSSValue* Hyphens::CSSValueFromComputedStyleInternal(
     const ComputedStyle& style,
     const LayoutObject*,
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index a9fcf416..c28f7f9 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -1205,6 +1205,35 @@
   }
 }
 
+StyleHyphenateLimitChars StyleBuilderConverter::ConvertHyphenateLimitChars(
+    StyleResolverState&,
+    const CSSValue& value) {
+  if (const auto* ident = DynamicTo<CSSIdentifierValue>(value)) {
+    DCHECK_EQ(ident->GetValueID(), CSSValueID::kAuto);
+    return StyleHyphenateLimitChars();
+  }
+  const auto& list = To<CSSValueList>(value);
+  DCHECK_GE(list.length(), 1u);
+  DCHECK_LE(list.length(), 3u);
+  Vector<unsigned, 3> values;
+  for (const Member<const CSSValue>& item : list) {
+    if (const auto* primitive = DynamicTo<CSSPrimitiveValue>(item.Get())) {
+      DCHECK(primitive->IsInteger());
+      DCHECK_GE(primitive->GetIntValue(), 1);
+      values.push_back(primitive->GetIntValue());
+      continue;
+    }
+    if (const auto* ident = DynamicTo<CSSIdentifierValue>(item.Get())) {
+      DCHECK_EQ(ident->GetValueID(), CSSValueID::kAuto);
+      values.push_back(0);
+      continue;
+    }
+    NOTREACHED();
+  }
+  values.Grow(3);
+  return StyleHyphenateLimitChars(values[0], values[1], values[2]);
+}
+
 LayoutUnit StyleBuilderConverter::ConvertBorderWidth(StyleResolverState& state,
                                                      const CSSValue& value) {
   double result = 0;
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
index 5b14aaf1..360c32c 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
@@ -169,6 +169,9 @@
                                             const CSSValue&);
   static GridTrackList ConvertGridTrackSizeList(StyleResolverState&,
                                                 const CSSValue&);
+  static StyleHyphenateLimitChars ConvertHyphenateLimitChars(
+      StyleResolverState&,
+      const CSSValue&);
   template <typename T>
   static T ConvertLineWidth(StyleResolverState&, const CSSValue&);
   static LayoutUnit ConvertBorderWidth(StyleResolverState&, const CSSValue&);
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index 7a4079c..19437de 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/core/display_lock/display_lock_document_state.h"
 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
 #include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h"
+#include "third_party/blink/renderer/core/dom/css_toggle.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/dom/element.h"
@@ -32,6 +33,7 @@
 #include "third_party/blink/renderer/core/page/page_animator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/pre_paint_tree_walk.h"
+#include "third_party/blink/renderer/core/style/toggle_trigger.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -70,28 +72,55 @@
   DetermineIfInSharedElementTransitionChain();
 }
 
-void DisplayLockContext::SetRequestedState(EContentVisibility state) {
-  if (state_ == state)
+void DisplayLockContext::SetRequestedState(EContentVisibility state,
+                                           const AtomicString& toggle_name) {
+  if (state_ == state && toggle_name_ == toggle_name)
     return;
   state_ = state;
+  toggle_name_ = toggle_name;
   base::AutoReset<bool> scope(&set_requested_state_scope_, true);
+  bool should_lock = false;
+  uint16_t lock_activation_mask = 0;
   switch (state_) {
     case EContentVisibility::kVisible:
-      RequestUnlock();
       break;
     case EContentVisibility::kAuto:
       UseCounter::Count(document_, WebFeature::kContentVisibilityAuto);
       had_any_viewport_intersection_notifications_ = false;
-      RequestLock(static_cast<uint16_t>(DisplayLockActivationReason::kAny));
+      should_lock = true;
+      lock_activation_mask =
+          static_cast<uint16_t>(DisplayLockActivationReason::kAuto);
       break;
     case EContentVisibility::kHidden:
       UseCounter::Count(document_, WebFeature::kContentVisibilityHidden);
-      RequestLock(
+      should_lock = true;
+      lock_activation_mask =
           is_hidden_until_found_ || is_details_slot_
               ? static_cast<uint16_t>(DisplayLockActivationReason::kFindInPage)
-              : 0u);
+              : 0u;
       break;
   }
+  if (!toggle_name.IsNull()) {
+    if (should_lock) {
+      // We have both 'content-visibility' and 'toggle-visibility'.  We want
+      // to combine their effects (i.e., content is hidden if *either* would
+      // hide it), which means we want to intersect the activation masks.
+      lock_activation_mask &=
+          static_cast<uint16_t>(DisplayLockActivationReason::kToggleVisibility);
+    } else {
+      // We have 'toggle-visibility', but no 'content-visibility'.
+      should_lock = true;
+      lock_activation_mask =
+          static_cast<uint16_t>(DisplayLockActivationReason::kToggleVisibility);
+    }
+  }
+
+  if (should_lock) {
+    RequestLock(lock_activation_mask);
+  } else {
+    RequestUnlock();
+  }
+
   // In a new state, we might need to either start or stop observing viewport
   // intersections.
   UpdateActivationObservationIfNeeded();
@@ -116,7 +145,7 @@
 }
 
 void DisplayLockContext::AdjustElementStyle(ComputedStyle* style) const {
-  if (state_ == EContentVisibility::kVisible)
+  if (IsAlwaysVisible())
     return;
   if (IsLocked())
     style->SetSkipsContents();
@@ -181,8 +210,8 @@
 
   // We require observation if we are in 'auto' mode and we're connected to a
   // view.
-  bool should_observe =
-      state_ == EContentVisibility::kAuto && ConnectedToView();
+  bool should_observe = state_ == EContentVisibility::kAuto &&
+                        toggle_name_.IsNull() && ConnectedToView();
   if (is_observed_ == should_observe)
     return;
   is_observed_ = should_observe;
@@ -287,6 +316,8 @@
   DetachDescendantTopLayerElements();
 
   // Schedule ContentVisibilityAutoStateChanged event if needed.
+  // TODO(https://crbug.com/1250716): We shouldn't fire this if it was the
+  // result of toggle state changing.
   ScheduleStateChangeEventIfNeeded();
 
   if (!element_->GetLayoutObject())
@@ -317,7 +348,7 @@
   // to the default state of being visible. This will get updated when we gain
   // new style.
   if (!element_->GetComputedStyle()) {
-    SetRequestedState(EContentVisibility::kVisible);
+    SetRequestedState(EContentVisibility::kVisible, g_null_atom);
     return;
   }
 
@@ -325,7 +356,7 @@
   if (ForceUnlockIfNeeded())
     return;
 
-  if (!IsLocked() && state_ != EContentVisibility::kVisible) {
+  if (!IsLocked() && !IsAlwaysVisible()) {
     UpdateActivationObservationIfNeeded();
     NotifyRenderAffectingStateChanged();
   }
@@ -400,6 +431,14 @@
     SetKeepUnlockedUntilLifecycleCount(2);
   }
 
+  if (!toggle_name_.IsNull()) {
+    CSSToggle* toggle = CSSToggle::FindToggleInScope(*element_, toggle_name_);
+    DCHECK(toggle) << "should no longer be locked with a toggle state";
+    ToggleTrigger trigger(toggle_name_, ToggleTriggerMode::kSet,
+                          ToggleTrigger::State(1u));
+    toggle->FireToggleActivation(*element_, trigger);
+  }
+
   if (reason == DisplayLockActivationReason::kFindInPage)
     document_->MarkHasFindInPageContentVisibilityActiveMatch();
 }
@@ -572,6 +611,8 @@
     cache->ChildrenChanged(element_);
 
   // Schedule ContentVisibilityAutoStateChanged event if needed.
+  // TODO(https://crbug.com/1250716): We shouldn't fire this if it was the
+  // result of toggle state changing.
   ScheduleStateChangeEventIfNeeded();
 
   auto* layout_object = element_->GetLayoutObject();
@@ -894,7 +935,7 @@
   // We remove the style when disconnecting an element, so we should also unlock
   // the context.
   DCHECK(!element_->GetComputedStyle());
-  SetRequestedState(EContentVisibility::kVisible);
+  SetRequestedState(EContentVisibility::kVisible, g_null_atom);
 
   // blocked_child_recalc_change_ must be cleared because things can be in an
   // inconsistent state when we add the element back (e.g. crbug.com/1262742).
@@ -918,7 +959,7 @@
   // When |element_| is removed from the flat tree, we need to set this context
   // to visible.
   if (!element_->GetComputedStyle()) {
-    SetRequestedState(EContentVisibility::kVisible);
+    SetRequestedState(EContentVisibility::kVisible, g_null_atom);
     blocked_child_recalc_change_ = StyleRecalcChange();
   }
 }
@@ -1025,7 +1066,7 @@
       }
       // If we forced unlock, then we need to prevent subsequent calls to
       // Lock() until the next frame.
-      SetRequestedState(EContentVisibility::kVisible);
+      SetRequestedState(EContentVisibility::kVisible, g_null_atom);
     }
     return true;
   }
@@ -1245,21 +1286,19 @@
   };
 
   // Check that we're visible if and only if lock has not been requested.
-  DCHECK(state_ == EContentVisibility::kVisible ||
-         state(RenderAffectingState::kLockRequested));
-  DCHECK(state_ != EContentVisibility::kVisible ||
-         !state(RenderAffectingState::kLockRequested));
+  DCHECK_EQ(IsAlwaysVisible(), !state(RenderAffectingState::kLockRequested));
 
   // We should be locked if the lock has been requested (the above DCHECKs
   // verify that this means that we are not 'visible'), and any of the
   // following is true:
   // - We are not in 'auto' mode (meaning 'hidden') or
+  // - We have a non-null toggle_name_ (for 'toggle-visibility') or
   // - We are in 'auto' mode and nothing blocks locking: viewport is
   //   not intersecting, subtree doesn't have focus, and subtree doesn't have
   //   selection, etc. See the condition for the full list.
   bool should_be_locked =
       state(RenderAffectingState::kLockRequested) &&
-      (state_ != EContentVisibility::kAuto ||
+      (state_ != EContentVisibility::kAuto || !toggle_name_.IsNull() ||
        (!state(RenderAffectingState::kIntersectsViewport) &&
         !state(RenderAffectingState::kSubtreeHasFocus) &&
         !state(RenderAffectingState::kSubtreeHasSelection) &&
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index f607fa4b..89eb156 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -41,6 +41,9 @@
   kUserFocus = 1 << 7,
   // Intersection observer activation
   kViewportIntersection = 1 << 8,
+  // NOTE: We don't need an activation reason for CSS toggles, since toggle
+  // state changes trigger restyles that update the context through a call to
+  // SetRequestedState().
 
   // Shorthands
   kViewport = static_cast<uint16_t>(kSelection) |
@@ -55,7 +58,24 @@
          static_cast<uint16_t>(kSelection) |
          static_cast<uint16_t>(kSimulatedClick) |
          static_cast<uint16_t>(kUserFocus) |
-         static_cast<uint16_t>(kViewportIntersection)
+         static_cast<uint16_t>(kViewportIntersection),
+  kAuto = kAny,
+
+  // The css-toggles specification says that toggle-visibility works like
+  // content-visibility, except it's not activated by being on-screen.
+  //
+  // TODO(https://crbug.com/1250716): Conceptually I *think* we might want to
+  // omit kUserFocus from kToggleVisibility.  However, omitting kUserFocus but
+  // retaining kScriptFocus doesn't appear to work in practice.  (Is this
+  // because kUserFocus affects Element::IsFocusableStyle?)
+  //
+  // TODO(https://github.com/tabatkins/css-toggle/issues/42): While this
+  // doesn't match the current specification draft, we also exclude kSelection
+  // because the presence of a selection shouldn't prevent other user actions
+  // from changing the toggle and making the element skip its contents.
+  kToggleVisibility = static_cast<uint16_t>(kAny) &
+                      ~(static_cast<uint16_t>(kViewportIntersection) |
+                        static_cast<uint16_t>(kSelection)),
 };
 
 // Instead of specifying an underlying type, which would propagate throughout
@@ -76,8 +96,14 @@
   explicit DisplayLockContext(Element*);
   ~DisplayLockContext() = default;
 
-  // Called by style to update the current state of content-visibility.
-  void SetRequestedState(EContentVisibility state);
+  // Called by style to update the current state of content-visibility and
+  // toggle-visibility.
+  // toggle_visibility should be non-null when toggle-visibility is set
+  // to a toggle *and* the toggle is currently inactive (meaning the
+  // element should be hidden due to the toggle).  Otherwise it should
+  // be g_null_atom.
+  void SetRequestedState(EContentVisibility state,
+                         const AtomicString& toggle_visibility);
   // Called by style to adjust the element's style based on the current state.
   void AdjustElementStyle(ComputedStyle* style) const;
 
@@ -191,7 +217,13 @@
   // Debugging functions.
   String RenderAffectingStateToString() const;
 
-  bool IsAuto() const { return state_ == EContentVisibility::kAuto; }
+  bool IsAlwaysVisible() const {
+    return state_ == EContentVisibility::kVisible && toggle_name_.IsNull();
+  }
+
+  bool IsAuto() const {
+    return state_ == EContentVisibility::kAuto && toggle_name_.IsNull();
+  }
   bool HadLifecycleUpdateSinceLastUnlock() const {
     return had_lifecycle_update_since_last_unlock_;
   }
@@ -372,6 +404,7 @@
   WeakMember<Element> element_;
   WeakMember<Document> document_;
   EContentVisibility state_ = EContentVisibility::kVisible;
+  AtomicString toggle_name_;
 
   // A struct to keep track of forced unlocks, and reasons for it.
   struct UpdateForcedInfo {
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index 131c46f..4e9b55c 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -152,7 +152,7 @@
   }
 
   void UnlockImmediate(DisplayLockContext* context) {
-    context->SetRequestedState(EContentVisibility::kVisible);
+    context->SetRequestedState(EContentVisibility::kVisible, g_null_atom);
   }
 
   mojom::blink::FindOptionsPtr FindOptions(bool new_session = true) {
@@ -2005,7 +2005,7 @@
     return context->needs_compositing_dependent_flag_update_;
   }
   void LockImmediate(DisplayLockContext* context) {
-    context->SetRequestedState(EContentVisibility::kHidden);
+    context->SetRequestedState(EContentVisibility::kHidden, g_null_atom);
   }
   void RunStartOfLifecycleTasks() {
     auto start_of_lifecycle_tasks =
diff --git a/third_party/blink/renderer/core/dom/css_toggle.cc b/third_party/blink/renderer/core/dom/css_toggle.cc
index 2e9ba7ed..33ad9bb 100644
--- a/third_party/blink/renderer/core/dom/css_toggle.cc
+++ b/third_party/blink/renderer/core/dom/css_toggle.cc
@@ -297,7 +297,7 @@
     if (specifier)
       states = &specifier->StateSet();
 
-    if (!ValueMatches(State(0u), states)) {
+    if (ValueIsActive(states)) {
       MakeRestOfToggleGroupZero();
     }
   }
@@ -553,7 +553,7 @@
 
   // If t’s value does not match 0, and group is true, then set the value of
   // all other toggles in the same toggle group as t to 0.
-  if (is_group && !ValueMatches(State(0u), &states))
+  if (is_group && ValueIsActive(&states))
     MakeRestOfToggleGroupZero();
 }
 
diff --git a/third_party/blink/renderer/core/dom/css_toggle.h b/third_party/blink/renderer/core/dom/css_toggle.h
index 9cfd5d0..60c7d51e 100644
--- a/third_party/blink/renderer/core/dom/css_toggle.h
+++ b/third_party/blink/renderer/core/dom/css_toggle.h
@@ -101,6 +101,11 @@
   bool ValueMatches(const State& other,
                     const States* states_override = nullptr) const;
 
+  // Is the value a non-zero (active) value?
+  bool ValueIsActive(const States* states_override = nullptr) const {
+    return !ValueMatches(State(0u), states_override);
+  }
+
  private:
   void setStatesInternal(const States& states, ExceptionState& exception_state);
   void SetValueAndCheckGroup(const State& value);
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 18acdc3..69013aa 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3824,7 +3824,17 @@
   if (UNLIKELY(context || !style->IsContentVisibilityVisible())) {
     if (!context)
       context = &EnsureDisplayLockContext();
-    context->SetRequestedState(style->ContentVisibility());
+    AtomicString toggle_visibility = style->ToggleVisibility();
+    if (!toggle_visibility.IsNull()) {
+      CSSToggle* toggle =
+          CSSToggle::FindToggleInScope(*this, toggle_visibility);
+      if (!toggle || toggle->ValueIsActive()) {
+        // The element is not in scope for a toggle, or it is in scope and
+        // the toggle is active, therefore it is visible.
+        toggle_visibility = g_null_atom;
+      }
+    }
+    context->SetRequestedState(style->ContentVisibility(), toggle_visibility);
     context->AdjustElementStyle(style.get());
   }
 
diff --git a/third_party/blink/renderer/core/dom/live_node_list_registry.cc b/third_party/blink/renderer/core/dom/live_node_list_registry.cc
index 7c6a426..0d9758c 100644
--- a/third_party/blink/renderer/core/dom/live_node_list_registry.cc
+++ b/third_party/blink/renderer/core/dom/live_node_list_registry.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/core/dom/live_node_list_registry.h"
 
+#include "base/containers/contains.h"
+#include "base/ranges/algorithm.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/live_node_list_base.h"
 
@@ -15,7 +17,7 @@
 void LiveNodeListRegistry::Add(const LiveNodeListBase* list,
                                NodeListInvalidationType type) {
   Entry entry = {list, MaskForInvalidationType(type)};
-  DCHECK(std::find(data_.begin(), data_.end(), entry) == data_.end());
+  DCHECK(!base::Contains(data_, entry));
   data_.push_back(entry);
   mask_ |= entry.second;
 }
@@ -23,7 +25,7 @@
 void LiveNodeListRegistry::Remove(const LiveNodeListBase* list,
                                   NodeListInvalidationType type) {
   Entry entry = {list, MaskForInvalidationType(type)};
-  auto* it = std::find(data_.begin(), data_.end(), entry);
+  auto* it = base::ranges::find(data_, entry);
   DCHECK(it != data_.end());
   data_.erase(it);
   data_.ShrinkToReasonableCapacity();
diff --git a/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc b/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
index f2b0bc5..418a83d 100644
--- a/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
+++ b/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/public/platform/web_document_subresource_filter.h"
 
+#include "base/containers/contains.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
@@ -31,9 +32,7 @@
   LoadPolicy GetLoadPolicy(const WebURL& resource_url,
                            mojom::blink::RequestContextType) override {
     String resource_path = KURL(resource_url).GetPath();
-    if (std::find(queried_subresource_paths_.begin(),
-                  queried_subresource_paths_.end(),
-                  resource_path) == queried_subresource_paths_.end()) {
+    if (!base::Contains(queried_subresource_paths_, resource_path)) {
       queried_subresource_paths_.push_back(resource_path);
     }
     String resource_string = resource_url.GetString();
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.cc b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
index fc6eef57..d20d08691 100644
--- a/third_party/blink/renderer/core/frame/attribution_src_loader.cc
+++ b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
@@ -332,6 +332,13 @@
   auto* client = MakeGarbageCollected<ResourceClient>(
       this, src_type, associated_with_navigation);
   ++num_resource_clients_;
+
+  // TODO(https://crbug.com/1374121): If this registration is
+  // `associated_with_navigation`, there is a risk that the navigation will
+  // complete before the resource fetch here is complete. In this case, the
+  // browser will mark the page as frozen. This will cause MojoURLLoaderClient
+  // to store the request and never dispatch it, causing ResponseReceived() to
+  // never be called.
   RawResource::Fetch(params, local_frame_->DomWindow()->Fetcher(), client);
 
   RecordAttributionSrcRequestStatus(AttributionSrcRequestStatus::kRequested);
diff --git a/third_party/blink/renderer/core/frame/pending_beacon_dispatcher_test.cc b/third_party/blink/renderer/core/frame/pending_beacon_dispatcher_test.cc
index 1485d11..7f9f251 100644
--- a/third_party/blink/renderer/core/frame/pending_beacon_dispatcher_test.cc
+++ b/third_party/blink/renderer/core/frame/pending_beacon_dispatcher_test.cc
@@ -328,9 +328,8 @@
 class PendingBeaconDispatcherOnPagehideTest
     : public PendingBeaconDispatcherTestBase {
   void SetUp() override {
-    const std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-        enabled_features = {{blink::features::kPendingBeaconAPI,
-                             {{"send_on_navigation", "true"}}}};
+    const std::vector<base::test::FeatureRefAndParams> enabled_features = {
+        {blink::features::kPendingBeaconAPI, {{"send_on_navigation", "true"}}}};
     feature_list_.InitWithFeaturesAndParameters(enabled_features, {});
     PendingBeaconDispatcherTestBase::SetUp();
   }
diff --git a/third_party/blink/renderer/core/frame/screen.cc b/third_party/blink/renderer/core/frame/screen.cc
index c9468d2..1288aa5 100644
--- a/third_party/blink/renderer/core/frame/screen.cc
+++ b/third_party/blink/renderer/core/frame/screen.cc
@@ -73,6 +73,20 @@
   if (prev.is_extended != current.is_extended)
     return false;
 
+  if (RuntimeEnabledFeatures::CanvasHDREnabled()) {
+    // (red|green|blue)Primary(X|Y) and whitePoint(X|Y).
+    const auto& prev_dcs = prev.display_color_spaces;
+    const auto& current_dcs = current.display_color_spaces;
+    if (prev_dcs.GetPrimaries() != current_dcs.GetPrimaries())
+      return false;
+
+    // highDynamicRangeHeadroom.
+    if (prev_dcs.GetHDRMaxLuminanceRelative() !=
+        current_dcs.GetHDRMaxLuminanceRelative()) {
+      return false;
+    }
+  }
+
   return true;
 }
 
diff --git a/third_party/blink/renderer/core/html/forms/html_input_element.cc b/third_party/blink/renderer/core/html/forms/html_input_element.cc
index e6856e1..21daa0d3 100644
--- a/third_party/blink/renderer/core/html/forms/html_input_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_input_element.cc
@@ -503,7 +503,7 @@
   if (old_value_mode == ValueMode::kValue &&
       (new_value_mode == ValueMode::kDefault ||
        new_value_mode == ValueMode::kDefaultOn)) {
-    if (HasDirtyValue())
+    if (HasDirtyValue() && !non_attribute_value_.empty())
       setAttribute(html_names::kValueAttr, AtomicString(non_attribute_value_));
     non_attribute_value_ = String();
     has_dirty_value_ = false;
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index dc5de9a..2780062a 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -932,6 +932,7 @@
   "ng/ng_physical_box_fragment_test.cc",
   "ng/ng_physical_fragment_test.cc",
   "ng/ng_relative_utils_test.cc",
+  "ng/svg/layout_ng_svg_foreign_object_test.cc",
   "ng/svg/layout_ng_svg_text_test.cc",
   "ng/svg/ng_svg_text_layout_algorithm_test.cc",
   "ng/svg/ng_svg_text_layout_attributes_builder_test.cc",
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 8765c6e..f99abf7 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -490,7 +490,10 @@
       (StyleRef().SpecifiesColumns() && !IsLayoutNGObject()))
     return kNormalPaintLayer;
 
-  if (HasNonVisibleOverflow())
+  const bool is_replaced_element_respecting_overflow =
+      RuntimeEnabledFeatures::CSSOverflowForReplacedElementsEnabled() &&
+      IsLayoutReplaced();
+  if (HasNonVisibleOverflow() && !is_replaced_element_respecting_overflow)
     return kOverflowClipPaintLayer;
 
   return kNoPaintLayer;
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index 9f58498..740d7423 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -206,7 +206,7 @@
       !StyleRef().HasStickyConstrainedPosition()) {
     if (const auto* scroll_container =
             Layer()->ContainingScrollContainerLayer()) {
-      scroll_container->GetScrollableArea()->RemoveStickyLayer(Layer());
+      scroll_container->GetScrollableArea()->InvalidateAllStickyConstraints();
     }
   }
 
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc b/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
index 61107cf..d35c0173 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
@@ -1524,4 +1524,54 @@
   UpdateAllLifecyclePhasesForTest();
 }
 
+TEST_P(LayoutBoxModelObjectTest,
+       RemoveStickyStatusInNestedStickyElementsWithContain) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      body, #container, #child {
+        contain: strict;
+        position: sticky;
+        bottom: 0;
+        height: 2000px;
+      }
+    </style>
+    <div id="container">
+      <div id="child"></div>
+    </div>
+  )HTML");
+
+  auto* body = GetDocument().body()->GetLayoutBox();
+  auto* container_element = GetDocument().getElementById("container");
+  auto* container = container_element->GetLayoutBoxModelObject();
+  auto* child = GetLayoutBoxModelObjectByElementId("child");
+
+  ASSERT_TRUE(body->StickyConstraints());
+  ASSERT_TRUE(container->StickyConstraints());
+  auto* child_constraints = child->StickyConstraints();
+  ASSERT_TRUE(child_constraints);
+  EXPECT_EQ(
+      container->Layer(),
+      child_constraints->nearest_sticky_layer_shifting_containing_block.Get());
+
+  GetLayoutView().GetScrollableArea()->ScrollToAbsolutePosition(
+      gfx::PointF(0, 50));
+
+  container_element->setAttribute(html_names::kStyleAttr, "position: relative");
+  GetDocument().View()->UpdateLifecycleToLayoutClean(
+      DocumentUpdateReason::kTest);
+
+  ASSERT_TRUE(body->StickyConstraints());
+  ASSERT_FALSE(container->StickyConstraints());
+  child_constraints = child->StickyConstraints();
+  ASSERT_TRUE(child_constraints);
+  EXPECT_EQ(
+      body->Layer(),
+      child_constraints->nearest_sticky_layer_shifting_containing_block.Get());
+
+  // This should not crash.
+  GetLayoutView().GetScrollableArea()->ScrollToAbsolutePosition(
+      gfx::PointF(0, 0));
+  UpdateAllLifecyclePhasesForTest();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
index a6f8b37..3daf5ce 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
@@ -243,6 +243,9 @@
 
 void NGFlexLayoutAlgorithm::HandleOutOfFlowPositionedItems(
     HeapVector<Member<LayoutBox>>& oof_children) {
+  if (oof_children.empty())
+    return;
+
   HeapVector<Member<LayoutBox>> oofs;
   std::swap(oofs, oof_children);
 
@@ -251,18 +254,16 @@
   const LayoutUnit previous_consumed_block_size =
       BreakToken() ? BreakToken()->ConsumedBlockSize() : LayoutUnit();
 
-  // If fragmentation is present we place all the OOF candidates within the
-  // last fragment. The last fragment has the most up-to-date container sizing
-  // info.
+  // We will attempt to add OOFs in the fragment in which their static
+  // position belongs. However, the last fragment has the most up-to-date flex
+  // size information (e.g. any expanded rows, etc), so for center aligned
+  // items, we could end up with an incorrect static position.
   if (UNLIKELY(InvolvedInBlockFragmentation(container_builder_))) {
     should_process_block_end = !container_builder_.DidBreakSelf() &&
                                !container_builder_.HasChildBreakInside();
     if (should_process_block_end) {
       // Recompute the total block size in case |total_intrinsic_block_size_|
-      // changed as a result of fragmentation. Note that center aligned OOFs
-      // may receive an incorrect static position if the total block size is
-      // different as a result of fragmentation since we only update this once
-      // we reach the last fragment.
+      // changed as a result of fragmentation.
       total_block_size_ = ComputeBlockSizeForFragment(
           ConstraintSpace(), Style(), BorderPadding(),
           total_intrinsic_block_size_, container_builder_.InlineSize());
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index a77a42e0..5db601d 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -1482,21 +1482,6 @@
 
   track_collection->ResetBaselines();
 
-  auto UpdateBaseline = [&](const GridItemData& grid_item,
-                            LayoutUnit candidate_baseline) {
-    // "If a box spans multiple shared alignment contexts, then it participates
-    //  in first/last baseline alignment within its start-most/end-most shared
-    //  alignment context along that axis"
-    // https://www.w3.org/TR/css-align-3/#baseline-sharing-group
-    if (grid_item.BaselineGroup(track_direction) == BaselineGroup::kMajor) {
-      track_collection->SetMajorBaseline(
-          grid_item.SetIndices(track_direction).begin, candidate_baseline);
-    } else {
-      track_collection->SetMinorBaseline(
-          grid_item.SetIndices(track_direction).end - 1, candidate_baseline);
-    }
-  };
-
   for (auto& grid_item : *grid_items) {
     if (!grid_item.IsBaselineSpecifiedForDirection(track_direction))
       continue;
@@ -1531,21 +1516,27 @@
         !baseline_fragment.FirstBaseline().has_value();
     grid_item.SetAlignmentFallback(track_direction, has_synthesized_baseline);
 
+    if (!grid_item.IsBaselineAlignedForDirection(track_direction))
+      continue;
+
     const auto margins =
         ComputeMarginsFor(space, item_style, baseline_writing_direction);
     const bool is_last_baseline =
         grid_item.IsLastBaselineSpecifiedForDirection(track_direction);
-
-    LayoutUnit baseline =
+    const LayoutUnit baseline =
         (is_last_baseline ? margins.block_end : margins.block_start) +
         GetLogicalBaseline(baseline_fragment, is_last_baseline);
 
-    // TODO(kschmi): The IsReplaced() check here is a bit strange, but is
-    // necessary to pass some of the tests. Follow-up to see if there's
-    // a better solution.
-    if (grid_item.IsBaselineAlignedForDirection(track_direction) ||
-        grid_item.node.IsReplaced()) {
-      UpdateBaseline(grid_item, baseline);
+    // "If a box spans multiple shared alignment contexts, then it participates
+    //  in first/last baseline alignment within its start-most/end-most shared
+    //  alignment context along that axis"
+    // https://www.w3.org/TR/css-align-3/#baseline-sharing-group
+    if (grid_item.BaselineGroup(track_direction) == BaselineGroup::kMajor) {
+      track_collection->SetMajorBaseline(
+          grid_item.SetIndices(track_direction).begin, baseline);
+    } else {
+      track_collection->SetMinorBaseline(
+          grid_item.SetIndices(track_direction).end - 1, baseline);
     }
   }
 }
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index c785758..e91a5bf 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -443,13 +443,23 @@
 
   // Even if we are a layout root, our baseline may have shifted. In this
   // (rare) case, mark our containing-block for layout.
-  // The baseline of SVG <text> doesn't affect other boxes.
-  if (is_layout_root && previous_result && !Base::IsNGSVGText()) {
+  if (is_layout_root && previous_result) {
     if (To<NGPhysicalBoxFragment>(previous_result->PhysicalFragment())
             .FirstBaseline() != physical_fragment.FirstBaseline()) {
       if (auto* containing_block = Base::ContainingBlock()) {
-        containing_block->SetNeedsLayout(
-            layout_invalidation_reason::kChildChanged, kMarkContainerChain);
+        // Baselines inside replaced elements don't affect other boxes.
+        bool is_in_replaced = false;
+        for (auto* parent = Base::Parent();
+             parent && parent != containing_block; parent = parent->Parent()) {
+          if (parent->IsLayoutReplaced()) {
+            is_in_replaced = true;
+            break;
+          }
+        }
+        if (!is_in_replaced) {
+          containing_block->SetNeedsLayout(
+              layout_invalidation_reason::kChildChanged, kMarkContainerChain);
+        }
       }
     }
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 7f46f0b..cadf13e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -2352,9 +2352,15 @@
     // not be contained by the innermost multicol container, and so on. Skip
     // above all OOFs in the containing block chain, to find the right
     // fragmentation context root.
-    while (containing_block->IsOutOfFlowPositioned())
+    while (containing_block->IsOutOfFlowPositioned() &&
+           !containing_block->IsLayoutView())
       containing_block = containing_block->ContainingNGBlock();
-    containing_block = containing_block->ContainingFragmentationContextRoot();
+    // If we got to the root LayoutView, it has to mean that it establishes a
+    // fragmentation context (i.e. we're printing).
+    if (containing_block->IsLayoutView())
+      DCHECK(containing_block->IsFragmentationContextRoot());
+    else
+      containing_block = containing_block->ContainingFragmentationContextRoot();
 
     // Since this is treated as a nested multicol container, we should always
     // find an outer fragmentation context.
diff --git a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object.cc b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object.cc
index 233ff51..8d13f857 100644
--- a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object.cc
+++ b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object.cc
@@ -68,6 +68,11 @@
   return transform;
 }
 
+LayoutPoint LayoutNGSVGForeignObject::Location() const {
+  NOT_DESTROYED();
+  return overridden_location_;
+}
+
 PaintLayerType LayoutNGSVGForeignObject::LayerTypeRequired() const {
   NOT_DESTROYED();
   // Skip LayoutSVGBlock's override.
@@ -136,7 +141,7 @@
   // would pull this information from ComputedStyle - in SVG those properties
   // are ignored for non <svg> elements, so we mimic what happens when
   // specifying them through CSS.
-  SetLocation(LayoutPoint(zoomed_location));
+  overridden_location_ = LayoutPoint(zoomed_location);
 
   UpdateNGBlockLayout();
   DCHECK(!NeedsLayout());
diff --git a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object.h b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object.h
index 39d30e2..4962bb0d 100644
--- a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object.h
+++ b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object.h
@@ -44,6 +44,7 @@
   AffineTransform LocalToSVGParentTransform() const override;
 
   // LayoutBox override:
+  LayoutPoint Location() const override;
   PaintLayerType LayerTypeRequired() const override;
   bool CreatesNewFormattingContext() const override;
 
@@ -53,6 +54,10 @@
   // The resolved viewport in the regular SVG coordinate space (after any
   // 'transform' has been applied but without zoom-adjustment).
   gfx::RectF viewport_;
+
+  // Override of LayoutBox::frame_rect_.location_.
+  // A physical fragment for <foreignObject> doesn't have the owner NGLink.
+  LayoutPoint overridden_location_;
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object_test.cc b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object_test.cc
new file mode 100644
index 0000000..0caf349
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_foreign_object_test.cc
@@ -0,0 +1,42 @@
+// Copyright 2022 The Chromium Authors
+// 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_layout_test.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+
+namespace blink {
+
+class LayoutNGSVGForeignObjectTest : public NGLayoutTest {
+ public:
+  LayoutNGSVGForeignObjectTest() = default;
+
+ private:
+  ScopedLayoutNGForeignObjectForTest foreign_object_ng_{true};
+};
+
+// crbug.com/1372886
+TEST_F(LayoutNGSVGForeignObjectTest, SubtreeLayoutCrash) {
+  SetBodyInnerHTML(R"HTML(
+<svg style="position:absolute;">
+  <svg></svg>
+  <foreignObject>
+    <div id="in-foreign"></div>
+  </foreignObject>
+</svg>
+<div></div>
+<span></span>
+<div id="sibling-div"></div>
+<svg><pattern id="pat"></pattern>
+</svg>)HTML");
+  UpdateAllLifecyclePhasesForTest();
+  GetElementById("in-foreign")->setAttribute("style", "display: inline-block");
+  UpdateAllLifecyclePhasesForTest();
+  GetElementById("pat")->setAttribute("viewBox", "972 815 1088 675");
+  UpdateAllLifecyclePhasesForTest();
+  GetElementById("sibling-div")->setAttribute("style", "display: none");
+  UpdateAllLifecyclePhasesForTest();
+  // Pass if no crashes.
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/clip_path_clipper.cc b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
index 924054e..d226a8c 100644
--- a/third_party/blink/renderer/core/paint/clip_path_clipper.cc
+++ b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
@@ -105,8 +105,6 @@
   ClipPathPaintImageGenerator* generator =
       clip_path_owner.GetFrame()->GetClipPathPaintImageGenerator();
 
-  // TODO(crbug.com/1248610): Fix bounding box. It should enclose affected area
-  // of the animation.
   // The bounding rect of the clip-path animation, relative to the layout
   // object.
   absl::optional<gfx::RectF> bounding_box =
@@ -158,16 +156,27 @@
   ClipPathOperation& clip_path = *object.StyleRef().ClipPath();
   if (clip_path.GetType() == ClipPathOperation::kShape) {
     auto zoom = object.StyleRef().EffectiveZoom();
+
+    bool uses_zoomed_reference_box = UsesZoomedReferenceBox(object);
+    gfx::RectF adjusted_reference_box =
+        uses_zoomed_reference_box ? reference_box
+                                  : gfx::ScaleRect(reference_box, zoom);
+
     gfx::RectF bounding_box;
-    auto& shape = To<ShapeClipPathOperation>(clip_path);
-    if (UsesZoomedReferenceBox(object)) {
-      bounding_box = shape.GetPath(reference_box, zoom).BoundingRect();
+    if (HasCompositeClipPathAnimation(object)) {
+      // For composite clip path animations, the bounding rect needs to contain
+      // the *entire* animation, or the animation may be clipped.
+      ClipPathPaintImageGenerator* generator =
+          object.GetFrame()->GetClipPathPaintImageGenerator();
+      bounding_box = generator->ClipAreaRect(*object.GetNode(),
+                                             adjusted_reference_box, zoom);
     } else {
-      bounding_box = gfx::ScaleRect(
-          shape.GetPath(gfx::ScaleRect(reference_box, zoom), zoom)
-              .BoundingRect(),
-          1.f / zoom);
+      auto& shape = To<ShapeClipPathOperation>(clip_path);
+      bounding_box = shape.GetPath(adjusted_reference_box, zoom).BoundingRect();
     }
+
+    if (!uses_zoomed_reference_box)
+      bounding_box = gfx::ScaleRect(bounding_box, 1.f / zoom);
     bounding_box.Intersect(gfx::RectF(LayoutRect::InfiniteIntRect()));
     return bounding_box;
   }
@@ -257,8 +266,6 @@
                                                   DisplayItem::kSVGClip))
     return;
 
-  // TODO(crbug.com/1248610): Fix paint rectangle for
-  // CompositeClipPathAnimation.
   DrawingRecorder recorder(
       context, display_item_client, DisplayItem::kSVGClip,
       gfx::ToEnclosingRect(properties->MaskClip()->PaintClipRect().Rect()));
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 9a607fd..631eddb 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -929,7 +929,7 @@
             .HasStickyConstrainedPosition()) {
       if (const auto* scroll_container =
               old_child->ContainingScrollContainerLayer()) {
-        scroll_container->GetScrollableArea()->RemoveStickyLayer(old_child);
+        scroll_container->GetScrollableArea()->InvalidateAllStickyConstraints();
       }
     }
   }
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index d543c12..305a123 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -2084,11 +2084,6 @@
   EnsureRareData().sticky_layers_.insert(layer);
 }
 
-void PaintLayerScrollableArea::RemoveStickyLayer(PaintLayer* layer) {
-  if (rare_data_)
-    rare_data_->sticky_layers_.erase(layer);
-}
-
 void PaintLayerScrollableArea::InvalidateAllStickyConstraints() {
   // Don't clear StickyConstraints for each LayoutObject of each layer in
   // sticky_layers_ because sticky_layers_ may contain stale pointers.
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index 3631bbf..33b6e5a 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -522,7 +522,6 @@
   }
 
   void AddStickyLayer(PaintLayer*);
-  void RemoveStickyLayer(PaintLayer*);
   bool HasStickyLayer(PaintLayer* layer) const {
     return rare_data_ && rare_data_->sticky_layers_.Contains(layer);
   }
diff --git a/third_party/blink/renderer/core/style/build.gni b/third_party/blink/renderer/core/style/build.gni
index 2a57383c..e2b5c3d2 100644
--- a/third_party/blink/renderer/core/style/build.gni
+++ b/third_party/blink/renderer/core/style/build.gni
@@ -78,6 +78,7 @@
   "style_generated_image.h",
   "style_highlight_data.cc",
   "style_highlight_data.h",
+  "style_hyphenate_limit_chars.h",
   "style_image.cc",
   "style_image.h",
   "style_inherited_variables.cc",
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index adbdb66..90f5a5b 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2091,7 +2091,8 @@
   }
 
   bool IsContentVisibilityVisible() const {
-    return ContentVisibility() == EContentVisibility::kVisible;
+    return ContentVisibility() == EContentVisibility::kVisible &&
+           ToggleVisibility().IsNull();
   }
 
   // Interleaving roots are elements that may require layout to fully update
diff --git a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
index 7247eb38..3dc7b220 100644
--- a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
+++ b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -76,7 +76,8 @@
                 "text-overflow", "shape-margin", "order", "-webkit-highlight",
                 "text-indent", "text-align-last", "EffectiveZoom",
                 "word-break", "overflow-wrap", "-webkit-line-break",
-                "-webkit-text-security", "hyphens", "hyphenate-character",
+                "-webkit-text-security",
+                "hyphens", "hyphenate-character", "hyphenate-limit-chars",
                 "image-orientation", "-webkit-ruby-position",
                 "TextEmphasisMark", "text-emphasis-position",
                 "TextEmphasisCustomMark", "text-orientation",
diff --git a/third_party/blink/renderer/core/style/style_hyphenate_limit_chars.h b/third_party/blink/renderer/core/style/style_hyphenate_limit_chars.h
new file mode 100644
index 0000000..99a1ba87
--- /dev/null
+++ b/third_party/blink/renderer/core/style/style_hyphenate_limit_chars.h
@@ -0,0 +1,61 @@
+// Copyright 2022 The Chromium Authors
+// 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_STYLE_STYLE_HYPHENATE_LIMIT_CHARS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_HYPHENATE_LIMIT_CHARS_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+// Style data for the `hyphenate-limit-chars` property.
+// https://w3c.github.io/csswg-drafts/css-text-4/#propdef-hyphenate-limit-chars
+class CORE_EXPORT StyleHyphenateLimitChars {
+  DISALLOW_NEW();
+
+ public:
+  StyleHyphenateLimitChars() = default;
+  StyleHyphenateLimitChars(unsigned min_word_chars,
+                           unsigned min_before_chars,
+                           unsigned min_after_chars)
+      : min_word_chars_(base::saturated_cast<uint8_t>(min_word_chars)),
+        min_before_chars_(base::saturated_cast<uint8_t>(min_before_chars)),
+        min_after_chars_(base::saturated_cast<uint8_t>(min_after_chars)) {}
+
+  // The minimum number of characters in the word / before the hyphen / after
+  // the hyphen. `0` means `auto`, the UA chooses a value that adapts to the
+  // current layout.
+  unsigned MinWordChars() const { return min_word_chars_; }
+  unsigned MinBeforeChars() const { return min_before_chars_; }
+  unsigned MinAfterChars() const { return min_after_chars_; }
+
+  bool IsAuto() const {
+    return !min_word_chars_ && !min_before_chars_ && !min_after_chars_;
+  }
+
+  bool operator==(const StyleHyphenateLimitChars& other) const;
+  bool operator!=(const StyleHyphenateLimitChars& other) const;
+
+ private:
+  uint8_t min_word_chars_ = 0;
+  uint8_t min_before_chars_ = 0;
+  uint8_t min_after_chars_ = 0;
+};
+
+inline bool StyleHyphenateLimitChars::operator==(
+    const StyleHyphenateLimitChars& other) const {
+  return min_word_chars_ == other.min_word_chars_ &&
+         min_before_chars_ == other.min_before_chars_ &&
+         min_after_chars_ == other.min_after_chars_;
+}
+
+inline bool StyleHyphenateLimitChars::operator!=(
+    const StyleHyphenateLimitChars& other) const {
+  return !operator==(other);
+}
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_HYPHENATE_LIMIT_CHARS_H_
diff --git a/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc b/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
index 1f3d2fa..b619b60a 100644
--- a/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
+++ b/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
@@ -25,8 +25,7 @@
 
 #include "third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.h"
 
-#include <algorithm>
-
+#include "base/ranges/algorithm.h"
 #include "third_party/blink/renderer/core/svg/animation/smil_animation_value.h"
 #include "third_party/blink/renderer/core/svg/svg_animation_element.h"
 
@@ -53,7 +52,7 @@
 }
 
 void SMILAnimationSandwich::Remove(SVGAnimationElement* animation) {
-  auto* position = std::find(sandwich_.begin(), sandwich_.end(), animation);
+  auto* position = base::ranges::find(sandwich_, animation);
   DCHECK(sandwich_.end() != position);
   sandwich_.erase(position);
   // Clear the animated value when there are active animation elements but the
diff --git a/third_party/blink/renderer/core/timing/profiler_group.cc b/third_party/blink/renderer/core/timing/profiler_group.cc
index 0dead83..7012a62c 100644
--- a/third_party/blink/renderer/core/timing/profiler_group.cc
+++ b/third_party/blink/renderer/core/timing/profiler_group.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/timing/profiler_group.h"
 
+#include "base/ranges/algorithm.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "third_party/blink/public/platform/task_type.h"
@@ -325,8 +326,7 @@
 
   // we use a vector instead of a map because the expected number of profiler
   // is expected to be very small
-  auto* it = std::find(detached_profiler_ids_.begin(),
-                       detached_profiler_ids_.end(), profiler_id);
+  auto* it = base::ranges::find(detached_profiler_ids_, profiler_id);
 
   if (it == detached_profiler_ids_.end()) {
     // Profiler already stopped
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
index c29f668..ea703a33 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -8,6 +8,7 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
 #include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_request_requestorusvstringsequence_usvstring.h"
@@ -261,7 +262,7 @@
     const SkBitmap& icon,
     int64_t ideal_to_chosen_icon_size) {
   if (loader)
-    loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader));
+    loaders_.erase(base::ranges::find(loaders_, loader));
 
   auto ukm_data = mojom::blink::BackgroundFetchUkmData::New();
   ukm_data->ideal_to_chosen_icon_size = ideal_to_chosen_icon_size;
diff --git a/third_party/blink/renderer/modules/bluetooth/README.md b/third_party/blink/renderer/modules/bluetooth/README.md
index 5e4dd78..6da8fdf 100644
--- a/third_party/blink/renderer/modules/bluetooth/README.md
+++ b/third_party/blink/renderer/modules/bluetooth/README.md
@@ -43,8 +43,14 @@
         abstraction layer.
 *   `testing/clusterfuzz`
     *   [Web Bluetooth Fuzzer] runs on cluster fuzz infrastructure.
+*   [Web Bluetooth Manual Tests]
+    *   Not browser-specific.
+    *   Relies on the full Bluetooth hardware stack. Helps find bugs
+        specific to an operating system, or even OS level bugs.
+    *   Can be run by external web-application developers.
 
 [Web Bluetooth Fuzzer]: testing/clusterfuzz/README.md
+[Web Bluetooth Manual Tests]: https://github.com/WebBluetoothCG/manual-tests
 
 
 ## Design Documents
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.cc b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.cc
index b7e315e..f195684 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.cc
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.cc
@@ -120,10 +120,9 @@
       interpolable_value, untyped_non_interpolable_value, conversion_data);
 }
 
-void GetAnimatedShapesFromKeyframes(
+scoped_refptr<BasicShape> GetAnimatedShapeFromKeyframe(
     const PropertySpecificKeyframe* frame,
     const KeyframeEffectModelBase* model,
-    Vector<scoped_refptr<BasicShape>>* animated_shapes,
     const Element* element) {
   scoped_refptr<BasicShape> basic_shape;
   if (model->IsStringKeyframeEffectModel()) {
@@ -156,7 +155,7 @@
         *non_interpolable_value);
   }
   DCHECK(basic_shape);
-  animated_shapes->push_back(basic_shape);
+  return basic_shape;
 }
 
 void GetCompositorKeyframeOffset(const PropertySpecificKeyframe* frame,
@@ -322,7 +321,7 @@
     const gfx::SizeF& clip_area_size,
     const Node& node) {
   DCHECK(node.IsElementNode());
-  const Element* element = static_cast<Element*>(const_cast<Node*>(&node));
+  const Element* element = To<Element>(&node);
 
   Vector<scoped_refptr<BasicShape>> animated_shapes;
   Vector<double> offsets;
@@ -343,7 +342,8 @@
           PropertyHandle(GetCSSPropertyClipPath()));
 
   for (const auto& frame : *frames) {
-    GetAnimatedShapesFromKeyframes(frame, model, &animated_shapes, element);
+    animated_shapes.push_back(
+        GetAnimatedShapeFromKeyframe(frame, model, element));
     GetCompositorKeyframeOffset(frame, offsets);
   }
   progress = effect->Progress();
@@ -364,6 +364,39 @@
   return PaintWorkletDeferredImage::Create(std::move(input), clip_area_size);
 }
 
+// TODO(crbug.com/1374390) adjust for custom timing functions
+gfx::RectF ClipPathPaintDefinition::ClipAreaRect(
+    const Node& node,
+    const gfx::RectF& reference_box,
+    float zoom) {
+  DCHECK(node.IsElementNode());
+  const Element* element = To<Element>(&node);
+
+  const Animation* animation = GetAnimationIfCompositable(element);
+  DCHECK(animation);
+
+  const AnimationEffect* effect = animation->effect();
+  DCHECK(effect->IsKeyframeEffect());
+  const KeyframeEffectModelBase* model =
+      static_cast<const KeyframeEffect*>(effect)->Model();
+  const PropertySpecificKeyframeVector* frames =
+      model->GetPropertySpecificKeyframes(
+          PropertyHandle(GetCSSPropertyClipPath()));
+
+  gfx::RectF clip_area;
+
+  for (const auto& frame : *frames) {
+    scoped_refptr<BasicShape> basic_shape =
+        GetAnimatedShapeFromKeyframe(frame, model, element);
+    scoped_refptr<ShapeClipPathOperation> scpo =
+        ShapeClipPathOperation::Create(basic_shape);
+    Path path = scpo->GetPath(reference_box, zoom);
+    clip_area.Union(path.BoundingRect());
+  }
+
+  return clip_area;
+}
+
 void ClipPathPaintDefinition::Trace(Visitor* visitor) const {
   NativePaintDefinition::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.h b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.h
index 484c3fd..58acf0b 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.h
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.h
@@ -39,6 +39,11 @@
                              const gfx::RectF& reference_box,
                              const gfx::SizeF& clip_area_size,
                              const Node&);
+  // The bounding rect for the entire animation, fitting the clip path at its
+  // largest extent
+  static gfx::RectF ClipAreaRect(const Node& node,
+                                 const gfx::RectF& reference_box,
+                                 float zoom);
   static Animation* GetAnimationIfCompositable(const Element* element);
   void Trace(Visitor* visitor) const override;
 };
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc
index 80c8c55..02c0bda 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc
@@ -69,4 +69,48 @@
             animation);
 }
 
+TEST_F(ClipPathPaintDefinitionTest, ClipBoundingBoxEncompassesAnimation) {
+  ScopedCompositeClipPathAnimationForTest composite_clip_path_animation(true);
+  SetBodyInnerHTML(R"HTML(
+    <div id ="target" style="position: fixed; width: 100px; height: 100px">
+    </div>
+  )HTML");
+
+  Timing timing;
+  timing.iteration_duration = ANIMATION_TIME_DELTA_FROM_SECONDS(30);
+
+  CSSPropertyID property_id = CSSPropertyID::kClipPath;
+  Persistent<StringKeyframe> start_keyframe =
+      MakeGarbageCollected<StringKeyframe>();
+  start_keyframe->SetCSSPropertyValue(property_id, "inset(20% 20%)",
+                                      SecureContextMode::kInsecureContext,
+                                      nullptr);
+  Persistent<StringKeyframe> end_keyframe =
+      MakeGarbageCollected<StringKeyframe>();
+  end_keyframe->SetCSSPropertyValue(property_id, "inset(-100% -100%)",
+                                    SecureContextMode::kInsecureContext,
+                                    nullptr);
+
+  StringKeyframeVector keyframes;
+  keyframes.push_back(start_keyframe);
+  keyframes.push_back(end_keyframe);
+
+  auto* model = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
+  model->SetComposite(EffectModel::kCompositeReplace);
+
+  Element* element = GetElementById("target");
+  NonThrowableExceptionState exception_state;
+  DocumentTimeline* timeline =
+      MakeGarbageCollected<DocumentTimeline>(&GetDocument());
+  Animation* animation = Animation::Create(
+      MakeGarbageCollected<KeyframeEffect>(element, model, timing), timeline,
+      exception_state);
+  UpdateAllLifecyclePhasesForTest();
+  animation->play();
+
+  gfx::RectF reference_box = gfx::RectF(0, 0, 100, 100);
+  EXPECT_EQ(ClipPathPaintDefinition::ClipAreaRect(*element, reference_box, 1.f),
+            gfx::RectF(-100, -100, 300, 300));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_image_generator_impl.cc b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_image_generator_impl.cc
index 73568bd8..287f922 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_image_generator_impl.cc
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_image_generator_impl.cc
@@ -35,6 +35,13 @@
                                             node);
 }
 
+gfx::RectF ClipPathPaintImageGeneratorImpl::ClipAreaRect(
+    const Node& node,
+    const gfx::RectF& reference_box,
+    float zoom) const {
+  return clip_path_paint_definition_->ClipAreaRect(node, reference_box, zoom);
+}
+
 Animation* ClipPathPaintImageGeneratorImpl::GetAnimationIfCompositable(
     const Element* element) {
   return ClipPathPaintDefinition::GetAnimationIfCompositable(element);
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_image_generator_impl.h b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_image_generator_impl.h
index 700b2572..7c1716e4e 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_image_generator_impl.h
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_image_generator_impl.h
@@ -26,6 +26,9 @@
                              const gfx::RectF& reference_box,
                              const gfx::SizeF& clip_area_size,
                              const Node&) final;
+  gfx::RectF ClipAreaRect(const Node& node,
+                          const gfx::RectF& reference_box,
+                          float zoom) const final;
   Animation* GetAnimationIfCompositable(const Element* element) final;
 
   void Shutdown() final;
diff --git a/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.cc
index 85caafc..aa044a2 100644
--- a/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/document_picture_in_picture/picture_in_picture_controller_impl.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/callback_helpers.h"
+#include "base/ranges/algorithm.h"
 #include "media/mojo/mojom/media_player.mojom-blink.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
@@ -347,8 +348,7 @@
 void PictureInPictureControllerImpl::RemoveFromAutoPictureInPictureElementsList(
     HTMLVideoElement* element) {
   DCHECK(element);
-  auto it = std::find(auto_picture_in_picture_elements_.begin(),
-                      auto_picture_in_picture_elements_.end(), element);
+  auto it = base::ranges::find(auto_picture_in_picture_elements_, element);
   if (it != auto_picture_in_picture_elements_.end())
     auto_picture_in_picture_elements_.erase(it);
 }
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture.cc b/third_party/blink/renderer/modules/imagecapture/image_capture.cc
index 922b37d..88b8b50 100644
--- a/third_party/blink/renderer/modules/imagecapture/image_capture.cc
+++ b/third_party/blink/renderer/modules/imagecapture/image_capture.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/trace_event/trace_event.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
@@ -55,10 +56,6 @@
 const char kInvalidStateTrackError[] =
     "The associated Track is in an invalid state";
 
-bool Contains(const Vector<bool>& vector, bool value) {
-  return std::find(vector.begin(), vector.end(), value) != vector.end();
-}
-
 bool TrackIsInactive(const MediaStreamTrack& track) {
   // Spec instructs to return an exception if the Track's readyState() is not
   // "live". Also reject if the track is disabled or muted.
@@ -774,7 +771,7 @@
       constraints->backgroundBlur()->IsBoolean();
   if (settings->has_background_blur_mode) {
     const auto background_blur = constraints->backgroundBlur()->GetAsBoolean();
-    if (!Contains(capabilities_->backgroundBlur(), background_blur)) {
+    if (!base::Contains(capabilities_->backgroundBlur(), background_blur)) {
       resolver->Reject(MakeGarbageCollected<OverconstrainedError>(
           "backgroundBlur", "backgroundBlur setting value not supported"));
       return;
diff --git a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
index 4ab3bfb..d03c65e7 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
@@ -1035,6 +1035,14 @@
   outline: none;
 }
 
+audio::-internal-media-controls-text-track-list-header:focus-visible,
+video::-internal-media-controls-text-track-list-header:focus-visible,
+audio::-internal-media-controls-playback-speed-list-header:focus-visible,
+video::-internal-media-controls-playback-speed-list-header:focus-visible,
+audio::-internal-media-controls-text-track-list-item:focus-visible,
+video::-internal-media-controls-text-track-list-item:focus-visible,
+audio::-internal-media-controls-playback-speed-list-item:focus-visible,
+video::-internal-media-controls-playback-speed-list-item:focus-visible,
 audio::-internal-media-controls-overflow-menu-list-item:focus-visible,
 video::-internal-media-controls-overflow-menu-list-item:focus-visible {
   border: 1px solid currentColor;
@@ -1643,10 +1651,6 @@
     border: 1px solid Window;
     margin: 2px;
   }
-  audio::-internal-media-controls-overflow-menu-list-item:focus,
-  video::-internal-media-controls-overflow-menu-list-item:focus {
-    border: 1px solid Highlight;
-  }
   label[pseudo="-internal-media-controls-overflow-menu-list-item"] div span.subtitle {
     color: WindowText;
   }
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
index e2f35e43de..a7d328f 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/location.h"
+#include "base/ranges/algorithm.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -715,7 +716,7 @@
 
 static void RemoveSinkInternal(Vector<WebMediaStreamSink*>* sinks,
                                WebMediaStreamSink* sink) {
-  auto** it = std::find(sinks->begin(), sinks->end(), sink);
+  auto** it = base::ranges::find(*sinks, sink);
   DCHECK(it != sinks->end());
   sinks->erase(it);
 }
diff --git a/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc b/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc
index ae009b7b..896a0df 100644
--- a/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.cc
@@ -12,6 +12,7 @@
 #include "base/check_op.h"
 #include "base/containers/contains.h"
 #include "base/notreached.h"
+#include "base/ranges/algorithm.h"
 #include "third_party/blink/renderer/modules/peerconnection/mock_data_channel_impl.h"
 #include "third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h"
 #include "third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h"
@@ -407,16 +408,14 @@
     rtc::scoped_refptr<webrtc::RtpSenderInterface> s) {
   rtc::scoped_refptr<FakeRtpSender> sender(
       static_cast<FakeRtpSender*>(s.get()));
-  auto it = std::find(senders_.begin(), senders_.end(), sender);
-  if (it == senders_.end()) {
+  if (!base::Contains(senders_, sender)) {
     return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                             "Mock: sender not found in senders");
   }
   sender->SetTrack(nullptr);
 
   for (const auto& stream_id : sender->stream_ids()) {
-    auto local_stream_it = std::find(local_stream_ids_.begin(),
-                                     local_stream_ids_.end(), stream_id);
+    auto local_stream_it = base::ranges::find(local_stream_ids_, stream_id);
     if (local_stream_it != local_stream_ids_.end())
       local_stream_ids_.erase(local_stream_it);
   }
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
index c1172eb4..58168b9 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
@@ -7,7 +7,6 @@
 #include <ctype.h>
 #include <string.h>
 
-#include <algorithm>
 #include <functional>
 #include <memory>
 #include <set>
@@ -16,6 +15,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
@@ -2262,7 +2262,7 @@
   // removed transceivers are reflected as "stopped" in JavaScript.
   Vector<uintptr_t> removed_transceivers;
   for (auto transceiver_id : previous_transceiver_ids_) {
-    if (std::find(ids.begin(), ids.end(), transceiver_id) == ids.end()) {
+    if (!base::Contains(ids, transceiver_id)) {
       removed_transceivers.emplace_back(transceiver_id);
       rtp_transceivers_.erase(FindTransceiver(transceiver_id));
     }
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_info.cc b/third_party/blink/renderer/modules/quota/deprecated_storage_info.cc
index cfcef98..c823419 100644
--- a/third_party/blink/renderer/modules/quota/deprecated_storage_info.cc
+++ b/third_party/blink/renderer/modules/quota/deprecated_storage_info.cc
@@ -94,32 +94,22 @@
 DeprecatedStorageQuota* DeprecatedStorageInfo::GetStorageQuota(
     int storage_type,
     ExecutionContext* execution_context) {
-  switch (storage_type) {
-    case kTemporary:
-      if (!temporary_storage_) {
-        temporary_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>(
-            DeprecatedStorageQuota::kTemporary, execution_context);
-      }
-      return temporary_storage_.Get();
-    case kPersistent:
-      // Show deprecation message and record usage for persistent storage type.
-      Deprecation::CountDeprecation(execution_context,
-                                    WebFeature::kPersistentQuotaType);
-      if (blink::features::IsPersistentQuotaIsTemporaryQuota())
-        return GetStorageQuota(kTemporary, execution_context);
-
-      if (!persistent_storage_) {
-        persistent_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>(
-            DeprecatedStorageQuota::kPersistent, execution_context);
-      }
-      return persistent_storage_.Get();
+  if (storage_type == kPersistent) {
+    // Show deprecation message and record usage for persistent storage type.
+    Deprecation::CountDeprecation(execution_context,
+                                  WebFeature::kPersistentQuotaType);
   }
-  return nullptr;
+  // As of crbug.com/1233525 kPersistent quota type is deprecated.
+  // Ignore `storage_type` and always return `temporary_storage_`.
+  if (!temporary_storage_) {
+    temporary_storage_ =
+        MakeGarbageCollected<DeprecatedStorageQuota>(execution_context);
+  }
+  return temporary_storage_.Get();
 }
 
 void DeprecatedStorageInfo::Trace(Visitor* visitor) const {
   visitor->Trace(temporary_storage_);
-  visitor->Trace(persistent_storage_);
   ScriptWrappable::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_info.h b/third_party/blink/renderer/modules/quota/deprecated_storage_info.h
index 2c958fd..6492ae5d 100644
--- a/third_party/blink/renderer/modules/quota/deprecated_storage_info.h
+++ b/third_party/blink/renderer/modules/quota/deprecated_storage_info.h
@@ -72,7 +72,6 @@
                                           ExecutionContext* execution_context);
 
   mutable Member<DeprecatedStorageQuota> temporary_storage_;
-  mutable Member<DeprecatedStorageQuota> persistent_storage_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_info.idl b/third_party/blink/renderer/modules/quota/deprecated_storage_info.idl
index 9ca1126..976f60af 100644
--- a/third_party/blink/renderer/modules/quota/deprecated_storage_info.idl
+++ b/third_party/blink/renderer/modules/quota/deprecated_storage_info.idl
@@ -27,6 +27,8 @@
     LegacyNoInterfaceObject,
     RuntimeEnabled=PrefixedStorageInfo
 ] interface DeprecatedStorageInfo {
+    // As of crbug.com/1233525, PERSISTENT quota type is deprecated and
+    // `storageType` parameter will be ignored.
     const unsigned short TEMPORARY = 0;
     const unsigned short PERSISTENT = 1;
 
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc
index 2c788d3..72d9aea 100644
--- a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc
+++ b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.cc
@@ -32,7 +32,6 @@
 
 #include "base/location.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_storage_error_callback.h"
@@ -56,21 +55,6 @@
 
 namespace {
 
-StorageType GetStorageType(DeprecatedStorageQuota::Type type) {
-  if (blink::features::IsPersistentQuotaIsTemporaryQuota()) {
-    DCHECK_EQ(type, DeprecatedStorageQuota::kTemporary);
-    return StorageType::kTemporary;
-  }
-  switch (type) {
-    case DeprecatedStorageQuota::kTemporary:
-      return StorageType::kTemporary;
-    case DeprecatedStorageQuota::kPersistent:
-      return StorageType::kPersistent;
-    default:
-      return StorageType::kUnknown;
-  }
-}
-
 void DeprecatedQueryStorageUsageAndQuotaCallback(
     V8StorageUsageCallback* success_callback,
     V8StorageErrorCallback* error_callback,
@@ -129,9 +113,8 @@
 }
 
 DeprecatedStorageQuota::DeprecatedStorageQuota(
-    Type type,
     ExecutionContext* execution_context)
-    : type_(type), quota_host_(execution_context) {}
+    : quota_host_(execution_context) {}
 
 void DeprecatedStorageQuota::queryUsageAndQuota(
     ScriptState* script_state,
@@ -144,15 +127,6 @@
   // attribute, so the kQuotaRead use counter must be explicitly updated.
   UseCounter::Count(execution_context, WebFeature::kQuotaRead);
 
-  StorageType storage_type = GetStorageType(type_);
-  if (storage_type != StorageType::kTemporary &&
-      storage_type != StorageType::kPersistent) {
-    // Unknown storage type is requested.
-    EnqueueStorageErrorCallback(script_state, error_callback,
-                                DOMExceptionCode::kNotSupportedError);
-    return;
-  }
-
   const SecurityOrigin* security_origin =
       execution_context->GetSecurityOrigin();
   if (security_origin->IsOpaque()) {
@@ -164,9 +138,11 @@
   auto callback = WTF::BindOnce(&DeprecatedQueryStorageUsageAndQuotaCallback,
                                 WrapPersistent(success_callback),
                                 WrapPersistent(error_callback));
+  // StorageType::kPersistent is deprecated as of crbug.com/1233525.
+  // Therefore all requests are for StorageType::kTemporary.
   GetQuotaHost(execution_context)
       ->QueryStorageUsageAndQuota(
-          storage_type,
+          StorageType::kTemporary,
           mojo::WrapCallbackWithDefaultInvokeIfNotRun(
               std::move(callback), mojom::blink::QuotaStatusCode::kErrorAbort,
               0, 0, nullptr));
@@ -182,15 +158,6 @@
   // attribute, so the kQuotaRead use counter must be explicitly updated.
   UseCounter::Count(execution_context, WebFeature::kQuotaRead);
 
-  StorageType storage_type = GetStorageType(type_);
-  if (storage_type != StorageType::kTemporary &&
-      storage_type != StorageType::kPersistent) {
-    // Unknown storage type is requested.
-    EnqueueStorageErrorCallback(script_state, error_callback,
-                                DOMExceptionCode::kNotSupportedError);
-    return;
-  }
-
   auto callback = WTF::BindOnce(&RequestStorageQuotaCallback,
                                 WrapPersistent(success_callback),
                                 WrapPersistent(error_callback));
@@ -201,9 +168,11 @@
     return;
   }
 
+  // StorageType::kPersistent is deprecated as of crbug.com/1233525.
+  // Therefore all requests are for StorageType::kTemporary.
   GetQuotaHost(execution_context)
       ->RequestStorageQuota(
-          storage_type, new_quota_in_bytes,
+          StorageType::kTemporary, new_quota_in_bytes,
           mojo::WrapCallbackWithDefaultInvokeIfNotRun(
               std::move(callback), mojom::blink::QuotaStatusCode::kErrorAbort,
               0, 0));
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h
index dc46c0a..d7f3dd2 100644
--- a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h
+++ b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h
@@ -51,16 +51,11 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  enum Type {
-    kTemporary,
-    kPersistent,
-  };
-
   static void EnqueueStorageErrorCallback(ScriptState*,
                                           V8StorageErrorCallback*,
                                           DOMExceptionCode);
 
-  DeprecatedStorageQuota(Type, ExecutionContext*);
+  explicit DeprecatedStorageQuota(ExecutionContext*);
 
   void queryUsageAndQuota(ScriptState*,
                           V8StorageUsageCallback*,
@@ -78,7 +73,6 @@
   // provider, and returns it,
   mojom::blink::QuotaManagerHost* GetQuotaHost(ExecutionContext*);
 
-  Type type_;
   HeapMojoRemote<mojom::blink::QuotaManagerHost> quota_host_;
 };
 
diff --git a/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc b/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
index e67a7999..97b75cb 100644
--- a/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
+++ b/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
@@ -31,7 +31,6 @@
 #include "third_party/blink/renderer/modules/quota/navigator_storage_quota.h"
 
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/core/frame/deprecation/deprecation.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/navigator.h"
@@ -61,8 +60,7 @@
   NavigatorStorageQuota& navigator_storage = From(navigator);
   if (!navigator_storage.temporary_storage_) {
     navigator_storage.temporary_storage_ =
-        MakeGarbageCollected<DeprecatedStorageQuota>(
-            DeprecatedStorageQuota::kTemporary, navigator.DomWindow());
+        MakeGarbageCollected<DeprecatedStorageQuota>(navigator.DomWindow());
   }
 
   // Record metrics for usage in third-party contexts.
@@ -81,23 +79,8 @@
     Deprecation::CountDeprecation(navigator.DomWindow(),
                                   WebFeature::kPersistentQuotaType);
   }
-  if (blink::features::IsPersistentQuotaIsTemporaryQuota())
-    return webkitTemporaryStorage(navigator);
-
-  NavigatorStorageQuota& navigator_storage = From(navigator);
-  if (!navigator_storage.persistent_storage_) {
-    navigator_storage.persistent_storage_ =
-        MakeGarbageCollected<DeprecatedStorageQuota>(
-            DeprecatedStorageQuota::kPersistent, navigator.DomWindow());
-  }
-
-  // Record metrics for usage in third-party contexts.
-  if (navigator.DomWindow()) {
-    navigator.DomWindow()->CountUseOnlyInCrossSiteIframe(
-        WebFeature::kPrefixedStorageQuotaThirdPartyContext);
-  }
-
-  return navigator_storage.persistent_storage_.Get();
+  // Persistent quota type is deprecated as of crbug.com/1233525.
+  return webkitTemporaryStorage(navigator);
 }
 
 StorageManager* NavigatorStorageQuota::storage(NavigatorBase& navigator) {
@@ -111,7 +94,6 @@
 
 void NavigatorStorageQuota::Trace(Visitor* visitor) const {
   visitor->Trace(temporary_storage_);
-  visitor->Trace(persistent_storage_);
   visitor->Trace(storage_manager_);
   Supplement<NavigatorBase>::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/modules/quota/navigator_storage_quota.h b/third_party/blink/renderer/modules/quota/navigator_storage_quota.h
index 45dde6a..06f6c43 100644
--- a/third_party/blink/renderer/modules/quota/navigator_storage_quota.h
+++ b/third_party/blink/renderer/modules/quota/navigator_storage_quota.h
@@ -62,7 +62,6 @@
   static NavigatorStorageQuota& From(NavigatorBase&);
 
   mutable Member<DeprecatedStorageQuota> temporary_storage_;
-  mutable Member<DeprecatedStorageQuota> persistent_storage_;
   mutable Member<StorageManager> storage_manager_;
 };
 
diff --git a/third_party/blink/renderer/modules/quota/navigator_storage_quota.idl b/third_party/blink/renderer/modules/quota/navigator_storage_quota.idl
index e8bd4d5..ea74e64a 100644
--- a/third_party/blink/renderer/modules/quota/navigator_storage_quota.idl
+++ b/third_party/blink/renderer/modules/quota/navigator_storage_quota.idl
@@ -24,6 +24,8 @@
 ] partial interface Navigator {
     // http://www.w3.org/TR/2012/WD-quota-api-20120703/#idl-def-StorageQuotaEnvironment
     [MeasureAs=PrefixedStorageQuota] readonly attribute DeprecatedStorageQuota webkitTemporaryStorage;
+
+    // As of crbug.com/1233525, webkitPersistentStorage is an alias to webkitTemporaryStorage.
     [MeasureAs=PrefixedStorageQuota] readonly attribute DeprecatedStorageQuota webkitPersistentStorage;
 
     // https://storage.spec.whatwg.org/#api
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
index 358cb11..876bd56 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
@@ -7,6 +7,7 @@
 #include <cinttypes>
 #include <limits>
 
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/numerics/safe_conversions.h"
@@ -102,8 +103,7 @@
                            ExceptionState* exception_state,
                            WTF::String error_message,
                            WTF::Vector<T> supported_values) {
-  if (std::find(supported_values.begin(), supported_values.end(), value) ==
-      supported_values.end()) {
+  if (!base::Contains(supported_values, value)) {
     if (exception_state) {
       WTF::StringBuilder error_builder;
       error_builder.Append(error_message);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index d646d5cf..8fbce131 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -28,6 +28,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/numerics/checked_math.h"
 #include "base/synchronization/lock.h"
@@ -3410,9 +3411,7 @@
 bool ShouldMeasureGLParam(GLenum pname) {
   return IdentifiabilityStudySettings::Get()->ShouldSampleType(
              blink::IdentifiableSurface::Type::kWebGLParameter) &&
-         std::find(std::begin(kIdentifiableGLParams),
-                   std::end(kIdentifiableGLParams),
-                   pname) != std::end(kIdentifiableGLParams);
+         base::Contains(kIdentifiableGLParams, pname);
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
index f435d5e..ecd989fe 100644
--- a/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
+++ b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
@@ -11,6 +11,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
 #include "base/threading/thread_checker.h"
 #include "build/build_config.h"
 #include "media/audio/audio_sink_parameters.h"
@@ -774,7 +775,7 @@
     return false;
 
   PlayingStates& array = found->second;
-  auto state_it = std::find(array.begin(), array.end(), state);
+  auto state_it = base::ranges::find(array, state);
   if (state_it == array.end())
     return false;
 
diff --git a/third_party/blink/renderer/platform/mediastream/media_constraints.cc b/third_party/blink/renderer/platform/mediastream/media_constraints.cc
index f495e6e6..3d2e7d6 100644
--- a/third_party/blink/renderer/platform/mediastream/media_constraints.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_constraints.cc
@@ -31,6 +31,8 @@
 #include "third_party/blink/renderer/platform/mediastream/media_constraints.h"
 
 #include <math.h>
+
+#include "base/containers/contains.h"
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -417,8 +419,7 @@
     String& found_name) const {
   for (auto* const constraint : AllConstraints()) {
     if (constraint->HasMandatory()) {
-      if (std::find(good_names.begin(), good_names.end(),
-                    constraint->GetName()) == good_names.end()) {
+      if (!base::Contains(good_names, constraint->GetName())) {
         found_name = constraint->GetName();
         return true;
       }
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h b/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h
index 9c66dcb..0776bd26 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h
@@ -5,9 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_MEDIASTREAM_MEDIA_STREAM_AUDIO_DELIVERER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MEDIASTREAM_MEDIA_STREAM_AUDIO_DELIVERER_H_
 
-#include <algorithm>
-
 #include "base/containers/contains.h"
+#include "base/ranges/algorithm.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "base/trace_event/trace_event.h"
@@ -69,12 +68,11 @@
     base::AutoLock auto_lock(consumers_lock_);
     const bool had_consumers =
         !consumers_.empty() || !pending_consumers_.empty();
-    auto it = std::find(consumers_.begin(), consumers_.end(), consumer);
+    auto it = base::ranges::find(consumers_, consumer);
     if (it != consumers_.end()) {
       consumers_.erase(it);
     } else {
-      it = std::find(pending_consumers_.begin(), pending_consumers_.end(),
-                     consumer);
+      it = base::ranges::find(pending_consumers_, consumer);
       if (it != pending_consumers_.end())
         pending_consumers_.erase(it);
     }
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_stats.cc b/third_party/blink/renderer/platform/peerconnection/rtc_stats.cc
index c548511..8ecf99ef 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_stats.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_stats.cc
@@ -4,11 +4,11 @@
 
 #include "third_party/blink/renderer/platform/peerconnection/rtc_stats.h"
 
-#include <algorithm>
 #include <set>
 #include <string>
 
 #include "base/check_op.h"
+#include "base/containers/contains.h"
 #include "base/containers/cxx20_erase.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_piece.h"
@@ -97,7 +97,7 @@
         const std::vector<webrtc::NonStandardGroupId>& ids =
             member->group_ids();
         for (const webrtc::NonStandardGroupId& id : exposed_group_ids) {
-          if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
+          if (base::Contains(ids, id)) {
             return false;
           }
         }
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
index d610a37..f1ddab07 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
@@ -4,13 +4,13 @@
 
 #include "third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.h"
 
-#include <algorithm>
 #include <limits>
 
 #include "base/callback_helpers.h"
 #include "base/check_op.h"
 #include "base/containers/contains.h"
 #include "base/location.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "media/base/audio_timestamp_helper.h"
@@ -243,7 +243,7 @@
   SendLogMessage(
       base::StringPrintf("Adapter::RemoveSink([label=%s])", label_.c_str()));
   base::AutoLock auto_lock(lock_);
-  const auto it = std::find(sinks_.begin(), sinks_.end(), sink);
+  const auto it = base::ranges::find(sinks_, sink);
   if (it != sinks_.end())
     sinks_.erase(it);
 }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index afb8be6..7930c17 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -699,6 +699,7 @@
     {
       // crbug.com/924069
       name: "CSSHyphenateLimitChars",
+      status: "test",
     },
     {
       name: "CSSIcUnit",
@@ -898,7 +899,7 @@
       //
       // https://drafts.csswg.org/css-values-4/#viewport-relative-units
       name: "CSSViewportUnits4",
-      status: "experimental",
+      status: "stable",
     },
     // Support for view-timeline.
     //
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index b2c549d..051cb30 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -59,7 +59,7 @@
 using ::base::sequence_manager::FakeTask;
 using ::base::sequence_manager::FakeTaskTiming;
 using blink::WebInputEvent;
-using FeatureAndParams = ::base::test::ScopedFeatureList::FeatureAndParams;
+using FeatureAndParams = ::base::test::FeatureRefAndParams;
 using ::testing::InSequence;
 using ::testing::Mock;
 using ::testing::NiceMock;
diff --git a/third_party/blink/renderer/platform/widget/input/scroll_predictor_unittest.cc b/third_party/blink/renderer/platform/widget/input/scroll_predictor_unittest.cc
index 5e71095c..4b9761b 100644
--- a/third_party/blink/renderer/platform/widget/input/scroll_predictor_unittest.cc
+++ b/third_party/blink/renderer/platform/widget/input/scroll_predictor_unittest.cc
@@ -146,13 +146,13 @@
       const std::string& filter_type) {
     base::FieldTrialParams pred_field_params;
     pred_field_params["predictor"] = predictor_type;
-    base::test::ScopedFeatureList::FeatureAndParams prediction_params = {
-        pred_feature, pred_field_params};
+    base::test::FeatureRefAndParams prediction_params = {pred_feature,
+                                                         pred_field_params};
 
     base::FieldTrialParams filter_field_params;
     filter_field_params["filter"] = filter_type;
-    base::test::ScopedFeatureList::FeatureAndParams filter_params = {
-        filter_feature, filter_field_params};
+    base::test::FeatureRefAndParams filter_params = {filter_feature,
+                                                     filter_field_params};
 
     scoped_feature_list_.Reset();
     scoped_feature_list_.InitWithFeaturesAndParameters(
@@ -177,7 +177,7 @@
   void InitLinearResamplingTest(bool use_frames_based_experimental_prediction) {
     base::FieldTrialParams params;
     params["filter"] = ::features::kPredictorNameLinearResampling;
-    base::test::ScopedFeatureList::FeatureAndParams prediction_params = {
+    base::test::FeatureRefAndParams prediction_params = {
         features::kResamplingScrollEvents, params};
 
     base::FieldTrialParams prediction_type_params;
@@ -185,10 +185,9 @@
         use_frames_based_experimental_prediction
             ? ::features::kPredictionTypeFramesBased
             : ::features::kPredictionTypeTimeBased;
-    base::test::ScopedFeatureList::FeatureAndParams
-        experimental_prediction_params = {
-            ::features::kResamplingScrollEventsExperimentalPrediction,
-            prediction_type_params};
+    base::test::FeatureRefAndParams experimental_prediction_params = {
+        ::features::kResamplingScrollEventsExperimentalPrediction,
+        prediction_type_params};
 
     scoped_feature_list_.Reset();
     scoped_feature_list_.InitWithFeaturesAndParameters(
diff --git a/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines.py b/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines.py
index eb655f7..02cb965 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines.py
@@ -23,17 +23,38 @@
             self.test_option,
             self.suffixes_option,
             self.port_name_option,
+            self.flag_specific_option,
             self.results_directory_option,
         ])
 
     def execute(self, options, args, tool):
         self._tool = tool
         port_name = options.port_name
+        flag_specific = options.flag_specific
         for suffix in options.suffixes.split(','):
-            self._copy_existing_baseline(port_name, options.test, suffix)
+            self._copy_existing_baseline(port_name, flag_specific,
+                                         options.test, suffix)
 
-    def _copy_existing_baseline(self, port_name, test_name, suffix):
+    def _log_skipped_test(self, port, test_name):
+        flag_specific = port.get_option('flag_specific')
+        if flag_specific:
+            _log.debug('%s is skipped on %s(%s).', test_name, port.name(),
+                       flag_specific)
+        else:
+            _log.debug('%s is skipped on %s.', test_name, port.name())
+
+    def _copy_existing_baseline(self, port_name, flag_specific, test_name,
+                                suffix):
         """Copies the baseline for the given builder to all "predecessor" directories."""
+
+        # copy existing non virtual baseline to virtual subtree
+        self._patch_virtual_subtree(port_name, flag_specific, test_name,
+                                    suffix)
+
+        if flag_specific:
+            # No test will fallback to a flag-specific baseline
+            return
+
         baseline_directory = self._tool.port_factory.get(
             port_name).baseline_version_dir()
         ports = [
@@ -41,17 +62,19 @@
             _immediate_predecessors_in_fallback(baseline_directory)
         ]
 
+        # Copy baseline to any flag specific suite running on the port
+        for flag_specific_config in self._tool.builders.flag_specific_options_for_port_name(
+                port_name):
+            port = self._tool.port_factory.get(port_name)
+            port.set_option_default('flag_specific', flag_specific_config)
+            ports.append(port)
+
         old_baselines = []
         new_baselines = []
 
         # Need to gather all the baseline paths before modifying the filesystem since
         # the modifications can affect the results of port.expected_filename.
         for port in ports:
-            old_baseline = port.expected_filename(test_name, '.' + suffix)
-            if not self._tool.filesystem.exists(old_baseline):
-                _log.debug('No existing baseline for %s.', test_name)
-                continue
-
             new_baseline = self._tool.filesystem.join(
                 port.baseline_version_dir(),
                 self._file_name_for_expected_result(test_name, suffix))
@@ -63,11 +86,17 @@
             full_expectations = TestExpectations(port)
             if ResultType.Skip in full_expectations.get_expectations(
                     test_name).results:
-                _log.debug('%s is skipped on %s.', test_name, port.name())
+                self._log_skipped_test(port, test_name)
                 continue
-            if (port.skipped_due_to_smoke_tests(test_name) or
-                    port.virtual_test_skipped_due_to_platform_config(test_name)):
-                _log.debug('%s is skipped on %s.', test_name, port.name())
+            if port.skips_test(test_name):
+                self._log_skipped_test(port, test_name)
+                continue
+
+            old_baseline = port.expected_filename(test_name, '.' + suffix)
+            if not self._tool.filesystem.exists(old_baseline):
+                _log.debug('No existing baseline(%s) for %s.', suffix,
+                           test_name)
+                # TODO: downloading all passing baseline for this test harness test
                 continue
 
             old_baselines.append(old_baseline)
@@ -83,6 +112,58 @@
                 self._tool.filesystem.dirname(new_baseline))
             self._tool.filesystem.copyfile(old_baseline, new_baseline)
 
+    def _patch_virtual_subtree(self, port_name, flag_specific, test_name,
+                               suffix):
+        port = self._tool.port_factory.get(port_name)
+        if flag_specific:
+            port.set_option_default('flag_specific', flag_specific)
+        full_expectations = TestExpectations(port)
+
+        if port.lookup_virtual_test_base(test_name):
+            # Do nothing for virtual tests
+            return
+
+        old_baseline = port.expected_filename(test_name,
+                                              '.' + suffix,
+                                              return_default=False)
+
+        for vts in port.virtual_test_suites():
+            virtual_test_name = vts.full_prefix + test_name
+            if port.lookup_virtual_test_base(virtual_test_name) is None:
+                # Not a valid virtual test
+                continue
+
+            if ResultType.Skip in full_expectations.get_expectations(
+                    virtual_test_name).results:
+                self._log_skipped_test(port, virtual_test_name)
+                continue
+
+            if port.skips_test(test_name):
+                self._log_skipped_test(port, virtual_test_name)
+                continue
+
+            baseline_dir, filename = port.expected_baselines(
+                virtual_test_name, '.' + suffix)[0]
+            if baseline_dir is not None:
+                # This virtual test does not fall back to non virtual baseline
+                continue
+
+            if old_baseline is None:
+                _log.debug('No existing non virtual baseline(%s) for %s.',
+                           suffix, virtual_test_name)
+                # TODO: downloading all passing baseline for this virtual test harness test
+                continue
+
+            new_baseline = self._tool.filesystem.join(
+                port.baseline_version_dir(),
+                self._file_name_for_expected_result(virtual_test_name, suffix))
+
+            _log.debug('Copying baseline from %s to %s.', old_baseline,
+                       new_baseline)
+            self._tool.filesystem.maybe_make_directory(
+                self._tool.filesystem.dirname(new_baseline))
+            self._tool.filesystem.copyfile(old_baseline, new_baseline)
+
     def _port_for_primary_baseline(self, baseline):
         """Returns a Port object for the given baseline directory base name."""
         for port in [
diff --git a/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines_unittest.py
index 6b6aceb..a930b1fd 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines_unittest.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/copy_existing_baselines_unittest.py
@@ -17,6 +17,7 @@
             'suffixes': 'txt',
             'verbose': False,
             'port_name': None,
+            'flag_specific': None,
         }
         options_dict.update(kwargs)
         return optparse.Values(options_dict)
@@ -42,6 +43,11 @@
                 self.baseline_path(
                     'platform/test-mac-mac10.10/failures/expected/image-expected.txt'
                 )))
+        self.assertFalse(
+            self.tool.filesystem.exists(
+                self.baseline_path(
+                    'platform/test-mac-mac10.11/virtual/virtual_failures/failures/expected/image-expected.txt'
+                )))
 
         self.command.execute(
             self.options(
@@ -58,6 +64,122 @@
                 self.baseline_path(
                     'platform/test-mac-mac10.10/failures/expected/image-expected.txt'
                 )), 'original test-mac-mac10.11 result')
+        self.assertEqual(
+            self._read(
+                self.baseline_path(
+                    'platform/test-mac-mac10.11/virtual/virtual_failures/failures/expected/image-expected.txt'
+                )), 'original test-mac-mac10.11 result')
+
+    def test_copy_baseline_linux_newer_to_older_and_flag_specific(self):
+        self._write(
+            self.baseline_path(
+                'platform/test-linux-trusty/failures/expected/image-expected.txt'
+            ), 'original test-linux-trusty result')
+        self.assertFalse(
+            self.tool.filesystem.exists(
+                self.baseline_path(
+                    'platform/test-linux-precise/failures/expected/image-expected.txt'
+                )))
+        self.assertFalse(
+            self.tool.filesystem.exists(
+                self.baseline_path(
+                    'flag-specific/disable-layout-ng/failures/expected/image-expected.txt'
+                )))
+
+        self.command.execute(
+            self.options(port_name='test-linux-trusty',
+                         test='failures/expected/image.html'), [], self.tool)
+
+        self.assertEqual(
+            self._read(
+                self.baseline_path(
+                    'platform/test-linux-trusty/failures/expected/image-expected.txt'
+                )), 'original test-linux-trusty result')
+        self.assertEqual(
+            self._read(
+                self.baseline_path(
+                    'platform/test-linux-precise/failures/expected/image-expected.txt'
+                )), 'original test-linux-trusty result')
+        self.assertEqual(
+            self._read(
+                self.baseline_path(
+                    'flag-specific/disable-layout-ng/failures/expected/image-expected.txt'
+                )), 'original test-linux-trusty result')
+
+    def test_copy_virtual_baseline_for_flag_specific(self):
+        self._write(
+            self.baseline_path(
+                'flag-specific/disable-layout-ng/failures/expected/image1-expected.txt'
+            ), 'original test-linux-trusty image1 result')
+        self._write(
+            self.baseline_path(
+                'flag-specific/disable-layout-ng/failures/expected/image2-expected.txt'
+            ), 'original test-linux-trusty image2 result')
+        self._write(
+            self.baseline_path(
+                'platform/test-linux-trusty/virtual/virtual_failures/failures/expected/image2-expected.txt'
+            ), 'original test-linux-trusty image2 virtual result')
+        self.assertFalse(
+            self.tool.filesystem.exists(
+                self.baseline_path(
+                    'platform/test-linux-trusty/virtual/virtual_failures/failures/expected/image1-expected.txt'
+                )))
+        self.assertFalse(
+            self.tool.filesystem.exists(
+                self.baseline_path(
+                    'flag-specific/disable-layout-ng/virtual/virtual_failures/failures/expected/image1-expected.txt'
+                )))
+        self.assertFalse(
+            self.tool.filesystem.exists(
+                self.baseline_path(
+                    'flag-specific/disable-layout-ng/virtual/virtual_failures/failures/expected/image2-expected.txt'
+                )))
+
+        self.command.execute(
+            self.options(port_name='test-linux-trusty',
+                         flag_specific='disable-layout-ng',
+                         test='failures/expected/image1.html'), [], self.tool)
+
+        self.command.execute(
+            self.options(port_name='test-linux-trusty',
+                         flag_specific='disable-layout-ng',
+                         test='failures/expected/image2.html'), [], self.tool)
+
+        self.assertEqual(
+            self._read(
+                self.baseline_path(
+                    'flag-specific/disable-layout-ng/virtual/virtual_failures/failures/expected/image1-expected.txt'
+                )), 'original test-linux-trusty image1 result')
+        self.assertFalse(
+            self.tool.filesystem.exists(
+                self.baseline_path(
+                    'flag-specific/disable-layout-ng/virtual/virtual_failures/failures/expected/image2-expected.txt'
+                )))
+
+    def test_no_copy_existing_virtual_baseline(self):
+        self._write(
+            self.baseline_path(
+                'platform/test-mac-mac10.10/failures/expected/image-expected.txt'
+            ), 'original test-mac-mac10.10 result')
+        self._write(
+            self.baseline_path(
+                'platform/test-mac-mac10.11/virtual/virtual_failures/failures/expected/image-expected.txt'
+            ), 'original test-mac-mac10.11 result')
+        self.assertFalse(
+            self.tool.filesystem.exists(
+                self.baseline_path(
+                    'platform/test-mac-mac10.10/virtual/virtual_failures/failures/expected/image-expected.txt'
+                )))
+
+        self.command.execute(
+            self.options(port_name='test-mac-mac10.11',
+                         test='failures/expected/image.html'), [], self.tool)
+
+        self.assertFalse(
+            self.tool.filesystem.exists(
+                self.baseline_path(
+                    'platform/test-mac-mac10.10/virtual/virtual_failures/failures/expected/image-expected.txt'
+                )))
 
     def test_copy_baseline_to_multiple_immediate_predecessors(self):
         # The test-win-win10 baseline is copied over to the test-linux-trusty
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
index 9b5082c..de6339c6 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
@@ -34,6 +34,7 @@
 
 from collections import defaultdict
 
+from blinkpy.common import message_pool
 from blinkpy.common.path_finder import WEB_TESTS_LAST_COMPONENT
 from blinkpy.common.memoized import memoized
 from blinkpy.common.net.results_fetcher import Build
@@ -412,10 +413,10 @@
         return args
 
     def _rebaseline_commands(self, test_baseline_set, options):
-        test_port_pairs_to_suffixes = collections.defaultdict(set)
         path_to_blink_tool = self._tool.path()
         cwd = self._tool.git().checkout_root
         rebaseline_commands = []
+        copy_baseline_commands = []
         lines_to_remove = {}
         fetch_urls = []
 
@@ -445,11 +446,9 @@
                     lines_to_remove[test].append(port_name)
                 continue
 
-            if suffixes:
-                test_port_pairs_to_suffixes[test, port_name].update(suffixes)
-
             flag_spec_option = self._tool.builders.flag_specific_option(
                 build.builder_name, step_name)
+
             args = self._rebaseline_args(test, suffixes, port_name,
                                          flag_spec_option, options.verbose)
             args.extend(['--builder', build.builder_name])
@@ -470,19 +469,14 @@
             ] + args
             rebaseline_commands.append((rebaseline_command, cwd))
 
-        copy_baseline_commands = []
-        for (test, port_name), suffixes in sorted(
-                test_port_pairs_to_suffixes.items()):
             copy_command = [
                 self._tool.executable,
                 path_to_blink_tool,
                 'copy-existing-baselines-internal',
             ]
             copy_command.extend(
-                self._rebaseline_args(test,
-                                      suffixes,
-                                      port_name,
-                                      verbose=options.verbose))
+                self._rebaseline_args(test, suffixes, port_name,
+                                      flag_spec_option, options.verbose))
             copy_baseline_commands.append((copy_command, cwd))
 
         return copy_baseline_commands, rebaseline_commands, lines_to_remove
@@ -603,7 +597,11 @@
             system_remover.remove_os_versions(test, versions)
         system_remover.update_expectations()
 
-    def _run_in_parallel(self, commands):
+    def _run_in_parallel(self, commands, resultdb):
+        """
+        Parallel run the commands using the MessagePool class to make sure that
+        each process will have only one request session.
+        """
         if not commands:
             return []
 
@@ -612,15 +610,29 @@
                 _log.debug('Would have run: "%s"',
                            self._tool.executive.command_for_printing(command))
             return [(0, '', '')] * len(commands)
+        results = []
+        if resultdb:
+            try:
+                pool = message_pool.get(self, self._worker_factory,
+                                        self._tool.executive.cpu_count(),
+                                        self._tool)
+                pool.run(('rebaseline', command) for command, cwd in commands)
+            except Exception as error:
+                _log.debug('%s("%s") raised, exiting',
+                           error.__class__.__name__, error)
+                raise
+        else:
+            results = self._tool.executive.run_in_parallel(commands)
 
-        command_results = self._tool.executive.run_in_parallel(commands)
-        for _, _, stderr in command_results:
+        for _, _, stderr in results:
             if stderr:
                 lines = stderr.decode("utf-8", "ignore").splitlines()
                 for line in lines:
                     print(line)
+        return results
 
-        return command_results
+    def _worker_factory(self, worker_connection):
+        return Worker(worker_connection, self._tool.git().checkout_root)
 
     def rebaseline(self, options, test_baseline_set):
         """Fetches new baselines and removes related test expectation lines.
@@ -645,9 +657,12 @@
         copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = self._rebaseline_commands(
             test_baseline_set, options)
         lines_to_remove = {}
-        self._run_in_parallel(copy_baseline_commands)
-
-        command_results = self._run_in_parallel(rebaseline_commands)
+        # TODO(crbug/1213998): Make both copy and rebaseline command use the
+        # message pool, currently the second time when run the message pool,
+        # it will halt there.
+        self._run_in_parallel(copy_baseline_commands, False)
+        command_results = self._run_in_parallel(
+            rebaseline_commands, getattr(options, 'resultDB', False))
         change_set = self._extract_expectation_line_changes(command_results)
         lines_to_remove = change_set.lines_to_remove
         for test in extra_lines_to_remove:
@@ -831,3 +846,30 @@
         _log.debug('Rebaselining: %s', test_baseline_set)
 
         self.rebaseline(options, test_baseline_set)
+
+
+class Worker(object):
+    def __init__(self, caller, cwd):
+
+        # Add the header here to avoid the circle import
+        from blinkpy.tool.blink_tool import BlinkTool
+
+        self._caller = caller
+        self._tool = BlinkTool(cwd)
+
+    def __del__(self):
+        self.stop()
+
+    def start(self):
+        """This method is called when the object is starting to be used and it is safe
+        for the object to create state that does not need to be pickled (usually this means
+        it is called in a child process).
+        """
+        pass
+
+    def handle(self, name, source, command):
+        assert name == 'rebaseline'
+        self._tool.main(command[1:])
+
+    def stop(self):
+        _log.debug('%s cleaning up', self._caller.name)
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
index 6223a513..affedd1 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
@@ -18,6 +18,7 @@
 from blinkpy.tool.commands.rebaseline_cl import RebaselineCL
 from blinkpy.tool.commands.rebaseline_unittest import BaseTestCase
 from blinkpy.web_tests.builder_list import BuilderList
+from unittest import mock
 
 
 class RebaselineCLTest(BaseTestCase, LoggingTestCase):
@@ -332,14 +333,15 @@
                 build, self.web_test_resultsdb)
             self.tool.results_fetcher.set_artifact_query_for_build(
                 build, self.test_artifacts_list)
-        exit_code = self.command.execute(self.command_options(resultDB=True),
-                                         [], self.tool)
-        self.assertEqual(exit_code, 0)
-        self.assertLog([
-            'INFO: All builds finished.\n',
-            'INFO: Rebaselining one/missing.html\n',
-            'INFO: Rebaselining two/image-fail.html\n',
-        ])
+        with mock.patch('blinkpy.common.message_pool.get'):
+            exit_code = self.command.execute(
+                self.command_options(resultDB=True), [], self.tool)
+            self.assertEqual(exit_code, 0)
+            self.assertLog([
+                'INFO: All builds finished.\n',
+                'INFO: Rebaselining one/missing.html\n',
+                'INFO: Rebaselining two/image-fail.html\n',
+            ])
 
     def test_execute_with_test_name_file(self):
         fs = self.mac_port.host.filesystem
@@ -386,17 +388,18 @@
                 build, self.web_test_resultsdb)
             self.tool.results_fetcher.set_artifact_query_for_build(
                 build, self.test_artifacts_list)
-        exit_code = self.command.execute(
-            self.command_options(test_name_file=test_name_file, resultDB=True),
-            [], self.tool)
-        self.assertEqual(exit_code, 0)
-        self.assertLog([
-            'INFO: All builds finished.\n',
-            'INFO: Reading list of tests to rebaseline from %s\n' %
-            test_name_file,
-            'INFO: Rebaselining one/missing.html\n',
-            'INFO: Rebaselining two/image-fail.html\n',
-        ])
+        with mock.patch('blinkpy.common.message_pool.get'):
+            exit_code = self.command.execute(
+                self.command_options(test_name_file=test_name_file,
+                                     resultDB=True), [], self.tool)
+            self.assertEqual(exit_code, 0)
+            self.assertLog([
+                'INFO: All builds finished.\n',
+                'INFO: Reading list of tests to rebaseline from %s\n' %
+                test_name_file,
+                'INFO: Rebaselining one/missing.html\n',
+                'INFO: Rebaselining two/image-fail.html\n',
+            ])
 
     def test_execute_with_no_issue_number_aborts(self):
         # If the user hasn't uploaded a CL, an error message is printed.
@@ -722,11 +725,24 @@
             self.command_options(builders=['MOCK Try Linux Multiple Steps']),
             ['one/text-fail.html', 'one/does-not-exist.html'], self.tool)
         self.assertEqual(exit_code, 0)
-        self.assertEqual(self.tool.executive.calls[0], [[
-            'python', 'echo', 'copy-existing-baselines-internal', '--test',
-            'one/text-fail.html', '--suffixes', 'txt', '--port-name',
-            'test-linux-trusty'
-        ]])
+        self.assertEqual(sorted(self.tool.executive.calls[0]), [
+            [
+                'python', 'echo', 'copy-existing-baselines-internal', '--test',
+                'one/text-fail.html', '--suffixes', 'txt', '--port-name',
+                'test-linux-trusty'
+            ],
+            [
+                'python', 'echo', 'copy-existing-baselines-internal', '--test',
+                'one/text-fail.html', '--suffixes', 'txt', '--port-name',
+                'test-linux-trusty', '--flag-specific', 'disable-layout-ng'
+            ],
+            [
+                'python', 'echo', 'copy-existing-baselines-internal', '--test',
+                'one/text-fail.html', '--suffixes', 'txt', '--port-name',
+                'test-linux-trusty', '--flag-specific',
+                'disable-site-isolation-trials'
+            ],
+        ])
         self.assertEqual(sorted(self.tool.executive.calls[1]), [
             [
                 'python', 'echo', 'rebaseline-test-internal', '--test',
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
index 40d1c49..c676ab4 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
@@ -113,8 +113,19 @@
         self.test_expectations_path = self.mac_port.path_to_generic_test_expectations_file(
         )
 
-        # These files must exist for Port classes to function properly.
-        self._write('VirtualTestSuites', '[]')
+        self._write(
+            'VirtualTestSuites',
+            json.dumps([{
+                "prefix":
+                "prefix",
+                "platforms": ["Linux", "Mac"],
+                "bases": [
+                    "userscripts/first-test.html",
+                    'userscripts/second-test.html'
+                ],
+                "args": ["--enable-features=flag"]
+            }]))
+
         self._write(
             'FlagSpecificConfig',
             json.dumps([
@@ -134,6 +145,7 @@
         # Create some dummy tests (note _setup_mock_build_data uses the same test names).
         self._write('userscripts/first-test.html', 'Dummy test contents')
         self._write('userscripts/second-test.html', 'Dummy test contents')
+        self._write('userscripts/third-test.html', 'Dummy test contents')
 
         # In AbstractParallelRebaselineCommand._rebaseline_commands, a default port
         # object is gotten using self.tool.port_factory.get(), which is used to get
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py
index f9c557a0..287fe7cf 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -1352,13 +1352,11 @@
         """Checks whether the given test is skipped for this port.
 
         Returns True if:
-          - the test is a manual test
           - the port runs smoke tests only and the test is not in the list
           - the test is marked as Skip in NeverFixTest
           - the test is a virtual test not intended to run on this platform.
         """
-        return (self.is_manual_test(test)
-                or self.skipped_due_to_smoke_tests(test)
+        return (self.skipped_due_to_smoke_tests(test)
                 or self.skipped_in_never_fix_tests(test)
                 or self.virtual_test_skipped_due_to_platform_config(test))
 
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index e94a0b32..1728a33 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -11,6 +11,9 @@
 # Tests that fail in legacy but pass in NG
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-hashchange.html [ Timeout ]
+crbug.com/626703 external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-pushstate.html [ Timeout ]
+crbug.com/626703 external/wpt/screen-orientation/non-fully-active.html [ Timeout ]
 crbug.com/626703 external/wpt/fetch/api/abort/serviceworker-intercepted.https.html [ Timeout ]
 crbug.com/626703 virtual/orb-v01/external/wpt/fetch/api/abort/serviceworker-intercepted.https.html [ Timeout ]
 crbug.com/626703 virtual/plz-dedicated-worker/external/wpt/fetch/api/abort/serviceworker-intercepted.https.html [ Timeout ]
@@ -2169,6 +2172,7 @@
 crbug.com/1147859 paint/markers/inline-spelling-markers-hidpi.html [ Failure ]
 crbug.com/1147859 paint/markers/marker-early-break-bug.html [ Failure ]
 crbug.com/1147859 paint/markers/markers-zoomed.html [ Failure ]
+crbug.com/1121942 printing/abspos-multicol-with-abspos.html [ Failure ]
 crbug.com/1121942 printing/block-with-overflow-in-bottom-aligned-fixedpos.html [ Pass ]
 crbug.com/1311165 printing/fixed-positioned-but-static-headers-and-footers.html [ Failure ]
 crbug.com/1121942 printing/fixed-positioned-headers-and-footers-clipped.html [ Pass ]
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
index 0213f02..2c1646c 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
+++ b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
@@ -53,6 +53,9 @@
 crbug.com/1209233 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-hashchange.html [ Timeout ]
+crbug.com/626703 external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-pushstate.html [ Timeout ]
+crbug.com/626703 external/wpt/screen-orientation/non-fully-active.html [ Timeout ]
 crbug.com/626703 external/wpt/fetch/api/abort/serviceworker-intercepted.https.html [ Timeout ]
 crbug.com/626703 virtual/orb-v01/external/wpt/fetch/api/abort/serviceworker-intercepted.https.html [ Timeout ]
 crbug.com/626703 external/wpt/encoding/unsupported-labels.window.html [ Failure Timeout ]
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index b88d44a..3586f59 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -1952,8 +1952,8 @@
 crbug.com/1260483 virtual/fenced-frame-mparch/http/tests/inspector-protocol/fenced-frame/* [ Pass ]
 
 # Feature is not yet launched, so skip the base.
-crbug.com/1293679 external/wpt/page-unload-beacon/* [ Skip ]
-crbug.com/1293679 virtual/pending-beacon/external/wpt/page-unload-beacon/* [ Pass ]
+crbug.com/1293679 external/wpt/unload-beacon/* [ Skip ]
+crbug.com/1293679 virtual/pending-beacon/external/wpt/unload-beacon/* [ Pass ]
 
 # Experimental JS shared memory features
 crbug.com/1351118 wpt_internal/js/shared_memory/* [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index edf8df2..8be9236d 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3340,6 +3340,11 @@
 crbug.com/626703 [ Win ] virtual/partitioned-cookies/http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-hashchange.html [ Timeout ]
+crbug.com/626703 external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-pushstate.html [ Timeout ]
+crbug.com/626703 external/wpt/screen-orientation/non-fully-active.html [ Timeout ]
+crbug.com/626703 [ Mac ] external/wpt/screen-orientation/lock-basic.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/screen-orientation/lock-sandboxed-iframe.html [ Failure ]
 crbug.com/626703 [ Win10.20h2 ] external/wpt/webaudio/idlharness.https.window.html [ Failure Timeout ]
 crbug.com/626703 [ Win10.20h2 ] virtual/css-highlight-overlay-painting/external/wpt/css/css-highlight-api/idlharness.window.html [ Failure Timeout ]
 crbug.com/626703 virtual/storage-access-api/external/wpt/storage-access-api/requestStorageAccess.sub.window.html [ Failure ]
@@ -7273,3 +7278,5 @@
 crbug.com/1374264 [ Mac ] external/wpt/screen-capture/permissions-policy-audio+video.https.sub.html [ Failure ]
 crbug.com/1374264 [ Mac ] external/wpt/screen-capture/permissions-policy-audio.https.sub.html [ Failure ]
 crbug.com/1374264 [ Mac ] external/wpt/screen-capture/permissions-policy-video.https.sub.html [ Failure ]
+
+crbug.com/1372181 external/wpt/scroll-animations/css/scroll-timeline-default-iframe-print.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 0f61b0d..014f5ddba 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1251,7 +1251,7 @@
     "prefix": "pending-beacon",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [
-      "external/wpt/page-unload-beacon",
+      "external/wpt/unload-beacon",
       "wpt_internal/pending_beacon"
     ],
     "args": [
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 34d08c4..61c11b1 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -624,13 +624,6 @@
         {}
        ]
       ],
-      "image-in-fragmented-flexbox-crash.html": [
-       "3c8a6c52944da437e1d8a0b5e6cf35b766f2c1c0",
-       [
-        null,
-        {}
-       ]
-      ],
       "monolithic-item-in-fragmented-flexbox-crash.html": [
        "edf13244e1b4b5a8f29185f2aef52cde2c12445a",
        [
@@ -2494,6 +2487,20 @@
        null,
        {}
       ]
+     ],
+     "webkit-line-clamp-041-crash.html": [
+      "3f4bf3c8ef578fa22469e81e504879aa5d713bf8",
+      [
+       null,
+       {}
+      ]
+     ],
+     "webkit-line-clamp-042-crash.html": [
+      "1a5fe2e246ff5abb8b4096223c8f0fd47a3968b2",
+      [
+       null,
+       {}
+      ]
      ]
     },
     "css-paint-api": {
@@ -2591,6 +2598,13 @@
        {}
       ]
      ],
+     "highlight-painting-soft-hyphens-002-crash.html": [
+      "eb80d4890991f1b3d92b6c6e0b580bd7408016a5",
+      [
+       null,
+       {}
+      ]
+     ],
      "placeholder-as-multicol-crash.html": [
       "8407f95d7f3489de2f476a8993c10326fe5801ac",
       [
@@ -3372,6 +3386,13 @@
        null,
        {}
       ]
+     ],
+     "wm-propagation-table-internals-crash.html": [
+      "8f5798cf09d7f6e85337bce4d628025d6e14f4c4",
+      [
+       null,
+       {}
+      ]
      ]
     },
     "cssom": {
@@ -94383,6 +94404,19 @@
        {}
       ]
      ],
+     "at-supports-047.html": [
+      "8ad858581478dad4721079b54c079fd93fab57c7",
+      [
+       null,
+       [
+        [
+         "/css/css-conditional/at-supports-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "at-supports-content-001.html": [
       "19c99f504be7766978dc3816d186e7c2dabe126e",
       [
@@ -148904,6 +148938,19 @@
        {}
       ]
      ],
+     "webkit-line-clamp-043.html": [
+      "54f0ac538daaa351de0e7d870e8bf35f3a6711f8",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "webkit-line-clamp-block-in-inline-001.html": [
       "75d1de3bf5bcf5d00d6980de4a70845e9f7ae8e4",
       [
@@ -174657,7 +174704,7 @@
        ]
       ],
       "text-align-justify-001.html": [
-       "f2ba8cc230201b7e180517e9f7574797c0fc8a4d",
+       "9e1319e91ee07252b9d5d40666d0c65b1f0671b6",
        [
         null,
         [
@@ -174670,7 +174717,7 @@
        ]
       ],
       "text-align-justify-002.html": [
-       "3f91b6d478987585a701b1f7548c81571e3f4da0",
+       "250f680393bc4f1740dddc867e3011ec2ef54336",
        [
         null,
         [
@@ -174683,7 +174730,7 @@
        ]
       ],
       "text-align-justify-003.html": [
-       "73d0b2fe69deb8195de993ccc32eb6ef7140d9ab",
+       "b08cd88e7ad86f5997fbabfdc1b6a64b163877f9",
        [
         null,
         [
@@ -174696,7 +174743,7 @@
        ]
       ],
       "text-align-justify-004.html": [
-       "f8621ee8a11f0343bf895d23b086bf63d8189f71",
+       "20ca4fe24212a423a3fc0da004254554ef28736a",
        [
         null,
         [
@@ -174709,7 +174756,7 @@
        ]
       ],
       "text-align-justify-005.html": [
-       "5723776938f50ca21edba4df7a156c358f6625ae",
+       "851e1a0950745f2a08622c29d769d97fd177c360",
        [
         null,
         [
@@ -174722,7 +174769,7 @@
        ]
       ],
       "text-align-justify-006.html": [
-       "2a92792107897f518bbecec0f5e17d5fb3615ecd",
+       "d02fa47aeaa1ee2d9c1cbe3ce0db4001ed5ab420",
        [
         null,
         [
@@ -175040,7 +175087,7 @@
        ]
       ],
       "text-align-start-001.html": [
-       "43219cc248fcca0a20cacae5993860b7e4cd292e",
+       "3af1130f2c3d582114fed052b597895c5eaa419b",
        [
         null,
         [
@@ -175053,7 +175100,7 @@
        ]
       ],
       "text-align-start-002.html": [
-       "911a185ade6bb542e6dda6e08836df336ab9dfe6",
+       "27aad6fde678e08b5832b6c15cec331434960d47",
        [
         null,
         [
@@ -175066,7 +175113,7 @@
        ]
       ],
       "text-align-start-003.html": [
-       "0ca38da0bec7fb9568f678e6ab657f55a380ebd3",
+       "9a007f09fb631a965710f35ccee9e3d714f8999e",
        [
         null,
         [
@@ -175079,7 +175126,7 @@
        ]
       ],
       "text-align-start-004.html": [
-       "739bd8811ff4034742c52cb92a3bd9d16b0882e5",
+       "b1e01e3ed934e8e12bed36f86350624684441785",
        [
         null,
         [
@@ -175092,7 +175139,7 @@
        ]
       ],
       "text-align-start-005.html": [
-       "5dbe17de9b15245811e12fb65525031f2b59afbb",
+       "37c61154803d7b9c9a7a648fce5e2d9b54f22edf",
        [
         null,
         [
@@ -175105,7 +175152,7 @@
        ]
       ],
       "text-align-start-006.html": [
-       "8557affeb770d8a777e5e7d6cde8d5c64ed82ea5",
+       "b55c7cb7da61c147ba8b5a944c7da2c5f9d72368",
        [
         null,
         [
@@ -175118,7 +175165,7 @@
        ]
       ],
       "text-align-start-007.html": [
-       "1a56287c355774e982c4861c60ec6c2452e80173",
+       "f79c10947c766665f462810f74e2150432bdec1d",
        [
         null,
         [
@@ -175131,7 +175178,7 @@
        ]
       ],
       "text-align-start-008.html": [
-       "3885c4dba459eed467e560a2161552c91252a733",
+       "81ff886f751bf46c96c511f921e5a2acae733e85",
        [
         null,
         [
@@ -175144,7 +175191,7 @@
        ]
       ],
       "text-align-start-009.html": [
-       "044c896a02c409263fe021c1dc13b3d1fafb02cd",
+       "bf231c56429483da753f6ceafe01e3b98743012f",
        [
         null,
         [
@@ -175157,7 +175204,7 @@
        ]
       ],
       "text-align-start-010.html": [
-       "358fc373aad11a96bd169e8c6b26ee3424997122",
+       "215e60b3895ed5c9223b5a3ef64eb9529e13d17a",
        [
         null,
         [
@@ -175170,7 +175217,7 @@
        ]
       ],
       "text-align-start-014.html": [
-       "04a2bf562e5596814dfcd9d0fef74538b69b7331",
+       "add058c38082701bf481e2bb631ef720e83338bf",
        [
         null,
         [
@@ -175183,7 +175230,7 @@
        ]
       ],
       "text-align-start-015.html": [
-       "ba41e6142c9dccbab0ae9694997a4972efea04c3",
+       "b8432da1c23e5dd73edf9a39cd6800c8da504706",
        [
         null,
         [
@@ -175196,7 +175243,7 @@
        ]
       ],
       "text-align-start-016.html": [
-       "c45667b59f0dc5d007b7b4502c79048bfcb73209",
+       "ab9bc30b595c73075ba1ce2bc99dcbb9c194d4c9",
        [
         null,
         [
@@ -175209,7 +175256,7 @@
        ]
       ],
       "text-align-start-017.html": [
-       "55273f897de00458689f59bbd9dd2f7a0e5974a4",
+       "554adb8faf51877a0d76f96d4d69fa7cc1a150ae",
        [
         null,
         [
@@ -188225,7 +188272,7 @@
       ]
      },
      "fractional-scale-gradient-bg-obscure-red-bg.html": [
-      "3796b099b9687e3c55ae6da01e3f9f2cf9ea0d5d",
+      "4fbc7590c7b98f527e8c135e559d195616cb49ef",
       [
        null,
        [
@@ -188234,7 +188281,23 @@
          "=="
         ]
        ],
-       {}
+       {
+        "fuzzy": [
+         [
+          null,
+          [
+           [
+            0,
+            1
+           ],
+           [
+            0,
+            350
+           ]
+          ]
+         ]
+        ]
+       }
       ]
      ],
      "gradientTransform": {
@@ -232000,7 +232063,7 @@
       ]
      ],
      "nesting.html": [
-      "7160b9a1c2263ca269393b73c403b598d7fc8288",
+      "c5e3e9282ee2529d09ecd2e93cb78a1f702595f2",
       [
        null,
        [
@@ -256141,7 +256204,7 @@
       []
      ],
      "dispatcher.js": [
-      "4b9b18dad7799e0598201d05e17812b8195464cc",
+      "a0f9f43e622483c3ab4df2621a4e4be40692eebf",
       []
      ],
      "dispatcher.py": [
@@ -256198,7 +256261,7 @@
      []
     ],
     "object-association.js": [
-     "458aae67db0cef0ce8306b6c2b56297b344ee615",
+     "669c17c07b1ae5bfbe3ac5205a2dd927818154d4",
      []
     ],
     "object-association.js.headers": [
@@ -259336,7 +259399,7 @@
      ],
      "fedcm-manifest-not-in-list": {
       "fedcm.json": [
-       "c29126e183b0ec06f80e60aefa5970793c547ffa",
+       "fe8c06b1ee9518eeb6d77f6baa266d108df9b527",
        []
       ]
      },
@@ -259349,7 +259412,7 @@
       []
      ],
      "fedcm.json": [
-      "b4901f538c239dc4c994d233d4349e92016be6f7",
+      "7f5eec2f0ad82c5b64553640baf1e61a791745a1",
       []
      ],
      "federatedcredential-get.html": [
@@ -259807,6 +259870,14 @@
        "e93c831aeb43c7e5de5308e0fba6292fe2415a31",
        []
       ],
+      "background-intrinsic-004.xht.ini": [
+       "5c34090db683e9c1f3535fe3c28b3970933d185f",
+       []
+      ],
+      "background-intrinsic-006.xht.ini": [
+       "0c7d04c69bf4b5c381df1ccb8f6cfc542860ca7c",
+       []
+      ],
       "background-intrinsic-ref.xht": [
        "5efb66f202d30c264113c1ef26615dab628df24d",
        []
@@ -261751,6 +261822,10 @@
        "32efe5b4f805365a509634a0373c2b659ba10a54",
        []
       ],
+      "inherit-computed-001.html.ini": [
+       "12e8c80098d2962204fdfcda9e10ab4ffb685722",
+       []
+      ],
       "inherit-computed-002-ref.html": [
        "d127db1e42ff2025b3333965d376fdac47d729ba",
        []
@@ -262059,14 +262134,34 @@
        "540c8048af61a2c7804d99ff14c3a2bf1f87e6ad",
        []
       ],
+      "float-nowrap-3-ref.html.ini": [
+       "b73dfd8dcd60cd6908afcaf9ac20524cf9d854f1",
+       []
+      ],
       "float-nowrap-4-ref.html": [
        "a8c7b060819839dd1e7107a327dfbf32fb1ea794",
        []
       ],
+      "float-nowrap-4.html.ini": [
+       "460132587ff26a1a1e5bad329e42dcd4925db9c3",
+       []
+      ],
       "float-nowrap-5-ref.html": [
        "7f400841037cfb79bafa2c41d3834cdd942445f4",
        []
       ],
+      "float-nowrap-7.html.ini": [
+       "d3a5d2cbe02b22d0c3173c5a055ee18d894912d8",
+       []
+      ],
+      "float-nowrap-8.html.ini": [
+       "8e07c4780556503778b82cbc44976ed6d106c21a",
+       []
+      ],
+      "float-nowrap-9.html.ini": [
+       "8eab0f65affc9e07d0f214ca1abc7a336fa68069",
+       []
+      ],
       "float-root-ref.html": [
        "1f593f460a0da7dbde9a2c8b3f96628d88f7c9df",
        []
@@ -262099,6 +262194,10 @@
        "f16aba29c9d4161854223705e7818a5a2b5cfcf5",
        []
       ],
+      "floats-rule3-outside-left-002.xht.ini": [
+       "5a03f09f4404275d5d476c74d6806f03ed3eda22",
+       []
+      ],
       "floats-rule3-outside-right-001-ref.xht": [
        "149574160700e8b6ff7e6f1239a51809edd98cdb",
        []
@@ -262107,14 +262206,26 @@
        "e95714e46680c38678e4fd854e41c85c8aa9c0ed",
        []
       ],
+      "floats-rule3-outside-right-002.xht.ini": [
+       "cbad66d3a8f3257e7e3cea8f03dced6104266e7a",
+       []
+      ],
       "floats-rule7-outside-left-001-ref.xht": [
        "546e2ae41c11c952da305474c868f1839559751f",
        []
       ],
+      "floats-rule7-outside-left-001.xht.ini": [
+       "8ed9f3c1a488b83e06f89d965b17d5dcb133c3f4",
+       []
+      ],
       "floats-rule7-outside-right-001-ref.xht": [
        "69e1a26a28330022f9517763257198dffb9fc0c3",
        []
       ],
+      "floats-rule7-outside-right-001.xht.ini": [
+       "0a1b241c746749b717fbd086c68e1fd73b0ec8d4",
+       []
+      ],
       "floats-wrap-bfc-001-left-overflow-ref.xht": [
        "9d4c968d1d687c42932cfa205775f300de4fe343",
        []
@@ -262167,6 +262278,10 @@
        "59051f846a58397e9d629553dd49e6f8f800e3be",
        []
       ],
+      "floats-wrap-bfc-006.xht.ini": [
+       "382770ac676086ffe314c88c88aa500b99b6066e",
+       []
+      ],
       "floats-wrap-bfc-007-ref.xht": [
        "f67bd790c31f5b69504d69b60ca591d968172883",
        []
@@ -262929,10 +263044,34 @@
        "f82f8fe1aeaeb656aeb8cb2a22cc869dfebbd50b",
        []
       ],
+      "inline-formatting-context-002.xht.ini": [
+       "3b6420d558a7756d30d36aa819ff47edeb728a39",
+       []
+      ],
       "inline-formatting-context-003-ref.xht": [
        "03ba993de2ce5b3da4a3ee744bccb3c79df6dd81",
        []
       ],
+      "inline-formatting-context-003.xht.ini": [
+       "394620b9e26e0e0730162bcb0e6e5eb05ed8c77f",
+       []
+      ],
+      "inline-formatting-context-004.xht.ini": [
+       "ecad8c49042f6527591c6180ec1811608fbac766",
+       []
+      ],
+      "inline-formatting-context-005.xht.ini": [
+       "75606e254490cb68218da36b25cbb6331a73e454",
+       []
+      ],
+      "inline-formatting-context-006.xht.ini": [
+       "e98a1b582c659a8a4a9b3c7387b9579b1c15e843",
+       []
+      ],
+      "inline-formatting-context-007.xht.ini": [
+       "a59ef6cbc53bc4cba87abd5b8c9393bb30856d7b",
+       []
+      ],
       "inline-formatting-context-008-ref.xht": [
        "8650d13d3833c659d09e616e545714441cb37a21",
        []
@@ -263175,6 +263314,14 @@
        "9167843266f8ba8954df276e537100fe0ac42a44",
        []
       ],
+      "vertical-align-sub-001.xht.ini": [
+       "6089c80d81db77ac9570a1927a50c8c7435a7885",
+       []
+      ],
+      "vertical-align-super-001.xht.ini": [
+       "ab61c7551181a1ac369c70f0da98a94998ec6eae",
+       []
+      ],
       "vertical-align-top-bottom-padding-ref.html": [
        "f855bab6a2f4a8845aebd98fb33b7c9e0d4adc8c",
        []
@@ -263721,6 +263868,14 @@
        "4570a69eeec2a8cd802d706e8b0f44756d2ce328",
        []
       ],
+      "max-width-applies-to-005.xht.ini": [
+       "53ce2670d442104944ce533fd9435960d1c136f8",
+       []
+      ],
+      "max-width-applies-to-006.xht.ini": [
+       "7d62d814540a99b5a0754c90b22009715564c9b5",
+       []
+      ],
       "max-width-percentage-001-ref.xht": [
        "e9ff55264073e183faed2aff2454f49104a10c62",
        []
@@ -263749,10 +263904,18 @@
        "d48d43e00a4c8c03b2ce948e5cadcf8c4119a85d",
        []
       ],
+      "replaced-intrinsic-001.xht.ini": [
+       "d4c4ce64a0c4ceb91415eaaf330b808e68a8f5d3",
+       []
+      ],
       "replaced-intrinsic-002-ref.xht": [
        "16ec5f231920842f3b288354d48cebaebc3185e7",
        []
       ],
+      "replaced-intrinsic-002.xht.ini": [
+       "bf85cf0048b0844b0f7fabb1fd5bc3f07b5e3307",
+       []
+      ],
       "replaced-intrinsic-003-ref.xht": [
        "58acdaff9de9ae2d2d11f67b273989e1c4f581fb",
        []
@@ -264473,6 +264636,10 @@
        "fba91bd52570405160a63d82633763bf70381bf9",
        []
       ],
+      "position-relative-035.xht.ini": [
+       "1d21cdcd18e179c4fbab4efcec46222c90ee98bb",
+       []
+      ],
       "position-relative-037-ref.xht": [
        "daae9c9d2799a8063b20b2a72a49a3b639e1c322",
        []
@@ -265227,6 +265394,10 @@
        "9b706a27fa4cae785ec97ee47d87a5ba16255d7e",
        []
       ],
+      "column-visibility-004.xht.ini": [
+       "a8f26b3611b646d14969e7f73b1b840239fdd947",
+       []
+      ],
       "fixed-table-layout-002a-ref.xht": [
        "c4b2fcd3008cebaba2b59f2696272bf1f57bfc7c",
        []
@@ -265599,10 +265770,198 @@
         []
        ]
       },
+      "table-anonymous-objects-079.xht.ini": [
+       "be6297505877de8c5f6553ff5f2ba7119a705e4a",
+       []
+      ],
+      "table-anonymous-objects-080.xht.ini": [
+       "85071f93fc2adfdf24933a32dc4bd8d09859d7d3",
+       []
+      ],
+      "table-anonymous-objects-081.xht.ini": [
+       "f23dd59d866760eb6132c3b32c0a921eb2d132fd",
+       []
+      ],
+      "table-anonymous-objects-082.xht.ini": [
+       "67e1503813c80e0c28e2720d6244904f51e32838",
+       []
+      ],
+      "table-anonymous-objects-083.xht.ini": [
+       "b255b53c8403b523d7f2a3987adfef5d4955d889",
+       []
+      ],
+      "table-anonymous-objects-084.xht.ini": [
+       "fe4e59909d90c6cc10d0f4021beaa7dd000419e7",
+       []
+      ],
+      "table-anonymous-objects-085.xht.ini": [
+       "ed053430a60eaee7aff94bba50d3a32c83d2139c",
+       []
+      ],
+      "table-anonymous-objects-086.xht.ini": [
+       "46c00c68ebb93114b2c582671a2bb00986500679",
+       []
+      ],
+      "table-anonymous-objects-093.xht.ini": [
+       "59ca4a7282476c7215c6bf6684365db2af7b88d4",
+       []
+      ],
+      "table-anonymous-objects-094.xht.ini": [
+       "6838b84e1a7e89f616fc9247331bb11e6898df27",
+       []
+      ],
+      "table-anonymous-objects-095.xht.ini": [
+       "1a1dbded814803dc446f4e9c476147ec408a7d43",
+       []
+      ],
+      "table-anonymous-objects-096.xht.ini": [
+       "f3e247c64cb31c1228294c8cab17416e7d2b9a0f",
+       []
+      ],
+      "table-anonymous-objects-097.xht.ini": [
+       "c4f894e1f02f98477d6a21aa3b242624850c9dc7",
+       []
+      ],
+      "table-anonymous-objects-098.xht.ini": [
+       "f09a4407f17fd92f191827ead0c61a9e503e7200",
+       []
+      ],
+      "table-anonymous-objects-103.xht.ini": [
+       "8e24928f52e28d9a68bf150690b791c0830e1416",
+       []
+      ],
+      "table-anonymous-objects-104.xht.ini": [
+       "a53d0914fd3aecdf1ea4e7a0d36814b58a154caf",
+       []
+      ],
+      "table-anonymous-objects-125.xht.ini": [
+       "96f6e4976d55b9c79eb23099dd8ece54f77e2897",
+       []
+      ],
+      "table-anonymous-objects-126.xht.ini": [
+       "c9a5ac196fbb9c910987206b9c6d2784bcc61b62",
+       []
+      ],
+      "table-anonymous-objects-127.xht.ini": [
+       "976c52bf99c1ae4f1f6ac9220c72df946c838b13",
+       []
+      ],
+      "table-anonymous-objects-128.xht.ini": [
+       "3c189d614e5eea8278271bcbd896db9cbc624ab4",
+       []
+      ],
+      "table-anonymous-objects-129.xht.ini": [
+       "663d86f499cd43007a36a97ca3e68637334f32fb",
+       []
+      ],
+      "table-anonymous-objects-130.xht.ini": [
+       "6d0b0102b5abd29a61c51b3194bdfee1da92a2e3",
+       []
+      ],
+      "table-anonymous-objects-131.xht.ini": [
+       "dce0b114d5178f575742e95c0db65f471d180924",
+       []
+      ],
+      "table-anonymous-objects-132.xht.ini": [
+       "692aca74ad5de613260fe7f8fae2f85dcf28f342",
+       []
+      ],
+      "table-anonymous-objects-155.xht.ini": [
+       "4447e3be2ae4437cbac45b0c9d2296e717dd3ed1",
+       []
+      ],
+      "table-anonymous-objects-156.xht.ini": [
+       "b78c37511866a58c3bdc04cabe5687f5760ff968",
+       []
+      ],
+      "table-anonymous-objects-157.xht.ini": [
+       "cc84e04a7d0c60f9c6e588daedc1017494a19230",
+       []
+      ],
+      "table-anonymous-objects-158.xht.ini": [
+       "e36e94f46c17aeb2e2d080253a3554f5be3abb1e",
+       []
+      ],
+      "table-anonymous-objects-167.xht.ini": [
+       "a3a684ba80c2f8bbd5d75099180fe786914d681e",
+       []
+      ],
+      "table-anonymous-objects-168.xht.ini": [
+       "57cab473248e0d89128600d1900e217f238c05a9",
+       []
+      ],
+      "table-anonymous-objects-171.xht.ini": [
+       "f1975bca721874ad7f03f213e7aa6e730b9405cb",
+       []
+      ],
+      "table-anonymous-objects-172.xht.ini": [
+       "29da376c9a056e1e7b98caab983759b4ccf3c4dd",
+       []
+      ],
+      "table-anonymous-objects-181.xht.ini": [
+       "a48bdf7a01da83defc46b1ef1b7f67658690672b",
+       []
+      ],
+      "table-anonymous-objects-182.xht.ini": [
+       "5df7c5d1e880af33f0435aa4e7361bdfb6f63daf",
+       []
+      ],
+      "table-anonymous-objects-183.xht.ini": [
+       "5b8b29c78190090d281faa5f22f752e23898aa72",
+       []
+      ],
+      "table-anonymous-objects-184.xht.ini": [
+       "a1198c6605923c2b22f3569c1b558be477833c8d",
+       []
+      ],
+      "table-anonymous-objects-185.xht.ini": [
+       "f77f68b124d05b765633971a3cbd8a08496aa6b2",
+       []
+      ],
+      "table-anonymous-objects-186.xht.ini": [
+       "62dde9493eefa797cef1702ecb26933532f6a892",
+       []
+      ],
+      "table-anonymous-objects-187.xht.ini": [
+       "b1ea0e06232cb8807b76a04f7d78f2af721fc98e",
+       []
+      ],
+      "table-anonymous-objects-188.xht.ini": [
+       "48ab69946768dd3db25dc4201e27f0c3d21eed38",
+       []
+      ],
+      "table-anonymous-objects-199.xht.ini": [
+       "e67617bcc90f02576457bde8f5c1d0d260e889d2",
+       []
+      ],
+      "table-anonymous-objects-200.xht.ini": [
+       "df790626e1a177874adf9febc6740de1a6f566f0",
+       []
+      ],
+      "table-anonymous-objects-201.xht.ini": [
+       "7df8c8b688818fa2d3376384420039e20fa30398",
+       []
+      ],
+      "table-anonymous-objects-202.xht.ini": [
+       "3445d39db4028ef7fcc2580f5865b2d03918266c",
+       []
+      ],
+      "table-anonymous-objects-203.xht.ini": [
+       "b21a61a16ad4651d420dc187f05282a06621c7c4",
+       []
+      ],
+      "table-anonymous-objects-204.xht.ini": [
+       "e8115dc0cebc366c17388af17bdfe5321cb68b5b",
+       []
+      ],
       "table-anonymous-objects-211-ref.xht": [
        "5133164219b73747fb0f40fc98cb4a7bfca8b56a",
        []
       ],
+      "table-anonymous-objects-211.xht.ini": [
+       "b970506794687edf7baf05d9fe5aa5736abecab4",
+       []
+      ],
       "table-backgrounds-bc-cell-001-ref.xht": [
        "4ee2659b4458c95b53dfbd16071d4aed7b11a3b7",
        []
@@ -265693,6 +266052,10 @@
        "ec24b9871d7e43542f65ff037cce55fda4bd8148",
        []
       ],
+      "letter-spacing-080.xht.ini": [
+       "36e78cb5cc7a0f8c5f0583ddf08416b42859463d",
+       []
+      ],
       "letter-spacing-091-ref.xht": [
        "7d485ac65c1fa11e56c9c53967a18cdf64b53f60",
        []
@@ -265891,6 +266254,10 @@
        "7ff7515baabad81366d3573482094fe0cfd5634e",
        []
       ],
+      "text-align-white-space-003.xht.ini": [
+       "629be9fcc3a4951b5081526f91b2397dd881809a",
+       []
+      ],
       "text-align-white-space-004-ref.xht": [
        "0a8fea56cc682e4bd064a89b5eb1fc4a2bd5dc91",
        []
@@ -265907,6 +266274,10 @@
        "b1743f1a4e0a9b2d123dbf0e47d7fbef16ec9c61",
        []
       ],
+      "text-decoration-va-length-001.xht.ini": [
+       "04285060eb51ef687cf05dc137555a842da5daa2",
+       []
+      ],
       "text-decoration-va-length-002-ref.xht": [
        "6b44915705366ccf698fb854a4c700a3e732ddac",
        []
@@ -266055,6 +266426,10 @@
        "56e640913d0537b5045e0474389af17e254a8f7b",
        []
       ],
+      "text-transform-bicameral-007.xht.ini": [
+       "5610ec93ff426a948d9e9ebdbd5cb63cc30d163d",
+       []
+      ],
       "text-transform-bicameral-008-ref.xht": [
        "7fdd0d0140fd94dc7e6e353e5c1d190634c67f75",
        []
@@ -266183,6 +266558,10 @@
        "df6da32f52e00fd5c213b0dbe85e14a4c4bca91e",
        []
       ],
+      "white-space-collapsing-bidi-001.xht.ini": [
+       "83500dd16e9cdc7688ed7932132eaab8d08a844d",
+       []
+      ],
       "white-space-collapsing-bidi-003-ref.xht": [
        "b02276c9ec7af6c6f78bbe344423656d7424a45d",
        []
@@ -266199,6 +266578,10 @@
        "7e17ec3d266fd3637afc96ec940c8b142c4dae36",
        []
       ],
+      "white-space-mixed-001.xht.ini": [
+       "b1cf457e7d158951322ec2f8eca74e26b58e57f5",
+       []
+      ],
       "white-space-mixed-002-ref.xht": [
        "85fa1788833d68b7955d3f74f2b7bf4c40e63584",
        []
@@ -266299,10 +266682,18 @@
        "ab837b027688853645e16a8a9e97fa98293e0550",
        []
       ],
+      "white-space-processing-048.xht.ini": [
+       "d6fae45ecb00f21e27d991d7b20db9d67a236359",
+       []
+      ],
       "white-space-processing-049-ref.xht": [
        "0903a615cf65d60fa5f4b90706779f038ca76a2c",
        []
       ],
+      "white-space-processing-049.xht.ini": [
+       "8f4f9404c0ac156388062b974b96b96aa1916736",
+       []
+      ],
       "white-space-processing-052-ref.xht": [
        "318b6321a071f0f84c22145879a3c2c5c044346a",
        []
@@ -268980,6 +269371,18 @@
       "3b9e23678d4eb08387423de7a0a0dfb5675445ef",
       []
      ],
+     "box-decoration-break-clone-001.html.ini": [
+      "559906ee160fcfdfd7d7a750e373597bb6e02f6b",
+      []
+     ],
+     "box-decoration-break-clone-002.html.ini": [
+      "bba7ca6c1ff8261d102f2183c8c6181e6398b568",
+      []
+     ],
+     "box-decoration-break-clone-004.html.ini": [
+      "fdaa2c733969b195dc983d58c411bdc0f83f5db0",
+      []
+     ],
      "box-shadow-ref.html": [
       "f87e16adedc779911ec081990acd76dd5f6ed5ad",
       []
@@ -269057,10 +269460,18 @@
        "d0e574022b50c800263bb5a9cb16ddaad13dbfc5",
        []
       ],
+      "multi-line-row-flex-fragmentation-058.html.ini": [
+       "7f0ce760a2a8ac4750ad6d286446316e41e83c90",
+       []
+      ],
       "single-line-column-flex-fragmentation-040-ref.html": [
        "3d20cb44e49b065fdb90d400fba69aca442f0fc2",
        []
       ],
+      "single-line-column-flex-fragmentation-043.html.ini": [
+       "3b1824f28eb011032a1fff0835c0386ad42db506",
+       []
+      ],
       "single-line-row-flex-fragmentation-027-ref.html": [
        "e1079de13fb771854107b4022054945a0b460e18",
        []
@@ -269086,10 +269497,20 @@
       "5effc82452da07054ca2c3e2d74e3a9b0f84d9ea",
       []
      ],
+     "grid": {
+      "grid-item-fragmentation-039.html.ini": [
+       "5f8c1d324e8cb3f3eb9f29f86659a3664f11304b",
+       []
+      ]
+     },
      "inheritance-expected.txt": [
       "738ea649f554f91280becd58a760fdd07827a9b1",
       []
      ],
+     "inheritance.html.ini": [
+      "292380389b02c7ea1b53608d2d4a249ae04f4bb5",
+      []
+     ],
      "line-after-unbreakable-float-after-padding-ref.html": [
       "9a329b2446849d8f13b9d88cb5f73934536c3767",
       []
@@ -269127,33 +269548,65 @@
        "2bf7d5cfd390f7f989cffa3197643b87699fdefe",
        []
       ],
+      "box-decoration-break-computed.html.ini": [
+       "dac38329d0094c96cbefc3c2a1c730a0189a0e80",
+       []
+      ],
       "box-decoration-break-valid-expected.txt": [
        "172bdaec9a7301e657cc3e539dfaf2a0864923a8",
        []
       ],
+      "box-decoration-break-valid.html.ini": [
+       "957a8bd5d612bf16a1efc38bc5db981311b9d566",
+       []
+      ],
       "break-after-computed-expected.txt": [
        "658ff18a5387c9e39de50d20f0e361c0756b896c",
        []
       ],
+      "break-after-computed.html.ini": [
+       "f2b3f9a29e9034b1ebfba618f529e34abf5a3dbf",
+       []
+      ],
       "break-after-valid-expected.txt": [
        "38682b8b82e6fc2386c353a329dac6e25da867ce",
        []
       ],
+      "break-after-valid.html.ini": [
+       "ff0d464b8e7cf0a77712a04afaecb157b0ded5a9",
+       []
+      ],
       "break-before-computed-expected.txt": [
        "7255a534b89ddbe075715ec55853970e66316a21",
        []
       ],
+      "break-before-computed.html.ini": [
+       "a5cb8e05305c39076b2161a6354dab2b2b169803",
+       []
+      ],
       "break-before-valid-expected.txt": [
        "61b33a7deca2dcf111a69afe551d0a15fb2af6df",
        []
       ],
+      "break-before-valid.html.ini": [
+       "c8f229e8bd0f269633ef6869f7b3dab28629826b",
+       []
+      ],
       "break-inside-computed-expected.txt": [
        "5787cc6a1f688528da28571ca0b57c31f900918e",
        []
       ],
+      "break-inside-computed.html.ini": [
+       "c5e6858ee430895876de82b2e49d120e98e61e22",
+       []
+      ],
       "break-inside-valid-expected.txt": [
        "2818d4d7b0ce38430c434f1bd7476c5c82346ed2",
        []
+      ],
+      "break-inside-valid.html.ini": [
+       "bc94263f0ecbdd55e9ea125de951119ab5f3bb17",
+       []
       ]
      },
      "reference": {
@@ -269318,6 +269771,10 @@
       "50599b119a7f0ab5246389de57c439e086b8797d",
       []
      ],
+     "transform-007.html.ini": [
+      "cf25f3d55cbca7eef9f4d1ec9ae5a9cc642cfd56",
+      []
+     ],
      "transform-008-ref.html": [
       "2a16079545c82dd417f8fde6efa66d5a31c90111",
       []
@@ -269325,6 +269782,14 @@
      "transform-009-ref.html": [
       "d7d3ebf604c62d80874d4f42a2dc71744c776b75",
       []
+     ],
+     "transform-009.html.ini": [
+      "cad216fbc3e6385b2b89bc03358c15d5073913a5",
+      []
+     ],
+     "widows-orphans-017.html.ini": [
+      "a2b8899cdfdf438127da9ed58d404f0d3e4e8a2a",
+      []
      ]
     },
     "css-cascade": {
@@ -269333,7 +269798,7 @@
       []
      ],
      "OWNERS": [
-      "54387d37c800d276f31f3575f6d7b787f18a0166",
+      "77c044dc6bc51f638d16d8e285d7652c35eec0b2",
       []
      ],
      "all-prop-001-ref.html": [
@@ -270093,7 +270558,7 @@
       []
      ],
      "OWNERS": [
-      "54387d37c800d276f31f3575f6d7b787f18a0166",
+      "1d83d3d366d28815eb47da2822550e2185d9cca8",
       []
      ],
      "at-supports-001-ref.html": [
@@ -270104,18 +270569,50 @@
       "9d1fbaaf47b97cb82dc3003ffd2d46268100774e",
       []
      ],
+     "at-supports-046.html.ini": [
+      "4f07d8fc19e6fcae2a16c6adcfa04ffbd8381c78",
+      []
+     ],
+     "at-supports-namespace-001.html.ini": [
+      "72d1a736a6b395a0278212649feba66a61afe2c4",
+      []
+     ],
+     "at-supports-namespace-002.html.ini": [
+      "dd9aed65ab827c1703dd56b2457f0204e954e009",
+      []
+     ],
      "at-supports-selector-detecting-invalid-in-forgiving-argument-ref.html": [
       "681ef4bcefe672c22a0828f09cfb8038404f00fb",
       []
      ],
+     "css-supports-040.xht.ini": [
+      "0d8be8dcd4694997dfc255c0deefb27f7d6c489d",
+      []
+     ],
+     "css-supports-041.xht.ini": [
+      "0abe17cb744659f7ac3a7a3a97ef5fa1553bbffe",
+      []
+     ],
+     "css-supports-042.xht.ini": [
+      "eb12d74568e421ff5f2d6203cb5204de61c8036e",
+      []
+     ],
      "js": {
       "CSS-supports-CSSStyleDeclaration-expected.txt": [
        "1ab42afe9ea4ae7fd528bdaff30199d6236c2340",
        []
       ],
+      "CSS-supports-CSSStyleDeclaration.html.ini": [
+       "c90e8e280b10d3a3a8c95bf16b386310df08ccb1",
+       []
+      ],
       "supports-conditionText-expected.txt": [
        "8c41303fcd5b39af695b6b934cf90dee6bf792aa",
        []
+      ],
+      "supports-conditionText.html.ini": [
+       "f7cf2cf879ff836cf5267b725532e4bd825bddab",
+       []
       ]
      },
      "reference": {
@@ -287281,7 +287778,7 @@
       []
      ],
      "OWNERS": [
-      "54387d37c800d276f31f3575f6d7b787f18a0166",
+      "1d83d3d366d28815eb47da2822550e2185d9cca8",
       []
      ],
      "README": [
@@ -294043,27 +294540,27 @@
         []
        ],
        "text-align-justify-ref-001.html": [
-        "0218b47f26c80b9f9eb137fba322234cd75e5f1e",
+        "f13a49481906f992f9ab36c8bdcf93c5ed0f6aa8",
         []
        ],
        "text-align-justify-ref-002.html": [
-        "02e1f234cb5415add7226fa9d86b6fc15a78d5e7",
+        "63206ff29ea942cab364306ad81ffaab728697af",
         []
        ],
        "text-align-justify-ref-003.html": [
-        "b869ef98103a4c9e7f389051274a67fca5e90c56",
+        "9437b4fa2b040f0f2bd11f913b70d7080bcf8bfd",
         []
        ],
        "text-align-justify-ref-004.html": [
-        "006bea1ce5a90f07564b2105b53093d0b03565c7",
+        "fe2bbe8d46594ac70b8f9428117839d3f60477e1",
         []
        ],
        "text-align-justify-ref-005.html": [
-        "3de1f09d066ecdc2aa3435ec798654153fc29b71",
+        "bb383de0d03375025ea0b19bd0c8ff150311e821",
         []
        ],
        "text-align-justify-ref-006.html": [
-        "05531186ba8a5e78dda0218f835eedd86c092f18",
+        "cead2a25516ed50a0e038b5a9ad11ff1321e7f9d",
         []
        ],
        "text-align-justify-shy-ref-001.html": [
@@ -294083,59 +294580,59 @@
         []
        ],
        "text-align-start-ref-001.html": [
-        "72e11fae2dd1eccb5d9742970a401db54b72dfc0",
+        "5d14b17626e26304fcf7d064474d9cb1429f8270",
         []
        ],
        "text-align-start-ref-002.html": [
-        "a30dc620be14bef08d0d348bbc2e5bd9277a36e9",
+        "fc54ede6cc3a3737f0b1ac174587e45e392700b6",
         []
        ],
        "text-align-start-ref-003.html": [
-        "8393996ff9c85d4759e433bb89fff998218549c9",
+        "fa5e76a2756721792df51f9540fc873bb1eb70bc",
         []
        ],
        "text-align-start-ref-004.html": [
-        "4ec0fdeebef0da9232f81d02097532b1c4b444f8",
+        "1deee0c701f392c3999fa392f0de791e9c174163",
         []
        ],
        "text-align-start-ref-005.html": [
-        "70a8d53da9a69e5c0635d310949824ac3533d672",
+        "701845e99334b46c9920c802b3ca5026ec91a831",
         []
        ],
        "text-align-start-ref-006.html": [
-        "affc904e21277a18d3b1ad42744929f8930f3743",
+        "914df4654bf2c90e8ef3dfd10e0f48acd211babc",
         []
        ],
        "text-align-start-ref-007.html": [
-        "de8d8790f43838ca5a0e6bb6d771c483eed18776",
+        "62cca9b99ce0152908db65d61a55d17129e87d06",
         []
        ],
        "text-align-start-ref-008.html": [
-        "8c8160345e8f882894bda748a295b0e49377a694",
+        "1b09404b2fe2aeef4bc6a9fe8cba29b6af18c4cc",
         []
        ],
        "text-align-start-ref-009.html": [
-        "f3c0cc74150d1c5e7b9031238dbcfcd3392e6c86",
+        "0cfe79e6c1642109f46c23808fc91fd439e8bd55",
         []
        ],
        "text-align-start-ref-010.html": [
-        "3014c053d515cdd626d55b3f1be505d63d3249c0",
+        "727fb656e41ba3b340ecbeaa77930d665ea04194",
         []
        ],
        "text-align-start-ref-014.html": [
-        "703ffe38b1da5f4272cb39985d2538c915e404b9",
+        "8113fe23f182555a8fb10cb30d0850f4cb5954a1",
         []
        ],
        "text-align-start-ref-015.html": [
-        "814c76f0482fad9cc9d372ad0cd0259c0694629a",
+        "d61b2585e66a8efbff493f63c080003571264cc3",
         []
        ],
        "text-align-start-ref-016.html": [
-        "8253f594305de3ad7468eb938c8f6ea5963b9a0d",
+        "3df6be4048a25f5cdbcc71eb4e7883723420b562",
         []
        ],
        "text-align-start-ref-017.html": [
-        "e8ad0119bbacbcaaaf21a072c595f20095956bd7",
+        "89b5c4028d3c8c2cd87cda909130b1e1735ad9f4",
         []
        ]
       },
@@ -302921,7 +303418,7 @@
       []
      ],
      "getComputedStyle-detached-subtree-expected.txt": [
-      "49adafd97aa9214e12f4a4e1ac1e530706563b23",
+      "ed6c7d939646d3a05c5bc0ef6709db1ac9bfe163",
       []
      ],
      "getComputedStyle-insets-absolute-expected.txt": [
@@ -302933,7 +303430,7 @@
       []
      ],
      "getComputedStyle-pseudo-expected.txt": [
-      "5ab221bc88209056bce2e7b249b03bc3ab22a4f9",
+      "0fe62f5a2609fbf74cc72e3161e61810d20341af",
       []
      ],
      "getComputedStyle-width-scroll.tentative-expected.txt": [
@@ -305205,7 +305702,7 @@
     ],
     "custom-element-registry": {
      "per-global-expected.txt": [
-      "b6ce8a322bfc8f0a53c3bffa96fd6d3753f259ef",
+      "99e8fe948642112db663295770cf266fb82058ef",
       []
      ]
     },
@@ -306111,7 +306608,7 @@
      "non-cancelable-when-passive": {
       "resources": {
        "scrolling.js": [
-        "1d898d8c7959c26e7e9932b67b3757d0be9fe3dc",
+        "88e10f5efdceab71dac9cecabdc12bc82ad8a7fa",
         []
        ],
        "touching.js": [
@@ -310260,6 +310757,14 @@
       "response-null-body.any.worker-expected.txt": [
        "fa818f443d303b3903069f46bc8824dd2bf8bb27",
        []
+      ],
+      "scheme-blob.sub.any-expected.txt": [
+       "508142e888987fc903bd74fbadcbcbbdbec10875",
+       []
+      ],
+      "scheme-blob.sub.any.worker-expected.txt": [
+       "508142e888987fc903bd74fbadcbcbbdbec10875",
+       []
       ]
      },
      "body": {
@@ -313602,7 +314107,7 @@
      ]
     },
     "trusted-click.js": [
-     "7ee0669eece3e341ef76da4dd153e5ec05ccb288",
+     "240ee01c23472cafb11243974e41434fb8b99faa",
      []
     ]
    },
@@ -314522,11 +315027,41 @@
        ]
       },
       "overlapping-navigations-and-traversals": {
-       "tentative": {
-        "README.md": [
-         "cdd7975c81ad0ee468b46970aaac2a57dc683337",
+       "README.md": [
+        "cc313a155a167fa9f8182346c96764fe949da455",
+        []
+       ],
+       "cross-document-traversal-cross-document-traversal-expected.txt": [
+        "bc974a74ff1fc48aa94303d9a8d43bfe48f233a5",
+        []
+       ],
+       "nav-cancelation-1-expected.txt": [
+        "16fb35024af873f1a1e1e6548374a4cd9b21a83a",
+        []
+       ],
+       "nav-cancelation-2.sub-expected.txt": [
+        "d02213bc0797ff078c349be679d0bff4dc331039",
+        []
+       ],
+       "resources": {
+        "helpers.mjs": [
+         "79384979209dd6d56fbaa1059288a798a7c61161",
          []
         ],
+        "nav-cancelation-2-helper.html": [
+         "a0b4acda2ea17322b85d1e46c2675de374be8889",
+         []
+        ],
+        "slow.py": [
+         "5ee32a60baea5edb5d1560ef282789e5d22555c8",
+         []
+        ]
+       },
+       "same-document-traversal-cross-document-nav-expected.txt": [
+        "a2cebc4ccd1f7dfaa2156351e6af89c0444cd969",
+        []
+       ],
+       "tentative": {
         "cross-document-traversal-same-document-nav-expected.txt": [
          "4ceed7722c4ea66b83050c23c8bca51e0fc7854b",
          []
@@ -314543,20 +315078,6 @@
          "d02213bc0797ff078c349be679d0bff4dc331039",
          []
         ],
-        "resources": {
-         "helpers.mjs": [
-          "d2ecb9d9bc21ad85f62c8341d084c6485a5d43cf",
-          []
-         ],
-         "nav-cancelation-2-helper.html": [
-          "a0b4acda2ea17322b85d1e46c2675de374be8889",
-          []
-         ],
-         "slow.py": [
-          "5ee32a60baea5edb5d1560ef282789e5d22555c8",
-          []
-         ]
-        },
         "same-document-traversal-same-document-nav-expected.txt": [
          "4ceed7722c4ea66b83050c23c8bca51e0fc7854b",
          []
@@ -316523,7 +317044,7 @@
       },
       "drawing-text-to-the-canvas": {
        "2d.text.draw.fill.basic.png": [
-        "1e313371d828e9f5edf61480e64ea5c689653fca",
+        "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
         []
        ],
        "2d.text.draw.fill.maxWidth.large.png": [
@@ -316531,7 +317052,7 @@
         []
        ],
        "2d.text.draw.fill.rtl.png": [
-        "1e313371d828e9f5edf61480e64ea5c689653fca",
+        "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
         []
        ],
        "2d.text.draw.fontface.notinpage-expected.txt": [
@@ -316539,7 +317060,7 @@
         []
        ],
        "2d.text.draw.stroke.basic.png": [
-        "b04566f5c66e5816afdf094c1441d8a483297420",
+        "fb3b5b830d345d2aa858e41673e08f99977baf08",
         []
        ],
        "reference": {
@@ -317815,15 +318336,15 @@
         []
        ],
        "2d.text.draw.fill.basic.png": [
-        "1e313371d828e9f5edf61480e64ea5c689653fca",
+        "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
         []
        ],
        "2d.text.draw.fill.maxWidth.large.png": [
-        "1e313371d828e9f5edf61480e64ea5c689653fca",
+        "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
         []
        ],
        "2d.text.draw.fill.rtl.png": [
-        "1e313371d828e9f5edf61480e64ea5c689653fca",
+        "70d7b046cb226cfcb2bfeebe3477d3b580d8270a",
         []
        ],
        "2d.text.draw.space.collapse.end-expected.txt": [
@@ -317859,7 +318380,7 @@
         []
        ],
        "2d.text.draw.stroke.basic.png": [
-        "b04566f5c66e5816afdf094c1441d8a483297420",
+        "fb3b5b830d345d2aa858e41673e08f99977baf08",
         []
        ],
        "2d.text.measure.width.space-expected.txt": [
@@ -317910,7 +318431,7 @@
        []
       ],
       "canvas-tests.js": [
-       "25e2351c7c146a4db76b85c1e7d23e84d50564cd",
+       "c6e28732838119e71f920dc2eacf43af41dafb4a",
        []
       ],
       "canvas-tests.js.headers": [
@@ -317928,11 +318449,11 @@
        []
       ],
       "gentestutils.py": [
-       "732f32f337e36f01cb61fdc8082aebb189ca3863",
+       "5a16cfc835bf0db0f190d42baa5192d213f73e7e",
        []
       ],
       "gentestutilsunion.py": [
-       "b188ed7bc08e83aca33c825cbb6288a2083e3918",
+       "f2abec53c72d0e5aefa4bda758aa707aa5a11c1b",
        []
       ],
       "name2dir-canvas.yaml": [
@@ -318071,7 +318592,7 @@
         []
        ],
        "filters.yaml": [
-        "6bc759bf8d3cebde610424bbb7d6cd9cef1dda4f",
+        "cc5dfe7fefbcd9a5cbf487e46cdab3afdd84c3d1",
         []
        ],
        "reset.yaml": [
@@ -324427,10 +324948,6 @@
          "eeda1b6a09c2fdb270388f07902d9bcde8e40f72",
          []
         ],
-        "resource-selection-invoke-insert-into-iframe-expected.txt": [
-         "5bd63aa8db07e60083a498e3f1be696ccc32ce36",
-         []
-        ],
         "resource-selection-invoke-insert-source-networkState-expected.txt": [
          "749d55c61831a927f68c07e288647196b8637cf0",
          []
@@ -324499,10 +325016,6 @@
         []
        ],
        "playing-the-media-resource": {
-        "pause-move-to-other-document-expected.txt": [
-         "aa9a81c300cf2ca6de1c1b7a5c613b6e578770de",
-         []
-        ],
         "play-in-detached-document-expected.txt": [
          "08960a395b06e03eed895f39cb8d3158f095b724",
          []
@@ -325211,6 +325724,10 @@
          "bb625942f88c51d4eb6058586c96d574ec354e1d",
          []
         ],
+        "sandbox-top-navigation-helper.js": [
+         "7792c261309587a6434138dea98b80c74f411017",
+         []
+        ],
         "subframe.html": [
          "07cb999afaefe344a0f8d5ac2b792b60abcd22b4",
          []
@@ -330107,7 +330624,7 @@
      "system-state-and-capabilities": {
       "the-navigator-object": {
        "per-global.window-expected.txt": [
-        "9b493c49922c1c58917ae0fff20d4bf2e56cea9c",
+        "d4cf47ba11e3f618dd17572d513c4deef0a28e2f",
         []
        ],
        "resources": {
@@ -332703,7 +333220,7 @@
       []
      ],
      "largest-contentful-paint-helpers.js": [
-      "5012faf3b1be3388b9e342af5ee25265e4c3de22",
+      "de359ebb8ad303a4084de4dd63467c4dacd302ea",
       []
      ],
      "lcp-sw-from-cache.js": [
@@ -332785,7 +333302,7 @@
     ]
    },
    "lint.ignore": [
-    "95288fc538e546447560755aa57a6de6f683e521",
+    "dd3f7b61a9ff2653577da9fc55a64495310c33f4",
     []
    ],
    "loading": {
@@ -335029,6 +335546,10 @@
      "488432d41ea61c18264c37310369dbd59ccb78ea",
      []
     ],
+    "csp.https.window.js.headers": [
+     "6b6605899c2b12b9fa9b279da2451c49696d8b76",
+     []
+    ],
     "gen": {
      "sharedworker-classic-data.http-rp": {
       "opt-in": {
@@ -335632,6 +336153,14 @@
       "4e5e1a000c9a67b7dbc591dd7d0abc5f279f363c",
       []
      ],
+     "navigation-type-post-back.html": [
+      "8c19a2f5a5ffe4215184b22ded42c4741e9fa2a4",
+      []
+     ],
+     "navigation_type_post_back.py": [
+      "9da06f4f035925f023b0a31f9bc17ad94ed51c70",
+      []
+     ],
      "performance-attribute-sender.html": [
       "99f544690d331f8c172a3f54bd589a89eaa35716",
       []
@@ -335888,26 +336417,6 @@
      []
     ]
    },
-   "page-unload-beacon": {
-    "META.yml": [
-     "18b08c1ed5117b028bf1571e7110546cca89f4f8",
-     []
-    ],
-    "resources": {
-     "get_beacon.py": [
-      "32cb9a9ba30638bf0e5c7e54655ae87e7085978d",
-      []
-     ],
-     "pending_beacon-helper.js": [
-      "636e8d8023c40f8e918d04e85b6e685f54c21641",
-      []
-     ],
-     "set_beacon.py": [
-      "1c71f23e57849481b7deb204cb859ef25f6e4356",
-      []
-     ]
-    }
-   },
    "page-visibility": {
     "DIR_METADATA": [
      "ad88c7283bfa1315fe5d8d47084a600d4fa4c588",
@@ -339223,6 +339732,10 @@
      "2852fc5895a9b4e8fccf5c53619cdb79fb399587",
      []
     ],
+    "reporting-api-honors-limits.https.sub.html.sub.headers": [
+     "376788443e0bcb7e716de7d0571a22f560e46fa4",
+     []
+    ],
     "resources": {
      "README.md": [
       "b77d1f96b7d6b5886f1d43b2b44aea76afd56df6",
@@ -339921,7 +340434,7 @@
       []
      ],
      "mock-pressure-service.js": [
-      "27a684e1de9b777b9f4c5902a5992696682e210f",
+      "15bd65789300b04a2c66a5d2088e841cddde2063",
       []
      ],
      "mock-pressure-service.js.headers": [
@@ -339986,7 +340499,7 @@
      ]
     },
     "idlharness-shadowrealm.js": [
-     "05c4a1affc8699b6cd2a1fe02aa0ac2085b04a8a",
+     "9484ca6f512ad0414d0969b3ec265114c95fd306",
      []
     ],
     "idlharness.js": [
@@ -340034,7 +340547,7 @@
      []
     ],
     "testdriver.js": [
-     "5a59c724a7a1330f0b8686315ef836ae8975e5fb",
+     "3474a3361043fda1301f0e242d74bee675d33f41",
      []
     ],
     "testdriver.js.headers": [
@@ -340042,7 +340555,7 @@
      []
     ],
     "testharness.js": [
-     "9ec328222097e070ab46490b28aeed3016026008",
+     "423108e736aeca752f3b3999d4d5e27b5d0a1ad1",
      []
     ],
     "testharness.js.headers": [
@@ -340151,25 +340664,13 @@
      "54ed00de803e12c4bb9429803e7b62daf5fc4a2b",
      []
     ],
-    "getdisplaymedia-after-discard.https-expected.txt": [
-     "fd71c3c63b587fb17f8b5582fd7631df01e96754",
-     []
-    ],
     "getdisplaymedia.https-expected.txt": [
-     "baa9eb85b191ff7a5e4d747e2935ad1ef5408cb6",
+     "c0c57062afbad884872a96a160d68bcc533a04e6",
      []
     ],
     "idlharness.https.window-expected.txt": [
      "4605eb29fe6fe1f326bec5abf4c5f14e22a31bb6",
      []
-    ],
-    "permissions-policy-audio.https.sub-expected.txt": [
-     "0e8322924f443bffcae91b32da1742d34be3582c",
-     []
-    ],
-    "permissions-policy-video.https.sub-expected.txt": [
-     "669a952761a4c756f65f80be8f9dd8ef3b4caaff",
-     []
     ]
    },
    "screen-details": {
@@ -340184,7 +340685,7 @@
      []
     ],
     "META.yml": [
-     "8f5bd75ca7b32face08d400d641513297638ec59",
+     "b8c0b9741d4a22ac42a995ca04b3df2c96cfc16f",
      []
     ],
     "event-before-promise-expected.txt": [
@@ -340200,7 +340701,7 @@
      []
     ],
     "onchange-event-expected.txt": [
-     "76af39c5c08a2a59d1699fe78e04253db0db86a3",
+     "eb540f79482eac6a678a28bbaf1232002629ee3d",
      []
     ],
     "onchange-event-subframe-expected.txt": [
@@ -340212,16 +340713,20 @@
      []
     ],
     "resources": {
+     "empty.html": [
+      "0e76edd65b7baf5316fc9d0c4da59a3502e4c27a",
+      []
+     ],
      "iframe-listen-orientation-change.html": [
-      "4cfd37d02bc58f2bed39075357b393fea769a155",
+      "68a67f8818a3e88db5c56da67187464bb6b0257c",
       []
      ],
      "orientation-utils.js": [
-      "85be16c3691dcd5498e117c165f8f4b17c53064b",
+      "f2fb045fa9509287b1bd3c3c351a26d23fe37091",
       []
      ],
      "sandboxed-iframe-locking.html": [
-      "9e305a08c125e38cdcd8317d2857ee08b40f5fa7",
+      "7f5496b3f3fb1c3c6da600559634de5b87a2438e",
       []
      ]
     }
@@ -340325,7 +340830,7 @@
     },
     "view-timelines": {
      "testcommon.js": [
-      "faddf121c52e03bc77dc9308dcc29a160c0bd51d",
+      "fe4f92d81acbbfff75688d54d2f2bbec66e60b9f",
       []
      ]
     }
@@ -344065,7 +344570,7 @@
       []
      ],
      "soft-navigation-helper.js": [
-      "5d95ea9e2de4359c42a2557c9b922dec929fe80e",
+      "c0c6cbd1e5187bda807200d7d02ab2497b72823a",
       []
      ]
     }
@@ -344109,6 +344614,14 @@
        "db99d586e2b8b96da36344653a9e6be80d6d2247",
        []
       ],
+      "accept-ch.html": [
+       "1a23661a444aaacfe354c5c3dd6ba03362f33e65",
+       []
+      ],
+      "accept-ch.html.headers": [
+       "6c56648705dad11556dbca5dbe246b169546c5cf",
+       []
+      ],
       "audio-setSinkId.https.html": [
        "f53e2f9a8b390a6ae1ecff359046316e214bcfb4",
        []
@@ -344197,10 +344710,22 @@
        "49ceb2648a93410bdd5ee53ef0e114146210741b",
        []
       ],
+      "echo-client-hints-received.py": [
+       "26bd48d007ba8f09b6c25d064fc06bad4b078734",
+       []
+      ],
+      "echo-prerender-page-client-hints-received.py": [
+       "b32dcec8f637a309769e386d0de191894af364e4",
+       []
+      ],
       "echo-referrer.py": [
        "38b54291ca47ac57edae648ff0f61212b48a197c",
        []
       ],
+      "echo-subresource-client-hints-received.py": [
+       "bb0d128e50313d4a680c4965da982ed98d8e5b14",
+       []
+      ],
       "empty.html": [
        "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
        []
@@ -344398,7 +344923,7 @@
        []
       ],
       "utils.js": [
-       "ac80eaa3eb144c02cc1fa736f1884245f2672e6d",
+       "d9459247b8ceece286bf37773406ac9b50fb88a9",
        []
       ],
       "wake-lock.https.html": [
@@ -344815,7 +345340,7 @@
    "subapps": {
     "resources": {
      "subapps-helpers.js": [
-      "53d66d3054a7702c118b44b82c8497a24f2a556f",
+      "4a79d21b37d9688a935fa49f163fea3e5a019872",
       []
      ]
     }
@@ -345974,17 +346499,21 @@
        []
       ],
       "SVGGeometryElement.isPointInFill-01-expected.txt": [
-       "0aade2cb737a5552860af534718e01c333dcd1d2",
+       "2f0e7846b0100636956128e34251d5e56c799679",
        []
       ],
       "SVGGeometryElement.isPointInStroke-01-expected.txt": [
-       "ec8b928c9253bf4280b3cc14dee8ae5ead6ca017",
+       "6d622c0964805d2895cab45e9f31ba4c5040a560",
        []
       ],
       "SVGLength-px-expected.txt": [
        "c5846bc4934faf0e2f70d9f363c23a164026bec4",
        []
       ],
+      "SVGPoint-expected.txt": [
+       "7fe069fbe9d7cd3b7b35cea6f3412a7dd88d4f0d",
+       []
+      ],
       "resources": {
        "SVGLengthList-helper.js": [
         "07697d6491b83414923e80a4a8c5a06f7471cce9",
@@ -346513,6 +347042,18 @@
       }
      }
     },
+    "mouse": {
+     "resources": {
+      "mouse-event-reporter-subframe.html": [
+       "f12f429491342ebd04df786d1d88edacc8cd3e84",
+       []
+      ],
+      "utils.js": [
+       "669a2e2edd923aa51c44e06215cfd66b2c19f727",
+       []
+      ]
+     }
+    },
     "order-of-events": {
      "README.md": [
       "a6ef35eb0bea778ee6f0bc9b069691b08d88d1d3",
@@ -346526,6 +347067,26 @@
      ]
     }
    },
+   "unload-beacon": {
+    "META.yml": [
+     "70848e7ce20e104680acf812604a5802192c2276",
+     []
+    ],
+    "resources": {
+     "get_beacon.py": [
+      "32cb9a9ba30638bf0e5c7e54655ae87e7085978d",
+      []
+     ],
+     "pending_beacon-helper.js": [
+      "067bf60c4405558ef2bf076c3260f54edaad796f",
+      []
+     ],
+     "set_beacon.py": [
+      "1c71f23e57849481b7deb204cb859ef25f6e4356",
+      []
+     ]
+    }
+   },
    "upgrade-insecure-requests": {
     "DIR_METADATA": [
      "a19d4eeecc75654a46966efa7badc560e5ebc3e1",
@@ -347700,7 +348261,7 @@
     "animation-model": {
      "animation-types": {
       "accumulation-per-property-001-expected.txt": [
-       "ca973cf0e747f51518b2a0f5ccdca673ce25127a",
+       "26a808fb34b46ff4f49a8ae53ae674b9d77c3e97",
        []
       ],
       "accumulation-per-property-002-expected.txt": [
@@ -347708,7 +348269,7 @@
        []
       ],
       "addition-per-property-001-expected.txt": [
-       "a711accf305cd5eb4b2c0a0d07758280363133d4",
+       "43fd0879ee3469af7ca1fb4c5bb6b1042e36df7a",
        []
       ],
       "addition-per-property-002-expected.txt": [
@@ -347716,7 +348277,7 @@
        []
       ],
       "interpolation-per-property-001-expected.txt": [
-       "b9f21595f549b13ab1bf4ebeeec2064a0ea180ef",
+       "c48c09d1fa86ac81e7cc48f91af90e741b3dcea4",
        []
       ],
       "interpolation-per-property-002-expected.txt": [
@@ -349544,7 +350105,7 @@
        []
       ],
       "sync.py": [
-       "05f3e621408bb4c7caf56ad1c91bc844089830ae",
+       "015ebd37a0966860a452a6f69420ba6787b4877e",
        []
       ]
      },
@@ -349892,7 +350453,7 @@
      []
     ],
     "idlharness.https.any-expected.txt": [
-     "8f3597f750fe129fdc1a9767350606d1a72c6b2d",
+     "d3ff6ff3a85ec4de9ef84c226f88183e664bcbe8",
      []
     ],
     "idlharness.https.any.worker-expected.txt": [
@@ -350410,7 +350971,7 @@
      []
     ],
     "supported-stats-expected.txt": [
-     "66839af4e9e3fd3775ef95b059ba6aebe723681a",
+     "a1cbb24a5e3d64b5acf8c85476df2f5ae7249b0f",
      []
     ]
    },
@@ -351355,21 +351916,41 @@
        "f4033effe39a34aa73954e085beba2eab1f2c5ea",
        []
       ],
+      "constructor.html.ini": [
+       "60f815f2cd2f53db31c431e49703e2be09fdf9b6",
+       []
+      ],
       "getCueAsHTML-expected.txt": [
        "c976b69ac36a6cec241b51fdf5e8e0e260501018",
        []
       ],
+      "getCueAsHTML.html.ini": [
+       "d31292ffb1530ad81fd7fa3601f27ab607c46f07",
+       []
+      ],
       "lineAlign-expected.txt": [
        "e3cb95fabe90e6439ef12a91b42aa1f220e374d1",
        []
       ],
+      "lineAlign.html.ini": [
+       "0fb67d63ab4a4ed2e7d97d4015083c9ea8a36083",
+       []
+      ],
       "positionAlign-expected.txt": [
        "83c37d8d9f10848b732d57f0c54e88e4dec844d8",
        []
       ],
+      "positionAlign.html.ini": [
+       "a05ab835ec5734a4ae325fa643939ae545c23b1b",
+       []
+      ],
       "region-expected.txt": [
        "305af887cbb64413add0152ae0b7bb0d83120d97",
        []
+      ],
+      "region.html.ini": [
+       "7c459fc9940ab70aa3920b06d8eaa992732bf3e2",
+       []
       ]
      },
      "categories.json": [
@@ -351379,6 +351960,10 @@
      "idlharness.window-expected.txt": [
       "c931731f9e66d75e0b5e86405e5b5691d3b7b955",
       []
+     ],
+     "idlharness.window.js.ini": [
+      "c5a097ba30b07342d0c55345fa26d43ccd48c941",
+      []
      ]
     },
     "categories.json": [
@@ -351642,18 +352227,34 @@
         "67f2cfa4854c6f37d1f27a3029e9f11a14d9a747",
         []
        ],
+       "regions-id.html.ini": [
+        "7210e89980d1b059debbe75d04c81bcb6ceca9da",
+        []
+       ],
        "regions-lines-expected.txt": [
         "281a7b0c33a1e0d6d23ffb0cc8f3568ff3b099ef",
         []
        ],
+       "regions-lines.html.ini": [
+        "34a94ce6e58cff8a358c27897786cb3fe341056d",
+        []
+       ],
        "settings-line-expected.txt": [
         "449a34d3f847f0b9c05f6cd81537ba4ebce4984a",
         []
        ],
+       "settings-line.html.ini": [
+        "40340c96c3b27a92ed984b7fe33697a5f576fa3b",
+        []
+       ],
        "settings-position-expected.txt": [
         "124ce2244672ed900c3356060194e547ff1e8b81",
         []
        ],
+       "settings-position.html.ini": [
+        "e08fa570f5ecee79d18f75001045bc50a2d55d7e",
+        []
+       ],
        "support": {
         "arrows.vtt": [
          "30d17b9de1afdbdf1a3616d133ead56d54440ae0",
@@ -351840,66 +352441,130 @@
         "17222bdc7b3cf03cbdc99959c718158860fcf8c6",
         []
        ],
+       "2_cues_overlapping_completely_move_up.html.ini": [
+        "6892bcb1359822d71c02b44941dbdf3646118070",
+        []
+       ],
        "2_cues_overlapping_partially_move_down-ref.html": [
         "8262b9e598c42bdfbf9c4e55986e4639efd4767f",
         []
        ],
+       "2_cues_overlapping_partially_move_down.html.ini": [
+        "6ec3e671d77cab6712f4c20b4d177de3199573f8",
+        []
+       ],
        "2_cues_overlapping_partially_move_up-ref.html": [
         "22a711af6878bdaf8f9e7ee6d574a6de84c3a788",
         []
        ],
+       "2_cues_overlapping_partially_move_up.html.ini": [
+        "6437cad6f0481fff2642eef320085040bb824922",
+        []
+       ],
        "2_tracks-ref.html": [
         "464fbcff8bff1201ca5725bae22a6995431c3eff",
         []
        ],
+       "2_tracks.html.ini": [
+        "c4e6639c79823c0f889f8fcf3c8d54bf3e37a1b4",
+        []
+       ],
        "3_tracks-ref.html": [
         "3f155dd0ade2fdfecfa2122faf1bef041f35ca39",
         []
        ],
+       "3_tracks.html.ini": [
+        "62f66507411d63aee885d52ee54c6d1d4c70c085",
+        []
+       ],
        "align_center-ref.html": [
         "90f011dc576bb7a9b40226953cfcb63c759e1a91",
         []
        ],
+       "align_center.html.ini": [
+        "9f1e2611d5b41d31c685263ad2a93be3caf81c69",
+        []
+       ],
        "align_center_position_50-ref.html": [
         "ed5e3a5e8e10e273fb56be99d072768e97193a15",
         []
        ],
+       "align_center_position_50.html.ini": [
+        "43907ecff0cd842910b17983a12ca3d7fce3436a",
+        []
+       ],
        "align_center_position_gt_50-ref.html": [
         "4d7553a8b7a0f7713c7b576511bb66eb07e1f97a",
         []
        ],
+       "align_center_position_gt_50.html.ini": [
+        "e4792661026176dbadf288a5d2097dc33f59071f",
+        []
+       ],
        "align_center_position_gt_50_size_gt_maximum_size-ref.html": [
         "73db73ed6aa7ff2a0f3fc8c5b45a97542d4d5c28",
         []
        ],
+       "align_center_position_gt_50_size_gt_maximum_size.html.ini": [
+        "c2ba0fee69c4b2daaf46a5b897251f79cc633f40",
+        []
+       ],
        "align_center_position_lt_50-ref.html": [
         "baa6511046330c8114e6805eb13c695bc2b5c4a0",
         []
        ],
+       "align_center_position_lt_50.html.ini": [
+        "82893345d531837ea30dd3fe95a4211e4e38a1d0",
+        []
+       ],
        "align_center_position_lt_50_size_gt_maximum_size-ref.html": [
         "aeaf757cc6842674186dee1157de4df9c7c890cc",
         []
        ],
+       "align_center_position_lt_50_size_gt_maximum_size.html.ini": [
+        "fec6adb84b649d7d0ba41142a7a280f13fb8ff55",
+        []
+       ],
        "align_center_wrapped-ref.html": [
         "55aed284b7a5560b70f5634cf7e7b0ab79852087",
         []
        ],
+       "align_center_wrapped.html.ini": [
+        "3175a4d21d1616c1afeaf3dc731ea88cebeb0146",
+        []
+       ],
        "align_end-ref.html": [
         "23c7c71affc17143b1f7cdc70d76092e83ec7c17",
         []
        ],
+       "align_end.html.ini": [
+        "db184375d21a92cee9697d643670938588c87a72",
+        []
+       ],
        "align_end_wrapped-ref.html": [
         "eee75f138fdef2d3745f6ce99313c056d45073a7",
         []
        ],
+       "align_end_wrapped.html.ini": [
+        "7b9ce4adc5c142c1c3d0f9941576fc38753a38ad",
+        []
+       ],
        "align_start-ref.html": [
         "b1bae4af0b78f16c9f7c9f5ea2faa79933d6dfb3",
         []
        ],
+       "align_start.html.ini": [
+        "e6275575a3f06b86600e9e502c1d8610b25bbdaa",
+        []
+       ],
        "align_start_wrapped-ref.html": [
         "45cb287e2f6c8b38731f91bc635d040e5709931f",
         []
        ],
+       "align_start_wrapped.html.ini": [
+        "42468adfaab622c360654f344f4233a91318327b",
+        []
+       ],
        "audio_has_no_subtitles-ref.html": [
         "d4bd2b74c2db0e560114109af960c7f38cb38575",
         []
@@ -351912,84 +352577,164 @@
         "182bc69277be6e553873d115f3af1f4550090986",
         []
        ],
+       "basic.html.ini": [
+        "71c924c9b58d0776e13d06cee5e024bbc990808a",
+        []
+       ],
        "bidi": {
         "bidi_ruby-ref.html": [
          "cc4df4178e6f1347d69f78021ff7c7069572adcb",
          []
         ],
+        "bidi_ruby.html.ini": [
+         "7f0b73a07abf1b8695608b70a51a60a079c3bb61",
+         []
+        ],
         "start_alignment-ref.html": [
          "78ca8979c95a31196d67a16c52ddc49a781cacef",
          []
         ],
+        "start_alignment.html.ini": [
+         "c7258a4459ae52d4d67fa686ba172af019fcb048",
+         []
+        ],
         "u002E_LF_u05D0-ref.html": [
          "3c968da7c2920fe2efb4d2eb8edd23f417548d82",
          []
         ],
+        "u002E_LF_u05D0.html.ini": [
+         "d06c91f28018eddcc62118c72e262504438459c4",
+         []
+        ],
         "u002E_u2028_u05D0-ref.html": [
          "492b1941636f38bff79b402325c93fb826a14b07",
          []
         ],
+        "u002E_u2028_u05D0.html.ini": [
+         "8d4a9cdd9432a73bfe630681fdd8adb577905e2d",
+         []
+        ],
         "u002E_u2029_u05D0-ref.html": [
          "b2c03406d5331711a03e40c3649c46ffacacce8b",
          []
         ],
+        "u002E_u2029_u05D0.html.ini": [
+         "1a8394062d591ff0abd189f408070af6dcef0c14",
+         []
+        ],
         "u0041_first-ref.html": [
          "56e47f0e083da6656d68a3bb4608a233ae5b9f42",
          []
         ],
+        "u0041_first.html.ini": [
+         "f67556a5615212eb317ced7d6baba2c67e169c68",
+         []
+        ],
         "u05D0_first-ref.html": [
          "8ea95ae597971ef74881afcf2e0cb5ffee7a2011",
          []
         ],
+        "u05D0_first.html.ini": [
+         "097c6c7bada79a3e36d1b9d99bccbe827e38e09f",
+         []
+        ],
         "u0628_first-ref.html": [
          "f5816cf62d613a7a6b9dde082c721b2b9973aaff",
          []
         ],
+        "u0628_first.html.ini": [
+         "c9921f1cbf14a6ea8c50700b8bb2e46f6f8fcb51",
+         []
+        ],
         "u06E9_no_strong_dir-ref.html": [
          "c1dfd3b6c1cb09e9c95c9b2b44bd47c286d52c65",
          []
         ],
+        "u06E9_no_strong_dir.html.ini": [
+         "7896b169a3b9680088dbffda705d2a8ed8d72ff9",
+         []
+        ],
         "vertical_lr-ref.html": [
          "42b6a5dac03e55645a3bf572d88bacb1870052fc",
          []
         ],
+        "vertical_lr.html.ini": [
+         "7b1a53abdc117879712541e1d00b7db34bc35432",
+         []
+        ],
         "vertical_rl-ref.html": [
          "737c6955532e3d01022db26b442fa88d3ef63671",
          []
+        ],
+        "vertical_rl.html.ini": [
+         "195bd7e61db01ddaa34bf5cd43196074f2519893",
+         []
         ]
        },
        "cue_too_long-ref.html": [
         "85683c7ba5c5d8c7f202c079c470e959fde60976",
         []
        ],
+       "cue_too_long.html.ini": [
+        "27d8e577f722ced68daa466eb50c64c778c410ce",
+        []
+       ],
        "decode_escaped_entities-ref.html": [
         "d12188cfa43b540d91324b22d2faceffb813ed88",
         []
        ],
+       "decode_escaped_entities.html.ini": [
+        "37e271e21509a73e3783d1ce262d955499f44a1a",
+        []
+       ],
        "disable_controls_reposition-ref.html": [
         "874cef1fa0e7f8209a4f5920df3c3fdc641ba4d3",
         []
        ],
+       "disable_controls_reposition.html.ini": [
+        "e05ee8bd3da06372d3c26d338ca3a0be8480d0e3",
+        []
+       ],
        "dom_override_cue_align_position_line_size-ref.html": [
         "dd48970516462968adcb8f46f0f9faf86933688b",
         []
        ],
+       "dom_override_cue_align_position_line_size.html.ini": [
+        "0985c53480893b21cf4a1627202771f8b86e4ecc",
+        []
+       ],
        "dom_override_cue_align_position_line_size_while_paused-ref.html": [
         "fccabb9bbafaa449f093a3b446791116f40f9efe",
         []
        ],
+       "dom_override_cue_align_position_line_size_while_paused.html.ini": [
+        "a648314d58d3f5a9795c8bd3fd8c3c6e79f992c9",
+        []
+       ],
        "dom_override_cue_line-ref.html": [
         "7569d28e4d86a2be5737094fd6f935d4128470b9",
         []
        ],
+       "dom_override_cue_line.html.ini": [
+        "9e5ce2732e1df391f5730fa8892fd0bf7dae7bf8",
+        []
+       ],
        "dom_override_cue_text-ref.html": [
         "e00d422ff7087980c507c5d7c53cc4252992f4fe",
         []
        ],
+       "dom_override_cue_text.html.ini": [
+        "0879cf29cf0376db88265e090646e4e069c6dc6a",
+        []
+       ],
        "dom_override_cue_text_while_paused-ref.html": [
         "ef2edc968f8a4f29514f48bda4ba2ee70bc8fd70",
         []
        ],
+       "dom_override_cue_text_while_paused.html.ini": [
+        "3815b4fcf288dcb995e6b562ba353d12832fe511",
+        []
+       ],
        "dom_override_remove_cue_while_paused-ref.html": [
         "60f7bb0cd380bc18f1c9ed43c240e669c819a976",
         []
@@ -352030,15 +352775,27 @@
         "f150531bbda8dc17dc9e6c1bc7211c60d773af47",
         []
        ],
+       "enable_controls_reposition.html.ini": [
+        "ec1a8ee2f458f624c02013c9ec9fbb3ff55871e1",
+        []
+       ],
        "evil": {
         "9_cues_overlapping_completely-ref.html": [
          "5eb5d732564881e4b3564de8e5c8efb7f5862d3d",
          []
         ],
+        "9_cues_overlapping_completely.html.ini": [
+         "929cd75d495b5d030b7e6e300ef68cc11ee9b258",
+         []
+        ],
         "9_cues_overlapping_completely_all_cues_have_same_timestamp-ref.html": [
          "22095bf685855978a8f86b6612609fcb2ad2f696",
          []
         ],
+        "9_cues_overlapping_completely_all_cues_have_same_timestamp.html.ini": [
+         "38ebba6c90ecff562de19584852ee6cc07998872",
+         []
+        ],
         "media_404_omit_subtitles-ref.html": [
          "b4b242795b6b3e07717b4764e737b96b36f269c0",
          []
@@ -352047,18 +352804,34 @@
          "2b7a1ed2bf600569bc554fc3a744847a334d6ceb",
          []
         ],
+        "media_height_19.html.ini": [
+         "64882286835832368a8dacd74c9307bc6a9a7304",
+         []
+        ],
         "single_quote-ref.html": [
          "81c546e026b4668c1b65e8012f28f0dae4acbb3e",
          []
         ],
+        "single_quote.html.ini": [
+         "d5d4df5237a499c0f1cd032da667d3010262ac0a",
+         []
+        ],
         "size_90-ref.html": [
          "de39a8b7adcc410f976ca716c6802d56e66ab48d",
          []
         ],
+        "size_90.html.ini": [
+         "c6c388f70259dd0bd1afc0c12e83952d8a5f9d0c",
+         []
+        ],
         "size_99-ref.html": [
          "7a6755a08d474ab6c58292b6efaa95ae3d74d0f4",
          []
         ],
+        "size_99.html.ini": [
+         "a63129470ed29f1bb1062c232442a50569547b56",
+         []
+        ],
         "support": {
          "9_cues_overlapping_completely.vtt": [
           "3f4250d8b1c9f4a8af5595e46b6bb7d2f7336753",
@@ -352090,34 +352863,66 @@
         "b3819320bf7648acd2d9cfa4db00a8f2a5f51403",
         []
        ],
+       "line_-2_wrapped_cue_grow_upwards.html.ini": [
+        "589205a415de38d82f1f99f11b56101a37c7f932",
+        []
+       ],
        "line_0_is_top-ref.html": [
         "85f2a95fa8a263bbe9bad330db7470142fb8e6b5",
         []
        ],
+       "line_0_is_top.html.ini": [
+        "92f6773615ae162bb097b0242de3cf62cad6202a",
+        []
+       ],
        "line_1_wrapped_cue_grow_downwards-ref.html": [
         "44f2c31785985df87eb020e1c5b59edcde081e9b",
         []
        ],
+       "line_1_wrapped_cue_grow_downwards.html.ini": [
+        "37e84c5d02612d12527d93915dbe347cedc25d49",
+        []
+       ],
        "line_50_percent-ref.html": [
         "098679f7be710fdfa67687912ad4471fc873df7c",
         []
        ],
+       "line_50_percent.html.ini": [
+        "a849999adf7dddc8e728c308c3ddbb15edac25f8",
+        []
+       ],
        "line_integer_and_percent_mixed_overlap-ref.html": [
         "cb39fde53e58952a32927d88e62146f7816eacc8",
         []
        ],
+       "line_integer_and_percent_mixed_overlap.html.ini": [
+        "074470be397de86642726b915e80f6bfda8fadef",
+        []
+       ],
        "line_integer_and_percent_mixed_overlap_move_up-ref.html": [
         "13247ea8bbd6751112d684e1a8fd75faabe21c11",
         []
        ],
+       "line_integer_and_percent_mixed_overlap_move_up.html.ini": [
+        "158c703e551d467d582cf316068292526cabd289",
+        []
+       ],
        "line_percent_and_integer_mixed_overlap-ref.html": [
         "6f96ab986e170ebd67bca154929ba8172e07c01f",
         []
        ],
+       "line_percent_and_integer_mixed_overlap.html.ini": [
+        "496732b9091d7d7bb33919dd4473370e3ae30ab8",
+        []
+       ],
        "line_percent_and_integer_mixed_overlap_move_up-ref.html": [
         "8f14e15e92c8d632669ae112c2687d8c7461c5d1",
         []
        ],
+       "line_percent_and_integer_mixed_overlap_move_up.html.ini": [
+        "559d0928750939e547904fbcc45a35961d0c4abc",
+        []
+       ],
        "media": {
         "background.gif": [
          "b3185c409c6dc2cede64114ad75ec7ba8561e8ab",
@@ -352128,10 +352933,18 @@
         "ed5b3f88264cbd11a158bacbd180b442d6e64d0e",
         []
        ],
+       "media_height400_with_controls.html.ini": [
+        "18e3a2e703636b46686bdc72c35db31e36b0918e",
+        []
+       ],
        "media_with_controls-ref.html": [
         "58b32dd6597cb930720c8ed15d98fbb917c04895",
         []
        ],
+       "media_with_controls.html.ini": [
+        "620646066ff8c1b9cc6f105854155fdb905e6f2c",
+        []
+       ],
        "navigate_cue_position-1.html": [
         "87f3834e3d788ac998993c996876e761cc0b3b4f",
         []
@@ -352144,31 +352957,59 @@
         "b973a71c0debac0eb4835f0e47cdaadc53bfc62b",
         []
        ],
+       "navigate_cue_position.html.ini": [
+        "d0a4880ef008174ffc47317be22fac5464118857",
+        []
+       ],
        "one_line_cue_plus_wrapped_cue-ref.html": [
         "47bb32d8c7c54a5a3fa27ba7c05035926a3f524e",
         []
        ],
+       "one_line_cue_plus_wrapped_cue.html.ini": [
+        "dc857379564af66891eea8a5a750dfc5bb792704",
+        []
+       ],
        "regions": {
         "basic-ref.html": [
          "e73018cb9e219343bc8c3462f4f328bda1ac68de",
          []
         ],
+        "basic.html.ini": [
+         "71c924c9b58d0776e13d06cee5e024bbc990808a",
+         []
+        ],
         "regionanchor_x_50_percent-ref.html": [
          "8e87920daa1c1675822af48963bc113655e05efe",
          []
         ],
+        "regionanchor_x_50_percent.html.ini": [
+         "e6ff2c1fd30ecabcba4c031bce42ae3016ef6651",
+         []
+        ],
         "regionanchor_y_50_percent-ref.html": [
          "db1031093c7a118962a6928ba85e51974a2af71f",
          []
         ],
+        "regionanchor_y_50_percent.html.ini": [
+         "85ccf3bcbf6cf023d5e99090da531ca761c75d2f",
+         []
+        ],
         "scroll_up-ref.html": [
          "378df3d2ab2e6164aef263d3dea7f083707fda32",
          []
         ],
+        "scroll_up.html.ini": [
+         "923f5eb04b1d31a5ece02d2953354100efb76db2",
+         []
+        ],
         "single_line_top_left-ref.html": [
          "8dea283bc9012b25818b44fbab91f5e826816437",
          []
         ],
+        "single_line_top_left.html.ini": [
+         "a970f9db4dc1a0d58cfb83c5e032e830578c52cb",
+         []
+        ],
         "support": {
          "basic.vtt": [
           "ed978274793480111586d0ef6e85156d142d3d03",
@@ -352207,109 +353048,213 @@
          "79f8e089caa4cc1a01fd278676c8de2e5e8848cc",
          []
         ],
+        "viewportanchor_x_50_percent.html.ini": [
+         "e50c02782d652be750c248bfd08969cfa8484dcb",
+         []
+        ],
         "viewportanchor_y_50_percent-ref.html": [
          "238b4af7995feb0e1c3dde5d9dfe03fdbacfb0a4",
          []
         ],
+        "viewportanchor_y_50_percent.html.ini": [
+         "c26599df57a8756c5f1099e330d57a5f9e6dc149",
+         []
+        ],
         "width_50_percent-ref.html": [
          "d27d698f79d9dac851286a427b6a50a9ec88c44f",
          []
+        ],
+        "width_50_percent.html.ini": [
+         "6d91bc0af4948b7c82970f3b21f51d350429d724",
+         []
         ]
        },
        "repaint-ref.html": [
         "49f385b079dc5a1422a9984db4db1cced68c8abe",
         []
        ],
+       "repaint.html.ini": [
+        "14541dd1ec51a632043d74824b0f1e741bccbe1e",
+        []
+       ],
        "selectors": {
         "cue": {
          "background_properties-ref.html": [
           "c38d513a42be17e55f03df88f96fcbbc4bad3e20",
           []
          ],
+         "background_properties.html.ini": [
+          "1c4067b109c53e782a7d129949b6376759f59a49",
+          []
+         ],
          "background_shorthand-ref.html": [
           "b6e8692dc9258b28ac5a4a76c3cf6c91111ae33d",
           []
          ],
+         "background_shorthand.html.ini": [
+          "c6689229af13647a85fd0690ab9a72212d201fc3",
+          []
+         ],
          "background_shorthand_css_relative_url-ref.html": [
           "f630d7caad5d84c6d9e05cf12262d58e6778ca58",
           []
          ],
+         "background_shorthand_css_relative_url.html.ini": [
+          "2784c4f05eacd0116698dcaaf1a12f26c775c1b6",
+          []
+         ],
          "color_hex-ref.html": [
           "7e37d8f78764e3806e995ac0b0b1d76b6c6a9cb0",
           []
          ],
+         "color_hex.html.ini": [
+          "dd33dbd26ce899436e72318bf8fbcf422f7d2bb3",
+          []
+         ],
          "color_hsla-ref.html": [
           "377a8ebe82a8c45a91d87bd8f25a647d1fd1fed6",
           []
          ],
+         "color_hsla.html.ini": [
+          "19672482f8b10dd20cda479637f4c0217d48d11c",
+          []
+         ],
          "color_rgba-ref.html": [
           "461e743da56c7f6c62afe220db53bbdd9b063209",
           []
          ],
+         "color_rgba.html.ini": [
+          "c0bb173ce604029d4cf80d4e65d1e3b053dd1fb0",
+          []
+         ],
          "cue_selector_single_colon-ref.html": [
           "cf00fe891d3bda22b5c4cec5e7493d2961f49de2",
           []
          ],
+         "cue_selector_single_colon.html.ini": [
+          "3d3a2d71a8dde53e7c411eee8ab2945257307e2e",
+          []
+         ],
          "font_properties-ref.html": [
           "c584cf1f0306dcfc4e7866b170d0fc77835c2cf1",
           []
          ],
+         "font_properties.html.ini": [
+          "d1743fc6b551b260328509025d86ca9fda7847a4",
+          []
+         ],
          "font_shorthand-ref.html": [
           "c0787248512e43288567b4d95934a80fdb29345d",
           []
          ],
+         "font_shorthand.html.ini": [
+          "07bef8faf22f485df42502b59abdfc761be19ca2",
+          []
+         ],
          "inherit_values_from_media_element-ref.html": [
           "82cebf460694afa6175e15a651df758baa78f1b6",
           []
          ],
+         "inherit_values_from_media_element.html.ini": [
+          "de9ddf441175b4cb2475567c039c79ee344ffe16",
+          []
+         ],
          "outline_properties-ref.html": [
           "c436b0a72f5063370a5a797b2c366e6d12bdfe9d",
           []
          ],
+         "outline_properties.html.ini": [
+          "4d8e07ac3970c29d64aecdb44de6cc55f423b369",
+          []
+         ],
          "outline_shorthand-ref.html": [
           "5ec6727ea2f0278110d8c2e8e68a8abafe658214",
           []
          ],
+         "outline_shorthand.html.ini": [
+          "13b24178decc4d955b64ff936b02c40d0221ef1c",
+          []
+         ],
          "text-decoration_line-through-ref.html": [
           "594d5b29b3d0d5b76313ec6cc39ad75b1f8d00db",
           []
          ],
+         "text-decoration_line-through.html.ini": [
+          "a63ffd3625b929748f42f6a710d7dca285c10908",
+          []
+         ],
          "text-decoration_overline-ref.html": [
           "bb18854b8a4859b6f434da3c5473cce131914561",
           []
          ],
+         "text-decoration_overline.html.ini": [
+          "74ff2291ca43be821a4296f0066a0f8ab3f82446",
+          []
+         ],
          "text-decoration_overline_underline_line-through-ref.html": [
           "85b2067559bf8522ccbc57ee54426559407eb9e8",
           []
          ],
+         "text-decoration_overline_underline_line-through.html.ini": [
+          "9ec52d7f1fa40425665ee19be2d5b7b74471ef27",
+          []
+         ],
          "text-decoration_underline-ref.html": [
           "4a5247233ab707e8574a365d14604f937244e361",
           []
          ],
+         "text-decoration_underline.html.ini": [
+          "2b298de9d0a5093deb5646b19fc31116c68e4cf9",
+          []
+         ],
          "text-shadow-ref.html": [
           "72e6a15ca31fecbc5c1ac25cdb1487e0979dc5c3",
           []
          ],
+         "text-shadow.html.ini": [
+          "567ce6dfdff2760596e5c6e42dd59ed4ba8eeac9",
+          []
+         ],
          "vertical_ruby-position-ref.html": [
           "8e33ca41a4729ec9da2afd8b0813f7610ed1ca51",
           []
          ],
+         "vertical_ruby-position.html.ini": [
+          "a9f04d24177adce91da0d1d7e610a19b3a08f38d",
+          []
+         ],
          "vertical_text-combine-upright-ref.html": [
           "9283f049c2a64bf805a2b3687febdec0f15bcc6b",
           []
          ],
+         "vertical_text-combine-upright.html.ini": [
+          "5fa1bc9f0ba80a5cce2d6d22379bcc26b731b813",
+          []
+         ],
          "white-space_normal_wrapped-ref.html": [
           "6c28a4f792e496beb7479bd807448ff1134ba541",
           []
          ],
+         "white-space_normal_wrapped.html.ini": [
+          "8992a83033ec3220e906fdb2c0bdba9b0584ec82",
+          []
+         ],
          "white-space_nowrap_wrapped-ref.html": [
           "b6364cab1a1515b3594f15fb4d3590e69188a94d",
           []
          ],
+         "white-space_nowrap_wrapped.html.ini": [
+          "ae5037697679411c20cb8aa1647050e8471eba6d",
+          []
+         ],
          "white-space_pre-line_wrapped-ref.html": [
           "45ee7f85dc74f7fe0685b3c3348fc0d3f2de05b2",
           []
          ],
+         "white-space_pre-line_wrapped.html.ini": [
+          "d7d36df849486b704d0dc9c43a25406978a41371",
+          []
+         ],
          "white-space_pre-ref.html": [
           "075b762bd00aa5640cd988a3a3a4db6d27b09f72",
           []
@@ -352318,9 +353263,21 @@
           "06313b9c710202aa4cf13411be326901298ce0b2",
           []
          ],
+         "white-space_pre-wrap_wrapped.html.ini": [
+          "e4ddc893f48f1318a5d06f8dbac0abe3dde7897c",
+          []
+         ],
+         "white-space_pre.html.ini": [
+          "d8fd73181dd7f8cd2e00afa2746e4cf154656095",
+          []
+         ],
          "white-space_pre_wrapped-ref.html": [
           "f568217a1470a0d3e05308564ab0b69622d5c0a3",
           []
+         ],
+         "white-space_pre_wrapped.html.ini": [
+          "b88a5e26b54a3a60edf0bebea71dbabcdc59ba5d",
+          []
          ]
         },
         "cue-region": {
@@ -352328,6 +353285,10 @@
           "669342072a0c3a855f46391aab089ae63a15deff",
           []
          ],
+         "font_properties.html.ini": [
+          "d1743fc6b551b260328509025d86ca9fda7847a4",
+          []
+         ],
          "support": {
           "test.vtt": [
            "5ead6782ec1aeaa1e3c8998808d1af162f3dffdb",
@@ -352340,6 +353301,10 @@
           "6c027c28a23c926334e6cddf428a1bcbbd63b431",
           []
          ],
+         "font_properties.html.ini": [
+          "d1743fc6b551b260328509025d86ca9fda7847a4",
+          []
+         ],
          "support": {
           "test.vtt": [
            "7edfaf7262bd9b027da2c7650ddfb6c0f82ab726",
@@ -352352,102 +353317,202 @@
           "04ce82af37bb7e44ab5aa578dcfa7366cb476122",
           []
          ],
+         "background_box.html.ini": [
+          "568758ccc9ad13f1bd7e87c997d257c9334ea603",
+          []
+         ],
          "background_properties-ref.html": [
           "e85da9c268afcad0dd3c5717984f25487b6afc00",
           []
          ],
+         "background_properties.html.ini": [
+          "1c4067b109c53e782a7d129949b6376759f59a49",
+          []
+         ],
          "background_shorthand-ref.html": [
           "85a65c96365b2fd5f20f153d8ff3d1940c2581e6",
           []
          ],
+         "background_shorthand.html.ini": [
+          "c6689229af13647a85fd0690ab9a72212d201fc3",
+          []
+         ],
          "background_shorthand_css_relative_url-ref.html": [
           "9f203dfe85eb83e3f31d6ea997df69c36ebc8405",
           []
          ],
+         "background_shorthand_css_relative_url.html.ini": [
+          "2784c4f05eacd0116698dcaaf1a12f26c775c1b6",
+          []
+         ],
          "bold_object": {
           "bold_animation_with_timestamp-ref.html": [
            "12ff3e16b8e31c1050d7000fcc63f5a2632dc5f5",
            []
           ],
+          "bold_animation_with_timestamp.html.ini": [
+           "bd2c741b0a0e0a385a92a55a6512f0979b5853ea",
+           []
+          ],
           "bold_background_properties-ref.html": [
            "53c778e9127b6d41c8f5c7493bb23530d388dd0c",
            []
           ],
+          "bold_background_properties.html.ini": [
+           "f0cf67cf1b57ec11d09f1d75dfe7d8d2f1e65592",
+           []
+          ],
           "bold_background_shorthand-ref.html": [
            "7d973a56c9cbfa20663baab53b8d9c1e21d0cc60",
            []
           ],
+          "bold_background_shorthand.html.ini": [
+           "193621c95db9b0d0cac1b5732baff4fd584878bc",
+           []
+          ],
           "bold_color-ref.html": [
            "35ed8955462d2b12976905a0f6c2dd80a2be6114",
            []
           ],
+          "bold_color.html.ini": [
+           "c565355b8d5ad2fafa2e6824e396a1600ab7dbec",
+           []
+          ],
           "bold_font_properties-ref.html": [
            "74e8acc0b626e4842124d3db335c2f680a7f2f1c",
            []
           ],
+          "bold_font_properties.html.ini": [
+           "24fe59fd6c4ec09cb523e52ca9b6cf22380c0e86",
+           []
+          ],
           "bold_font_shorthand-ref.html": [
            "ad450735b1401b4e2cf840351eb647f27d169aae",
            []
           ],
+          "bold_font_shorthand.html.ini": [
+           "c99fece190e0ac8449606a1a65a93bdd02584e5d",
+           []
+          ],
           "bold_namespace-ref.html": [
            "dba8e3d37f2dfb168a6488d65132ca79aab7d5b3",
            []
           ],
+          "bold_namespace.html.ini": [
+           "b0e4257d8a68d4ed2a231378910de00822aed3e4",
+           []
+          ],
           "bold_outline_properties-ref.html": [
            "67f873c4246aa713541b976acb5071756bc14aff",
            []
           ],
+          "bold_outline_properties.html.ini": [
+           "0c9e8a5944290e34a0f7320e655047dcb6d73194",
+           []
+          ],
           "bold_outline_shorthand-ref.html": [
            "ebb9258299512532947f5d815e9425e7d91c8f12",
            []
           ],
+          "bold_outline_shorthand.html.ini": [
+           "8a37c499e36a7e91f3ada5693e3a05b8b57715c7",
+           []
+          ],
           "bold_text-decoration_line-through-ref.html": [
            "eb06125634e515675e9a19a1cc664dd694329399",
            []
           ],
+          "bold_text-decoration_line-through.html.ini": [
+           "42b3cac490a3fe5595a4218b8c87cbd6a6f71501",
+           []
+          ],
           "bold_text-shadow-ref.html": [
            "5cd5f8985868bcd4154d79f646c712a1f7c49082",
            []
           ],
+          "bold_text-shadow.html.ini": [
+           "3f10f31e8913828c60eca6dc8e2581a774b99f6c",
+           []
+          ],
           "bold_timestamp_future-ref.html": [
            "425754ea8e0f9a6b385a237ea8eaf11c882c82fc",
            []
           ],
+          "bold_timestamp_future.html.ini": [
+           "7cb93e69af5013bfb5aabf49c6b8357c298fbfd2",
+           []
+          ],
           "bold_timestamp_past-ref.html": [
            "7cca2b42b1b44cbfe819b54f3febaedac4676235",
            []
           ],
+          "bold_timestamp_past.html.ini": [
+           "502e25ea4ad3e0c494a45d893e1c76263d083b63",
+           []
+          ],
           "bold_transition_with_timestamp-ref.html": [
            "a958d8f787a7bb4f1063d50eaefdbc5114bd79f3",
            []
           ],
+          "bold_transition_with_timestamp.html.ini": [
+           "f910f5b81fd200636108cf1b24fb7bf9ca4a01fb",
+           []
+          ],
           "bold_white-space_normal_wrapped-ref.html": [
            "9b682b2546bd72e4d393833265341f2a002c0180",
            []
           ],
+          "bold_white-space_normal_wrapped.html.ini": [
+           "47a1dc9afbafef86477013970757a1c491318ef6",
+           []
+          ],
           "bold_white-space_nowrap-ref.html": [
            "949a72e3e72b2270ee276f86e7d8ff01f8879e1e",
            []
           ],
+          "bold_white-space_nowrap.html.ini": [
+           "ea083aa5bbecf73440b53c94766ce96c9414b499",
+           []
+          ],
           "bold_white-space_pre-line_wrapped-ref.html": [
            "951b9c932cfc8d80ded6922287176e023725421a",
            []
           ],
+          "bold_white-space_pre-line_wrapped.html.ini": [
+           "dbda9d95d0786803c68096ddc060ab67d1e8a200",
+           []
+          ],
           "bold_white-space_pre-wrap_wrapped-ref.html": [
            "ffc8721a16d638b968465704969f168ca9746a71",
            []
           ],
+          "bold_white-space_pre-wrap_wrapped.html.ini": [
+           "cb82c8cd56493d7ca0083d961604e585e21e1733",
+           []
+          ],
           "bold_white-space_pre_wrapped-ref.html": [
            "b8b6025c31d1686867095dc9834c7c7cded7b072",
            []
           ],
+          "bold_white-space_pre_wrapped.html.ini": [
+           "2f982781f01e8e427da5c0094f14d180cacdd2fb",
+           []
+          ],
           "bold_with_class-ref.html": [
            "e8ce47ef8d79df5523838e213eed825a93f9ef30",
            []
           ],
+          "bold_with_class.html.ini": [
+           "893cca748c4db868be17da921badaf7b99c2748e",
+           []
+          ],
           "bold_with_class_object_specific_selector-ref.html": [
            "5de9e151499015d1e9ab5636347ce63c14c71f43",
            []
+          ],
+          "bold_with_class_object_specific_selector.html.ini": [
+           "9c16c05b951766d77cae9f5f14f6f3c79c161675",
+           []
           ]
          },
          "class_object": {
@@ -352455,341 +353520,677 @@
            "bbd5d40132b217bb5aad880c3a6594bb9decba2e",
            []
           ],
+          "class_animation_with_timestamp.html.ini": [
+           "d7b1b105712d6b1b371c1398232dcbdc8167bcc1",
+           []
+          ],
           "class_background_properties-ref.html": [
            "5639c67ac516e1a510915e34df6751a8e4ad85dd",
            []
           ],
+          "class_background_properties.html.ini": [
+           "5cad43a230625b7792bc89b6006b47256e0841f8",
+           []
+          ],
           "class_background_shorthand-ref.html": [
            "a688693582bdda0e6a2222fe4bb800d66b8fab1c",
            []
           ],
+          "class_background_shorthand.html.ini": [
+           "9b3af13c4192f09baa7bc88855f86a3f080eab3e",
+           []
+          ],
           "class_color-ref.html": [
            "22584f6910e4dd047815dcd9aa399c675c130c19",
            []
           ],
+          "class_color.html.ini": [
+           "dbd99545111576fd4056316ec9f66bc9ab80cc9b",
+           []
+          ],
           "class_font_properties-ref.html": [
            "62ab14239e010c72ea8fcb267381bd011b1ac595",
            []
           ],
+          "class_font_properties.html.ini": [
+           "eeb27f0243f309de32a89fcddf351abfd0cb3a95",
+           []
+          ],
           "class_font_shorthand-ref.html": [
            "fe17d8f4188c7187cd480c21f578a7949e122e0f",
            []
           ],
+          "class_font_shorthand.html.ini": [
+           "29d1132cadf710aedca358d8c18c1c69abef7c33",
+           []
+          ],
           "class_namespace-ref.html": [
            "13705162368153d4950a83e5c881fc843ae5860b",
            []
           ],
+          "class_namespace.html.ini": [
+           "4d6baded743454ba3c9fc4c7cc0c4a99b6dd0697",
+           []
+          ],
           "class_outline_properties-ref.html": [
            "cd712eab23ddacc0ce300f0c02550ff4a71f6192",
            []
           ],
+          "class_outline_properties.html.ini": [
+           "3488655f90146e60f7f0f2fea9037cd4c111fe23",
+           []
+          ],
           "class_outline_shorthand-ref.html": [
            "eb0195f269ccee8d159c1a61a5b59feb0550394c",
            []
           ],
+          "class_outline_shorthand.html.ini": [
+           "1b76845fe4decff0dde33572574a5ae99707570c",
+           []
+          ],
           "class_text-decoration_line-through-ref.html": [
            "d7eabfac2b13a337b4018bdd86a48c3bf49189a4",
            []
           ],
+          "class_text-decoration_line-through.html.ini": [
+           "daa47678a72bfc489cc88b8952b7eda7cffe3268",
+           []
+          ],
           "class_text-shadow-ref.html": [
            "22c339c8c535a8a84ab08913a295617127f43b80",
            []
           ],
+          "class_text-shadow.html.ini": [
+           "e8cc9f5345a0fb979dec25ccff2c0633c0cad226",
+           []
+          ],
           "class_timestamp_future-ref.html": [
            "0567e7e2c0289c6f06544b946ab267bf75d8f8cb",
            []
           ],
+          "class_timestamp_future.html.ini": [
+           "b57b6c3d431950b90adabbf39648bf1f0a620a80",
+           []
+          ],
           "class_timestamp_past-ref.html": [
            "20c8a374930e5861d8cf78e8395820136972b257",
            []
           ],
+          "class_timestamp_past.html.ini": [
+           "23023b1a1bcb9cc48b3624cdf43650e537e3bcc4",
+           []
+          ],
           "class_transition_with_timestamp-ref.html": [
            "7cb9a1ea4f0001c5b24048985802e2092aabda48",
            []
           ],
+          "class_transition_with_timestamp.html.ini": [
+           "2097db9ca08e9fd2002cb7130ff39a19399cc094",
+           []
+          ],
           "class_vertical_text-combine-upright-ref.html": [
            "8bbd791136c1053c874a413a5dafc8f140dc650b",
            []
           ],
+          "class_vertical_text-combine-upright.html.ini": [
+           "b6d979cb78d73b52c687c4eb7f5101baaed05718",
+           []
+          ],
           "class_white-space_normal_wrapped-ref.html": [
            "b710c322ee070ef9e49e28e7a3283ae24834d26f",
            []
           ],
+          "class_white-space_normal_wrapped.html.ini": [
+           "035b3eb4f8c63e4f4566a959aae015db23a22b9d",
+           []
+          ],
           "class_white-space_nowrap-ref.html": [
            "4176a6553dbec21a18b364eebe5ddf58246baf50",
            []
           ],
+          "class_white-space_nowrap.html.ini": [
+           "155396b9840a4c6466d8108037742f3f9d53bafd",
+           []
+          ],
           "class_white-space_pre-line_wrapped-ref.html": [
            "34bf662975212366d8a3b95dafeaba1f20cfaf7e",
            []
           ],
+          "class_white-space_pre-line_wrapped.html.ini": [
+           "b852c4a787872db8f024550d36bf4bb89e52b526",
+           []
+          ],
           "class_white-space_pre-wrap_wrapped-ref.html": [
            "bf642420fa1f0cbbc2f179940dca5624aa0cdfc5",
            []
           ],
+          "class_white-space_pre-wrap_wrapped.html.ini": [
+           "242a5e324eb1c24b9eea04e01c7d991f9ccf03e5",
+           []
+          ],
           "class_white-space_pre_wrapped-ref.html": [
            "a681294feccbe10427daf6cbb5dbdef2347303f0",
            []
           ],
+          "class_white-space_pre_wrapped.html.ini": [
+           "19c099a43902e21cb4efee39bef9a32df42cc7cb",
+           []
+          ],
           "class_with_class-ref.html": [
            "7f524ca84622fc571c3097cb35be511c454d2dd7",
            []
           ],
+          "class_with_class.html.ini": [
+           "44662a0c2cc47f0a717c9ecba9ad367b1795f3fa",
+           []
+          ],
           "class_with_class_object_specific_selector-ref.html": [
            "15fcc651785890af78133e58200ad2a66fe4c88f",
            []
+          ],
+          "class_with_class_object_specific_selector.html.ini": [
+           "a50ab7b5ece3a8280cfb5751bd1f47701f5e1767",
+           []
           ]
          },
          "color_hex-ref.html": [
           "9b1d412d5a52611e92588ac4d801d476fec08b31",
           []
          ],
+         "color_hex.html.ini": [
+          "dd33dbd26ce899436e72318bf8fbcf422f7d2bb3",
+          []
+         ],
          "color_hsla-ref.html": [
           "0ad35cd63bacc89763927b3f3f1ca3195e96cefb",
           []
          ],
+         "color_hsla.html.ini": [
+          "19672482f8b10dd20cda479637f4c0217d48d11c",
+          []
+         ],
          "color_rgba-ref.html": [
           "15cc158bc81dba64b49afdabf726d706fa156603",
           []
          ],
+         "color_rgba.html.ini": [
+          "c0bb173ce604029d4cf80d4e65d1e3b053dd1fb0",
+          []
+         ],
          "cue_func_selector_single_colon-ref.html": [
           "e2ccf63de3108dc7c99dce13e25a58de2bd1096e",
           []
          ],
+         "cue_func_selector_single_colon.html.ini": [
+          "3642895dc2379a333cff22f9c0717e53775b7259",
+          []
+         ],
          "font_properties-ref.html": [
           "ce446d9e96e91946fc3a36d04c287ed4a8733c2d",
           []
          ],
+         "font_properties.html.ini": [
+          "d1743fc6b551b260328509025d86ca9fda7847a4",
+          []
+         ],
          "font_shorthand-ref.html": [
           "4c9d11a16eed602cd7d555ca19f343560cabc86f",
           []
          ],
+         "font_shorthand.html.ini": [
+          "07bef8faf22f485df42502b59abdfc761be19ca2",
+          []
+         ],
          "id_color-ref.html": [
           "fce51702f7459b3413cc955d342a111cc11de835",
           []
          ],
+         "id_color.html.ini": [
+          "b467256657b63d56ac442a38ebcded4700549626",
+          []
+         ],
          "inherit_values_from_media_element-ref.html": [
           "caef6dc409c9b764b0129f8068673bcf65b27093",
           []
          ],
+         "inherit_values_from_media_element.html.ini": [
+          "de9ddf441175b4cb2475567c039c79ee344ffe16",
+          []
+         ],
          "italic_object": {
           "italic_animation_with_timestamp-ref.html": [
            "14e4fced51bc4c76c7bff13d60080e9f363679f9",
            []
           ],
+          "italic_animation_with_timestamp.html.ini": [
+           "e065b59555a856ec149894b7119359572f2b272f",
+           []
+          ],
           "italic_background_properties-ref.html": [
            "7af39a3693dbcc71cecaf1025e2e618dc6f97b5c",
            []
           ],
+          "italic_background_properties.html.ini": [
+           "1406dc0eea5a63e8b8fd1f7a763b29927720d44f",
+           []
+          ],
           "italic_background_shorthand-ref.html": [
            "030c31609f04f59229c2b41f9c2f86d9de970862",
            []
           ],
+          "italic_background_shorthand.html.ini": [
+           "391734a4531b5eb71bc0df3131da79231d79a16d",
+           []
+          ],
           "italic_color-ref.html": [
            "dd8c1d2fc15c833dc1fde7b780d43d52fcee5e16",
            []
           ],
+          "italic_color.html.ini": [
+           "04df99e28c42a5f280b1bc041f1ebf2b7ef8d681",
+           []
+          ],
           "italic_font_properties-ref.html": [
            "1d0312a1c6d98e31f8dd791a595447c8e29cbb0c",
            []
           ],
+          "italic_font_properties.html.ini": [
+           "3172efb8962ff3364dcdf999e8909174a1292a7e",
+           []
+          ],
           "italic_font_shorthand-ref.html": [
            "0abd4d322539edf55fbf9276ee05dc129bd85924",
            []
           ],
+          "italic_font_shorthand.html.ini": [
+           "95c7453a189f1c802221652db594634f88f2de24",
+           []
+          ],
           "italic_namespace-ref.html": [
            "d75cf446ff2969804e58312b88824171548071d1",
            []
           ],
+          "italic_namespace.html.ini": [
+           "7a7c66f273d2f6ba5abc26544f283daed6255dba",
+           []
+          ],
           "italic_outline_properties-ref.html": [
            "77e4d70053b67cf3ad56b3fb83f5fa6c0c8a7ec0",
            []
           ],
+          "italic_outline_properties.html.ini": [
+           "b318b050ee3b3103ac95a116d43812c6caef38ba",
+           []
+          ],
           "italic_outline_shorthand-ref.html": [
            "57ce50fab6ce70c421030fb44ce3bb4b0653c15a",
            []
           ],
+          "italic_outline_shorthand.html.ini": [
+           "c358866e8d1b6faffd50c3d5597761dca4a32d70",
+           []
+          ],
           "italic_text-decoration_line-through-ref.html": [
            "814440a571ccfe3f2e4fe122c7ef829c789aeaed",
            []
           ],
+          "italic_text-decoration_line-through.html.ini": [
+           "1cbd9f63bdb1020ba9d6a7cfea187e7c3d18f596",
+           []
+          ],
           "italic_text-shadow-ref.html": [
            "47765604096363da6e65d72456d1804c4296bb86",
            []
           ],
+          "italic_text-shadow.html.ini": [
+           "d695bc6ae0a153a2ffbc733752722af99c628646",
+           []
+          ],
           "italic_timestamp_future-ref.html": [
            "bd27d1b895fc61f1bb214aacca270f04048a54da",
            []
           ],
+          "italic_timestamp_future.html.ini": [
+           "55fb58461fce779665c84ff5f1badab2f1bf4e11",
+           []
+          ],
           "italic_timestamp_past-ref.html": [
            "b721f252d55d77a5921db4f207fa62e8d801fd7e",
            []
           ],
+          "italic_timestamp_past.html.ini": [
+           "aecb8ad3587f011b553c81e1971e2159e0ba0567",
+           []
+          ],
           "italic_transition_with_timestamp-ref.html": [
            "019e66db54b79d9aee5b8d032291a187b5a6ee2c",
            []
           ],
+          "italic_transition_with_timestamp.html.ini": [
+           "49975ce31f06a17011c075dec47b9edbf2d67453",
+           []
+          ],
           "italic_white-space_normal_wrapped-ref.html": [
            "5a50562ef78e3d437c1d8c60a5c6e82b18a7bcb2",
            []
           ],
+          "italic_white-space_normal_wrapped.html.ini": [
+           "e0a00386b4e5baee3f3e1e995df4110c384543db",
+           []
+          ],
           "italic_white-space_nowrap-ref.html": [
            "fddae1e0aad7a7800ad666b4dfed29d9a9e73acc",
            []
           ],
+          "italic_white-space_nowrap.html.ini": [
+           "270f424f02d01f78268881995ee328eb1b91af7b",
+           []
+          ],
           "italic_white-space_pre-line_wrapped-ref.html": [
            "3d075bf6dafdccfeb42e6020936607ad54e28786",
            []
           ],
+          "italic_white-space_pre-line_wrapped.html.ini": [
+           "f10b61ff2464dae453d11d03729424caeca697a4",
+           []
+          ],
           "italic_white-space_pre-wrap_wrapped-ref.html": [
            "be50ab9abe9fa6dfa73343a8788b5b2bb7a76e2b",
            []
           ],
+          "italic_white-space_pre-wrap_wrapped.html.ini": [
+           "3f462dbfd65517324fe5498ff76c13b7f4c85719",
+           []
+          ],
           "italic_white-space_pre_wrapped-ref.html": [
            "3eb92d702acd5dce6faf79719feabced9a0a8db4",
            []
           ],
+          "italic_white-space_pre_wrapped.html.ini": [
+           "40fb9d2d2d6aa63f9ba8c47392afb9289bbefd5a",
+           []
+          ],
           "italic_with_class-ref.html": [
            "f1d54d9e7f56dbdb5cd336fde50dc69f5c465f74",
            []
           ],
+          "italic_with_class.html.ini": [
+           "2d0117ecad7296183abfb490517e431785cafe08",
+           []
+          ],
           "italic_with_class_object_specific_selector-ref.html": [
            "00f9a8fc29e8351e8b50236dfab96ee53cf60f26",
            []
+          ],
+          "italic_with_class_object_specific_selector.html.ini": [
+           "87187fc58041d181e1c6f8da44020b7efb467a45",
+           []
           ]
          },
          "not_allowed_properties-ref.html": [
           "333cdb818bcde439ad7242bf4f538abc88b7ac84",
           []
          ],
+         "not_allowed_properties.html.ini": [
+          "81225a39760548477a579debfbf0792023705736",
+          []
+         ],
          "not_root_selector-ref.html": [
           "d7b46209e94c9b06d383dd0ac65f715f4743cff0",
           []
          ],
+         "not_root_selector.html.ini": [
+          "9559999af708abe3cd554088a8a21ea1bcd79a99",
+          []
+         ],
          "outline_properties-ref.html": [
           "a4cf1518d18d7b3bbe6dd4394c7aa5b24250c458",
           []
          ],
+         "outline_properties.html.ini": [
+          "4d8e07ac3970c29d64aecdb44de6cc55f423b369",
+          []
+         ],
          "outline_shorthand-ref.html": [
           "c808acba76afd012fb72864dead85e043affe82a",
           []
          ],
+         "outline_shorthand.html.ini": [
+          "13b24178decc4d955b64ff936b02c40d0221ef1c",
+          []
+         ],
          "root_namespace-ref.html": [
           "28602829d269793f80dcffe20e5275e8a4750cd3",
           []
          ],
+         "root_namespace.html.ini": [
+          "fea1ee476915c26d306a285de2b218ee90efbfe9",
+          []
+         ],
          "root_selector-ref.html": [
           "a6840f1519861ebb392f740326fb6b9607f9946f",
           []
          ],
+         "root_selector.html.ini": [
+          "813ad4ab25cf137e0234ddc98164e8bb94ac9686",
+          []
+         ],
          "text-decoration_line-through-ref.html": [
           "537f3ebf95ecb25d94bb693748172b644aa8c843",
           []
          ],
+         "text-decoration_line-through.html.ini": [
+          "a63ffd3625b929748f42f6a710d7dca285c10908",
+          []
+         ],
          "text-decoration_overline-ref.html": [
           "893bbfd02a31525a246f727c22d8087db8dfdf19",
           []
          ],
+         "text-decoration_overline.html.ini": [
+          "74ff2291ca43be821a4296f0066a0f8ab3f82446",
+          []
+         ],
          "text-decoration_overline_underline_line-through-ref.html": [
           "a8f54e2fdd64680ded2a747c7c2d6e3995267098",
           []
          ],
+         "text-decoration_overline_underline_line-through.html.ini": [
+          "9ec52d7f1fa40425665ee19be2d5b7b74471ef27",
+          []
+         ],
          "text-decoration_underline-ref.html": [
           "46bada32f788103e0ab7c7692a5e846280253044",
           []
          ],
+         "text-decoration_underline.html.ini": [
+          "2b298de9d0a5093deb5646b19fc31116c68e4cf9",
+          []
+         ],
          "text-shadow-ref.html": [
           "7fcb4e1626e52a0755775587422ba74f0e9b89ac",
           []
          ],
+         "text-shadow.html.ini": [
+          "567ce6dfdff2760596e5c6e42dd59ed4ba8eeac9",
+          []
+         ],
          "type_selector_root-ref.html": [
           "95d3f775ec8d79f40786612b650caa0a077f4e81",
           []
          ],
+         "type_selector_root.html.ini": [
+          "d35fd06543e1b158ff12ee35e564ef4579f9e018",
+          []
+         ],
          "underline_object": {
           "underline_animation_with_timestamp-ref.html": [
            "4836d205d66fafc550f0a99c6c21c519e48d897e",
            []
           ],
+          "underline_animation_with_timestamp.html.ini": [
+           "646bf3a4c6a6d63e26f7a8978b69c8f913a63a64",
+           []
+          ],
           "underline_background_properties-ref.html": [
            "a56ed92f206aad9bbfa054e673da65f360f2901c",
            []
           ],
+          "underline_background_properties.html.ini": [
+           "333c9a72148da2dedffda5752e23f04d36e3ec30",
+           []
+          ],
           "underline_background_shorthand-ref.html": [
            "a87f5bd1c77571d95946a483dbf463cb17c8c741",
            []
           ],
+          "underline_background_shorthand.html.ini": [
+           "fd55aaef323a4eed42ada13e49e18f859ccba00f",
+           []
+          ],
           "underline_color-ref.html": [
            "2f77c824e64b214c7685303e774d71f3061864cb",
            []
           ],
+          "underline_color.html.ini": [
+           "fc8102a9286fd6a7858d216740ea91c1d6be118e",
+           []
+          ],
           "underline_font_properties-ref.html": [
            "5acb4e56cff06091ebb038ed0f9441e496466aaa",
            []
           ],
+          "underline_font_properties.html.ini": [
+           "4f85fc4f339b63656e4aeb99446b698d51dc8595",
+           []
+          ],
           "underline_font_shorthand-ref.html": [
            "5326c4883f9a06f7cb61cf95be980efef64a5449",
            []
           ],
+          "underline_font_shorthand.html.ini": [
+           "fc989720bb29237ff90384af739b4437fd9b30f8",
+           []
+          ],
           "underline_namespace-ref.html": [
            "0823f44e346fe347b413276089a41e8ab090d0d9",
            []
           ],
+          "underline_namespace.html.ini": [
+           "1a380d44c7e0a28677da10c6c4cf19cf3a79ebcd",
+           []
+          ],
           "underline_outline_properties-ref.html": [
            "04fbe5a54e772dfbb216ead94c16e6aca244fa11",
            []
           ],
+          "underline_outline_properties.html.ini": [
+           "1caccd04f2733df172422ba201faea9dec093b9b",
+           []
+          ],
           "underline_outline_shorthand-ref.html": [
            "47ac3ce14c00746d369f26c0f4b067120d92db48",
            []
           ],
+          "underline_outline_shorthand.html.ini": [
+           "7241f1b8041129074648ce489302f233498600c8",
+           []
+          ],
           "underline_text-decoration_line-through-ref.html": [
            "6f78eb5df7fd1a1f08f9523d7b7f77224af60d36",
            []
           ],
+          "underline_text-decoration_line-through.html.ini": [
+           "327386c4c592c608cb5389ecff3aff5fcec24bf1",
+           []
+          ],
           "underline_text-shadow-ref.html": [
            "daf2c614e56a80d853cf07d3421dd3a8da012058",
            []
           ],
+          "underline_text-shadow.html.ini": [
+           "2e73b0e263c48b732a54c02a41480ad09728a0aa",
+           []
+          ],
           "underline_timestamp_future-ref.html": [
            "502104107a2e91632fe2af4a8b35aa4b727e3829",
            []
           ],
+          "underline_timestamp_future.html.ini": [
+           "86f8f4542191fe7e40b67beee8333052e31a8baf",
+           []
+          ],
           "underline_timestamp_past-ref.html": [
            "7ab25929baa102ba245fbebb145f7ff95f17da72",
            []
           ],
+          "underline_timestamp_past.html.ini": [
+           "971d4c1370705369ccfbcdd1a365ce1cc51900fc",
+           []
+          ],
           "underline_transition_with_timestamp-ref.html": [
            "97e2b1afc23536cc560a4d565fdf54edd462240e",
            []
           ],
+          "underline_transition_with_timestamp.html.ini": [
+           "7b24f5325037435d01da05ec36d62c852742b5e4",
+           []
+          ],
           "underline_white-space_normal_wrapped-ref.html": [
            "12563423a64c72eefc436c21a012b0b50de6826c",
            []
           ],
+          "underline_white-space_normal_wrapped.html.ini": [
+           "fe12eda37bfbd4989e34f65a29251215c666b8a6",
+           []
+          ],
           "underline_white-space_nowrap-ref.html": [
            "7e813106a1f678f97c566f54addc71dff6ab4d81",
            []
           ],
+          "underline_white-space_nowrap.html.ini": [
+           "4ea86be985189d99db96abc777aa05931f849d7f",
+           []
+          ],
           "underline_white-space_pre-line_wrapped-ref.html": [
            "227651700f6b56fbc00c0a1754046021341dfe71",
            []
           ],
+          "underline_white-space_pre-line_wrapped.html.ini": [
+           "eeba43d16e3bf366f05349c028cb6a66b18dedc0",
+           []
+          ],
           "underline_white-space_pre-wrap_wrapped-ref.html": [
            "756a66fc1701787b31570ba379c8661b1be5feae",
            []
           ],
+          "underline_white-space_pre-wrap_wrapped.html.ini": [
+           "d54ceb49ae859445e3400ad41f81f65f2ca9f2bb",
+           []
+          ],
           "underline_white-space_pre_wrapped-ref.html": [
            "8b9f12a4e0b1ea066bc56f8e9c15da58cc86d4a3",
            []
           ],
+          "underline_white-space_pre_wrapped.html.ini": [
+           "9d4863021a30418254804b18ec0834844c81f4ce",
+           []
+          ],
           "underline_with_class-ref.html": [
            "2af8b31774d34702f498f1513c81fd1d89bf9df6",
            []
           ],
+          "underline_with_class.html.ini": [
+           "550e80de3b6fd30786bb8bfaa460818f11cfc640",
+           []
+          ],
           "underline_with_class_object_specific_selector-ref.html": [
            "a2b9350bc47637bf3ac46b9c40acc6392a0f2ff0",
            []
+          ],
+          "underline_with_class_object_specific_selector.html.ini": [
+           "9a6b9c807d70d44429f9e0fa2ef74612a2582a77",
+           []
           ]
          },
          "voice_object": {
@@ -352797,103 +354198,203 @@
            "7a8a94fecde5f633f5830fc289aef7ec2d4a8bf4",
            []
           ],
+          "voice_animation_with_timestamp.html.ini": [
+           "766ff94973b4cafe3ad4ebe69d8577767467870c",
+           []
+          ],
           "voice_background_properties-ref.html": [
            "c45b7a550a7c8726d6c2da31ef472e23746e07f2",
            []
           ],
+          "voice_background_properties.html.ini": [
+           "bfa8c0855a23de6d37fc743910d5bdad0c86ba48",
+           []
+          ],
           "voice_background_shorthand-ref.html": [
            "5766b544233a993f16b6979c2e96cf9a6ad91bad",
            []
           ],
+          "voice_background_shorthand.html.ini": [
+           "1106076eecc18bc33408adfbffb0fb2271442bd8",
+           []
+          ],
           "voice_color-ref.html": [
            "81919b22e26b9173a76b5ef1acb5279740af4632",
            []
           ],
+          "voice_color.html.ini": [
+           "2f4786d3ea6df802ebdbc1bbb702fabf20095ecb",
+           []
+          ],
           "voice_font_properties-ref.html": [
            "4ed65ec581d5b113df4b67219c8413a8ff6d289d",
            []
           ],
+          "voice_font_properties.html.ini": [
+           "b87293ed24b22b85440dbaba8ffcd147f674ee9a",
+           []
+          ],
           "voice_font_shorthand-ref.html": [
            "e2ca7e18396c84c300e3bed144e13ef8dc548dd0",
            []
           ],
+          "voice_font_shorthand.html.ini": [
+           "0afa7453783f429bc1a943147dc406106e8843ca",
+           []
+          ],
           "voice_namespace-ref.html": [
            "421789935cf087bb839a386573bcee5a4b8880eb",
            []
           ],
+          "voice_namespace.html.ini": [
+           "512c252a2e48ab9587770962e2320b2bb1e3dbcf",
+           []
+          ],
           "voice_outline_properties-ref.html": [
            "da004b3abfc76c8ebf22098d9a67c20e8a3cca58",
            []
           ],
+          "voice_outline_properties.html.ini": [
+           "1691c339ea339831632396c72512a36f1c75f697",
+           []
+          ],
           "voice_outline_shorthand-ref.html": [
            "b3b85edeaee438854452ee9f5d0da4fadcca2cc7",
            []
           ],
+          "voice_outline_shorthand.html.ini": [
+           "a5c2d9e6f2ed5ea28eff40a5e00ec268e95d6ab7",
+           []
+          ],
           "voice_text-decoration_line-through-ref.html": [
            "3d43b6a5c58e59201b89a6f941d4b9cee5725dbc",
            []
           ],
+          "voice_text-decoration_line-through.html.ini": [
+           "e35db12e35f4622244d38e60364f09633a1d5edd",
+           []
+          ],
           "voice_text-shadow-ref.html": [
            "bd237e99cb33fd63a68604ff4adbe33be1787008",
            []
           ],
+          "voice_text-shadow.html.ini": [
+           "7970c835b7a0cc4f39bb9e0f5d7a513379ecee9e",
+           []
+          ],
           "voice_timestamp_future-ref.html": [
            "75239939c36504afdad75db5d29d1ba145f8dd8f",
            []
           ],
+          "voice_timestamp_future.html.ini": [
+           "f622c630e850126a3be229ac502f944799f9d18d",
+           []
+          ],
           "voice_timestamp_past-ref.html": [
            "c142ecacace7be9f8520c6fd5c542cb7af40b4c0",
            []
           ],
+          "voice_timestamp_past.html.ini": [
+           "8ab960018b6161550abacd968dade937257fd760",
+           []
+          ],
           "voice_transition_with_timestamp-ref.html": [
            "039034d9d799f040b2cd9b7a771e4734e79452e4",
            []
           ],
+          "voice_transition_with_timestamp.html.ini": [
+           "f0dd7013168e111ba19261a43a61084340d6f334",
+           []
+          ],
           "voice_voice_attribute-ref.html": [
            "c4a91ab892d3d21086e80d4c8c0f5baeb6e729f3",
            []
           ],
+          "voice_voice_attribute.html.ini": [
+           "5bb4abacd11219615b27952291bb746b2595c36c",
+           []
+          ],
           "voice_white-space_normal_wrapped-ref.html": [
            "ad67ecc03f788b89ebdcec3ba3c8119f64578b06",
            []
           ],
+          "voice_white-space_normal_wrapped.html.ini": [
+           "b187a82100a99a01bf1f4fa82f9df7cd674f1621",
+           []
+          ],
           "voice_white-space_nowrap-ref.html": [
            "1d682da28990005efce46bcd3673f041dafb156c",
            []
           ],
+          "voice_white-space_nowrap.html.ini": [
+           "90e2981524014b677eb6b2a323fc67e077204faf",
+           []
+          ],
           "voice_white-space_pre-line_wrapped-ref.html": [
            "6ddaff86502aec625af00452ecd2aeb04e40c950",
            []
           ],
+          "voice_white-space_pre-line_wrapped.html.ini": [
+           "52e6a8c474ecd647e9580be1a286c11a3dd9af1a",
+           []
+          ],
           "voice_white-space_pre-wrap_wrapped-ref.html": [
            "3822d83f2b45d7c30df71e088bff8484c832cc85",
            []
           ],
+          "voice_white-space_pre-wrap_wrapped.html.ini": [
+           "a14602e3633c041641067ff56fbd1e6fdfa4449e",
+           []
+          ],
           "voice_white-space_pre_wrapped-ref.html": [
            "5f32a25d3fd76dda2602e3fac84329528ca890f9",
            []
           ],
+          "voice_white-space_pre_wrapped.html.ini": [
+           "77845c9c8b2158e097edfafacc6c57d8445e233f",
+           []
+          ],
           "voice_with_class-ref.html": [
            "6090532837de7d351433bb231187e5c45da8a346",
            []
           ],
+          "voice_with_class.html.ini": [
+           "e38985c7030edec902d8c92acb928f6b0527a675",
+           []
+          ],
           "voice_with_class_object_specific_selector-ref.html": [
            "f6e9c19be9fe90165d7658d474a5feb616e68e0c",
            []
+          ],
+          "voice_with_class_object_specific_selector.html.ini": [
+           "a1b6679241d046f402255fc44c9dd5cb1226196d",
+           []
           ]
          },
          "white-space_normal_wrapped-ref.html": [
           "b4f797d3b9672a54ee78e2bbeb35a516dc1389e5",
           []
          ],
+         "white-space_normal_wrapped.html.ini": [
+          "8992a83033ec3220e906fdb2c0bdba9b0584ec82",
+          []
+         ],
          "white-space_nowrap_wrapped-ref.html": [
           "901257b613fc9d4a397eae722fa67750f9e7a3f9",
           []
          ],
+         "white-space_nowrap_wrapped.html.ini": [
+          "ae5037697679411c20cb8aa1647050e8471eba6d",
+          []
+         ],
          "white-space_pre-line_wrapped-ref.html": [
           "4b805184751fb6fae3d57bf54b297b7f2cbc53e8",
           []
          ],
+         "white-space_pre-line_wrapped.html.ini": [
+          "d7d36df849486b704d0dc9c43a25406978a41371",
+          []
+         ],
          "white-space_pre-ref.html": [
           "d21f199bed649353826927fe9e825209dea2f5a2",
           []
@@ -352902,9 +354403,21 @@
           "8e9e33d569e4728d7a6c560401afb33c65ff0044",
           []
          ],
+         "white-space_pre-wrap_wrapped.html.ini": [
+          "e4ddc893f48f1318a5d06f8dbac0abe3dde7897c",
+          []
+         ],
+         "white-space_pre.html.ini": [
+          "d8fd73181dd7f8cd2e00afa2746e4cf154656095",
+          []
+         ],
          "white-space_pre_wrapped-ref.html": [
           "394549b1d83b7f1ae0f74e07351b1a40c44bb3b9",
           []
+         ],
+         "white-space_pre_wrapped.html.ini": [
+          "b88a5e26b54a3a60edf0bebea71dbabcdc59ba5d",
+          []
          ]
         },
         "default_styles": {
@@ -352912,17 +354425,33 @@
           "fa388608e520192bb70e68b1464960a8106112e0",
           []
          ],
+         "bold_object_default_font-style.html.ini": [
+          "5134a538bca94a6a0c1848e972d43a4606ed7a47",
+          []
+         ],
          "inherit_as_default_value_inherits_values_from_media_element-ref.html": [
           "2fb094846f77ef4e6dc691694d555aed578cb1e1",
           []
          ],
+         "inherit_as_default_value_inherits_values_from_media_element.html.ini": [
+          "e78156cf3e82d5ae9f1b0b74a506d6d088a8c89b",
+          []
+         ],
          "italic_object_default_font-style-ref.html": [
           "76b85bb98f03a1515cd31bfc962a02917e905e89",
           []
          ],
+         "italic_object_default_font-style.html.ini": [
+          "a4399895cf91104265414fc9d3b9d38eccf7a166",
+          []
+         ],
          "underline_object_default_font-style-ref.html": [
           "3769a49d6515eff1e6783f29182416178f0ad4f8",
           []
+         ],
+         "underline_object_default_font-style.html.ini": [
+          "7924537f386b0f0c0a6924853950105cdf043470",
+          []
          ]
         }
        },
@@ -352930,10 +354459,18 @@
         "24ac13d9dc081d0b2dc6922537ab7212c97f231a",
         []
        ],
+       "size_50.html.ini": [
+        "5780c256d305bb0eb26eca09c2d2a6f8cd95b8de",
+        []
+       ],
        "snap-to-line-ref.html": [
         "bcd2dd2942c846f4f56938e842360ccf992eae09",
         []
        ],
+       "snap-to-line.html.ini": [
+        "391d7a689bfc25a6ef9ea4b88076d10d12d327f8",
+        []
+       ],
        "support": {
         "2_cues_overlapping_completely_move_up.vtt": [
          "1ca56e56f6a8be9c485cb11081c30108573a1b54",
@@ -353312,9 +354849,17 @@
         "f3ba00163067c9f389a562d3634ee53b17eed665",
         []
        ],
+       "too_many_cues.html.ini": [
+        "9bb2b2c25c78f11eda38c598104092d5c3790ba0",
+        []
+       ],
        "too_many_cues_wrapped-ref.html": [
         "24bc5271d801859f6dbf5570b24af19c3e28b7c7",
         []
+       ],
+       "too_many_cues_wrapped.html.ini": [
+        "bb05baaeffb3319e7562335b2365c903a01aed10",
+        []
        ]
       }
      }
@@ -377951,6 +379496,13 @@
       {}
      ]
     ],
+    "compute_pressure_options.tentative.https.window.js": [
+     "d142ecc088187e60bcdbbd5a94b81c1d37c89331",
+     [
+      "compute-pressure/compute_pressure_options.tentative.https.window.html",
+      {}
+     ]
+    ],
     "compute_pressure_supported_sources.tentative.https.window.js": [
      "2a69e731e7f9f7c5c0b54ea3b7bc9202bda57f16",
      [
@@ -377976,6 +379528,24 @@
       }
      ]
     ],
+    "compute_pressure_timestamp.tentative.https.window.js": [
+     "be53b0ed7b257f2c5bdd20c1198db4987dae94c6",
+     [
+      "compute-pressure/compute_pressure_timestamp.tentative.https.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/resources/test-only-api.js"
+        ],
+        [
+         "script",
+         "resources/pressure-helpers.js"
+        ]
+       ]
+      }
+     ]
+    ],
     "idlharness.https.window.js": [
      "1cdfb59be031ce1fccda43609c61b00a401c245a",
      [
@@ -399469,6 +401039,29 @@
       ]
      }
     },
+    "css-initial-letter": {
+     "initial-letter-computed.html": [
+      "e46306259a7088c3637597907a4b9f6d76933717",
+      [
+       null,
+       {}
+      ]
+     ],
+     "initial-letter-invalid.html": [
+      "574a347bda88b5bf6084bbd6485131ff1a3e8ae4",
+      [
+       null,
+       {}
+      ]
+     ],
+     "initial-letter-valid.html": [
+      "3c1e32811d80927b0e4017bfec3f98ef55f22fee",
+      [
+       null,
+       {}
+      ]
+     ]
+    },
     "css-inline": {
      "inheritance.html": [
       "6723c2a6e2ff38cb0af2ab13baf5ef9a9af0f18a",
@@ -406326,6 +407919,13 @@
         null,
         {}
        ]
+      ],
+      "table-writing-mode-computed.html": [
+       "36698ef2f50c9806bf086d218fc0600b2599d9b9",
+       [
+        null,
+        {}
+       ]
       ]
      },
      "percent-height-overflow-auto-in-restricted-block-size-cell.html": [
@@ -421533,7 +423133,7 @@
      ],
      "non-cancelable-when-passive": {
       "non-passive-mousewheel-event-listener-on-body.html": [
-       "e3be8dac7497603bf84e4fa2971ec6fea68768de",
+       "5574fe0acbcccb64ff05213fa518c49d4149e7e4",
        [
         null,
         {
@@ -421542,7 +423142,7 @@
        ]
       ],
       "non-passive-mousewheel-event-listener-on-div.html": [
-       "345e8188788cedc7ad2440b28d8cebb715fdf093",
+       "6fbf692cd79d768443492402584de4d30e519248",
        [
         null,
         {
@@ -421551,7 +423151,7 @@
        ]
       ],
       "non-passive-mousewheel-event-listener-on-document.html": [
-       "acca8a65dfe38b22b70ac2c2b9fc862aea2e1b15",
+       "7d07393c699dd51422b65c518d6e2ae42e7936e6",
        [
         null,
         {
@@ -421560,7 +423160,7 @@
        ]
       ],
       "non-passive-mousewheel-event-listener-on-root.html": [
-       "6009ec8101db15e197a54180fff89e898b05a15e",
+       "e85fbacaba6a975953a8537439c188e89cabc133",
        [
         null,
         {
@@ -421569,7 +423169,7 @@
        ]
       ],
       "non-passive-mousewheel-event-listener-on-window.html": [
-       "a1aa7b32872936cec3be5ebc21de11ed65a8aa69",
+       "29b09f85615d61195fa678487c8e9f5011dc9fcb",
        [
         null,
         {
@@ -421668,7 +423268,7 @@
        ]
       ],
       "non-passive-wheel-event-listener-on-body.html": [
-       "7545b98275f4741afedc64101ded0070a6ac5618",
+       "070cadc29187af4d8b7403f07e5cfcc8056d2efa",
        [
         null,
         {
@@ -421677,7 +423277,7 @@
        ]
       ],
       "non-passive-wheel-event-listener-on-div.html": [
-       "8884e136368c86f81b2f4eecb0b9b4e02af41e54",
+       "c49d18ac139a55ac984f27a5edc8b9c9e82292e2",
        [
         null,
         {
@@ -421686,7 +423286,7 @@
        ]
       ],
       "non-passive-wheel-event-listener-on-document.html": [
-       "de6009ee3d1ba57ce75aa27ca7eb7137ae31f096",
+       "31a55cad43e17d2fce71c8ea51bbbbe0c613bf9a",
        [
         null,
         {
@@ -421695,7 +423295,7 @@
        ]
       ],
       "non-passive-wheel-event-listener-on-root.html": [
-       "562635a84af797debaf53a9bedd1bd0308195733",
+       "b7bacbfc7ceb3843267c1c3677e57782c94f9d27",
        [
         null,
         {
@@ -421704,7 +423304,7 @@
        ]
       ],
       "non-passive-wheel-event-listener-on-window.html": [
-       "75ef3b3c40d55f038670d0d8bfeac4342e257c05",
+       "c236059df4dac95f90513dc8a691ecd5917ea9e9",
        [
         null,
         {
@@ -421713,7 +423313,7 @@
        ]
       ],
       "passive-mousewheel-event-listener-on-body.html": [
-       "24f76197183fb4d650e0f26ca82762c45bb0636a",
+       "9db12cfbdc73430a6e3461e185d33a4a94d459b5",
        [
         null,
         {
@@ -421722,7 +423322,7 @@
        ]
       ],
       "passive-mousewheel-event-listener-on-div.html": [
-       "b3a16e5fda4e42d5a5185b8ba4df2851a0b82b1a",
+       "373670856b833e96a128385e31f3cc5c3413993d",
        [
         null,
         {
@@ -421731,7 +423331,7 @@
        ]
       ],
       "passive-mousewheel-event-listener-on-document.html": [
-       "9c0796e5501a2897e51479ebf4ce3563939a14e6",
+       "71262280b6fec6fcdd63d4809455ce372cbcbbc3",
        [
         null,
         {
@@ -421740,7 +423340,7 @@
        ]
       ],
       "passive-mousewheel-event-listener-on-root.html": [
-       "20f1b9856dbd99331ffa4cb4612a4527f5fbec29",
+       "fc641d172e91bba7c111eac8de39880f289e5387",
        [
         null,
         {
@@ -421749,7 +423349,7 @@
        ]
       ],
       "passive-mousewheel-event-listener-on-window.html": [
-       "bed62cd86eca182e4295fd358b92194be25e5c62",
+       "f60955c7c488951421785db2cece005a326825ad",
        [
         null,
         {
@@ -421848,7 +423448,7 @@
        ]
       ],
       "passive-wheel-event-listener-on-body.html": [
-       "09873a9192aa3b59a2e19a5156a3994c921fafe0",
+       "fe0869b0229f5cd8c7371820db22018d5f418706",
        [
         null,
         {
@@ -421857,7 +423457,7 @@
        ]
       ],
       "passive-wheel-event-listener-on-div.html": [
-       "d29c573cdf8bc6ee9d8a69751dca9fa955ba7e4d",
+       "e2ca6e795ae0f364e2243db9731d903870c0d55b",
        [
         null,
         {
@@ -421866,7 +423466,7 @@
        ]
       ],
       "passive-wheel-event-listener-on-document.html": [
-       "b080f8331abd3f3eef40691b3398b79b724782d1",
+       "61b716f7bbfb580e596a1d2955d0ab1449d8beea",
        [
         null,
         {
@@ -421875,7 +423475,7 @@
        ]
       ],
       "passive-wheel-event-listener-on-root.html": [
-       "f4e35a791622b97fcdcc56e8fd951e9dda691536",
+       "6b383bc871d7aadfd125071ce88d97cd392dcd36",
        [
         null,
         {
@@ -421884,7 +423484,7 @@
        ]
       ],
       "passive-wheel-event-listener-on-window.html": [
-       "eb2a6f33286e4a9ae964c036b4b14a28a7728786",
+       "a1e901f5527d9ae85420f193cbd456ed0c34cd10",
        [
         null,
         {
@@ -443936,7 +445536,7 @@
        ]
       ],
       "scheme-blob.sub.any.js": [
-       "eaf01ebdf296296e6e40b6d8757a426ccfc38207",
+       "228574f25a3554a733524cf0483a8d5e1ab93f1c",
        [
         "fetch/api/basic/scheme-blob.sub.any.html",
         {
@@ -453967,7 +455567,7 @@
       ]
      ],
      "subresource-fragments.html": [
-      "61f91b6a369dd62ea3e2f61ac00bf1c79d8557a9",
+      "0bd74d7bfbcdbe78507000ef1a560ddfa0f5f672",
       [
        null,
        {}
@@ -458803,187 +460403,185 @@
        ]
       },
       "overlapping-navigations-and-traversals": {
-       "tentative": {
-        "anchor-fragment-history-back-on-click.html": [
-         "fe59f17fa7fc83315f7e550e9ab34151741b7f8b",
-         [
-          null,
-          {}
-         ]
-        ],
-        "cross-document-nav-cross-document-nav.html": [
-         "99d9a8fbb19996e5f3afe074871783c86433d252",
-         [
-          null,
-          {}
-         ]
-        ],
-        "cross-document-nav-cross-document-traversal.html": [
-         "1173f3a39b9fbfe5c300e5ad2e25aa1e0aed5bcf",
-         [
-          null,
-          {}
-         ]
-        ],
-        "cross-document-nav-same-document-nav.html": [
-         "1b2aeaecfcc6f238e058cbe31fe9f0ce2acfa23d",
-         [
-          null,
-          {}
-         ]
-        ],
-        "cross-document-nav-same-document-traversal.html": [
-         "fac6624091ab011fc9c6084528d477f664fb6fda",
-         [
-          null,
-          {}
-         ]
-        ],
-        "cross-document-nav-stop.html": [
-         "0803d6c8d15c6934f655e2147d1d00b40a254edb",
-         [
-          null,
-          {}
-         ]
-        ],
-        "cross-document-traversal-cross-document-nav.html": [
-         "05d4705df166bfb71e4a9a52a6f8a12afab0d021",
-         [
-          null,
-          {
-           "timeout": "long"
-          }
-         ]
-        ],
-        "cross-document-traversal-cross-document-traversal.html": [
-         "ec8b37427f259cc042a6c5314f9ca16b07e21023",
-         [
-          null,
-          {}
-         ]
-        ],
-        "cross-document-traversal-same-document-nav.html": [
-         "5d3850ff4e2459652c00fc6099e1b9997cc3ccf9",
-         [
-          null,
-          {}
-         ]
-        ],
-        "cross-document-traversal-same-document-traversal.html": [
-         "0a9154ca8f8f72628c4f876dba9d8fcd5e8ca38d",
-         [
-          null,
-          {}
-         ]
-        ],
-        "cross-document-traversal-stop.html": [
-         "49d97e72a65c878f452d3322bcf99ab91da42ca4",
-         [
-          null,
-          {}
-         ]
-        ],
-        "forward-to-pruned-entry.html": [
-         "f5f9a2c804f962d3b4f42f3cc22cfd8ebeea3224",
-         [
-          null,
-          {}
-         ]
-        ],
-        "nav-cancelation-1.html": [
-         "b52fa0497714f356b505fde388dc543c108121a1",
-         [
-          null,
-          {}
-         ]
-        ],
-        "nav-cancelation-2.sub.html": [
-         "62f824fdce192b57ca1d785a2e066c4f6508aeea",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-nav-cross-document-nav.html": [
-         "8082e9bbe08703be1d4cd4283b655c7c308dd4f3",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-nav-cross-document-traversal.html": [
-         "fc6f92e8194120199d61043ce58d312f6887a9f0",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-nav-same-document-nav.html": [
-         "2d8961d6e4e1e42681ecbe1b2a98bba9c307aa40",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-nav-same-document-traversal.html": [
-         "a11214383786576a0437110f96c44d5f39506b54",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-nav-stop.html": [
-         "a9036209a591902dc1617b1882fa7db25fd9621f",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-traversal-cross-document-nav.html": [
-         "3978a2c53204e6f54828cc010f91c772460e593f",
-         [
-          null,
-          {
-           "timeout": "long"
-          }
-         ]
-        ],
-        "same-document-traversal-cross-document-traversal.html": [
-         "5dfd3e12fb66bf9e06ab7152f088b64c7ec6b4c9",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-traversal-same-document-nav.html": [
-         "7142cbb06116b5148da395b1954a5e0b020e3133",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-traversal-same-document-traversal-hashchange.html": [
-         "43aefa071d888c25fc6b1fc3c115cff534e87a16",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-traversal-same-document-traversal-pushstate.html": [
-         "026173387a0b8f2c886a26dd5b245515ba3421b2",
-         [
-          null,
-          {}
-         ]
-        ],
-        "same-document-traversal-stop.html": [
-         "ffa2f1413b3d1ef5dfe611ee45c91c12a5f588e6",
-         [
-          null,
-          {}
-         ]
+       "anchor-fragment-history-back-on-click.html": [
+        "a081bec514e5e46537e30c7643d12537c698df83",
+        [
+         null,
+         {}
         ]
-       }
+       ],
+       "cross-document-nav-cross-document-nav.html": [
+        "99d9a8fbb19996e5f3afe074871783c86433d252",
+        [
+         null,
+         {}
+        ]
+       ],
+       "cross-document-nav-cross-document-traversal.html": [
+        "341f66a99655411932138b6af72f669f5c177dca",
+        [
+         null,
+         {}
+        ]
+       ],
+       "cross-document-nav-same-document-nav.html": [
+        "99525cb3edcb505fd8c59fc81b799e5c480eb40a",
+        [
+         null,
+         {}
+        ]
+       ],
+       "cross-document-nav-same-document-traversal.html": [
+        "2ff91be7e144ec4b201947182673cdde0d38eaf6",
+        [
+         null,
+         {}
+        ]
+       ],
+       "cross-document-nav-stop.html": [
+        "0803d6c8d15c6934f655e2147d1d00b40a254edb",
+        [
+         null,
+         {}
+        ]
+       ],
+       "cross-document-traversal-cross-document-nav.html": [
+        "5141259d0851517530ffe142941b596457a0d184",
+        [
+         null,
+         {
+          "timeout": "long"
+         }
+        ]
+       ],
+       "cross-document-traversal-cross-document-traversal.html": [
+        "97907df23db5dc186d70ee553e3646ed2874a16d",
+        [
+         null,
+         {}
+        ]
+       ],
+       "cross-document-traversal-same-document-nav.html": [
+        "df6258f9b3d3608d9ef6f263d417b0d182010c44",
+        [
+         null,
+         {}
+        ]
+       ],
+       "cross-document-traversal-same-document-traversal.html": [
+        "3c37c46b64c1b8f7f6103556db966dbaa525c5c6",
+        [
+         null,
+         {}
+        ]
+       ],
+       "cross-document-traversal-stop.html": [
+        "6202eb92262bc714ad0a6298e5fdcb0cdc6d37d0",
+        [
+         null,
+         {}
+        ]
+       ],
+       "forward-to-pruned-entry.html": [
+        "8e1c349e21652ca77db77a323345bca9d96bae11",
+        [
+         null,
+         {}
+        ]
+       ],
+       "nav-cancelation-1.html": [
+        "b52fa0497714f356b505fde388dc543c108121a1",
+        [
+         null,
+         {}
+        ]
+       ],
+       "nav-cancelation-2.sub.html": [
+        "c081513b7c86901c73d0648d6972e77ec10d77df",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-nav-cross-document-nav.html": [
+        "8082e9bbe08703be1d4cd4283b655c7c308dd4f3",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-nav-cross-document-traversal.html": [
+        "fc6f92e8194120199d61043ce58d312f6887a9f0",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-nav-same-document-nav.html": [
+        "2d8961d6e4e1e42681ecbe1b2a98bba9c307aa40",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-nav-same-document-traversal.html": [
+        "a11214383786576a0437110f96c44d5f39506b54",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-nav-stop.html": [
+        "a9036209a591902dc1617b1882fa7db25fd9621f",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-traversal-cross-document-nav.html": [
+        "37960c3c540ae70a3af8effa132a645930c03833",
+        [
+         null,
+         {
+          "timeout": "long"
+         }
+        ]
+       ],
+       "same-document-traversal-cross-document-traversal.html": [
+        "a48f4d484ffb3111bbd3f03725e8bdd324c1cade",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-traversal-same-document-nav.html": [
+        "5094651ab5bb295faa5c2bfd35cd7d28283bf045",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-traversal-same-document-traversal-hashchange.html": [
+        "df5ea5caab0bf37ba7b17e3d4ab82d529e2076df",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-traversal-same-document-traversal-pushstate.html": [
+        "47c7d6e3dce29754b9f86bc79c8d995bba52c7aa",
+        [
+         null,
+         {}
+        ]
+       ],
+       "same-document-traversal-stop.html": [
+        "2f0570380a897edd73ed1f340a04e9f5cf9b5eb5",
+        [
+         null,
+         {}
+        ]
+       ]
       },
       "read-media": {
        "cross-origin-video.html": [
@@ -460126,6 +461724,24 @@
          {}
         ]
        ],
+       "history-associated-with-document.window.js": [
+        "94c1b2cf6b0a4b95e164824edde3fb1281631517",
+        [
+         "html/browsers/history/the-history-interface/history-associated-with-document.window.html",
+         {
+          "script_metadata": [
+           [
+            "title",
+            "the History object must be associated with the Document object, not the Window object"
+           ],
+           [
+            "script",
+            "/common/object-association.js"
+           ]
+          ]
+         }
+        ]
+       ],
        "history-state-after-bfcache.window.js": [
         "5f04890a72805c00ea07eae302f294b632362c2a",
         [
@@ -462598,175 +464214,175 @@
       ],
       "compositing": {
        "2d.composite.canvas.copy.html": [
-        "b0eb7af95d361bbd5378a9e453999f0603aad6f6",
+        "ac022f95e0855f65952e76decca0a7a73cd348a5",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.destination-atop.html": [
-        "415815a93416fef349b7f3047a90057801cd5296",
+        "29cf9bcc53064d9579dfad643eb9e5c42c46d6e2",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.destination-in.html": [
-        "634d0ef9486f96b885826a80c38a54af1e16e3ce",
+        "dc748df15370bf619abe20d399ad0535475c76c3",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.destination-out.html": [
-        "2a17abe97a7633e501571a93f6e73c29d391dbd0",
+        "ebf33f3eba1a6852d33ba90daadf4a28dcbb89ef",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.destination-over.html": [
-        "2086c3131bb52de6913db8f7d29f99ba78633f5d",
+        "6727e324c63d65c315e60338e872132ca583928b",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.lighter.html": [
-        "16af5ff73afcb76b6f32bcb21220221587f0f989",
+        "abb1fe0ea740d5bd53d5f06b7b146f66a3dff3a8",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.source-atop.html": [
-        "9f308283ba1c8299823e2b06a0e08c5c540b8637",
+        "76ee7db0534cdb1f8ffb8757e8ddc51dc7831955",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.source-in.html": [
-        "88c578a117f03f60bf6d709eab61460a66c2ca2e",
+        "77cbb5e0a63d44bca981408fe229a149093a29e0",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.source-out.html": [
-        "b2a83cc94c6e5a78b517739a240d7579b7838b59",
+        "353dcd443810e6212c63f9cbe6fbb7c18f344db9",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.source-over.html": [
-        "9272a462148ec043ebb46bbac78a72ecba12996e",
+        "06516cb75193a91b1d84996d514c02f0fc9375f3",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.xor.html": [
-        "d9b8f4e2c86d452e15f5712ac4c33ee2a616e6c0",
+        "3bc6eb5d7908cab756fd58540cc5232d9b6bc7da",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.copy.html": [
-        "b8f0384d29242dac9690c5f426594594e1a196a0",
+        "ace0618cca4c14ae9fc623ffd1a75f8a17aff77c",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.destination-atop.html": [
-        "3b29bba8a4df3886f6d5acbe0f86f37954d28e62",
+        "45301941d7ce0ceaecca83b6e5955c7c30f1a79e",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.destination-in.html": [
-        "9679d5de46ebef68c6266f904e9ec9a0a45cfc2b",
+        "2ace910253b56b1e4ae7e80f6f05265610944573",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.destination-out.html": [
-        "69b3a4916ae7164888bf15d290ed96aa4d244923",
+        "4b3acf9b86f0bed688e6799347af7e6152bec3a4",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.destination-over.html": [
-        "60c74c659fb2fc311bd58da87e266aff593a4511",
+        "0b1f9b52711fd177ca589051abae4c20744d69eb",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.lighter.html": [
-        "ab8ea116c887f25a20320dbc684813157757d2fa",
+        "4d2525d75132c164f99fbc518b130983e208d281",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.source-atop.html": [
-        "c9e1251df48ea34253f90bf6f3ce0e3ebe322009",
+        "db722a8983aa80077c0f83295822d2f6c433dfe4",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.source-in.html": [
-        "347cfc77e6a35d46c070192156dda2bd61d6f1d9",
+        "43479240529a4d00f338e813b0a2883a73ef9f17",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.source-out.html": [
-        "c43a0f192ce1565b83ecb242e36040be89d14c71",
+        "358dad372ec3ef47754b6b76a0cb00f8d98fcb47",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.source-over.html": [
-        "6d1e5b558e65048043dad0ac33918c343c96778f",
+        "542f889e7f389b198adb5171164396658f4abf00",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.xor.html": [
-        "9f5eda566aa549507e1708cda4aa78aeab552ab0",
+        "edbf6b0be2a82bccd7270a732ef483d9c34df43f",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.canvas.html": [
-        "ea287a599ada52bdfddd665a91906090b0e2819b",
+        "2ae3d662f08c594665637f94896b0397a8fc4253",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.canvascopy.html": [
-        "3bb9577f3cc7bc076edcfc1e4be375c14d3969a6",
+        "1f3e6299ba05f010deca392df34b8c868245a213",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.canvaspattern.html": [
-        "6f6e4e247f849d80569458b85ef2c49f48e5e6a6",
+        "e861cddf302a0f6874e354d60bf3789dc70e348f",
         [
          null,
          {}
@@ -462780,21 +464396,21 @@
         ]
        ],
        "2d.composite.globalAlpha.fill.html": [
-        "dd551687c9272321fb50102d005b55f487fe4b39",
+        "fce9b7fbfc391e1f909e5f52578597954eb8527a",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.image.html": [
-        "ab24cfb0522af68898284d5cc38d42e33af33fa0",
+        "deb13f34160cfec3d6ab42c6ee62b374dbea2e48",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.imagepattern.html": [
-        "36b46d152205d043c314911b0ab49306542ba0c8",
+        "06aea4c02958c8e4d6e8b0a53507750d63076735",
         [
          null,
          {}
@@ -462815,77 +464431,77 @@
         ]
        ],
        "2d.composite.image.copy.html": [
-        "b8f9a80cb6ee5b8fb1a887b55682e8abcc77fe08",
+        "f32e03bbaefabb9ce2f84223d1a3db3e4a5d70b5",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.destination-atop.html": [
-        "e14d76e2eccaba96138e1d4ef616afcbc306fc54",
+        "2da0d198d058172c9c468590a6e79e8efb2a0a5f",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.destination-in.html": [
-        "b2a8e2595b50fd1a90a00732ec1d9119e5ad7335",
+        "63871b2d8e7de22bbba9614f4e7e0342731bef34",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.destination-out.html": [
-        "1281af962392aefe3580051436f128922395a2dc",
+        "3d96b191ecba0215a7cd107ad54486d98a8910e8",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.destination-over.html": [
-        "d742f84dfb8622669dd860c234ba192688c96027",
+        "8e3dafb6357239a5e95a49b768007b6ea16474fd",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.lighter.html": [
-        "139f65a5ec10ff112f01186a4a05ef03acb16ddd",
+        "6271a77594ed8aa4a7d19ee6715ece2f43a21da2",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.source-atop.html": [
-        "c1d952c2b87fce603196ed638576d5ba032921bd",
+        "eb7d75449dd0440bf403a49fc3251947a3fef7b5",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.source-in.html": [
-        "23d7273f336940bc7d58e563cdd6420d6df509ce",
+        "0f2fdad979f9879757e8450c1160c096f449df74",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.source-out.html": [
-        "94a904c018d4a76b2f63f1370d76bc58db2ab913",
+        "fd920855d403fa5cd79641c7b3c561af064d5b7b",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.source-over.html": [
-        "6ecd184b5b3174d01f94389afa083b135537232c",
+        "ce5b6c631b805ff56e538b2c488cf40d66287805",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.xor.html": [
-        "2114751e09bde2eb750cd36f6961b95661d78ff2",
+        "68ce901d2af7ed78864cf0807933879dae651efa",
         [
          null,
          {}
@@ -462955,294 +464571,294 @@
         ]
        ],
        "2d.composite.solid.copy.html": [
-        "25fb4ed6301180a533e22654636becd0aaea6939",
+        "74d9ad5cc2eb7152601a7729059414bf4ed702c9",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.destination-atop.html": [
-        "4557b11c3ae58f73af41ed905f53f6fe108db092",
+        "5e8f60474ea5722d878fb4d54d2f6f6d20f08839",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.destination-in.html": [
-        "3f8ab1424105081f30ff7f94287c6ed9aad4b464",
+        "246bdee5450f2b217b40c8f04a39cbbecc9012ee",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.destination-out.html": [
-        "a96e1c84d9b7c355931a66b68bb9ea5da0850e52",
+        "7227cf41d82556e8dc0ca0b8f9ac5c04e1b0c38b",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.destination-over.html": [
-        "9943a582ef7ee5aae0a5488e308ffbece40e9792",
+        "48671cee5bedab06177e862aaae2a517a5dc65a4",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.lighter.html": [
-        "7c8f514a0c5d742e94f7ff3aaf6756147e53c449",
+        "f869b6d1a909bef98ee2824490d8e4a9c8d05b03",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.source-atop.html": [
-        "0cff288de3ffd5ba52e46724404313dbae085069",
+        "14041236d2d97d97bd00a49d244ad2e2e81cce75",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.source-in.html": [
-        "91652da756ceb2fa7dd351daa8df7956bfc1181c",
+        "8f1cfcd16fdfbdbef6d08118eedecdb8d3d1c4eb",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.source-out.html": [
-        "62f7faac53c1552a084bf3385be520769002e144",
+        "55522d54c2416bc15c277290f240bd75aaf5287c",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.source-over.html": [
-        "ef030462c746985075d200722a133dfc6cc4c419",
+        "6194526396d2b7ec55543c6435c96471f54c5364",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.xor.html": [
-        "88089aad16faa8eca65aa4c127965ccf161a3f89",
+        "431b8a334644df311a5bc7e735490c3033232084",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.copy.html": [
-        "91cb114f1ed15444efede3d3e947af96065a6b58",
+        "58673a12f8347f64cbabe621a1cd4ecf60211c60",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.destination-atop.html": [
-        "8e7c441ddf82c10fdf7f86f72fc37cd1b20268f9",
+        "4d22016feace83c44bbd925bef2edb0cd0508f22",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.destination-in.html": [
-        "00643667f61902a638e486bcdca45799150f6e89",
+        "e946c721514754edf7e47c19cfaaddb89a2125dc",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.destination-out.html": [
-        "32c5be9e804429c7216d72451e4094472131508f",
+        "6e2482519336ef8d810a0d4e62b14290cd54a56a",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.destination-over.html": [
-        "bc1792f0b00a0ce155e3339fe136aab56075c47c",
+        "4c9c9fbc5fcb06c338adc87d3100523002bfcde5",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.lighter.html": [
-        "2147088fdb74f3f6414b3a821974a72ba7fa60d8",
+        "4b3d148447909d461f6cfaabb8cb3e2cb7d496a5",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.source-atop.html": [
-        "6f4f502533bb1e4aa7d4d874d3d639063afcac40",
+        "4b0987764a196ffaa5fac1785788c8ccbf435dce",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.source-in.html": [
-        "4cef84f51bbff38d61cdca5b39a722983174997e",
+        "236f01b49ea3842a3e1917865a06f317b2650744",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.source-out.html": [
-        "18dc208a517687c7c49451eb2adde49b93d847cb",
+        "d597ff9e06ecdcea3b6b9d0eb62bbcb849aa58b5",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.source-over.html": [
-        "6045b14cafaac20441225e7bec9d50b6816b50d9",
+        "e2f8a7f6f8a6224bd7d03dd4f4d01bc9e7143f02",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.xor.html": [
-        "a40168bc150f57732e62e9fafcc70d1e708d8beb",
+        "83027e552045df71d3c326d159e110ca7a00b412",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.fill.copy.html": [
-        "b5153b71b667e3af0e7520b8163b92f1c4cd86c5",
+        "cd443ae6aa668f1416ea51fe4cb4d84f160a630d",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.fill.destination-atop.html": [
-        "1875aa813d5e5ee4f23376e2bc581715e149448c",
+        "9182124ecf23c0749c3aefe71f7f39d4f7748899",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.fill.destination-in.html": [
-        "ea88b1111775f06e5abf359490224e62167def66",
+        "7906c159d44982a5e03e055d55b7258b68318f52",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.fill.source-in.html": [
-        "18631c94cfb38bbb27d64b83a64fb3ddcde5e02d",
+        "d46b7d44765654c701c8953ecb10503a5f5ebd56",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.fill.source-out.html": [
-        "60c82a990613e0f3e7da45ad55c760e5e70d7a82",
+        "08a026496d58f30b703da9190ac14d03fa24c3f1",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.copy.html": [
-        "d53c7113c6c5d017861ae937b34350b91628814f",
+        "e909612a5f5ed010dd3c23d78d751c3aff4ded25",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.destination-atop.html": [
-        "aedc0993282bfea98e4bc24c384c52b04c582373",
+        "d257e2f2af15fb5f64def557d02ad19b55331f54",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.destination-in.html": [
-        "f9efba60997f6c60ef2ba8c8f38289f3e4119387",
+        "c3e3bc0c47dbd819f4d4e41894308e21b53afbaa",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.source-in.html": [
-        "a01fce3d074b52852633c92312b737199c7cf232",
+        "fbcb3c23dfa21c062d5b8c6c2662c47971399ee7",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.source-out.html": [
-        "495cbfd8f8ae9ee6fb533e2d09ddf5ee8c4c785f",
+        "03979e6ffed45a1fd007102f863bd30b2c6ee7a0",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.copy.html": [
-        "93a3e9d95df5e9123c48a2f81f5a5382305bcb16",
+        "4bdf1d21761d28a49c0cdd6fdac4f0414827d656",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.destination-atop.html": [
-        "c2fe2de400795a086a4f9da27a781c387e132441",
+        "093b6829536fa26dc496b1a96d166397a0cc9fb4",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.destination-in.html": [
-        "9c30b6edfc6690994049a414f9220db3b4592efe",
+        "dc613bd0619b6aa1c123a8ecbbf90b1f962f1d56",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.source-in.html": [
-        "375c50661c6d7a3c3b64b305875ad3beddc241f4",
+        "6616b4ebe4c256cb36dfa8ef50aca1b9b1555791",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.source-out.html": [
-        "6891ff64eb9d80b25760a3f4564062694a4559c8",
+        "fe2d70f258b659708bac6b1fd4e0c3091d9d1644",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.copy.html": [
-        "4fdd6e08a2e2a5fa76c6ff2f023406fde470f9c8",
+        "4d6a91de91827f64cb3eec6535f61f50d4a337d7",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.destination-atop.html": [
-        "47ad8ff7fce676538aad95248674d4af1c9ca39b",
+        "bf03da0791dbddad69087d4e756db79ce923c23d",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.destination-in.html": [
-        "2dfa056e2a0f36ce2b72d84f31d62dda792b0da2",
+        "f5a5fe3f9df83156afc9c22e5f07b3ef18eb945c",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.source-in.html": [
-        "0be4fb6bd556bb3a719191b1f957d56331faa4d0",
+        "385334d4c6627ee8e027bf0994bd91e00bcac7b7",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.source-out.html": [
-        "dacae113cb573632e09693a74e20af2b8ecb99af",
+        "ae0be111a98ddbba2b6a94c222be3e69aedbc437",
         [
          null,
          {}
@@ -463281,77 +464897,77 @@
       },
       "drawing-images-to-the-canvas": {
        "2d.drawImage.3arg.html": [
-        "22844edd23f242256de4088b5ca7a440e06d8097",
+        "7669c280491a93d1b2ae2adca50c60cce41af18c",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.5arg.html": [
-        "fac52a0fc00c4f915a956161944b59e76991063a",
+        "3a2f205094612965813c49075625a4a4c1878704",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.9arg.basic.html": [
-        "3f2a3c6e7dbb6ae328d6b05b1168956d3f1b4e8e",
+        "eddf3c1ea91686c8f8b7f8affc09723fc3548bfc",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.9arg.destpos.html": [
-        "f1abe00330d1c4ce214f5029968b7fa7eb137450",
+        "d85ae7806569f6f3057889f5a64d9939c131939b",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.9arg.destsize.html": [
-        "b3df0219a33ad158035f1d7fd78dd0ec8d95d308",
+        "703c67889481e38310eb5db959a16baddc5892d3",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.9arg.sourcepos.html": [
-        "f8f55f97d2d38843ec6a2196be8726393c739fc6",
+        "48ab9376ffbe42bb0c6e2739af696a32c031b58a",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.9arg.sourcesize.html": [
-        "aedbb25193e2eece0fad89446dc37e1fa26d1bd1",
+        "5946cb30c9aa6033cdc0b7dd4fe1f302269bc48d",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.alpha.html": [
-        "adec48a6f6fd9ec52eec4f7a310ec1ec0afa968a",
+        "36db82e4edb912e7b4ea92f2b5605c19f90c9526",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.animated.apng.html": [
-        "a7dac1719626e24c5c3b752c02b9554075685c15",
+        "b16473e36857c9b2013042f6609fd1e31b73e3c7",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.animated.gif.html": [
-        "c2489159eed991848420ea7bc46d2660a73d5106",
+        "30cad0c7aea9f2d93bb800431e98401f260dca66",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.animated.poster.html": [
-        "95b255c5e022170bd23951cf1bfe85e65185f14d",
+        "6afc4e713c4c5942e3cb0fe69cccb83b3094e381",
         [
          null,
          {}
@@ -463365,84 +464981,84 @@
         ]
        ],
        "2d.drawImage.canvas.html": [
-        "18348d27bfcdd1b1aa323976e6163e64f62e225a",
+        "3041d73791369c7d77b55a623b1a624ab094797e",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.clip.html": [
-        "876862d0abc6ff21af4a91c9c475dc15fc2b0fe4",
+        "fac98fe949d85aa870988c968bbc7c7ae4cb8729",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.composite.html": [
-        "ae3b32fba072216c82642f2f2bcdbd325ef59208",
+        "60204a5d27b7259b0cb1306183ed175c5e15d4ad",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.floatsource.html": [
-        "0b0f30703edad503e39f0986535c6d8acb3d023b",
+        "4b715f29feaae425e20bf7b93841219b9df2c658",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.incomplete.emptysrc.html": [
-        "471ff440a4d085e327d0681da2445348541698bc",
+        "c684589de06ba2f8dc3b982e5a1c59955577342b",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.incomplete.immediate.html": [
-        "d44e26ab92aef880e95e75a8783b83c669a7495b",
+        "347e750eef99883f6abeb1f9de5a788137819b32",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.incomplete.nosrc.html": [
-        "f9b21e0e2a72ee89d09971c19faec5c27c38bf2b",
+        "677a7b856fa5157d63f6773ca848a6e35c41fb18",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.incomplete.reload.html": [
-        "e3457e4bee038b694d3f3c3ac9551fa868c3a559",
+        "5f90f819efe9f9c5be18412ca63d31681dba61a3",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.incomplete.removedsrc.html": [
-        "f963d8d169c13dc88a4fad800c8479deaa7c10c3",
+        "c887fd64533a0e7487f935da86a9eba9c892c46c",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.negativedest.html": [
-        "33702398226fc5acae824a65f499c935bb791257",
+        "8418f635d4865fa89ef65ff1f15b068d5bbd7859",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.negativedir.html": [
-        "a6083eabd02fd6c661f466db33f24fc36ebd7bc4",
+        "9a42e5af85490f2e66dd898b25519634d1a44672",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.negativesource.html": [
-        "bc14864eec6a959950bb4446fe5ff7fb372b4006",
+        "07b154b1f02ebc8a3beb5170633c227bb103d3fd",
         [
          null,
          {}
@@ -463456,14 +465072,14 @@
         ]
        ],
        "2d.drawImage.nonfinite.html": [
-        "cda50dfc5c1622ec92bf24b62759816d81fbbc1d",
+        "673cd3e64aa21aa65ca483808b424f529b96cf5b",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.nowrap.html": [
-        "e6f4254e0547a5107e9529e9f8e326e14198cafe",
+        "71b45a52d43763c059a8b6864a5af47ebf004f9f",
         [
          null,
          {}
@@ -463477,35 +465093,35 @@
         ]
        ],
        "2d.drawImage.path.html": [
-        "8c1ae7211b76a593d91ba9d0a38b6253c1ba4e07",
+        "7cc5afe094274f7885e857468b629a16f6a34f68",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.self.1.html": [
-        "8b0a4c0b7792c33d605759525152b904837ce264",
+        "7c5524b95fdbe552e782ae57a6491fb590aa43c8",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.self.2.html": [
-        "62a43044153b644753bf815e29c01b56a5d31203",
+        "dbc96dbb3c17a5a5a56937f6be0b975fdb6992b0",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.svg.html": [
-        "6c12a6bdccaed00338a080ffb303ad23eab7666d",
+        "b01232d447d6c7056d4f6449f5f8a4f16f4607d9",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.transform.html": [
-        "eaf3895eca2fde06ad62e2705653d736016373ae",
+        "c49070e69cbe542c6c437307412117201658678d",
         [
          null,
          {}
@@ -463533,14 +465149,14 @@
         ]
        ],
        "2d.drawImage.zerosource.html": [
-        "b2cd1e82089223e32a481198d6a6b3323123ed96",
+        "3831f3cc86494d48ff67a76dacadbc6b92bf7697",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.zerosource.image.html": [
-        "8739265a8b25c7c6e41cb127cebd3e336dad2162",
+        "b37cd4d19da45cc07899a7720ee100b13f67f271",
         [
          null,
          {}
@@ -463549,224 +465165,224 @@
       },
       "drawing-rectangles-to-the-canvas": {
        "2d.clearRect.basic.html": [
-        "6179636480234f7f128938a89ad02afef1802c9c",
+        "3821fff21c0c2472b03831184862114bfacd3f43",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.clip.html": [
-        "0c6deaaaada1e675882b81cc63e343d3b2f60f2e",
+        "da2642394416fb93c14b3a0fe052aa132d09de98",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.globalalpha.html": [
-        "cd27ecf2bc9bccb4d7c4b43dc86eeb7c24d7c96b",
+        "3a228ae7ab3f9e3cd2562555d161dd80e0ad8e32",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.globalcomposite.html": [
-        "54976fe3f3a7b7e2c06bdec4d7aa654e0265d126",
+        "2f49b8086004d03418bd73124e1ffb6371ef49a8",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.negative.html": [
-        "2124535f2be60c03e35c88a09239047dd4c19197",
+        "13ad1fb81204e6eb4680cb2dcaefe86e34158c5a",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.nonfinite.html": [
-        "18ce63081322d29d8365b59c23c8ad0689104c17",
+        "56232594e10accfdd37ed73745f500b8d9ec10fc",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.path.html": [
-        "d0dbc6cd2d0e151ad160e4d45c9694594d944a66",
+        "8d837adc3a3df4e233018ace8e6578aaf2a2d84c",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.shadow.html": [
-        "89c051b5cce05cc509e5a25b72413a6ac616ec57",
+        "e65b46b23cd3d62733c92a995335b4d19c5bea63",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.transform.html": [
-        "a3ca992af15f7c561050839fc89a20438b233e85",
+        "9e524c36f2122296e98fe1033fb5d7a141478ed6",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.zero.html": [
-        "45830a1683bc6b88296265b3a7f99ea25a7f95c5",
+        "ea1fff31cb86a1c074de52a515c3f418dc2ce3a6",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.basic.html": [
-        "a440dfd847b43467bb110e89d4c1ceee58b6cefb",
+        "14c04829a7501ea39679e78ca321787a3028c868",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.clip.html": [
-        "ccbe776889ac1849f6770968248b39d8ab1ec7ab",
+        "bdd269e1ad0c3f09323acc4d04e184a6ea5c977e",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.negative.html": [
-        "0a2fa3d4c8f85c9de412efb5f3b7d8420b3c54e0",
+        "6f754581b22bb02440e33ed8f7b65f936e9b1e26",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.nonfinite.html": [
-        "98b19cee4fda962aa53555ec847c84d60efef6c2",
+        "bf0ea501a07eaaf24e778bfbb15ec8a6f1597489",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.path.html": [
-        "d13144925abd6f9b393c8e9420d221c877629427",
+        "3d073c41f60f71c121d05d67125ee973bcf2ddf5",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.shadow.html": [
-        "35c73e98a8a9311f6b8eedb9046367cbb12fb1f4",
+        "78f3f4d36771b49540799eb59475baf4b383732c",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.transform.html": [
-        "409faaba0bdecf4799af5f8d968f09815ef159c4",
+        "6892747651e4d56d7fad4530fb7f25d85b8d638c",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.zero.html": [
-        "44b50244eb628dd64ddc3b1540e402b876d3ccf6",
+        "915347713fa3443c5a38b33db58cf7e92b232529",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.basic.html": [
-        "c50fb1b969d3f1546ec27aa3cb83038051ae283d",
+        "299bb8a39eeceb9890b464f99e9eec587c77e255",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.clip.html": [
-        "1da47f43d959d91fa7cfcb784a168cd4fddf772b",
+        "5f35cd07be33ac91c12b60ac60ab1c1d1a90088a",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.globalalpha.html": [
-        "300aa59ecae703c5ebb4e2531268b98ad3aa11bd",
+        "3e80a77f74441a8197b9e570962fa3f2366b39ff",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.globalcomposite.html": [
-        "5b6481803d06b7f960066d4d80e89bdcc1bb8ae6",
+        "ce52dffd8c215f8d6b2eba34323faf09d903f7cd",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.negative.html": [
-        "5dfdfee14f66a3c8c6e6a37fa363699a246612e5",
+        "617d56f125cd6baf72413e314eef9bb5c6b99174",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.nonfinite.html": [
-        "27829cb31f0bee9906342689a35f6d25d57bd34b",
+        "3f98e5e2feb4665c2966e6c0c7891c2674057713",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.path.html": [
-        "2dcf83d700174851e721555d63ceafb54d2cca40",
+        "5d88373525a7f4285f071ba538c5b93003acd9b6",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.shadow.html": [
-        "0c6928b74d6182b96432ffb79ba91b99e48de47a",
+        "a8c7ba314a31e5807b38fe1e8a2d347b2b1c363e",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.transform.html": [
-        "436dcc18d2e6e27a3c178c9783ca84b46d204928",
+        "9fe89042abf02b780f9765589ffd33e7fe32e234",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.1.html": [
-        "f8b6cdca623e046517b7a980dbd1b1a714a63195",
+        "188699d6a8d11b1efc846b54b026853ccec0e2f9",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.2.html": [
-        "78045a4d9f6fa2e17fb3173b2907f4c0f7589826",
+        "2e28b90dd2a50c487fdb28fd7c14b27b09b1e09e",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.3.html": [
-        "9103800747775ed55401bbc0da8e815a1ac0a616",
+        "5831c228fffc352256be3235d768dc08e60787a3",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.4.html": [
-        "435a77f3f348793865c3902a6f8f9116ae45a5a9",
+        "6a09e8eaf9586fa24b42dec40fd396a6d2c78622",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.5.html": [
-        "cb1a7537aea0950365a5d33b5ed087ef03d22d61",
+        "c6cc50ca9b5deec39cc6b0148c4e901391941026",
         [
          null,
          {}
@@ -463775,49 +465391,49 @@
       },
       "drawing-text-to-the-canvas": {
        "2d.text.draw.align.center.html": [
-        "3aecdd14fcc49aca7461573a4adf9a334593754d",
+        "71a7cae30a17ec7bce07d36340c8c6a8b5afbe8f",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.end.ltr.html": [
-        "5e9f0d20126a0977227731263125e5e99ead342b",
+        "5bd7aa10b0223061bf878b84ad677e130e2e1f14",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.end.rtl.html": [
-        "527fec9a3c4d29c4008601b15a69b15e5352dea2",
+        "d37a29c558d2414c280fdef78dee8d8ad5de58bc",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.left.html": [
-        "a9626bacac07f3e882de86b47ad4ba17052e978a",
+        "5a4bdb6abb9df4d20937ba6701f3764859095366",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.right.html": [
-        "e62ad304168b246bc92707ca02ea68031ee8f2d3",
+        "29e009e72249a93a00520e051fb540c82856147e",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.start.ltr.html": [
-        "af4c77179ebdfb0aa0f85227d22e3d5d738a20bb",
+        "d74a4b89e41977e2ef382511b153bc5efa97e24d",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.start.rtl.html": [
-        "2492482e80cac6604bc58e16b1cf758a7537af86",
+        "8dd671cf20403a7319f269bb142c99f57acc166d",
         [
          null,
          {}
@@ -463831,14 +465447,14 @@
         ]
        ],
        "2d.text.draw.fill.maxWidth.bound.html": [
-        "300c4539d3317fcbb2c19568da64523d9179e191",
+        "50c67293492f3ac07465a914e45fd9e2b3204ead",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fill.maxWidth.fontface.html": [
-        "8de1ac69eacb96a36edfeb392f527e3c07348c52",
+        "1e133a6736ca915ab6bfd0c1a099cebab81ac17c",
         [
          null,
          {}
@@ -463866,49 +465482,49 @@
         ]
        ],
        "2d.text.draw.fill.unaffected.html": [
-        "9cbace645bb1c4f6575dfa976468e906e24492bd",
+        "cb1e7dbae02896719ab6526bd192aafa8031e254",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fontface.html": [
-        "f6435a6af07451874f30d0e8c54f49a92b83b623",
+        "9adcf3560d5730e08a286136a937c7907c5afe22",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fontface.notinpage.html": [
-        "7a21dbc40e79b0134b18386849bdc622b54b9be1",
+        "6ccb0c020affffda57863f0cf00a65b20e196e8c",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fontface.repeat.html": [
-        "13c27b6e029c9c95b505e64a7ad827b075da15f2",
+        "457c48c3d1b0e4a72496fbe936814a8dff106a73",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.basic.html": [
-        "6e1ea12a595ace25c7413ccb64f4b76ae57cec92",
+        "26f8114e20ea20d4a13ded7b81ff92c6dd670e55",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.nonspace.html": [
-        "9c1d2f758c79f9e833ad462b8287342d881ea8f2",
+        "e105ec358e0b10c9f542d06e1a3aca8f18bb8160",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.stroke.unaffected.html": [
-        "39636e2322b08600f0f49d1625b467fee2de1471",
+        "728765c1fe752bdc64cc309962f7909291c43245",
         [
          null,
          {}
@@ -464071,28 +465687,28 @@
       },
       "fill-and-stroke-styles": {
        "2d.fillStyle.CSSHSL.html": [
-        "9850817c114fa40281ae475b0949f4a9df201341",
+        "cc48c2e1476e6ba946a3d39594b9026b1a953d80",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.CSSRGB.html": [
-        "f916b8f6751515cfba116fb1b14137ef06748ea9",
+        "0e3fcd4f67174a4515e10c4268b02813569cad31",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.colorObject.html": [
-        "969d2f34cb44b15785dad4040752bd765b59f10b",
+        "02408138c24178cee210192711e97a3a894ecdcc",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.colorObject.transparency.html": [
-        "ffc16d73ac201d33aa76d375d48185a0a866a092",
+        "09a8eacdeca918f3699376eb9553d514f03415e0",
         [
          null,
          {}
@@ -464134,868 +465750,868 @@
         ]
        ],
        "2d.fillStyle.invalidstring.html": [
-        "e9473b6a189d26621baab4d89789199bd50b4b3f",
+        "16bb9235c9b9cd931e45b1da2616bdcbc37e9a21",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.invalidtype.html": [
-        "3434e336607f42a3222c7e221090b2f0bc0db2fd",
+        "d218368359fce477f65fdd1c8a0c66d88f656382",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-1.html": [
-        "7f8d28cf6cd8caa0f9a9a4538b3ca0b641c5e5d0",
+        "12a338e066ab67f6ccffdd56fc3e738f1fbc57c9",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-2.html": [
-        "3d0b465286790fb40b014d2b2b4adf632a82efac",
+        "71db4187ac043b7a2555e04c608bb71289ea4d40",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-3.html": [
-        "0b2ab3b973c9fdcfad4a303d81b9fde1027ff196",
+        "6c84e94b031248f9219ea5e5c9d51b3f0d4f40e7",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-4.html": [
-        "85a7f728359506217b3c4a4d1b9cf9de2a229bd8",
+        "d37965702e0371dd9f1c93484c1db018f88d83c3",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-5.html": [
-        "357a6ba48f833a748fec5dc58e59cfb1cd51b01d",
+        "62ad91f1dbaee87e7fe689cfa12a530f69b24574",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-6.html": [
-        "4fd50152afdd3eb955febc2a252594dcb0c63544",
+        "9c879828d0af031a15c300b8e2c083b89a6279b8",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-7.html": [
-        "6f5ca4f90ed03a9b1dda613fa96cc1b801f8f558",
+        "c3e2334d445f2cd8c8e1a7bbab7dcae5837afe11",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-8.html": [
-        "bf45c6ebb6b2020626329bd845016e8890476da9",
+        "b9baf11e2b4db3518284023e7102231c051c04e0",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-9.html": [
-        "54b5661e635668ade8628d1b715ae297e35033a1",
+        "274585c3c9f7ce70c59cda0a52081f2da3094071",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-1.html": [
-        "fd950ff0122f8e42873902fe16475f63a0b57a80",
+        "e4a5cbc0942fb98155f22aead153e9c928adb4c2",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-2.html": [
-        "0ed5e85995c8f3eaf28abf98737f5036cdb0fb0a",
+        "976bf71b87fd7a1bce1ad055a70df6f61870fd87",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-3.html": [
-        "4a816ac7768331f529cfe91a09da2ffb7d6c422f",
+        "16100e6a94ca8a65c5ca26bed09ec2a912e084a0",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-4.html": [
-        "87a81e18409329fe328ec34c3f874534566362bd",
+        "eb0158e392cd0435b9e646602d244f8f0abe80f3",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-5.html": [
-        "89af5de587c0c58e80e902be4b32f7d73aaf7288",
+        "c1b7c566b3a823bc84a79d18df9475d8ee824f72",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-6.html": [
-        "fd54bde52ae2997a1c861d6f7907718690ad32f5",
+        "06aa355d251fb695dd3b8426b04b55c6ed34c908",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-7.html": [
-        "553a567238daf4931218a193228d9f833fa6ea2a",
+        "eb66e2748aa66b2ec372832aefde1096df5887a4",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-8.html": [
-        "992074987d833a0f2461b044f1847fb7d052550e",
+        "0c13368ac26bc1f822408c8e9be4176963021b39",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-9.html": [
-        "5ec6d24e3a78adf503a9c519b44de1d9315f3592",
+        "fd2cedd56d903ab78d5fe034104fc8d33cb1aeec",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-1.html": [
-        "4267b6e6ad7983e3cfff1a9166aa311d524a08e7",
+        "7fa79bf07d1a1c0ae8785cefad4814e6fb1bb691",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-2.html": [
-        "d4e21c3d0f7bb4dce90f722ab41855d9fdf69e4b",
+        "89ef2183a74166012479bfd7c94ba83fba7fbf6f",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-3.html": [
-        "2842aeab688b09db65d28c2f646313c8595fcc1c",
+        "6be6f060671fb9d07a39e96fc0f562bf5090b34b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-4.html": [
-        "a4d1bad77f841100afe724e46bb9b37e67d34a26",
+        "23c69bd939e068b26169db2223f41d33070fc9a8",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-5.html": [
-        "ba2c4599db43fb77eea395707c06acfd492e7e0a",
+        "b853fbf35376583163a26e3c58c29e0a7772870f",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-6.html": [
-        "2540613e70640a969f5378cd8d879039b694a99a",
+        "8a62fa22d8ea495dcd20768a2f92f6e05747a250",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-1.html": [
-        "f480a3773be09447e8505c0035ed7f36adbec3af",
+        "66834dd7064339d6e7e23ab628fc69220bcfc9e1",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-2.html": [
-        "97b0bdd8186d2e049f6e04bfed6da45ae3d0cc13",
+        "4a4cb78c62aa532c3ece6d3121c08e950452e16a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-3.html": [
-        "7e3e2605febdc711066905291791aeb613162c76",
+        "51e946878619c020105a36019296f74d436fe4ac",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-4.html": [
-        "d7a85210e00cbebfcb504df8ccece1ded9a157b3",
+        "07a65ac8f365add36b75695f9117f2409b2839be",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-5.html": [
-        "ac36578800dd30e2e84fad3406349e81ba5a672f",
+        "2f798f47f31fae1fac8c3ccf9824ec5c1bd459c3",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-6.html": [
-        "7d559caa1d1f1005c227987c7e95cf911b90d50e",
+        "5ca7564a0587ee2ef00f5fea6fd176f9dd434f9c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.current.basic.html": [
-        "2de43c8ddfeeeca4017a5fa6c981fcec732e9bde",
+        "e48d05ceabb43b8a2809815a4b21fd7b58d66bb1",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.current.changed.html": [
-        "13541d822ec34caf39811a294e076c42b633be56",
+        "f298af5adb69854c34efda384152ca2deaf94ab0",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.current.removed.html": [
-        "16e7ff0f7e2c755d183b65a46ec2660797a12a33",
+        "2642b888e9de22399f889d39ed520efd0a9ad699",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hex3.html": [
-        "48d3d80b28099e137611c42cb35dd329cbf14bd9",
+        "9fbb2750147d6f671fbfdadb10ead8f7718de43c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hex4.html": [
-        "61845d95886ce06841f20e74669a4e94f6417288",
+        "fc79cc7d3fc7c726e34c9c8f50fa54d2bc66aff4",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hex6.html": [
-        "1dd71fa0ebbfd2822c8121a923db9f215d863c8e",
+        "b946c30e1748865a1371ce281c2a318d8f28fbd9",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hex8.html": [
-        "15c7cb47e24d3e3bedb3ed749f58216cf32d2270",
+        "5865e98f3f5d1a40c6b9de8abfdaa81d9dbb17be",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-1.html": [
-        "d24c25c57d2c343f2ac6e9751305c31b63d7c214",
+        "e169904889b64446d5a9b3ec598c1cf49a0f0f93",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-2.html": [
-        "124144c361713550814a8e835503f3f32a967205",
+        "ec61f580eb64aa7ee8782fa88904d5a04142f91c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-3.html": [
-        "9a82ded60894c84eca74158920062926f60de8b9",
+        "0ec6fce487b80072db91161474113e293d668155",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-4.html": [
-        "02c736567806cf17f945454ee4c78d89a803c836",
+        "b3119da927dbbc59d3c033c02257473a609afe46",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-5.html": [
-        "619d49eb321368dfb5fd986df3da176e3368230e",
+        "1867bba7cb836d46b2cfe8956c0e8dc78550240a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-6.html": [
-        "cfe735736d092da4ced108b2282e193b33c12140",
+        "7a5e764d95fb0facc840f0f5cf24430f398fb604",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-1.html": [
-        "50271c3c3d7bbbe5365b3eca76c8c4bb6ef62191",
+        "f623320cd537166bf095926a30b8297539ce92f9",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-2.html": [
-        "aebf22bcff5c8c2bc3b526695f829e29a97c0f98",
+        "0293acd9eb499eb1fa1070d83fd54aa963a56845",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-3.html": [
-        "aa73a581d2d17d08d389406cfdc512d693a94824",
+        "2ea1a5115a57809f5947decb417f159fcd8b34ae",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-4.html": [
-        "b63144c667c73ff9b6316f494137e0b9aae62237",
+        "add688ebc915b2e09c2b2a8a7f2b940de6028438",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-1.html": [
-        "d9721fd0ebc3a1a147051311fa8b52f614c58860",
+        "38427cfc3ac40798a7ace37ff759867d8a237c12",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-2.html": [
-        "ec6b3057f9492388a23a3c00c17ed6c81803e4ed",
+        "01a83676ad8de3052108cce997e3fb8a622ae052",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-1.html": [
-        "b45507e9afd524fa5706be955a3c92a6cbd1e5a8",
+        "b7914e3a021ad1325ed9ed68d013d89142f925c7",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-2.html": [
-        "e83535ed6ff622824ac49aee672bdb5ce48c4978",
+        "94b6237456046687b30a44b36d962ad06c61f5a0",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-3.html": [
-        "e04d97ae08af1519bbcc63ebe7bd9e8fb94f08b5",
+        "bc2466b6b57694d8b6294362621d89e3a43a7cc0",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-4.html": [
-        "8fbf870aa54f504960d40031efba09655a03a343",
+        "35c0d00011be9ce09f41cc07deb9bd56c96583de",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-5.html": [
-        "f9cf1ec2ed6ed8fa9f430799855363734caf5130",
+        "13fac2fd589b1af1bf1e407fbc33026b88ed51d3",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-6.html": [
-        "b150cdaa0f1a4b593b8f72641dada8544db3d2f7",
+        "ba76ad6a99b4f0baf061d19e37cd5ceef851976c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.html4.html": [
-        "e345457d9e70f570d4d0f9aadd604c97b12b996b",
+        "ae54397c924cb2972d1cc7cd1d1f94009b6a5c6b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-1.html": [
-        "3841c5e7cd2ffffb37d374c9e79eeb69647271f8",
+        "1850125baa451ac098c4979d3cbb07966679267e",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-2.html": [
-        "6926a8672116003d70ed95ce6fa07017a9a1e23e",
+        "b4fd4a6fd97c16072f063218cb0f5077330396b6",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-3.html": [
-        "e2652c43d382697e1c850787afc081ae0d4a59ad",
+        "224da3a981d8072b6bc148714271194c2a5479b3",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-4.html": [
-        "1a09a1ecc46033ac2250df25498f1fa006c408ee",
+        "0e4b77ba80b98fdaf92c8f387a046c0fc543f991",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-5.html": [
-        "bfeb3c5a522607e588fbccfc9166789518c72e2b",
+        "08e03db12f3dda0c473ffa6876c199f926ccecb4",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsla-1.html": [
-        "b5caa8049566e641230348d0f90212bfb8a7a2e3",
+        "62f82953fdb1348155cc567f4bb4b1676c710b75",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsla-2.html": [
-        "d9ce0ceb97b388d90eabaf53542d22e4bde0b0e1",
+        "d6b78e923d555439cc5bf31ac3a67497012a2810",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsla-3.html": [
-        "e8b762de6d67d7cba7367eb4a009b747773c991c",
+        "c5717406a208c29f0fe6e394cfe0f74a3ccd9e56",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-1.html": [
-        "4c3ba2e8e3dde13bf26369e69ad64b7ee3e27ef6",
+        "01ff94e8b02590c78346abdc7df5e42035dbaa99",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-2.html": [
-        "caddf3cb76e6e7e15ace19f5f4be6287a3298152",
+        "2b782e35fc1d8bbf81d24cee2e4e0d27eec58f0c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-3.html": [
-        "3f6edbfd5add2a440cefb398eda203c7c27e5cd8",
+        "54849f6c55986853a65e270ac67309850370f67a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-4.html": [
-        "fff8c8bc45cf61189f22401a09e2718e093de2fc",
+        "97d5748aaff4b0c3aa3c891841ab138432b9f299",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-5.html": [
-        "4dab0570685f2428cbdeb3b95fc3515beabe5705",
+        "666c3c3d3e5e858537d2afeb83626ab4a4bee7a9",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgba-1.html": [
-        "29d99e4ca9e37bd4c2c1a4453b6e648bb13ae430",
+        "fefe336c19fb5b844cee47522ef67e32183b75a1",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgba-2.html": [
-        "9d9d9090e9d115c36b3b8f7d1693b3df9adc09b8",
+        "bf12006745c12210576325cd2be596f88c14f6ed",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgba-3.html": [
-        "7c82f2827eb85dabbd7e4fe05b849f02fe78b1d1",
+        "a4e4e906afcc1a24f7c394be512a87ecff57fa98",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex1.html": [
-        "d0cd0132a40af1e9332b220ee52cf862950e0aee",
+        "04c67e343efa3e15f0fac54b57fde37954911be2",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex2.html": [
-        "8131812166ea83b0a694b3dfc499a52bbbadd7d3",
+        "7027db50cad94f7639ac5f46aff68849a359e51c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex3.html": [
-        "1999d07f0aad55e89754acf2d33fb89163b834b2",
+        "ae7a32a5a4a17ce5a5ac1f1d1660c6f29cc27e01",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex4.html": [
-        "958d667a7c13d1ac6759c8e2a59822016db7ea3f",
+        "d355309c19bd7ab971de9f5a857bd0477542761a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex5.html": [
-        "9a3df4eacce3e21c8d9b2c9e58b435ac22ce2951",
+        "0b80566b8cf6edbfe5b3391659395d7d0c09785c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex6.html": [
-        "79ff88676961943d2ef2b88bb71b9f243efacdb1",
+        "02b75c3aba68595f41562cb2023d1d92a349782d",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex7.html": [
-        "8567854daec90003e0344ad468a87b46b04ce3d5",
+        "6a73bc1f75c7277d4ce3059be95ad54fa12d805c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex8.html": [
-        "696192024bec7e6367963842652f1fe3aeb74aa8",
+        "3a03959ec4e77af72c76730d7df2b934c5116b60",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-1.html": [
-        "e85c62150117f8b4e8d4706a9e0f0a839632d598",
+        "38a01fc107abf2d8ec1d7154e3a83709892d18b2",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-2.html": [
-        "9991412ce6de1ab3a4dcded42bd8727710299aaf",
+        "6783a18e8734baa352c34a509aa4aba223370e9b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-3.html": [
-        "4fee496c7434964d7c59241d97c5290b820b5ce5",
+        "8f9137e4d724437f4d466d54672c772748ed333e",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-4.html": [
-        "9031dab72f2a8f7612946c0e7c0626f73d2c5f02",
+        "56c7228b410d750711a83a11cfadfa2ea5fdea10",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-5.html": [
-        "77c3c1155f720b09ea7895d561a055f348c0cc71",
+        "df84f6854f544686cc00d8535dd95969da64528c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-6.html": [
-        "580323ffcafac7914e1a818cb93766124bbf10dc",
+        "2a7d0753d905345b78ad96f9a9299e346d4def2e",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsla-1.html": [
-        "bef560790c9386a5aea400c45fa10085254bd61f",
+        "5d22135c5cf961fa81d00bde8b6517fcfb86a3bb",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsla-2.html": [
-        "c87505ceb79e50178b847d9883abfcd59030074d",
+        "f1a29cdac2da48f8bf9ff7ccd46e31927b7997df",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsla-3.html": [
-        "296bd4bb0a70c102dee09580fc897baa762e1014",
+        "e48d086ef23ef4ef9c2b2532fb9f7553521c9080",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-1.html": [
-        "3517b6593afaabd398ae4cf7959d28b0e8b7b0a3",
+        "80433bcffd6173111f9ffd0a7e3d1f107a6e8cd6",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-2.html": [
-        "c67a36733eb0f42b626ac4ca23dacdc6b3a3eca9",
+        "e1a49f97c9dbdf5693c0bb814b1b3b0570b2c4bb",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-3.html": [
-        "0ef250dc4871dab35a76e8a77d67bc5f92d438e4",
+        "c8a7f2e6588a1756c5d9cff1f537b1adb11a6f70",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-4.html": [
-        "341bb1ace0c9e49c4a2da57601b2344f4e2db7ee",
+        "b9c491fd3109c5301182733cb3d710d6d3064eda",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-5.html": [
-        "b612be95fe48774cf6bab610a44edef9fa7ec6af",
+        "15dab0bef5b745d7dbac500abfbf626090187667",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgb-1.html": [
-        "a1df321433fdd53d08b5c9184a9b7696e15a6475",
+        "7ab4a42fa8c4072e94b0f525c0731daa7cd9ca3b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgb-2.html": [
-        "3a6d359b118cf37abd46cc9a0ab160406ce31219",
+        "1aa36bb32bded00a59ff8ba0bf8f5032310bb085",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgb-3.html": [
-        "e756704abe868bb246ef34165d990850adc01ad4",
+        "7ce48c1b7e90dc7049725c5030ab84eecd5b951e",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-1.html": [
-        "e66008ba563dd68af38aef3ecc0db216950b622e",
+        "d3bd36dcf2dd7f067e82589b86e5c12058dc3cc5",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-2.html": [
-        "699093be6cfdd5727cf726d8920d146849aaff1e",
+        "0f468b66fada675f4a27ec2fe6ef06d7ed7e1241",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-3.html": [
-        "ae3556541a94ff1759ce35f437682229510a5350",
+        "20da461ad9e0eb344b5c1b105325b80c4cbc26e5",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-4.html": [
-        "9c35b2f8ed3bb6f11fca224bcb55f12f2745ce5a",
+        "6dc36ea341dbf4f85bce63552c154dc067dae16b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-5.html": [
-        "b93d0a27a98fd20489e1ee1c70d0c14c649ddb08",
+        "86afaa70977c01cbba2000d988b2c71c9ac89aa4",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-1.html": [
-        "f4bfb9df3a4a3dc557e8a9318ca096752c12e899",
+        "dfaac14637104f5a46416a21dad0d970b3a5b137",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-2.html": [
-        "dcce56eecfe02fbe98bc369b368de5843107e536",
+        "5247f46731869dba3592b18deb24770c799c347a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-3.html": [
-        "531c058e34e063a3d3f29a1fc9cf51b4808ed430",
+        "8db471c3c054f09035158a0f0c66a6ebe99a2992",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-4.html": [
-        "0ea164a8eaf8bd3a69cf4a24da40e6b728373ab9",
+        "e7a210f48d5ede6f4065ee770cf048918d4e3e3b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-5.html": [
-        "8c7fdfbc9787c7fa23eefe987b95e1d757d5846d",
+        "1f1e9ef70fb2b5f9ae82708a741054b1195580cc",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-eof.html": [
-        "2319cda87d9bbf6566ce056d809a4ac322fabdcc",
+        "b69c779a7a91a26f7c80e3bada2beb45957dbdda",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-num.html": [
-        "55e2f52625aefd9aff914202f83a149ee05a4e2c",
+        "7d9d5eda56cb54ab5a4797f2809a086526934c23",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-percent.html": [
-        "79400949dc26527cf0afcc00b3b30caebf8bf8c5",
+        "ea5529c0ee64ca9ca3e2e099de6067c698f49509",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-clamp-1.html": [
-        "e7215b0d085716c0fb79ba11da889b80bfbd114e",
+        "c5816e0660f6ee14a8966852f8305390877e1542",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-clamp-2.html": [
-        "04e9833041b390839493fc9eb6550d312ea7a6fa",
+        "69a55cfc9a05b56af54bfe344d7f405d7f141397",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-eof.html": [
-        "68ff65e8810fd744de7cfb8e8839b47b15f51e3e",
+        "12c296dcfb323fbd04d38656ed3c734fa8dcb058",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-num-1.html": [
-        "cfd9d03b42c1af821da97b576473f3683fa80050",
+        "41968883df3c6d5c7af617f0f450a69484660ee3",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-num-2.html": [
-        "88aaa2e9035027e8f3cee205999e82c93e11524e",
+        "f7fb6185ea03d0cff5ff788fa92afe65f5262660",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-percent.html": [
-        "57df2a5be1f7bb101be0adb9e0b5a7b8d00e51bc",
+        "3f1a7305bdede6ac0db010b143c510ddde77df01",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-1.html": [
-        "bc7cb30b468dd047cb814ec25175b8cac12012be",
+        "efa7eb8928a3ec73f68836c3d812e7f1ca00d406",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-2.html": [
-        "258f5cfc044fada8a44c1a3172c2b40da143c98e",
+        "eaf917e2c9cb90602202baac01c66820fe16848c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-3.html": [
-        "d527715c6648d66ccfb560cd01c3bc19934c545a",
+        "c525f824a9268969e5cefc4f349b9b127d0659c2",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-4.html": [
-        "e5f4655755dff940ff23db4890922802a649bdb0",
+        "b7f96741bd5f8d8c81acb28a4513c9ddb087a36d",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.svg-1.html": [
-        "491749330ee91bd073b12702ee07a21a3bf2971f",
+        "9a9a280c477c4eb40e59c97fd186a14744ca6162",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.svg-2.html": [
-        "da98bd2d2df2ccb0e06ac5331058c20d857f6a10",
+        "26c2abec09cbede7cfcb143b81d0e8ae7195dc7c",
         [
          null,
          {}
@@ -465009,14 +466625,14 @@
         ]
        ],
        "2d.fillStyle.parse.transparent-1.html": [
-        "efccb35d32774ee70cf3664d4adad616a9f45698",
+        "9ab01f0cbb6bc118967091b769564832f343799d",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.transparent-2.html": [
-        "7ebeeace5b4e56583ff762a61c6eba79a998e5ea",
+        "d7730a55045b5fb32cd623fc9d3e48e6f0bb3c85",
         [
          null,
          {}
@@ -465037,98 +466653,98 @@
         ]
        ],
        "2d.gradient.conic.negative.rotation.html": [
-        "9a988ce01aa6269a31b454f4aa68f48ea0d6a1e8",
+        "f61b614f705ab83d62e3d1da408fbec91cf1ae6f",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.conic.positive.rotation.html": [
-        "4a8376a81f02a71ff705b48d1ff764a50cb2b3f1",
+        "ffe958665844175d34120ab7637b4a99a43c1467",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.empty.html": [
-        "c5fc908df31e33abd27c1c228367d7bd56fb7444",
+        "bdf702fb49ccce08863f4db5cb6534424c3a82db",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.alpha.html": [
-        "ea330abe31073f2688e7c7be24c0983bd29b4a81",
+        "e0ed47e03fe40ce1013c87ef07ae10d7df758688",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.color.html": [
-        "ea22e2fe36874e8127dc6e63d14e0bfd3b725c1b",
+        "e6806d7df10840c970511b8378fd6d3c649f18fd",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.coloralpha.html": [
-        "e5cee70a49e6766bf9ff92834425e2111fbe968d",
+        "33fee527d4b1bbc331654e3ccb10b62a0603041a",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.multiple.html": [
-        "ed1792cde16e1d720501239aaa4dab18a209619d",
+        "adfac66d57d3d468e8eda884e4a178da71bc58dc",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.outside.html": [
-        "4ce8d0fe19cc78f79c6a684f90cccb41408d2f21",
+        "abad0b5cb0144d31fdc94d718dfd3e02e9bcffef",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.overlap.html": [
-        "60cc806f1ea7d0d2bbd6e28ba42683e4e7005929",
+        "ecd61728c2599076e5f674b94903792a15cd59f3",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.overlap2.html": [
-        "3e7e4010f135ecbbaf76998a842afe7fd05a4cc5",
+        "3b5446950580fb40fa9f148e0c998c401dcfe1f1",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.solid.html": [
-        "bd546aa5be30eb543142a3329cf64e0672a9cd4b",
+        "f6fa97475b1a08efd71e9bff3deb16d7e7b8fe4c",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.vertical.html": [
-        "fc742d4833b6dd219f93b492de617a3d45f072f7",
+        "5297996c065d881f541923f581e387fa0921e462",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.fill.html": [
-        "13eaae8fbebf7a12e49e0f50e9a7e099d8301aec",
+        "8c6b944cfff6c9dcb7f08fe97af9e3edb79c349a",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.fillRect.html": [
-        "816480977e417dcde29f9f65d8ba27d8863c71c8",
+        "3a7fe18a3477daec3c2958c058bf9996f4248c25",
         [
          null,
          {}
@@ -465142,14 +466758,14 @@
         ]
        ],
        "2d.gradient.interpolate.zerosize.stroke.html": [
-        "2203a901492afa956439228ef9e0436a8a11fb28",
+        "e5fb64820270b0487b0246be97ec7e2eef9c3021",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.strokeRect.html": [
-        "6ad2a0e6d37592f2b6d512bbc5873c884285055c",
+        "54f49233b75ee73dda6c2238b81869f457cbc9ef",
         [
          null,
          {}
@@ -465170,21 +466786,21 @@
         ]
        ],
        "2d.gradient.linear.transform.1.html": [
-        "c695cd7e6aab0e9ec06b2a2ea30a1dd799735cff",
+        "b2b1f78ffd8077e8a345b9d2fc0428d6535ffe2b",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.linear.transform.2.html": [
-        "2515cdf1712e6f78ab377480008007327b9999da",
+        "49ff026226da0fbba619f792fdc8c7e5fec4e732",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.linear.transform.3.html": [
-        "4fac1c6b14158081e9e59ce7a26a2514aa305c3f",
+        "36f5e469727c13b7f1cab492e8bb87598aa8aa05",
         [
          null,
          {}
@@ -465198,14 +466814,14 @@
         ]
        ],
        "2d.gradient.object.crosscanvas.html": [
-        "42a6e1257b7f73bf73fa743e173202dcd8da1813",
+        "3b185b4dfefa64bac02e1357ce8e2744aa417e9d",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.object.current.html": [
-        "85912c877362297c3aa09a05e3d5addde9c3e4f7",
+        "b0d5c01cae744cced7fab688a76433faa8c20796",
         [
          null,
          {}
@@ -465240,91 +466856,91 @@
         ]
        ],
        "2d.gradient.object.update.html": [
-        "ce2392bac685b5dcc73a844fc7e24d5e27df8b8c",
+        "b54b110c5f8ddbd0ac4177471129e256943787f9",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.behind.html": [
-        "94ffdf8d40b77ed5c7a7a6110ee20abe3f10f605",
+        "4200a1e7b82d605956eaedcb93c89cb875d3b7b6",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.beside.html": [
-        "a6b486b77a9514d367322d77784019c708d9fdec",
+        "ab183f9030d345e412724702e7397647464b4bd9",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.bottom.html": [
-        "b07428a50a2ee80943369fd1bfad1b676b665ffd",
+        "872420b30277ad7b8b293153861beb0e4fc45857",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.cylinder.html": [
-        "ca6cc0066f20e252d727759cf57c598e25a48160",
+        "fae7ef86bad7a41ac17e84c75fa1ef2ab9cf8d1f",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.front.html": [
-        "f4c820f192de0dbc8ec5374b4f4fc7e8a80b08d3",
+        "ff743824962a33146537670a0dea7e0206fcf97c",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.shape1.html": [
-        "9fd2217d8629f8f21f0ec69e2257865a521dbda5",
+        "7e95eb25b2f4d3dbea9d2dc9cb5ca8a77f206742",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.shape2.html": [
-        "15e8209247f4433ecd9a0e511c1953f30f3011df",
+        "7ebe7d26c5946d64870d5a3d627133c0e58714b7",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.top.html": [
-        "94c122d09851456dfbe2ae2920638750e80932b1",
+        "5db91b7ff682bb27285cf37c348ebe784ea42996",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.equal.html": [
-        "f67e60c9a21e5362067f16e45256162f11570f13",
+        "aeb4990eec67ea6e96983a9c938f191df5ba9315",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.inside1.html": [
-        "bb00026469c1456b9682a140f67964e86066d00f",
+        "102a31bf216bc55de53fc935a87ae99539690ede",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.inside2.html": [
-        "42afc472e312bee5a587b2c42b7888f183a0ca35",
+        "5b26ec5ebdd78ef6de1ba313cab0ca4e415d07e1",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.inside3.html": [
-        "70ec41f5db6ba26c5311233bdddf380b49796fa6",
+        "30612d458c5e4e768b0c75b08f115dde1215b10c",
         [
          null,
          {}
@@ -465345,91 +466961,91 @@
         ]
        ],
        "2d.gradient.radial.outside1.html": [
-        "49cccdb7a0e0fab68e6459b4594ad59ae4cf9276",
+        "cb1614455e96be722de50c3a5b3b5680b2182d2a",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.outside2.html": [
-        "9244b732a10c1308de93bc625e2ba0ea3eccb691",
+        "685384968265d7833046633e3190d9e6da27fbac",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.outside3.html": [
-        "a8fc86095f7a0ce39668d429ba9f1570ffc47b9a",
+        "9330fcdefa5e9153a7b6c406287d58ca7d7b92e0",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.touch1.html": [
-        "fca58c601213bae95a9c41e02f29125ec63ef333",
+        "3a13947d3c3c84bce067993d563f240525cb9dfb",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.touch2.html": [
-        "04e7198ef2cddd8e9bd60927412f60704fcd2cf5",
+        "ca6c1b7e1f4bd094cce67af83c3b7223851c7bd1",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.touch3.html": [
-        "7fc62985d75d29f96bfa8ed711f132d591c860eb",
+        "bd032a94de0740bd9b619acc66259a2b572f17d2",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.transform.1.html": [
-        "b4dadd6ecdc9b6590ed508497fc7aac4912ee818",
+        "505dd698294ffd3f20b4bed690c8eceaa6eccb44",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.transform.2.html": [
-        "aeda7ba07ae93d0c4d939ab8ddc500135de13716",
+        "d8d475fc5a5a46cb801b0043c266e430e1fbe37b",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.transform.3.html": [
-        "67be46c97cd79be3f4d1e28060e6904f144b1d38",
+        "ff27cb0cc8405d52a01204daf6c0622352c7ec83",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.animated.gif.html": [
-        "a24c2cb193fa85d40c6658670f045f20217029ea",
+        "9b975228eaaabf7277ecf9576b2a2d12f26f74bc",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.basic.canvas.html": [
-        "49a80726c6433a62104fa82c72b4584b9ed45195",
+        "f0e50d0df5fadeca68434f6dfd065feda6b3d6d4",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.basic.image.html": [
-        "8d723329ec687da5d6a2a5e8a4e9d53599cc7ec5",
+        "31999965d1ea7a101221c7693912f0e2c1517697",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.basic.nocontext.html": [
-        "34e358a9a5f7b009829070150c1fbbaad1755cfa",
+        "09e0a0474a120f4261fe51d718b5c7b3a42c4548",
         [
          null,
          {}
@@ -465450,7 +467066,7 @@
         ]
        ],
        "2d.pattern.crosscanvas.html": [
-        "f28542ff7113b0033e442f530a0f938eb7d7e4b4",
+        "cbda7d0a2dc618aea77df168f6b8b82b64c1f8df",
         [
          null,
          {}
@@ -465555,154 +467171,154 @@
         ]
        ],
        "2d.pattern.modify.canvas1.html": [
-        "7a09739176db6d09a113422c18712bb32f226d53",
+        "066b30a9b83a99dc5876e6b4f88b9edcdb2ac21b",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.modify.canvas2.html": [
-        "078e5e595c229e4fcda6544d9c11beb44abe0303",
+        "10f9c0ab18b08f16955303b6cd22ada2a05dba80",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.modify.image1.html": [
-        "36cb89df371cf353c4df8d5df8a8c144ee2459ff",
+        "5ac850a446dc8cfa99fd9b7480eee7fcc05ecb10",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.modify.image2.html": [
-        "69d7d482aac1b5e536ef02cf2992d47394caac3c",
+        "1c95aa0909bcf55dd5820d7aea3d934bb702f420",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.basic.html": [
-        "0febc57fa25e3cc9880063dbf5cf4e37f205d942",
+        "6b0fb8c3090da7dbf7a76ba6a589cf0fbdd21f0a",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.coord1.html": [
-        "98a363dbe85f454a34262ae71b76556f678085ef",
+        "1b1b9bb1b5803fe6afe974c58c0ffffb74d98d84",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.coord2.html": [
-        "c3eb012f86136e2a1ee104ffbffd06a25a6f6f6b",
+        "c483e4f64e2ef8b5b11ae35d3cba944c5fc1d9cc",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.coord3.html": [
-        "13fff6d0035136145e93b85d61d6c9495c555945",
+        "733f728ad6c0cc72f2c7850cf0baef4c0cfb9836",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.outside.html": [
-        "27cb51817c6a3b8aa8247725cc41145cd8b006b9",
+        "a7279943d474d5f20ff9a6ae90bad2efefc396da",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.orientation.canvas.html": [
-        "ab4040180b31663e868933eec4ad60df08467736",
+        "b45c95be1f82fcb7f4ffd418804b6205061db4e2",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.orientation.image.html": [
-        "4d069b797f7218753f0d856475c20979a40249c7",
+        "a618223b06043df2112afe79c683d838efea4209",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.basic.html": [
-        "dbc721150f5e1a01891a15315e5a34afc87e08f7",
+        "238f155b2aec9a8318843f04a64946c1212350b8",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.coord1.html": [
-        "11ae1c7520e6da9fe46bf78f0bb5aa3bb917f459",
+        "cfc270d379d2062d9181823ed5d51132b6ebf82d",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.coord2.html": [
-        "da165d1f5c25e7955de04a7d0aaface32c1d169a",
+        "b05feec9374365de956465f1c2151fc5e7aaf8fa",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.coord3.html": [
-        "dbb967666b0634608d3cc98ec54d46d528d7adf6",
+        "223d8c021554dd34e3c46abf5c8fa7200254d917",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.outside.html": [
-        "927cc7bf393c0b53f8ba50468626637929ac02f4",
+        "ca140400d8f098829a376111cf664e9960f6093d",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeatx.basic.html": [
-        "ccaab8dba11f1a4bf76a9e1d14890bf27609b91a",
+        "9f2f871c0b0743d9bcd99fb423ee2b629a400c74",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeatx.coord1.html": [
-        "9a882d97b6009cffd20de489bfe80b07909bfe19",
+        "38ad51b237c24fd3f8e923f3a28decf32fdc50c9",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeatx.outside.html": [
-        "9b26b98140e769e1697285f5434e2bd831db0aa2",
+        "ba01bf3092d3a61eb5c5a071673bdf2ff87c6d0a",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeaty.basic.html": [
-        "465cd73de80d92ab71444f969252b97c29c1614d",
+        "bb07aca80e153bf31f23b2bab15b862f0081ad4e",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeaty.coord1.html": [
-        "3e24bda0b24cd7b196a7bfee0234d3312773c8b1",
+        "c7ec99e720a6728e1b4ec1117b7bfaa66d23d0bd",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeaty.outside.html": [
-        "810596b86de03c6c8ca14471de95a3c79e4fa422",
+        "a3267d970177a1f61e8213a30db316a4d8923f43",
         [
          null,
          {}
@@ -465716,7 +467332,7 @@
         ]
        ],
        "2d.pattern.repeat.empty.html": [
-        "265cd77c347343323d3f2ed766c0f8507bb2e3c2",
+        "48db7da219a420139a2b558adec24352ec2b68da",
         [
          null,
          {}
@@ -465779,14 +467395,14 @@
         ]
        ],
        "2d.pattern.transform.identity.html": [
-        "56a44df86bd3564da34c09e445b73ff290f03870",
+        "775d360e1c00df827754b6db958db3fe33175aad",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.transform.infinity.html": [
-        "d298d70c3505a7b09b7b4a1f802555d30ab4b7e5",
+        "8650ed9a1d1a9393e8648995670b6d776e036f0d",
         [
          null,
          {}
@@ -465800,14 +467416,14 @@
         ]
        ],
        "2d.strokeStyle.colorObject.html": [
-        "24eae192acc4742a5d559063aafbff79efcb0866",
+        "a56a020abdaa4136ef01d4c8b0e3fe5f638a1dfb",
         [
          null,
          {}
         ]
        ],
        "2d.strokeStyle.colorObject.transparency.html": [
-        "1d14ace481b53d9399cbd45ac0808d53c9611608",
+        "1b19cab317a3f8c7c53c8e7b8392f38f043401b2",
         [
          null,
          {}
@@ -465830,42 +467446,42 @@
         ]
        ],
        "2d.filter.canvasFilterObject.colorMatrix.tentative.html": [
-        "71233a2d0047e716cc53bbfb146b77dbd08fa2e6",
+        "678a722520a98bb0039c3c0fb846c320fd943800",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html": [
-        "d622c135a0504f75ab268dab9c6d3059bf7a2ea8",
+        "0ecd132c8efa286b90f5a2777e1351c3204316d0",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html": [
-        "aea335bb4b29476e8c7fc9ce05dba3aa170ab8eb",
+        "4ef30c9249bb01fa1780f8ab07d677b087073ff2",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html": [
-        "666ac083e93fad38ccf5d37e5131743c0a0b27f4",
+        "3b3dfdb82ed5705208db6f248291a63886c5fdb8",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html": [
-        "dde65c16feae7f0de752032e33b9f3fc6f632cb1",
+        "c45f5586009150b862acd6b3398ca53350456baa",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.table.tentative.html": [
-        "66922fb00dc36a0e40b54f9d20b58124243e35cc",
+        "b561cb6fd3f0a8d293941bffada44c70416d266a",
         [
          null,
          {}
@@ -465902,14 +467518,14 @@
       },
       "line-styles": {
        "2d.line.cap.butt.html": [
-        "62ddcfc611e51c9750feea1d6526b911d039df8b",
+        "59b1f76c686c2eba0be332f446b70fad1d22dbeb",
         [
          null,
          {}
         ]
        ],
        "2d.line.cap.closed.html": [
-        "5e4d04c056c6f7b1ab6381a86cb5d0ee7028ddf1",
+        "5f16ac950058762a8e9da8521db191c56642eb29",
         [
          null,
          {}
@@ -465923,21 +467539,21 @@
         ]
        ],
        "2d.line.cap.open.html": [
-        "1efe2ded8eafa835f6782a82eeb76b590f139201",
+        "fc5aca585c5f3ba34d7349b5840f3f66fd667778",
         [
          null,
          {}
         ]
        ],
        "2d.line.cap.round.html": [
-        "efffb3c8c6822768a58e41f31c62f2f76d4d3714",
+        "48411812de05864bbc1e14989ede3971d1f339f9",
         [
          null,
          {}
         ]
        ],
        "2d.line.cap.square.html": [
-        "953ee92c064da42ce7ccf8074fe73c4e87e085cc",
+        "3423fa79e473bb648d44a3c18462738224ba6af9",
         [
          null,
          {}
@@ -465951,7 +467567,7 @@
         ]
        ],
        "2d.line.cross.html": [
-        "ea1174522456274b021c414d152973e4982c1969",
+        "a664e372534722f46986592463568a9252ad560f",
         [
          null,
          {}
@@ -465972,14 +467588,14 @@
         ]
        ],
        "2d.line.join.bevel.html": [
-        "210b08f62b6e8680ad182b6ba53946469482d099",
+        "c1320c2c0b364f96f68004f870d899102d6940d7",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.closed.html": [
-        "e230d9a09a5315528f75d0b6790504d8436fda97",
+        "6fd9d9d300badcd07c604d93f519f0f025770c50",
         [
          null,
          {}
@@ -465993,28 +467609,28 @@
         ]
        ],
        "2d.line.join.miter.html": [
-        "24c21567aec52e38880f9e211186b22d5085f2bc",
+        "b4f8fbc9a40e427c8d8f876cb46403e44b8bd5a0",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.open.html": [
-        "521a8a6cf7450daa9b33af382f221c6fe0517e5c",
+        "162b1f87b294da6d8a01d414dcf3f6be71464dd2",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.parallel.html": [
-        "828ff0cfe5d17e6f1100c1eaf315fa54abe77514",
+        "c26182b0b47ab09686cccd12f065ac47871c3682",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.round.html": [
-        "a20cee9f089d5a3e7a780a8dcaf62c88a3a9412d",
+        "f1e60182f3cdad6b8d70a5579becb3fcd69548f3",
         [
          null,
          {}
@@ -466028,14 +467644,14 @@
         ]
        ],
        "2d.line.miter.acute.html": [
-        "531276cbd1f2c955ea48abf84089b7d02a2f859f",
+        "7807d5942da915f6b979085e78d22459c351725c",
         [
          null,
          {}
         ]
        ],
        "2d.line.miter.exceeded.html": [
-        "a4a0fd23565b7a8be16ef7cee368908a6c259ec0",
+        "9c31cdd4ff6a59bad5b206119eb94086c989a0a6",
         [
          null,
          {}
@@ -466049,21 +467665,21 @@
         ]
        ],
        "2d.line.miter.lineedge.html": [
-        "1de599390f7b73fa8303dfb51da6087ed61fe1eb",
+        "33d96f36cc813a81c0730a7788e88b602572a059",
         [
          null,
          {}
         ]
        ],
        "2d.line.miter.obtuse.html": [
-        "c6b7619be9a237601fc67587591ea69e202ad0a5",
+        "73507f623c223f5a3b011a77906243cc0661744b",
         [
          null,
          {}
         ]
        ],
        "2d.line.miter.rightangle.html": [
-        "3100a6c3f928b33063eaab4251f356175693a2ea",
+        "a8b528bf056ea88f05490cf7844fa0f05b0720a1",
         [
          null,
          {}
@@ -466077,21 +467693,21 @@
         ]
        ],
        "2d.line.miter.within.html": [
-        "4a15782ab87f4941a1718d425c7e2073b8b623cb",
+        "c5d71cda57449925aec39682903692eed1c0c222",
         [
          null,
          {}
         ]
        ],
        "2d.line.union.html": [
-        "7d5fb787aea47b4ebd639c4ee9d5db35408c1ce7",
+        "e9f5a85e02a33c40c4d1a6525123afcda6d93541",
         [
          null,
          {}
         ]
        ],
        "2d.line.width.basic.html": [
-        "a0bdc4be9b6cab247fa284868cc597cc30ad36c1",
+        "b0fe6c466502daa5d028b4f59d2826b49d20135a",
         [
          null,
          {}
@@ -466105,14 +467721,14 @@
         ]
        ],
        "2d.line.width.scaledefault.html": [
-        "b009e110429fb47eee9b88bb2ed379433280ff3f",
+        "9c50a0d68e1d75e4d91c0ad60f59a658fed1c4df",
         [
          null,
          {}
         ]
        ],
        "2d.line.width.transformed.html": [
-        "f3f57a968a337880110c57750e2f9cd4bae12524",
+        "f42f859a31ee1ce18c173fdceee68ef6d0a4c7b3",
         [
          null,
          {}
@@ -466226,7 +467842,7 @@
        },
        "fill-and-stroke-styles": {
         "2d.fillStyle.parse.current.notrendered.html": [
-         "59eedb1cff4d29c4156b3a4594b80e464239da80",
+         "37701bacee146687f4afc2135872af731048dc1e",
          [
           null,
           {}
@@ -466244,7 +467860,7 @@
         "tentative": {
          "idl-conversions": {
           "canvas-filter-sequence-conversion.html": [
-           "7774f3aa4fa5d7e3448a6b938d79d2246b67b98f",
+           "8b1a5cdf60d9442812fce61b7d49efab69267a56",
            [
             null,
             {}
@@ -466292,14 +467908,14 @@
          ]
         ],
         "createImageBitmap-bounds.html": [
-         "9c4f1401e2d4078776a4e24b67e51a2db84d0d22",
+         "a2dcf0cc0b8207966cddd3dc0207d62a575a6726",
          [
           null,
           {}
          ]
         ],
         "createImageBitmap-colorSpaceConversion.html": [
-         "1efb8e7dc910ecc515bcd4bf7e5ca928c0d79f18",
+         "2ddf3648f5a34a8d1513d6d6b038d07bd5caae9c",
          [
           null,
           {}
@@ -466313,7 +467929,7 @@
          ]
         ],
         "createImageBitmap-drawImage.html": [
-         "e734820d116b772d03c9f5579f768ab1be99bcd1",
+         "5b5698813afeb1766f35b4652ae8d51c8af6c69a",
          [
           null,
           {}
@@ -466327,7 +467943,7 @@
          ]
         ],
         "createImageBitmap-flipY.html": [
-         "99d08d830075d86fb00ca57ea3e96ead7a50c236",
+         "32791b039c6a6392935bac9ebc1a3b3f3195fea7",
          [
           null,
           {}
@@ -466529,63 +468145,63 @@
       },
       "path-objects": {
        "2d.path.arc.angle.1.html": [
-        "a202700fa6c69399847a6e0b035f75e16d3d60dc",
+        "838492d182a845512df72cd61c83d6bdbe9f4446",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.2.html": [
-        "decff2b6276fb1a238f4772bf62c0f3e32e66c56",
+        "7ddcbcbe47749ca253a9aa8a3e1eb271555ee115",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.3.html": [
-        "feff59e3a700e14f9b4d08e688688a799403b8e1",
+        "f5df8a2bf2cf7d9238b60cf32c2aa5e76ba335eb",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.4.html": [
-        "5bfc531c1442038a8f41f9c940de04f99a549d2f",
+        "635112f76bc8d1ff468bab4a3ad426531672e4c9",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.5.html": [
-        "d5ef61d7637c46febd86082709f1e5530e8290da",
+        "59edd27bbeff7929ce8c60f8db64082590a6def9",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.6.html": [
-        "8d37b4453b1622fbc30ecf3a0d59cbe09cfd363b",
+        "83f960b60e2481d5b8db3e71c8550342bfe8c31a",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.default.html": [
-        "1f36d93162f785ae395708d56fa0096276bce442",
+        "51c1f1a8f809d2bd805bb6fa5cab53ce347dd803",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.empty.html": [
-        "76cf593217fd3adc4127fcb04c6259cfb2a9b532",
+        "bff802900152098db1802ddbb729840f58868525",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.end.html": [
-        "52836a2e428438ded5ef500e40a66c6f2f5da3de",
+        "aa26b65921874efe96806af26b1aa82d73855dae",
         [
          null,
          {}
@@ -466599,175 +468215,175 @@
         ]
        ],
        "2d.path.arc.nonempty.html": [
-        "5fd51cea921ef328378cf4e2299784fa8c139c2b",
+        "63a472ba9af24ffe24919f16628cb3dfce6556cf",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.nonfinite.html": [
-        "e70ecb2827d92d18653f42558fb1a6456fda8c15",
+        "04d51bffc0fb1386782bbe853ab922f29d4cc61a",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.scale.1.html": [
-        "9cb1e84ae453120dd8a1f0e748b534b02ed7ad01",
+        "c100c6476fa878ec3e7ae31cd1b0f783a6bcb07c",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.scale.2.html": [
-        "f81358ae944ed7774823d06dd2d9beb5f3eec05c",
+        "1045e4027693df6a18ded63ca5835579ae0b5516",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.selfintersect.1.html": [
-        "34d4a535135aa4f059bf2b9826abef6443ee11a8",
+        "c97c833ec1aea76c75fce66a40c81457918b2497",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.selfintersect.2.html": [
-        "006258890a1edcfec566f648d4de6bb39289d63b",
+        "58c51e32ec852a8146c8c588275b793da539b0b1",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.1.html": [
-        "c30fc669945f1c03a87b0bd6f6ccdb6bfb989939",
+        "29bf2cf6532a30a917a67715190f61fa3b9932ea",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.2.html": [
-        "c94242415d58869acd9f0c84d9d186d0ba03c7a4",
+        "aad3a51964566cc0a9400e069543383af772ee40",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.3.html": [
-        "f7181158e8b1fa55feca8e18bfca15552ec3c1a2",
+        "8f9e2735828cbf696205c5bf82cbba3083b340f7",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.4.html": [
-        "4ac95ad15dbe8592b088fd467774e7ecc7202711",
+        "4efa26369f9f1d234e02538def426085db10dbbf",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.5.html": [
-        "5e53c6f356c610a579c48096aeb89d2ddcff26ed",
+        "21727d4f4992b63a4b9056669e1e6cd26fca9619",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.twopie.1.html": [
-        "ed65638541ecd47e86c525bd92ebde6052ce9cbf",
+        "a07eb101bd8d29694e56bff9788b318e56c7aeda",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.twopie.2.html": [
-        "fc39ff06a5f937313ee3de7f415a45eeb0e70249",
+        "5ea0c1e60f044fefd859a1c5002093ba3ca52895",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.twopie.3.html": [
-        "505dc737a12b6779b51d2d90ab4a75ef3c37286c",
+        "8e1d50e002f7a343e04a642b7ccbc852bf40902c",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.twopie.4.html": [
-        "c49714ff6fd5f3b2fb98b02372639c09152c30de",
+        "914fc4b18d8e8d8468ba39d79fc0338cef0b2c91",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.zero.1.html": [
-        "f375b18439fe2084ca3c8b980f47d7af49c525d0",
+        "b648c869adc275af00d0dc8cdbcf07993d7ce603",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.zero.2.html": [
-        "45a96d4d9007cd204d831e3e1289cdf6e206b141",
+        "4aab17a7a5a0a9b48af2113462f66555fe914818",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.zeroradius.html": [
-        "33172cc54bca33a0b80b7bef607534469f88434d",
+        "6f50bb474f9cfe2c84e2b9597ab49eac29629451",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.coincide.1.html": [
-        "c3e719e20f3e8802b6e100e6357a20dbbcbe6681",
+        "9b963505ee2d0e22241b214be27b16e658ad0cd2",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.coincide.2.html": [
-        "49fe8e19b01e36e00ab53f573d44eaf65fa9e12f",
+        "4cabedd056a545dc86aca5678c2c0613a5dd3b17",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.collinear.1.html": [
-        "0bc58ff2b1dbcd2395ab8792e89eafa89ce95d05",
+        "393c7a7f67354acc225f5fe57a648da913edc1fb",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.collinear.2.html": [
-        "71a69d3fe67dfc4c73d1bfe191d54a06af0ac0b4",
+        "7dc386b518397761384e9f6640a9427c35e0eef2",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.collinear.3.html": [
-        "6c2e1b8bf2d794410dfd2b4cc76529a0260eed0c",
+        "76930e5fd1235e88d62a4356475a3fa7945c55c7",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.ensuresubpath.1.html": [
-        "8ec82e0ff467519c6edd2f23bef0e8b81122861f",
+        "756cfe602c7ab9709ec083683a2aed23111d7a9c",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.ensuresubpath.2.html": [
-        "fb8be3f4959dff4307a637a0b8e1bcdcea330a70",
+        "18b1992d89db2e7672e17ee874c958f89deabc4d",
         [
          null,
          {}
@@ -466781,182 +468397,182 @@
         ]
        ],
        "2d.path.arcTo.nonfinite.html": [
-        "fe2bc69db86e49e625c921c49dfc6f3ebc2b5f13",
+        "d05e05d278147b4a40aa35f9a7530c9846fb89ce",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.scale.html": [
-        "ccbdde9f4a580d2cfb89c2679af169d7f20a2d39",
+        "00d9f99b96a3731768dfbd365c802a85f7ee75ad",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.shape.curve1.html": [
-        "7d52f3c9f09fa9cdc4ad51c9224a6bf991e80a59",
+        "0caf25048d345fdc3257eadeca7ae16574478062",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.shape.curve2.html": [
-        "b0ffa46e6f4c073aecd7cc72e15244b49308b79c",
+        "3e1677bec01ece8796be72c7ba9ce3159823f1cc",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.shape.end.html": [
-        "59685ae6f6473d636eb8ae980afbfe5b5c431944",
+        "8a41dcd7b61c09af7c5730afb0f06939f8d7bf98",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.shape.start.html": [
-        "c5755ddd4666ea258cf87d2434308aaf54280818",
+        "1ee229ef327cb95c2cc8dea772ee0fe98518a746",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.transformation.html": [
-        "1417e073c2a6af7e933e5a0c0c43223f876ff17f",
+        "32811f2300530ddd032dd0c25e6703e0c143fea4",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.zero.1.html": [
-        "a2a8a8bdc87a393014800593ea6db3cf0c2daa5d",
+        "4bacbf0dbce7237695844eee3e51584775b4e804",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.zero.2.html": [
-        "a0db92a8e5e85bf041952f79def913a9d5df7a75",
+        "1f26b5942b2fbde6a4f12970a6bd38711f2599fd",
         [
          null,
          {}
         ]
        ],
        "2d.path.beginPath.html": [
-        "8140ac73ad96b80c39c8395d6efcf533d9386198",
+        "a21282cc3e55d376cff1f653467af553a532018f",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.basic.html": [
-        "e3285291e6e37c5dcf77c44a9e8671a36157bb5d",
+        "7f90f7bde4698ad415fe32d51ab82a58c4950ebc",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.ensuresubpath.1.html": [
-        "caece38fa8c95997fc44f0cec2cba73a47f029fa",
+        "1e6f8298c5ac2d7c4974bd02c4e06c6fb8e0e127",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.ensuresubpath.2.html": [
-        "cf2bd5deff6077660a273caa0189c27f3276b1e1",
+        "875601c5dabd8bc04ffeaaf357cc6e89f38ea7ae",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.nonfinite.html": [
-        "05df77ab0805902238c6d55408152e5e1b410d42",
+        "e6da7b2726736d733abf2c65353056865a3a79f5",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.scaled.html": [
-        "6bff2a01da5902c1888ece308e69aed2f77745c9",
+        "d24b83786fc350dc01d428c12f0e3f714aa0e8eb",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.shape.html": [
-        "c6d6c310ff9508fcb6db9b74387203a64be95a32",
+        "7ebe1e3460c64f8bc9d51345490fc098270d614d",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.basic.1.html": [
-        "b347387b0d7b7fe1ef406e0ff2bcb6568a0d77f2",
+        "c49afd431ff7cd5902985ed51e7e612925c36b45",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.basic.2.html": [
-        "908fc8a7b1b59dc2563617f15467ce18913bcfba",
+        "dfba3b8164a2adcca837d2b317c8bc8ed44c8dde",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.empty.html": [
-        "6b5862c0308c640cf8c796802066f8b222d55354",
+        "ba7a869f5cdc858e6ca5d96dd16ec8271096f751",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.intersect.html": [
-        "c171822595f27de88390e48680db20f506dd6efe",
+        "1cdd9603d79eef2d1c18a298095655f1ab98f622",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.unaffected.html": [
-        "b4c09f6d5a2e5613633308e1a7c90a86cceb0b50",
+        "893877f876d2f4efdc5ec40b6c02cbc0dd68f906",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.winding.1.html": [
-        "3a70bddde5658cb24e06c043df125e6c668c0d5a",
+        "5e8fa814243901a67cde7889c4e50ae03b49834e",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.winding.2.html": [
-        "f296ee4593e04509a4fc8dba43652a4cad2639ef",
+        "ae8fd4c4d94576e3e5c5e3a9cfb3a903d7072e57",
         [
          null,
          {}
         ]
        ],
        "2d.path.closePath.empty.html": [
-        "a6a5f14ed4333925994d1aa072ff02c96f4ece51",
+        "e9840f195a3e78430abce062b73ee4b3497f35e0",
         [
          null,
          {}
         ]
        ],
        "2d.path.closePath.newline.html": [
-        "c12e5f084d31c23ba464fa19ccc554aa63a2357e",
+        "2ad2609e1aec28c1e8855f7f66c936c1b1140eb3",
         [
          null,
          {}
         ]
        ],
        "2d.path.closePath.nextpoint.html": [
-        "3ac3b099eea2da97374003c8c3a5126bcffe8da0",
+        "7538af29f3033658274fb16472c150d0bb98c1af",
         [
          null,
          {}
@@ -466970,56 +468586,56 @@
         ]
        ],
        "2d.path.fill.closed.basic.html": [
-        "33a96df92c9498616dccabdd9fc4c7c16943ef07",
+        "890c15cf4b29310c019f07e4e97049950e842a25",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.closed.unaffected.html": [
-        "acda47373aa49e6d11d9fa28aae6514f0aaa7c9b",
+        "bd42e95181f743e5ee17779acb301fb9c5fafd62",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.overlap.html": [
-        "fbe0f03f357776141f2c67857738f7baf3f8694b",
+        "eb50ac6846bfee3394ea2de2b239c327360b27d6",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.winding.add.html": [
-        "bac163ff9f988bc9ca71ee2cb0443d3a3584fbe2",
+        "5fbcd65260170528099fa6aed30cafb39e0837c7",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.winding.subtract.1.html": [
-        "4980616f389b40493bfe5581b888487c40c3f61d",
+        "963e5d3c75d5cb627dc7477bf235e5a95e3d9e54",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.winding.subtract.2.html": [
-        "6429ff68a59c6cea943fa9ce265342e73072ba52",
+        "305d628b9e56b2f188e7f2602e17f855b9edd8bb",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.winding.subtract.3.html": [
-        "97dadad7036ea3e3e2089125b0ca802d4fbc97d5",
+        "4bda1bd248f32c3c5f3d7ee0cb4949a7647240ca",
         [
          null,
          {}
         ]
        ],
        "2d.path.initial.html": [
-        "fa700b36822144ffcbd726d133dd505caa047ad9",
+        "ec17cc330aa55db43ae7982239ed5ede8c611023",
         [
          null,
          {}
@@ -467166,28 +468782,28 @@
         ]
        ],
        "2d.path.lineTo.basic.html": [
-        "317baf93a1dd5b80b8f54c915585f85aecc63bfa",
+        "4a2cca3a3affa9922656b33a5cee7436a79de139",
         [
          null,
          {}
         ]
        ],
        "2d.path.lineTo.ensuresubpath.1.html": [
-        "9e2f0cf4e93c6f1692178d5e3b13c9edb6f78aa1",
+        "0fa8f1c0549101dc57eef4e90aef3910806d80a0",
         [
          null,
          {}
         ]
        ],
        "2d.path.lineTo.ensuresubpath.2.html": [
-        "b24ebb04111c272a0b13e71767f22071949df867",
+        "e5b2aa335c24e057a05d5cf60352b2b9b4b9054c",
         [
          null,
          {}
         ]
        ],
        "2d.path.lineTo.nextpoint.html": [
-        "0e8147d2bddb31959d2c27004f29829a9e22c075",
+        "54b586176de9f623e858f91ed1d3d0f7449d0879",
         [
          null,
          {}
@@ -467201,413 +468817,413 @@
         ]
        ],
        "2d.path.lineTo.nonfinite.html": [
-        "df0bf367f11e555e1850381b8cd2cb1ebf537b2d",
+        "fa3acf53851985da11df88e314a7642519c349c5",
         [
          null,
          {}
         ]
        ],
        "2d.path.moveTo.basic.html": [
-        "cacbfab39f3c22fa84eaa8f1c2be6a022593538c",
+        "3ab41dc039920345ab4639d057ed3b9005c76142",
         [
          null,
          {}
         ]
        ],
        "2d.path.moveTo.multiple.html": [
-        "0a364e425cf62c45cd7d46dcb128de2a0c0f4f10",
+        "24307b4e9ed56676cff8c7c014662a9f50d2b786",
         [
          null,
          {}
         ]
        ],
        "2d.path.moveTo.newsubpath.html": [
-        "8830f89a9c299d4ed65754c22c8fd3cf1215e21e",
+        "456b7538ace7dec8e0b78c7c82eae394d2b486ac",
         [
          null,
          {}
         ]
        ],
        "2d.path.moveTo.nonfinite.html": [
-        "617e3cdfb734ec335ee07990c2493e5e70949c66",
+        "4f61d9e58b9c59b0ce8930ede43169e7e72a5272",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.basic.html": [
-        "8f9d2875bf26a76a2fe3b00f5590edaf87a0b59d",
+        "1c2da33f9673517f85422fc938846b3bbee2e632",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.ensuresubpath.1.html": [
-        "81a18d061dd65c29d0cefa5e97a4f0cf62388805",
+        "6c75732dacafabec8d81f2493db81d7d1ee01b5d",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.ensuresubpath.2.html": [
-        "f66c0d85c92c5ddd7000e21ca2d41bb42c324c71",
+        "8da6964cc2fad05bc12572a37133633a51a45cd2",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.nonfinite.html": [
-        "253d39bc5e85618ebed0067879e8f3a90528a028",
+        "4bc7107fca2718781ba4e30b911835c8d539ba69",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.scaled.html": [
-        "ebd7668e315b363ba4f3b3a2359e1ce04b7143aa",
+        "4b6ffaa741b42809281a9e3e5b8dc918fe8979d6",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.shape.html": [
-        "e0a7e9bdbe22ea91896e67f96c716b51f05fc785",
+        "58d35dc22f266696d65cd6816282fd7b6e9d3e70",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.basic.html": [
-        "3799fee8778094ecca22a6168f72a30aac7be009",
+        "296800decd521871d675dc5e9c3950b41df5c8b9",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.closed.html": [
-        "2aaf5aeec19751f6fe9fa7cc489a4dc047ff50b1",
+        "60a237770fa3ea7208ea122a845bd0ff66a6de04",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.end.1.html": [
-        "2893931509e49360b784b32431be5be280e057ef",
+        "6f3338b84114879325d5775e863f32541806468a",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.end.2.html": [
-        "2145d0e4ca3b84ab5813e1f9e0df7a5a70cf78dd",
+        "e5a1776dd64e13a8bdc30b017ac6786a3468eb31",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.negative.html": [
-        "3b30ef00375e1f0b9c9cdf27c1383039a9cb040b",
+        "e7e51371e164ece9089eccf5d7e05c2723269e1e",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.newsubpath.html": [
-        "2e610e44b51b99cffd4e79ef0db2453615881923",
+        "e2c5a4cff83673f4c0ee908f05b308ea2abd8104",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.nonfinite.html": [
-        "22891bb4ca705819f5f5397953d794235d2b74fe",
+        "b8517e8fa4dca487159939f95a4bb321b322d85f",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.selfintersect.html": [
-        "c02c5523827d44c787e3c426c63b02bddf5a4dec",
+        "e7c73dfaffbd449fec3708e7dfda7b8dcd8b56b3",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.winding.html": [
-        "942bf1da50b6a0f63f21fbeb5aa4692dd666ac2e",
+        "c9547fe32aae0b69152fa1124932d7a3ec99d335",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.1.html": [
-        "f8d45cdd131fb726377909e6ca5bd766a4d0cbde",
+        "9a210e74414751d8e2605aaac7f8ca722dad4c0a",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.2.html": [
-        "f5250b54f30a1e9111439ffc7029230fb17703d9",
+        "0e3a7c87d66d486127453599695f4d3e7ac1d3ea",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.3.html": [
-        "6d7879debccc8a7a459d98c2fb3107744d67249c",
+        "e92b121f312528300851fa10d8120b37cfc72c44",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.4.html": [
-        "cf813aef36fdd600a3e7902b90792c0133bb9135",
+        "086ef94f29210ccf9109de8ec081b430ff5f7b96",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.5.html": [
-        "f8643aeeea22af73d60bae88b517fb07e41b1403",
+        "880cab561409cfa3a70b800b2cfe0f1ff2009153",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.6.html": [
-        "b3ded772c83b9347dc9f1095f578357cfc9c5851",
+        "34c9d15cfede26225a53676e3e15f8a3d000e7b8",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.dompoint.html": [
-        "ad7168a793c82e84ca8e75e69443044c94b1be23",
+        "bdcf60d44ccdd14410da530108535806a354b93f",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.dompoint.single argument.html": [
-        "5fc1425dec04e69bcddfd6599da4fd21836b5b4c",
+        "6e13276c987d1e6cee90d64e3f0b686372666285",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.dompointinit.html": [
-        "7ca4dd7265a4d16fa8fab35359352a7e31508068",
+        "6186d98eafa5db93fa1cda6ccfb7c13a9b8752e2",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.dompointinit.single.argument.html": [
-        "17f4946a9b075d50e9d3948907098af41cbdfe8b",
+        "7bf91ffe35c088849d954828d7d8bbc77f198abd",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.double.html": [
-        "0703e9f10b3e8ae30afe5380218b47f6401331cf",
+        "250bf7d6ab545046864641e9a20e185af922de48",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.double.single.argument.html": [
-        "c097ac9b506086d426b4e2c8682e1c26b1759e84",
+        "e5e953de74bb9e1931988841c49789cb3d23ef8f",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.1.dompoint.html": [
-        "e74e0f1eabe48ae8416ad7f6b63af3ed7b4ae28c",
+        "699603b4fdb93dbd96d57c9206720e0c7321c6d2",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.1.dompointinit.html": [
-        "37eb89dcf76428bbc6242f29dfe33b700211bc9d",
+        "55c06ca2ebb81c71a7fd459d0372e59a27525de1",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.1.double.html": [
-        "f35ec3246dc6df32ea637ab9d80fb605078c47a6",
+        "1d38197baff9dc1efd99f1ac9f267265512d36ad",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.2.dompoint.html": [
-        "6aebe1b9f7509c0fe391d06aaa02258666231b72",
+        "701109d4f2e61cef64625cad2acade509d359773",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.2.dompointinit.html": [
-        "7f672555008d90c636fc62a05e612301dc93a3b0",
+        "409d5014c3175a9247f444d9c576748d9d8428f1",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.2.double.html": [
-        "9ae82104c98ba88c5976fa25a006bd180ef6f862",
+        "a0c458f006d80abcf5db3cd555d45f1af3429e1f",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.1.dompoint.html": [
-        "3402094027df987ecf273cb0f5c8ca29ef3ee244",
+        "ac4a3ddd89417a3f2941b113e937156cc36ad765",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.1.dompointinit.html": [
-        "11709a1df8907b628c9ea0d59dd986a3d2a0bb4c",
+        "bdfba5df41986c45cf4a28589e8c7857c8dd0b60",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.1.double.html": [
-        "197a8add86a75db42d10ab6c6053fa7768382847",
+        "3e8931e7fc00d07dc1017ca4ae6639cae6151aaf",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.2.dompoint.html": [
-        "1a4b9c4ba9c5aa0744f9fbae6b920a313edaaacb",
+        "7546120a6992f1adb5695f66cff981d0cab009ff",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.2.dompointinit.html": [
-        "72e753305999132a9636da41783ed0a84296877a",
+        "d8c805c28b6933371660a0a507e5a1c8339e2c16",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.2.double.html": [
-        "74df39e99170e23d0771ea723f1524b66b37a245",
+        "c3d722bac4e41525fa6a9d52a1192712c1fb7c81",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.3.dompoint.html": [
-        "5b16dcd9b88caba986d8b7d80cfc53e901c6b997",
+        "1d61ce570594205aa7b1f49834c39d6d2e29b027",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.3.dompointinit.html": [
-        "eec602ea453ac0544436967146c190eca117e3c5",
+        "f1714a84e322c849a03cee70aa796f3cc95c591c",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.3.double.html": [
-        "af7d760faba33bcdf26ff7e1e2dad91f46d3967c",
+        "f3f5721a729f07c5348fc5e925c7a90aa74ee392",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.1.dompoint.html": [
-        "9a4c3975326af2b4fac43f6152ba438e1da0e682",
+        "4ecff46aeec9960045585e4cfa61cdf8ac7f5712",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.1.dompointinit.html": [
-        "72b9ecc7b5136891e6dfdd3c9525168840d4d43d",
+        "e5b1feed32f08d54a11e17f5581de746bb79a6f2",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.1.double.html": [
-        "059f49f0c1b91070dc493a00dfea95c28ec73149",
+        "7c22f2457cb3d8004852d55209bb024a33fd7953",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.2.dompoint.html": [
-        "50b64d51c110b7f7a1cdaca68b816576ed99ed3c",
+        "f897a721cf7e02509aeee773f78c749d13abc935",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.2.dompointinit.html": [
-        "a58a8461c51338376796b8ab01b66286410e9e39",
+        "826befa02a57063851805ccaefaf9bb65f38d838",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.2.double.html": [
-        "0ffbbfe2b0458ca6c190c551168d1d9709a50edf",
+        "a0db8fa25e374a005501c9d63a3a780afa66ac4d",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.3.dompoint.html": [
-        "2452564e9e7e6d849b07bf90e53012404a5593dc",
+        "ac4f0795c68cc771221832dcdd59e884223de972",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.3.dompointinit.html": [
-        "f58de8e49bed2a2215ccdf3a5a2727931cc5c89b",
+        "b902fb9fce29fc7d1a9259a521d255c6b2e84ec9",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.3.double.html": [
-        "3d6225289d2c0e55b53ecb1fc86d4eab75bd161e",
+        "d69e2da221d3f4785b46611b581bc3cc9c15774c",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.4.dompoint.html": [
-        "99c9aa3dada09f0de2a2daee6e031b3025ed4127",
+        "f660fdaa6485fb1d9ed620cb5d5163fdcc77a9cd",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.4.dompointinit.html": [
-        "59291121aa79c47c3d223af3ae61ed23378a4277",
+        "0764d3e0014a761c23d4e72ed852fb50a65ff164",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.4.double.html": [
-        "7e2addf116d80c2b7f45b7e0d9aaecfca1bd45c0",
+        "7a2cd952e6087ba8a18dc0f3bd3e0d27c8b16cf6",
         [
          null,
          {}
@@ -467621,70 +469237,70 @@
         ]
        ],
        "2d.path.roundrect.closed.html": [
-        "780323cfed15ed81c1a0496a484706e4ef248e56",
+        "40756e5d941c3bfb183135ad914f02e394614565",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.end.1.html": [
-        "03ed7f31e2659cd37a98e23c9adbe8e98624a095",
+        "10ab8c1fb8320192810fefa34ca3eda0561d37df",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.end.2.html": [
-        "1ed59f2a4980cb1665a0ae057b3ab0548c3d6b4c",
+        "3b95d1ca88e95818cd2f28a815f2396991b62559",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.end.3.html": [
-        "f42177b4e4c89bc9ae85854547a825813839d027",
+        "48fc4988aa8db76b680fb7b0cf88b9813141b3de",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.end.4.html": [
-        "a2c59b35095163b3d8d9e9a5540cee0d92a5426b",
+        "4b70fbc344a736c3ca6bf1127f1698182ccda619",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.negative.html": [
-        "4327046c382f39dc8b3c9a51750d2f69b95401b1",
+        "81ffe8c93e4cdfb5d97a99fda527e030f1470b06",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.newsubpath.html": [
-        "8ec9a5f14cdf5336575694321966979cdad79322",
+        "892ef6e5f195331059532e707a3b7820218a355d",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.nonfinite.html": [
-        "91c1abf353a16597e68e1abf9c996eb1c0d2f8b5",
+        "a047b73177f7ae9b5fd18993c1c19d35e8c65b57",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.radius.intersecting.1.html": [
-        "fa6be6a13cc01a1c239b388b289ee41e3c2efdbf",
+        "e7675ba35c35ce108814eec2fc7eadb063a39b7e",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.radius.intersecting.2.html": [
-        "30f064c70477d3c5d0973df63de095a4df9c0530",
+        "48140ca60ed47ed22704a3b41d57bb1adb2065c3",
         [
          null,
          {}
@@ -467698,14 +469314,14 @@
         ]
        ],
        "2d.path.roundrect.radius.noargument.html": [
-        "7e5f387014d39bb1056f4530211a38cfe35721b6",
+        "e45b20b7a0762b20c8f423efb5eee16fe3df0488",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.radius.noarugment.html": [
-        "8b1840e02836e054b05791adf7a156663071b24e",
+        "08f576b3792559e2c947be4b4b5f423eba1cc4cf",
         [
          null,
          {}
@@ -467726,168 +469342,168 @@
         ]
        ],
        "2d.path.roundrect.selfintersect.html": [
-        "4b2c7d7c837d0fa030eca1c992f21451741f01fa",
+        "d644d66e7ca6e4014ed7c140a0058fab319f87ba",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.winding.html": [
-        "53eb5863a10e4389344376d4fc7376b7c6ec1bf3",
+        "6bcad2c9642c9737c801e4555110c688ab4eb103",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.1.html": [
-        "cd1c4746d8e8b79fe779864224aa1323f410ad7a",
+        "690087f0aa0ef4ff9b6fb74512ab46441a81ca0d",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.2.html": [
-        "d2ed1a7134561fa8102bf2c4508fa81d266696bd",
+        "cfeb923299a2aa67cc86a4eb3e4261e8b9c125c6",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.3.html": [
-        "e756672fe97b99a011251269d80349e89d81f3cf",
+        "39151f38c76276cefd116b198c85fe8d3e2e7127",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.4.html": [
-        "9258a680f8945fa92ef9e34a10d55b10e657b6e3",
+        "20dccbeaa0b68eecbafbe71f8a09237accc517f0",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.5.html": [
-        "2bcaf4ddba12339d7d9ddd31460b08f1aebb6625",
+        "bcb84a591710530d85bfdc5ee9576570d927bd81",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.6.html": [
-        "abc43f7851d3e8e86f8fb6681be850f48e681354",
+        "829503767dc9b88022f0509d00f64ff6f2ad4cc0",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.empty.html": [
-        "4c2991c7bd8dd26bfd05522413cacc89ff8ba4ae",
+        "5a2a91bd0fe8ab6de13837c6f3ceb5b6030a02b0",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.overlap.html": [
-        "2747bf73e978c2ab91154784588e894bed54a797",
+        "c1b425d18c7a7fd5a239cb26ff11499e09054bac",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.arc.html": [
-        "1757270fb33078552909cdcba379d7eb354dbe5b",
+        "abef923f6a6db5638ffec013cdcfd6262a01727a",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.closed.html": [
-        "bfae13e1b9c48c7e8ebd2a48e54f65d35b2cac55",
+        "4515669bc8e536670d7ece6bee7af68a8d63ae82",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.corner.html": [
-        "d7589116e3bb41a9eaccf638dcaedaad8415d845",
+        "532c74659500dc2758eec6caa4d4693ad94e2d4e",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.curve.html": [
-        "6e7a9a47db348d94ad12fee3c60be26c6a5f46c7",
+        "6055d8b3f4c46aba63804aa52d0ee7efc4146ee8",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.line.html": [
-        "06a3e1da4a16969b6721f4edfddc1e7d3fbabf4e",
+        "2d8dcbe49954e6fe3ae2fa187a81b0c967680f31",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.rect.html": [
-        "6044ee332004e8f1bbbfdd4d133b6babd4e33906",
+        "28b02ca3255633527496f838e9ffa21e40134431",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.scale1.html": [
-        "dcb21daf7f33b36943542ac1022073aeb60982c4",
+        "29ccc6613dace91eeff0848315b2a6fd0579f1bd",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.scale2.html": [
-        "0920d8f1bbbe5c66ba6ec8fd5309ae304cdf9d48",
+        "bc72c5c140f80bf8382f2627074110da4f6e2222",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.skew.html": [
-        "26f16f7cc5860ad2d3f6a9f9fbd6a9a9ef69face",
+        "b902a1dc2754c0fd1bffc3f53d5bdd8f6f67a8dd",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.unaffected.html": [
-        "7bdd3bbec02d87d1b1b5c8fb400e316059f3ff1e",
+        "9b05a6aa0dbb9e62eec3230c4deaecf6562e8fd0",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.union.html": [
-        "a4b1091770d6a91a20beaad179feac1c7ce881f3",
+        "daa8da9349378e75078b432212a3b35af20a0f9e",
         [
          null,
          {}
         ]
        ],
        "2d.path.transformation.basic.html": [
-        "d19c507cc84be943ed70ca8d97d858a3130169c6",
+        "d77b66a68fc9624becca5cf7e2757a2cbf0662da",
         [
          null,
          {}
         ]
        ],
        "2d.path.transformation.changing.html": [
-        "c02d6925d7ec6157d79dd7ece1a4ba067519c76c",
+        "5f79285a81dd413673df7dff5c7457f9f99a3b20",
         [
          null,
          {}
         ]
        ],
        "2d.path.transformation.multiple.html": [
-        "1c9fa3e7b083cd553561833f20128316d61cea84",
+        "aafa11c127b6ff4385510ada8fcd1f95d6558a87",
         [
          null,
          {}
@@ -468127,7 +469743,7 @@
         ]
        ],
        "2d.imageData.get.unaffected.html": [
-        "a77992f5d2cd3c2c17d0ada46ad83ee8440c7a0a",
+        "15ad997d5f1bc41181cd4a5066dd1fa91508cc60",
         [
          null,
          {}
@@ -468232,77 +469848,77 @@
         ]
        ],
        "2d.imageData.put.alpha.html": [
-        "cce73c80180cf4e474b5f60c86c7d51e596ad7f3",
+        "ae8ad977766d3bcf66f5b218bc2cbd2fc582f278",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.basic.html": [
-        "061ea97a2f1c0de0f1f1b8eadb51731741e8e97d",
+        "9a7021fd56a6885010058748d13a1fed91b5ca37",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.clip.html": [
-        "b476ea81d73123218548eb1ba984cae92b7c3419",
+        "229b8129563def3299a3889334c9d4ee60e2d982",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.created.html": [
-        "b6e1512bfde49e3a72acefb8e400d6f379038003",
+        "3f515b2523ef68173fbf27e700efa7c82b745982",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.cross.html": [
-        "f9166ffbf48d2fad780ec9a87385e41553c2043e",
+        "282ad03e6d5e9419763c56baed4b2236e365dde2",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.negative.html": [
-        "b07334beacc8ff317301143d86d3865dbeac50a1",
+        "81226e6978f43b42d4b60498e2d0879ddfd0a545",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.outside.html": [
-        "bed261b7480018481b2d60164e4f4b2591f2a51e",
+        "8750c332d60b1d52a1fd7856d34b81c46d39a1f0",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.rect1.html": [
-        "6871666ffd4c623cc695a87fed71a4ec6dbee72a",
+        "104896d20173c1f75e76d89d9739170c6c06e6ce",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.rect2.html": [
-        "c59a89c742b678a7728a903e8e992582c08e1527",
+        "7acb2205a357368741f456c14f230cc68861e1c9",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.zero.html": [
-        "d6e2101a238495f6e3879effa151c2ad03411c80",
+        "336e02a35a2688e20d408170a89081c625d6b07b",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.modified.html": [
-        "96d55315033ba2a8fb68832ecf23f7b50c5f2df2",
+        "f5f085a0010e95ccd17e8483d4ce3afb80dc638f",
         [
          null,
          {}
@@ -468323,14 +469939,14 @@
         ]
        ],
        "2d.imageData.put.path.html": [
-        "1406e5057cef6e51f643e7daa72b606703ab408b",
+        "b81054d2281186da5a89241a7b6a067ba42dabb0",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.unaffected.html": [
-        "ca45c0a3d5caac767b8e6d7079374b291492aa10",
+        "345cb5cbc71fb1cc10e0b89456d651adbb031d25",
         [
          null,
          {}
@@ -468353,7 +469969,7 @@
       },
       "reset": {
        "2d.reset.basic.html": [
-        "c6fe6333b715e761f648c16b54186a46a9ec9afa",
+        "8f63730851df9173343188dc60bd18a3445f5e14",
         [
          null,
          {}
@@ -468392,35 +470008,35 @@
       },
       "shadows": {
        "2d.shadow.alpha.1.html": [
-        "fe875fcac7a5fab41d5650fef478a48e197a92f2",
+        "38d3bd74eeb299971d367eb9e05aca88af86056b",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.alpha.2.html": [
-        "ab0e2bbc330d45328273e72ac6cd40f8466a72c7",
+        "ae813036b8c573d7e89c8499dd7237dbd9482d7c",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.alpha.3.html": [
-        "c0037cf5a58d93455fdd186062bcf397d5807b3b",
+        "42cabad36a059d98787f9e613ef721922630f70f",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.alpha.4.html": [
-        "a4ab327eb2afc20613208822238c8829a80f4c73",
+        "96af9df0faab0c3c582edd0819bc4e82fde7627e",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.alpha.5.html": [
-        "8f4c71c33142314a7d3523d8e14b4e3ffb844787",
+        "2f0b6838d8091408659925f78f725b01e8b02c5a",
         [
          null,
          {}
@@ -468490,294 +470106,294 @@
         ]
        ],
        "2d.shadow.canvas.alpha.html": [
-        "331ddd98dfe08716c1d9f641988a47299efeb9ff",
+        "5ad64e16fdf035f812714033118864768a3791da",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.canvas.basic.html": [
-        "b6a92107a8d2c73ed6380092c7bcf4c985ea9310",
+        "fd70884d02d0e063b6dfc7de96943ab7f9a65046",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.canvas.transparent.1.html": [
-        "3b7dabc9a9d7baa39030f34bf82f5d950e8a6c8c",
+        "f18b7d7189ed279c029429a823794edc892f6b3c",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.canvas.transparent.2.html": [
-        "6d7f34fbfd14c47cca3915b382408ef9e3093f23",
+        "c9590543ea377f5de17ec1d6cbda6738f77f67b1",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.clip.1.html": [
-        "880c26558dea842b7880fcb38c032e760dfed3f0",
+        "f952096bbd67e13f3ab179dc2544515ff3d0400f",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.clip.2.html": [
-        "823352dd209ab652353bda3523ea825219444d3c",
+        "22208c5ad33947ddc7b89fed9c9d3ea3d7539a4d",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.clip.3.html": [
-        "104a51e9ca626fc57174c029cfd34245e1322d72",
+        "5af9b012adc09dc2c3aa4ea4688f7e0ccdb99e63",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.composite.1.html": [
-        "8f32cf9bd0c6ff467511b52341d38d7d4d41822f",
+        "28a82e65868e78beb8f93194643402304c09cc14",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.composite.2.html": [
-        "1b693a923d4366a3b5c2742936749017afc5e110",
+        "aeb6dc1053d272581f2a82b6730f01504dc42cc4",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.composite.3.html": [
-        "05c8e8f950e5e350e3bb040228a00113f690d931",
+        "9a0c02e110f96d5c261354fe1bc140e49784ba00",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.blur.html": [
-        "bb59ad4b6388b6ebfb3d9057b4e413744707c590",
+        "ffe70f1c38552995102863c8c387b096f982c8e0",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.off.1.html": [
-        "25438b9aa6d75d991c494ff43562d808f9f3eb2e",
+        "e3adc9ae896006670d267ece05668c8ea6df2740",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.off.2.html": [
-        "52528ae05b20093d8ddae32982471aed15b318b6",
+        "8dd3fc32d787b877238be30cef711d6ffb5e57f6",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.x.html": [
-        "9e3bc404800e8ecfb669be30c17b2fb6f17bdd6d",
+        "54fa86e11547dbb428063e1f0cf955d78af36d53",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.y.html": [
-        "810891116b8c0bf155c92a3c540b7fbda0de3734",
+        "7295d578be32ad37c3c48dbdaa07f65ca913ba39",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.gradient.alpha.html": [
-        "f864bb37af442dbf9c4ecaaf70e87dcf723a1bd7",
+        "7ae83ebe9af9cc3308b3eda3d15ec2fadc26a3aa",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.gradient.basic.html": [
-        "1ee39b112652124dd4c3b4f62b74a6a948dfb9b5",
+        "233770e0d00a0004a31fd59ad2d6384fb6dfcad0",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.gradient.transparent.1.html": [
-        "bd542c9c0efcfe1e187d48fb511c612ce7d69a41",
+        "2427c7f59d5e170e3b4c2c001f2e2f382fa5e2fd",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.gradient.transparent.2.html": [
-        "2fbec52b49ad0dc9d4eb8c2c7cddf470449006f0",
+        "e27b19cc0af02c91633de22e241ce3bd5c3cd0fb",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.alpha.html": [
-        "3b6bf2c31e02d3631c7ac54240e813a9494ebe3a",
+        "2c8133f6309525c96eaace32d1b272f8292503f2",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.basic.html": [
-        "f424c29b63a335b82514f8d4717da683a7e44de7",
+        "f91b195e4c041ad4ccbc22ed6dd13503a2a2018d",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.scale.html": [
-        "9e41f76ac1b1bd2ce47fac5ad5c5a1178ad03d15",
+        "c0edc313739b8981f3201825ddb49200497b84c6",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.section.html": [
-        "d1bce82099c87b826b5e5cd7ca6bd4d64fc8a068",
+        "2ff2bf2a2449d85f399a7244fdf70677adcf363a",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.transparent.1.html": [
-        "d04561fa852a76d2d82f8d0f2dd4ddaa06134ca3",
+        "c152dc2962b986d39683a78e4f983a0852e50af3",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.transparent.2.html": [
-        "fed2d2a8f30f49233dec2fb648e34b7199abe115",
+        "636c72d9d6bed11b0d197a52f71e949dd1d1b44d",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.offset.negativeX.html": [
-        "9fbf9eed074c81f006d7e36d8650825549251300",
+        "828fe89f000c5d4cacdc2c40b0354ec44f44d16c",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.offset.negativeY.html": [
-        "428bed4587612b981b40a05f82afecb189245b63",
+        "daf9b7eec0cfcb1e96af4ba843fd0863fc1e4c27",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.offset.positiveX.html": [
-        "fe722d90e09ae0173744c7b9ae85a26272d424fc",
+        "9d627ddfddb1aa8e804ac0358fba25905258d25a",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.offset.positiveY.html": [
-        "49e64b7a9be41224e54e94b2482ab9c2bdfca501",
+        "619826342e895c027e55dc1c219203aaf768d5e8",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.outside.html": [
-        "c71394dca64f40cb738a16e71a2085e66ed3ba0e",
+        "331dca9246ccbd6dec0de43e1ee9d9bd87eb75af",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.pattern.alpha.html": [
-        "1fa95ada061e9713778e734e0943c017f9442f33",
+        "a995a4ab1f1afd9cd3f9e007f6dd102f1006256c",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.pattern.basic.html": [
-        "3bd3d6ded47579f04e6d78a2ee2ecef26c27faa1",
+        "adb8aeaedf67ac33925f12c9f16a4c68d8c5a751",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.pattern.transparent.1.html": [
-        "3909a31aa9ed3d9a31edfa40b5b37a7c5b65f0ff",
+        "37af35d44d24fc12ac4815a203078573b2d48ccc",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.pattern.transparent.2.html": [
-        "24becd0490d8744caac7645ba6cb918273b73840",
+        "e96e9e33a473b4292022f7cdc990b03935514ce1",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.basic.html": [
-        "5cf7f054a75596e688687c2818c9321e73332786",
+        "c5834b86dcf4c9b296181e3d69fcb8c6e38164ad",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.cap.1.html": [
-        "739ca1f3379f980770156ca8f6bac2ac153eebd8",
+        "ff6a1c4c1dff5012213486a832f8ead364b2b74a",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.cap.2.html": [
-        "38a56e713b0d96772a2dd162bbb489629f7d023c",
+        "40fd22a1c35482490b162256b398633003bd775a",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.join.1.html": [
-        "0f685285bcd7d4b18e3e2e2c7a59ffd838d4b0bc",
+        "5c7cda8e7b9842ba8306827c7ecf16838d7aecd4",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.join.2.html": [
-        "71c6a70bdd8ea535edfb6221c62ea71eaa71d9ec",
+        "0ed3c90cb857d1a39a9c65c47b752edbdd584c23",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.join.3.html": [
-        "5fa3b8209a151fec4d11ba8106584c3a0008ba84",
+        "ada4e159fa0d61ede51393b0248bae85a68e9ec0",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.transform.1.html": [
-        "5623237aacdfac5553275c484d165dab96568e99",
+        "57450512775eca6fd82e6c42bc2439a90e6823e4",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.transform.2.html": [
-        "06d1ade6f494b660d0bc18e117e9123e52051631",
+        "dc97c0672cf4a87d9cd0c4d515c9049cb27715c3",
         [
          null,
          {}
@@ -468828,70 +470444,70 @@
         ]
        ],
        "2d.text.draw.baseline.alphabetic.html": [
-        "d97656a1b89191fb2414fe9fb0e9c12b01dcb577",
+        "5bbd90f6375d81baacb8fcd98406f3dfeacad0df",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.bottom.html": [
-        "b587f2207047c05ed04d2c87b5dc94050fd933a2",
+        "311be39f4fe8434986656902bc9419a6204141c4",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.hanging.html": [
-        "710345673da8f555a72061f17fc73510cacc94af",
+        "65aa7cd176e575de585ced59cd010222ff001638",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.ideographic.html": [
-        "1cb1743663e09f546b99af0671f7eb3dd90787d4",
+        "84f126200a9074a57855d97290730668ec50cc0b",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.middle.html": [
-        "e446c3e1cc3c0f9f09516449eeb74ecfab2d436a",
+        "a09a2f3153ce1ca3df23bbe4f188605de0f6ad2e",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.top.html": [
-        "43a7c9ac17e914a654f1891c5950482bc2b8e76c",
+        "b0c72c41eadd1431761b8c07b776ca6c7cf92186",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.end.html": [
-        "904bce1b8349a59d6dc7b19d5f8161cd1ff0a479",
+        "57de14adc2363683ae218b32fe81ab1a3a37dfc7",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.other.html": [
-        "44d34d10fa38c0f4276ff2492a9f25f62e09b5da",
+        "e593b9769e58ec34ea73b1376d7dc4357170fb9b",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.space.html": [
-        "ef5fec9fbab8efcbdfbcfb15132221615a8fc039",
+        "6e24007b1c9844d44a41d79183a1e861c993c653",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.start.html": [
-        "2a1b38e7772122bf56506c439f33f6dbffecf1f1",
+        "5ec776e324083b173d91743a79a592045f94c763",
         [
          null,
          {}
@@ -468984,14 +470600,14 @@
       },
       "the-canvas-state": {
        "2d.state.saverestore.bitmap.html": [
-        "2a9a4b577ac076b01c15f68351dd4e3770aa2568",
+        "459e0d543f433cdc063899ba14904085b65e5634",
         [
          null,
          {}
         ]
        ],
        "2d.state.saverestore.clip.html": [
-        "89f59c46f93b6303d3520b10bcd63a953d1e92cf",
+        "6d1ab02f89d487c5bcd330f2214c5a4a2f558d96",
         [
          null,
          {}
@@ -469054,7 +470670,7 @@
         ]
        ],
        "2d.state.saverestore.path.html": [
-        "90cf624515712231f69a1cb195d5f50df183a937",
+        "a8023f1448c8e83e6df7c6a6315828da89fb9ccf",
         [
          null,
          {}
@@ -469124,7 +470740,7 @@
         ]
        ],
        "2d.state.saverestore.transformation.html": [
-        "02e86307037b378c0bed05680066d20cab4ef38e",
+        "6d035ef9ea32e29702301a90f64dd6062c66dec1",
         [
          null,
          {}
@@ -469140,154 +470756,154 @@
       },
       "transformations": {
        "2d.transformation.order.html": [
-        "0aa6c4a33fb3df4837947bd7e96da681281e15d7",
+        "7fe6dbc133c988a2aad7a18919068fc339535e1e",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.direction.html": [
-        "4c1b48f7480f29d3e0d079040216b0eb7c98cf6b",
+        "756b5ee6670bed87e831eaf16282ad24fd1b31f3",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.nonfinite.html": [
-        "c034cfa8f4edcbbb52ca69e934c5deeee9a6d97b",
+        "93839c6427e2d8df21a01841980baa5bd73a0a27",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.radians.html": [
-        "41835f1fa4829a7d0a08d1268bb33a5659e9372c",
+        "fabf9da24f04bf0546a170b8fa603046d4bd0beb",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.wrap.html": [
-        "c75426e9b74139306bb2b9f2128cbc3aab0e1839",
+        "05cb3073ee2ab89d9768015b435109ab681fe9ef",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.wrapnegative.html": [
-        "a94528185c1a10f74cc8294c57a584596ae75ca7",
+        "9eae3c5214d43c5361213ea29b80e25007180ff5",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.zero.html": [
-        "ddbf3e3df0c495f181922b06dd3563b1b3e179fd",
+        "54ad6aa138527f7679420509dfabf4a716e98122",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.basic.html": [
-        "83e77491520991f7f7486463429af279c3969010",
+        "0573702bd8622fd6195d32c7969830d2936e1353",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.large.html": [
-        "eefdb842aaea5cbae6fb3faf35f212f350fdcd0d",
+        "65fa9ab8da0fd4d1f5872ca989ba79f154149510",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.multiple.html": [
-        "44e8d2ece530953ee927480df0060363391410f6",
+        "5bf837ccd76d5d6e7b51d08f33e98be8327d3ca0",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.negative.html": [
-        "ee3c00c1addd05e67cc7c2a704f775f4f2d7550a",
+        "e7085999a2b814baf2d764380b5a71c0ecc00ea3",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.nonfinite.html": [
-        "4ee2fd75bc7e6b937c4c3f22f9b2bcf743d3086a",
+        "59b154904523ce0f52936b003396b54fb10fe0a7",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.zero.html": [
-        "e2d952a2099bb88fff2b6e37dc3e0b652c49793e",
+        "4ff7397ae8c4ab109e08302e71a7a745203c0313",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.setTransform.multiple.html": [
-        "7e90537113eea070fa5213554e101870aa6f5541",
+        "5fa910a5b1115101273b9c3ad985397f0c0c3f1e",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.setTransform.nonfinite.html": [
-        "b30293bff1c839d70f54e5f76b371fb16e79bf44",
+        "fea3799a41f7fab9421dc8abcebd66a5c6b0ee37",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.setTransform.skewed.html": [
-        "0381679538a662aae08b27fcfd3458d0791d076c",
+        "e78a07897b574142d0dac576a49b4a93ea30f731",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.transform.identity.html": [
-        "a33209ee83c15846487e991341c9a2261e6279c1",
+        "c9742ac210ccd4500c98cb0ededf1b0b4cc792dc",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.transform.multiply.html": [
-        "29aa5fb94531fb491164f00db0906a38a33202f1",
+        "04e5adf4c86a4a10fa7374b704ed0524d2e453fd",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.transform.nonfinite.html": [
-        "6d5f19cf780ba2a7cff13e1426247aede2b77063",
+        "b94da2c381885c4dae177840c823191d7a95e6ec",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.transform.skewed.html": [
-        "a873fe85eeccf8cee51be7d646eaf477fcc5d3cc",
+        "35cf997eb0ab2b0e56c33855fa88fda90e3a4bb3",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.translate.basic.html": [
-        "0a506ad745ca14f0c41d20d84f19d6f795239eef",
+        "967d2d2761448797d49ba81e35b61e4ce0da1c2a",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.translate.nonfinite.html": [
-        "898aad99d0861d8b91a6df0063f0164b01c852b5",
+        "83a8ebf7ba8c44cd8435739eb6c7b31ebe643b60",
         [
          null,
          {}
@@ -469407,350 +471023,350 @@
       ],
       "compositing": {
        "2d.composite.canvas.copy.html": [
-        "bab39234ad71ca84defe99359da5d9eb1082d879",
+        "a89736b579386ae168d5aa7c23867e01d05083d1",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.copy.worker.js": [
-        "ecf7afd3e031a8de73081e434c165d359ce217fd",
+        "a8fbc74c1c31a3271a31979ebd7e4b9eec59e485",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.copy.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.destination-atop.html": [
-        "feb3080ba80bbcf16969888fb904982bd1fcb30d",
+        "dc53e8b5f0203ba94aabebbee8960ef561020336",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.destination-atop.worker.js": [
-        "f6c64225739aa36d44869a38083a905cbbfc2ae2",
+        "fcb944543c01b2776484cd17f005ba0da5a75999",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.destination-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.destination-in.html": [
-        "b35792195639f6602bd04b7b126f3729b3f193bf",
+        "73140e11df149a03ad183eaef14db31612a3efb1",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.destination-in.worker.js": [
-        "d150bffbfbd60832573a377b54db314eb231cc34",
+        "e5d7f0b039ffea3fb431af1d3d99b31297ba34d4",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.destination-in.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.destination-out.html": [
-        "401a9e0dc514bff5c4d07c52d10a011c36ddc994",
+        "5f89aa29f7f4c5f8fec59c2a2bb929541533c249",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.destination-out.worker.js": [
-        "cbdcfde403c2f462dfdc8c3c538cff846e148e32",
+        "a4436be0d2f489c2b9a457368c3ce3bd52e47613",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.destination-out.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.destination-over.html": [
-        "079f74e5ebb49daf48559934072c4ff607730c22",
+        "d18f9dc8641151512ccc081a1707e6c28f808722",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.destination-over.worker.js": [
-        "3ae7bdb85bbc15983b3c09ddcfc556f2829a3f11",
+        "967e47b34d20dfa98298cd7f3e2e0b30bd52e357",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.destination-over.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.lighter.html": [
-        "0a3862abe668c0c8d8fab1d20bf2e62027f0f1e2",
+        "9de44add68341abf38f5291a7e0aa48f9bb780f0",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.lighter.worker.js": [
-        "2c217ceca2e6b0c7fe7b51198195f3c041b1cfa1",
+        "849d4a6a6f80642b9887e77a78af9fda226b8097",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.lighter.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.source-atop.html": [
-        "092e191aeb0b7e5f13b18c600c2a685f447b837e",
+        "cf9d5cfcbe1cb7e50664107b2337048e6d4be050",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.source-atop.worker.js": [
-        "2664155c3d7f8e79d7d7254121f943f010af24ff",
+        "7601db1f5aa0098fdd02abdbdbac8e06a72bedd3",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.source-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.source-in.html": [
-        "ee053857a948bb4d6e84a3cf5bb201fbf4eb46f1",
+        "30864d65a33b05d37dbcceab56fd99cd7455ddec",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.source-in.worker.js": [
-        "4c9731d8a74083aef7025686780832606346e193",
+        "5b21b35564a7fb87325543b05549fb92c034a1d3",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.source-in.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.source-out.html": [
-        "95b77f5bb67544d35ea278c560cd6cf6274f5f3f",
+        "d698540260fd3822b9e1e2df0d7d9835e93d7611",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.source-out.worker.js": [
-        "0d2da83f516a5fd6ef9091d078354105e9e5bf2e",
+        "cf5b0a9ac470fc693e696197cd980f5a5bc9e254",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.source-out.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.source-over.html": [
-        "cb93a986f463149a75729db50012a577835a59f1",
+        "e1e86c7979f8bad23d8ff632400e2289642fdd16",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.source-over.worker.js": [
-        "85ff012081e8b9b02b57677eb6b02146020cfe28",
+        "d61ebd1e56a72d552a592ef1c6bf233cae8f3237",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.source-over.worker.html",
          {}
         ]
        ],
        "2d.composite.canvas.xor.html": [
-        "d9e57fc8c4f284f5363e10437e7a208db9a75768",
+        "c2d1f52645451a59983dab25d5e8471e781f4655",
         [
          null,
          {}
         ]
        ],
        "2d.composite.canvas.xor.worker.js": [
-        "eedd05d5db3e710cad6453aabe34df7817dc04d3",
+        "1b2286a87ac487fb30506e7c5fa20129e4e57d9f",
         [
          "html/canvas/offscreen/compositing/2d.composite.canvas.xor.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.copy.html": [
-        "0023597610e4508ea07a3a684cb7c505be46a81e",
+        "5d6afc11cf68afcb471d0132fec652e8d3acf5f9",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.copy.worker.js": [
-        "6803969762ff504cb083c588af0e8eb8c326c54e",
+        "3158893fc5bb4013c906267fee6db17188650b33",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.copy.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.destination-atop.html": [
-        "e72e962ee111e2259457b3686b85b0a24ffb49ff",
+        "93d4d70adb76104e2e98b54138540c6287eadd53",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.destination-atop.worker.js": [
-        "67bea9fa6962c5ffbb4289e095ec2905fe902df9",
+        "78b5368194d9183479051cff9063e5a33d13bd21",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.destination-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.destination-in.html": [
-        "d808d13d1c0815ee6d9928565f27ff046ae38c82",
+        "d2520378e471b8c4d16642195fb24e546642f304",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.destination-in.worker.js": [
-        "7576ba59cf1edef8c571dd949652ffa91c287015",
+        "bc12026103866fd5577e49bb6756e94bc3eb1747",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.destination-in.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.destination-out.html": [
-        "292c7b0cc00c91ca5e96856e05c988da498f3b73",
+        "fdb1792b538a8f11f8889a8c12f05e0bc39443db",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.destination-out.worker.js": [
-        "2d2b58ef007cc0308ab687b4508d0f533cf0b54f",
+        "ebe3a70d03588ab58ad0308a931b2d885d1a7685",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.destination-out.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.destination-over.html": [
-        "61a508e52c3273c3261f5dc73f4fe652a374dc7e",
+        "ae4cb499bca932dd9998db3dc5eb390afb700749",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.destination-over.worker.js": [
-        "79dc3f7d50a0602fa8abd7a3a06abdb1fbd27a3f",
+        "fb8778f0e15ec60008f9dfdefae1f43c1639fdb1",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.destination-over.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.lighter.html": [
-        "1e8c3477624acabc20132ae0367411f1ff4468c3",
+        "1f705f26455326de5ddbab8bf4b534ff30745f2b",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.lighter.worker.js": [
-        "267030c8ce00f78aefc15566b5962f65562565ca",
+        "f6bf4c4aff4905ad10a0e509cfa71df8d046632e",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.lighter.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.source-atop.html": [
-        "1d2396866908b4c4a149fa289e60479365ccdff3",
+        "eb5474702c7b0845b9700805f47a74a1932581a8",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.source-atop.worker.js": [
-        "8b869b19b3bc77a12866e6e7af74925b3b836da4",
+        "fec34e1bc62c3dfdc6f012f75c34a2e7a833b989",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.source-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.source-in.html": [
-        "43f9304ba544bf660ceaef5b711cf9145a7f0a02",
+        "cdc814fa75f945ca35451d5d23a7468df5b70a57",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.source-in.worker.js": [
-        "a8d2e587af90bece7c43bfec89e30eb626a4d299",
+        "b9a67cef2e85325170e7b71ad73fd7fc81d2eb02",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.source-in.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.source-out.html": [
-        "b4872e5e76eefab4912350d48b43873aef041c51",
+        "9df047f77f91447fcfd9209d3e9e41c94376160f",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.source-out.worker.js": [
-        "42dcb8e5c9807a947e3946e528476fc328b3c101",
+        "9d2524064a74240519ce0564430cea03d34447b6",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.source-out.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.source-over.html": [
-        "1da6f53b80f7e504c4fa00b720eff3cfb94f355a",
+        "522f4f996badbaaa2d9010ce8cc48654a4306609",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.source-over.worker.js": [
-        "aac34989159b0ac598d205c42684e7749e94d8fd",
+        "6d401c46b05c7a1557b14df4d8ca9040f94cb678",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.source-over.worker.html",
          {}
         ]
        ],
        "2d.composite.clip.xor.html": [
-        "ce92ac6115cf94a0be6270c6163ab43ac569017b",
+        "dc1170db37a52e3a3e621f8380f0760dfa72bed7",
         [
          null,
          {}
         ]
        ],
        "2d.composite.clip.xor.worker.js": [
-        "38a33a3527982db2f1a78d68522669d665cdab26",
+        "1d89becc27ba20f6c9c9c8d99361c29134a8df48",
         [
          "html/canvas/offscreen/compositing/2d.composite.clip.xor.worker.html",
          {}
         ]
        ],
        "2d.composite.globalAlpha.canvas.html": [
-        "612731bae9473b6f2852b10a7f2d82ef365d0c3f",
+        "cd05d7b57b1f10a2a0bf6b0f792aa7d426a9198a",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.canvas.worker.js": [
-        "5089f8cfea250f32c90b1a6b705f50428de5331c",
+        "fe644f2ca3e5be88bbe7d0c2df04ce8160729b08",
         [
          "html/canvas/offscreen/compositing/2d.composite.globalAlpha.canvas.worker.html",
          {}
         ]
        ],
        "2d.composite.globalAlpha.canvascopy.html": [
-        "f76e9d5afb81ba1264d0059b6de9847e2a7c2f19",
+        "52a431cfaa1d740c9828b01a9812a14b8e73372f",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.canvascopy.worker.js": [
-        "87d741b4ad5a6db5270d8066817d1ba84c5a37bf",
+        "e0ef84a78b46dc52268a7eb08e2f79d243fcfbc0",
         [
          "html/canvas/offscreen/compositing/2d.composite.globalAlpha.canvascopy.worker.html",
          {}
         ]
        ],
        "2d.composite.globalAlpha.canvaspattern.html": [
-        "13af53a6d41b39a21b031b7f4e4ad6b0cc3e0fed",
+        "24d7a0fc3cddce64dc1dcb81609908745c00b434",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.canvaspattern.worker.js": [
-        "0bb2b58327a4ad53b3839165b5d26dba62fb1649",
+        "2fb494d054a410067b9bc79959271cf495bc9b91",
         [
          "html/canvas/offscreen/compositing/2d.composite.globalAlpha.canvaspattern.worker.html",
          {}
@@ -469771,42 +471387,42 @@
         ]
        ],
        "2d.composite.globalAlpha.fill.html": [
-        "62a74820199b51ed4ea495ec1782628fc6426774",
+        "e349b92376ba1d214884f11bfee31b489ac088ea",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.fill.worker.js": [
-        "e70a53821a4ffa5ac8681acb37c2ba820e48bb1a",
+        "f354773bf467ecc214f560281508ad5dc431e8ad",
         [
          "html/canvas/offscreen/compositing/2d.composite.globalAlpha.fill.worker.html",
          {}
         ]
        ],
        "2d.composite.globalAlpha.image.html": [
-        "97be17ca70113036d3d21205c25cbb9bc2cf1122",
+        "29a963a7c6f542c55d7f100a6a49b90c5424df20",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.image.worker.js": [
-        "49705cdab4e0a6b993fa99ff9bd168018da3f195",
+        "010fbd8bfa9d8c9a9194e9bfb274dc02bee0f632",
         [
          "html/canvas/offscreen/compositing/2d.composite.globalAlpha.image.worker.html",
          {}
         ]
        ],
        "2d.composite.globalAlpha.imagepattern.html": [
-        "67847cdb08b24a82e1befdce54a00c9418dd8745",
+        "7eacf16c4fce067af07d4d1923aacf5b72fba45b",
         [
          null,
          {}
         ]
        ],
        "2d.composite.globalAlpha.imagepattern.worker.js": [
-        "b855604fb49f59284a44e140aa5cdf8040c8aa34",
+        "5607972635ead409bea5b29a6b0cd969606dfef5",
         [
          "html/canvas/offscreen/compositing/2d.composite.globalAlpha.imagepattern.worker.html",
          {}
@@ -469841,154 +471457,154 @@
         ]
        ],
        "2d.composite.image.copy.html": [
-        "b6ee1ffb0e01ae45b3d408937f1475a70a497cb4",
+        "1aa9c98e9d3a628205043af6ae3c28837c939a42",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.copy.worker.js": [
-        "82f3cdbcd810e51ef06cc84d2dcd782ff78ccdd1",
+        "ba3399a2b11f7d07269784bc8fd12cd2b9ca9a21",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.copy.worker.html",
          {}
         ]
        ],
        "2d.composite.image.destination-atop.html": [
-        "91b1922ee53c569ee82d1b20f1fbd8be0cbe54f4",
+        "76547a1f86a3fd000643b4fc287fc49dd20dc979",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.destination-atop.worker.js": [
-        "b69c55882c3189e751f799616fd5c616775e7078",
+        "677b882b011379aba744ee174fe06a5fa51f5810",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.destination-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.image.destination-in.html": [
-        "ec6b1b0b7d1aba2ec7ea92e4e81d73f0ad8633ca",
+        "8fa5786961653d9a33b0ab4937ded1e8822e91a5",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.destination-in.worker.js": [
-        "58d40492a046e61240ede301eb4bbf5abb052ba9",
+        "aa8c1ac06d5c5d63fbc68cbba3ba86613987354e",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.destination-in.worker.html",
          {}
         ]
        ],
        "2d.composite.image.destination-out.html": [
-        "e383b18b2d7b574cd157c4cbb1a0057f3a6c8318",
+        "3a4da68c2cb2b0c6100bea59dd20e884fada49a8",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.destination-out.worker.js": [
-        "95936bdc4b71406819ff02f4344bfea3a0112b12",
+        "94ac27a00d4277f88c3a123e5d257a70ab2cda9b",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.destination-out.worker.html",
          {}
         ]
        ],
        "2d.composite.image.destination-over.html": [
-        "f96cfb70803af7692563fa51ef7cb82cb5a05a15",
+        "c6da28db6a7c1648bbff609e86885b87fe88429c",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.destination-over.worker.js": [
-        "65dc9a7445126dd1b8e48d5e050103d12ddfb497",
+        "3bc357dce8777317336c004f5cb9e777ac86acde",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.destination-over.worker.html",
          {}
         ]
        ],
        "2d.composite.image.lighter.html": [
-        "f0db5b43f64c4febd29657543fa526e842ede9c5",
+        "db89e5a3e8e0a42b2950c62d5041ed0a95e0d91d",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.lighter.worker.js": [
-        "cca47e902daa7d0435b97b9870cb927cbb3377de",
+        "922b5f463529416726419c19ae3701a5432fc6d8",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.lighter.worker.html",
          {}
         ]
        ],
        "2d.composite.image.source-atop.html": [
-        "1547e108c7985995bd703c9e9a83f53e25f63b4b",
+        "44dd6f4274dd205ea2b3e913279777827eea958e",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.source-atop.worker.js": [
-        "434eeb7f991b6567df282ce0e140e672d437667d",
+        "1b32993858815205d92c3afc2e1e087a88f03779",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.source-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.image.source-in.html": [
-        "6529b9042582363763da31f6f469e6f889b63653",
+        "64c28c0c2111c123229606c80b84f07263131c1a",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.source-in.worker.js": [
-        "869a6b94c4d47fcfd7ed27a9bbcc52cccffa8c51",
+        "3048f849a9c8fd2228c30c2a9270ef4815da0d41",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.source-in.worker.html",
          {}
         ]
        ],
        "2d.composite.image.source-out.html": [
-        "fde8083be4011066d4c6f5c957bc6c0a07f61291",
+        "46d3e483ee71c795ffafeb3230e14ce928709934",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.source-out.worker.js": [
-        "379347628379319df7a0cb420a3ebe6640588753",
+        "090bbe7d226927a2022cf0a530a0de984683b9da",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.source-out.worker.html",
          {}
         ]
        ],
        "2d.composite.image.source-over.html": [
-        "67c08390bdbffd3f43804e56eac77a6dddf7cf14",
+        "1d13b7724836357184bb81cd88d656d7e0ee573d",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.source-over.worker.js": [
-        "e337f4d7b0efe9363599473b7c3a959d40ecaf96",
+        "7937e5be6946f2ae97af9527ce7b5427c4d92e6c",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.source-over.worker.html",
          {}
         ]
        ],
        "2d.composite.image.xor.html": [
-        "800a615510ad9a6a76de640a49b04228d0a9f984",
+        "73253fabcaa44911451f4ba335e057557a814324",
         [
          null,
          {}
         ]
        ],
        "2d.composite.image.xor.worker.js": [
-        "0793948b38f645251a3de0e95ae4facfebd5027a",
+        "7a22f7d39f20b29ed2188819bca0d7051affe03b",
         [
          "html/canvas/offscreen/compositing/2d.composite.image.xor.worker.html",
          {}
@@ -470121,343 +471737,343 @@
         ]
        ],
        "2d.composite.solid.copy.html": [
-        "b9e34001b426850bc7134a55398fdf8dc0242894",
+        "aaad0b418fff84ed656642405bbbb651468c1bdc",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.copy.worker.js": [
-        "2baab2847b60eb16cef31545c430eca806f58d18",
+        "63cc6c1e90dec7163d4c9ff947750c0146b1da73",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.copy.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.destination-atop.html": [
-        "6fae26d9804afe3065c89a1f8f59879d8a227f5c",
+        "be4cf393a1beb527476a909caf47d82a3c317cc7",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.destination-atop.worker.js": [
-        "e9cc3f9a9da5e72f897282d5dab773d6f114693c",
+        "a09827ca88b0e40835c4a7eb60846c52fe4ddae3",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.destination-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.destination-in.html": [
-        "72b51c6cb3eb09d6d51eb96fa8ee079bfa86c62b",
+        "e5ea33b5b0bbd330beefc755d1cfe8d388f1b44e",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.destination-in.worker.js": [
-        "d4b55604e0bbf78768d5ca5ee56151e817eaad56",
+        "b06ad632668fea9628ee210fdeefb7c52f59e38b",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.destination-in.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.destination-out.html": [
-        "7fe711decbde43730372ca3c8ad086dcd273bc87",
+        "49efe240d0896fa89396586d5e05a7d54c65f57a",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.destination-out.worker.js": [
-        "de9811ecb3e35d62df50ad779242e1d29cdc6562",
+        "3b0232e2555b2542cd4b2a165c14140630d58b83",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.destination-out.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.destination-over.html": [
-        "1d7e0fb08e0afba2cd28abf38ba761db888891aa",
+        "c1d7965cad1a0a02d8b710565a1c5e5936c2026f",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.destination-over.worker.js": [
-        "60464d2c242a5b6bae890ee1ab26d77c63568e2f",
+        "99d64be57830f3b78d9fb6aa56c923459175d917",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.destination-over.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.lighter.html": [
-        "5bb9593cb9d2688e33352dab9bdd52ce17491448",
+        "2877e14ad9c121b82f0ba5bf897474a779527fa1",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.lighter.worker.js": [
-        "23a34fcc01ac08712403654d2ccb71df05a428c2",
+        "011a19934ee1a0eb306a74ab020f75461516ed50",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.lighter.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.source-atop.html": [
-        "5360ac58f4fa805fc23603b9066cbe3ff22d18b6",
+        "9f972edabc99b235bf2b6540287b96cb9408cd1f",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.source-atop.worker.js": [
-        "79ce54ef2cfa4c637745be3527d0f89a69e35e92",
+        "2dc6ec9b2e812ae3ad578f4bcfa44b45f78014c4",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.source-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.source-in.html": [
-        "80ecf3aba1c05d4012c9ca660fce6caf3070432a",
+        "c674bbde91bbf682234b7320680f068b117bb48e",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.source-in.worker.js": [
-        "1cfedc98617632de386782d380845518c95983ee",
+        "5b833ec156aa0f73a2bbacb4af79d34060dc9858",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.source-in.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.source-out.html": [
-        "8bab40a14d653dd36bc2a968105848e4c184981d",
+        "0fa403bb75cba6623594970892965502405ffdc1",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.source-out.worker.js": [
-        "7a64d43b7809bbf6daa73090d6dde0d209907f84",
+        "0486939935fbd9e9c64f56183dbd34e0d2a3e0df",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.source-out.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.source-over.html": [
-        "6a77533886be1695daf1bdb241feb217b8368005",
+        "4392e60c9e5e03fe43bd9b5961c7a7aa01b7c3c8",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.source-over.worker.js": [
-        "db6f5c3ca6a98d983e189a2a58ee7c8cf678f9c8",
+        "ce8190ec0f918ff30dbecadd15c6131da66694c5",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.source-over.worker.html",
          {}
         ]
        ],
        "2d.composite.solid.xor.html": [
-        "12a5ab864ab8f15b43b9854fed212562cd10334e",
+        "a9eb83e6a9d6e73cc189c4970a82a8121ea54373",
         [
          null,
          {}
         ]
        ],
        "2d.composite.solid.xor.worker.js": [
-        "3da6e4dca5a1aaaa820d3576a3cf932eaf1780e3",
+        "8b7edec945fc1450f544138d011b3c046236e5e2",
         [
          "html/canvas/offscreen/compositing/2d.composite.solid.xor.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.copy.html": [
-        "1f15d77ac943958cfe9223c50fbb65f6d8bbd1d6",
+        "20c107bd774a4dc8ad679c4275d0536645a0122d",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.copy.worker.js": [
-        "0c954b08ccc0b93143a0a491b05bb56501146415",
+        "7fb646acd50a0308e40d77db8e0237045d7cdec3",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.copy.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.destination-atop.html": [
-        "b6f5e88425fe81804f35dcbfca3e406db8199073",
+        "2bc5466d27858df48c78d6b0ea28db4c97e3f127",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.destination-atop.worker.js": [
-        "d2909e4e0085aad0690f7185ba801b2c00d08b5b",
+        "f433bedf7c91f64c619b3b909b57b5fc8a2d27be",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.destination-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.destination-in.html": [
-        "4ba2c25de9cebfa87846a52efe21fb271c02fc58",
+        "1d1121812df00e7ff5bdb236768f79f9f5c5612a",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.destination-in.worker.js": [
-        "a62b40e1140c9d468319ba29790fd09f494b5a98",
+        "a4c159aeef8156a8e238c9c4e07a3f7d63bf84bf",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.destination-in.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.destination-out.html": [
-        "e5dcfed8108953cd047d9116e4fecfe7a462bc84",
+        "17b3fecd028031feda67787e43e0a66f1ecc54b1",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.destination-out.worker.js": [
-        "49f968da42178fa60ab1e799ce68e62bee9f6135",
+        "cf6827fc51f13ba663ad2bd8f83d833b5bc41e17",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.destination-out.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.destination-over.html": [
-        "0b81d543a786009ca95941219788a81ab63e13e9",
+        "04c267a81702de02dc340136fc79be87f6263bd0",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.destination-over.worker.js": [
-        "3ef1433d106a61290cf34e4162b7a316688cc23d",
+        "98a4b5b59ed769e0703756c4852dda71b810b80d",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.destination-over.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.lighter.html": [
-        "b74c593dc2712b12e450442a10c19d9135f86a6e",
+        "86d06f2485df7354585db03e028243fc930764ab",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.lighter.worker.js": [
-        "239ad65739315ead3f79c01855bbcb9224e19974",
+        "f9b419ace745b4133595b94947d4866c6784ceb5",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.lighter.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.source-atop.html": [
-        "ba61962a1fa60a09eb13ce20067b73229881d54e",
+        "f4e79c0c2407f457599640a5a676df2c64063035",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.source-atop.worker.js": [
-        "517942b93569b89ed6c391ad6b969e34f264296b",
+        "db65db8366605300c37994f8649faff46d810c7b",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.source-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.source-in.html": [
-        "501d5975626eba37815bc63e8423dda753ca6976",
+        "56b4e7704d5d18d24f369f4799146fbf209869c3",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.source-in.worker.js": [
-        "7e3964a18ebc96efe63f9ab14c93077bfed2a2c3",
+        "32765c4c03e11b896427dde7c51286dd6e68cb2d",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.source-in.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.source-out.html": [
-        "09e2f3f6555071f2c63e74ecbbce7bcb4bf2c88f",
+        "cca28c5ebcffa2a6026bf30e31a3c2c47ebc95d2",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.source-out.worker.js": [
-        "f0660fe10730bfab041167548634a121746de8db",
+        "3cf507bf84567e9d74ef1818507c1270969e899b",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.source-out.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.source-over.html": [
-        "291355d1f89c39bbbb7fd2fdafde9ddfee0759eb",
+        "a8ae30131d013140c43ef756e498700aaab6ebc1",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.source-over.worker.js": [
-        "126e80741e44390f99e635c16aaef9deec4abcd3",
+        "35545c04d4eb182cac9e0a27f8c30520965a7459",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.source-over.worker.html",
          {}
         ]
        ],
        "2d.composite.transparent.xor.html": [
-        "b9100d636bb68a63980661a19d72cc629df36db8",
+        "638bae02ececff0b002575a32dba50d62ccc5769",
         [
          null,
          {}
         ]
        ],
        "2d.composite.transparent.xor.worker.js": [
-        "d97d3a9841387ee1c200c9d0de66d5d18c5dc492",
+        "b21d30d900c4c8e7930f5a6e58261c01ad2335c5",
         [
          "html/canvas/offscreen/compositing/2d.composite.transparent.xor.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.fill.copy.html": [
-        "ea7f416feeb2836307c1b45cb80219ff295b81d0",
+        "f10275f40751df01f2d4126360dca6e24f473d51",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.fill.copy.worker.js": [
-        "6d8b4c22ec050bbc98a6341d1a47361287989754",
+        "3b86c720f5fc867f1559678a4555f7eea186f473",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.fill.copy.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.fill.destination-atop.html": [
-        "37d3ffbda616e036da0d0a59a760299f8eb3b913",
+        "8672e9e19f4b815023140826a31b2326989f02aa",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.fill.destination-atop.worker.js": [
-        "9312298b965c0f7e0ba136f0c512f8d74b203f70",
+        "69610fc1072c06b2c3ae492fed5a60d2c9525fdc",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.fill.destination-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.fill.destination-in.html": [
-        "690a03fcb86a301b1c82724656895c9df8f0dc02",
+        "0f069372ad141c3e4c4099d6c032ec2342d1cb3c",
         [
          null,
          {
@@ -470466,7 +472082,7 @@
         ]
        ],
        "2d.composite.uncovered.fill.destination-in.worker.js": [
-        "5e7b3b3d08d2052b2674a60190851f2486278b53",
+        "26b287134b1305c7201858c760c895b6290dfdce",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.fill.destination-in.worker.html",
          {
@@ -470481,238 +472097,238 @@
         ]
        ],
        "2d.composite.uncovered.fill.source-in.html": [
-        "704221440f121f09b580ac6a3de671bda897c958",
+        "6e1ecdd719fdd673774054e7ea34dfcde252e41d",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.fill.source-in.worker.js": [
-        "79153081190a7d51918348999a1919a98f6e997d",
+        "6da98654cfc0decbc9fcc81e65db484594ff75cc",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.fill.source-in.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.fill.source-out.html": [
-        "d9f63657e58f92c8636fa957dc66280d368ce1f4",
+        "de16897f8c4e504b10b1de22f6a70854402597b0",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.fill.source-out.worker.js": [
-        "f77835ae27dc485bf304fec978a56935e41cb8c2",
+        "515b587b58b261e92d49951519f58b36b6dcb712",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.fill.source-out.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.image.copy.html": [
-        "30d9022cfa5e7dfad64a7d7fbc9e5d8ae3ae92ee",
+        "5f3c9a191431ef9747b3ee3733138a13059acc34",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.copy.worker.js": [
-        "bd07d4d3713b955166fd57d7fc21fb87fb5ba5a0",
+        "2faecdf0dd97fc9d43782ef9e5df8e17f61880ac",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.image.copy.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.image.destination-atop.html": [
-        "a44416863e09d5f58775b8af4a0c0d87f1c1d134",
+        "3605e4469832ad9f4718a186abc72786943cc4c1",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.destination-atop.worker.js": [
-        "d12ca85fa3b59b10922d6951b2511c902f3c076d",
+        "8b361e066d9d1607b794f4a91115374b941156c3",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.image.destination-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.image.destination-in.html": [
-        "9257ff9fb52e18f9581c70484849b98263c69cac",
+        "c48ee8e16e38553cb5b833eb46ce4ca8c338da72",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.destination-in.worker.js": [
-        "eb119651eeeba4c689a3a493abc23c2b9ec979b5",
+        "b270efc7aa43453cd7cf17545fbc92e31d56a83f",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.image.destination-in.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.image.source-in.html": [
-        "954f9be2f61a79bf0c55df2f30157993f794e441",
+        "af4c3b7daaad401c39db5040eed1bd6ec348bb62",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.source-in.worker.js": [
-        "b5344ee1bd7de0e0895f5a8cf007e4ba84a613b2",
+        "5fe00cf14b02a257d43e06470560115b4f45ed4d",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.image.source-in.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.image.source-out.html": [
-        "7c9060caed75fa56169ff4dad2b7fdd08af5b0ea",
+        "4f1c3869b0d3476bb0cece510bb033702c9995ac",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.image.source-out.worker.js": [
-        "06fdd5a1a41800085bf5b18f260f5c84ff307b85",
+        "f93185bc66c343d32ad775ec857d2eb858e85203",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.image.source-out.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.copy.html": [
-        "81e72a0c762c603179b3d75d3318af9b8bf5126a",
+        "57c499d81cc9984f35575d87d71606a8029cb902",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.copy.worker.js": [
-        "85b5e3bef3086c95a705e2006bcd4885f14de344",
+        "bf6bdfe94310d1001c1c6f1a3fa18dcf43325273",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.nocontext.copy.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.destination-atop.html": [
-        "1083a875ba53150cbfc69bad5968b4778ee82ce8",
+        "73684800ca588c53662a97392fabd77d9b231a24",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.destination-atop.worker.js": [
-        "3b26653a5605ab2dd89aa1e8a1b8344f01f80385",
+        "3574add7d801f9f82a5fa60b975bbe0b26ff6e73",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.nocontext.destination-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.destination-in.html": [
-        "ceac0e58d22e148a7bc1369e20f6d1d634dbf9cf",
+        "b41c4b749c7f2da0bdf24c36f6de19fe6e19fc5e",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.destination-in.worker.js": [
-        "ed739a8eb250c4a2c5366bb7aa9f71005eb87b29",
+        "979a0849e81c5fda408158259b5a1231989c4364",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.nocontext.destination-in.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.source-in.html": [
-        "d114ee2d1318bba58db7106e4cd635c522fe10b8",
+        "99aeefbb6af5ba4fe2782eb0ced6c83f0d3cd56c",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.source-in.worker.js": [
-        "77d2e442f6e68d6a7c4cb6b593e39372d9bf3fc0",
+        "55596f859de0fe5b3bc7e822506bc416c7b6ec23",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.nocontext.source-in.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.source-out.html": [
-        "d8ec902f058f30f3034dacafde1951b8d386db26",
+        "0dfd4ae0d0b51766b81e30557e5cef9bc4cf39e0",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.nocontext.source-out.worker.js": [
-        "1696690cd90f0fbaeb4bb9600d6d8261fd8fbdfa",
+        "f0820e03fe01cb58bf7fb02535b41475ccbdf176",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.nocontext.source-out.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.copy.html": [
-        "db3ca44053e6d741e1db77687900a413a5bc499b",
+        "244cc82f55674a6a0720e63945864212272cfb07",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.copy.worker.js": [
-        "209e56b48418bc0835c70ae2bb9adfd7284f3164",
+        "3aeddac219e3fb225a96b6f49a4909f2ebfb4de5",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.copy.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.destination-atop.html": [
-        "76153815a42337bbf8e724e770e5abcbe116051e",
+        "3624f1baa91102667b4196041b8494a0dc27ebfb",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.destination-atop.worker.js": [
-        "774fbc093f764f565edf19f16d776d59cffa2293",
+        "86aaf9fb52af9f001e4504ef668c18e1eb21e0e1",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.destination-atop.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.destination-in.html": [
-        "9951cefd76e4e1cace98252f920d23c8eea4a24b",
+        "21990f1ae0fc6624e5a795c863a33ca524aa75bd",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.destination-in.worker.js": [
-        "2eafc21ba3b6ae05a7eeeda824ffbc8ac036f63c",
+        "184efcd71e3f371f5a1c531bede817c3d95eb978",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.destination-in.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.source-in.html": [
-        "e6117e2215dcf187f1cdab0e8777b826e2d6ebc6",
+        "f95da543c913bd16070e91d218bcaccf0ee00b4c",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.source-in.worker.js": [
-        "90394a19d12c8b2dcb5c8c231941eea9591d8797",
+        "61c798b7aae60210536bd6fdbf3966125a86c834",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.source-in.worker.html",
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.source-out.html": [
-        "a0856adad63e73e1c35c02e170f35d8676fa8159",
+        "4eb6ba519f70e22320491472089542796092eabc",
         [
          null,
          {}
         ]
        ],
        "2d.composite.uncovered.pattern.source-out.worker.js": [
-        "515411d7d7c88fddfcf4e909db58c08bf7363ae9",
+        "5827c7a1d7f64180b5dbc3cf0d346bd10b081dab",
         [
          "html/canvas/offscreen/compositing/2d.composite.uncovered.pattern.source-out.worker.html",
          {}
@@ -470751,7 +472367,7 @@
       },
       "drawing-images-to-the-canvas": {
        "2d.drawImage.3arg.html": [
-        "15d7b73a7319fffb8959543af2342c7d7c21aa16",
+        "8e144b1ba6b81fad3d62219ea44c8438e199758b",
         [
          null,
          {
@@ -470760,7 +472376,7 @@
         ]
        ],
        "2d.drawImage.3arg.worker.js": [
-        "875e618d18990ee603f1baaa72f9eb2e18e1863a",
+        "22cb3653e41f1e7aed74563f3bc69a2b1035bad0",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.3arg.worker.html",
          {
@@ -470775,7 +472391,7 @@
         ]
        ],
        "2d.drawImage.5arg.html": [
-        "046e38f217b8cc3b9f87cb835da850f8c37f11e0",
+        "c383d1a41729990d892bb4737e6a861139be395a",
         [
          null,
          {
@@ -470784,7 +472400,7 @@
         ]
        ],
        "2d.drawImage.5arg.worker.js": [
-        "d5dad453a9315e6e05b2761ef5812031e59b6ddb",
+        "3906a5a00b374c57d9fedd93864e35ee28c45169",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.5arg.worker.html",
          {
@@ -470799,7 +472415,7 @@
         ]
        ],
        "2d.drawImage.9arg.basic.html": [
-        "c1b927dfaf739e9b15a8ba68be3bd7bf603a4f30",
+        "72ffb4ee3b698faf94069f58dd61e96ab4fcb413",
         [
          null,
          {
@@ -470808,7 +472424,7 @@
         ]
        ],
        "2d.drawImage.9arg.basic.worker.js": [
-        "c392330cce9118fb225810716ee8599ff89d6a96",
+        "244bc90fe7fe8445591cdc4f6ae511c2580ddcab",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.9arg.basic.worker.html",
          {
@@ -470823,7 +472439,7 @@
         ]
        ],
        "2d.drawImage.9arg.destpos.html": [
-        "4c0dc527c99c84671260868f89880365632df4f2",
+        "ddfa0cbf7cd112da15d86dff1be35e1280647646",
         [
          null,
          {
@@ -470832,7 +472448,7 @@
         ]
        ],
        "2d.drawImage.9arg.destpos.worker.js": [
-        "292b113445035e961093cd9602f3bef4b20222a7",
+        "81fdae81df620b1c6291004f15555643eb60ccae",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.9arg.destpos.worker.html",
          {
@@ -470847,7 +472463,7 @@
         ]
        ],
        "2d.drawImage.9arg.destsize.html": [
-        "96d7666b989b33cab88ab1a7ee24474d7414c18b",
+        "d94daa861e00f87d4b4168fc45c27ae47e591562",
         [
          null,
          {
@@ -470856,7 +472472,7 @@
         ]
        ],
        "2d.drawImage.9arg.destsize.worker.js": [
-        "32a87f914cd4d9e0bfbc097462cedc9114f952a9",
+        "60fea26afe3d9500ce6297c7e292ce5011732891",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.9arg.destsize.worker.html",
          {
@@ -470871,7 +472487,7 @@
         ]
        ],
        "2d.drawImage.9arg.sourcepos.html": [
-        "53f9dcf28269326f9e76a23f807be41374e8c2e8",
+        "ffd60f5da94190804de5ef85f2560e9a2679624d",
         [
          null,
          {
@@ -470880,7 +472496,7 @@
         ]
        ],
        "2d.drawImage.9arg.sourcepos.worker.js": [
-        "79604b11a67b51f1a881fd7b66e0653db9eac4d2",
+        "1522353ad6ee4e781027f94539c589e486a31e38",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.9arg.sourcepos.worker.html",
          {
@@ -470895,7 +472511,7 @@
         ]
        ],
        "2d.drawImage.9arg.sourcesize.html": [
-        "1ba1c4571fd5207e46fc31e03490c380bb6af8fb",
+        "91962b671b149d791df7ea4bc0c9fb4a77885413",
         [
          null,
          {
@@ -470904,7 +472520,7 @@
         ]
        ],
        "2d.drawImage.9arg.sourcesize.worker.js": [
-        "b1667d68cba26f53744ecb69c568c5625a821454",
+        "6658e217505480b0ad21e88e9f1a7e5250965c8e",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.9arg.sourcesize.worker.html",
          {
@@ -470919,7 +472535,7 @@
         ]
        ],
        "2d.drawImage.alpha.html": [
-        "7382452ec3251d8d251d0aff9131e25d3d87b603",
+        "505c3fde5d1148b028e8bdfbdbffed60fdd425dc",
         [
          null,
          {
@@ -470928,7 +472544,7 @@
         ]
        ],
        "2d.drawImage.alpha.worker.js": [
-        "59f48f8c2d54b0c1a7271ee57559664c7f3f3eed",
+        "92cb23fe14d02fa669285b1665e2ba1d78c4f358",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.alpha.worker.html",
          {
@@ -470943,7 +472559,7 @@
         ]
        ],
        "2d.drawImage.animated.poster.html": [
-        "ee4e17ec1e8d11f0912fc6840316667118310c33",
+        "59d79fd7174df6c76ba56e1430cc7f66fcffcd06",
         [
          null,
          {
@@ -470952,7 +472568,7 @@
         ]
        ],
        "2d.drawImage.animated.poster.worker.js": [
-        "ba77be0a8d452fd7ba6576cce4e53f9a4e730dfd",
+        "94ca08a075b32350ee7af47f393afe8257dc4f39",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.animated.poster.worker.html",
          {
@@ -470967,7 +472583,7 @@
         ]
        ],
        "2d.drawImage.broken.html": [
-        "ee3f758bb96528c8b94c5ad326e083fb722c5733",
+        "3324bebcbf947b8ee8d9addad9567ee6753cd71c",
         [
          null,
          {
@@ -470976,7 +472592,7 @@
         ]
        ],
        "2d.drawImage.broken.worker.js": [
-        "f43f7eef171dee0d827675ddf157496133b158ff",
+        "d3f1b7e4a1165d1cfcff42eca8e29c0b77e301a6",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.broken.worker.html",
          {
@@ -470991,7 +472607,7 @@
         ]
        ],
        "2d.drawImage.canvas.html": [
-        "99251b5a2084d512fe17662f04c5da0c6282a694",
+        "9b128710866e19112c5daf33ec27ec8a5ac77c15",
         [
          null,
          {
@@ -471000,7 +472616,7 @@
         ]
        ],
        "2d.drawImage.canvas.worker.js": [
-        "fb979816999f1d675c427d950381c686612adf9c",
+        "da01a86ba059511158aec8d37b2dda520866ca20",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.canvas.worker.html",
          {
@@ -471015,7 +472631,7 @@
         ]
        ],
        "2d.drawImage.clip.html": [
-        "2d7b97a93f82334585f57418a1ab0cca5567e2c8",
+        "fa31852158517fcc82d6e810824c61976848c833",
         [
          null,
          {
@@ -471024,7 +472640,7 @@
         ]
        ],
        "2d.drawImage.clip.worker.js": [
-        "d6fa618f77e5a4b73aed22e2732c9d257cf904aa",
+        "d30a05fa9dbc96fc1f38bbb62c18d7ed4c68c481",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.clip.worker.html",
          {
@@ -471039,7 +472655,7 @@
         ]
        ],
        "2d.drawImage.composite.html": [
-        "9d721a50d5579301951f61574eaab17b2ca9c0f9",
+        "de4ea40d7d712b972e57711143d521bf2b691a90",
         [
          null,
          {
@@ -471048,7 +472664,7 @@
         ]
        ],
        "2d.drawImage.composite.worker.js": [
-        "6a8962b195bb62391037a98cdbee5447a04c50a9",
+        "0c4a7fe10a849cd3edf359e5f1f36a3d4e7e160c",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.composite.worker.html",
          {
@@ -471063,7 +472679,7 @@
         ]
        ],
        "2d.drawImage.floatsource.html": [
-        "a4a82615fa90ad1b87b78ffad342b9fc45199cbe",
+        "5f729737827493892b2926b1692becad31815f78",
         [
          null,
          {
@@ -471072,7 +472688,7 @@
         ]
        ],
        "2d.drawImage.floatsource.worker.js": [
-        "b2e9112244189835a09a27b5cb35f85cdb28ac4a",
+        "7b16cbb4f5f1d2c0c900912e6e7a1fcf4d0c26a3",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.floatsource.worker.html",
          {
@@ -471087,7 +472703,7 @@
         ]
        ],
        "2d.drawImage.negativedest.html": [
-        "a70da77feec0a1a42bcc847631e169358050c5bb",
+        "5851fcfb03c56a88fc5096206a27cbe47c22b9d7",
         [
          null,
          {
@@ -471096,7 +472712,7 @@
         ]
        ],
        "2d.drawImage.negativedest.worker.js": [
-        "567a126f93a738fb8d428ebe4eb2749786118097",
+        "5ca4d14ef635f56e09affb9e976664fbf6c0a846",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.negativedest.worker.html",
          {
@@ -471111,7 +472727,7 @@
         ]
        ],
        "2d.drawImage.negativedir.html": [
-        "caf5ebaa396022dd329d42938c269dc631f2f481",
+        "f9d820733d0e6fe0f4319a71ef0851dcb30ab845",
         [
          null,
          {
@@ -471120,7 +472736,7 @@
         ]
        ],
        "2d.drawImage.negativedir.worker.js": [
-        "a52ef8269fd6d9463ab91b388edcac3c14460c95",
+        "2a6cc81058d3e3e6442c136a638f0678728b0569",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.negativedir.worker.html",
          {
@@ -471135,7 +472751,7 @@
         ]
        ],
        "2d.drawImage.negativesource.html": [
-        "3c9dffe3993f131605fb111facc4d9f556c27ad6",
+        "9c2a2a1b103286d726bd42845f055ec8cfa28f56",
         [
          null,
          {
@@ -471144,7 +472760,7 @@
         ]
        ],
        "2d.drawImage.negativesource.worker.js": [
-        "de832f4ac7a94dca4f246b8b810dad82209f0c5b",
+        "ada79f9137d865b5864d07597990f7c7ec6cf2d8",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.negativesource.worker.html",
          {
@@ -471159,7 +472775,7 @@
         ]
        ],
        "2d.drawImage.nonfinite.html": [
-        "a1911392020adad92c77b107cecce7850d00c22e",
+        "54f8d9526933b7415a185f073c5279ec28fd01e0",
         [
          null,
          {
@@ -471168,7 +472784,7 @@
         ]
        ],
        "2d.drawImage.nonfinite.worker.js": [
-        "f7484b6577b604b1d63a8c54442c9f6ee6618807",
+        "a2e77832a20d8cde747939d048038be9b0f2c046",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.nonfinite.worker.html",
          {
@@ -471183,7 +472799,7 @@
         ]
        ],
        "2d.drawImage.nowrap.html": [
-        "aeeaff6ddaa04a8513deecf76cdb7d4316999e77",
+        "6ec22c45d616d46d28ecd1272a4970c8460684ec",
         [
          null,
          {
@@ -471192,7 +472808,7 @@
         ]
        ],
        "2d.drawImage.nowrap.worker.js": [
-        "6fc94276ac52bfa35468dd5b439b40b5f2d9ec89",
+        "ab3a9367dd3168b4ee0ac36f26d40cefd1bfcba0",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.nowrap.worker.html",
          {
@@ -471221,7 +472837,7 @@
         ]
        ],
        "2d.drawImage.path.html": [
-        "df3af5bf663bf3df6be17c77eb3c63ae86781757",
+        "b6bad65df59f5c4e6ad15abaddc303a03dd8ef2e",
         [
          null,
          {
@@ -471230,7 +472846,7 @@
         ]
        ],
        "2d.drawImage.path.worker.js": [
-        "3f477c0594cef1911af8976acebcd7e5829ca549",
+        "5521290977879fc171c8116cd060e650e11f8131",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.path.worker.html",
          {
@@ -471245,35 +472861,35 @@
         ]
        ],
        "2d.drawImage.self.1.html": [
-        "eae0558d61f5a47c8d210d4db47e44d1ac40a606",
+        "38857453a442d8b3eb6be0d508db233bb5d79f0c",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.self.1.worker.js": [
-        "1f31233a434647986993196e102df84f628b112f",
+        "01d47cb334e752b7d0a5e12b07ef6eb6571a922d",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.self.1.worker.html",
          {}
         ]
        ],
        "2d.drawImage.self.2.html": [
-        "5c58f34c15e6bbcbda4bf1c62d90b701d2f37363",
+        "74d383f7e38b2d4acdc453be20d6c6a5201e918f",
         [
          null,
          {}
         ]
        ],
        "2d.drawImage.self.2.worker.js": [
-        "c7c4437f188c302177c440421a7bb15df34ba49f",
+        "61a02c87a673901c00dcbe9cec02fc4724b2fc32",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.self.2.worker.html",
          {}
         ]
        ],
        "2d.drawImage.svg.html": [
-        "6f568d7d092b36ca76f25bfd2a1c11df74283ea3",
+        "d275bf95675846e2c1cd5ad9e37f734d0a8ff7db",
         [
          null,
          {
@@ -471282,7 +472898,7 @@
         ]
        ],
        "2d.drawImage.svg.worker.js": [
-        "7c2c0933060a0ebf73578f5b2a8dd3c47905e637",
+        "2d832be3636f35944b232742ab406f20a70d5fff",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.svg.worker.html",
          {
@@ -471297,7 +472913,7 @@
         ]
        ],
        "2d.drawImage.transform.html": [
-        "25f120269d268e2987d600a018c9501d6a398273",
+        "741c5efb9fac3adac2989e3df2d3e968b581cfc3",
         [
          null,
          {
@@ -471306,7 +472922,7 @@
         ]
        ],
        "2d.drawImage.transform.worker.js": [
-        "8fa51fb23e7205f92a71fb2f26a77f3d51d9e17e",
+        "2fc0caf1c3150a3ed8d9df1e4402cb725e8c751a",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.transform.worker.html",
          {
@@ -471359,7 +472975,7 @@
         ]
        ],
        "2d.drawImage.zerosource.html": [
-        "77d05e8c845661e025bebfb86f08c76540a21097",
+        "cc610399dbbbccdb4e7451a1ffbc89aaa5349824",
         [
          null,
          {
@@ -471368,7 +472984,7 @@
         ]
        ],
        "2d.drawImage.zerosource.image.html": [
-        "50c49d97842b02f3c69b8f1214f89aecf37fafe6",
+        "d79f821d44022aabd740c66474aef75d9400821f",
         [
          null,
          {
@@ -471377,7 +472993,7 @@
         ]
        ],
        "2d.drawImage.zerosource.image.worker.js": [
-        "57985f2ec4a98687c2d0e8f18e9fa563477e8998",
+        "1465d6c1bc274fe341cedb04d5385ae56074202c",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.zerosource.image.worker.html",
          {
@@ -471392,7 +473008,7 @@
         ]
        ],
        "2d.drawImage.zerosource.worker.js": [
-        "1c0c2b15332b0f5e0d99016b27f63db5a5600f8c",
+        "654e9bdd744ec6f404ec590d03e6e335bebf5c2f",
         [
          "html/canvas/offscreen/drawing-images-to-the-canvas/2d.drawImage.zerosource.worker.html",
          {
@@ -471409,448 +473025,448 @@
       },
       "drawing-rectangles-to-the-canvas": {
        "2d.clearRect.basic.html": [
-        "7a931c37486acbf8d23d4acf5dbaf64de3b3b777",
+        "846b264ee8c5e73915c1d9413526f626cbd3d002",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.basic.worker.js": [
-        "2a7a70e7dc756348373bb88f0701422b47af7f28",
+        "5908ecca85bf8f36aaa7f4b2eab3c749dfddeea8",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.basic.worker.html",
          {}
         ]
        ],
        "2d.clearRect.clip.html": [
-        "6f70f0e85471c41dbc8ea93b88feaf73b8bac86c",
+        "eb3de8b591f1402f720e51b713eb809587eeac83",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.clip.worker.js": [
-        "ac9d849988bf6282f93e3eeccc6511271395af0a",
+        "7fb5791cc9a1525c1a9f66490a47f283c0936c00",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.clip.worker.html",
          {}
         ]
        ],
        "2d.clearRect.globalalpha.html": [
-        "3f89f69f55cd0623a872099a44247c9f1bc5fe5b",
+        "c1a3463d313c5af0e4bd5740c892c8efd5004923",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.globalalpha.worker.js": [
-        "b0d766a9648cf505b46004c701228699dfa746ca",
+        "885e389ba52aace6797b5cde1218a3cf443c3d28",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.globalalpha.worker.html",
          {}
         ]
        ],
        "2d.clearRect.globalcomposite.html": [
-        "828ea03fc266cf6e0f7c4a90baf682bc0df94304",
+        "a77f67a4ba4cdcab57cee617d349c43b3b3d28e6",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.globalcomposite.worker.js": [
-        "6f31696027a584d25632c22933c4328f771e85ce",
+        "a31962f73e004dbfdda34593a974208095a45627",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.globalcomposite.worker.html",
          {}
         ]
        ],
        "2d.clearRect.negative.html": [
-        "3c1afcb572cce6fa78c512e082f38594d5b9f934",
+        "158294ab3eacb9604d5b39a917a7d24939f8480a",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.negative.worker.js": [
-        "e07e6360952dcf5319bb2c77bf3d3e4d5577a323",
+        "c7390550b8ae0df942bd5dc5ba9dcb71075166dc",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.negative.worker.html",
          {}
         ]
        ],
        "2d.clearRect.nonfinite.html": [
-        "dc11a5a9e3cfa20cb7aa45db69dc1e4d98915840",
+        "4d3037b26ba19bc1d0a7700e0a43a7dccec15f22",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.nonfinite.worker.js": [
-        "0e24270901c1611662a38e4203be2ef9d8a2730d",
+        "e4dc952200de34d039254e1bee06489c96fb0132",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.clearRect.path.html": [
-        "435d6906cf7f981432b196adb2ab1b58756d2379",
+        "ab813b1e9b8364e6b09f49ffc0012deb1d48e959",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.path.worker.js": [
-        "ab6f498bd0846bb44c790f7c247037a77f4c5909",
+        "eee973df5a346477943a9a7d8fc78d8edbd5e4b4",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.path.worker.html",
          {}
         ]
        ],
        "2d.clearRect.shadow.html": [
-        "d543d73240c30f873f3ec238be46e7b8bdd645ea",
+        "050591d620312ae22d6cceff50e6ca8f5975a42f",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.shadow.worker.js": [
-        "02740b85d00c5be98671b677a674ad8450da4682",
+        "74ac17c1d2fa0fae1e1922cc7e34c4f981f9946b",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.shadow.worker.html",
          {}
         ]
        ],
        "2d.clearRect.transform.html": [
-        "d861e75788f36aea73b41c98094596ae458813de",
+        "cca3c4d32bd78cbe594635999a6d8810c20e5b23",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.transform.worker.js": [
-        "bfbaa92fb02ca1ad14055f0194a007f16aba433f",
+        "8b76d4e0ae9de2862b86a7439ff2b42f9b4ef1ce",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.transform.worker.html",
          {}
         ]
        ],
        "2d.clearRect.zero.html": [
-        "a418fe62b5c3afe95596282c41df9c074005707f",
+        "69bbb5ecc7ba417adb02f3e519c6d747e53fd3ba",
         [
          null,
          {}
         ]
        ],
        "2d.clearRect.zero.worker.js": [
-        "de87699bb4d70ec22b250ab9b1cc4ce8008217a8",
+        "24c1c4253f8e53f338546c5d09d86c3db6d2fb05",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.clearRect.zero.worker.html",
          {}
         ]
        ],
        "2d.fillRect.basic.html": [
-        "f39d9ddb9d4c91d5bc99a9c64c6ab94e1d4c5465",
+        "bad032bb7c718ed91af0c43928986eb38612d539",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.basic.worker.js": [
-        "7d07bbd00e896569d62a61504cc1a306d88edce5",
+        "3a42a2a13b1b5c0c900b236fd626ea81aaa52de2",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.fillRect.basic.worker.html",
          {}
         ]
        ],
        "2d.fillRect.clip.html": [
-        "d39bbc96e85c334e44223adb692861e2badec3cf",
+        "7043c2355bcc8090d4bd375b326910a7ba4e18de",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.clip.worker.js": [
-        "0edab03b0ebd501ba3e06d7c617a495f0e6fdc33",
+        "926821ac96dc03f7068a0fad9b288f3063877ead",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.fillRect.clip.worker.html",
          {}
         ]
        ],
        "2d.fillRect.negative.html": [
-        "1802e96ff3e28b98d92b219f73de7b97914e09c7",
+        "880e5700bd3db126d01cd71da75273e0bfbb4c22",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.negative.worker.js": [
-        "9acaeb4941d75049980f3c707f498feecbbb0d79",
+        "b868dec9ff66bab72d8baa95ea0605ad6fbaab58",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.fillRect.negative.worker.html",
          {}
         ]
        ],
        "2d.fillRect.nonfinite.html": [
-        "70f91e1d2ba06e76a50fadae1e98f2031e8184bf",
+        "0d545e9f3fa4f864685e10d1dfe8e5b0c43f7c1c",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.nonfinite.worker.js": [
-        "dc429214a12998e00cf1687ab09f82a64d4d3b3c",
+        "418250e4bf99ee32e8ec7bee3c10b296edc2aa29",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.fillRect.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.fillRect.path.html": [
-        "8fa577e680ccb2682d2c688a661d3c185dc47405",
+        "13974b7e2ab8f8ef456e65309eab0d0f787800b3",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.path.worker.js": [
-        "d8a5e00ad8444c2f0faead7f6c218929f2e30245",
+        "0200fc568eeac3f722fad7749614dc21c91fdc72",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.fillRect.path.worker.html",
          {}
         ]
        ],
        "2d.fillRect.shadow.html": [
-        "71c677d092a16bd8daab1cf0c7c54435d39775cf",
+        "f3b015f25a79f5872bd09e2919ab6cfe10eff657",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.shadow.worker.js": [
-        "3da576dfd64a1739e5c934b8d5e6423e1571fe73",
+        "dea83df9aaea1b6a2da95d7d99fad5f283b1099c",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.fillRect.shadow.worker.html",
          {}
         ]
        ],
        "2d.fillRect.transform.html": [
-        "858beb448998a81f652ac241bd26df0fa3f10822",
+        "081ac763bdf70e936aa10ed194817368dd6fb3e5",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.transform.worker.js": [
-        "4aed159862ab9ec58fba80f0bad5b4bf69acc80b",
+        "8d0cb83c1bfd5875c04e8c9cf1f5aeece4b9c69e",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.fillRect.transform.worker.html",
          {}
         ]
        ],
        "2d.fillRect.zero.html": [
-        "f5d1f1dacb85edbef5c487db6984397be2c8ff6c",
+        "3f015475d5393f4903a1eac7613ad9227b2bd580",
         [
          null,
          {}
         ]
        ],
        "2d.fillRect.zero.worker.js": [
-        "a034c0caa2d6bd5eea9c4a9184902f0812b10c4b",
+        "48ee67ae7482d42bd0e39d4f45480ee816c0111c",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.fillRect.zero.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.basic.html": [
-        "489754a0fb158b8d5cbfc92b9710090159b8c47b",
+        "caee5d67354d8685cb1a2b04d3431c47d03b89c2",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.basic.worker.js": [
-        "39d8ac70546574e75672f5c33f2aaf872f6a8db0",
+        "304fc5ba843b394b775ef8065e569642749add2f",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.basic.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.clip.html": [
-        "135b68548440abbb4b2aeb8fd9625055ca61c548",
+        "3aa5d0392ebd9022bc7566d4dad5f0e6c81025cd",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.clip.worker.js": [
-        "0937ac4e0af86676b9ade9756cefab6d2fc53a8a",
+        "d5a50443d3a242e6f1e3db07586e2ab0d4b0455f",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.clip.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.globalalpha.html": [
-        "6e4a71899b552a83131779ccc84059955880379b",
+        "a470939455b904e4690f08a5191b9dbf1df568fc",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.globalalpha.worker.js": [
-        "25538b368e0eb5439118c1314d74f022029c1833",
+        "2556f65668136f419a3fc319bab2ac06d082719b",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.globalalpha.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.globalcomposite.html": [
-        "ca2e49cbcf0f3c7533d336dad7c22ee6692a2615",
+        "bfca74c48af751a95b48e8fafeef35e4aaaa67b5",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.globalcomposite.worker.js": [
-        "86e8f32ebb3375d91d832c9e4dd943578d76a94d",
+        "7c9859c7fb3a4cbf1baada913d377554e2844641",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.globalcomposite.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.negative.html": [
-        "c2d3f9b50ccdf701cb6c0ee16411b7abe689d498",
+        "04f33b184cd500be80a9011def7b584bc4829434",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.negative.worker.js": [
-        "7df75594ba22c8b86bd1dc2f0f593bf843d5c630",
+        "c80a44680cac581903ac498806278a2e2f9bfe27",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.negative.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.nonfinite.html": [
-        "de1617b157b9870c70e244674d70992e2479335f",
+        "1688912ab8903e8ebb434536c731a4c8f88f9c32",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.nonfinite.worker.js": [
-        "11efdf8a66872d20dc131fbfe6a488d182922019",
+        "4c1bc4c609d2d1bb1f50097bdc1151d984fc83f8",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.path.html": [
-        "42891df44e4db2549c16bbb5d033bc413cbfb743",
+        "c3d80bf299e8304001d5c9d8ea98c7c311c3f393",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.path.worker.js": [
-        "81da4d363a56d810916922960d356efc1c4533d3",
+        "436bd03107d4cd8ef7b235e346e94ea6e6c52928",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.path.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.shadow.html": [
-        "44c98389490d3ecd63deff42dcbe8bc5a41c24d4",
+        "e80d7511d435f73db1f51572ce7a601d37099fb2",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.shadow.worker.js": [
-        "7b51e5e92b733d11cbcefd2ede17977bbe52c3d5",
+        "13beb42ff091af7bfabca363dd581f1cebefbd27",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.shadow.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.transform.html": [
-        "fa6676270aba6f10b91ca3d7c4c4f656fd6e5787",
+        "2b44d0c627262023808a4ffd2dbd4612362f5c93",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.transform.worker.js": [
-        "c3c2863f32f575a45f764ccc6c9f430f69eb1020",
+        "5958cf140694a2e306a0aa63058790b963e339c8",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.transform.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.zero.1.html": [
-        "d663833f443b8fd4c6646ff5bc2bc3eb03eed94f",
+        "fe4d77baaa988c201c34d7f91172c3772301d06e",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.1.worker.js": [
-        "10750ec9f19c0ebdcbb5dc568d0c95005ba917a7",
+        "be3da7c88a846f47567d2c52e01069abe597c8f1",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.1.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.zero.2.html": [
-        "962502f2e8345a3cdbfef0b68c77ba63f25a57fc",
+        "0e234f85e58d3c33028d03495a6101c77b7e60aa",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.2.worker.js": [
-        "eabc38837145c212ea682e6dd14d756a5514ae6d",
+        "ab24ad34127f6afb269bfd78c438fe6ecb0aa9cb",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.2.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.zero.3.html": [
-        "079e84b17d525558f7975f5f32621a4162c39f0a",
+        "0145b2e412c298ff157bb828af290d47baf93458",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.3.worker.js": [
-        "452fd83aa9edb54609f4f75d711345ec68cfd07c",
+        "d9b365f7e8072becdfdb48ab73c4f435099b80d5",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.3.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.zero.4.html": [
-        "1cc44b7c29b754a98bb59d8dfb99210f45cab02f",
+        "d0c284f8e0936f82048591113e5e4ea524b5a499",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.4.worker.js": [
-        "94d407293d618978a08bc89106cd0068a2abc8e9",
+        "23513a47507c926d161f5711e7583edc20f52106",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.4.worker.html",
          {}
         ]
        ],
        "2d.strokeRect.zero.5.html": [
-        "a3c5a041e1c9755a5f8609504e4b9c9fb4404266",
+        "2441354c90766b433f1d11695cdd1089b8cb0118",
         [
          null,
          {}
         ]
        ],
        "2d.strokeRect.zero.5.worker.js": [
-        "9846ec3c3397b2e1a4abd3a7828e3b2c7af59693",
+        "0ef9e6772544e869b29c106d810efd4501eed65f",
         [
          "html/canvas/offscreen/drawing-rectangles-to-the-canvas/2d.strokeRect.zero.5.worker.html",
          {}
@@ -471859,7 +473475,7 @@
       },
       "fill-and-stroke-styles": {
        "2d.fillStyle.CSSHSL.html": [
-        "d89a51f3c44d0c5aa99755f251a71a659a74d73a",
+        "af5b04170d4101a15d10a9034146c90518ae00f0",
         [
          null,
          {}
@@ -471936,1694 +473552,1694 @@
         ]
        ],
        "2d.fillStyle.invalidstring.html": [
-        "a6e86cdfe0fbb11e3c8c89fa8a3a1d4787fc1e84",
+        "260554c4bcbe9aa6c353115160519d733b9ba40a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.invalidstring.worker.js": [
-        "43ac52e246f9a431ce76a2e3a189888a6fdb5529",
+        "4e4df4f810b60cb105d11e79848361e8fb1e2258",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.invalidstring.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.invalidtype.html": [
-        "a8de9932309b075a6bfedceb5c52e46e4d1b63f0",
+        "53c0f77c8ce8759d5d7fd36c6d8722cceade1cb4",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.invalidtype.worker.js": [
-        "f8b661aa221628b96f0c33d2b5465a60169812ca",
+        "19b31206388a470d0302a51ece336f06df10b1e3",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.invalidtype.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-1.html": [
-        "7d6e78966dd4c4050182edc96eb3776b012e1bca",
+        "d4a2466b7d3f5adfc8f36edbd91adaa6f6a7bdaf",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-1.worker.js": [
-        "99ccafd4934f8395a8c23313a6d922b99001b068",
+        "074d796caf34decee4143464308647276e2abaad",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-2.html": [
-        "67779b50d096b9efafa9c91639e360b3ae766a0e",
+        "6853ae51ea52d1927688ae0892a7b1591bc836f9",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-2.worker.js": [
-        "d24a0dea8eead25029dda5776b707a9111f795f3",
+        "a4226cf8cad12a1c4611203a88313e0aad36b714",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-3.html": [
-        "078813772706e4ffa10dd43eb1ef35459a900cf8",
+        "62f4e48ef3c495e728389d8ba9f4355b7de4674f",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-3.worker.js": [
-        "2e2f03438ad8198f84e39ad4c306f93f2b99f05b",
+        "de3e3791fa794dc75f0e9f50fb17fb3977c4a0c6",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-4.html": [
-        "5989679d7026a8172ca64a1832af0cb377083ebb",
+        "082ddcd75ef66e09dd28065f32814088cd39cb9e",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-4.worker.js": [
-        "8cd4d66bc75d94f7d3eb3510336a282f1fd554bf",
+        "2714bdf835a2281a1e6b355587a8d0f6ff64c921",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-5.html": [
-        "f60b97ee644173cab3425c8ac102e0e3e0c23d1a",
+        "55f92e17ef8e97507044d6366924e0a7caf50d36",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-5.worker.js": [
-        "932b6969051fd4d6f6bf7250438e72cf99a4f6a0",
+        "ef3fe13355b295f9536a5faf9436784dd2e17f02",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-6.html": [
-        "39d5a62fad67cd2516b8dde95b1dc587fbbae12c",
+        "74657fca63e0a69f6a1a1d8c67f4a4aad8227fe2",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-6.worker.js": [
-        "572e8ccfcb332345380a3f7c4ff102193594171c",
+        "a36af9a563a310c923822a5fae828efc800215fc",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-6.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-7.html": [
-        "a6c654ffc1a1e2b9f12a48b15548a5d994ecd74d",
+        "419b15f72e1e5a46148a7a4faf30c4d5ef21be28",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-7.worker.js": [
-        "335c2600114f662f4157f932d869e2f3bd304f07",
+        "10da1141aac1c2301e2ae4a83120693fdbf2355b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-7.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-8.html": [
-        "644015f43fccad5618fb4a222e7b04cc8dbbee51",
+        "a5acc80ef8cd88fae12d8a4383a24c083615b654",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-8.worker.js": [
-        "0f8fb44f37e3d637dd447e99552bd6aca2e2c8fa",
+        "e12f96350b9e46f8897c7eccdb9c65b74f9fae03",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-8.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-9.html": [
-        "506f235e650473b5440568d99f87873c1b8ea2ef",
+        "dc184153996c238423d74b99867c4aec8f923e91",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsl-9.worker.js": [
-        "fb2c39445545a6136ec010860c601fb015c48e63",
+        "51de0e0b15ec57358f761f30d358b3925d67a733",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-9.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-1.html": [
-        "aa24927e2b9f5d0d0b9996b3bc15480a1052b5dd",
+        "84b80615be0f1d999fbbfb6978e8eff0e51de7a6",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-1.worker.js": [
-        "2b0fcc89f24f53e6ff2e591d5291f0643c708af8",
+        "2d7abab3be68079c154531e8222a06dbb158a8b0",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-2.html": [
-        "6e629d1672606da050d6e75ec9a9b796eef439c2",
+        "a3f2c67ab4764f6755d6e1be0a6fe21adb6759e6",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-2.worker.js": [
-        "4ea0a256395e704d1f90097b0332629c3bdf11de",
+        "dd66b1d079a160f3f0ac055222987c5a480657e9",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-3.html": [
-        "d4ceb4d4655813942ee3e90992692c77f26edb86",
+        "5b809ba567b7c0b8b5cbdf2778cf747353349848",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-3.worker.js": [
-        "8f21b2f39b897f3d3184f92f1efbeeec2cf12347",
+        "7ef6d8f4751a1219ce3442913bd1beee5724f0f6",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-4.html": [
-        "5c63ba2149019d1efc4e82c1c9eb39ba9269ae30",
+        "3e063664fb95e8f5754157ad62447591efccecb6",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-4.worker.js": [
-        "d138da57fdb7a7273248a5b320468f957cda5653",
+        "ed1dec016241581d229804d769ec3535f1dcef4a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-5.html": [
-        "9320a1c2c80d76bad95a1a04face6a4b8106e771",
+        "34f626a0a5557f1b8e5fa698029114c657317fca",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-5.worker.js": [
-        "80ad13a21b6c1b0c005cbdb1897c8aa1cbcacdd5",
+        "89042269ab29bc945bebd9ca1dd734c1fde0cff8",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-6.html": [
-        "d4b0499e0a4e4d8b0e304080b7d769066c4ecc6d",
+        "3c1a23bf37e5e1ed727841b574d402b8e7ce011d",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-6.worker.js": [
-        "4afd20c40b1461c85a636d0bfcc5455a90d8c803",
+        "645081df5e1f67c4a25ac534f64de45cd5ce8761",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-6.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-7.html": [
-        "10773ee1f667e91f74c3decb9f2bd6dff84a1d16",
+        "cc874e8fbe1f5f305ad1ecdadfee8ee4a5a742b5",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-7.worker.js": [
-        "4fc3e4d5710d09cb1aedb27f14df307f379e7547",
+        "f42602ebc3a7f10cfc4f9d1fb75af0ad3d22ea48",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-7.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-8.html": [
-        "97e52102c8f3049beefec2c7fb2110db2d0f3ce2",
+        "75014364817a49405a41c897368b6b4e1b03fe83",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-8.worker.js": [
-        "af502b3c707e606f743c5ab077592fb22052172a",
+        "376cb94c904147f1cbca6ec2cde7b6ffd3c46eca",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-8.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-9.html": [
-        "235f586e441b02836fdda38b9e84d2076fa32a36",
+        "f759e6910bf54fe1611683573f7ec0632dd28afa",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-hsla-9.worker.js": [
-        "f048dda389335d16f0211b84d72b336805d30a6d",
+        "58f404175d08b45d3c3d96ccaef209c92171639a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-9.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-1.html": [
-        "1c38fce40f532d7faafd04e107c4f95dbc1002c7",
+        "44648751a30565595d186ab5838fa07f1b477adf",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-1.worker.js": [
-        "b35ee79812fe310b3cd64276085f96472e4e9941",
+        "34ecf3d3186d696153e23b391258dcf9c7cd1f74",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-2.html": [
-        "5efeb47bb3f3f77fa52261e371e6d03e330e8783",
+        "328d731e491cc1e877d361cbaffef9208ebd0dad",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-2.worker.js": [
-        "0f996ec2811085562cd94dd68619916682029a7e",
+        "958d5df352edefaac8b4fffb85e649286c202507",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-3.html": [
-        "34ce23e0c1cdbb023be0702dc632991ddb8413fb",
+        "1dc99c24c7b3f36d77fac940b0e775310501d884",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-3.worker.js": [
-        "f580f7bd7309777d0a6df9e077eff91c12733e19",
+        "f82df16e9adf4b280699b28e8adc01ac954dfe52",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-4.html": [
-        "c35dd12bd2ff830724ec861ec4b8e4dfda928364",
+        "1b72c4f235d80624176ff4a165fccf876d0de740",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-4.worker.js": [
-        "02656cf36f47c15f95efac9152b88393663a92ca",
+        "08dba89ec817c27b3a56aeb6d78491147f10885e",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-5.html": [
-        "865c76deac186c9b07331f28e7d6e863fe8149a0",
+        "9044fe81a4e8561edde7aa8a78448d9494f9c51b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-5.worker.js": [
-        "306850a5d919eb42dfd38f509d5ac707c553513d",
+        "27ccca6c64f58c2a28f7aa802298e5e2fb8e6534",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-6.html": [
-        "9b17978a4685f069ef079b89659666095dc5d093",
+        "66cb90876f1e52eeb61316f312f572c8f13ce5b3",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgb-6.worker.js": [
-        "38c492c50e3d0a22027f656462d01c5efa02c460",
+        "3ff4312fcb2108f8e06ef88af16b761634cc4a7d",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-6.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-1.html": [
-        "a3c18c5a7a910841433f70883a80a2ee21497041",
+        "a0d2239244afda9c77649c8b582a0e8981e6dfc8",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-1.worker.js": [
-        "2200d1d53b65308ba6b77a5df7c4b35d3e1a4c5f",
+        "ef45434cabfc3741724f41cc9a455fe241696d68",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-2.html": [
-        "20f99598c49cab394dc057f39bf186e233317f4f",
+        "96dcbf61d8f24c87930507fb0d7d552aef8010c2",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-2.worker.js": [
-        "8fe773cc3bb2dc3415b271881adeac13c84249f4",
+        "e03f5252e9f26141c80f9090c458a99357e0af6a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-3.html": [
-        "6172eef2a5abb5f33f003043a0addb0538daf2bd",
+        "f972e83696f3477b7ffd64f70a5a454b349e4574",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-3.worker.js": [
-        "3582e7d6b70067783e8190c0a246eddc34151067",
+        "3bc693f212c501da8eca2165bfc3080a92086b98",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-4.html": [
-        "37d02e60de1c16ef2739229cda6bae647860269f",
+        "6825e8658afaefa9f81811b07a50658f07dc8f52",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-4.worker.js": [
-        "15d3c3ab5395b92b518c479b792da980fb9036f8",
+        "a50cc026bb73cce7e3398fc337a69d36872c7e66",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-5.html": [
-        "30a418a6b7e77d6e37e76e67e2f261b28a12b9b3",
+        "7c8b19c80d4aa4f1a6e75c343ada94a6065dc58e",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-5.worker.js": [
-        "a01ee82555b6e0fd171b69bf4e1315e08a8fb979",
+        "e134e34b2975fb97a80ac672820e335ce9501c8e",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-6.html": [
-        "b7f2287732abe500dd968fb4748f4aa390533f2f",
+        "b63b46f9d25894aa701ff6b6ec19312e4fa0fd4c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.css-color-4-rgba-6.worker.js": [
-        "8df045de2eb3a64790265775a5aac89c2c297301",
+        "3e401de74d50b57018c630df1b0bf1e7d0b00e0b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-6.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hex3.html": [
-        "ca2fa741699a539b90b2fe62a0b5661a45e9dc43",
+        "90d3e6037eb1739ac78c9ca926956f0b9765fdff",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hex3.worker.js": [
-        "32d4bad2c1798bb3765422f196925058b30e711c",
+        "9f0d0a4322a18a628fa450d3bdaa9d7cd4b6d7fe",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hex3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hex4.html": [
-        "591d19435ea8579aed60f4a44b940671add342fc",
+        "d10e3a891063d38d6ac64e7aebaffdb5219a1a5d",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hex4.worker.js": [
-        "cd73f70963dcfcd96c0ae3f9ec438206e20dde20",
+        "fa84ca13529eed306e6608572818781fc17dad46",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hex4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hex6.html": [
-        "f6e1c4f23f0ba7f0222a1b8cf9a04c61c26836cb",
+        "69394c9a83112f3f4bebbc3c40248bd89f54eb71",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hex6.worker.js": [
-        "55185d449996df295b01d2a4115c19df80ae6afa",
+        "cb432b4f99efcbb3831787063029b8e8c1bd3a61",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hex6.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hex8.html": [
-        "f24f6bcf9bbbe5d0d3a3c4be0afafe0afe6c6d06",
+        "80abfe3265ed716ed3f2623451ad99dd5f2cd75d",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hex8.worker.js": [
-        "39e5fb5da8f7e873315f09a72454b65c7660f28d",
+        "e114569893e21dec798f91a99c988df10fa6ccf9",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hex8.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-1.html": [
-        "71b3d5670999fd54a9ba43c71f1ce09f8fa61319",
+        "65e5c1874743acd84a4b4be45717712f596224a2",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-1.worker.js": [
-        "71028334db21386ae3e14196c2333098278c3921",
+        "83d507c826cb3d572c94dada5e7f04d403adba2c",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-2.html": [
-        "819eebbd9b920dd1dc969ce11f1e4e7818692c8d",
+        "fdd78ad7bea0e49edd7bde99d3df9c81ad8f13c1",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-2.worker.js": [
-        "182c050398e4cd38ac1d86dc94b6b7547345c9a5",
+        "0dfc848716eb232600dedce6d96891958d4558b9",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-3.html": [
-        "38fb322d83023fb8784d0f66232b6d7ee1ea5f8a",
+        "51692444076aed27cc1a0ebd9b7a468d6f635198",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-3.worker.js": [
-        "612a31581f1829637d06fb5cf1499a29c90b6df5",
+        "54dec44d38ef6318337296524fb00bfb1de92e41",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-4.html": [
-        "72d8ce8430fe954eb37cccb48732b592fd450ffd",
+        "90f30ab92c33d302328b1af70b6842a30d738d91",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-4.worker.js": [
-        "f9fb8582e090a67dae66eb264e5ef09f0eab3b3f",
+        "43c20668afb6236a3dbdee5ede4d267e85d03b79",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-5.html": [
-        "33a373ae99df517305b6cabe968785f33f03cf24",
+        "7760e236fdcdb24125ff3b05262d8f88d0f91a47",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-5.worker.js": [
-        "ade7babd4d6e58ba6c1597891d05ee3ec3811c05",
+        "d4c95c10b24d0e739f1e29f145fd6828723357e7",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-6.html": [
-        "dfd80ad4774effbe8610393462a75697d0af56c1",
+        "795092931b77d981f2cd633052be09d67e2c810e",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-6.worker.js": [
-        "4669a0c631e77af096b13c6f7517e86963a11287",
+        "f5acc2df25b16e1bf75f972615df111ccda0e76c",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-6.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-1.html": [
-        "87232ccbc994135cffefdd7497e5b30fbf80c5d9",
+        "1b375468baf4d2529d6c2ab5c2e757ccf9b7a033",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-1.worker.js": [
-        "00ccf329be00d7d0dc7cf2a405beb2ace0c778da",
+        "cc3308d7ed60aa432357049d7a44bc065695954c",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-2.html": [
-        "2aabf993ebb95c3406340f0d7e69d3b34b6136bb",
+        "0133f7f50a3384d66d3835e8df6baa6c1c532207",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-2.worker.js": [
-        "4cce2df08c619597647d31d8ee0299eafbd8029c",
+        "48c23aa10aafa505eeeeeae6ccacd0d4fbebd82c",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-3.html": [
-        "8d2d6bc8bee44e33180560c3e86cac77cfef14dd",
+        "e35355c21c045354ce81e1470b63b05d90ae529a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-3.worker.js": [
-        "8dc92dfd55a0f2487f70835ed114ed6c5fcb2290",
+        "ef1ac418c9c42f102944438bf14ad3dd523c99e9",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-4.html": [
-        "a2e56df94dcd07ec5e07954c31ff4d40b816955b",
+        "c42b6f1f5d1babd7006fcedefdfc8eca491b0aca",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsl-clamp-4.worker.js": [
-        "89d33da8b8ab7844d8277dc9304a56a2c40cadaf",
+        "061685dbdef51b15c3c9824c2a9a2d99190ea12c",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsl-clamp-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-1.html": [
-        "f8e130e0323a2f6cfb2e2836d6cbb74f70f75867",
+        "0defd457ab0c9e750dfe9abed77bc5b77fe979de",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-1.worker.js": [
-        "69a322e74e0ca65c7188ab46528e690701489668",
+        "64a26e6ca3b0bd4a4e6686ebb95c20735a573779",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-2.html": [
-        "a38f62464cad67d5ecd8105c80b032b3101383a6",
+        "0498edd6da6ea49671ff6f25ab75f9e7c42ae218",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-2.worker.js": [
-        "34676fc23fe3145d52348e689b714a2ed4a91c44",
+        "6101f0e3ab719f45a7aa32400ce72a098d9142aa",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-1.html": [
-        "5c6a5eea2b2fd031c3bbf169afddf8c2f1d9335e",
+        "313ecf277cf8f85ad50de922707eb5bd4e3eaf7e",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-1.worker.js": [
-        "968684aad93ddb1ab44caf862bc775b8e142dbc8",
+        "8724efd28ab7ab0ce66e23e006bac3cbe6c2769a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-2.html": [
-        "35cd11fb7f1f1aa07b810c3d60f91ae5677336b3",
+        "761471f43ae1758778d2f363f670f50381206e30",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-2.worker.js": [
-        "ae40bbd616693d55de890fb11adb1c26fa4d7004",
+        "af4271c66ccb03ffa6899aadb29399fd419f17f4",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-3.html": [
-        "117e58f4056eec1ace6b484ded46d7333e556c69",
+        "287a23a58a29a695ee24f021c594b339a2e47334",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-3.worker.js": [
-        "7e61bec4196d079824e8f4037f9ddccef6437b1c",
+        "1e10a76dc27d54f1dd613e8210066b15b56fcf59",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-4.html": [
-        "31350f2470a9b2662e7356c21348288c2214b638",
+        "a0e420cab28a02d7b77197f4b24a5955a8c4c8fe",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-4.worker.js": [
-        "8a461f16fe168d9ebb49631110a9e773f26a9281",
+        "e746bc34729e08a7b581a1fac356f435aa8b70c6",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-5.html": [
-        "1476c2dcea1d8ea1e36cce60ca207f40b32d2275",
+        "06837197499586cd3709bffd011e6efe915ae276",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-5.worker.js": [
-        "a7591080c290fd30ba183980fdfcbeff466fc18e",
+        "61d86a8a95ffdd7e214c54f04670a59c11613ccc",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-6.html": [
-        "8514c70a2964d82ed0a1574c6a9f8e3becba05a8",
+        "a8106395194109814a4c7f35ac51661eb928b354",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.hsla-clamp-6.worker.js": [
-        "f19520cb90324fdf99851d9d0457b358fb39d830",
+        "57c0d587eee7892c44e3a751690e97ca8126ef93",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.hsla-clamp-6.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.html4.html": [
-        "e6fc9baadf2c91edee4182594bfe5e6778ce135b",
+        "767768ab2f7055c28db387ff2a7fe24004a270f4",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.html4.worker.js": [
-        "b4f2e00942f87ca80bb387e8fa227a1face5e0fd",
+        "a8b8552afb5ce16f053f017783cea37e488eaf6d",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.html4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-1.html": [
-        "3db32fe49de2f4138d9444aca6f177b2071f5757",
+        "1a227a436a4f7da23d08b0ef1a8802c096c1333d",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-1.worker.js": [
-        "97b03f75fb14f99217d7446cb71d2f023bfc608a",
+        "20fc879bc6299aea064d5be61ee8125a7786b210",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-hsl-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-2.html": [
-        "8051a63e9a47ecac776680345472b20d0d2234f7",
+        "36b95ed247a70cfcc04b5b607a8d706e79f0945b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-2.worker.js": [
-        "c3a8cc5026b52337a7ed6511bae0abefc0ce4ef6",
+        "c2c6fc0ace08a535e54051c23b35e6080e5f7699",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-hsl-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-3.html": [
-        "e0a6514a4ae1bdd8ce33d9ccf5e7741cb505b374",
+        "d208c6296b67d079fed24418015de4a692b39794",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-3.worker.js": [
-        "f64aa3efb29aea6ef20d5eb5f150c33a67004ded",
+        "c2f90ef320c52ff37b482f99b66547f223ebdf8b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-hsl-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-4.html": [
-        "07b5fd879a016d28d0b4b50153bcbdd018043e79",
+        "2fba5aaf9c68a786bc1f032350fcac02ed120044",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-4.worker.js": [
-        "d286c1963ecba8aa5df58a9395a3cef6a55e2765",
+        "6903ae94c2d5a9de65b68fd20ce8ac2c04b3ccdf",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-hsl-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-5.html": [
-        "ababebd7c3b454d7313d32036248a8b2cc8235fd",
+        "f340a52aa8c26db9e2857f00b63aaf510e1215f5",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsl-5.worker.js": [
-        "80e19172abb6794e1aaa6b2d855b704e95e8774a",
+        "8f0cfc0cba58cd82418b88b9f92b974db0a02855",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-hsl-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsla-1.html": [
-        "64fabf39f7cc74f4ba141c3ef805d37e9c9dbece",
+        "834a1b7b18e3f203013c4a30e47919db20553b1f",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsla-1.worker.js": [
-        "cb7086505643118382da91aedca6dcb1ad0bf2a7",
+        "45e074321e3b5836c719a7545bee68548bab7b0d",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-hsla-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsla-2.html": [
-        "6c14743111445947b47c945185a9164307c7d8b3",
+        "cd33bbf8007b859eadfbff830b6e106339e6133c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsla-2.worker.js": [
-        "6ba2fbd75a6b03b19f533f057c37178b8e33b124",
+        "e0d75717db7df46ada18354e8a28d6183d6cb806",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-hsla-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsla-3.html": [
-        "24d347d74cd659da412f8b2f10b509895fe3df72",
+        "fd01b7623af43fe43fa488fc1d4547a0bb02e100",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-hsla-3.worker.js": [
-        "139eeb01e10ef6e00cbe54a0d189a3cb4c35f499",
+        "4adb92bb6444650031424dce06b6ae36677a76a2",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-hsla-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-1.html": [
-        "39801a0b13166e46dedf96f295f4b2b9b64ba2af",
+        "f1e1b2ab37d8513ec2a80290b304eab29750cc3a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-1.worker.js": [
-        "b87aff85a739806a9a177b9a9ef624d0be1d18d6",
+        "450556b31be0fa3f2dea56a76b552a887f2b62ca",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-rgb-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-2.html": [
-        "d86e63afbcc6605fc95573f793d266f1ed72c9ef",
+        "dc22f99e3d3159cca135e191f7982d5e7871ab4a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-2.worker.js": [
-        "bf99c939f9392f66f9a2908f096efc5a110c0ed7",
+        "35217d1b807d7e3e0a03f14e66658ca4ab479ed0",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-rgb-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-3.html": [
-        "0b47dc0cf878bb8ee11927686f000311bb77cd8f",
+        "434c15eccb3acd8c759723c2ad6bfc60de72399c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-3.worker.js": [
-        "dcbdc50a8b44e1718b3d6a2766ddffbe36463153",
+        "28200cfdd5a1588e96b20db183a011b22b94ad44",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-rgb-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-4.html": [
-        "c9682085e9fa3283c76304b79466b6ff27cc5158",
+        "58ed0e7318ff7428dad5a3cc457efb066cab0712",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-4.worker.js": [
-        "3cf1c8dae4098998fe3ca0b2852bcabe2807f39b",
+        "1830996c26b4b5afdcf62f7cd6658e6b643fda0d",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-rgb-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-5.html": [
-        "75de3cf8de3282b041791857415fce55106bd464",
+        "95643739c411639dde22fb373bd886940ddc13cc",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgb-5.worker.js": [
-        "a8277929ac37126f1817a74b8b67b7c97efbccea",
+        "4591bbde34ae0c5b877056fa49baca8a54a615f3",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-rgb-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgba-1.html": [
-        "074c4bca95c33192cbd9c0d4d5cb9f0c685f6dcb",
+        "5ae093eae1ea2dead69899ac1b814d27cb518330",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgba-1.worker.js": [
-        "565395efaca934bb55fb1d20437b7dbd85b96358",
+        "d9a315c98dbc33b00635e201c10ca9a25c3f4077",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-rgba-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgba-2.html": [
-        "a94393333e15962d171f3dad2101fd3914b4a850",
+        "036f389153a121bc0218cb63fc985a26f6cb2ef2",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgba-2.worker.js": [
-        "5768745fc5b4bf936743584b62d638749d2c427f",
+        "1fc2f5d86380c0f1b8fc315db8b9aff757d51e49",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-rgba-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgba-3.html": [
-        "d87f0929c4b04757e6b871ed0a97aac86cedee7b",
+        "663557987aabd226de04d92e906210d9a2ffdd72",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.css-color-4-rgba-3.worker.js": [
-        "e373b2f632f8efbfed33d7c016398ac461e10836",
+        "1eadf9125b03f28885f30b0155b6a57aa97d5ef5",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.css-color-4-rgba-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex1.html": [
-        "e27c89a799cbc2a0835ac78e4a802985700206b6",
+        "83e1c410f5e8c84911ef14c77476775f1d2dfd13",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex1.worker.js": [
-        "e957f8886dd8e6c7784f8afd9b504e1d9a37110e",
+        "3807fd331127612e13585f0293a332b473d4fa4b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hex1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex2.html": [
-        "acd620c97c5a11caf16b816dd55e69573455432f",
+        "453ec4bd5c3c0e05671436f2653c92660daae1c3",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex2.worker.js": [
-        "0863e5fdb1795ad370deda35d5cab3c9e5cb874c",
+        "9bb7e2c33c8f06e6fe8075b3942402e3cf7c2bfc",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hex2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex3.html": [
-        "14d687ba2df905b877888f189b60653cad6045bc",
+        "c1d4e8c1e85346d0cbecea01718f43bdb0438b28",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex3.worker.js": [
-        "faa66420bc6c9968f81e0a390c785e28fb4155c8",
+        "4eaa0b0d0f57cc927155bdfc11e49f5fee6a065c",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hex3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex4.html": [
-        "98d155bcd09ca13d56103dd84cb91d4f4c920713",
+        "89c23a0074aab0677204c632293798989caf0222",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex4.worker.js": [
-        "42ebb181bd7b8e98d30e374e595f94085280e48c",
+        "ceffb191b2bab78f137bac9c0a68136cece4d70e",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hex4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex5.html": [
-        "72eee71dee92b268cef0738447f6aee4ba34c14f",
+        "4d62d09be03615fded2cedd04732d691610e51c2",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex5.worker.js": [
-        "d864a8830705e8d1963aa41b8c3b5adb1838abed",
+        "7225544f8b71b4399f48ae948ed5f359c424c83d",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hex5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex6.html": [
-        "9ffa1efc4a9b536e2d8cf85fbde7f8bfa80c7e5c",
+        "69dfdc723fcead0bf0a3610ff68c6318e951d78a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex6.worker.js": [
-        "d0c6098fa073a6a4ebda70d874cfb292fef65632",
+        "2e5a93b49a9b502d8137c29bb4a683281210bd15",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hex6.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex7.html": [
-        "83dab53912fa8a2a5b7f75d032f49ee389339743",
+        "2be93ca69a8e7a0123f7f878de59959fbd422814",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex7.worker.js": [
-        "453e72f8644caabfa200082a4f9ddfbee21567de",
+        "fbd4a887c5e7b52ea467abc504456765412689ef",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hex7.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex8.html": [
-        "9797b81de2e78b193583dd1ad79763ea124c72b5",
+        "f67758d42ed1900f39291bf3568ab3cf62974233",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hex8.worker.js": [
-        "2c9c0d6076fa5d21477420906b9fd6401f515181",
+        "fcc230ce9db65dd0d74c1c3df085ef18fb6aa683",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hex8.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-1.html": [
-        "fc8a53e67a0543dc936e646c4e9f5ca9a963ebc7",
+        "54e6711137959fb3e5d070e5a954b1c567ce0d70",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-1.worker.js": [
-        "f984cfb4a369ab628544d50256f7e8425a3e10f2",
+        "3b0bb9165b3518c5bc5af51ff2c2a72f5d3da7ca",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hsl-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-2.html": [
-        "2375c0d1d9aa99e8c050fb45ff1a99b598d77ecf",
+        "7614b8c34d0b9569bda89ede8ef5dcd63294990f",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-2.worker.js": [
-        "1987103046fcb252ea467f5a556df6f8fce7c516",
+        "ec906f7fa19b4e27c15cb325e963562f16fc5902",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hsl-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-3.html": [
-        "7769b878054b5085f573dd663160df648a908c81",
+        "13d19ac92406ab9220848a76f3d158992b2df22a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-3.worker.js": [
-        "cee63524943cb3d2ea3544cbd2890661e83598cd",
+        "370eba209785d781cb134d8ffe22ff6f650d2372",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hsl-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-4.html": [
-        "fa36f0c590248bd1695e675fbe7fc82345001cc6",
+        "9f01aa2180011f5f7da4f55de709357b95c8091f",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-4.worker.js": [
-        "cb96b622051603e5c1643793612aa7ce0e60a71a",
+        "9d53d26c96afe5058893c26a035d47ac66b79525",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hsl-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-5.html": [
-        "7d17ebf884990482bf2d2b5e191af89cac065c30",
+        "23f38067a9ff7f816debda760338a3c9d297c2cc",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-5.worker.js": [
-        "0617cdadead84a371414aeb1917618676368db0f",
+        "98f4b1c7214e5e927e7fd8bc9bb09b22812dbc30",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hsl-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-6.html": [
-        "65d4d2c4152ed603e73f1ab32394668d2c609d59",
+        "405a0e52b24a16099ccc7a64c58270a98604ae2c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsl-6.worker.js": [
-        "656087e0e2540ea03de83ba2989d97e2c3e665ad",
+        "87185470028a255e78ff55db70c8e53f6a1e9663",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hsl-6.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsla-1.html": [
-        "0bb55b869ba9a5fe4f5879fbf0016b6379abe97d",
+        "ae9d7986b7a82579f88a7a6bb4f0463cb9b32b2b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsla-1.worker.js": [
-        "152eca19477e9660ebd007e08605089366d519f3",
+        "b6a70f2a421473d67a3b86bc1139d4af79fc56db",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hsla-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsla-2.html": [
-        "8da3bb73ea6d3bd4498871850ac6f00edd55786b",
+        "de123411ecd538dcc99d6230b799c167ae953f73",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsla-2.worker.js": [
-        "3af68054ddf6bf77fde77e57f4de5448fb4778e7",
+        "809c805352d8404d9e440ce2a67b40c7718701a5",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hsla-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsla-3.html": [
-        "a41774f50cb21c35bd0c43ec8876eceeb426c2fa",
+        "beab07b8624ebd6530418a03b8cd7b20fbdf0033",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.hsla-3.worker.js": [
-        "d78c3ec6952618991c86e229cf5628a867d4efd2",
+        "4d2b53bbeba2026f83acb3067f6493268a8ec829",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.hsla-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-1.html": [
-        "f42c5e00fba946dbb6cffb43c326a78d7844e391",
+        "4ac286e61602336ce2ac3e7d53f9079d0640bef7",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-1.worker.js": [
-        "8acea69fdb3658b997efbed4c9acbd05aeda381f",
+        "ef588934c15fcfd14ba05e0726450b193a4fac6f",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.name-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-2.html": [
-        "42fb3fc3b9fba48fdb87bc95bb957225c303bff4",
+        "6b54c1816b95e928e562fb57a0d153d4320e0af0",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-2.worker.js": [
-        "7c2bf79d7f0ba8948fbfb99f1716848920aff7e5",
+        "b66a07419c1765b4d2316f49a3d99c1bb1ac7d00",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.name-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-3.html": [
-        "8d351754c3e440ba163eea999328ceab1b0bc6a0",
+        "05cfaa906d630b9f379a334321cbe5fc88262c38",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-3.worker.js": [
-        "3f5a115c08d562c2192803d90b86bb8ee3307e41",
+        "da51a4ab2ab8de019c558f29dc7f6d506a201ba5",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.name-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-4.html": [
-        "b2f4b4f69cd463c3c6030fd086467a82f843da01",
+        "47aab58ada205e3429ec95ced745f542bfd4b0ec",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-4.worker.js": [
-        "2299ff85277b36bc22389402d365f3362664c7a9",
+        "c167c2b9556fcd046df045dae8f28d5b51279a20",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.name-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-5.html": [
-        "4fe8e67683564601e87904aeb89adf312bc613a6",
+        "af19e193e0476cd95b783ba80ea92e813d51de0c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.name-5.worker.js": [
-        "8280800d13e2bd121461d8bde793a6090b1d7e8e",
+        "8fe3a9b13e62ab214392b26fb455f642766d981f",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.name-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgb-1.html": [
-        "6e4fb4ed6f14c74350609bfe80535109ac1e11da",
+        "300bb85ee2cea3b0b66bac018d7ae331319948ce",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgb-1.worker.js": [
-        "ae7cb8b154bbd14e8455df9ad9a87f3454d22a6e",
+        "3c97d856c7a5127d07170c602f16d4fd49442b94",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.rgb-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgb-2.html": [
-        "15aedf0b805f3e4e0325562914e30fb9596297f7",
+        "8bc9c079dd152c8a3361a331e0b882bfdcc9aaf7",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgb-2.worker.js": [
-        "1d09da7389a4723a510d126375eab11285cfd907",
+        "7e4e27c9142455d71512417dc44a8e3af7f5a36e",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.rgb-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgb-3.html": [
-        "93c0a82485d22ef928d470e9ca91bf687ba91443",
+        "11e93a1c724245e45324bf6f77c60e1cf978d63b",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgb-3.worker.js": [
-        "21ed0b90bd75f6e4adbfac7944492f7469ede46a",
+        "59d89f7b519e7608e596d1c36588858fb46becfc",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.rgb-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-1.html": [
-        "7ffc5613126a0672ce147405a6b23723b93b0eb7",
+        "3a0b39911735afd570382c8eb02499d1e5849b69",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-1.worker.js": [
-        "450ed24d48a00a596bd991f29f2ac7ca7fb1b256",
+        "efd7640594f25064c75a0067e8bf1de19b4df814",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.rgba-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-2.html": [
-        "9771a390a8941fa1460d0df9a6b21a3d4ffc7c2b",
+        "28a218052043a9d82aeab014f00a22d2b391fbb6",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-2.worker.js": [
-        "974f09cec6ea878e69be94899df2c2291552df4f",
+        "dfdafb1a7e05d568e77c7f55ac17144442a30aa3",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.rgba-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-3.html": [
-        "052cda3862babc261a0d3e26696d4c3a18bd10a4",
+        "d9ad0be5e50ef8e96390dc4d11fb6147ba53d367",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-3.worker.js": [
-        "e97be9122a2e38331aa4b1f967153bcbf2c307cd",
+        "1dca0eb9b14f280cf1ad8d7db95729b852308ad1",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.rgba-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-4.html": [
-        "58685cae41038a1b23efe9380ece324947bd4b3f",
+        "db71a88e704f02e1fea921e905d9dd5a40d923f1",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-4.worker.js": [
-        "a9a4e97a9f639abe652a6aa347755a1a15ef8706",
+        "dff64ba90730f3314bad794788dac828a1d1be5b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.rgba-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-5.html": [
-        "23c958e5ce3eb7453218276488bfe0ed80005ede",
+        "00e7791bcbeb940282e8d087f3bd10f7c622f39c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.invalid.rgba-5.worker.js": [
-        "e354cc1b9c77b714e456bc3dbba83f12bdb0e4be",
+        "80a65dcbc2d1c976013d5bb159f30eeb4ee84aa2",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.invalid.rgba-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-1.html": [
-        "e487acdc3d717130c850e79696c3416923536abb",
+        "ce03f7b840351baaf203d6e3fc22ead5174d9611",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-1.worker.js": [
-        "1abc22477dec731dc51dfb473ed3e3cbf1677454",
+        "48cf6a72f569c3ebd71092406b010671aebb1ee0",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgb-clamp-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-2.html": [
-        "3af37d4e1028b19860b90cfb83d3c9d50103f309",
+        "e4f9260ec6b43d3f8cfae093c39b19484817febf",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-2.worker.js": [
-        "412e782a226a70d28ed2848963ad5c3214e6a2de",
+        "70adec462ac60643ba20d2048781b4a3ef8fd58a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgb-clamp-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-3.html": [
-        "f53615840bdd26d2ef897f051efd799358943e10",
+        "73bbc00d1eda0e40f20125acb05671385f82ed72",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-3.worker.js": [
-        "6309fa99576bdba436f103555ac1379f96301082",
+        "883328b42d75b254fe601f50051f9d297c63b26a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgb-clamp-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-4.html": [
-        "13ee1e7b685d8efdbb85b6e33989e1f49810f0ba",
+        "1bdb70d68c94c651d50efe9dbe2b3f9f9df24d7d",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-4.worker.js": [
-        "04c29c2a1ef78a7b4d700515ff2326fb63af0a38",
+        "ca5543ac9b5d2ca184dc3711c633e4751f831ebd",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgb-clamp-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-5.html": [
-        "93a404a75f2fe2716489acecf5f574be45659915",
+        "880ad046e14ee42c78e7ce2a47dd703130f6cdfe",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-clamp-5.worker.js": [
-        "c77f3c0cf0e207427a6bf6cdf5d1033865a0344c",
+        "41f8799f400c92e3a5719635f8912a4afa255b38",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgb-clamp-5.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-eof.html": [
-        "14a932e0f52e8f26b46e4b8b4e606f2d60c80717",
+        "9a84105dbc5288ee7e4e98d2e2da9ab12a4853d7",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-eof.worker.js": [
-        "2f37fc8ed0a2a966567c17d426a6ab2b7b9084c5",
+        "39589937d55564624442ca6b5997a3469d9d84c0",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgb-eof.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-num.html": [
-        "0847040b921902e98b7aa1aeef3f27962f03c386",
+        "6cda83e0a8039edad04a3616d37984edbab874aa",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-num.worker.js": [
-        "839139aa3ab742947acee5a8321a657255b5877f",
+        "229d6aec613d7a04868d9dfe17a72b29bc5e8fe6",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgb-num.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-percent.html": [
-        "7b9b300c6e7ad7dd8998c1e5c92fe60db60ddd4b",
+        "6f7125de0ff7f3899eab6ec8fd23da449bae39f1",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgb-percent.worker.js": [
-        "b3f5c6161d70bacfabbcd317e2174462fd4b9e25",
+        "4ba5c987e58f05d238aa74c802d234ca96196fa9",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgb-percent.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-clamp-1.html": [
-        "9752ef1b2c86f472e2559a1dd04489ff3c70be74",
+        "1cf20f7898c53f0e1fffba8746182540dc838319",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-clamp-1.worker.js": [
-        "37fe065f640834a8989fd8070e5d67fab008ffeb",
+        "9ba73e22eb7ace9b06f98b15739c8b304de88c70",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-clamp-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-clamp-2.html": [
-        "119589e5062069dbf876677a679de23e56d4e5a3",
+        "c8b4844ae62b6414c85213e55d0922f60915e76c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-clamp-2.worker.js": [
-        "684aa3492cd84c49c1998bec22bad7b32f46d86e",
+        "fd1c53a7335c6e4f2d2d655b4b311adbf0850cdc",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-clamp-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-eof.html": [
-        "d233eab3893a01568faa88035db573a34935cf08",
+        "d3fd3df2e4f066a4c230f539b7ed703185ffc450",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-eof.worker.js": [
-        "0a6e57025b261cf812ca2dee041a71e4fe1971eb",
+        "6e51f09b5fa4c98a6c34ac8d6aa9c0b68b6703d5",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-eof.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-num-1.html": [
-        "6946f78b42d16d9254652049bcd09d9a27ea2a11",
+        "1ce69821ae5e5607e0eb2a900abc5c049caf8b6a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-num-1.worker.js": [
-        "a2b1eec2881378cff004a78fd9f68690c2f5e575",
+        "2805af6e05c58efa1ec0df8e015e4007d7677d0c",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-num-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-num-2.html": [
-        "6e0c04f2ad832e91885cce87961e20cd44dae8c9",
+        "979eff66b24f540ade853f7312789396d43d2c70",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-num-2.worker.js": [
-        "1b9aede49d90eaf0aa8261ddb156a624d18f855a",
+        "2ed1549240763db2b7e681e020828d2c6649ba5d",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-num-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-percent.html": [
-        "ecfb52730a506c5a5d35aebce2359ef6ca94c88f",
+        "2c737e21c14c40627d2398728fa9f12b36eb91be",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-percent.worker.js": [
-        "39054cd36fcfdeea7b69367368bba7c3c488689e",
+        "5852ea3eb1e67f42f355c8c32eeb59cedbbcb6c0",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-percent.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-1.html": [
-        "c0740571031f9ed042c4624aa25ec6d2b47a7579",
+        "701b5efc79bf3994345ff2e87488ffd2b5ac7677",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-1.worker.js": [
-        "a9a753d9b72c98b2de0d686d7859d7e293ac17ca",
+        "51e6d7742106dc05d3b4f50827237cbd0e37f077",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-solid-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-2.html": [
-        "64b87bec3f72c16be27f6e13ce149102f7866e61",
+        "7280c10dd649a2d827d8cee9cb4c4530450b7cce",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-2.worker.js": [
-        "fc81f0f3464f7d82ccd9fdfdcdd269d66636ca13",
+        "4dcbd72aef07ccb06b2c8c11e725557247086b2e",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-solid-2.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-3.html": [
-        "2b1b8972349bea0a75d09219651d52cf3be17ad1",
+        "dfbb44397361dded6f45f372ea128bc2b52078ba",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-3.worker.js": [
-        "c85dfb3d12124c1cf89e93fa3218383d9d703fe6",
+        "060fad9bb853637340c4916ca7adf5eccafbf3d5",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-solid-3.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-4.html": [
-        "be05e23dc57f92f21d4ae3d1d1c36cfeafa72516",
+        "131396c8d0975d4d6d451818c463828569b6b49a",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.rgba-solid-4.worker.js": [
-        "141669ab09d6c659dc25b6f3919f4eeccb9d0016",
+        "43a8cf8251623fd3261f44e23275841c23522238",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.rgba-solid-4.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.svg-1.html": [
-        "1736db0744973132ec91cfbe98a69d5645ba15d9",
+        "ffcc525b486839c9338919fe904a6cd153d5f207",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.svg-1.worker.js": [
-        "bee57ccb734761a0bfe8f37b4094c77e41935a84",
+        "86b4f8175dadbc035a2f3ca4cbb04b9aae4e6a2a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.svg-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.svg-2.html": [
-        "c5641e1604dcb14abca6ddc719013dfad82f5d08",
+        "eafecd0e6dace176d8e0ec2e571efc45f6d8d699",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.svg-2.worker.js": [
-        "dee217fa95c1ef792ed7e5ff580a09233e73bdbb",
+        "3aa530508e154f7596d1c2fce11a95ab0a465e64",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.svg-2.worker.html",
          {}
@@ -473644,28 +475260,28 @@
         ]
        ],
        "2d.fillStyle.parse.transparent-1.html": [
-        "fb2fa0e8bfbf038b7f5a32b7f60f76e691632fa5",
+        "98da0c29cde3598f4c22548aa0cb5903e964a25c",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.transparent-1.worker.js": [
-        "0c838f66b2f13fb89f9b6f9286bc3c1a17ceee1b",
+        "a934b66c8c5bedcd935ba696138af179d32ba7b1",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.transparent-1.worker.html",
          {}
         ]
        ],
        "2d.fillStyle.parse.transparent-2.html": [
-        "cf54ac7cd9b761119e7c7c768765a4b6785f7247",
+        "cfebe8fc1da0f07898a4b55b431b97c671b52a1d",
         [
          null,
          {}
         ]
        ],
        "2d.fillStyle.parse.transparent-2.worker.js": [
-        "e2438166e5b1cc264d7e05119678195499deeb36",
+        "e577bf55dd6d7fddb44c891f16da4c5903c8c360",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.fillStyle.parse.transparent-2.worker.html",
          {}
@@ -473700,224 +475316,224 @@
         ]
        ],
        "2d.gradient.conic.negative.rotation.html": [
-        "33eff9b3b703b41bdb7b5cd7b53665acd1e5f8ea",
+        "dde54400e28ea9ba59aa32f1bc760a065ef7ad97",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.conic.negative.rotation.worker.js": [
-        "a5a32a6808087999a60a93758131591e67761e99",
+        "68589cfab51990e94c3dd1678a3ef8df9136bf5c",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.conic.negative.rotation.worker.html",
          {}
         ]
        ],
        "2d.gradient.conic.positive.rotation.html": [
-        "d77182c155eba83afee8e9bbd648b6e8784c735b",
+        "42d5a87af494d01a572732b2dae09d40e4a8ab4c",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.conic.positive.rotation.worker.js": [
-        "9a0b95f85852d86762c3e27be01c2949a34349f7",
+        "cece603ddb987ad111d90b1715a8664e902a8155",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.conic.positive.rotation.worker.html",
          {}
         ]
        ],
        "2d.gradient.empty.html": [
-        "154a8885c53f4ab9572131dac603de6cfdbe6609",
+        "93229d93f5d7bd31711f980584e8587452af3136",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.empty.worker.js": [
-        "0db82eebe7b4d4b12ad13bae2b8debaddd33e7bf",
+        "207a1b0cabd9e904c520ef40114482a9c3acdf6b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.empty.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.alpha.html": [
-        "4507adf92a4e988b65174333e6ac11a2216fd879",
+        "52c11fcbfd7dc1e5ce6a872130fb0649a8e4326b",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.alpha.worker.js": [
-        "119de347aa5c248b508fec21f06c1bec55d088c5",
+        "d9f08a9bedee65df6808eb81d4d76a769af4c6aa",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.alpha.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.color.html": [
-        "7f8d6eabf900dca053962dbaa15c16a7d3cfb8e5",
+        "8f3278176016bada6c63a3081cac050f6d261905",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.color.worker.js": [
-        "514d378178ca9217f03b95725e90c6e25b4d6f58",
+        "fcf1f84f37c19f5caa5b0f92cc04a89dfbd9edf2",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.color.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.coloralpha.html": [
-        "555730ccb56311331c23797bc344b0c9615ce9b9",
+        "0e7d3b5577b9a771bdfac7983141ca79a13ef877",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.coloralpha.worker.js": [
-        "44fbed39e2f3a985f4be884f7c9174def615cf9c",
+        "cc1cc9f2191b34c4f8db050484eb9701467aac4a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.coloralpha.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.multiple.html": [
-        "2abbd658701da69af0ca2d2c89c2373b32756b21",
+        "724ae5c0939218103987493273ddec44cbdfaba7",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.multiple.worker.js": [
-        "f732b0dbbb3463dab38a5d0f115b836936992258",
+        "ff3687c1a98c6ae3e30da24386b11a87983aea8d",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.multiple.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.outside.html": [
-        "ce53d957e380d2e841affea88164c4cad0926a03",
+        "0ef97af879a252c0768adb663807f680501149b6",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.outside.worker.js": [
-        "9a9949fd843c04d3f1c56243fd4015a1f1c424e4",
+        "60d10a59d8ad7750b24fcd7a353ec022c164469f",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.outside.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.overlap.html": [
-        "a63eb3626de7c05e7425fbda1222853639ab4cc7",
+        "77eb328ecf1d3302ccd583663c03747033e52f07",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.overlap.worker.js": [
-        "8fc2fd5640bb5b1cf21c37f93e982f0d08ad3dbe",
+        "e11c85f8d81c535211ee1598ee2c27ca793a19fd",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.overlap.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.overlap2.html": [
-        "25ef30ed05496598d213fef69dab6635f3d592a7",
+        "662913b13f96d282250410a9537df616c3a5b20f",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.overlap2.worker.js": [
-        "8b47778338e0b7f1b5450431460e70b576aff9ae",
+        "a6329af99acc695fe3a6529725261974ae0d2aed",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.overlap2.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.solid.html": [
-        "98514add7898b373d4dd5da5a2f3b65d24093843",
+        "aa488d9412071dd9139296a0f435fae26607850b",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.solid.worker.js": [
-        "c296f483006a78bbfa4010e3aad735806d91e47d",
+        "8cc4a88d98e97f8ab3f5345d0822167708fc6cf1",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.solid.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.vertical.html": [
-        "3ca5a764c2feb9804708aa0dd27a17eed7123c52",
+        "15c4c7c39ef16c8e5d980b629effb789e98320ec",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.vertical.worker.js": [
-        "319d03c0aec3ec6c2a931203845e51234f7fc874",
+        "a25692cf42f19345f68b08bd47965cf169818525",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.vertical.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.fill.html": [
-        "b0f7be685f5bf9c73af117b8eb29dc6fb11329d9",
+        "b679d5b83d6716f15616bd938707d6bc314dc3e6",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.fill.worker.js": [
-        "4fbb8582bd7c16b637fcc59ac5fbc815b333a004",
+        "71df9674ce7e32142d35d6c01b8e8a8661a28c48",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.zerosize.fill.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.fillRect.html": [
-        "cec97f0a688ecb1153c4028fd6ff02ead2291119",
+        "9576f2a99e5c02f3327faad8fa5813e0afc71085",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.fillRect.worker.js": [
-        "ef3f42a9d3aaa4ff8ca55b6ac94d83b391aff3dd",
+        "b6dfbf081c88db16912cc86c65e312df553bd77b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.zerosize.fillRect.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.stroke.html": [
-        "ff1eac4249a5f3c0e2a9811b5a5280c98a2a20e1",
+        "81a5e4e35dae91ecf08036de47e8540992ead0a7",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.stroke.worker.js": [
-        "8fc30d69c8547393463ae6689c9792d8027e25e3",
+        "c8744645a022f946b21e533ed884a0d909c2eea5",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.zerosize.stroke.worker.html",
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.strokeRect.html": [
-        "76273ab10728314084e8bb54ede778a1d8c54647",
+        "91cedc706956aa1c49219ebaf548714d5cb3a055",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.interpolate.zerosize.strokeRect.worker.js": [
-        "03e91be6e19883f7f8e52354b8831270ee283b6c",
+        "0949fc8a1952f2c191407f569818c24a615f9bef",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.interpolate.zerosize.strokeRect.worker.html",
          {}
@@ -473938,42 +475554,42 @@
         ]
        ],
        "2d.gradient.linear.transform.1.html": [
-        "0dd162acf5db0f9e552de8467380ca5ce84a1eae",
+        "5e7910790778695ba9c7ee07c8e514ec649913fb",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.linear.transform.1.worker.js": [
-        "57f23ff9da8a3cc28d7b0f73213e1444a0d8f134",
+        "62a96e2f6778cb93a9987e4ab291da02e9c2c207",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.linear.transform.1.worker.html",
          {}
         ]
        ],
        "2d.gradient.linear.transform.2.html": [
-        "5856c3992f3d1226e97fd60a353c32722bed3253",
+        "86fb507334976b66b95f031a57340fb1e01b4d0d",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.linear.transform.2.worker.js": [
-        "326a02801adbbffcdfd12861023e97e214bab489",
+        "dace251811a60c339cfeed124241a9d56bffccf3",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.linear.transform.2.worker.html",
          {}
         ]
        ],
        "2d.gradient.linear.transform.3.html": [
-        "3d0359cb9ef15ae291950265e8082a2ad8229d42",
+        "ccbc3ab2839d9568d8da8f98000735185a52dfc4",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.linear.transform.3.worker.js": [
-        "8a3f5024461736638d945bdb082795a3d652f7a4",
+        "8f5a7115ecabe61632ac11bd1578f27c666eebe7",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.linear.transform.3.worker.html",
          {}
@@ -473994,14 +475610,14 @@
         ]
        ],
        "2d.gradient.object.crosscanvas.html": [
-        "82b6bc139c20bfa85c746a921e628ede8fd124dc",
+        "8d54f95f727302a44417ac858c1020690b7796a5",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.object.crosscanvas.worker.js": [
-        "6639cc752292ecd23d8c9c0f80cde319e7587247",
+        "fa8cee44caab72b2f90407e2c9a5f10de7783dd4",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.object.crosscanvas.worker.html",
          {}
@@ -474036,182 +475652,182 @@
         ]
        ],
        "2d.gradient.object.update.html": [
-        "fa48b02f202abcdc244c74db9c10debf0ce8bc65",
+        "05f8e747f2f5d3ea60292270a124209a667aa784",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.object.update.worker.js": [
-        "758934237b7a8d48ecd06159c8e1402928a845b3",
+        "5960d0afe9fd7cc4f5c14c1af3c71f0c5909682b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.object.update.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.cone.behind.html": [
-        "80c71480e1510626ddcdba50464cf25517ed2a81",
+        "537f960d8ddecb7a288eefee73bf27b24c9b1715",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.behind.worker.js": [
-        "373896c892fc5678bf1c150bdc897823c72a1d1e",
+        "99711c732de57a68bd331f3e84b20ece5c9e69e0",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.cone.behind.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.cone.beside.html": [
-        "283a5fae2c42f34d0706b1e21a363d4ee76090f6",
+        "360f1ab7359f34d4cd883fa0f19de0cab7c416c4",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.beside.worker.js": [
-        "77a4eb84ff3b3ce9122f02911d85b26323c36ea6",
+        "6af48259a3571f8e9e5dc727140bb984e91de3c1",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.cone.beside.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.cone.bottom.html": [
-        "8dae29c43ecdd07f61ceefa67550d67e59f738a2",
+        "3f3690381d36c686e260e17cfb1d91b3e029e09c",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.bottom.worker.js": [
-        "d0aede162dc2965894f99e01a7c35cc46e66229c",
+        "2eca2d573e07de471820508ce1534deeda6d45c9",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.cone.bottom.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.cone.cylinder.html": [
-        "9eb0840c020890e72f9c71c5fdb56b18a927b65b",
+        "700740938c80260460c6c8f4f2e006050546227b",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.cylinder.worker.js": [
-        "606a4d564a699754af2ce6688b1fa322bd333294",
+        "25ff9b861da188abdf319bf33d3bc29d538e39f6",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.cone.cylinder.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.cone.front.html": [
-        "2cabc1f8769d9144829a554b63b154660369f26e",
+        "12f14ce0055f15bff21b967b8fe17e7ff8994b80",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.front.worker.js": [
-        "4fa20456d4b4d90b9d84800c418bdb586e5473cf",
+        "6053cb40d199ce1610a60656da99a61c670be801",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.cone.front.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.cone.shape1.html": [
-        "424c08c0ff98382203daef9c2f9ca0ee46466200",
+        "242aaa0128096f460286ed2ce1db628e9d695dd2",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.shape1.worker.js": [
-        "562570df6ba414260b4952b41eab9cd1c72c6c23",
+        "15e7a6f696cf866ed062008f82e25050d0b1d06b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.cone.shape1.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.cone.shape2.html": [
-        "7b338dc79231074fcdb4a98dbd581d69a6b95e09",
+        "d51a132f82aa48c50aedd7c96ad75f21e0b60087",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.shape2.worker.js": [
-        "1a138dabd6b98d089f626897da4ed0536c6369bb",
+        "793d2513dd390e463ee89b0ef7399477391c5c1b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.cone.shape2.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.cone.top.html": [
-        "ce021f4ab6afcfc946a460d8690c6797deda3540",
+        "9759eb3fa98ea35bc3a2a4563239ae27a00b103c",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.cone.top.worker.js": [
-        "f16460b5ae24adb7788ce691ad1957f501ee2599",
+        "2ee6de3479c79b5ce4f9d3df84f4cc38b06a9161",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.cone.top.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.equal.html": [
-        "a63587ec09ecfbd230aeda8d6761a662b71693ad",
+        "465ee976fae939ab7e515557d93dcb37205baca6",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.equal.worker.js": [
-        "c436c6e773f29c8e3b76096da066a9e37add9b74",
+        "74567335b426282261070c921c0b3fc5be133d58",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.equal.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.inside1.html": [
-        "63a3804ab44c870e97ab19156db6d230cb48a173",
+        "7c6fd31d67d213fb61f3c1c527ab1c6abb3dc449",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.inside1.worker.js": [
-        "6db3ac8cd8a24197873268ac3e70f8516910006a",
+        "6d73c0935ac5514eb9e090a9668a65ab0fd95ddd",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.inside1.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.inside2.html": [
-        "e3e4ac250cbb9558b38ac96fc561212b93d3b06f",
+        "fbad8b57b569e80e189a9ab2cc165f78cb77ec8b",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.inside2.worker.js": [
-        "5c307376081fc87e3f0451bbd875f7c94218db2a",
+        "aa6ecba5f493a3504791b9419d1045ebc36dcd9a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.inside2.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.inside3.html": [
-        "994e0b6853c49f183da96ec2547572c51b62fb93",
+        "54794b13fc429136465dc643e7c53b411d5b93f7",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.inside3.worker.js": [
-        "2a8eda9def670c6c8ba09312cf77b0175de8866d",
+        "b6d58b656c082b935e631e3adcb329fdc5ff9485",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.inside3.worker.html",
          {}
@@ -474246,168 +475862,168 @@
         ]
        ],
        "2d.gradient.radial.outside1.html": [
-        "e35b67d6603297d3011299ef0dc16ba6c6731ad6",
+        "44b2aa49fc177c97e1e224cb0e93b99a9387f02d",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.outside1.worker.js": [
-        "39720705a483c8b24e5a721ceb348bf36237c51b",
+        "e1d3cddb24471c34f362bd2bbd1e0d059f4bec05",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.outside1.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.outside2.html": [
-        "ab26b36bc698b94107135f105f89d3d231454a04",
+        "e9e7ce497cd0879a6ed2d52effe4224618038330",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.outside2.worker.js": [
-        "63b4cb0524ffc10fe544cca1d133e3e1a4a66de8",
+        "a3f0235ed7afbd49994d73898addde652c357f26",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.outside2.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.outside3.html": [
-        "f51f65249ce07f3c8d03a3f1be6b8e01739ce69f",
+        "b66480a52c402c1e68b6c27c70ae6159463d8628",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.outside3.worker.js": [
-        "d369c2a5b77bfa9cfbdf7dec9daadcfd38bc9204",
+        "7b90c87d0385faf66ea872625dd5ea8074dcf82d",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.outside3.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.touch1.html": [
-        "b1a1bddc4b538c9b8012620ea96609b45d4a1e25",
+        "c042b03b3399513ea6c4f6dfeccd4cb34fd30718",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.touch1.worker.js": [
-        "3bfab866194ce4e4cc5db2491939e33799c8939e",
+        "7465345f6bf4026c78fce9282b7a84da631e5e09",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.touch1.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.touch2.html": [
-        "6ee97948e74708e22815e3578a76c8a98fe84fa0",
+        "5da1d592f843acaa42806e1f815585ad9293ca09",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.touch2.worker.js": [
-        "74e9662ef58261ccb595437ae63ad5bfb12b81b0",
+        "91dfcb31acfcf250765c0f833f53cd017e239380",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.touch2.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.touch3.html": [
-        "a21416f4f2e6684969030590d62cb6804da796c3",
+        "804589f074b3edc5042ba1696393aadc2a6d005f",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.touch3.worker.js": [
-        "9e476c245f2ea1a0a398dec80ea3eb3712938cda",
+        "11e17fbb80bfa26742c8067b86c9af43e4d23bb3",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.touch3.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.transform.1.html": [
-        "875c8e6ada99d6b01823c3d6f4fcad5527c1f754",
+        "c54044c0ea62bdd3d846c3d63d16f5fd6a9b633e",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.transform.1.worker.js": [
-        "8daebf732a2b0bab89257c8714f0681c41290466",
+        "e2159d269f65b303f50a3f05f4455f1e73c9c95a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.transform.1.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.transform.2.html": [
-        "e2c221e2798285d7ef1d5bd7bee17135a81a735d",
+        "145c2923e9037f9ab984d2b6e0d2f54230dddad5",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.transform.2.worker.js": [
-        "83734174e218bb72a534b04d6951c21b2a037462",
+        "511b7f362a4360b340feab344771caffda92bb2a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.transform.2.worker.html",
          {}
         ]
        ],
        "2d.gradient.radial.transform.3.html": [
-        "ef6a880bc1a48db54862731259047b51a4ef27ef",
+        "01d14cfbfc029669fe4bafe74b8a98da5748ccbe",
         [
          null,
          {}
         ]
        ],
        "2d.gradient.radial.transform.3.worker.js": [
-        "a0790f04d5e0b47c584933bb69751c7fa7ebff06",
+        "b7bf68a979daab4a905cdb7f599b025b42c7ef4b",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.gradient.radial.transform.3.worker.html",
          {}
         ]
        ],
        "2d.pattern.basic.canvas.html": [
-        "7b437e3437558870002d55de2c2d6e13599b735a",
+        "80bb946660145a41231c9daacfe31da4877d0123",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.basic.canvas.worker.js": [
-        "f76f25acab5621f1809c892a4753be9fbc298a5b",
+        "a2608066eac5f8f5a878ca24b61ca5e60de676b9",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.basic.canvas.worker.html",
          {}
         ]
        ],
        "2d.pattern.basic.image.html": [
-        "f99eda3017707a5615eccd14f78ad4adf4b60ff2",
+        "965daccd3aa7a1a72d0ad1cf1569fe1f2abbb8e8",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.basic.image.worker.js": [
-        "aca360c81a65e5cc0d372a03f4bfc5d1bf6167f1",
+        "725df51307ed0b9d62a924ebd1e8f07dac4b46b2",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.basic.image.worker.html",
          {}
         ]
        ],
        "2d.pattern.basic.nocontext.html": [
-        "be6c5a1254bacc91a11b01d703c12ae24db1f8d5",
+        "50cd38ed0f0cb2ba7a3b0e47448265aa8ada93dd",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.basic.nocontext.worker.js": [
-        "e710b2a61b332c0863101545b60fd7a838ed8ee3",
+        "8f33ec9d8d93f8f0808dc0df097468278a04e851",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html",
          {}
@@ -474428,14 +476044,14 @@
         ]
        ],
        "2d.pattern.crosscanvas.html": [
-        "b20ce96573df73b56e074764e08ec97dfb216311",
+        "c6e0b36092e3b3b8bb37e4015e9c145e84033e17",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.crosscanvas.worker.js": [
-        "6958906ad0b3be5f9a8ae0668a5c18839dc8fc17",
+        "1a1d045ba6f4b2fc1017c6c95559416c010094f8",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.crosscanvas.worker.html",
          {}
@@ -474484,280 +476100,280 @@
         ]
        ],
        "2d.pattern.modify.canvas1.html": [
-        "9ae28ac647fb8966bbe32cc08e01e21f299acceb",
+        "4c27f26347faabd4a038f5cc22cfd90dc0ee8733",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.modify.canvas1.worker.js": [
-        "84d4c81f387a28163c839fe6ddcba36cec325e53",
+        "c83755c984c160ca792f5f423ae9c7a1f7209468",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.modify.canvas1.worker.html",
          {}
         ]
        ],
        "2d.pattern.modify.canvas2.html": [
-        "9e65676c9c238e984e424d4b3bedea3afe16dabc",
+        "08a6cd896eed95ce926bc8d3ef9983a015ae00a2",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.modify.canvas2.worker.js": [
-        "9ffa10977195fcb486bfc9b0e0d5044a44b5cf84",
+        "a49dd10213ed623975abf636449f8afee90d6196",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.modify.canvas2.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.basic.html": [
-        "7e95b5e6cc606c4f49a2300ae293dbd7b8c8e816",
+        "f5d9f5a5582ca1bb6ce5ec26920b9cc002955224",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.basic.worker.js": [
-        "2c822d01efd274de8798f434ceefb93134a2c9a4",
+        "82a49c331b513713fecacec65a5b474292a5f6ae",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.basic.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.coord1.html": [
-        "00c3d6a0bf15c00bb80d7789b071defeb344bce6",
+        "87158be57cec82da1184b1a3cb82b7842e2bb241",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.coord1.worker.js": [
-        "59d3d7d9381d03c3efba908de62e31bbc6cacf68",
+        "731df50c00f8ceca845f5f2b6041b554166c44fb",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.coord1.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.coord2.html": [
-        "193f2b4ee2c46c74110dd3625c12314ba4b9d83f",
+        "a600e6ef578c1829c5622f9ffcbf9e59a2e4179e",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.coord2.worker.js": [
-        "e3104475295f09d28b1e8035989ff77076926517",
+        "bd9c115f0da49269ae36d3f80ab1848d9563baf4",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.coord2.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.coord3.html": [
-        "ff010a0ecd3b6bb63a904b8c47315dd796f778d1",
+        "c569d877053a14bb76de419f71cc62b7055405e8",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.coord3.worker.js": [
-        "80fa05ebcbe6135d8e3e3e5b5dbb9c8569c8f3cb",
+        "cf88ebab7348dfc75246785224b0699640bb3293",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.coord3.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.outside.html": [
-        "4b2dd9356549263466d965d814efcdc5f0ae7357",
+        "4242375b0308626175bf1942e29b133227e996c0",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.norepeat.outside.worker.js": [
-        "e0eab9655f97c880f550ff7115462ed708a47fd6",
+        "85a6e43bd1094a48820ce18f37248ce40a87ec54",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.norepeat.outside.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.orientation.canvas.html": [
-        "fb0da46c8b779e7fee8838f3c12d4cf76a76fb9e",
+        "ccad92e529c6a90902499bcb419399266798f32c",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.orientation.canvas.worker.js": [
-        "088985b9c92f4dcdf580a59031dad93a1599e5a6",
+        "38fa35f138dbae6975c1316ff58d1f8c0bec2758",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.orientation.canvas.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.orientation.image.html": [
-        "79061ddcad59238b7846b993a6ae8d5a0a6b2501",
+        "377cc58685baccab280eb7528748cc2d2b187d93",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.orientation.image.worker.js": [
-        "453c5a73740818bb62113be8570569beba5f420b",
+        "fccfe704267b1fbd84e58ad9d8bad0880d12ee6a",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.orientation.image.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeat.basic.html": [
-        "a2a3aa7d9104583973c59c0de4498acf140b5587",
+        "b5613c379801f2120164950166f1de5caa8cbc37",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.basic.worker.js": [
-        "50a9883d10471c6f03c3d2baf3506662594a7a09",
+        "1f09d297f9d1e440c163323fb7a752e5b84a1424",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.basic.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeat.coord1.html": [
-        "b11e802f2811dbd0a5aec333fc97131d900e431f",
+        "a4b2bbdd7d8964d202419848fbf274127eabf6c6",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.coord1.worker.js": [
-        "f81a902796d2c9a29c58cdd5d6a5c3f7a3e007d3",
+        "ea064ea327a6426431b3536dd72bc1f264d6b71d",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.coord1.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeat.coord2.html": [
-        "bbffa5d59897dee7daae62e13cc90d0c1566019d",
+        "52449506a7d98fb21e813fcca38ec622b03cea71",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.coord2.worker.js": [
-        "469c2a3676d8f44b3a298c20b492d6f8ea513ddc",
+        "29c6f8f006deb3c1f877a68273fd89b1cf9bab38",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.coord2.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeat.coord3.html": [
-        "a0688ba95e2b9cb9e685390dc6fb58fba1d94837",
+        "d01acb8a6deb7529246b176b879be91394a5f862",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.coord3.worker.js": [
-        "abda4b749f314edeca0284754aa3143074c7dc7f",
+        "91c14f98dc0b360444d5181c7196216c6fa0bfb1",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.coord3.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeat.outside.html": [
-        "7b0b40d12b89eaaa85b9568b12abc8a37cb80c3c",
+        "2c91f1d736cfd18b198ce445c76f7a045f2c8fab",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeat.outside.worker.js": [
-        "a4f70bd051ef95ec2bb798932257ab4ae0d29d6b",
+        "147eadf8e717f32f9e6e726cf3ec5b6fe751c5ec",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeat.outside.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeatx.basic.html": [
-        "36bc3533a9798124e6501b5680f7ba7795c1bad6",
+        "ed7cee297d328431590d35806467e7ffd0df6537",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeatx.basic.worker.js": [
-        "408a5cc98aec2664b1cc20af7a56f573e80f6a89",
+        "d7efcfa1e1389eddc4068f2aa2c0d4212a3c0f40",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeatx.basic.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeatx.coord1.html": [
-        "ee04dee0258c6d313cba397373125010b0f8f561",
+        "342ce06aadf3b1167b162811059bc1cba280204d",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeatx.coord1.worker.js": [
-        "2e51b4469bd850ff1cb433fb41321b7826a72481",
+        "351092befd370a1e919b578c31ca970d94899f7c",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeatx.coord1.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeatx.outside.html": [
-        "ebdafe1c6ee9cc80dda52fe0a5c4aa8df4539c91",
+        "ad4a4a2461430531d8588ea42366b238931f0ee4",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeatx.outside.worker.js": [
-        "4a2c1c4b2f8919f282ad51975ca3383ccceabf50",
+        "0e031109f287d8fd5ac3cc4f24539c4617ec55d2",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeatx.outside.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeaty.basic.html": [
-        "43b68e2fda574107dcdcf372966ffbbe647afda1",
+        "6069902498e57254cc4bcc0f1b5b68b40cf9951a",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeaty.basic.worker.js": [
-        "1d6b338c499c9878c3148d6ce993e31287c270f0",
+        "09e9b023946a016df5a266570810f7baaa426216",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeaty.basic.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeaty.coord1.html": [
-        "fd79559bcd40a526d3837605544b3d25c7f84fef",
+        "fd1cca2e9592ae954b5a598849f7211364af6bba",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeaty.coord1.worker.js": [
-        "f91d00590118725d6c6a1d520187e41502d11421",
+        "1701d3cc766363ca5f666079574e5ba9444f8eed",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeaty.coord1.worker.html",
          {}
         ]
        ],
        "2d.pattern.paint.repeaty.outside.html": [
-        "44caa8033ba2943c5b4ad14497aa013a8426f717",
+        "b7fbd9eb8794fef5e89563e84bda00ab548d31ef",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.paint.repeaty.outside.worker.js": [
-        "e7b12c95b8b4f24419ef88fa52df4f6d6096258f",
+        "7242c8ff484c16faed0af67ccc342540817ae83f",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeaty.outside.worker.html",
          {}
@@ -474778,14 +476394,14 @@
         ]
        ],
        "2d.pattern.repeat.empty.html": [
-        "11c38581353695af8e8373a78f08929c70cf91c3",
+        "76e54e9616f011ae8748865ba8a5b11d7a90d657",
         [
          null,
          {}
         ]
        ],
        "2d.pattern.repeat.empty.worker.js": [
-        "9cf75403d39820cdc4db9266bf96a288d71b2542",
+        "e3048881e371923781d2244e33b6edb272e5d459",
         [
          "html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.repeat.empty.worker.html",
          {}
@@ -474892,84 +476508,84 @@
         ]
        ],
        "2d.filter.canvasFilterObject.colorMatrix.tentative.html": [
-        "c772b2fa8c44b1ff16a6c820fc2e8863b230ad09",
+        "ece8a52216ee4f397c4dd0be87b710cb1b794f3e",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.colorMatrix.tentative.worker.js": [
-        "f3bfced9dd09d3359b9c368a12d4783f7657ee03",
+        "105f312b9ceae0243b27234934477568493861df",
         [
          "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.colorMatrix.tentative.worker.html",
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.html": [
-        "a9e77c22176198049556cd32d11da2e8fba74ba1",
+        "eaaa12f0a79fdfe59eb9931fc96d527b9f917e30",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.worker.js": [
-        "56ffa5ae8a4f1b892076d22e310b3a075a2cc322",
+        "f1274f14253c559ccfe9939abbc87c62884ff7c0",
         [
          "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.discrete.tentative.worker.html",
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.html": [
-        "36c0ca0583d8af8061cfb527c500630bbd6e48d8",
+        "6c5b04ab8a79694c5b3afcdc548fbee40b409372",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.worker.js": [
-        "3d1fca79b5b36a1d7fa55e646c67a3b48bfac525",
+        "14bf50f89dde725304dbcbdb9f8ea65447c373ca",
         [
          "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.gamma.tentative.worker.html",
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.identity.tentative.html": [
-        "7e8670ed6f3e127870dd081d4b834ea74ab26604",
+        "a6a7a3615a88b2cfd2f7002471050237cb7eae7d",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.identity.tentative.worker.js": [
-        "299b5b385a731c70fe35cb15fedb89e5695f0b47",
+        "ae749673f4362ea4aade37ffdc55986e77735a6c",
         [
          "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.identity.tentative.worker.html",
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.linear.tentative.html": [
-        "66c85e7f879a155135f896146c5e7dd71f29dff2",
+        "f2218b7a1d5afb1d33ff817ce9bee9b43b7a6b6a",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.linear.tentative.worker.js": [
-        "aaca12b36946db7f6c268bdc873d298750e691a6",
+        "5117d4a1b3b0d683146a9ee39eb1b30966cb72b7",
         [
          "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.linear.tentative.worker.html",
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.table.tentative.html": [
-        "8fe0f2c35f3583a2588198d3504d6b2ce7f0a0c0",
+        "9c4c16db8517c9039d46a13ee552380ef6968465",
         [
          null,
          {}
         ]
        ],
        "2d.filter.canvasFilterObject.componentTransfer.table.tentative.worker.js": [
-        "590f4f4dbf0d1dae3f2fdb74050e058a7e6809c4",
+        "e2463eb9e7663b0409b6ea661d333d500e08a9e1",
         [
          "html/canvas/offscreen/filters/2d.filter.canvasFilterObject.componentTransfer.table.tentative.worker.html",
          {}
@@ -475034,28 +476650,28 @@
       },
       "line-styles": {
        "2d.line.cap.butt.html": [
-        "86fedde95210662895e6e8771b8588c38c7d93bf",
+        "7f34def5648a8d8b44deb038dfe091792893c2f0",
         [
          null,
          {}
         ]
        ],
        "2d.line.cap.butt.worker.js": [
-        "d31be7946a13947710bcd971959662e0ee45a186",
+        "3eacba11a3e16bf038a81808c1eb8a3a04f9816f",
         [
          "html/canvas/offscreen/line-styles/2d.line.cap.butt.worker.html",
          {}
         ]
        ],
        "2d.line.cap.closed.html": [
-        "6a44954f65b218cee47799132805e3ba1ad0fa69",
+        "0a3f3fcab77edc110f8e338ce78a9b561b96d16f",
         [
          null,
          {}
         ]
        ],
        "2d.line.cap.closed.worker.js": [
-        "278739606c61c76a1a8c72322bb72fbb422701d0",
+        "24bace4c27535bda8afccb7d742a04aecb36d7a3",
         [
          "html/canvas/offscreen/line-styles/2d.line.cap.closed.worker.html",
          {}
@@ -475076,42 +476692,42 @@
         ]
        ],
        "2d.line.cap.open.html": [
-        "9eab060a4f79a6f45bace02876875886fb4eb0ff",
+        "00b72b62d2d66f01c60e9e31e6b50b6ec62e4b63",
         [
          null,
          {}
         ]
        ],
        "2d.line.cap.open.worker.js": [
-        "94e70b1d6a48612c17b8bc6230683bc8797d9b25",
+        "621de99a83f1dc83f215b46f0a5ae781846fba11",
         [
          "html/canvas/offscreen/line-styles/2d.line.cap.open.worker.html",
          {}
         ]
        ],
        "2d.line.cap.round.html": [
-        "ddf6a4d11751176521f1d3d3a150d285e4d1d90d",
+        "9f6c66567e9030c3347c80d61d5b33c38bd93ec6",
         [
          null,
          {}
         ]
        ],
        "2d.line.cap.round.worker.js": [
-        "37fffce3c8dc6fb4a7c7c3db606c0b09df7e8b8e",
+        "e744d2906fae4da099554f6fc215a85a36aef448",
         [
          "html/canvas/offscreen/line-styles/2d.line.cap.round.worker.html",
          {}
         ]
        ],
        "2d.line.cap.square.html": [
-        "68f6d2418f141748b227f36578c305d2a049729d",
+        "0fd4b2c71a75515ca3a4bd4b0d7356d4bcbc2523",
         [
          null,
          {}
         ]
        ],
        "2d.line.cap.square.worker.js": [
-        "5f687a057664e667bbc4c7be6322a3eb8a5aa4c2",
+        "7684bbbc85f318b6c5f8e22cf322ff67f1e6f7ef",
         [
          "html/canvas/offscreen/line-styles/2d.line.cap.square.worker.html",
          {}
@@ -475132,14 +476748,14 @@
         ]
        ],
        "2d.line.cross.html": [
-        "9569b1c4ef92dd96b3242db789301d86699b2e6f",
+        "09d3a00b3177e26090857d6c86ee302ffa6c138e",
         [
          null,
          {}
         ]
        ],
        "2d.line.cross.worker.js": [
-        "4f961fbcf44da786b7b67584691277f69df6f2d5",
+        "82b289bdeaca6fb5c85d608623f8fde79832c9ad",
         [
          "html/canvas/offscreen/line-styles/2d.line.cross.worker.html",
          {}
@@ -475160,28 +476776,28 @@
         ]
        ],
        "2d.line.join.bevel.html": [
-        "32c365ffdc87a6e787123f3e4df53860fe9128d4",
+        "45c8d3eb5439224a9f70fc1a8a9a7d9db5454315",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.bevel.worker.js": [
-        "6917daacf5b960c79617f9309837777befcda0bc",
+        "2dfbf34f1566a8fbd446694d43da8c2c7d382396",
         [
          "html/canvas/offscreen/line-styles/2d.line.join.bevel.worker.html",
          {}
         ]
        ],
        "2d.line.join.closed.html": [
-        "63a06536200a0fea0359450bc98f04c3e0541e8e",
+        "5e88ad0d0179b35b3150aceb6ce8f6682a9d6e67",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.closed.worker.js": [
-        "72c6038146a5557ecbb4ddac7b7c2a14ca41ae5d",
+        "f2b029ecaf08058e1af459c9fa6b486b6f0b2a28",
         [
          "html/canvas/offscreen/line-styles/2d.line.join.closed.worker.html",
          {}
@@ -475202,56 +476818,56 @@
         ]
        ],
        "2d.line.join.miter.html": [
-        "4be38c05757336da31470ee3c57846316240523f",
+        "64918eca38382e4bcbda700df72c717f319abb12",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.miter.worker.js": [
-        "603b3266a48fa99a9ae1e2500112f4269eef00d6",
+        "02712a806eb2315b8d2456ab0e4fa6597a01ec98",
         [
          "html/canvas/offscreen/line-styles/2d.line.join.miter.worker.html",
          {}
         ]
        ],
        "2d.line.join.open.html": [
-        "5520601c30c1061f83c463b192bb8d66fa1ea8d5",
+        "48154df59b63718fc26e3ddc8243a2d3a0b28bc0",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.open.worker.js": [
-        "d946fc1ceb0707fc076cf1f5f3d172cb0172e8fd",
+        "133854bf5488968ecc025385cdbd8d107fc4dbfa",
         [
          "html/canvas/offscreen/line-styles/2d.line.join.open.worker.html",
          {}
         ]
        ],
        "2d.line.join.parallel.html": [
-        "fbd243723bfe1375d8f286be86addfcf87b4ae01",
+        "fdda123dd8a45ce88e41160e1c766fde0c3caba7",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.parallel.worker.js": [
-        "a625bca104950aed67492de6cd0c593b74136ff1",
+        "68ed957b6d7a00120f3fd2363a30e47115e4396a",
         [
          "html/canvas/offscreen/line-styles/2d.line.join.parallel.worker.html",
          {}
         ]
        ],
        "2d.line.join.round.html": [
-        "79f01ed3695a44cc2b83f59647a97648987a32e3",
+        "ebc71c30f8389fa91252473cabd9003491c6eabd",
         [
          null,
          {}
         ]
        ],
        "2d.line.join.round.worker.js": [
-        "475070b219c2c136437a2ddd315f84842d3a0ce5",
+        "c7da3520b3fa3dfe05e0e64637826af215948753",
         [
          "html/canvas/offscreen/line-styles/2d.line.join.round.worker.html",
          {}
@@ -475272,28 +476888,28 @@
         ]
        ],
        "2d.line.miter.acute.html": [
-        "4620e179fdad8a96667f8da7bf1706a2126cbedb",
+        "fd6902ca4d694e72483f9976ed1bd8d9742d4d2c",
         [
          null,
          {}
         ]
        ],
        "2d.line.miter.acute.worker.js": [
-        "abb963976bd168a1bc7afa04728a6b7c91d9184d",
+        "ef2954a7fe2e21342471f14016f3bd26884fe489",
         [
          "html/canvas/offscreen/line-styles/2d.line.miter.acute.worker.html",
          {}
         ]
        ],
        "2d.line.miter.exceeded.html": [
-        "3e8b444d0026a5388d462a3edb17c8bee79e70cb",
+        "fd0e7a1ca2ffd61480370c788ae6f6a3002c9a74",
         [
          null,
          {}
         ]
        ],
        "2d.line.miter.exceeded.worker.js": [
-        "cccdbc552afbceefa394c317e91ba1d3a04c3165",
+        "2e0fbd4910cec862ff397076a8273246cabc3ca5",
         [
          "html/canvas/offscreen/line-styles/2d.line.miter.exceeded.worker.html",
          {}
@@ -475314,42 +476930,42 @@
         ]
        ],
        "2d.line.miter.lineedge.html": [
-        "e6418773449a9341ffeb115014a628ee6ff72f5d",
+        "292ed560de64898cd49c06e526eeb036a95273b8",
         [
          null,
          {}
         ]
        ],
        "2d.line.miter.lineedge.worker.js": [
-        "fca0924df833ca624de5e85fc49569656a7c8f2e",
+        "c7fa1e6d17334953694aa1be8c210d5f84df6071",
         [
          "html/canvas/offscreen/line-styles/2d.line.miter.lineedge.worker.html",
          {}
         ]
        ],
        "2d.line.miter.obtuse.html": [
-        "c956dcffbe6d77b5ffa78025035df9361e3f9323",
+        "4e60253ddcad8abacc6527a39ca7f19e6e996104",
         [
          null,
          {}
         ]
        ],
        "2d.line.miter.obtuse.worker.js": [
-        "8b369aa33aa21cd7b00a35984b985c6a88392186",
+        "3cf78ed21e8ed72e5b0c82ff8717381845692cbc",
         [
          "html/canvas/offscreen/line-styles/2d.line.miter.obtuse.worker.html",
          {}
         ]
        ],
        "2d.line.miter.rightangle.html": [
-        "331dbb4fb261845bb0c8431b63877e90e079b155",
+        "33cbe5d02c3b9dcc500d9296998f0f1326d2e993",
         [
          null,
          {}
         ]
        ],
        "2d.line.miter.rightangle.worker.js": [
-        "15bca3b57ca95156b5815fbf9c559954eccc7763",
+        "895318c3ef35bee0a24b3c556651a42dbe700d0d",
         [
          "html/canvas/offscreen/line-styles/2d.line.miter.rightangle.worker.html",
          {}
@@ -475370,42 +476986,42 @@
         ]
        ],
        "2d.line.miter.within.html": [
-        "ccda7aa48dc8451b727aaf31cfd4cfd03e8ab302",
+        "4af7c84a6a1532778e5c002d99231ab0ece16807",
         [
          null,
          {}
         ]
        ],
        "2d.line.miter.within.worker.js": [
-        "0a5c16a17b029741140a5871bdcdb81519322950",
+        "64fe4312c27164eefc0906a70a6ccdb8db4e4c6b",
         [
          "html/canvas/offscreen/line-styles/2d.line.miter.within.worker.html",
          {}
         ]
        ],
        "2d.line.union.html": [
-        "e3f85ea255bc0ee7fb1126e596dd44e256b4d77f",
+        "60defee7cb8aa32028ef7c71c814285c4c8bdd2b",
         [
          null,
          {}
         ]
        ],
        "2d.line.union.worker.js": [
-        "9770fc7ad79b8d6985f9cbcfaaab4bfca878fafb",
+        "ed262373374890d50fecc717b75ae3ce567b0b07",
         [
          "html/canvas/offscreen/line-styles/2d.line.union.worker.html",
          {}
         ]
        ],
        "2d.line.width.basic.html": [
-        "1f8513df9f96441d8dcbfd82b4ddce0bd8c5a551",
+        "9b81b1c386c15d6bcd1c8e03c234625072c2aa35",
         [
          null,
          {}
         ]
        ],
        "2d.line.width.basic.worker.js": [
-        "d1b6a353fa1f3d27032b43f0ed91cc426f6fd162",
+        "e822679c637a90c0d256ce564f29ed802cdb5548",
         [
          "html/canvas/offscreen/line-styles/2d.line.width.basic.worker.html",
          {}
@@ -475426,28 +477042,28 @@
         ]
        ],
        "2d.line.width.scaledefault.html": [
-        "09ae212129592a4a7a8533ca8ff8f0946dcdfcea",
+        "78139978580c48c1b4caaf1c4e969d15a61c2789",
         [
          null,
          {}
         ]
        ],
        "2d.line.width.scaledefault.worker.js": [
-        "d6251463484ef8e5f157c5a972b8b211a0e2a737",
+        "f9506c4accfa95b407fa68420fe3a50ad92b1627",
         [
          "html/canvas/offscreen/line-styles/2d.line.width.scaledefault.worker.html",
          {}
         ]
        ],
        "2d.line.width.transformed.html": [
-        "c99078517f43167a10fa0c91b65fe73a7bbe6cf1",
+        "e75cccd99127f0e0c5ec1ad4eae3b5de265c21fb",
         [
          null,
          {}
         ]
        ],
        "2d.line.width.transformed.worker.js": [
-        "2ed23fb6878035a572858fe300ae4b3b040a92a9",
+        "f377d03ca75d6b50384e899c1dc5807cb344e1ed",
         [
          "html/canvas/offscreen/line-styles/2d.line.width.transformed.worker.html",
          {}
@@ -475535,14 +477151,14 @@
        },
        "the-offscreen-canvas": {
         "offscreencanvas.commit.html": [
-         "fa0e2ac5fc8b73d316599d8147c039751fd1da3d",
+         "4ee68b430fda4fd786a9b790fb52ca4c94b291ba",
          [
           null,
           {}
          ]
         ],
         "offscreencanvas.commit.w.html": [
-         "6d4bad11c94826d700442b2727ad241ef4a572d2",
+         "7d1d2c85f9cf3a290345fc559621b12ca034efea",
          [
           null,
           {}
@@ -475563,14 +477179,14 @@
          ]
         ],
         "offscreencanvas.getcontext.html": [
-         "537b582dc1b524c66edcfee763e04d75887d1b8a",
+         "51c167ddca995abe2653d5a48d34bcf86d12056e",
          [
           null,
           {}
          ]
         ],
         "offscreencanvas.getcontext.worker.js": [
-         "ad5e1243e97eb1f855ac3600da8550a049e2199f",
+         "c413791f61bf33283021b042ac64f0fac2ce5591",
          [
           "html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.worker.html",
           {}
@@ -475591,7 +477207,7 @@
          ]
         ],
         "offscreencanvas.transfer.to.imagebitmap.html": [
-         "c9a83802a43f43d144fea847452e39a8cf2db744",
+         "6e1adf9591fa8c2fb67efca4b55f8d6a3c3acdf0",
          [
           null,
           {}
@@ -475661,126 +477277,126 @@
       },
       "path-objects": {
        "2d.path.arc.angle.1.html": [
-        "3f4e85d7ad18811facf833fd0bb77b2687159b9d",
+        "cf358e38fc1d3beb55d8b72d7969635780fce3f3",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.1.worker.js": [
-        "b8dfd990a2c883f46f41dd6cfe5328f0dcd052ac",
+        "5a1f54c4c2fb2ff7504e61858c9bedc92c77e265",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.angle.1.worker.html",
          {}
         ]
        ],
        "2d.path.arc.angle.2.html": [
-        "389db761cc72a5bb533654093a2bec59d1298df5",
+        "9b3983fb370c1303cea9c46835e753a30e36f77f",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.2.worker.js": [
-        "9d84eee957d1fc4080350fbe4ff9e615f1134079",
+        "15bf295b2d5759c1f21f3e7f42376411bc1bada0",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.angle.2.worker.html",
          {}
         ]
        ],
        "2d.path.arc.angle.3.html": [
-        "e89cdc57e44e9f81b14733779b8ae2de55a63f06",
+        "a757b31efba874479655de4dba3ec6c38db2e3f9",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.3.worker.js": [
-        "4ebd45b1c62a948e9a2194e4834c493b79b814b0",
+        "646349fb99f3c48f320079e7312f2b253e11bd1f",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.angle.3.worker.html",
          {}
         ]
        ],
        "2d.path.arc.angle.4.html": [
-        "e40a05e3dc232d17a6ecfa78b6e1f7813934e0f9",
+        "b8e4d54027df3ef4b59a1206c321ae826dbe5d49",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.4.worker.js": [
-        "93ad2723477e0f5f825a98d2b39d568efc4b1ad6",
+        "8fa2ef137d7bd645e12d117a0a744b67f3b89eb7",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.angle.4.worker.html",
          {}
         ]
        ],
        "2d.path.arc.angle.5.html": [
-        "5ab209b4b9bec0533f5e96787ac27c04951e0d8b",
+        "f13a2e41c964b2b4f6bafc0882dd707e16460d63",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.5.worker.js": [
-        "651ec5a9b78f6bb3b05ce3db7d94a5eca12405ac",
+        "50b23cd9ba88ffaf039bc10b0a9ba65a641236aa",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.angle.5.worker.html",
          {}
         ]
        ],
        "2d.path.arc.angle.6.html": [
-        "3c8e2a6623e78d42eeeb049b4a64232aafeea008",
+        "88184b8d77d44f29246593a27fffe39da8b4c4a3",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.angle.6.worker.js": [
-        "27024158a8deb3824b79f8d5e633a0b9e932d4b6",
+        "38bd40489ba9620a2e8cdb7df34cfb343d3cfa6f",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.angle.6.worker.html",
          {}
         ]
        ],
        "2d.path.arc.default.html": [
-        "58aa1f981c8e460713c806ff8b3a7133daf761b7",
+        "848f20c32fa92bca95971882799a349434de3803",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.default.worker.js": [
-        "8ad1a6f9026467ddf53165cd3dc305ef400c659b",
+        "c73829a0eeee543bf2da5a085328898ed13144e6",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.default.worker.html",
          {}
         ]
        ],
        "2d.path.arc.empty.html": [
-        "16889781cf4dec9f6adda382790776bb7f5e78ad",
+        "9098b7fe02327f971a83850bc90f44f131e14c2b",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.empty.worker.js": [
-        "916e6b889f98c5759b0a99eb5f358cae130b06a5",
+        "82281ea4b083a40986213440d77378cfca8f7bbb",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.empty.worker.html",
          {}
         ]
        ],
        "2d.path.arc.end.html": [
-        "65fa073150a3f4a17166b8ecefe95419b7f57a14",
+        "12be27afa6620d3c7a5332fd90fcf9e3cb66ea00",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.end.worker.js": [
-        "a2653efd0c88e0f57150b2413aef84cbcb8d3cf9",
+        "a2519f0bad02b9d96fbd6276b628cbe4c8ad550a",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.end.worker.html",
          {}
@@ -475801,350 +477417,350 @@
         ]
        ],
        "2d.path.arc.nonempty.html": [
-        "b88812171d73733ef4a2613c80dbcf3ecdf2e344",
+        "542940435af00a1f995af043149a952c50c9c298",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.nonempty.worker.js": [
-        "8e30f5696ca9e74c2a66ba84c785f96dd1f04165",
+        "1d7de77486856830fb5ae78961bb23dcfe4dde11",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.nonempty.worker.html",
          {}
         ]
        ],
        "2d.path.arc.nonfinite.html": [
-        "c37dec24e75ac30616f58aabf1ae890dd36227cd",
+        "c65af631b54f767af4eb9faf600532e483976b5b",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.nonfinite.worker.js": [
-        "d027f5d36bdfb52247540b230780a5601f6a72ee",
+        "f83dcf1080dcfbe8179a5c9544e922406b14fd07",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.path.arc.scale.1.html": [
-        "52d03ed8c90b3ed380ce502c3ed6438b1a217c9f",
+        "3b0aed390f58e405345bc0a0fc240ba72ceb680f",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.scale.1.worker.js": [
-        "04372c2d047e335bb5fb2c963d0c3d78c7cfe72b",
+        "ec300985c8a69873d8b6030d3cb6f17b7397fda1",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.scale.1.worker.html",
          {}
         ]
        ],
        "2d.path.arc.scale.2.html": [
-        "cd38bdfcbe0be98f64309d306456600517137c41",
+        "f6822f8203fad4c81e7fdf060cb00b60a330e371",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.scale.2.worker.js": [
-        "e419c7cc22bfe3fa5279aa0aca070c4c315c51e5",
+        "d946f7f0fee991cbbd10bb1aaf087ccc99416d7f",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.scale.2.worker.html",
          {}
         ]
        ],
        "2d.path.arc.selfintersect.1.html": [
-        "c8fe46103bcc7315330c1176e6cdc6f9b0c1e315",
+        "9e8803a102da055720c8944017e39859e9063439",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.selfintersect.1.worker.js": [
-        "75e366edff4243de591a0adf034c4c60cb2a1157",
+        "84cb983f1aae34330cbd0123615f36d227140ce1",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.selfintersect.1.worker.html",
          {}
         ]
        ],
        "2d.path.arc.selfintersect.2.html": [
-        "c5cb5cd3001eab35ed7dbc6235da2884f8ae7b4f",
+        "f2118ef29b89df4d5fb6a57d7623a8d5face9907",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.selfintersect.2.worker.js": [
-        "769d5faa913bd0f31f89c17b1f80bb886368c9ad",
+        "be7f13aee7e14032779987b5181b080d1b8bfe1c",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.selfintersect.2.worker.html",
          {}
         ]
        ],
        "2d.path.arc.shape.1.html": [
-        "301cd054a5fa861ac7044753883ee6da23448bdf",
+        "42242536e2bda882433dbc884ccdaf405cd96bf0",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.1.worker.js": [
-        "ed5a7ffa0f70c4f783f7ddac25e6b5ffc4524b2d",
+        "b41863bfb7b14d67fc2cc5e8d613b033510fc91f",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.shape.1.worker.html",
          {}
         ]
        ],
        "2d.path.arc.shape.2.html": [
-        "cb60d6686196f70fdb4604ea36fb21c75288d666",
+        "1e33a0241633e89de48ce7d99f5ff27171ba0a91",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.2.worker.js": [
-        "b470bb63ce73915439878b3584ee015da3c982b3",
+        "d5d6cb7b7e3daef66f634daadecbd8db08d8a723",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.shape.2.worker.html",
          {}
         ]
        ],
        "2d.path.arc.shape.3.html": [
-        "14cd7fe603065bb48d99cd7c2ba8ec0686562167",
+        "b90284e5798a1962114e271c94a37495754bf12b",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.3.worker.js": [
-        "1e4843e5774299c9900ee014a9fd2eb7d1b2a852",
+        "5d0cf805399eeebfbc1ab0d51cc71881a798b1ea",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.shape.3.worker.html",
          {}
         ]
        ],
        "2d.path.arc.shape.4.html": [
-        "81a533abb166d7d0abac9d47d82870c6965d209d",
+        "dce9547a6b4e360712cc93461dea6cff2e2c7bac",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.4.worker.js": [
-        "0de7e2d458e0a1b6e94d4b8ecb55554c8a1c7a3b",
+        "8bd028b0bd178af918c2249f9554f8ed86a93c52",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.shape.4.worker.html",
          {}
         ]
        ],
        "2d.path.arc.shape.5.html": [
-        "b9621da7ea78058975e4b35830d42b080667fa49",
+        "bd7e54af3b91ececb55412cf05d048a7bdd192cb",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.shape.5.worker.js": [
-        "212de173ebe338b6fbfa4d386ce82db6fb479bad",
+        "0584590afb31fa82580165a107f6833b67bfbf2a",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.shape.5.worker.html",
          {}
         ]
        ],
        "2d.path.arc.twopie.1.html": [
-        "01a930e86476556c176341275256a321172aad0b",
+        "ddf200c88b59724a550343762dfcced20fa952bf",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.twopie.1.worker.js": [
-        "94b38b479f76b795ab095c0d0847e985eac86a55",
+        "c56d25c70ba13bd1dfe3837e12c93ef415d22a9f",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.twopie.1.worker.html",
          {}
         ]
        ],
        "2d.path.arc.twopie.2.html": [
-        "26344fe9938286ed311451f6de64d4981d812e50",
+        "0a9e0c782a616afd976d0e8cdab8e88086d64b86",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.twopie.2.worker.js": [
-        "505250233f71b67001a31df37c02a06b7b18557d",
+        "5db75de2a26897b71227e3aa6ece0f5ed3ae6337",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.twopie.2.worker.html",
          {}
         ]
        ],
        "2d.path.arc.twopie.3.html": [
-        "1c2112eb951edcde31aed7e44f74ae73d40b99c9",
+        "df1e45480d46f105e590dead06a5659f0971c856",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.twopie.3.worker.js": [
-        "4382003e17cf0e5ca4cbc3a38c987185ed6ebd89",
+        "0c984884c9a9556c3688667534059b15ca4bb12e",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.twopie.3.worker.html",
          {}
         ]
        ],
        "2d.path.arc.twopie.4.html": [
-        "6809cb441d807b16884711b232a4e267a1c68056",
+        "8afa122c7c2031c848e7972432c224cef5dd0554",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.twopie.4.worker.js": [
-        "ecc65e4a3e82de10145cfdf42bb7e9f9c2cdafa8",
+        "3158528f6579cb557fe6ab649a96fd414139d263",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.twopie.4.worker.html",
          {}
         ]
        ],
        "2d.path.arc.zero.1.html": [
-        "530a4304f5906cdd6b2a17a0e41529560e8771f6",
+        "f26162f22382f0125498ce7c1715b58ce47bf6cc",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.zero.1.worker.js": [
-        "4fb264a5926321e4f09e84210f3ce4f5b99c9439",
+        "efb137a92af8a0b041735db7c97b9b5c54a1eab9",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.zero.1.worker.html",
          {}
         ]
        ],
        "2d.path.arc.zero.2.html": [
-        "60b860cef00ff93b24646c2e929c06fc3793afad",
+        "f2eda4b8a2de1b3762982fd877dfafcadeb1be52",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.zero.2.worker.js": [
-        "f7cca0bb5485187a62ce8491d5d033af8b649884",
+        "28f4f3759afd56bff23d8d83e4cc3f20a38b2aaf",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.zero.2.worker.html",
          {}
         ]
        ],
        "2d.path.arc.zeroradius.html": [
-        "4f7791802c40271f61eb1e6ac1acd1e3c2ef2ebd",
+        "2d56e369b893436a68f3a5af646d7ae7d5440b47",
         [
          null,
          {}
         ]
        ],
        "2d.path.arc.zeroradius.worker.js": [
-        "cd228d4904bd5ce2119c9841efcf08e9dd30575e",
+        "c57046ab94dbd4a5d714788f6c4b7812ec6dfe50",
         [
          "html/canvas/offscreen/path-objects/2d.path.arc.zeroradius.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.coincide.1.html": [
-        "233dda5d29a72dcde6086ae5540405bea9fc2eee",
+        "58b26356991c5e3335efc654f0aea90e9311ca5f",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.coincide.1.worker.js": [
-        "57e5766a3aa3ecb9e73e2ee0c039e450d366151b",
+        "44926712fcf1d803e4ec82461bafb3fee163530a",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.coincide.1.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.coincide.2.html": [
-        "46a7c52b304f3fc1e5a17284e083295e38dbce2e",
+        "d85e310c85268f090fe6054d41ffd931add69537",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.coincide.2.worker.js": [
-        "eced5ad8ac194f716a7a5a13fcf391f1ad4b24ec",
+        "c8b336a494e19861db315dacd649f9183faa8e3d",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.coincide.2.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.collinear.1.html": [
-        "471ac41b827ce86a38827c43f7086696b77778e9",
+        "5531ca62ae093921886dfcc11df3ba73e07e98cc",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.collinear.1.worker.js": [
-        "f765cff0a9be9c708624b2ae55106b9b138e4923",
+        "3864a311db372520d53c04613571415e3c9b272e",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.collinear.1.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.collinear.2.html": [
-        "5a8fc62e3d4e9b17efc46e1b4c12236f043f2589",
+        "a78d626ef0a5fe0b734f894eecc1a5ba2656072d",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.collinear.2.worker.js": [
-        "9b081699e8ac969e3da35244d05133c0a9d32670",
+        "6f4c2aa8c65e06be182bc5f808ab454e6a335f08",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.collinear.2.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.collinear.3.html": [
-        "b042e1136c056a3d1a37862429412b4917e71f3c",
+        "f2d52e424178d843960ae0ec8a473c4702d0e8b9",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.collinear.3.worker.js": [
-        "d6eef69523a7a432e2b9082958a91a755b3ff5d8",
+        "2d152b0d83fc0f75c30de3c363b247711bc839a6",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.collinear.3.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.ensuresubpath.1.html": [
-        "aee1d50b5b15a809593fd588cdc5b1082315fece",
+        "81dc7b1bd818584e884d96684383597abbe42c38",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.ensuresubpath.1.worker.js": [
-        "8481a37108b072066e11a209260315082d722d43",
+        "99354ac735a89d0df6bfb7bff9bb5c162d6cbdf5",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.ensuresubpath.1.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.ensuresubpath.2.html": [
-        "36b143cdb3a1bbd6f001e471c6a7c13d39e8be10",
+        "43c9aec29411b6ebbcb57b8a22b13cae146121c3",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.ensuresubpath.2.worker.js": [
-        "e27280f5b659a8e210dec1ae1bb4b73cc94ca8f8",
+        "aad3d006c992d9bef7c2746905cf7821e1d1d7fa",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.ensuresubpath.2.worker.html",
          {}
@@ -476165,476 +477781,476 @@
         ]
        ],
        "2d.path.arcTo.nonfinite.html": [
-        "be6fcff31b7f48b733a5894a2a7d66db27f4fae3",
+        "982ad4a9648c64ea7a4963e898826f956ee63b11",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.nonfinite.worker.js": [
-        "6ad8e60123383102d57d0ee5700b06952849940c",
+        "6aa674fc90d6f890b0094186b40fb0f2d8fe653b",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.scale.html": [
-        "1abbf953ad48d11e005f992baf52438c033d6587",
+        "7139455bda45dad99548973a6ea80c95311c5251",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.scale.worker.js": [
-        "998265de84fa3dce6c1d87517c28a3d5a0218b8b",
+        "b06c8f935c5cbd634cc90db89f8b6d0ff44ee3a2",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.scale.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.shape.curve1.html": [
-        "7ba352fa5971aeb236704facc182f094e4be8db0",
+        "659b02ceed445dbe9ba7c38ae93dad9e7adb8e34",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.shape.curve1.worker.js": [
-        "ff04a00e19249cdd46f46f16f65036d13da5e8a8",
+        "5223b55abb29c8d9afe0f8a86588a5a0732f1531",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.shape.curve1.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.shape.curve2.html": [
-        "8d1f4953dd83a931e9494cd5fa4bdb32df466850",
+        "02ab6c1437d879ccb9e7454f60f95c6fcc0e9ea2",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.shape.curve2.worker.js": [
-        "b83dff1d2a15802a8e5d918d760d7790ef929b17",
+        "f06c2cdc33f2ff2192af430ff280123e1c9b61b2",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.shape.curve2.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.shape.end.html": [
-        "2806684328f574ffc335ebd4c8d75523ab358334",
+        "0871c39157f08c06cbdc7ef5c94a349a2140865b",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.shape.end.worker.js": [
-        "4f12e45a358f3558e3a7abc7e7b25d65bfcee8a4",
+        "f3addb0a0c7f1f42a60539dc29aa372b9fbfdc51",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.shape.end.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.shape.start.html": [
-        "5db369a5f14136d1fb6f99790d9518e8dc0358cb",
+        "5040462ada3246bd67db2ebf54e81fa1d8bb958f",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.shape.start.worker.js": [
-        "d0a6e345586822027cb419c34855b3d7fa4b9c48",
+        "36706d600e2af9324a66c2b7887e405d90a3b140",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.shape.start.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.transformation.html": [
-        "4f470024fe902a0ae2bb1452d73f5c28cdc5257d",
+        "bea6374ea4e0a3300c1f4398c2de12282894c5b0",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.transformation.worker.js": [
-        "46bb4616c8b657bae1d94fec45b7063a2d231068",
+        "925140b675018d944fc5ccbb1bc7ede5c40b077f",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.transformation.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.zero.1.html": [
-        "e01f15b0dc596c18d9146615407b2c9d58f2d71b",
+        "00541a938b6655c2bdb4fe6360dba6c8bfcbaeb6",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.zero.1.worker.js": [
-        "9768431b73742d191fd51adfac169177753e0e3e",
+        "cee6d1c5baa4074d48e9ad485a0b03df66b8a7ed",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.zero.1.worker.html",
          {}
         ]
        ],
        "2d.path.arcTo.zero.2.html": [
-        "94158caa0a60810fde6e7f90487992ab323ee1d3",
+        "e10fe5ce95e10c7d14401aa24223d7cbee87c798",
         [
          null,
          {}
         ]
        ],
        "2d.path.arcTo.zero.2.worker.js": [
-        "63843ec31f5b1de871b6e94687c0c4309e990156",
+        "d0cc4a1484a70fadc2f951f2df7a4e7c8d006426",
         [
          "html/canvas/offscreen/path-objects/2d.path.arcTo.zero.2.worker.html",
          {}
         ]
        ],
        "2d.path.beginPath.html": [
-        "c3c826df3f8a2f89d44d75b0dfc827c802554d04",
+        "8b9c4cdc7ac45899f2576ddab69f01d7813e5bcf",
         [
          null,
          {}
         ]
        ],
        "2d.path.beginPath.worker.js": [
-        "e13b8bf0407d310c3f2fc9137aec015259be18bb",
+        "18b81afa5c4d5f2dbd3031e48b651e66e8b588db",
         [
          "html/canvas/offscreen/path-objects/2d.path.beginPath.worker.html",
          {}
         ]
        ],
        "2d.path.bezierCurveTo.basic.html": [
-        "9b595ab65facaf4e5222de7d9b8e0e19fcad2756",
+        "691728743228409114c0c2b92fef18387bdb93fa",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.basic.worker.js": [
-        "d22fdaa9c854f54f83aaa5e8f5f259ea6869fa07",
+        "a365372c9e67ffc195b565d37d08bdef8419f680",
         [
          "html/canvas/offscreen/path-objects/2d.path.bezierCurveTo.basic.worker.html",
          {}
         ]
        ],
        "2d.path.bezierCurveTo.ensuresubpath.1.html": [
-        "064d12ec9d8bcf1616866719a568d2261e4f76e0",
+        "67dd771fcbe72f4969964f2be2790e571cb041c6",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.ensuresubpath.1.worker.js": [
-        "32927fffe3e6f103e812ccd5c6cf0877ad7d13a6",
+        "beb275ba37811391f2adf3bc1db089da7f9bd58b",
         [
          "html/canvas/offscreen/path-objects/2d.path.bezierCurveTo.ensuresubpath.1.worker.html",
          {}
         ]
        ],
        "2d.path.bezierCurveTo.ensuresubpath.2.html": [
-        "55a05d34defaa495272b27e7f6c446f6e578c0b2",
+        "d4f99e1e2a406445dcb3cacc7bf25edf4a633b1a",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.ensuresubpath.2.worker.js": [
-        "a053b5d4a56b44c9cf2990159d92c6613965ff8a",
+        "7176dba0787607d08d421ab4826b24de913ef784",
         [
          "html/canvas/offscreen/path-objects/2d.path.bezierCurveTo.ensuresubpath.2.worker.html",
          {}
         ]
        ],
        "2d.path.bezierCurveTo.nonfinite.html": [
-        "c396f92a6b83c712319aab3effb3d06352e5d420",
+        "4c5abfbdc1e594afc4c3e4ea6a53d74cec953143",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.nonfinite.worker.js": [
-        "fba6b76c8e743a68526884662b97ed9016582698",
+        "752cb1b0ab8867e3840a9cd1f40560b5aebaa1ab",
         [
          "html/canvas/offscreen/path-objects/2d.path.bezierCurveTo.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.path.bezierCurveTo.scaled.html": [
-        "7bdcb0eec245ff19ac7a4a5d94c1df2074c9c904",
+        "2608237a6c00dc84494af88bdd7c334fc4ace6b2",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.scaled.worker.js": [
-        "bca64bd636677cf83e8442a66b5d3058cff49512",
+        "641cccf4b46a2e4f3483c0ae1073bd95c32dbe16",
         [
          "html/canvas/offscreen/path-objects/2d.path.bezierCurveTo.scaled.worker.html",
          {}
         ]
        ],
        "2d.path.bezierCurveTo.shape.html": [
-        "a270bf7fce504da24c170c14a1c718b3f3b8c23f",
+        "5f8f8daac2a53d2755f017faa69b698965a59958",
         [
          null,
          {}
         ]
        ],
        "2d.path.bezierCurveTo.shape.worker.js": [
-        "70951148b50f96c89766b5ec205988934e722ade",
+        "ee42982f2f6eba356b8fbdb185e6309435593cb6",
         [
          "html/canvas/offscreen/path-objects/2d.path.bezierCurveTo.shape.worker.html",
          {}
         ]
        ],
        "2d.path.clip.basic.1.html": [
-        "dde6f8bb33ae2b087d2bc301a74e2c17289831e9",
+        "cca53f6be6d1546a88a420202a4bd326ff51410d",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.basic.1.worker.js": [
-        "b0f42b96d55cebae6c953b789e8fc1b573c23cb3",
+        "cf5a5d3b63f4ec3d9f3c6ae79cb831f4284f5f79",
         [
          "html/canvas/offscreen/path-objects/2d.path.clip.basic.1.worker.html",
          {}
         ]
        ],
        "2d.path.clip.basic.2.html": [
-        "4aa16597b87717181a9d7e2aea721e454b9d3870",
+        "d5ef79bf1a13cf3d852a2b002c724cc989a1b742",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.basic.2.worker.js": [
-        "dfc5c18e8e471fa2caa47055482e05f3d8785037",
+        "bad906d4b73ece1e0857f05de5a5e34b30cb0745",
         [
          "html/canvas/offscreen/path-objects/2d.path.clip.basic.2.worker.html",
          {}
         ]
        ],
        "2d.path.clip.empty.html": [
-        "475c046514bb1e778b2339cd97cb9af893bff43e",
+        "d74fff0d81fcca4960c2c8552138ec641d297344",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.empty.worker.js": [
-        "fc15dbb5f79670aaadb509248f74cac5695c2c45",
+        "51beb6426a5a6a0454ed6d4dba5805825442bd2a",
         [
          "html/canvas/offscreen/path-objects/2d.path.clip.empty.worker.html",
          {}
         ]
        ],
        "2d.path.clip.intersect.html": [
-        "18b8baa97338aa45791aa9bdc33b64c9cefee6ab",
+        "3b269ce102d5574d8c5d08a98f580dd541acc992",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.intersect.worker.js": [
-        "85b8e0f2ddc0cb500016976de68425bf6e19c177",
+        "791c1bb78481ad33852d0770e3ece9b73044a759",
         [
          "html/canvas/offscreen/path-objects/2d.path.clip.intersect.worker.html",
          {}
         ]
        ],
        "2d.path.clip.unaffected.html": [
-        "739f5d378c314a5a22a4fd6a26e9f5d99704fd3e",
+        "a0ba94fb8a430f2fe5a294820419baa61a5a4b0a",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.unaffected.worker.js": [
-        "3c83b0918640f2ba401b8eeadc0035d8533f4dd7",
+        "e03257021c4b758490f3d7384dee20fa4fe21e46",
         [
          "html/canvas/offscreen/path-objects/2d.path.clip.unaffected.worker.html",
          {}
         ]
        ],
        "2d.path.clip.winding.1.html": [
-        "ef1649f44b62338e315123d137124049ed27da82",
+        "9a20e493db269e40964332a45e90d334d1f0e117",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.winding.1.worker.js": [
-        "8a7bdb7f11158a4ea5ee1d551fa9862785dc2bfe",
+        "02565fcc8b82c4baba382fa0c16f287c1216b1b8",
         [
          "html/canvas/offscreen/path-objects/2d.path.clip.winding.1.worker.html",
          {}
         ]
        ],
        "2d.path.clip.winding.2.html": [
-        "f5acfb24603368a0fa98243a6714909e7cccf21f",
+        "1f223a3b38fa2acc115e5e6da2f07d0802dfbb0c",
         [
          null,
          {}
         ]
        ],
        "2d.path.clip.winding.2.worker.js": [
-        "d97e45cd08880afbdd5811228253c5d3505baf37",
+        "e7e8c5039def31451d04f73ee3a3a6190380e115",
         [
          "html/canvas/offscreen/path-objects/2d.path.clip.winding.2.worker.html",
          {}
         ]
        ],
        "2d.path.closePath.empty.html": [
-        "c4a2262e3f2836ade3b9d285ffe74b15212ed481",
+        "50ea865696cc9e28fda6b9b4ab8881d2c8ce5188",
         [
          null,
          {}
         ]
        ],
        "2d.path.closePath.empty.worker.js": [
-        "f5eb5038cb19ee638960712c40772473d0d85b41",
+        "c06ce48635f434d8f806dddd6d0097bc1c8421b5",
         [
          "html/canvas/offscreen/path-objects/2d.path.closePath.empty.worker.html",
          {}
         ]
        ],
        "2d.path.closePath.newline.html": [
-        "11339fa4de9c0fa645590960a02f354a800f7cab",
+        "dca2e01b7e934b0ba2f2028bc53100758f081027",
         [
          null,
          {}
         ]
        ],
        "2d.path.closePath.newline.worker.js": [
-        "13a9f4846605caed8f0172e9226fe36c3f36a718",
+        "5d27821f5511cc6ca35f156bccfddf1c069397dc",
         [
          "html/canvas/offscreen/path-objects/2d.path.closePath.newline.worker.html",
          {}
         ]
        ],
        "2d.path.closePath.nextpoint.html": [
-        "e39f21fe6a54f475ba31feb3a4638b480a341b7b",
+        "4cf02d2b64417e8402fe95ede1c8611b1c1dce95",
         [
          null,
          {}
         ]
        ],
        "2d.path.closePath.nextpoint.worker.js": [
-        "961891890e1041e13e192fdcd827231284ad0e70",
+        "8a84ce7d83ccce1b8d8a9ab09b779ddf3e75d881",
         [
          "html/canvas/offscreen/path-objects/2d.path.closePath.nextpoint.worker.html",
          {}
         ]
        ],
        "2d.path.fill.closed.basic.html": [
-        "9d0c23538ac6d3cb054c44773b7f2650351203fb",
+        "72e755f7e8f0e7d799128af86bfdfa3b6a5a4772",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.closed.basic.worker.js": [
-        "e7650bfda0da9bd4c565e9f1858bc9012504c04a",
+        "2c63e1ec97f1d1b66300c2cf2123afc4d8373a75",
         [
          "html/canvas/offscreen/path-objects/2d.path.fill.closed.basic.worker.html",
          {}
         ]
        ],
        "2d.path.fill.closed.unaffected.html": [
-        "fb3a715a98d5101a109cbe22f8b4ad28e3c516b4",
+        "9d54512539870412e64e54602b070b867d7949b2",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.closed.unaffected.worker.js": [
-        "3f447087ab8d3c4a12594be429c05e0fe1999ca1",
+        "6b4aa9244f3deb47efaccb3921b6aa8b739f6f63",
         [
          "html/canvas/offscreen/path-objects/2d.path.fill.closed.unaffected.worker.html",
          {}
         ]
        ],
        "2d.path.fill.overlap.html": [
-        "f933a67c26fffbf5245dcc8903d03c82c1cdac7a",
+        "6eaf88edcde61e5d469b6c6a03457dd225da012d",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.overlap.worker.js": [
-        "907c9491a3dc60475670641d3405591238e0c6df",
+        "e1d64fe40bfa8dcb676c1f1769ce84490133c906",
         [
          "html/canvas/offscreen/path-objects/2d.path.fill.overlap.worker.html",
          {}
         ]
        ],
        "2d.path.fill.winding.add.html": [
-        "87ff1254e229e8142fe16645507cf3b3f7ea639c",
+        "c5f64924da313f23323507a2d08924729ab9b5f0",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.winding.add.worker.js": [
-        "8963be3c7fc12af367e9884f0ba62409486b3b11",
+        "b40e1706239ddc35063b00ee3e9bedc686366815",
         [
          "html/canvas/offscreen/path-objects/2d.path.fill.winding.add.worker.html",
          {}
         ]
        ],
        "2d.path.fill.winding.subtract.1.html": [
-        "31b9d4fa20ac955bd8d35eed0eea1ce4f703ccfc",
+        "4f553f2bc32375609f307f0c53c73d45df19ca5a",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.winding.subtract.1.worker.js": [
-        "4fb6a5420e18699696f25f89e63687b191ef828a",
+        "a820915413952806e0f85984d1b2fe7a89dc76d5",
         [
          "html/canvas/offscreen/path-objects/2d.path.fill.winding.subtract.1.worker.html",
          {}
         ]
        ],
        "2d.path.fill.winding.subtract.2.html": [
-        "3f7502dc7fda075c6bf5e8be886391d3d88b5802",
+        "cf1fcaa2d44759f17e58cb0f4ba3a21e5c56f649",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.winding.subtract.2.worker.js": [
-        "532f89c0df7533612c40ea1672ad016a0ede251b",
+        "2c83a41ae8e21b7bffb51e9405781ebd10150605",
         [
          "html/canvas/offscreen/path-objects/2d.path.fill.winding.subtract.2.worker.html",
          {}
         ]
        ],
        "2d.path.fill.winding.subtract.3.html": [
-        "2e0e0c6f783fd45896216d6f27bcd99ab12da2b6",
+        "ffcbfe2518de25cef34b4c2b2ed771ea819cab44",
         [
          null,
          {}
         ]
        ],
        "2d.path.fill.winding.subtract.3.worker.js": [
-        "cf54bfb105c214d4522d69b7c56c38849839947b",
+        "ca5510abf215cd7a015ee8354c2b958da8ae9593",
         [
          "html/canvas/offscreen/path-objects/2d.path.fill.winding.subtract.3.worker.html",
          {}
         ]
        ],
        "2d.path.initial.html": [
-        "851deac9919c2f12c56ae366274540f94f105044",
+        "35c96cdab5da97358683d2164c5a76058b4e303f",
         [
          null,
          {}
         ]
        ],
        "2d.path.initial.worker.js": [
-        "4bdc8ebf6fb01ed04fab6dee542adf330b90259b",
+        "de8597fbc3c50674defe7d66b187d719692ad0e0",
         [
          "html/canvas/offscreen/path-objects/2d.path.initial.worker.html",
          {}
@@ -476879,56 +478495,56 @@
         ]
        ],
        "2d.path.lineTo.basic.html": [
-        "ab309f428ab7180af844d443a7de4168b51a7cf9",
+        "3247ededcc872686c0881594d7b4c9327d5e82aa",
         [
          null,
          {}
         ]
        ],
        "2d.path.lineTo.basic.worker.js": [
-        "f00439ef1b52f3b6765c32d5a30d6d8871ce7011",
+        "980de5c1b286b8b9fde4ce2ce8ed4345b2a9c78d",
         [
          "html/canvas/offscreen/path-objects/2d.path.lineTo.basic.worker.html",
          {}
         ]
        ],
        "2d.path.lineTo.ensuresubpath.1.html": [
-        "f6b85bccb5689d6e75ae61a272e6dbf15c7877cd",
+        "5a15f9ece489e918cbd43b3e127e478845a8fc64",
         [
          null,
          {}
         ]
        ],
        "2d.path.lineTo.ensuresubpath.1.worker.js": [
-        "908fe2d95464b111483a9efc4977a5325ed97ed9",
+        "024754ca0ea07155bdce67e70dc1472a62dd1f86",
         [
          "html/canvas/offscreen/path-objects/2d.path.lineTo.ensuresubpath.1.worker.html",
          {}
         ]
        ],
        "2d.path.lineTo.ensuresubpath.2.html": [
-        "8659965bef293f0a476920de496f7b1598e92585",
+        "eaad8dabcceda6ed9ebe1b8e33430dbcc2b6bf7b",
         [
          null,
          {}
         ]
        ],
        "2d.path.lineTo.ensuresubpath.2.worker.js": [
-        "878b86d68614c950e71ae83047a366e43d7665fb",
+        "2a15c9e14d4f3c7eb1af219ef25a56ea2905d738",
         [
          "html/canvas/offscreen/path-objects/2d.path.lineTo.ensuresubpath.2.worker.html",
          {}
         ]
        ],
        "2d.path.lineTo.nextpoint.html": [
-        "7d42c0df8e0bb01a60f46e03297b033c04cf11c0",
+        "fc697b9be59ba0426d91c1f0d2ae79261a4c2067",
         [
          null,
          {}
         ]
        ],
        "2d.path.lineTo.nextpoint.worker.js": [
-        "258c0fefebe22434cecb5979ea1f96eaa5445a5c",
+        "de9d56be06e71c5c07a31d3f50dce1ea0668eee2",
         [
          "html/canvas/offscreen/path-objects/2d.path.lineTo.nextpoint.worker.html",
          {}
@@ -476949,924 +478565,924 @@
         ]
        ],
        "2d.path.lineTo.nonfinite.html": [
-        "ff8bda77e2aa5a360d652c5f91d7c9fe8db8f2d8",
+        "02d77163fd27f59133bbf62c0f31502fab1dc752",
         [
          null,
          {}
         ]
        ],
        "2d.path.lineTo.nonfinite.worker.js": [
-        "5eaa4f0eed2e7350842e0e141312791aa884a56b",
+        "5161b4e43229758d61c405be7b40304ec00e2a49",
         [
          "html/canvas/offscreen/path-objects/2d.path.lineTo.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.path.moveTo.basic.html": [
-        "7e2a58355e72b470512780f69b64e04d2dd3d88c",
+        "8363792c7067c02f3ee7c4f418753243392e725a",
         [
          null,
          {}
         ]
        ],
        "2d.path.moveTo.basic.worker.js": [
-        "9cf101f5e0327e75274a433bb59cd008304bfd96",
+        "eca39660bceea999729a6a09adf3184688121be6",
         [
          "html/canvas/offscreen/path-objects/2d.path.moveTo.basic.worker.html",
          {}
         ]
        ],
        "2d.path.moveTo.multiple.html": [
-        "cb2c4a408cd3e30fe571a2d72a769410277cdab0",
+        "928c9783d447c17f1afed702157ad28f2c81a051",
         [
          null,
          {}
         ]
        ],
        "2d.path.moveTo.multiple.worker.js": [
-        "2001b2a6c42cd0dfc9219543cfc1a6b99788f91e",
+        "686f5ae84ad82a27d64d3495e77f6b4bdc21709a",
         [
          "html/canvas/offscreen/path-objects/2d.path.moveTo.multiple.worker.html",
          {}
         ]
        ],
        "2d.path.moveTo.newsubpath.html": [
-        "c0b170a10e531490ccc812c0e48e577a1bbace36",
+        "89fda23ffc90c7d24844343d306caf1372a7e82f",
         [
          null,
          {}
         ]
        ],
        "2d.path.moveTo.newsubpath.worker.js": [
-        "721cb1a82106b35ca4a95d2349abbf37d0849dcb",
+        "d00491c42bfe1d65783e90316f65f028d8333f3d",
         [
          "html/canvas/offscreen/path-objects/2d.path.moveTo.newsubpath.worker.html",
          {}
         ]
        ],
        "2d.path.moveTo.nonfinite.html": [
-        "a2dda9e5feeba3aaa2212ddf221fd04af9c2a73e",
+        "1a2e6cfe83977c485fc54fa2936c67c72151bc27",
         [
          null,
          {}
         ]
        ],
        "2d.path.moveTo.nonfinite.worker.js": [
-        "d574e2c121a9ee89a614985d797268c3da801344",
+        "ced534fb9543e67567798044a1f31212571e368c",
         [
          "html/canvas/offscreen/path-objects/2d.path.moveTo.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.basic.html": [
-        "777b24adf485a2b525aba2062cc7ee67295947bc",
+        "46a83e112c507b030cfdc264e45cb9127235cfaa",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.basic.worker.js": [
-        "d19af374716f0efe7be72611b213185a088fed76",
+        "a1dfa045d94486a04de4e0134cc0ed21619f7317",
         [
          "html/canvas/offscreen/path-objects/2d.path.quadraticCurveTo.basic.worker.html",
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.ensuresubpath.1.html": [
-        "9cc6adfe9d94e4261d82d1ef71bea2b8b93e2797",
+        "37662e46185236496a6a85b3a0010473c215d6d3",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.ensuresubpath.1.worker.js": [
-        "6b119853e78c77a3040ddf745a1ca4f9df9692bf",
+        "fe20e7b890fb99c0f5ff1af90d46b768a52882da",
         [
          "html/canvas/offscreen/path-objects/2d.path.quadraticCurveTo.ensuresubpath.1.worker.html",
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.ensuresubpath.2.html": [
-        "4ceadbd6f1649cf1090076ea21e6034f3bd4854b",
+        "2f18424749f100ee7ad65033c47c5a2b77ba5e49",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.ensuresubpath.2.worker.js": [
-        "1d316175570551410093dbdc86432a22cda16887",
+        "f840168f986c2fe693f4d5e90933f982f8d52e74",
         [
          "html/canvas/offscreen/path-objects/2d.path.quadraticCurveTo.ensuresubpath.2.worker.html",
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.nonfinite.html": [
-        "4f32efb443a20826274041785f0148e35dbb5136",
+        "1083f027e2c664029660c250402049ca83461fd8",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.nonfinite.worker.js": [
-        "738b73590631d830ec2a9fd99df45a271ab6cf4c",
+        "df17bd6d3627cfabe8765142207bd30dfcedf996",
         [
          "html/canvas/offscreen/path-objects/2d.path.quadraticCurveTo.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.scaled.html": [
-        "14bff6a1466ff38a07daa94d0cdf04eb5308364e",
+        "60ba483f14d2f77071f8370f24257f5ca1f9f7da",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.scaled.worker.js": [
-        "48fadcdfdb2ac9f1ea5ad0949d140acda8440225",
+        "298001b212e08c67d3508feb4b347e3221d41699",
         [
          "html/canvas/offscreen/path-objects/2d.path.quadraticCurveTo.scaled.worker.html",
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.shape.html": [
-        "5090ea2897558490c56c394ad83ded496188a006",
+        "21cb175d598881728a7402243c59d36998e67767",
         [
          null,
          {}
         ]
        ],
        "2d.path.quadraticCurveTo.shape.worker.js": [
-        "2c22a2372724a2fe2c3e87fa66df12ea10bd4625",
+        "f7aac9135afa3b2e62c0d49f2880b85838876598",
         [
          "html/canvas/offscreen/path-objects/2d.path.quadraticCurveTo.shape.worker.html",
          {}
         ]
        ],
        "2d.path.rect.basic.html": [
-        "16fb2998a90aacb54d1f7bb5255d4a6e29a0d980",
+        "5214bd8dc059bcbfaf5b6d30f1cef01bfd2dde13",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.basic.worker.js": [
-        "e547f6d01d7fc780943bdfdefb465f847706ca6a",
+        "dcf3dc2a4bcffb335c4a01f4b486d0f9b7cb4b41",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.basic.worker.html",
          {}
         ]
        ],
        "2d.path.rect.closed.html": [
-        "8dd8f1810fd57de85807e5d87df630da7d4bfdf2",
+        "70db3725a1140394eec244d45fb53aef27ed23ac",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.closed.worker.js": [
-        "9c6ca9df16762c5279bedf1b1cb91d5f383fb11a",
+        "6ee09ef8d4379c0b18daf473ced695b6004abe6f",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.closed.worker.html",
          {}
         ]
        ],
        "2d.path.rect.end.1.html": [
-        "b3e59bc76751798d3dfc607c9b9301c40da1025b",
+        "bb4bfc0c9065b8a5f70e29216cda973f4644e6b6",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.end.1.worker.js": [
-        "33f5a72255b837312e26b482f67c5aba04d62331",
+        "f576ac436642ffd2e2abfcf16fb137f0aff899b3",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.end.1.worker.html",
          {}
         ]
        ],
        "2d.path.rect.end.2.html": [
-        "d58763b42e204c38ac088d66d4560220704ea107",
+        "1f945a858e9c46272edae786d6a6eb61f42aa8f3",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.end.2.worker.js": [
-        "7bbe9fed19a0be2e9ff174ac8be0c68504800277",
+        "8813ed81522a888c947f963eb58c6b4561cbcbee",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.end.2.worker.html",
          {}
         ]
        ],
        "2d.path.rect.negative.html": [
-        "c707698ccc7a12577cc4ddc32fd16dcdd5702b50",
+        "8c9effe2a546e351f8341f87f925febce40bdc5f",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.negative.worker.js": [
-        "f844c97d19429d25bd870ae02245b2127576f0bc",
+        "ea01c6d3f07eae1750131520684ce75d3afa78ab",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.negative.worker.html",
          {}
         ]
        ],
        "2d.path.rect.newsubpath.html": [
-        "cbd9c5830339eceb424c6310a41c323fbc45ac49",
+        "1dcfbe94869d5e6d2198cda8a917e84ee6f2a237",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.newsubpath.worker.js": [
-        "d5ad0d1f87d13e720264f5bf3545b75320b02813",
+        "44962c5f2f47e98eda3b91d79189bc3be719e8a5",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.newsubpath.worker.html",
          {}
         ]
        ],
        "2d.path.rect.nonfinite.html": [
-        "68931af372a5544f165d015ab68a6d02916a16d8",
+        "7f92cf5e48cb4bda3063f535195381ac3b573c7d",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.nonfinite.worker.js": [
-        "9095b9e721af29f933ccfa01dc9e21092214ded7",
+        "6fa1e82ae482e9b3b8d9440f9f3db927d0fc23d6",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.path.rect.selfintersect.html": [
-        "6e4fb684e3e052dd3a4387d8bfbad3d6732b3101",
+        "36c3f074194ed92ccb96d9e703dd78032cf4131a",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.selfintersect.worker.js": [
-        "85ec849010b881d98e48964a89b8a3b83635db78",
+        "84c2687f309350ff31b1ddcb46008b1c7e9f4634",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.selfintersect.worker.html",
          {}
         ]
        ],
        "2d.path.rect.winding.html": [
-        "15500294d095ab49db4dfd8aa89e65fb45b38a80",
+        "c4f4128188baff61e4456a42a8dc7d229c13f38c",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.winding.worker.js": [
-        "d406db9b59de68d650ed9ed66d848fe55891d4ef",
+        "90a3d05e8b21c58915b36f6a43d3b0889a574358",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.winding.worker.html",
          {}
         ]
        ],
        "2d.path.rect.zero.1.html": [
-        "f2772ccd634f0f735c5ac7acc6b40d0dc45c75ad",
+        "90c0bb1f68a71e1959dc04cb537f0852b7ebd8d1",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.1.worker.js": [
-        "33d2be8a50a85f7801e3fd531a132e2bad9ab1a4",
+        "4d080710d070bd8149b5521202f7b0c691cd072a",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.zero.1.worker.html",
          {}
         ]
        ],
        "2d.path.rect.zero.2.html": [
-        "8abca945cfbf1a1e1057f2548531de496d25e29c",
+        "4c3ae6f6ddfe8f828c06da68471ba8b6682b30ad",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.2.worker.js": [
-        "7c580da1f70503bedd9bec8b845a940c384e9b00",
+        "93d5a52875969291aa49cecc42343c6420dd7ce8",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.zero.2.worker.html",
          {}
         ]
        ],
        "2d.path.rect.zero.3.html": [
-        "c0af2d3e8962448d944f167613128ae42a078cdf",
+        "86bd7494186b075f7e8438a91892ecbb2dcdadc7",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.3.worker.js": [
-        "e6b7da7e31c3d01be84a7d60fb6f0b2896ac28bf",
+        "6403de43c03ca076f5fac03dcc2aed1e468dff8c",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.zero.3.worker.html",
          {}
         ]
        ],
        "2d.path.rect.zero.4.html": [
-        "fd40e7881bbc9d9932f40f88530802f2407db0d5",
+        "063ef2ba1d5543c6a3d41cf8e42ae055ccc5d4a9",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.4.worker.js": [
-        "c8cb1e2fc875528549ec4e386e377a53ca4b6f99",
+        "87fd69856630e6a241adb078732ca4c3c5ce1c4b",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.zero.4.worker.html",
          {}
         ]
        ],
        "2d.path.rect.zero.5.html": [
-        "d58b09dcc8d241f1a28fa3ac31fb5ad858fbb87f",
+        "0fa0b0755043613a09cb4ba66b3b1517045864fa",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.5.worker.js": [
-        "77bd33c163da20708b78bc1406d7cf12bc556442",
+        "77851f54d3ecc1a85b26541bae286e94f3cd1876",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.zero.5.worker.html",
          {}
         ]
        ],
        "2d.path.rect.zero.6.html": [
-        "7828d138d9aeeb14c89a70899dfbe4744a10b4c0",
+        "a3cf7b60ac7f3339371d08a932ce7b829dec6a39",
         [
          null,
          {}
         ]
        ],
        "2d.path.rect.zero.6.worker.js": [
-        "93e41f586c593867b485beb036555744484bc53e",
+        "5db284837c4f6b8d5df023737c8e38c32b6683eb",
         [
          "html/canvas/offscreen/path-objects/2d.path.rect.zero.6.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.dompoint.html": [
-        "d6b2aff3ffc835417159ad237357db41630b28d7",
+        "479ab00cd7df37738c0ffe670431c6ebd8395722",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.dompoint.worker.js": [
-        "224f4d6c630eab02fcf2a9a43b8006ff6f80efd9",
+        "ba4fb4e611fce50e4a995fe5b24a77532f4d33a6",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.1.radius.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.dompointinit.html": [
-        "f13e6dd45f253d67d8eccbd6a0efce7ba33ca2a0",
+        "18ff259e66cdda04ea2e42ebb7bc4444b1026709",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.dompointinit.worker.js": [
-        "7b3d4cb6767daa87dc83e5879db7239951a74e5f",
+        "589950c04e077b0ec7152d14f2f40f093308c8ea",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.1.radius.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.double.html": [
-        "4eef53ca2055e24848af177d2d18fe4d6099ce90",
+        "4761bb5e5e8693b67921c2c4386079c9f207a902",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.1.radius.double.worker.js": [
-        "f637778d5ba9dc84b16b11540201051b73e367ca",
+        "57f28c77786c46ed867ca9c924ce9605e0e38bac",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.1.radius.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.1.dompoint.html": [
-        "722d11208c7321752dfb01d869604b9b6a415ac4",
+        "c96ed08f05c6e387f9c1e394a87b26bf0817cdd9",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.1.dompoint.worker.js": [
-        "1324fd1a0c194cec683688ec72261f9f3be9cf6e",
+        "7e7a4efddc0ced8d67a5e6ee3b3a2c86905db43d",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.2.radii.1.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.1.dompointinit.html": [
-        "8338c9af65ac0b33bb925967b9812a3ce97b8b5b",
+        "02b889c7592f75a05f078b7852f402e76a4d08cc",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.1.dompointinit.worker.js": [
-        "4e91ac092fd8be47eabe1fbf7927f34a80fb7718",
+        "fcc3cb088ae197a54a9932080ef64ebf89c97ed8",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.2.radii.1.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.1.double.html": [
-        "a864fbd18e4c9ea5753cb24fffc810477567a890",
+        "2a6a030237bd249b578ab15acdbbdced4070c997",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.1.double.worker.js": [
-        "553c1073eeff3b0dca5b49396dd2f596c3023f85",
+        "6d4d029b1c8903f2c75462298dd0880532b76ab3",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.2.radii.1.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.2.dompoint.html": [
-        "b81559614b31cb1145740a18e74e545748934d13",
+        "bc6e27c6830f46c4d8684ddab40fe17dc7ffc0f1",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.2.dompoint.worker.js": [
-        "d753a2bed41a2dec8c2d7d88c2a3b3e6dc7c3e79",
+        "fead59e863ba9686e6bec03d17daa137f501cfeb",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.2.radii.2.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.2.dompointinit.html": [
-        "9e2e26810e07f3ab48a9ce53d995b5187a924268",
+        "fcca1c739fcf93c305d83e0a18e397ad4bde877c",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.2.dompointinit.worker.js": [
-        "824d6d4a414a8de12fa00879ab41a8deb08f9343",
+        "ab334e4ca06a36c52a466bb09eb9f7e0ce37a585",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.2.radii.2.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.2.double.html": [
-        "481833be2a11253d8188c1642f0d4a04fb7f9dd7",
+        "2bc67375669dbc386f33db9ae0c23ccd377889a5",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.2.radii.2.double.worker.js": [
-        "ab65f619fa0a1cdb72f49c49f4b2ef0ebe7632ae",
+        "d355852a5ce17e47ebb8caa73f38a6cab0e39ca8",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.2.radii.2.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.1.dompoint.html": [
-        "0f1b60fb09951a8c45d96dd3eadc7cb7becd0c56",
+        "f3388e6562e19b31a39403b5bdfea8829baa6a4c",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.1.dompoint.worker.js": [
-        "c16a781c07faaca8cca2ac4e310200f8ba77d956",
+        "36c6401bf3d516e29dfd86caf1c83ac590ed4dfa",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.3.radii.1.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.1.dompointinit.html": [
-        "08dde930cea06d149dc09aeb67ec0590235a3d8d",
+        "dd96e859ea1bd932d39a8727a1731e0fbea76064",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.1.dompointinit.worker.js": [
-        "53c33a3313f3fe366141afc121829b645e98f2d1",
+        "a497d5788baaaf15092595e105b925227ca9cd23",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.3.radii.1.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.1.double.html": [
-        "cf9ee8642485632a1f2dd26403935844c828d887",
+        "4c5f57122cd8b74e2a2f1c691187a13c73306688",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.1.double.worker.js": [
-        "dd64668c968f0a87152e408083eee9c97f01ddab",
+        "171a2ae5e6f6f9dbda76f75f67a7c2ca16b1136f",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.3.radii.1.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.2.dompoint.html": [
-        "918133e0b23ab2dcff1501024676caf65136262a",
+        "3459ac27bb2f454d56368270aec905b693937134",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.2.dompoint.worker.js": [
-        "f0bd34ee6c507342e25e9721ffbd16edf4d13d95",
+        "9588780f978dc0d1e5019d163577502ac20f31ab",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.3.radii.2.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.2.dompointinit.html": [
-        "6f7ecac8dec0f056eae43f60da22250dda692014",
+        "6476be489f78dfa4d4e642ebd6778dbc1bc11037",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.2.dompointinit.worker.js": [
-        "dd5d17023a1bc8726b8b7af611a15dcdcb9f00c5",
+        "42dead8509b7c840db9ea91d1139a04fff0c67a3",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.3.radii.2.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.2.double.html": [
-        "380d31634e102e929ce7785eb2caaf0ef9281228",
+        "652745e0bed6036769074f8f9b4db15ba3e7d3b9",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.2.double.worker.js": [
-        "1fd9fca33071e75e0e8dfffe3d1b967d21a9b9e1",
+        "e3929fbfdbb4b31ab09e61c0e5e9091084d17a11",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.3.radii.2.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.3.dompoint.html": [
-        "fcde6b974d6653f802639b3029ea1b7b60950522",
+        "1c295143c814f4f5690feab1003a4ca42576cfe3",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.3.dompoint.worker.js": [
-        "7d7989807ed86ae319d7a7364e9e1166eae0f3ec",
+        "c8e08ec297f1439ad142101115460dacada6dfb4",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.3.radii.3.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.3.dompointinit.html": [
-        "3d4b1b1b5aaf327e77cb509f7bcbc1143ee5931f",
+        "f8e62a5bf625a8f9af31832b53328aa9fc71d74e",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.3.dompointinit.worker.js": [
-        "c54c88a83528cf68cf34a8e91a8139a0fb0931ec",
+        "0fe2b89877a1641555e755599cd137df1ce20d7c",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.3.radii.3.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.3.double.html": [
-        "fc4e640ac6ef2f9576bd026421df25e81ee6e191",
+        "ff1301d9cd4308577dc961d8da9b353b349c0bbb",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.3.radii.3.double.worker.js": [
-        "86628624dba35312c49b682f25f2261eb05d8305",
+        "2422435d5264920601be37092d5f4c2f2117bbab",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.3.radii.3.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.1.dompoint.html": [
-        "3d22bb9e407bd80537857307ec46fc6febee34d1",
+        "3110983f7f84aaab0c899803249ca8cde5c3a8eb",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.1.dompoint.worker.js": [
-        "623ebe432c5f83ddeb38a77d61861a32ebdfe356",
+        "3bdb12e029893c969843fc48140d345a5d8a137f",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.1.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.1.dompointinit.html": [
-        "aaffcd27bcb0cc0e767192cb6f2d8d062507cde9",
+        "976b39a10216046702bcea5c883ff667843d5568",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.1.dompointinit.worker.js": [
-        "f9fb961af044919ad843f505092ef8ad548c4330",
+        "86b43ad2a1946c48ba33a386009652171e711a77",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.1.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.1.double.html": [
-        "1819c739beceddb21e50ce09f7ba303e8c6dffc0",
+        "c75d6420c9c5546f289508354e25214d1a38b681",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.1.double.worker.js": [
-        "2515f70e5abd7fa16dfe6cf6773169343d5374f7",
+        "925c93b0c9098ed97660e921b08e5bd8191aad76",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.1.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.2.dompoint.html": [
-        "1518d554a96d84dc5c39c2a9fe3e4833d7a5422a",
+        "33d861d6dcef4772dcdb66edbe3f4c8dbea5920b",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.2.dompoint.worker.js": [
-        "556a11714c647140bcbcdc7615271fe779bc53e0",
+        "12d1a8c8e633c6933789f477ee082e4df567c265",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.2.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.2.dompointinit.html": [
-        "78fe981d8bca617628d4fe55f6edf93d609322df",
+        "b088c2e717b56eb5789b988a17befa6a2de46667",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.2.dompointinit.worker.js": [
-        "81e115df9050a92779cfd2305af12097eb2c49df",
+        "49a247a26634edf2c57756ed9a32425891160939",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.2.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.2.double.html": [
-        "0a6e140f2608b1f8291aa6633faf784b3fec37d0",
+        "71395e0e9ee069c239bdcc3bc2aea22de35a3b82",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.2.double.worker.js": [
-        "57914f6ce49f2a91f67fd07dbcc3fe097b5a8c2e",
+        "f868c6272ef19dddbbd67fdc20e82a6ec4cf9b72",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.2.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.3.dompoint.html": [
-        "d9aceaa6f8ba0001555bcf797905b95ccefc68d9",
+        "4922bf37f22a0d4bc24edd67ab61061ed4710635",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.3.dompoint.worker.js": [
-        "6280aa5172a0a1e874a1dcf07af17644d9bab945",
+        "2da2f3591c614d01871e9390e192be6cbd413859",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.3.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.3.dompointinit.html": [
-        "cc0ad6d48b794e91703de68a4ece2c062ace9a94",
+        "3b6f2fd863f7b75ee6fa59bfa0af3134a5382446",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.3.dompointinit.worker.js": [
-        "0f54b1e6860a47bf039eff5b80de54bd707f2a54",
+        "65a3feb36f436c687a2b35f9417d13d404af7409",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.3.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.3.double.html": [
-        "93f41a5c44b99971a9aacb303d8928c0cdc6a75c",
+        "3dd2af98007fe9a2a44bd16104ddae43bb07f35f",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.3.double.worker.js": [
-        "08f2a21cee2c7a982eda5f7e10e940c07fe68299",
+        "a327ceac1579cdf60d0966bca11a0366e7d50ead",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.3.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.4.dompoint.html": [
-        "110e6848b01888ac0af7bf81dcdacf2b1543bab1",
+        "d61a3133cc476cab242cf49febe48950fdc8c0fe",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.4.dompoint.worker.js": [
-        "0240541b81ac0a23065317e440322c9339116f6d",
+        "d8a121e6da90bcb7c8307c0d5b8f0dae4df22254",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.4.dompoint.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.4.dompointinit.html": [
-        "a063eb19b224f47678ff62809c4f2c25ae235a7f",
+        "94ffc00433e099c73be839b27962e2f19141f81f",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.4.dompointinit.worker.js": [
-        "94d15618239518a7f6556493f2558cfec7715b3f",
+        "b7babb529615683008d95f0a1ad5779dec32554f",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.4.dompointinit.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.4.double.html": [
-        "efa52caa93bf5075276c656b802bcedba59b6b85",
+        "4ab2581847640217efbe0a6c2df7eddfedb15bcc",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.4.radii.4.double.worker.js": [
-        "058758d43f0519d8a8be822ce3fc4ed7feb82f41",
+        "ad4cca4953600820750cb5b74d4a3a7f6b5a5428",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.4.radii.4.double.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.closed.html": [
-        "5cac59fef58b5fd23bff0e3eb3c760491ed46335",
+        "1b4abf012c7067f6f06563e537e7885e1a1ca5ba",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.closed.worker.js": [
-        "5aebb5f89cc30c39250f17e45b0c1ab1f1d72c58",
+        "e0f1b81aa42f58fd7379b3b0dd75b2f59b6edc02",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.closed.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.end.1.html": [
-        "c32178529c2b07cb8e9213b745077096f3d80c4c",
+        "5c6b3cd537d16384442f62274b8ac3b091845905",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.end.1.worker.js": [
-        "09997975cf2946b0f3ee8822c7ef3aa62a8f1706",
+        "1ec22bdb6a77046cac6b03ee6c1f8cf4d4276081",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.end.1.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.end.2.html": [
-        "7f5927fbc25d789d289dddd445c053302bb9bc96",
+        "3913f69d412f9afeb140e3c7dee8ddbcc1218ca0",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.end.2.worker.js": [
-        "95d111df85139962c8ddd84aea3b598242de9e3c",
+        "c3085d53c3b05b72c05a387769b72cb62949896d",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.end.2.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.end.3.html": [
-        "f42768d734dd4dcdf7ecf377dcdf66d9bb9b4e3d",
+        "349f13485c04eb0b9fc509e074cdd1e59ca7a9af",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.end.3.worker.js": [
-        "85d51f70160da0fb55c959be482ae93b0592a093",
+        "52b9c442838b618dad02ad4c21dd986b230e40c3",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.end.3.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.end.4.html": [
-        "197955bab5c3bd458fff43f81e57779a2cef07ad",
+        "3c99e3970a1557649637b4bcfa4b0395a0b05dd5",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.end.4.worker.js": [
-        "65febe5791bf8a196f4107e9b003d669f6e9f58e",
+        "1d57b8978f2871ee2cc6448e9a72b0c9c2682c72",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.end.4.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.negative.html": [
-        "644ebdfd0fd50e18702a6936ca9f2dab2f30e006",
+        "e3696ca1a5b78c2b27470e220b2fe15d0e45d1ba",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.negative.worker.js": [
-        "1191eb4fc5cd9bcfcb6a401ec6e12ff617610678",
+        "c34c20397a898bd866a3c11f2a0178b490abbdb5",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.negative.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.newsubpath.html": [
-        "4c1c27e1f299f60e9cc6f889dc1f8561b5d8b96c",
+        "6d0a8149077a49f4153d14d9ba3d2e07a737d7fb",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.newsubpath.worker.js": [
-        "8274f6d6179b813438355fd58bd769c8777ba2b9",
+        "c6f7934bee952684bfdbf05d909ec53d72c50bcb",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.newsubpath.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.nonfinite.html": [
-        "a5436e5027887bb5a8564b87fa602c48310e58f8",
+        "29773503013118e309faa3cd4b3b38c8ebaa0a5e",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.nonfinite.worker.js": [
-        "cc60f0f22a63c224752e38546929c193217827d9",
+        "68d0d8a09a3b3158896dafa73688b233aff65841",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.radius.intersecting.1.html": [
-        "73614cf6cff70e58d90bacbae7aa485e20363151",
+        "c1916bf78f29e60db84ef8b5e24ddba9c06093c1",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.radius.intersecting.1.worker.js": [
-        "f93f84b008f98a9743b55d6ceda0d9e990c9f433",
+        "9da41478d91ec440178fd61a8f4a37f60ff8bc9a",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.radius.intersecting.1.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.radius.intersecting.2.html": [
-        "1cb5a0c70743b7693cbb1d07ad92885729b07103",
+        "f2a69c4ffc722a9c39881d4b8d15f51aa9111b53",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.radius.intersecting.2.worker.js": [
-        "5adfb12b7aeb12656172449e9fe22680b737e1b6",
+        "f0d3f57ca48d0c2b9f58d55124179f418c79df95",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.radius.intersecting.2.worker.html",
          {}
@@ -477915,336 +479531,336 @@
         ]
        ],
        "2d.path.roundrect.selfintersect.html": [
-        "b2956458d72f89e364459fc7c2ca2f2e93801eb8",
+        "0ec253549036ea114cdfdea67461a79c543f523a",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.selfintersect.worker.js": [
-        "73f3cd3821fd77e5202d7e62ffb9e5d0fd82abc9",
+        "8b6221414bab712441cc2dc67048806f0553c0f1",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.selfintersect.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.winding.html": [
-        "c63a3a6af0546990eec1dfb4978c39994a31d3a3",
+        "e7f52fbf29252fae0daa9fa661cd249449208073",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.winding.worker.js": [
-        "7fd2b434a7fcbae51bf856a49caad85faa68dd99",
+        "82e6b5c313507f873572bac841318bf580ce5456",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.winding.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.zero.1.html": [
-        "e3071128380de4a3869df36ac11c635c6f360017",
+        "252475194ee89cdef3dfb4853fbb5b19bd1bce30",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.1.worker.js": [
-        "0663ee78441c3b89ad4c49509fe5befaed515fb1",
+        "17c9be78ec6f064b6258b6a9334a7a405a78158c",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.zero.1.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.zero.2.html": [
-        "637c979f8c88769baa1c07ce3ad962b8fabd4dbd",
+        "2463e88f1eb913236d94657b73aea50a495726b1",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.2.worker.js": [
-        "9b049cf2e27fb2c4147af7946fc95b104c9e8fea",
+        "9ae058a847667cc243925cd341956df848f9e152",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.zero.2.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.zero.3.html": [
-        "551c5ad45f2f53e0653904e929ffeaec04a7b320",
+        "39de433b081bdda5ebf67899c47eb9058113d4be",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.3.worker.js": [
-        "e66388d9a1df6e48a49f4aabeb7fa5e5f3ef5788",
+        "98d37e08e534336b145cb2e3ab83d76fb972acd3",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.zero.3.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.zero.4.html": [
-        "659505f58917ae37e5bd4359b52e1100c7153f5e",
+        "3c6c734b19b15fff1060fbf7a07ca5b0c03e26d8",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.4.worker.js": [
-        "53776dbdb945f847dac46d7651d36b3f097564ea",
+        "462cde2a03e88ed1dd7c5a53a4c15eb9b1b78783",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.zero.4.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.zero.5.html": [
-        "28415a36b32c5c2e4b65ffb3cfec5fd27cafc296",
+        "de66603a66b6168e4c60293f917e531e0073cfa7",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.5.worker.js": [
-        "fafa2dfb04dc66d5e82dd7d00037cd9525cb469a",
+        "0f706ce246fee9b87a2a595f901d6bc0e6585344",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.zero.5.worker.html",
          {}
         ]
        ],
        "2d.path.roundrect.zero.6.html": [
-        "36f98111374194542aaf3d6bc77cfb76bd1795d5",
+        "bd7ef0fa94c49c0abf8315a65572a7e0d85a2605",
         [
          null,
          {}
         ]
        ],
        "2d.path.roundrect.zero.6.worker.js": [
-        "afcfe8c1928142f863df4662f2de0300ccb2c5ae",
+        "f2115cdd4610f77fc279e62b6864eb33191acd65",
         [
          "html/canvas/offscreen/path-objects/2d.path.roundrect.zero.6.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.empty.html": [
-        "7ac1e1ae9caaf82db56a4ba9e8076bfe954a847d",
+        "a873b260da2ba91c4353601c0367f39782fea0de",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.empty.worker.js": [
-        "f21efdc4ffa976d19854e885963fa197c13e4d85",
+        "1852c91876810880da2e27973014b0e6899953cd",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.empty.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.overlap.html": [
-        "35cc9090d635d503e812970f04e15da85df101b6",
+        "252a840ed7536c5268649eb71036e031546a5272",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.overlap.worker.js": [
-        "aa7a1637319418b33a8df4c77a36cf57876722d3",
+        "aa7cc51d77402dbbf9ed23e178f00aeced43aa5b",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.overlap.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.prune.arc.html": [
-        "2d4fb8ed76b682cd4ba8f861b2916c49eb7bd8a8",
+        "67f25440dcd3975b3a495b1c7214df962a4c8969",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.arc.worker.js": [
-        "5d3a87f0fe88f51777a5545b4389f7e0ac7f82f1",
+        "ca5844ce2aa5ba7b6e9cf99a84504ea3f2be47b6",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.prune.arc.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.prune.closed.html": [
-        "8890e106c910b9c2e38284fbb82fbb6c1c77813e",
+        "1012975fcf41e37ae58481629dcef3bcb56db11c",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.closed.worker.js": [
-        "cffdfdd40c44d771821e6e366c6a9c84d001d264",
+        "9b3426f6d0cabe45976e01da9a05349711199f81",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.prune.closed.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.prune.corner.html": [
-        "f9f4b01b8d892d6ecf76a7852996c1dd77c3aa0f",
+        "553fdb616575c03269287b82b6eeab5747c8cc03",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.corner.worker.js": [
-        "de307b1b4d79bd79f93b3eb953b2089092e84a8f",
+        "c2233bbc15b90878842baf8d45619c4af716c516",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.prune.corner.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.prune.curve.html": [
-        "270d6c3b0ff1f9c1c2b619c7a661c8202352c41b",
+        "ae2f922a41bd3b205b5be2e6e9827c3ec8aa6254",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.curve.worker.js": [
-        "386a4521c05f4b5fa1a9319f5e556f29d7e69177",
+        "7dc88a72134ba25ca8691a9b16045235f3f09435",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.prune.curve.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.prune.line.html": [
-        "bb9e98744f91f0f5ac52fbc8f94d4954780d63af",
+        "e9163cab40d1cec34bbaf480ff680dfc2d149623",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.line.worker.js": [
-        "736be715cce295f3426976ef3852f62136d1b55a",
+        "160bbe7eea3c28e9949a1036d4dbc0eaa297c559",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.prune.line.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.prune.rect.html": [
-        "833c7fe6f35a05f77a8305213b27ea54d008d2c9",
+        "72d0d6b6e9809f16dd4c0952cbdf8b7624b0965b",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.prune.rect.worker.js": [
-        "7d90a826e46d3ff18d145720f302fc509267bfe4",
+        "c6ed67ed9e4aacc957914b00455f24544af4da2c",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.prune.rect.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.scale1.html": [
-        "c911c09f9809b235f235d546bce9c0504c5960db",
+        "e13fd9fe550bdf2ba15bb14411568f5ac035ca52",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.scale1.worker.js": [
-        "507c60e2c5cd247c4eb0af9d47bfb924d49b51a2",
+        "ef7b2d4d04e6e034f6c90082d5243e2c52539746",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.scale1.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.scale2.html": [
-        "4c516a233ab4258874856f27cf093655424cfb3a",
+        "2b80f16898eee98e5ddc01395d4212dbb0d4056f",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.scale2.worker.js": [
-        "fe3138233c28f2bacf25507415f1568ed0c281c6",
+        "9c6d4fbf54a34d00e03a5e1b2ef35264bc43c70c",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.scale2.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.skew.html": [
-        "9988291255b616ed19a89689d5be7e81587b243e",
+        "55e96e08e06e460f3da40dc6ba9194918a320801",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.skew.worker.js": [
-        "8b854ad25e571d38ecfae20c3ed448c3f3fa81f2",
+        "745afe4ff53ccaed94d9a77b72ca3f170d1db281",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.skew.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.unaffected.html": [
-        "ec96d8b70570e3b6a9954783e27d6d4b9630691e",
+        "58e7f75dc8e504c75b69196ce3c2f266966aabaa",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.unaffected.worker.js": [
-        "5534fea05cbc98675f62c5e09446a05ac55b7a30",
+        "a47c32d0099eec7289874dc5f937a0c119f52d51",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.unaffected.worker.html",
          {}
         ]
        ],
        "2d.path.stroke.union.html": [
-        "cbb9925af36c8858b87d8a08da71328a70574ad3",
+        "c3f063fe52d32ae61bf37340acf5d867280dcd33",
         [
          null,
          {}
         ]
        ],
        "2d.path.stroke.union.worker.js": [
-        "f726705b2d9bd9efa5167f519c89a0ed6c6753fe",
+        "282cb10bf75d8dfcde1de8eae49208ecbd10ebd8",
         [
          "html/canvas/offscreen/path-objects/2d.path.stroke.union.worker.html",
          {}
         ]
        ],
        "2d.path.transformation.basic.html": [
-        "b000df7715eecd019506de4dcabb126c4bcd9258",
+        "18370041384d0b7bc6b039c1e85ba81c80727ac2",
         [
          null,
          {}
         ]
        ],
        "2d.path.transformation.basic.worker.js": [
-        "76da934178ca4f65a68fda79ce766827187a8107",
+        "7bc112dd1d0b2c90c6929bacc7f921b525b5941f",
         [
          "html/canvas/offscreen/path-objects/2d.path.transformation.basic.worker.html",
          {}
         ]
        ],
        "2d.path.transformation.changing.html": [
-        "ec6a682c8c78a19a950794888540040d69277a9c",
+        "b8a467387d55d49deaf0927a4da7c30ecc2e1249",
         [
          null,
          {}
         ]
        ],
        "2d.path.transformation.changing.worker.js": [
-        "12dc1c018b80b7efba9e91ac959d158e31b674e0",
+        "2460d24b199e378a4aeeef4b4ce731885178047e",
         [
          "html/canvas/offscreen/path-objects/2d.path.transformation.changing.worker.html",
          {}
         ]
        ],
        "2d.path.transformation.multiple.html": [
-        "113dadcd4fa16467748e6016c9002932afd19a77",
+        "fcc2942435f5e02d5ce3df781bd73b6a840e56a5",
         [
          null,
          {}
         ]
        ],
        "2d.path.transformation.multiple.worker.js": [
-        "abebb1fd64c505da5dc62051b35216c3f4101e88",
+        "a2a04ca7776a9bbf8ca947babdc591edbb36e8f8",
         [
          "html/canvas/offscreen/path-objects/2d.path.transformation.multiple.worker.html",
          {}
@@ -478575,14 +480191,14 @@
         ]
        ],
        "2d.imageData.get.unaffected.html": [
-        "d3c9320b8fe7c6332184ee90b53ee1d8257fbd92",
+        "f65f015e8f87e23784bd173935f2126d03a70f15",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.get.unaffected.worker.js": [
-        "ba536abfd1b495fad1594306bd689fb101bb0b9e",
+        "a733c6ffdf73c654cc7b5c2e09bb3c79c9b7e286",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.get.unaffected.worker.html",
          {}
@@ -478715,154 +480331,154 @@
         ]
        ],
        "2d.imageData.put.alpha.html": [
-        "64e7f2eb8bb4f7b8c90667342f992ff750bb8f2e",
+        "ecda85bd121550d4cb6c3ce6305490cfa9554c6e",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.alpha.worker.js": [
-        "44b791f745cd8d0b3643439e372d3198f39b56e3",
+        "3349c6928699e96756764049bdc1571c06ec480b",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.alpha.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.basic.html": [
-        "ab4cc7396f092cc675b1af0286d767988ddd41fd",
+        "d140cc39ab4315a834b7e54d4e30cc53be5d8903",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.basic.worker.js": [
-        "c3d51c4696476c107619b9e7db24fbdaed8e633a",
+        "276fea2d126c580bda7cc8a24548c8edaca4da60",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.basic.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.clip.html": [
-        "ebbd0d74768c51f18cd5e1a0d838a82701f79103",
+        "121a45fae8a429f5078a3f7155bae4be2786aafd",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.clip.worker.js": [
-        "174d915dfbd41ccbb023adde414b80481bfe0ede",
+        "9188b3cf88e52a565f14ac6c0fa08adeaaa9e4df",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.clip.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.created.html": [
-        "84ba511601045c5f743f5d1c641551f42a691945",
+        "7ade3b1debe225deb909739fc6ea06debccfd8fa",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.created.worker.js": [
-        "6f7cea04c4ab57c998cbd8f0a7c3ab0ae402875b",
+        "fd6b5ec8e098c4b3aaf59439ddc7a1cb2c72c5a2",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.created.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.cross.html": [
-        "8d94bbc577b87fc0d01dbc257c2362f7568be985",
+        "af90d71991e8b0ea292c1214993d0977abdd142c",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.cross.worker.js": [
-        "173808f218a2d0b24436be7f10a882a6e8003b39",
+        "bdeaa352457f7dc2f66b5d2cfa0ec34a1bce7de7",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.cross.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.dirty.negative.html": [
-        "2f408c4df11ef09305622c81e8be045e2dceb602",
+        "e2fbcb270283df8df3641e9597860e03230ec18e",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.negative.worker.js": [
-        "ba83579060f5c79c47be3aa92a25b0a0dfcf9b0d",
+        "5eec264c756e05e6c5f537cb8045eaedf3338a86",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.dirty.negative.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.dirty.outside.html": [
-        "37f049e22caeeb07a354062962dec678f15f03b6",
+        "aaf48a762bcf683c0594871e496d2da6f433111e",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.outside.worker.js": [
-        "9dd1110743f8acc78f2b79a0484a899713373935",
+        "9f537135dac2ba30b88ae060fd85d488da04de5c",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.dirty.outside.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.dirty.rect1.html": [
-        "8401ddfd9b60d2cfa963b46f531ff15787a7e1fe",
+        "e973eb6ca4b22886f6101543f1e6818f392fff1c",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.rect1.worker.js": [
-        "71cbb8d383439ad0220c41e40d6e0785e9da6dec",
+        "fdbe6561ce5484f71d9bc85d34a568e4a3b9ef7c",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.dirty.rect1.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.dirty.rect2.html": [
-        "c3b5f480e057ef2532d419aa30c4d0de30e09872",
+        "9b275429e6e7bb6355a621202674a4bc0e8e1c49",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.rect2.worker.js": [
-        "19aa4da5ea99ae7d95a24c820565327fddb029ee",
+        "3578ceec25aa6c69ee897166df829b323d5beebe",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.dirty.rect2.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.dirty.zero.html": [
-        "7b9231f98bb7f91b405c7aa14c85fb9c8a785d7d",
+        "c1b6735d259cf82c4442541b7b1bb5a36c347422",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.dirty.zero.worker.js": [
-        "149f9f16848ae96cb54ae67695e4dcfe24c8fd5e",
+        "db09379c624ab4030a52343dc37e4766fcb51c44",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.dirty.zero.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.modified.html": [
-        "2a14984407190b223170b171538aa6a296a809ac",
+        "543d9ff29304930d2ff9680a540b3d79f8b6b7c9",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.modified.worker.js": [
-        "9c016a37348cc3b7d7b014697f22dbe319dd41bb",
+        "b238d56cf967326fd8710c09e987514e369b7908",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.modified.worker.html",
          {}
@@ -478897,28 +480513,28 @@
         ]
        ],
        "2d.imageData.put.path.html": [
-        "f2578a5918ef8e73cfca2e38e2742766fd12337d",
+        "53e3ac4fceed8044e3c1f2bf7027624f8fda323c",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.path.worker.js": [
-        "8b280398698c76a153157409e4dc6c976d7cb081",
+        "81bd03eb4f25ffca31769a461d33535f25706694",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.path.worker.html",
          {}
         ]
        ],
        "2d.imageData.put.unaffected.html": [
-        "0217124bcadf0841008df7730c7038a63f9f137c",
+        "8d94f9bbf63541c65912bc463c33402f84679858",
         [
          null,
          {}
         ]
        ],
        "2d.imageData.put.unaffected.worker.js": [
-        "016f87d7fb30b099a8369cc9ec81dffa4db86181",
+        "9b931717f0a6662974a9a4ac048d7589b7f39803",
         [
          "html/canvas/offscreen/pixel-manipulation/2d.imageData.put.unaffected.worker.html",
          {}
@@ -478955,70 +480571,70 @@
       },
       "shadows": {
        "2d.shadow.alpha.1.html": [
-        "e28bb6aa3047d5f153e5094302911a9c628ef0bd",
+        "cf887b62a28453ad6d13e07ea72f8fd4f3a47741",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.alpha.1.worker.js": [
-        "73427988c34f576cd19f6cc07d818a712724e724",
+        "7bcf74463c55f07d144e7157b2d280eaac6cb1bc",
         [
          "html/canvas/offscreen/shadows/2d.shadow.alpha.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.alpha.2.html": [
-        "e4a4908bb32ce799369a838208423b1bf1767885",
+        "cb03866bc37ed34fc2e81c228955b60efcb29fe4",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.alpha.2.worker.js": [
-        "9e9eb55a280bbfa0ba2f987947cddc731f49ded0",
+        "8f4b98143b345435359a8d89650bca15dbe4c8f1",
         [
          "html/canvas/offscreen/shadows/2d.shadow.alpha.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.alpha.3.html": [
-        "5748cedaa97d0254a10c535e45bd345359c8dd2e",
+        "efc9fca97e262d0837319b88cf46cb2ee6274f45",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.alpha.3.worker.js": [
-        "f001559735f39a3a245781c952b052791d70a240",
+        "ddaae242d969c06b87a23160c3d8552f29ab35db",
         [
          "html/canvas/offscreen/shadows/2d.shadow.alpha.3.worker.html",
          {}
         ]
        ],
        "2d.shadow.alpha.4.html": [
-        "228ad2086032fa822b7b4f48ee771398a82f8cc0",
+        "295b61269cda8606287f042fd0ccf701cb517dfe",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.alpha.4.worker.js": [
-        "abb6a4cab8c9fd3872ad580cb710e641468063c4",
+        "16defd9094a8f9822153bd9e454aa609ac9ddeaf",
         [
          "html/canvas/offscreen/shadows/2d.shadow.alpha.4.worker.html",
          {}
         ]
        ],
        "2d.shadow.alpha.5.html": [
-        "04f7c4573687f3a9a511bdd1de2783c6c4f4773f",
+        "3b1089d7d79be5d5236c7b28f3af85955f4840eb",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.alpha.5.worker.js": [
-        "c64d584ab5345b434f395b1698a5aac771747b53",
+        "5437c65ec17e019ea234f653b75ecc75f0b65b19",
         [
          "html/canvas/offscreen/shadows/2d.shadow.alpha.5.worker.html",
          {}
@@ -479151,420 +480767,420 @@
         ]
        ],
        "2d.shadow.canvas.alpha.html": [
-        "299a3cccdbab92c809d5cdbd3491158c79adca7a",
+        "5fea8a7cf3d7ccf1aa43449d6b8ffc2ff0d1e33e",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.canvas.alpha.worker.js": [
-        "d3abbbb7762ca12e3edd0359b52f3dfba75fffb7",
+        "663e89f28435c85096dead2f20c9c91d1e0a5ad4",
         [
          "html/canvas/offscreen/shadows/2d.shadow.canvas.alpha.worker.html",
          {}
         ]
        ],
        "2d.shadow.canvas.basic.html": [
-        "5f454321bc6f7e68ccac9c196315908f8789605f",
+        "2fc6b547d57ed334c6b79ccb7f76f8db9d646f8d",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.canvas.basic.worker.js": [
-        "2a44897a88ee49ceef60a0e8c29d2aa8d3da816b",
+        "20c433b2f6a2a1b66ca1ad64a3f698f5e6920663",
         [
          "html/canvas/offscreen/shadows/2d.shadow.canvas.basic.worker.html",
          {}
         ]
        ],
        "2d.shadow.canvas.transparent.1.html": [
-        "14ac60cc7a08d7759881d8587b39fab413919c03",
+        "1bfcb3bf3b7ab858adc440ea03085e4c8d43c5e8",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.canvas.transparent.1.worker.js": [
-        "b9425ebc7fae4f40a3fcef297dac3d24dc8aba31",
+        "413ba6b24387cf66bf88e4df3e16b143d10abd10",
         [
          "html/canvas/offscreen/shadows/2d.shadow.canvas.transparent.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.canvas.transparent.2.html": [
-        "796fb79106f5737d7f6e6c4a855b344cd0968780",
+        "6d30dfcb85b96e4a372ada3fe88bec1e98f38d3c",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.canvas.transparent.2.worker.js": [
-        "6c8c31b0aa7bcccbcaea1222d58b6d8bebee200f",
+        "d702ded7463e79b82c7d3cd4c560f81fe6c6ffc6",
         [
          "html/canvas/offscreen/shadows/2d.shadow.canvas.transparent.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.clip.1.html": [
-        "9b31607daf6f65303ec0e375629a2afcdb4956cb",
+        "4beb1214b24891a0f4caa79e90eaadd75d780eb2",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.clip.1.worker.js": [
-        "574e22e1dc9a2ea0f75b2ac92b33b51056e0c491",
+        "4fafad83307e1f4ff24ba262cf198e3359ceb710",
         [
          "html/canvas/offscreen/shadows/2d.shadow.clip.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.clip.2.html": [
-        "8d439a408a8bf23f688671864a4db7fb56aa1ac3",
+        "bc3de09db7ae11813b4556ef99837d5e67edc334",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.clip.2.worker.js": [
-        "094ba9deecbd1aa07a312abbcd0e46135727d638",
+        "dd2712af40cba92f50ec5e720026ec3c32e1db6a",
         [
          "html/canvas/offscreen/shadows/2d.shadow.clip.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.clip.3.html": [
-        "63c16faa13294822c193d0aa04d7b7c15fb4b029",
+        "9656feb41fb179aa633390b316c1b20ad4843547",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.clip.3.worker.js": [
-        "01e8bf24dfb3541613522e41138772ab4c8c6e12",
+        "ed4983ac8ca6408486cbf559b0d92d1987aa9e3a",
         [
          "html/canvas/offscreen/shadows/2d.shadow.clip.3.worker.html",
          {}
         ]
        ],
        "2d.shadow.composite.1.html": [
-        "d45df852a29e181af50f07adab347fc6012437a5",
+        "13e0daf3aa1b491a5b40a969dc0b27aa9e0287b7",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.composite.1.worker.js": [
-        "9883655574f3f27dd6a43ee4f1372769426e8421",
+        "04d4801db90f69f31a005ce85c922d5c5dcc01e8",
         [
          "html/canvas/offscreen/shadows/2d.shadow.composite.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.composite.2.html": [
-        "e9955e596e59320d8fc09f65ea733ec2f95e3439",
+        "aea36997b65d1e1db0bc6ff3b7b72a2c0b3609ef",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.composite.2.worker.js": [
-        "83da3fd806fcc3fc76da4502582468b15aeb218f",
+        "505e3d535fa8614017582af50b6a357f99a107f0",
         [
          "html/canvas/offscreen/shadows/2d.shadow.composite.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.composite.3.html": [
-        "2ba82d7ea55e1aaacd9bdcb5c6c296eed893e865",
+        "2218602f38d60fac3afe3abc6d8a7464b813b437",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.composite.3.worker.js": [
-        "da5726c582713ef0c98483f43b37913cca7e6ec4",
+        "fd58d06192ee8b991f1c33e4f9db4c3064577720",
         [
          "html/canvas/offscreen/shadows/2d.shadow.composite.3.worker.html",
          {}
         ]
        ],
        "2d.shadow.enable.blur.html": [
-        "e029b0e0f43548bb55c44159eabc46a6602f31fc",
+        "edc4c527b21ceb0a69b13a614a3ff11ef659705f",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.blur.worker.js": [
-        "5dbc950b1fc26b414caa288ebb0292c8126c592b",
+        "85bf21a0861786bb04d2ef51714047bff48837aa",
         [
          "html/canvas/offscreen/shadows/2d.shadow.enable.blur.worker.html",
          {}
         ]
        ],
        "2d.shadow.enable.off.1.html": [
-        "38ebd479db42542e201f09c9917d07fb37874b72",
+        "f0c92820900f672f9e882b172ba779aad996f443",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.off.1.worker.js": [
-        "d230ef14be66d6e4b14532016aa7699b4ef06f61",
+        "dae0ea648dd2053423f6db6d414c23ae68ca2673",
         [
          "html/canvas/offscreen/shadows/2d.shadow.enable.off.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.enable.off.2.html": [
-        "a2aaa4ca7270b2d84d268dfc92e8b4a98839db00",
+        "3c27b988c94140aceeea22d283871fed090e31d9",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.off.2.worker.js": [
-        "89436362a390b3e669dc1188fc8389cb0c181724",
+        "2f1573ef3fe0384a16c6c7ecfda8c8f846df52b1",
         [
          "html/canvas/offscreen/shadows/2d.shadow.enable.off.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.enable.x.html": [
-        "a5a9c2458b614a1ce186e661b77aae4bff1bbf6c",
+        "9107ef25de021651d5d416e6582b6660601d7d45",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.x.worker.js": [
-        "a31b66d4d4188ac5e0fdd151a5f730d183cffdcb",
+        "d8e7d5039bb135fcf5788265dc3276c9dbc7dd97",
         [
          "html/canvas/offscreen/shadows/2d.shadow.enable.x.worker.html",
          {}
         ]
        ],
        "2d.shadow.enable.y.html": [
-        "346e22ac6f1f2ba7ed0778fba2027f4d6236f92f",
+        "77a79d8457d8799fd44bac6854834e65fb41737a",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.enable.y.worker.js": [
-        "fcb5db84e63c83d3dbb8553ca9de94da33ba94ae",
+        "53140b13a96d0e2323146784d138b3b88f5a1035",
         [
          "html/canvas/offscreen/shadows/2d.shadow.enable.y.worker.html",
          {}
         ]
        ],
        "2d.shadow.gradient.alpha.html": [
-        "6ba5e8a4abb3ac11e979a217b93059b402520f63",
+        "d92a2484408f311c354867dfd8b8f846d6386762",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.gradient.alpha.worker.js": [
-        "b5a64ab99ede9c0898ae7e83f039c0fa58fbe1b2",
+        "b5b65a00563e7754a6c8306a204251c6819b6114",
         [
          "html/canvas/offscreen/shadows/2d.shadow.gradient.alpha.worker.html",
          {}
         ]
        ],
        "2d.shadow.gradient.basic.html": [
-        "b5aada866e2f08d17bca27b77f93e3ca702249ff",
+        "b88281be9a3995273664019774d3eb56a56bb05a",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.gradient.basic.worker.js": [
-        "c73164ff4969ce29b192a1541d2050b188db06dd",
+        "ef9ce712f2b8c23059c1bcb26e755d1a2c5c7bc2",
         [
          "html/canvas/offscreen/shadows/2d.shadow.gradient.basic.worker.html",
          {}
         ]
        ],
        "2d.shadow.gradient.transparent.1.html": [
-        "67e753d3689412c9846d529f3e1bbdd8f6bca9c8",
+        "f71a8b4222aa81195c38d575afb121bff36ff0eb",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.gradient.transparent.1.worker.js": [
-        "b83cdaf953e35a2830d187dfcc2c265d5e757391",
+        "b60d6f7f593206c52d5a0c21d363100dcf5494fc",
         [
          "html/canvas/offscreen/shadows/2d.shadow.gradient.transparent.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.gradient.transparent.2.html": [
-        "43b43d1cc5dad2bfb27cf3b4685a126cc4f8acfb",
+        "d7c560ec4637e1749c45728609577aa4435c56ee",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.gradient.transparent.2.worker.js": [
-        "75e1fefce988a44d637335f1dbe04c9628284755",
+        "7226b004b808e152eb8257f7ec85f2049077ae70",
         [
          "html/canvas/offscreen/shadows/2d.shadow.gradient.transparent.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.image.alpha.html": [
-        "c57bba957dc84a3b290befe7718e3103ac08cd07",
+        "5add7eae5acaedc5800910ece74403bfc77959b6",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.alpha.worker.js": [
-        "eedb9cc06758d8d4846f959ad5299ca81bed90d4",
+        "7a1d99218f130501b805206416edb94959ebdae7",
         [
          "html/canvas/offscreen/shadows/2d.shadow.image.alpha.worker.html",
          {}
         ]
        ],
        "2d.shadow.image.basic.html": [
-        "850ae707b0e600fee845f36aa5bdcfbc62c7c856",
+        "101cfbab0c167d150f7c5efa2b6fa887229d59fd",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.basic.worker.js": [
-        "c6bee034aaf62f697a2023e22a20f074e9c0f576",
+        "f1d72def72b6fa99bdb0f9aa092a4123991398cb",
         [
          "html/canvas/offscreen/shadows/2d.shadow.image.basic.worker.html",
          {}
         ]
        ],
        "2d.shadow.image.scale.html": [
-        "3f9bdeae63dc6b3078f22c71774b46fc50c6cd4e",
+        "c56a73f7366dc2bda073e29f8200cc887135a973",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.scale.worker.js": [
-        "e39f61689b9a30a2cd5fbae450da16ec2638c59a",
+        "a8c0ead903b8a6add39dd4ec8f9c2e26b7e7dcc3",
         [
          "html/canvas/offscreen/shadows/2d.shadow.image.scale.worker.html",
          {}
         ]
        ],
        "2d.shadow.image.section.html": [
-        "b141d39ae9c8b8859c5cb9dcc1e6ed07de6866b5",
+        "cd0950349919b2cb8a0b3683caf325a54b9cc654",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.section.worker.js": [
-        "4fdd2180d60f44d53be62d1324f53e4b16dd0e5c",
+        "60e32b48835a16f1f60cf7377caaa1227b1d9f88",
         [
          "html/canvas/offscreen/shadows/2d.shadow.image.section.worker.html",
          {}
         ]
        ],
        "2d.shadow.image.transparent.1.html": [
-        "9f3160dd5d6a860c866dc251bc3563d64bf5871e",
+        "37844050a95f59ede4640feb953a540254ec9630",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.transparent.1.worker.js": [
-        "9f5eda36f9290325ebecb3f080d189fe751da4c4",
+        "8e8ded8bd3d8185cae4fb32c1cb7899ec3201a3e",
         [
          "html/canvas/offscreen/shadows/2d.shadow.image.transparent.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.image.transparent.2.html": [
-        "238c3042435549bd6cf4ec3a22052e2d1988894f",
+        "996bce718a34b1fa691249361f99d82f7964bccf",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.image.transparent.2.worker.js": [
-        "589755eefbe4027fe0dad74aff99e2097aed6573",
+        "5075d6cfa7e07142fe342d4903b4cba3556a1da3",
         [
          "html/canvas/offscreen/shadows/2d.shadow.image.transparent.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.offset.negativeX.html": [
-        "ff47ac66cae2ab836b5cf0de8919fdf285ee2511",
+        "97c04018ac4726ca02b9fd9f2882ff79dbd100cb",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.offset.negativeX.worker.js": [
-        "3d31f5a407e0917f589f608b854717da91f1dc1f",
+        "93c226570fb4de9309e9fbafe186eafc16dabe62",
         [
          "html/canvas/offscreen/shadows/2d.shadow.offset.negativeX.worker.html",
          {}
         ]
        ],
        "2d.shadow.offset.negativeY.html": [
-        "1abc62ee4872e196116ed80d0ffecf01d014f221",
+        "7f5d5ab9a8923adc29d212d4045e64fe9184bda4",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.offset.negativeY.worker.js": [
-        "806ff24bcc543879e4dc899e5864418974abaa40",
+        "6ee0bcc7c5d1430c70956b7d0140cd6f02d4e98a",
         [
          "html/canvas/offscreen/shadows/2d.shadow.offset.negativeY.worker.html",
          {}
         ]
        ],
        "2d.shadow.offset.positiveX.html": [
-        "ddfe2028eef49907680870d0cac1f3f1fd5032cf",
+        "a745de88ab625b7d69d4cded7362b25d0bf8c215",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.offset.positiveX.worker.js": [
-        "aded29344de040acc7f847a38aebfa750e8bb30d",
+        "241fbda8f31ea2305e42cb22a8b1edaeade229da",
         [
          "html/canvas/offscreen/shadows/2d.shadow.offset.positiveX.worker.html",
          {}
         ]
        ],
        "2d.shadow.offset.positiveY.html": [
-        "91a64f148f8fc46ee2c04db683e69e31179f11d5",
+        "168b179688489e2c778f7bfe4a0eb41d7f74b163",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.offset.positiveY.worker.js": [
-        "76fdaefd718aa083dbd9228923c76dd96aefd0e4",
+        "b3236d66a529e49ac716abdceee9fe15309a351e",
         [
          "html/canvas/offscreen/shadows/2d.shadow.offset.positiveY.worker.html",
          {}
         ]
        ],
        "2d.shadow.outside.html": [
-        "7d2757900427e0b5832ccb9cbfc75f808bbff855",
+        "207160d20f56b9b1947b337bd9f2068620e74904",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.outside.worker.js": [
-        "25bcf774e634713211121895a1480d498b15131b",
+        "d0787d67a41f25eca1503cedae9574c7fa6759f6",
         [
          "html/canvas/offscreen/shadows/2d.shadow.outside.worker.html",
          {}
@@ -479613,126 +481229,126 @@
         ]
        ],
        "2d.shadow.pattern.transparent.2.html": [
-        "225ccce5b7e51dc543b2ceb422e5de86a42ad429",
+        "600fbd03ff7661d0510a2da20b2a1e800ce5bcca",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.pattern.transparent.2.worker.js": [
-        "2069e746eabf3fc32e8f28f721e7a4227975626e",
+        "2aa31661469021fd12e0d3b34fd306af4e92c2f0",
         [
          "html/canvas/offscreen/shadows/2d.shadow.pattern.transparent.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.stroke.basic.html": [
-        "24d85243a5c222cf0655827a3aa06902e6823225",
+        "27110251346a79389c667b4e900d61818f1915b4",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.basic.worker.js": [
-        "f9cc851181f99207cb7cceeaa717dfdd4b7cac1f",
+        "7ebbd8ec5b4922b8657108d204c2cc84d50af755",
         [
          "html/canvas/offscreen/shadows/2d.shadow.stroke.basic.worker.html",
          {}
         ]
        ],
        "2d.shadow.stroke.cap.1.html": [
-        "6e477b840741701957e18230ad1f8fd3f9835960",
+        "3854669bf0c87e1440ba8dbd3be228aff6ab318f",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.cap.1.worker.js": [
-        "0e9289ab824aee572e171b0dcd237098f5ba4ef2",
+        "7ecd07b1cdad962ac53565902e53082d9ca9425d",
         [
          "html/canvas/offscreen/shadows/2d.shadow.stroke.cap.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.stroke.cap.2.html": [
-        "99ae3b165ec75aadc76e7e9cca763050e5037e7f",
+        "bd18ec6f8cbe3d1301f432655903d4101f94fa93",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.cap.2.worker.js": [
-        "ba5868118503438ad5c5781bf92152d0a78c4374",
+        "7c7dc26dd92354587648a0fcd61fa87a91d54972",
         [
          "html/canvas/offscreen/shadows/2d.shadow.stroke.cap.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.stroke.join.1.html": [
-        "9f22089f129143b74097888fc1728330d241c3dc",
+        "8faa2fef082c9d30af3c2d862abfbbd638270503",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.join.1.worker.js": [
-        "69563b08d89bb6b8b3168416c15b846f93966d60",
+        "e81a9b212d4e5b0daee834b5a1fbed2eca901251",
         [
          "html/canvas/offscreen/shadows/2d.shadow.stroke.join.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.stroke.join.2.html": [
-        "e42a21e2fe4db4609ff90fccd30a806ab3a1cfad",
+        "7b52a7c9508567d8c4cfc0f1437f91995c1415f4",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.join.2.worker.js": [
-        "e621f96544b0f978b5f1bd35e4558c0c5c0488ed",
+        "269a49d76cdbe88cce1bb9dfefcf30c8e9f38d77",
         [
          "html/canvas/offscreen/shadows/2d.shadow.stroke.join.2.worker.html",
          {}
         ]
        ],
        "2d.shadow.stroke.join.3.html": [
-        "d41b512624197c72b45cd75145a22da1f2d8f024",
+        "6110d3ae40c447cec685692885ecb959e23ca26a",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.stroke.join.3.worker.js": [
-        "cd01072128c031865b543a3735fcbc1595c129ad",
+        "43144b0fd9b2f76a1865f5c17651698f72f09f0c",
         [
          "html/canvas/offscreen/shadows/2d.shadow.stroke.join.3.worker.html",
          {}
         ]
        ],
        "2d.shadow.transform.1.html": [
-        "76688fef249c6ed95220e6088d229672d4f3e8d3",
+        "d6c4e483ba57882b4d661cbf424e054edca545a8",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.transform.1.worker.js": [
-        "8b16e520c9c735989353d60033decb00c660f356",
+        "38cdf7eb7cf6290f908fe8b133c7964ec189e76c",
         [
          "html/canvas/offscreen/shadows/2d.shadow.transform.1.worker.html",
          {}
         ]
        ],
        "2d.shadow.transform.2.html": [
-        "01513a2bd55ebb9a7a58f0cd76413880ad926099",
+        "f0b1607262db25d208958376a6d622aa67cd78b9",
         [
          null,
          {}
         ]
        ],
        "2d.shadow.transform.2.worker.js": [
-        "4f62cdfbeb4f2f5ef3828a24ed84106357e0de8f",
+        "9f204d24393bdd3679533e3ffaae90e9a610e218",
         [
          "html/canvas/offscreen/shadows/2d.shadow.transform.2.worker.html",
          {}
@@ -479825,182 +481441,182 @@
         ]
        ],
        "2d.text.draw.align.center.html": [
-        "abe6cb7f0ae01068fea5e5749cd71903a9c7dfd5",
+        "438e6756a06b6e18e8e5bd9c20d184205b6956ee",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.center.worker.js": [
-        "ba450334eff356759c0aa57f2bbae1b1d278900b",
+        "9487e6ab8ebdbf9ad49290ae89ff5610db418202",
         [
          "html/canvas/offscreen/text/2d.text.draw.align.center.worker.html",
          {}
         ]
        ],
        "2d.text.draw.align.end.ltr.html": [
-        "d229fac87935f470d390585ca8ca6d52f15ec689",
+        "6134042bdc977452b3dc84768bf389a97ac0d85d",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.end.ltr.worker.js": [
-        "7a4c6d35499647e2b0f5565c033284399ccc2d1c",
+        "2a7b9e9418c17eca2d15ac69eb4d4b61996285e3",
         [
          "html/canvas/offscreen/text/2d.text.draw.align.end.ltr.worker.html",
          {}
         ]
        ],
        "2d.text.draw.align.end.rtl.html": [
-        "b285da9a9086fa18ba15eddc968ad3a1847b4b24",
+        "a4b502480aed7778eda15158ba749b18f9b2564f",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.end.rtl.worker.js": [
-        "5e633f8d032d0ea57e12868a0d9d89ebc29b6ed8",
+        "deb8227ec4379ae039a454a912e3a34a4e3c8d14",
         [
          "html/canvas/offscreen/text/2d.text.draw.align.end.rtl.worker.html",
          {}
         ]
        ],
        "2d.text.draw.align.left.html": [
-        "12595fab440146ecb736bbee193e3462edbe4dd8",
+        "6e69a830a4ce0fc38cff3397d6963592301bf1a0",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.left.worker.js": [
-        "adc5b01df40b95f415caf200ef0f83973f7f9777",
+        "9c555126537cfd186811ff8ded0e314c967978c9",
         [
          "html/canvas/offscreen/text/2d.text.draw.align.left.worker.html",
          {}
         ]
        ],
        "2d.text.draw.align.right.html": [
-        "d731285924310e4c5f7d0797ae8845d770664c88",
+        "a56c7cab1d1369d210411399f373a9e676a95685",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.right.worker.js": [
-        "822712ebffe429c6c4c0de22330b361fbf8af09a",
+        "f246963f606bf277c869673faba1ad47ef73fbb6",
         [
          "html/canvas/offscreen/text/2d.text.draw.align.right.worker.html",
          {}
         ]
        ],
        "2d.text.draw.align.start.ltr.html": [
-        "8e888f2e306a714810345093363c156ae37baaaa",
+        "ba8c440c43b6e76a7b657a9f4982e331ec95034b",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.start.ltr.worker.js": [
-        "1765fb19fa42949bae3ecc259df770cda6c6efca",
+        "2de9d50fabb4e4925a6b600507c44758909b6caf",
         [
          "html/canvas/offscreen/text/2d.text.draw.align.start.ltr.worker.html",
          {}
         ]
        ],
        "2d.text.draw.align.start.rtl.html": [
-        "c277b0d487793a4b3af0ec59b19351a032d10c4e",
+        "32f83430e0949e1cecb62fa7644d7930a30afd27",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.align.start.rtl.worker.js": [
-        "26709778eb4f30c0e46a650b47b800344c16bef1",
+        "41cb57b9587bb9906b519b5bad55341ff77f6a6e",
         [
          "html/canvas/offscreen/text/2d.text.draw.align.start.rtl.worker.html",
          {}
         ]
        ],
        "2d.text.draw.baseline.alphabetic.html": [
-        "bd478f1d37c17a0256b90ec887403837a3b67512",
+        "bd6a1804a538fe28548858e3be0da1c1d1f61586",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.alphabetic.worker.js": [
-        "d2b5abc0ad281436fb0a4759e84d17baacf7e85f",
+        "5b4fe08b1307102cb826ba94b8ac9abd94cb9572",
         [
          "html/canvas/offscreen/text/2d.text.draw.baseline.alphabetic.worker.html",
          {}
         ]
        ],
        "2d.text.draw.baseline.bottom.html": [
-        "5bd71f2d5d771611ec10e8a07e38a9e7e38c9846",
+        "4e5fc8e346416796b1cb5d00918c3a4daa23c026",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.bottom.worker.js": [
-        "8df706f1ad2fbb11cfdf82c0eb2a78100f5aecb2",
+        "1c7cab3ef99aab8d20aea85337bcc2f6d5b12227",
         [
          "html/canvas/offscreen/text/2d.text.draw.baseline.bottom.worker.html",
          {}
         ]
        ],
        "2d.text.draw.baseline.hanging.html": [
-        "d1606117c445b54ce59b580a0ba644d7ee1b2d4c",
+        "d0d573790dbb6a4aa470bcb88754d0f7cba88cb8",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.hanging.worker.js": [
-        "58ca029ee6f8f24a6cfdc86a91bdf9b6291d9be8",
+        "79df7d8e484ab56d91fe618051376df9a91d220e",
         [
          "html/canvas/offscreen/text/2d.text.draw.baseline.hanging.worker.html",
          {}
         ]
        ],
        "2d.text.draw.baseline.ideographic.html": [
-        "a5cc0eb081fb709704aaafaa653d07bd6047982b",
+        "144d56f784d11d65460a35e25162fcd912afb69c",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.ideographic.worker.js": [
-        "8dc0ab550508ee8be5137821c4f6c03eb8328dcd",
+        "ef7d0180cda7627d92166f22b2f0373bde792103",
         [
          "html/canvas/offscreen/text/2d.text.draw.baseline.ideographic.worker.html",
          {}
         ]
        ],
        "2d.text.draw.baseline.middle.html": [
-        "fd3176c111fbe2d3d2f7e27f68941a4470e33c2c",
+        "3072264bb4a5101c58230633ebb8509f42bd85be",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.middle.worker.js": [
-        "72ca109344b6234fc94111f1bec8f790032ae9f9",
+        "a0509b6711c4929267f1607b192b77bc664f47f0",
         [
          "html/canvas/offscreen/text/2d.text.draw.baseline.middle.worker.html",
          {}
         ]
        ],
        "2d.text.draw.baseline.top.html": [
-        "2ddb63c757ebf96bc2968269bf15e19dd8a13a0b",
+        "a077aff348f2861ecaa259759730d2e407ad19df",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.baseline.top.worker.js": [
-        "daf872b379f7c4c8670de783e09505be31dbf5d2",
+        "bbc7fc06a31d3b5e9d1d111c69c1293e425186ba",
         [
          "html/canvas/offscreen/text/2d.text.draw.baseline.top.worker.html",
          {}
@@ -480021,28 +481637,28 @@
         ]
        ],
        "2d.text.draw.fill.maxWidth.bound.html": [
-        "0941ad75e6bd3985423a6d7964381481a9c705ee",
+        "63b30966f4a27e9fe96343c0a3f27baf10606681",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fill.maxWidth.bound.worker.js": [
-        "0e975c72c94e70cb193e9edcb9e5f33f463661ce",
+        "092289baf4a2a9c367d6705943e1749845cc9ab1",
         [
          "html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.bound.worker.html",
          {}
         ]
        ],
        "2d.text.draw.fill.maxWidth.fontface.html": [
-        "f247178ca3b317503569a1251f99b9bb9bea6c16",
+        "9294bf99736b33383d3b08d5a748de57a37107c1",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fill.maxWidth.fontface.worker.js": [
-        "0ad857c75b23fc785fc68811dc9ab1da37a5fb71",
+        "99cc25e7aeee24e874cfd08c6e97fd042db418f5",
         [
          "html/canvas/offscreen/text/2d.text.draw.fill.maxWidth.fontface.worker.html",
          {}
@@ -480101,154 +481717,154 @@
         ]
        ],
        "2d.text.draw.fill.unaffected.html": [
-        "8b67e37f44ce37823a3f16be27c330536595c559",
+        "e620ae1a181ee34516e28548e9dc44d16e63aea2",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fill.unaffected.worker.js": [
-        "54308035f5abd42d4d0705eea166920b95290c1e",
+        "9640bad6c9a4e1120f1350e085d9a801fba10753",
         [
          "html/canvas/offscreen/text/2d.text.draw.fill.unaffected.worker.html",
          {}
         ]
        ],
        "2d.text.draw.fontface.html": [
-        "d9ddd5cdbe1d95e7fc204891c26a8465d14ed20f",
+        "d2c65e8bb2b97cd94696d2fb8090dafcf62789b7",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fontface.notinpage.html": [
-        "092dc0794149fdcf85cf2888067535488dc2f03d",
+        "f390700ea0c5eeaf81d448b5d0f731e71262df02",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fontface.notinpage.worker.js": [
-        "e164fb1d5f0b5477171754c0c7426c3c31124c3f",
+        "8efab418a870908593ee49bb8efcd2ec2481e954",
         [
          "html/canvas/offscreen/text/2d.text.draw.fontface.notinpage.worker.html",
          {}
         ]
        ],
        "2d.text.draw.fontface.repeat.html": [
-        "fa3367ca2b36acf2039a6ef995b8ac3757c5e9ec",
+        "3766ab698900d8ec44173408376f3a630e4d034f",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.fontface.repeat.worker.js": [
-        "8625394e23d09c8d013823a4beba6fb8d0c90145",
+        "756e844709b9d2b9f2eddfea1cb00826a69d63bd",
         [
          "html/canvas/offscreen/text/2d.text.draw.fontface.repeat.worker.html",
          {}
         ]
        ],
        "2d.text.draw.fontface.worker.js": [
-        "ec8ba80e35e71438fd2a910791d3dd3841205d7f",
+        "45f18317b094b4c0282ee39bb713a499b44ba2e0",
         [
          "html/canvas/offscreen/text/2d.text.draw.fontface.worker.html",
          {}
         ]
        ],
        "2d.text.draw.space.basic.html": [
-        "b3880ea5540af441f74bcb51cb6939496cacb364",
+        "4bc03bb4adb9de2148d6ac971de47ab02a70d86e",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.basic.worker.js": [
-        "f2b4c280339486f0253f58c06fd57bc2b09f4c7a",
+        "39c00846e92fe02e257433898254843517aa2c48",
         [
          "html/canvas/offscreen/text/2d.text.draw.space.basic.worker.html",
          {}
         ]
        ],
        "2d.text.draw.space.collapse.end.html": [
-        "13030fe0cb2ab95fbb758112c7d92ad5eff65a3a",
+        "58fb292e132e5660a7d10a3aa8e7939284f6e204",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.end.worker.js": [
-        "fcbb9b2852868a52d3abe967bf83604101a0f923",
+        "81f85baff0b1d3cc254d65b10de55a6dfd3a26c0",
         [
          "html/canvas/offscreen/text/2d.text.draw.space.collapse.end.worker.html",
          {}
         ]
        ],
        "2d.text.draw.space.collapse.nonspace.html": [
-        "185fe51ef9ee4d13596ea19f36080d3a3bea25db",
+        "f018dc14658e93211f074eed745f5a1d1eaca66d",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.nonspace.worker.js": [
-        "7eb2e7042d0b161b122a9f804dfff7e1c1b5d429",
+        "cbc98034878a73a27d18ee9c524ddeecb4d5a156",
         [
          "html/canvas/offscreen/text/2d.text.draw.space.collapse.nonspace.worker.html",
          {}
         ]
        ],
        "2d.text.draw.space.collapse.other.html": [
-        "f49f8894f325f72e03d761b79df5a17d044e9e86",
+        "0a6bb09c07e4323b5594253880f3366d22dcc8a3",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.other.worker.js": [
-        "9b58f3366bd127a0c415ab9d72c8b85ab7145816",
+        "e13b87a531f578d858d8bfc1c6edbc6d347c6c3f",
         [
          "html/canvas/offscreen/text/2d.text.draw.space.collapse.other.worker.html",
          {}
         ]
        ],
        "2d.text.draw.space.collapse.space.html": [
-        "b0115aed8cb0ca0b8c796e206970e68ad657f3c8",
+        "3308cc75982625ccc7af40fb3d8ba90f64a5b153",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.space.worker.js": [
-        "5aecb5d17e35e312c85c965d5a5bb84eaa5665ea",
+        "4ea78a24664f9cf5bfc759363bcd48e6ae6bed0a",
         [
          "html/canvas/offscreen/text/2d.text.draw.space.collapse.space.worker.html",
          {}
         ]
        ],
        "2d.text.draw.space.collapse.start.html": [
-        "4e9115b3e016b72e0b4f5e1cd55d17a395bfbe1c",
+        "94b3f9ff0b00990f5ddf4790850743a1adc36878",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.space.collapse.start.worker.js": [
-        "a9e9cef517c5cc8834ce4def4304f27ef32f662a",
+        "20bd10ae57f564f5eba7cfc9db6d805280b55a62",
         [
          "html/canvas/offscreen/text/2d.text.draw.space.collapse.start.worker.html",
          {}
         ]
        ],
        "2d.text.draw.stroke.unaffected.html": [
-        "3c114c46b7a89d557f550a8d67b3ff1b16c331bd",
+        "7cad996cc0414eb5917a919a2d9ddbe14d7a0f16",
         [
          null,
          {}
         ]
        ],
        "2d.text.draw.stroke.unaffected.worker.js": [
-        "003b699695ceca9a76e1bed03224135346871726",
+        "7ce3b1adc721f80d5ed1067d082b81c8d2865114",
         [
          "html/canvas/offscreen/text/2d.text.draw.stroke.unaffected.worker.html",
          {}
@@ -480691,28 +482307,28 @@
       },
       "the-canvas-state": {
        "2d.state.saverestore.bitmap.html": [
-        "9491a4de247919b39615c9bc0b631258b45b79e5",
+        "3a6e67b77e4430222462c0ed6bd59d8eec2fedb0",
         [
          null,
          {}
         ]
        ],
        "2d.state.saverestore.bitmap.worker.js": [
-        "2cc795cf121f81dafd2991d773a9bfe9932e9ad8",
+        "c602488d366f04a7a79b6e879aa79c301d0666e0",
         [
          "html/canvas/offscreen/the-canvas-state/2d.state.saverestore.bitmap.worker.html",
          {}
         ]
        ],
        "2d.state.saverestore.clip.html": [
-        "f5127c0c9d076b7dda87f0ecb198b3fcc45cbc2b",
+        "e96df9e2a4eb466c4b2608bc047d69c57d66ab59",
         [
          null,
          {}
         ]
        ],
        "2d.state.saverestore.clip.worker.js": [
-        "6cc483504f489696ae888f08c20d7ce39da9291f",
+        "622d9416774d9dbac9b2074f2733117d9a689bdc",
         [
          "html/canvas/offscreen/the-canvas-state/2d.state.saverestore.clip.worker.html",
          {}
@@ -480817,14 +482433,14 @@
         ]
        ],
        "2d.state.saverestore.path.html": [
-        "5e6d8264231bac82e13016bdc92432575c97eda8",
+        "34c0b1e6d70325cd718768c7dd62bef3cef03c40",
         [
          null,
          {}
         ]
        ],
        "2d.state.saverestore.path.worker.js": [
-        "4c838e53f605b3a114b2d5a4e2dfdfc64bbe9a2e",
+        "24cec15972c85bd145f6fccd792a8f5a4f453eac",
         [
          "html/canvas/offscreen/the-canvas-state/2d.state.saverestore.path.worker.html",
          {}
@@ -480929,14 +482545,14 @@
         ]
        ],
        "2d.state.saverestore.transformation.html": [
-        "abb7db89dad76bc12a9e0f9fbffe684308f3d439",
+        "fff2ead703604a8dd0b62d8a01db836158545667",
         [
          null,
          {}
         ]
        ],
        "2d.state.saverestore.transformation.worker.js": [
-        "1ef2d6d1f9f5ffbe809b49857f4b320927afead4",
+        "64fb4c47347c0d076f20bf39b381cddd1814257c",
         [
          "html/canvas/offscreen/the-canvas-state/2d.state.saverestore.transformation.worker.html",
          {}
@@ -481040,14 +482656,14 @@
         ]
        ],
        "2d.getcontext.shared.html": [
-        "dfdcbfe67995c16bfd3c91f6afcc1af75fc4f9f1",
+        "6d6162528a84e1e4b43a2d54cbd9efc10b810b4b",
         [
          null,
          {}
         ]
        ],
        "2d.getcontext.shared.worker.js": [
-        "7a7821397e901be47c116117ddaa03ac4eb1491d",
+        "4b8dd52e61d53ff154eccf4fd061a746fd5d9ac8",
         [
          "html/canvas/offscreen/the-offscreen-canvas/2d.getcontext.shared.worker.html",
          {}
@@ -481166,14 +482782,14 @@
         ]
        ],
        "initial.color.html": [
-        "c49a1f0fcec56c4bc59a1e6be0d4348823265dbd",
+        "bfdcef7c4f95c062ebb2dca3e6c191c33f3407e0",
         [
          null,
          {}
         ]
        ],
        "initial.color.worker.js": [
-        "10f579566ee81e8d5c4b169283c552520075124b",
+        "2a6e6e576c1fb1da009806325648aefab0495c20",
         [
          "html/canvas/offscreen/the-offscreen-canvas/initial.color.worker.html",
          {}
@@ -481194,98 +482810,98 @@
         ]
        ],
        "initial.reset.clip.html": [
-        "a5c595561185a35ed886cb7e1b925d8a1d3c493b",
+        "87a3e43be46aee1fc3d79f3a8c9b5bdf46f54a81",
         [
          null,
          {}
         ]
        ],
        "initial.reset.clip.worker.js": [
-        "a12a6235d73e8709aeaa78f5069786811a8dc701",
+        "45ee30d08094dea54732df766829d544d8921c59",
         [
          "html/canvas/offscreen/the-offscreen-canvas/initial.reset.clip.worker.html",
          {}
         ]
        ],
        "initial.reset.different.html": [
-        "2a16c908f996f258210866a71a8fd588d33982be",
+        "632bc2fd69f66e4ace0d5e408a4809ec0c1cc8f6",
         [
          null,
          {}
         ]
        ],
        "initial.reset.different.worker.js": [
-        "5f98f5130ad3e50325ca02e729a7240aa5c5100c",
+        "9d840a59632726b4c059196c6419f5cf4212698c",
         [
          "html/canvas/offscreen/the-offscreen-canvas/initial.reset.different.worker.html",
          {}
         ]
        ],
        "initial.reset.gradient.html": [
-        "ff306d3831ae12f568746c3562609d2e8d3f8d89",
+        "96819a07d3d337e81c5b26246a12c6bdd8f64755",
         [
          null,
          {}
         ]
        ],
        "initial.reset.gradient.worker.js": [
-        "064eb52b5c0be6ee2aac53c55b17249545d0c99e",
+        "a18d11e86a02f1b17073e6cf1c8bd0234de9bd31",
         [
          "html/canvas/offscreen/the-offscreen-canvas/initial.reset.gradient.worker.html",
          {}
         ]
        ],
        "initial.reset.path.html": [
-        "ff39b7d163dd9e21f813350c2f2298885f1353c7",
+        "3c9667ca5cb27570ad3ccc66a01f5385e894f44a",
         [
          null,
          {}
         ]
        ],
        "initial.reset.path.worker.js": [
-        "7057d46ebbcbd482ea6d9e812076cfe6d9349bd9",
+        "9f34734a58ee98be3d0fda22bfa5c9397775bde8",
         [
          "html/canvas/offscreen/the-offscreen-canvas/initial.reset.path.worker.html",
          {}
         ]
        ],
        "initial.reset.pattern.html": [
-        "9a589bbe459249e758bc52a2ccec0215182b9dca",
+        "3766795ba95c8de0fdc425ba6cf597d00c804534",
         [
          null,
          {}
         ]
        ],
        "initial.reset.pattern.worker.js": [
-        "ccbd3f3b9f66d22b5b2c085514f1e6591f14f374",
+        "1fe6c01e2d3f6e04bc2853cc382553d73acff46c",
         [
          "html/canvas/offscreen/the-offscreen-canvas/initial.reset.pattern.worker.html",
          {}
         ]
        ],
        "initial.reset.same.html": [
-        "a2050a11a793112cf71ad4a54f7c38d1ae50fc8c",
+        "bfcf05013ef2dd6636a16159b7083ac18b365cfe",
         [
          null,
          {}
         ]
        ],
        "initial.reset.same.worker.js": [
-        "c67c57ae2594b15539216631bf0ce939ca89c6de",
+        "00db682f70aa554114d5f851beac6e4e7fe2f078",
         [
          "html/canvas/offscreen/the-offscreen-canvas/initial.reset.same.worker.html",
          {}
         ]
        ],
        "initial.reset.transform.html": [
-        "85912f4813dbd6f0578fbc85117a6fed0c9983cf",
+        "402b34f9c5c78ba42d2de6e5443d06f5a9d30cbb",
         [
          null,
          {}
         ]
        ],
        "initial.reset.transform.worker.js": [
-        "d88e7b000072ade237327cecfa8a0eea8af03832",
+        "3fb80d061ff216c8110231f0809aa858fc5c9fc6",
         [
          "html/canvas/offscreen/the-offscreen-canvas/initial.reset.transform.worker.html",
          {}
@@ -481588,308 +483204,308 @@
       },
       "transformations": {
        "2d.transformation.order.html": [
-        "94ec72b4a632986897208c0e99410a91aae20c5d",
+        "b1308035936676ff4f37f077b8aee96f9e4b56b7",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.order.worker.js": [
-        "d3a8f638fdc404b47ce133d7207b162be94b9c89",
+        "7ac61067b4b870f4ab6b8491ba69bf2e664e1680",
         [
          "html/canvas/offscreen/transformations/2d.transformation.order.worker.html",
          {}
         ]
        ],
        "2d.transformation.rotate.direction.html": [
-        "aa0493a20e39fe0c36eda2f70422ba9689dfb8b8",
+        "0a98c7e65f9b5fb288832048b3696eaac77c1346",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.direction.worker.js": [
-        "38195b566beee9b5743a5f8a6e90a6a111dd9b4f",
+        "465d3b679072de2c1d93274c877f8e047f0f0a34",
         [
          "html/canvas/offscreen/transformations/2d.transformation.rotate.direction.worker.html",
          {}
         ]
        ],
        "2d.transformation.rotate.nonfinite.html": [
-        "defe2fe8286aece8d1a87b367de6663cab5dd247",
+        "0f2227a4e5cc185d02236eaf3f1117648240e662",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.nonfinite.worker.js": [
-        "a8aead4a5c7eeed27fa4803303f027087c641ff1",
+        "56a04d874e864de75e904fb7961012f43aaf15a9",
         [
          "html/canvas/offscreen/transformations/2d.transformation.rotate.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.transformation.rotate.radians.html": [
-        "48104af683e740ee99f57151e25e4e0318e94f42",
+        "8a78dddd7f8e678c4e7ba762e96e8dd17900e64c",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.radians.worker.js": [
-        "5a2ac2fe3a03b2c8b9880ca02cb6b370e92846ac",
+        "9780e68a02f77a578dd570f256edd536dd981261",
         [
          "html/canvas/offscreen/transformations/2d.transformation.rotate.radians.worker.html",
          {}
         ]
        ],
        "2d.transformation.rotate.wrap.html": [
-        "a524af7543808427291e9f7510842086f040a2e8",
+        "7711a8c1404e95fd703737d5208c609540e0c79d",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.wrap.worker.js": [
-        "bc7dff2e3252612aefea655ea5aa8c94d93c5b82",
+        "db9fbd43bc148a62f905037c9c6db6c0f6dfeeca",
         [
          "html/canvas/offscreen/transformations/2d.transformation.rotate.wrap.worker.html",
          {}
         ]
        ],
        "2d.transformation.rotate.wrapnegative.html": [
-        "2c5222d879c5af8a81ef99ed6c56fef271e16d56",
+        "49959dac0227cabcb33cc1a37114804ae451783c",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.wrapnegative.worker.js": [
-        "ca0e473c1f018883ec582a8e0d71701738dbe90c",
+        "7f93f654582433f71d38bdb7b9735540f359e883",
         [
          "html/canvas/offscreen/transformations/2d.transformation.rotate.wrapnegative.worker.html",
          {}
         ]
        ],
        "2d.transformation.rotate.zero.html": [
-        "e1e000c579b176598b0abe7f60ddafc727474538",
+        "2255b9973dd0ee34a1ebd25fbaf0525b9a91ad57",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.rotate.zero.worker.js": [
-        "2d6367647e28ef96cfe4a2659ff113e23f759461",
+        "10e00c4656a0b4301328af8c785e0ee6ff89ab48",
         [
          "html/canvas/offscreen/transformations/2d.transformation.rotate.zero.worker.html",
          {}
         ]
        ],
        "2d.transformation.scale.basic.html": [
-        "17f8beab8169bb4103645447ad194c8f73ff39c5",
+        "c78ac79f5abc26f2e61b7da8f54acc6c4849f281",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.basic.worker.js": [
-        "282328b1e37f3b6d3e218bda19a4a2b1f795d830",
+        "39b52d57b5f68267c115b3b61d8310ca378587b4",
         [
          "html/canvas/offscreen/transformations/2d.transformation.scale.basic.worker.html",
          {}
         ]
        ],
        "2d.transformation.scale.large.html": [
-        "07277d5e364d8ebae2a9b8e79c3d06ad41518d37",
+        "a67d05eb2c2d8b52c0619d359d3041d85e969560",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.large.worker.js": [
-        "702b78d11ea2457f9d06dccca6554e09a53d7d0d",
+        "1293cce196fdb6fe092637de5932a40dc42b099b",
         [
          "html/canvas/offscreen/transformations/2d.transformation.scale.large.worker.html",
          {}
         ]
        ],
        "2d.transformation.scale.multiple.html": [
-        "ab8bb21316d5135745ca08cf5c216a3464f84712",
+        "717f3d305a146c994410b7bbb3d1b15dd3ada2da",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.multiple.worker.js": [
-        "641917399aa7ce486a4aabc97b0296d67b4275c1",
+        "c5a38207ea0c1a06ba754e6117edbd7f1509d5b2",
         [
          "html/canvas/offscreen/transformations/2d.transformation.scale.multiple.worker.html",
          {}
         ]
        ],
        "2d.transformation.scale.negative.html": [
-        "eaa32619f32291dfe2da4d7914e401d01de993b8",
+        "fbcec5d763a9518bf4d9e86baa9d8687e00f8fd1",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.negative.worker.js": [
-        "2a87b12d755619f9508f9fa02c0c7ceaa57c2c3f",
+        "a5344a9a7177e2d128aa72cf089e93de7ba386c7",
         [
          "html/canvas/offscreen/transformations/2d.transformation.scale.negative.worker.html",
          {}
         ]
        ],
        "2d.transformation.scale.nonfinite.html": [
-        "97f6c145378b1cfc131626a4fc986a2c60c56cba",
+        "ac38bc1fa468cb3087aa0e4a7fcc30e431fd359d",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.nonfinite.worker.js": [
-        "6ec8a8d9f7247a22e0876560e43425dcc3630be5",
+        "95e9922b69b521a2211502a4718425b2434e8648",
         [
          "html/canvas/offscreen/transformations/2d.transformation.scale.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.transformation.scale.zero.html": [
-        "6b78598a9c6a3ce1fa7d95625a1d8f13054279a2",
+        "9eae3b1db3338dced1ee49738454559cc038d00b",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.scale.zero.worker.js": [
-        "e0399211ffe37ad0ad26cc7e2219b874029b902d",
+        "0f8dad04422d52a66f4d49b59f22cebae76e300a",
         [
          "html/canvas/offscreen/transformations/2d.transformation.scale.zero.worker.html",
          {}
         ]
        ],
        "2d.transformation.setTransform.multiple.html": [
-        "5299bec075fb4d76dc22f0a2cb47f60ebb5a2308",
+        "f8dfb048812c34016a8ae2424855c688e92ce4a7",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.setTransform.multiple.worker.js": [
-        "0a1f034b30252884e70f6aca2a8a161797f85053",
+        "9d01c1302ec136bce85fe918bda42f176b591bf3",
         [
          "html/canvas/offscreen/transformations/2d.transformation.setTransform.multiple.worker.html",
          {}
         ]
        ],
        "2d.transformation.setTransform.nonfinite.html": [
-        "91fd054d684b4e1cdf2d8c9507a02c019a0eb0a3",
+        "fbed341a04a5599f1646fa3b92cdcd4b5d54d162",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.setTransform.nonfinite.worker.js": [
-        "0a0f3977853945e4b557564ea04886a36df00f20",
+        "be7e055a853ccff10e7ba9f76237dd3229a36dc1",
         [
          "html/canvas/offscreen/transformations/2d.transformation.setTransform.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.transformation.setTransform.skewed.html": [
-        "505fde266dad61defeef37c4187e846284ca7fdf",
+        "40fa8015d4ca10258c9b4870843af85b1c9f7022",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.setTransform.skewed.worker.js": [
-        "2293a6a8bb72f3a686295cc1e9257bd9645a4904",
+        "6490f9b7094ec6094c93953e7178ecfb60ce1580",
         [
          "html/canvas/offscreen/transformations/2d.transformation.setTransform.skewed.worker.html",
          {}
         ]
        ],
        "2d.transformation.transform.identity.html": [
-        "22d061a3ee5b3c3ed274581a73c0fc5525018fda",
+        "92753bc9e3eecb2f7a4b00054c967467be39c9e1",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.transform.identity.worker.js": [
-        "d9d0c0e1b06cc466adeb1f49332868d1bd9e2afe",
+        "99ac58d49d3ae634c1123bc9dd87aaae0bc59b96",
         [
          "html/canvas/offscreen/transformations/2d.transformation.transform.identity.worker.html",
          {}
         ]
        ],
        "2d.transformation.transform.multiply.html": [
-        "6600f4ef5475c25998a116c98558430c5a202e7f",
+        "f69fa4330af2d17d88b4315c08a03ae1fa4a3406",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.transform.multiply.worker.js": [
-        "5d335135dbcc50a026629421ca8d86534b06f232",
+        "1a0e702a05bf73984e1c8416bf639e5349eac711",
         [
          "html/canvas/offscreen/transformations/2d.transformation.transform.multiply.worker.html",
          {}
         ]
        ],
        "2d.transformation.transform.nonfinite.html": [
-        "970a0ad1737f3a8563b809ce43e2426917d019d7",
+        "6e679341d5d01012a23627e0251fdfe6c6073560",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.transform.nonfinite.worker.js": [
-        "631d98ee7eff47f966272295bb86aa6118cec055",
+        "d596fc9744b70e25f07c6e61ea84480e0b5f215f",
         [
          "html/canvas/offscreen/transformations/2d.transformation.transform.nonfinite.worker.html",
          {}
         ]
        ],
        "2d.transformation.transform.skewed.html": [
-        "cc0812958c73fc031caf5b899ac5bfe7c6d2dc75",
+        "78e1252c67c517cb9d35f80136178fa8e9ae7416",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.transform.skewed.worker.js": [
-        "cf1481d98bbd8e65f38640dad5639b4fe5a77924",
+        "46416bb957010f8bea2d29fc7256e87a8d832949",
         [
          "html/canvas/offscreen/transformations/2d.transformation.transform.skewed.worker.html",
          {}
         ]
        ],
        "2d.transformation.translate.basic.html": [
-        "9c595708512b1784801ca519f418856162317e2b",
+        "8144ab0cc1b4e6317f08953366fec5bd2de9d03b",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.translate.basic.worker.js": [
-        "55926e461946ab1030257ade0d9cc02a67407c2d",
+        "695aff37da54e53f925d65896546cca85a2235af",
         [
          "html/canvas/offscreen/transformations/2d.transformation.translate.basic.worker.html",
          {}
         ]
        ],
        "2d.transformation.translate.nonfinite.html": [
-        "1f06fcce354957add7dd2f83681fcb4a2ee7c6bb",
+        "4127a7a157ed2bad072b8df45ed80bec903bdbf8",
         [
          null,
          {}
         ]
        ],
        "2d.transformation.translate.nonfinite.worker.js": [
-        "bd8722c6ad673e637de3f72eec4d05a8246aa287",
+        "84b52a203b65bb9bea5834d96197a16f66149148",
         [
          "html/canvas/offscreen/transformations/2d.transformation.translate.nonfinite.worker.html",
          {}
@@ -492114,7 +493730,7 @@
         ]
        ],
        "2d.getcontext.shared.html": [
-        "6381734c24073af965781778ce9a511d9f06f0c5",
+        "93c1603b6959582248d0980751de2d6fc66c9ce0",
         [
          null,
          {}
@@ -492135,7 +493751,7 @@
         ]
        ],
        "2d.type.extend.html": [
-        "fd699b72d4152e9b85e351a366060c3a979f82ea",
+        "1cb5e4869f96f0471b22c74ef00fa8f88ca6713b",
         [
          null,
          {}
@@ -492149,7 +493765,7 @@
         ]
        ],
        "2d.type.replace.html": [
-        "72defa8c6844652cb3b0ce689e1cdc12a6a3bc93",
+        "47aa5bb8235a7b5e4892546973e3923e4393b0a8",
         [
          null,
          {}
@@ -492275,7 +493891,7 @@
         ]
        ],
        "initial.colour.html": [
-        "4c9aa314db323e6b0c9ba9494bd5799025be224d",
+        "166732a57b32df8997b387b11caf2771c840998b",
         [
          null,
          {}
@@ -492289,56 +493905,56 @@
         ]
        ],
        "initial.reset.clip.html": [
-        "6f8c5838ef8a2482884be6baadb48fa558b72d91",
+        "ebf52bfa764a3431f11edea22ca485c6398aafb0",
         [
          null,
          {}
         ]
        ],
        "initial.reset.different.html": [
-        "a2afaff4e1c922fbe86e7e29f72f78761639c42d",
+        "d55dd250c091a2a550d44ba6fc6dc791c2a13241",
         [
          null,
          {}
         ]
        ],
        "initial.reset.gradient.html": [
-        "6d9f6827afbb24aa229374203f035e6fc1e675d7",
+        "31b56ec8e9ba41510c282116e156d9091626aaff",
         [
          null,
          {}
         ]
        ],
        "initial.reset.path.html": [
-        "c0bb067faf09828e96c99ae8620770d8a2dcf1e7",
+        "3525377d2db6b376ce53730fb920d4a811a00db4",
         [
          null,
          {}
         ]
        ],
        "initial.reset.pattern.html": [
-        "170ab9e193f36723bd26f2a29dd086be23de177b",
+        "28f8306d96d3996488dae532e5e16aa7622c1327",
         [
          null,
          {}
         ]
        ],
        "initial.reset.same.html": [
-        "42966b11eda6773a0d27c584c85fdf1c926bb648",
+        "1a0872ba2c05bdef16e0cb1e4a4ae4469496fcb5",
         [
          null,
          {}
         ]
        ],
        "initial.reset.transform.html": [
-        "661bbe6db324869fd1b090087604747b5fa97804",
+        "36284ba4984108b589014b136aa8e3c88c23357e",
         [
          null,
          {}
         ]
        ],
        "security.dataURI.html": [
-        "9230cf641807d2d9ae3286402b1ed14d6699f7d6",
+        "93b560e82c472eaf8f9018c865d6eefd4d03db92",
         [
          null,
          {}
@@ -492814,21 +494430,21 @@
         ]
        ],
        "toDataURL.jpeg.alpha.html": [
-        "7260c9dd0fd993868ee4a32694a2be4231cc1fe3",
+        "daf278351d967927d6143675681a1f0b29c86ca7",
         [
          null,
          {}
         ]
        ],
        "toDataURL.jpeg.primarycolours.html": [
-        "abf07bffd4ba89aa9098ee7af97657927f0cf028",
+        "750487bdeaf60414a13db06c56473bd864e56655",
         [
          null,
          {}
         ]
        ],
        "toDataURL.jpeg.quality.basic.html": [
-        "fd96cdd1820feccddc67b8f2f0df24e5e5f2661c",
+        "dc5d8142441c28bc5ee43750cd9a3ecc14b08b32",
         [
          null,
          {}
@@ -492877,7 +494493,7 @@
         ]
        ],
        "toDataURL.png.complexcolours.html": [
-        "d7a39f33684b940b25da641caeb4d40fb00a40ba",
+        "dadea7c5b08eb8fc6c2141208acd33317843d46c",
         [
          null,
          {}
@@ -492891,7 +494507,7 @@
         ]
        ],
        "toDataURL.png.primarycolours.html": [
-        "93adc945096e2301642fd77e8a5fae298cd37530",
+        "a13850d54e8aab4b453fb0f5fee8221e7a44766f",
         [
          null,
          {}
@@ -493521,6 +495137,206 @@
          {}
         ]
        ],
+       "sandbox-top-navigation-child-special-cases.tentative.sub.window.js": [
+        "a9ea9e472323876d0fd21811450b76897071e40c",
+        [
+         "html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child-special-cases.tentative.sub.window.html",
+         {
+          "script_metadata": [
+           [
+            "title",
+            "Top-level navigation tests with cross origin & user activated child frames"
+           ],
+           [
+            "script",
+            "/common/dispatcher/dispatcher.js"
+           ],
+           [
+            "script",
+            "/common/get-host-info.sub.js"
+           ],
+           [
+            "script",
+            "/common/utils.js"
+           ],
+           [
+            "script",
+            "/resources/testdriver.js"
+           ],
+           [
+            "script",
+            "/resources/testdriver-vendor.js"
+           ],
+           [
+            "script",
+            "/resources/testharness.js"
+           ],
+           [
+            "script",
+            "/resources/testharnessreport.js"
+           ],
+           [
+            "script",
+            "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js"
+           ],
+           [
+            "script",
+            "./resources/sandbox-top-navigation-helper.js"
+           ]
+          ]
+         }
+        ]
+       ],
+       "sandbox-top-navigation-child.tentative.sub.window.js": [
+        "58133456970a79cb684beb45408fc7da1b5b811d",
+        [
+         "html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-child.tentative.sub.window.html",
+         {
+          "script_metadata": [
+           [
+            "title",
+            "Top-level navigation tests with child frames"
+           ],
+           [
+            "script",
+            "/common/dispatcher/dispatcher.js"
+           ],
+           [
+            "script",
+            "/common/get-host-info.sub.js"
+           ],
+           [
+            "script",
+            "/common/utils.js"
+           ],
+           [
+            "script",
+            "/resources/testdriver.js"
+           ],
+           [
+            "script",
+            "/resources/testdriver-vendor.js"
+           ],
+           [
+            "script",
+            "/resources/testharness.js"
+           ],
+           [
+            "script",
+            "/resources/testharnessreport.js"
+           ],
+           [
+            "script",
+            "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js"
+           ],
+           [
+            "script",
+            "./resources/sandbox-top-navigation-helper.js"
+           ]
+          ]
+         }
+        ]
+       ],
+       "sandbox-top-navigation-escalate-privileges.tentative.sub.window.js": [
+        "999f056f334db02ddd6e326648e96f542de61ca9",
+        [
+         "html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-escalate-privileges.tentative.sub.window.html",
+         {
+          "script_metadata": [
+           [
+            "title",
+            "Top-level navigation tests with frames that try to give themselves top-nav permission"
+           ],
+           [
+            "script",
+            "/common/dispatcher/dispatcher.js"
+           ],
+           [
+            "script",
+            "/common/get-host-info.sub.js"
+           ],
+           [
+            "script",
+            "/common/utils.js"
+           ],
+           [
+            "script",
+            "/resources/testdriver.js"
+           ],
+           [
+            "script",
+            "/resources/testdriver-vendor.js"
+           ],
+           [
+            "script",
+            "/resources/testharness.js"
+           ],
+           [
+            "script",
+            "/resources/testharnessreport.js"
+           ],
+           [
+            "script",
+            "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js"
+           ],
+           [
+            "script",
+            "./resources/sandbox-top-navigation-helper.js"
+           ]
+          ]
+         }
+        ]
+       ],
+       "sandbox-top-navigation-grandchild.tentative.sub.window.js": [
+        "519efc94e516d5938b8329ca6591133ed6fb5fef",
+        [
+         "html/semantics/embedded-content/the-iframe-element/sandbox-top-navigation-grandchild.tentative.sub.window.html",
+         {
+          "script_metadata": [
+           [
+            "title",
+            "Top-level navigation tests with grandchild frames"
+           ],
+           [
+            "script",
+            "/common/dispatcher/dispatcher.js"
+           ],
+           [
+            "script",
+            "/common/get-host-info.sub.js"
+           ],
+           [
+            "script",
+            "/common/utils.js"
+           ],
+           [
+            "script",
+            "/resources/testdriver.js"
+           ],
+           [
+            "script",
+            "/resources/testdriver-vendor.js"
+           ],
+           [
+            "script",
+            "/resources/testharness.js"
+           ],
+           [
+            "script",
+            "/resources/testharnessreport.js"
+           ],
+           [
+            "script",
+            "/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js"
+           ],
+           [
+            "script",
+            "./resources/sandbox-top-navigation-helper.js"
+           ]
+          ]
+         }
+        ]
+       ],
        "sandbox_001.htm": [
         "97af61163a8dd1e463cf2af4f5d350e167c407be",
         [
@@ -497565,7 +499381,7 @@
        ]
       ],
       "popup-attribute-basic.tentative.html": [
-       "dfce21b0c16d85c7da7efd7d738fd949ce5bc273",
+       "43b8a56ec743f26548a08699758b49c5a098019e",
        [
         null,
         {}
@@ -497634,7 +499450,7 @@
        ]
       ],
       "popup-light-dismiss.tentative.html": [
-       "8eca7a647a655144c63648729e0e47bb18a14336",
+       "265a8cb00b6e1bcf6f596dc1ab8c679882c6dc2b",
        [
         null,
         {
@@ -504553,7 +506369,7 @@
       ]
      ],
      "no-activation-thru-escape-key.html": [
-      "27988d16030777f94f50cccfb9c1e4f9256b7cac",
+      "0045e20788189a8b118a9363490bfa17c067a736",
       [
        null,
        {
@@ -508408,7 +510224,7 @@
       ]
      ],
      "get_all_cookies.sub.html": [
-      "ab9ac071dd1cedcf28e218931546b753c2eefe20",
+      "8545d06be96d631b8465197c84e81ad38465a406",
       [
        null,
        {
@@ -508417,7 +510233,7 @@
       ]
      ],
      "get_all_cookies.sub.https.html": [
-      "1359a75b5edd415a4b8c227f26f102ca4fd28579",
+      "08ab8cc3f43c4854eebe2a2ab6ef175cfbdc7c57",
       [
        null,
        {
@@ -508426,7 +510242,7 @@
       ]
      ],
      "get_named_cookie.sub.html": [
-      "2a6fb57024d92a692813cf5d4cc7019be35809dc",
+      "c3a8eed251eb8e3e1e7ae373f34c3748f759eb9f",
       [
        null,
        {
@@ -508435,7 +510251,7 @@
       ]
      ],
      "get_named_cookie.sub.https.html": [
-      "0a99590195143aa3a023db3ff3ff3d54893cbaad",
+      "d316d4ec72b526f3bf43b1420c218b034bf8b365",
       [
        null,
        {
@@ -509699,6 +511515,13 @@
        null,
        {}
       ]
+     ],
+     "observe-video.tentative.html": [
+      "49bdd986f6c728f1f3a172e42f4bf14d5ab64388",
+      [
+       null,
+       {}
+      ]
      ]
     },
     "contracted-image.html": [
@@ -514792,6 +516615,28 @@
       {}
      ]
     ],
+    "csp.https.window.js": [
+     "5428fb479110a5171174e0ffbebe95b890b4df32",
+     [
+      "mixed-content/csp.https.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/common/dispatcher/dispatcher.js"
+        ],
+        [
+         "script",
+         "/common/get-host-info.sub.js"
+        ],
+        [
+         "script",
+         "/common/utils.js"
+        ]
+       ]
+      }
+     ]
+    ],
     "gen": {
      "sharedworker-classic-data.http-rp": {
       "opt-in": {
@@ -521442,6 +523287,13 @@
       {}
      ]
     ],
+    "navigation-type-post-backforward.html": [
+     "1fbdf1ae9bf870a6456127a5c876ae86f43dea76",
+     [
+      null,
+      {}
+     ]
+    ],
     "nested-unload-timing.html": [
      "1130fb684065f412bdee9ff6a5287e80bedb056c",
      [
@@ -522279,134 +524131,6 @@
      ]
     ]
    },
-   "page-unload-beacon": {
-    "pending_beacon-basic.tentative.window.js": [
-     "efc9ed2617e3b90b90302b06826ca729f60eb763",
-     [
-      "page-unload-beacon/pending_beacon-basic.tentative.window.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "./resources/pending_beacon-helper.js"
-        ]
-       ]
-      }
-     ]
-    ],
-    "pending_beacon-deactivate.tentative.window.js": [
-     "74c0852adc322a7194ab0bc3aca83a358572d462",
-     [
-      "page-unload-beacon/pending_beacon-deactivate.tentative.window.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "./resources/pending_beacon-helper.js"
-        ]
-       ]
-      }
-     ]
-    ],
-    "pending_beacon-sendnow.tentative.window.js": [
-     "00baccd0c1ab42c0dfa08def5f23ad6ba21eed9b",
-     [
-      "page-unload-beacon/pending_beacon-sendnow.tentative.window.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "/common/utils.js"
-        ],
-        [
-         "script",
-         "./resources/pending_beacon-helper.js"
-        ]
-       ]
-      }
-     ]
-    ],
-    "pending_get_beacon-cors.tentative.https.window.js": [
-     "10bb3a0bed7f4888aaab7c7f6551f4a9a447c60e",
-     [
-      "page-unload-beacon/pending_get_beacon-cors.tentative.https.window.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "/common/get-host-info.sub.js"
-        ],
-        [
-         "script",
-         "/common/utils.js"
-        ],
-        [
-         "script",
-         "./resources/pending_beacon-helper.js"
-        ]
-       ]
-      }
-     ]
-    ],
-    "pending_get_beacon-send.tentative.window.js": [
-     "8c6e826af5b578b5893babb5e0ee90e37b37cc09",
-     [
-      "page-unload-beacon/pending_get_beacon-send.tentative.window.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "/common/utils.js"
-        ],
-        [
-         "script",
-         "./resources/pending_beacon-helper.js"
-        ]
-       ]
-      }
-     ]
-    ],
-    "pending_post_beacon-cors.tentative.https.window.js": [
-     "01511d22c1b7bc58cfd86ca3725b0514f292d058",
-     [
-      "page-unload-beacon/pending_post_beacon-cors.tentative.https.window.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "/common/get-host-info.sub.js"
-        ],
-        [
-         "script",
-         "/common/utils.js"
-        ],
-        [
-         "script",
-         "./resources/pending_beacon-helper.js"
-        ]
-       ]
-      }
-     ]
-    ],
-    "pending_post_beacon-sendwithdata.tentative.window.js": [
-     "77e91479e8b990b2b8240dc3fd6853e4d25ab980",
-     [
-      "page-unload-beacon/pending_post_beacon-sendwithdata.tentative.window.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "/common/utils.js"
-        ],
-        [
-         "script",
-         "./resources/pending_beacon-helper.js"
-        ]
-       ]
-      }
-     ]
-    ]
-   },
    "page-visibility": {
     "iframe-session-history.html": [
      "e0232153167e680b66e6d5eb1ca637f31ea7c934",
@@ -523591,6 +525315,15 @@
       }
      ]
     ],
+    "navigation-id-reset.tentative.html": [
+     "7386331d26e918ebe06b15207f92f7c60a372409",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
     "navigation-id-resource-timing.tentative.html": [
      "1ec906ebbbba4a8118f746ac94c52aa399556f05",
      [
@@ -539653,6 +541386,15 @@
       }
      ]
     ],
+    "reporting-api-honors-limits.https.sub.html": [
+     "4732711888ca5fa7be5f87108967b67102fdb706",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "reporting-isolated-across-navigations.https.sub.html": [
      "df61afa8330e5f230ba712d14f0f7109f758b502",
      [
@@ -542455,7 +544197,7 @@
      ]
     ],
     "getdisplaymedia.https.html": [
-     "c92a7154ee6728c1841a2e7e130f71ba521ae14e",
+     "1c9eb449f55a514f5ff958e40fbf97089357f7bb",
      [
       null,
       {
@@ -542579,7 +544321,7 @@
    },
    "screen-orientation": {
     "active-lock.html": [
-     "84fb603eaeb48420c2abe47bc561516dd24a6e49",
+     "f71d5f0dbc5f61ce78a256e97d22048ae73759ef",
      [
       null,
       {
@@ -542622,7 +544364,7 @@
      ]
     ],
     "lock-basic.html": [
-     "1ae26567fc2249ac1db40db52dbc01625a06e0d2",
+     "71c8e8e210d35a7c5ff5b7f906ca542468d0f214",
      [
       null,
       {
@@ -542631,7 +544373,7 @@
      ]
     ],
     "lock-sandboxed-iframe.html": [
-     "b8b856dc55be8a534f765cdd92a313daeaa695d0",
+     "1ce1039895684063e3881783d4b5f875ca094895",
      [
       null,
       {
@@ -542648,8 +544390,17 @@
       }
      ]
     ],
+    "non-fully-active.html": [
+     "61066ebd849ed8a554e688a721fdf8f301cf1f00",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "onchange-event-subframe.html": [
-     "0ba0edc957cf27c99ba072769bf28de9ddf74b57",
+     "4295e3f5e2328eb72672c64ad6cc198d2e0e8d7b",
      [
       null,
       {
@@ -542658,7 +544409,7 @@
      ]
     ],
     "onchange-event.html": [
-     "ebe002d96bd93fdc5dac1273ae0dbf7a1c9d81bf",
+     "9c416eba81faf55a6d870a1aeb572f233d6341ef",
      [
       null,
       {
@@ -542667,7 +544418,7 @@
      ]
     ],
     "orientation-reading.html": [
-     "7e6182c61bf3c1fb0a491ce6454043ee77a21af7",
+     "fdf05c87065ccb6927a833eefb1ec8a60c32fe9a",
      [
       null,
       {
@@ -543313,7 +545064,7 @@
     },
     "view-timelines": {
      "block-view-timeline-current-time-vertical-rl.tentative.html": [
-      "2c2e02be6bb98a274bcb53bd65d9138c4e49a4f9",
+      "d729f8075b4e52e570cfaa6e64af13b6ed891b3d",
       [
        null,
        {}
@@ -543334,7 +545085,7 @@
       ]
      ],
      "inline-view-timeline-current-time.tentative.html": [
-      "538bffb1a3bf8dde2f7f9e582fe6ec5a217e5ade",
+      "080c1c6e92dbf6e654eb84806b5d36171908505c",
       [
        null,
        {}
@@ -543354,6 +545105,13 @@
        {}
       ]
      ],
+     "view-timeline-inset.html": [
+      "045c5f0a707311b6c56638b87c899ed61e4fe018",
+      [
+       null,
+       {}
+      ]
+     ],
      "view-timeline-snapport.html": [
       "5d68d37037a344f4b514e5cd937500abbc66e43c",
       [
@@ -550389,8 +552147,17 @@
     ]
    },
    "soft-navigation-heuristics": {
+    "back.tentative.html": [
+     "94a8c7ea2f419df2385b75b3ad99fd9bcd115b4e",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "dropped-entries.tentative.html": [
-     "9234d759a15979cb8ecfd8db8804b4010e893935",
+     "c29b060a1eb69188b775e261f0bc4447b67c106a",
      [
       null,
       {
@@ -550400,7 +552167,7 @@
      ]
     ],
     "image-lcp-followed-by-image-softnav-lcp.tentative.html": [
-     "5865755f8105aaf2c595cd46aec3826f45ec6ad5",
+     "7e6c96ee69b875eff4860c86664a280cfda75895",
      [
       null,
       {
@@ -550409,7 +552176,7 @@
      ]
     ],
     "image-lcp-followed-by-text-softnav-lcp.tentative.html": [
-     "f4205d9611c504c6575ad663678abe18a5f16733",
+     "c2e2e149cefa2b4a888fbbd76bb052d1a833765f",
      [
       null,
       {
@@ -550418,7 +552185,7 @@
      ]
     ],
     "soft-navigation-detection-main-descendent.tentative.html": [
-     "bd4cd9967ce430134f65941bce6e27b994f8f3fc",
+     "c358f8095b5004979f46dd43ac1528261416a611",
      [
       null,
       {
@@ -550427,7 +552194,7 @@
      ]
     ],
     "soft-navigation-detection-non-main.tentative.html": [
-     "ccf436b6fba2785a75356a49348623b496195089",
+     "3aefdd8e9926143cf31c8e314aa71207d6dd630e",
      [
       null,
       {
@@ -550436,7 +552203,7 @@
      ]
     ],
     "soft-navigation-detection-web-component-lifecycle.tentative.html": [
-     "e74e5d535ca802a8d9955d9695b6c377aad1fd1c",
+     "1455e4e7cdb371fc3e0391e18575f889db4fa9bc",
      [
       null,
       {
@@ -550445,7 +552212,7 @@
      ]
     ],
     "soft-navigation-detection.tentative.html": [
-     "31a38a4d24ec3b871b9a77a42a2da3ad135941f6",
+     "8ca969da66c467ef57bfec6de1a9d2feee7c6a20",
      [
       null,
       {
@@ -550454,7 +552221,7 @@
      ]
     ],
     "soft-navigation-no-url.tentative.html": [
-     "9a9e2b7d91a9055fe4dde12e86fd74515333b3e8",
+     "12e27f10e8f4de17c5fa46a612edb8b242711e7a",
      [
       null,
       {
@@ -550463,7 +552230,7 @@
      ]
     ],
     "text-lcp-followed-by-image-softnav-lcp.tentative.html": [
-     "e3428f6208429464558a8ceb943b96cef05eb157",
+     "3f66a7f3e6fb50c2640d12004e7dd443050bc2f4",
      [
       null,
       {
@@ -550472,7 +552239,7 @@
      ]
     ],
     "text-lcp-followed-by-text-softnav-lcp.tentative.html": [
-     "a00d05882f21a73c9f6603f87d2151801ea978c0",
+     "6df2b738c0a6e7d4c8572d7fe523493928c55d5b",
      [
       null,
       {
@@ -550687,6 +552454,15 @@
        }
       ]
      ],
+     "accept-clint-hint-cache.https.html": [
+      "66e2c90c04a04dd69119569e24658697e258e4c6",
+      [
+       null,
+       {
+        "timeout": "long"
+       }
+      ]
+     ],
      "activation-start.html": [
       "676eca3fa151e8495225980ab1339d90c66c1e24",
       [
@@ -550723,6 +552499,24 @@
        }
       ]
      ],
+     "credentialed-prerender-not-opt-in.html": [
+      "8c797b80222d13038dfbb4a6bb7f65cf27e09c19",
+      [
+       null,
+       {
+        "timeout": "long"
+       }
+      ]
+     ],
+     "credentialed-prerender-opt-in.html": [
+      "eb8fd3cdfccb10903de132ea9d432959bebc7ad7",
+      [
+       null,
+       {
+        "timeout": "long"
+       }
+      ]
+     ],
      "cross-origin-iframe.html": [
       "f4819c207ba447d6b63d7c32e367fb7b78568170",
       [
@@ -556106,14 +557900,14 @@
    },
    "subapps": {
     "add-error.tentative.https.html": [
-     "90e05832f202e5744f9ab36e986231222abc8071",
+     "626c934cc103d74f15602ec3a38f667813b43a68",
      [
       null,
       {}
      ]
     ],
     "add-success.tentative.https.html": [
-     "3b84bc5614cc66815f4766a9f2c9d024afb529e6",
+     "1839b18e45e9a6bc700f0987c4bff66f07a1a906",
      [
       null,
       {}
@@ -559223,14 +561017,14 @@
        ]
       ],
       "SVGGeometryElement.isPointInFill-01.svg": [
-       "326c52298daf22345e06f7c4469a78c8752e7050",
+       "3fdeee2147c3ac9e1754119112b7318bdd5b4fcb",
        [
         null,
         {}
        ]
       ],
       "SVGGeometryElement.isPointInStroke-01.svg": [
-       "5864c43545812240217b567eec75e12a8b38ed81",
+       "78ba96d7db63fbb42b8f41f7c0a7778c96b64eff",
        [
         null,
         {}
@@ -559334,6 +561128,13 @@
         {}
        ]
       ],
+      "SVGPoint.html": [
+       "cdf44e29f20bd3440195752f4122d758a4d24659",
+       [
+        null,
+        {}
+       ]
+      ],
       "event-handler-all-document-element-events.svg": [
        "fa813dd1dd31987d2792aaa14a5f7ea996a8054d",
        [
@@ -560378,6 +562179,15 @@
      }
     },
     "mouse": {
+     "cancel-mousedown-in-subframe.html": [
+      "07350377354cda3c3fbafada0ff67700d01d06a0",
+      [
+       null,
+       {
+        "testdriver": true
+       }
+      ]
+     ],
      "layout_change_should_fire_mouseover.html": [
       "49257ae60d19dc69d523f735fc0e5ccbde1663bf",
       [
@@ -560396,6 +562206,15 @@
        }
       ]
      ],
+     "mouseenter-mouseleave-on-drag.html": [
+      "c36a1501c0bb44a8c88f50e4e7a1337aee7b6e8c",
+      [
+       null,
+       {
+        "testdriver": true
+       }
+      ]
+     ],
      "mouseevent_move_button.html": [
       "edde11d022e81969957cf99578c394db8697f461",
       [
@@ -560556,6 +562375,134 @@
      }
     }
    },
+   "unload-beacon": {
+    "pending_beacon-basic.tentative.window.js": [
+     "efc9ed2617e3b90b90302b06826ca729f60eb763",
+     [
+      "unload-beacon/pending_beacon-basic.tentative.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "./resources/pending_beacon-helper.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "pending_beacon-deactivate.tentative.window.js": [
+     "74c0852adc322a7194ab0bc3aca83a358572d462",
+     [
+      "unload-beacon/pending_beacon-deactivate.tentative.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "./resources/pending_beacon-helper.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "pending_beacon-sendnow.tentative.window.js": [
+     "00baccd0c1ab42c0dfa08def5f23ad6ba21eed9b",
+     [
+      "unload-beacon/pending_beacon-sendnow.tentative.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/common/utils.js"
+        ],
+        [
+         "script",
+         "./resources/pending_beacon-helper.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "pending_get_beacon-cors.tentative.https.window.js": [
+     "10bb3a0bed7f4888aaab7c7f6551f4a9a447c60e",
+     [
+      "unload-beacon/pending_get_beacon-cors.tentative.https.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/common/get-host-info.sub.js"
+        ],
+        [
+         "script",
+         "/common/utils.js"
+        ],
+        [
+         "script",
+         "./resources/pending_beacon-helper.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "pending_get_beacon-send.tentative.window.js": [
+     "8c6e826af5b578b5893babb5e0ee90e37b37cc09",
+     [
+      "unload-beacon/pending_get_beacon-send.tentative.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/common/utils.js"
+        ],
+        [
+         "script",
+         "./resources/pending_beacon-helper.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "pending_post_beacon-cors.tentative.https.window.js": [
+     "01511d22c1b7bc58cfd86ca3725b0514f292d058",
+     [
+      "unload-beacon/pending_post_beacon-cors.tentative.https.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/common/get-host-info.sub.js"
+        ],
+        [
+         "script",
+         "/common/utils.js"
+        ],
+        [
+         "script",
+         "./resources/pending_beacon-helper.js"
+        ]
+       ]
+      }
+     ]
+    ],
+    "pending_post_beacon-sendwithdata.tentative.window.js": [
+     "77e91479e8b990b2b8240dc3fd6853e4d25ab980",
+     [
+      "unload-beacon/pending_post_beacon-sendwithdata.tentative.window.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/common/utils.js"
+        ],
+        [
+         "script",
+         "./resources/pending_beacon-helper.js"
+        ]
+       ]
+      }
+     ]
+    ]
+   },
    "upgrade-insecure-requests": {
     "gen": {
      "iframe-blank-inherit.meta": {
@@ -574905,7 +576852,7 @@
      ]
     ],
     "videoFrame-copyTo.any.js": [
-     "d2d04c57d32776796028d554714f84961b771682",
+     "79ba3c63043f1c949a7a37eaff072c0b1cf16d9e",
      [
       "webcodecs/videoFrame-copyTo.any.html",
       {
@@ -578578,7 +580525,7 @@
      ]
     ],
     "supported-stats.html": [
-     "f59f5d8e8f95244aac767660fe8c141c048bd874",
+     "22b514e77a9cd70e59cfebc910c0b2eb42a1b01f",
      [
       null,
       {
@@ -611561,6 +613508,22 @@
        {}
       ]
      ],
+     "flexbox": {
+      "image-in-fragmented-flexbox-crash-001.html": [
+       "3c8a6c52944da437e1d8a0b5e6cf35b766f2c1c0",
+       [
+        null,
+        {}
+       ]
+      ],
+      "image-in-fragmented-flexbox-crash-002.html": [
+       "a63c5be6c3e8910bc5bddb52e99bab54bfd1b385",
+       [
+        null,
+        {}
+       ]
+      ]
+     },
      "nested-fixedpos-in-inline-crash-000.html": [
       "8d1d395e35c8a40faf07d688e6e51d34bc35e88f",
       [
diff --git a/third_party/blink/web_tests/external/wpt/common/object-association.js b/third_party/blink/web_tests/external/wpt/common/object-association.js
index 458aae67..669c17c 100644
--- a/third_party/blink/web_tests/external/wpt/common/object-association.js
+++ b/third_party/blink/web_tests/external/wpt/common/object-association.js
@@ -1,19 +1,48 @@
 "use strict";
 
-// For now this only has per-Window tests, but we could expand it to also test per-Document
+// This is for testing whether an object (e.g., a global property) is associated with Window, or
+// with Document. Recall that Window and Document are 1:1 except when doing a same-origin navigation
+// away from the initial about:blank. In that case the Window object gets reused for the new
+// Document.
+//
+// So:
+// - If something is per-Window, then it should maintain its identity across an about:blank
+//   navigation.
+// - If something is per-Document, then it should be recreated across an about:blank navigation.
 
-/**
- * Run tests for window[propertyName] after discarding the browsing context, navigating, etc.
- * @param {string} propertyName
- */
 window.testIsPerWindow = propertyName => {
-  test(t => {
+  runTests(propertyName, assert_equals, "must not");
+};
+
+window.testIsPerDocument = propertyName => {
+  runTests(propertyName, assert_not_equals, "must");
+};
+
+function runTests(propertyName, equalityOrInequalityAsserter, mustOrMustNotReplace) {
+  async_test(t => {
     const iframe = document.createElement("iframe");
     document.body.appendChild(iframe);
     const frame = iframe.contentWindow;
 
     const before = frame[propertyName];
-    assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`);
+    assert_implements(before, `window.${propertyName} must be implemented`);
+
+    iframe.onload = t.step_func_done(() => {
+      const after = frame[propertyName];
+      equalityOrInequalityAsserter(after, before);
+    });
+
+    iframe.src = "/common/blank.html";
+  }, `Navigating from the initial about:blank ${mustOrMustNotReplace} replace window.${propertyName}`);
+
+  // Per spec, discarding a browsing context should not change any of the global objects.
+  test(() => {
+    const iframe = document.createElement("iframe");
+    document.body.appendChild(iframe);
+    const frame = iframe.contentWindow;
+
+    const before = frame[propertyName];
+    assert_implements(before, `window.${propertyName} must be implemented`);
 
     iframe.remove();
 
@@ -21,38 +50,15 @@
     assert_equals(after, before, `window.${propertyName} should not change after iframe.remove()`);
   }, `Discarding the browsing context must not change window.${propertyName}`);
 
-  async_test(t => {
-    const iframe = document.createElement("iframe");
-    document.body.appendChild(iframe);
-    const frame = iframe.contentWindow;
-
-    const before = frame[propertyName];
-    assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`);
-
-    // Note: cannot use step_func_done for this because it might be called twice, per the below comment.
-    iframe.onload = t.step_func(() => {
-      if (frame.location.href === "about:blank") {
-        // Browsers are not reliable on whether about:blank fires the load event; see
-        // https://github.com/whatwg/html/issues/490
-        return;
-      }
-
-      const after = frame[propertyName];
-      assert_equals(after, before);
-      t.done();
-    });
-
-    iframe.src = "/common/blank.html";
-  }, `Navigating from the initial about:blank must not replace window.${propertyName}`);
-
-  // Per spec, document.open() should not change any of the Window state.
+  // Per spec, document.open() should not change any of the global objects. In historical versions
+  // of the spec, it did, so we test here.
   async_test(t => {
     const iframe = document.createElement("iframe");
 
     iframe.onload = t.step_func_done(() => {
       const frame = iframe.contentWindow;
       const before = frame[propertyName];
-      assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`);
+      assert_implements(before, `window.${propertyName} must be implemented`);
 
       frame.document.open();
 
@@ -64,5 +70,5 @@
 
     iframe.src = "/common/blank.html";
     document.body.appendChild(iframe);
-  }, `document.open() must replace window.${propertyName}`);
-};
+  }, `document.open() must not replace window.${propertyName}`);
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-047.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-047.html
new file mode 100644
index 0000000..8ad8585
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-047.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html>
+	<head>
+		<title>CSS Test (Conditional Rules): In @supports, pseudo elements can be parsed successfully</title>
+		<link rel="author" title="Jan Nicklas" href="https://twitter.com/jantimon">
+		<link rel="help" href="http://www.w3.org/TR/css3-conditional/#at-supports">
+		<link rel="match" href="at-supports-001-ref.html">
+		<style>
+			div {
+				background:red;
+				height:100px;
+				width:100px;
+			}
+			@supports selector(input::placeholder) {
+				div { background-color:green; }
+			}
+		</style>
+	</head>
+	<body>
+		<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+		<div></div>
+	</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-005.html b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-005.html
new file mode 100644
index 0000000..c217a3b6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/alignment/grid-align-baseline-005.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#alignment">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="display: inline-grid; grid-template: auto / 50px 50px; align-items: baseline; background: red;">
+  <canvas style="background: green; width: 100%; height: 100%;"></canvas>
+  <div style="height: 100px; background: green;"><br></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-fixed-position.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-fixed-position.html
index 9ef49b6e..a9f278d8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-fixed-position.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-fixed-position.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
+<meta name=fuzzy content="0-10;0-150">
 <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#basic-shape-interpolation">
 <link rel="match" href="clip-path-animation-fixed-position-ref.html">
 <!--
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/parsing/hyphenate-limit-chars-computed.html b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/hyphenate-limit-chars-computed.html
new file mode 100644
index 0000000..cf18f25
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/hyphenate-limit-chars-computed.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>CSS Text: hyphenate-limit-chars with computed values</title>
+<link rel="help" href="https://w3c.github.io/csswg-drafts/css-text-4/#propdef-hyphenate-limit-chars">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<div id="target"></div>
+<script>
+test_computed_value("hyphenate-character", "auto");
+test_computed_value("hyphenate-limit-chars", "auto auto", "auto");
+test_computed_value("hyphenate-limit-chars", "auto auto auto", "auto");
+test_computed_value("hyphenate-limit-chars", "5");
+test_computed_value("hyphenate-limit-chars", "5 2");
+test_computed_value("hyphenate-limit-chars", "5 2 3");
+test_computed_value("hyphenate-limit-chars", "5 2 calc(3.1)", "5 2 3");
+test_computed_value("hyphenate-limit-chars", "auto 2");
+test_computed_value("hyphenate-limit-chars", "auto 2 auto", "auto 2");
+test_computed_value("hyphenate-limit-chars", "auto auto 2");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/parsing/hyphenate-limit-chars-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/hyphenate-limit-chars-invalid.html
new file mode 100644
index 0000000..5a797fa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/hyphenate-limit-chars-invalid.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>CSS Text: parsing hyphenate-limit-chars with invalid values</title>
+<link rel="help" href="https://w3c.github.io/csswg-drafts/css-text-4/#propdef-hyphenate-limit-chars">
+<meta name="assert" content="hyphenate-character supports only the grammar 'none | manual | auto'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+test_invalid_value("hyphenate-limit-chars", "normal");
+test_invalid_value("hyphenate-limit-chars", "1 normal");
+test_invalid_value("hyphenate-limit-chars", "none");
+test_invalid_value("hyphenate-limit-chars", "1 none");
+test_invalid_value("hyphenate-limit-chars", "1.2");
+test_invalid_value("hyphenate-limit-chars", "1 1.2");
+test_invalid_value("hyphenate-limit-chars", "1 2 1.2");
+test_invalid_value("hyphenate-limit-chars", "1 2 3 4");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/parsing/hyphenate-limit-chars-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/hyphenate-limit-chars-valid.html
new file mode 100644
index 0000000..699ddd4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/hyphenate-limit-chars-valid.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>CSS Text: parsing hyphenate-limit-chars with valid values</title>
+<link rel="help" href="https://w3c.github.io/csswg-drafts/css-text-4/#propdef-hyphenate-limit-chars">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+test_valid_value("hyphenate-limit-chars", "auto");
+test_valid_value("hyphenate-limit-chars", "auto auto");
+test_valid_value("hyphenate-limit-chars", "auto auto auto");
+test_valid_value("hyphenate-limit-chars", "5");
+test_valid_value("hyphenate-limit-chars", "5 2");
+test_valid_value("hyphenate-limit-chars", "5 2 3");
+test_valid_value("hyphenate-limit-chars", "auto 2");
+test_valid_value("hyphenate-limit-chars", "auto 2 auto");
+test_valid_value("hyphenate-limit-chars", "auto auto 2");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-001.html
index 0218b47f..f13a494 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-001.html
@@ -1,25 +1,25 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, direction: rtl</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-.rb1 { top: 0; left: 0; height: 48px;  }
-.rb2 { top: 0; left: 109px; height: 48px; }
-.rb3 { top: 0; left: 218px; height: 48px; }
-.rb4 { top: 0; left: 327px; height: 72px; }
-.rb5 { top: 48px; right: 96px; height: 24px; }
-.rb6 { top: 48px; right: 192px; height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is the same.</div>
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: right;">REF REF REF</div>
+</div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: right;">REF REF REF</div>
+</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-002.html
index 02e1f234..63206ff 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-002.html
@@ -1,27 +1,27 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, direction: ltr</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-.rb1 { top: 0; right: 0; height: 48px;  }
-.rb2 { top: 0; right: 109px; height: 48px; }
-.rb3 { top: 0; right: 218px; height: 48px; }
-.rb4 { top: 0; right: 327px; height: 72px; }
-.rb5 { top: 48px; left: 96px; height: 24px; }
-.rb6 { top: 48px; left: 192px; height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
 <div style="direction: rtl;">
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: left;">REF REF REF</div>
+</div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: left;">REF REF REF</div>
+</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-003.html
index b869ef9..9437b4fa 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-003.html
@@ -1,25 +1,25 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, dir=rtl</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-.rb1 { top: 0; left: 0; height: 48px;  }
-.rb2 { top: 0; left: 109px; height: 48px; }
-.rb3 { top: 0; left: 218px; height: 48px; }
-.rb4 { top: 0; left: 327px; height: 72px; }
-.rb5 { top: 48px; right: 96px; height: 24px; }
-.rb6 { top: 48px; right: 192px; height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is the same.</div>
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: right;">REF REF REF</div>
+</div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: right;">REF REF REF</div>
+</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-004.html
index 006bea1..fe2bbe8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-004.html
@@ -1,27 +1,27 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, dir=ltr</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-.rb1 { top: 0; right: 0; height: 48px;  }
-.rb2 { top: 0; right: 109px; height: 48px; }
-.rb3 { top: 0; right: 218px; height: 48px; }
-.rb4 { top: 0; right: 327px; height: 72px; }
-.rb5 { top: 48px; left: 96px; height: 24px; }
-.rb6 { top: 48px; left: 192px; height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: left;">REF REF REF</div>
+</div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: left;">REF REF REF</div>
+</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-005.html
index 3de1f09..bb383de0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-005.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-005.html
@@ -1,25 +1,25 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, dir=auto, RTL first strong</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-.rb1 { top: 0; left: 0; height: 48px;  }
-.rb2 { top: 0; left: 109px; height: 48px; }
-.rb3 { top: 0; left: 218px; height: 48px; }
-.rb4 { top: 0; left: 327px; height: 72px; }
-.rb5 { top: 48px; right: 96px; height: 24px; }
-.rb6 { top: 48px; right: 192px; height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is the same.</div>
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: right;">REF REF REF</div>
+</div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: right;">REF REF REF</div>
+</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-006.html
index 0553118..cead2a2 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-006.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-justify-ref-006.html
@@ -1,27 +1,27 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, dir=auto, LTR first strong</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-.rb1 { top: 0; right: 0; height: 48px;  }
-.rb2 { top: 0; right: 109px; height: 48px; }
-.rb3 { top: 0; right: 218px; height: 48px; }
-.rb4 { top: 0; right: 327px; height: 72px; }
-.rb5 { top: 48px; left: 96px; height: 24px; }
-.rb6 { top: 48px; left: 192px; height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is the same.</div>
 <div dir="rtl">
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
-<div class="ref"><div class="rb rb1"></div><div class="rb rb2"></div><div class="rb rb3"></div><div class="rb rb4"></div><div class="rb rb5"></div><div class="rb rb6"></div></div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: left;">REF REF REF</div>
+</div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: left;">REF REF REF</div>
+</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-001.html
index 72e11fae..5d14b176 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-001.html
@@ -1,21 +1,17 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, direction: rtl</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; direction: rtl; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 300px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 24px; }
-#rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 120px;  height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes looks the same.</div>
-<div class="ref"><div id="rb1"></div></div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="ref">REFER</div>
+<div class="ref">REFER</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-002.html
index a30dc62..fc54ede6c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-002.html
@@ -1,23 +1,19 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, direction: ltr</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; direction: ltr; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 300px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 24px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 120px;  height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes looks the same.</div>
 <div style="direction: rtl;">
-<div class="ref"><div id="rb1"></div></div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="ref">REFER</div>
+<div class="ref">REFER</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-003.html
index 8393996..fa5e76a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-003.html
@@ -1,21 +1,17 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=rtl</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 300px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 24px; }
-#rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 120px;  height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
-<div class="ref"><div id="rb1"></div></div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="ref">REFER</div>
+<div class="ref">REFER</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-004.html
index 4ec0fde..1deee0c7 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-004.html
@@ -1,23 +1,19 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=ltr</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 300px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 24px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 120px;  height: 24px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<div class="ref"><div id="rb1"></div></div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="ref">REFER</div>
+<div class="ref">REFER</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-005.html
index 70a8d53d..701845e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-005.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-005.html
@@ -1,23 +1,17 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, direction: rtl</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; direction: rtl; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-.rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 72px;  height: 72px; }
-.rb2 { position: absolute; top: 0; right: 96px; background-color: orange; width: 72px;  height: 72px; }
-.rb3 { position: absolute; top: 0; right: 192px; background-color: orange; width: 72px;  height: 48px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes looks the same.</div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-006.html
index affc904..914df465 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-006.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-006.html
@@ -1,25 +1,19 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, direction: ltr</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; direction: ltr; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-.rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 72px; }
-.rb2 { position: absolute; top: 0; left: 96px; background-color: orange; width: 72px;  height: 72px; }
-.rb3 { position: absolute; top: 0; left: 192px; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
 <div style="direction: rtl;">
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-007.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-007.html
index de8d879..62cca9b9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-007.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-007.html
@@ -1,23 +1,17 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=rtl</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-.rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 72px;  height: 72px; }
-.rb2 { position: absolute; top: 0; right: 96px; background-color: orange; width: 72px;  height: 72px; }
-.rb3 { position: absolute; top: 0; right: 192px; background-color: orange; width: 72px;  height: 48px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: right;}
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes looks the same.</div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-008.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-008.html
index 8c81603..1b09404b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-008.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-008.html
@@ -1,25 +1,19 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=ltr</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-.rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 72px; }
-.rb2 { position: absolute; top: 0; left: 96px; background-color: orange; width: 72px;  height: 72px; }
-.rb3 { position: absolute; top: 0; left: 192px; background-color: orange; width: 72px;  height: 48px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-009.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-009.html
index f3c0cc74..0cfe79e6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-009.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-009.html
@@ -1,23 +1,17 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=auto, RTL first strong</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-.rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 72px;  height: 72px; }
-.rb2 { position: absolute; top: 0; right: 96px; background-color: orange; width: 72px;  height: 72px; }
-.rb3 { position: absolute; top: 0; right: 192px; background-color: orange; width: 72px;  height: 48px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-010.html
index 3014c05..727fb65 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-010.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-010.html
@@ -1,25 +1,19 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=auto, LTR first strong</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-.rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 72px; }
-.rb2 { position: absolute; top: 0; left: 96px; background-color: orange; width: 72px;  height: 72px; }
-.rb3 { position: absolute; top: 0; left: 192px; background-color: orange; width: 72px;  height: 48px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div><div class="rb3"></div></div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-014.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-014.html
index 703ffe3..8113fe2 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-014.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-014.html
@@ -1,23 +1,19 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, pre, dir=rtl inherited</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 48px; }
-#rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 72px;  height: 48px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<div class="ref"><div id="rb1"></div></div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="ref">REF<br>ERE</div>
+<div class="ref">REF<br>ERE</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-015.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-015.html
index 814c76f..d61b2585 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-015.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-015.html
@@ -1,23 +1,19 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, pre, dir=ltr inherited</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 48px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 48px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
 <div dir="ltr">
-<div class="ref"><div id="rb1"></div></div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="ref">REF<br>ERE</div>
+<div class="ref">REF<br>ERE</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-016.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-016.html
index 8253f594..3df6be40 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-016.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-016.html
@@ -1,22 +1,21 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, pre, dir=auto</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 48px; }
-.rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 24px; }
-.rb2 { position: absolute; bottom: 0; right: 0; background-color: orange; width: 72px;  height: 24px; }
+.ref1, .ref2 { border-left: 1px solid orange; border-right: 1px solid orange; margin-left: 20px; margin-right: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref1 { border-top: 1px solid orange; margin-top: 20px; text-align: left; }
+.ref2 { border-bottom: 1px solid orange; margin-bottom: 20px; text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div></div>
-<div class="ref"><div class="rb1"></div><div class="rb2"></div></div>
+<div class="ref1">REF</div>
+<div class="ref2">ERE</div>
+<div class="ref1">REF</div>
+<div class="ref2">ERE</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-017.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-017.html
index e8ad011..89b5c40 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-017.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/reference/text-align-start-ref-017.html
@@ -1,21 +1,17 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, pre, dir=auto on surrounding block</title>
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
-.test { text-align: start; }
-/* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 48px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 48px; }
+.ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
-<div class="ref"><div id="rb1"></div></div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="ref">REF<br>ERE</div>
+<div class="ref">REF<br>ERE</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-001.html
index f2ba8cc2..9e1319e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-001.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, direction: rtl</title>
@@ -7,24 +7,20 @@
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <meta name="assert" content="text-align:justify aligns text in order to exactly fill the line box. Unless otherwise specified by text-align-last, the last line before a forced break or the end of the block is start-aligned – in this case, to the right.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: justify; direction: rtl; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-#rb1 { top: 0; left: 0; height: 48px;  }
-#rb2 { top: 0; left: 109px; height: 48px; }
-#rb3 { top: 0; left: 218px; height: 48px; }
-#rb4 { top: 0; left: 327px; height: 72px; }
-#rb5 { top: 48px; right: 96px; height: 24px; }
-#rb6 { top: 48px; right: 192px; height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is the same.</div>
-<div class="test">XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX </div>
-<div class="ref"><div class="rb" id="rb1"></div><div class="rb" id="rb2"></div><div class="rb" id="rb3"></div><div class="rb" id="rb4"></div><div class="rb" id="rb5"></div><div class="rb" id="rb6"></div></div>
+<div class="test">TES TES TES TES TES TES TES TES TES TES TES </div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: right;">REF REF REF</div>
+</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-002.html
index 3f91b6d..250f680 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-002.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, direction: ltr</title>
@@ -7,26 +7,22 @@
 <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <meta name="assert" content="text-align:justify aligns text in order to exactly fill the line box. Unless otherwise specified by text-align-last, the last line before a forced break or the end of the block is start-aligned – in this case, to the left.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: justify; direction: ltr; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-#rb1 { top: 0; right: 0; height: 48px;  }
-#rb2 { top: 0; right: 109px; height: 48px; }
-#rb3 { top: 0; right: 218px; height: 48px; }
-#rb4 { top: 0; right: 327px; height: 72px; }
-#rb5 { top: 48px; left: 96px; height: 24px; }
-#rb6 { top: 48px; left: 192px; height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
 <div style="direction: rtl;">
-<div class="test">XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX </div>
-<div class="ref"><div class="rb" id="rb1"></div><div class="rb" id="rb2"></div><div class="rb" id="rb3"></div><div class="rb" id="rb4"></div><div class="rb" id="rb5"></div><div class="rb" id="rb6"></div></div>
+<div class="test">TES TES TES TES TES TES TES TES TES TES TES </div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: left;">REF REF REF</div>
+</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-003.html
index 73d0b2f..b08cd88e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-003.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, dir=rtl</title>
@@ -7,24 +7,20 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-justify-ref-003.html'>
 <meta name="assert" content="text-align:justify aligns text in order to exactly fill the line box. Unless otherwise specified by text-align-last, the last line before a forced break or the end of the block is start-aligned – in this case, to the right.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: justify; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-#rb1 { top: 0; left: 0; height: 48px;  }
-#rb2 { top: 0; left: 109px; height: 48px; }
-#rb3 { top: 0; left: 218px; height: 48px; }
-#rb4 { top: 0; left: 327px; height: 72px; }
-#rb5 { top: 48px; right: 96px; height: 24px; }
-#rb6 { top: 48px; right: 192px; height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is the same.</div>
-<div class="test" dir="rtl">XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX </div>
-<div class="ref"><div class="rb" id="rb1"></div><div class="rb" id="rb2"></div><div class="rb" id="rb3"></div><div class="rb" id="rb4"></div><div class="rb" id="rb5"></div><div class="rb" id="rb6"></div></div>
+<div class="test" dir="rtl">TES TES TES TES TES TES TES TES TES TES TES </div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: right;">REF REF REF</div>
+</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-004.html
index f8621ee..20ca4fe 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-004.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, dir=ltr</title>
@@ -7,26 +7,22 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-justify-ref-004.html'>
 <meta name="assert" content="text-align:justify aligns text in order to exactly fill the line box. Unless otherwise specified by text-align-last, the last line before a forced break or the end of the block is start-aligned – in this case, to the left.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: justify; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-#rb1 { top: 0; right: 0; height: 48px;  }
-#rb2 { top: 0; right: 109px; height: 48px; }
-#rb3 { top: 0; right: 218px; height: 48px; }
-#rb4 { top: 0; right: 327px; height: 72px; }
-#rb5 { top: 48px; left: 96px; height: 24px; }
-#rb6 { top: 48px; left: 192px; height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<div class="test" dir="ltr">XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX </div>
-<div class="ref"><div class="rb" id="rb1"></div><div class="rb" id="rb2"></div><div class="rb" id="rb3"></div><div class="rb" id="rb4"></div><div class="rb" id="rb5"></div><div class="rb" id="rb6"></div></div>
+<div class="test" dir="ltr">TES TES TES TES TES TES TES TES TES TES TES </div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: left;">REF REF REF</div>
+</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-005.html
index 5723776..851e1a0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-005.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-005.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, dir=auto, RTL first strong</title>
@@ -7,24 +7,20 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-justify-ref-005.html'>
 <meta name="assert" content="text-align:justify aligns text in order to exactly fill the line box. Unless otherwise specified by text-align-last, the last line before a forced break or the end of the block is start-aligned – in this case, to the right.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: justify; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-#rb1 { top: 0; left: 0; height: 48px;  }
-#rb2 { top: 0; left: 109px; height: 48px; }
-#rb3 { top: 0; left: 218px; height: 48px; }
-#rb4 { top: 0; left: 327px; height: 72px; }
-#rb5 { top: 48px; right: 96px; height: 24px; }
-#rb6 { top: 48px; right: 192px; height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is the same.</div>
-<div dir="auto" class="test">&rlm;XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX</div>
-<div class="ref"><div class="rb" id="rb1"></div><div class="rb" id="rb2"></div><div class="rb" id="rb3"></div><div class="rb" id="rb4"></div><div class="rb" id="rb5"></div><div class="rb" id="rb6"></div></div>
+<div dir="auto" class="test">&rlm;TES TES TES TES TES TES TES TES TES TES TES</div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: right;">REF REF REF</div>
+</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-006.html
index 2a927921..d02fa47 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-006.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-justify-006.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: justify, dir=auto, LTR first strong</title>
@@ -7,26 +7,22 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-justify-ref-006.html'>
 <meta name="assert" content="text-align:justify aligns text in order to exactly fill the line box. Unless otherwise specified by text-align-last, the last line before a forced break or the end of the block is start-aligned – in this case, to the left.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: justify; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 399px; color: orange; font: 24px/24px Ahem; }
-.ref { text-align: right; position: relative; height:72px;  }
-.rb { position: absolute;  background-color: orange;  width: 72px; }
-#rb1 { top: 0; right: 0; height: 48px;  }
-#rb2 { top: 0; right: 109px; height: 48px; }
-#rb3 { top: 0; right: 218px; height: 48px; }
-#rb4 { top: 0; right: 327px; height: 72px; }
-#rb5 { top: 48px; left: 96px; height: 24px; }
-#rb6 { top: 48px; left: 192px; height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 450px; color: orange; font: 25px/1 Ahem; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is the same.</div>
 <div dir="rtl">
-<div dir="auto" class="test">XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX</div>
-<div class="ref"><div class="rb" id="rb1"></div><div class="rb" id="rb2"></div><div class="rb" id="rb3"></div><div class="rb" id="rb4"></div><div class="rb" id="rb5"></div><div class="rb" id="rb6"></div></div>
+<div dir="auto" class="test">TES TES TES TES TES TES TES TES TES TES TES</div>
+<div class="ref">
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="word-spacing: 1em;">REF REF REF REF</div>
+<div style="text-align: left;">REF REF REF</div>
+</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-001.html
index 43219cc..3af1130f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-001.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, direction: rtl</title>
@@ -7,18 +7,17 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-001.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. right when direction is horizontal, rtl.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; direction: rtl; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 300px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 24px; }
-#rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 120px;  height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes looks the same.</div>
-<div class="test">XXXXX</div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="test">TESTI</div>
+<div class="ref">REFER</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-002.html
index 911a185..27aad6f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-002.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, direction: ltr</title>
@@ -7,20 +7,19 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-002.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. left when direction is horizontal, ltr.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; direction: ltr; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 300px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 24px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 120px;  height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes looks the same.</div>
 <div style="direction: rtl;">
-<div class="test">XXXXX</div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="test">TESTI</div>
+<div class="ref">REFER</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-003.html
index 0ca38da..9a007f0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-003.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=rtl</title>
@@ -7,18 +7,17 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-003.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. right when direction is horizontal, rtl.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 300px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 24px; }
-#rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 120px;  height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
-<div class="test" dir="rtl">XXXXX</div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="test" dir="rtl">TESTI</div>
+<div class="ref">REFER</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-004.html
index 739bd88..b1e01e3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-004.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=ltr</title>
@@ -7,20 +7,19 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-004.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. left when direction is horizontal, ltr.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 300px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 24px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 120px;  height: 24px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<div class="test" dir="ltr">XXXXX</div>
-<div class="ref"><div id="rb1"></div></div>
+<div class="test" dir="ltr">TESTI</div>
+<div class="ref">REFER</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-005.html
index 5dbe17d..37c61154 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-005.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-005.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, direction: rtl</title>
@@ -7,20 +7,17 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-005.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. right when direction is horizontal, rtl.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; direction: rtl; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-#rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 72px;  height: 72px; }
-#rb2 { position: absolute; top: 0; right: 96px; background-color: orange; width: 72px;  height: 72px; }
-#rb3 { position: absolute; top: 0; right: 192px; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes looks the same.</div>
-<div class="test">XXX XXX XXX XXX XXX XXX XXX XXX</div>
-<div class="ref"><div id="rb1"></div><div id="rb2"></div><div id="rb3"></div></div>
+<div class="test">TES TES TES TES TES TES TES TES</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-006.html
index 8557affe..b55c7cb7 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-006.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-006.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, direction: ltr</title>
@@ -7,22 +7,19 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-006.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. left when direction is horizontal, ltr.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; direction: ltr; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 72px; }
-#rb2 { position: absolute; top: 0; left: 96px; background-color: orange; width: 72px;  height: 72px; }
-#rb3 { position: absolute; top: 0; left: 192px; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes is identical.</div>
 <div style="direction: rtl;">
-<div class="test">XXX XXX XXX XXX XXX XXX XXX XXX</div>
-<div class="ref"><div id="rb1"></div><div id="rb2"></div><div id="rb3"></div></div>
+<div class="test">TES TES TES TES TES TES TES TES</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-007.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-007.html
index 1a56287c..f79c109 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-007.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-007.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=rtl</title>
@@ -7,20 +7,17 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-007.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. right when direction is horizontal, rtl.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-#rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 72px;  height: 72px; }
-#rb2 { position: absolute; top: 0; right: 96px; background-color: orange; width: 72px;  height: 72px; }
-#rb3 { position: absolute; top: 0; right: 192px; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if the shading in both orange boxes looks the same.</div>
-<div class="test" dir="rtl">XXX XXX XXX XXX XXX XXX XXX XXX</div>
-<div class="ref"><div id="rb1"></div><div id="rb2"></div><div id="rb3"></div></div>
+<div class="test" dir="rtl">TES TES TES TES TES TES TES TES</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-008.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-008.html
index 3885c4db..81ff886 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-008.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-008.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=ltr</title>
@@ -7,22 +7,19 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-008.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. left when direction is horizontal, ltr.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 72px; }
-#rb2 { position: absolute; top: 0; left: 96px; background-color: orange; width: 72px;  height: 72px; }
-#rb3 { position: absolute; top: 0; left: 192px; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<div class="test" dir="ltr">XXX XXX XXX XXX XXX XXX XXX XXX</div>
-<div class="ref"><div id="rb1"></div><div id="rb2"></div><div id="rb3"></div></div>
+<div class="test" dir="ltr">TES TES TES TES TES TES TES TES</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-009.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-009.html
index 044c896a..bf231c5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-009.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-009.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=auto, RTL first strong</title>
@@ -7,23 +7,20 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-009.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. right when direction is auto and first strong character is rtl.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-#rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 72px;  height: 72px; }
-#rb2 { position: absolute; top: 0; right: 96px; background-color: orange; width: 72px;  height: 72px; }
-#rb3 { position: absolute; top: 0; right: 192px; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
-<div class="test" dir="auto">&rlm;XXX XXX XXX XXX XXX XXX XXX XXX</div>
-<div class="ref"><div id="rb1"></div><div id="rb2"></div><div id="rb3"></div></div>
+<div class="test" dir="auto">&rlm;TES TES TES TES TES TES TES TES</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 <!-- Notes:
 The &rlm isn't in the Ahem font, so it may cause a spurious effect, such as a thin white line in the middle of a block in IE. This should be ignored. The test needs a RTL character in the Ahem font, so that the &RLM can be removed.
 -->
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-010.html
index 358fc37..215e60b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-010.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-010.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, dir=auto, LTR first strong</title>
@@ -7,22 +7,19 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-010.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. left when direction is auto and first strong character is ltr.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 72px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 72px; }
-#rb2 { position: absolute; top: 0; left: 96px; background-color: orange; width: 72px;  height: 72px; }
-#rb3 { position: absolute; top: 0; left: 192px; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<div class="test" dir="auto">XXX XXX XXX XXX XXX XXX XXX XXX</div>
-<div class="ref"><div id="rb1"></div><div id="rb2"></div><div id="rb3"></div></div>
+<div class="test" dir="auto">TES TES TES TES TES TES TES TES</div>
+<div class="ref">REF REF REF REF REF REF REF REF</div>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-014.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-014.html
index 04a2bf5..add058c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-014.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-014.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, pre, dir=rtl inherited</title>
@@ -7,24 +7,23 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-014.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. right when base direction is rtl.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 48px; }
-#rb1 { position: absolute; top: 0; right: 0; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
 <div dir="rtl">
-<pre class="test">XXX
-&rlm;XXX</pre>
-<div class="ref"><div id="rb1"></div></div>
+<pre class="test">TES
+&rlm;TIN</pre>
+<div class="ref">REF<br>ERE</div>
 </div>
 <!-- Notes:
 The &rlm isn't in the Ahem font, so it may cause a spurious effect, such as a thin white line in the middle of a block in IE. This should be ignored. The test needs a RTL character in the Ahem font, so that the &RLM can be removed.
 -->
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-015.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-015.html
index ba41e61..b8432da 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-015.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-015.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, pre, dir=ltr inherited</title>
@@ -7,24 +7,23 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-015.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. left when base  direction is  ltr.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 48px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
 <div dir="ltr">
-<pre class="test">XXX
-&rlm;XXX</pre>
-<div class="ref"><div id="rb1"></div></div>
+<pre class="test">TES
+&rlm;TIN</pre>
+<div class="ref">REF<br>ERE</div>
 </div>
 <!-- Notes:
 The &rlm isn't in the Ahem font, so it may cause a spurious effect, such as a thin white line in the middle of a block in IE. This should be ignored. The test needs a RTL character in the Ahem font, so that the &RLM can be removed.
 -->
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-016.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-016.html
index c45667b5..ab9bc30 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-016.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-016.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, pre, dir=auto</title>
@@ -7,23 +7,25 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-016.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. left when direction is auto and first strong character is ltr, and right when first strong is rtl.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 48px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 24px; }
-#rb2 { position: absolute; bottom: 0; right: 0; background-color: orange; width: 72px;  height: 24px; }
+.test, .ref1, .ref2 { width: 300px; color: orange; font: 25px/1 Ahem; }
+.test { border: 1px solid orange; margin: 20px; }
+.ref1, .ref2 { border-left: 1px solid orange; border-right: 1px solid orange; margin: 0 20px; }
+.ref1 { border-top: 1px solid orange; text-align: left; }
+.ref2 { border-bottom: 1px solid orange; text-align: right; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
-<pre class="test" dir="auto">XXX
-&rlm;XXX</pre>
-<div class="ref"><div id="rb1"></div><div id="rb2"></div></div>
+<pre class="test" dir="auto">TES
+&rlm;TIN</pre>
+<div class="ref1">REF</div>
+<div class="ref2">ERE</div>
 <!-- Notes:
 The &rlm isn't in the Ahem font, so it may cause a spurious effect, such as a thin white line in the middle of a block in IE. This should be ignored. The test needs a RTL character in the Ahem font, so that the &RLM can be removed.
 -->
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-017.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-017.html
index 55273f89..554adb8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-017.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-align/text-align-start-017.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html  lang="en" >
+<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>text-align: start, pre, dir=auto on surrounding block</title>
@@ -7,21 +7,20 @@
 <link rel='help' href='https://drafts.csswg.org/css-text-3/#text-align-property'>
 <link rel='match' href='reference/text-align-start-ref-017.html'>
 <meta name="assert" content="text-align:start aligns inline-level content to the start edge of the line box – ie. since dir=auto is not inherited by pre, to left in ltr context.">
-<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
 <style type='text/css'>
 .test { text-align: start; }
 /* the CSS below is not part of the test */
-.test, .ref { border: 1px solid orange;  margin: 20px; width: 290px; color: orange; font: 24px/24px Ahem; }
-.ref { position: relative;  height: 48px; }
-#rb1 { position: absolute; top: 0; left: 0; background-color: orange; width: 72px;  height: 48px; }
+.test, .ref { border: 1px solid orange; margin: 20px; width: 300px; color: orange; font: 25px/1 Ahem; }
+.ref { text-align: left; }
 </style>
 </head>
 <body>
 <div id='instructions'>Test passes if shading in both orange boxes is identical.</div>
 <div dir="auto">
-<pre class="test">XXX
-&rlm;XXX</pre>
-<div class="ref"><div id="rb1"></div></div>
+<pre class="test">TES
+&rlm;TIN</pre>
+<div class="ref">REF<br>ERE</div>
 </div>
 <!-- Notes:
 The &rlm isn't in the Ahem font, so it may cause a spurious effect, such as a thin white line in the middle of a block in IE. This should be ignored. The test needs a RTL character in the Ahem font, so that the &RLM can be removed.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-toggle/toggle-visibility-z-ordering-001.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-toggle/toggle-visibility-z-ordering-001.tentative.html
new file mode 100644
index 0000000..50f5d35
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-toggle/toggle-visibility-z-ordering-001.tentative.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: toggle-visibility</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-visibility-property">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+
+body {
+  toggle-root: inactive-toggle 1 at 0;
+}
+
+#container {
+  toggle-visibility: toggle inactive-toggle;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+
+#child, #sibling {
+  height: 100px;
+  width: 100px;
+  background: red;
+}
+
+#sibling {
+  margin-top: -100px;
+}
+
+</style>
+
+<body>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div id="container">
+  <div id="child"></div>
+</div>
+<div id="sibling"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-toggle/toggle-visibility-z-ordering-002.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-toggle/toggle-visibility-z-ordering-002.tentative.html
new file mode 100644
index 0000000..cc1ecb2a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-toggle/toggle-visibility-z-ordering-002.tentative.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: toggle-visibility</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-visibility-property">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+
+body {
+  toggle-root: active-toggle 1 at 1;
+}
+
+#container {
+  toggle-visibility: toggle active-toggle;
+  background: red;
+  width: 100px;
+  height: 100px;
+}
+
+#child, #sibling {
+  height: 100px;
+  width: 100px;
+}
+
+#child {
+  background: green;
+}
+
+#sibling {
+  background: red;
+  margin-top: -100px;
+}
+
+</style>
+
+<body>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div id="container">
+  <div id="child"></div>
+</div>
+<div id="sibling"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-toggle/toggle-visibility.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-toggle/toggle-visibility.tentative.html
new file mode 100644
index 0000000..0a720fd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-toggle/toggle-visibility.tentative.html
@@ -0,0 +1,267 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>CSS Toggles: toggle-visibility</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://tabatkins.github.io/css-toggle/#toggle-visibility-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/toggle-helpers.js"></script>
+<style id="style">
+
+</style>
+
+<body>
+
+<div id="container"></div>
+<script>
+
+let style = document.getElementById("style");
+let container = document.getElementById("container");
+
+promise_test(async function() {
+  style.innerText = `
+    #container { toggle-group: t self; }
+    #t, #t2 { toggle-root: t 1 at 0 group; }
+    #trigger, #t2 { toggle-trigger: t; }
+    #vis { toggle-visibility: toggle t; }
+    #child { height: 100px; }
+  `;
+  container.innerHTML = `
+    <div id="t"></div>
+    <div id="vis">
+      <div id="child"></div>
+    </div>
+    <div id="trigger"></div>
+    <div id="t2"></div>
+  `;
+
+  let t = document.getElementById("t");
+  let trigger = document.getElementById("trigger");
+  let t2 = document.getElementById("t2");
+  let vis = document.getElementById("vis");
+
+  await wait_for_toggle_creation(t);
+
+  const kVisibleHeight = 100;
+  const kHiddenHeight = 0;
+
+  assert_equals(vis.clientHeight, kHiddenHeight, "before first click");
+  trigger.click();
+  assert_equals(vis.clientHeight, kVisibleHeight, "after first click");
+  trigger.click();
+  assert_equals(vis.clientHeight, kHiddenHeight, "after second click");
+  t.toggles.get("t").value = 1;
+  assert_equals(vis.clientHeight, kVisibleHeight, "after toggle value setter");
+  t2.click();
+  assert_equals(vis.clientHeight, kHiddenHeight, "after click on other element in group");
+}, "showing and hiding in response to toggle changes");
+
+const action_tests = [
+  {
+    name: "focus",
+    markup: `<input type="checkbox" id="check">`,
+    action: () => {
+      document.getElementById("check").focus();
+    },
+  },
+  {
+    name: "scrollIntoView",
+    markup: `<input type="checkbox" id="check">`,
+    action: () => {
+      document.getElementById("check").scrollIntoView();
+    },
+  },
+];
+
+for (let test of action_tests) {
+  promise_test(async function() {
+    style.innerText = `
+      #container { toggle-group: tab self; }
+      #tab { toggle: tab 1 at 0 group; }
+      #panel { toggle-visibility: toggle tab; }
+    `;
+    container.innerHTML = `
+      <div id="tab">Tab</div>
+      <div id="panel">
+        ${test.markup}
+      </div>
+    `;
+
+    let tab = document.getElementById("tab");
+    let panel = document.getElementById("panel");
+
+    await wait_for_toggle_creation(tab);
+
+    let tab_toggle = tab.toggles.get("tab");
+
+    assert_equals(tab_toggle.value, 0, "toggle value before focus");
+    assert_equals(panel.clientHeight, 0, "panel height before focus");
+
+    test.action();
+
+    assert_equals(tab_toggle.value, 1, "toggle value after focus");
+    assert_not_equals(panel.clientHeight, 0, "panel height after focus");
+  }, `${test.name} inside hidden element changes a toggle to show it`);
+}
+
+const scope_tests = [
+  `
+    <div class="root-inactive">
+      <div class="vis expect-hidden"></div>
+    </div>
+    <div class="vis expect-hidden"></div>
+  `,
+  `
+    <div class="root-inactive-self">
+      <div class="vis expect-hidden"></div>
+    </div>
+    <div class="vis expect-shown"></div>
+  `,
+  `
+    <div class="root-active">
+      <div class="vis expect-shown"></div>
+    </div>
+    <div class="vis expect-shown"></div>
+  `,
+  `
+    <div class="root-active-self">
+      <div class="vis expect-shown"></div>
+    </div>
+    <div class="vis expect-shown"></div>
+  `,
+];
+
+for (let test of scope_tests) {
+  promise_test(async function() {
+    container.innerHTML = test;
+    style.innerText = `
+      .root-inactive { toggle-root: t 1 at 0; }
+      .root-active { toggle-root: t 1 at 1; }
+      .root-inactive-self { toggle-root: t 1 at 0 self; }
+      .root-active-self { toggle-root: t 1 at 1 self; }
+
+      .vis {
+        toggle-visibility: toggle t;
+      }
+
+      .vis::before {
+        content: "";
+        display: block;
+        height: 100px;
+        width: 100px;
+      }
+    `;
+
+    await wait_for_toggle_creation(container.querySelector('[class^="root-"]'));
+
+    for (let e of container.querySelectorAll('.expect-hidden')) {
+      assert_equals(e.clientHeight, 0);
+    }
+    for (let e of container.querySelectorAll('.expect-shown')) {
+      assert_equals(e.clientHeight, 100);
+    }
+  }, `scope test: ${test}`);
+}
+
+async function wait_for_content_visibility_auto() {
+  return new Promise(resolve => {
+    requestAnimationFrame(() => {
+      requestAnimationFrame(resolve);
+    });
+  });
+}
+
+promise_test(async function() {
+  style.innerText = `
+    #t { toggle-root: t 1 at 0; }
+    #vis {
+      toggle-visibility: toggle t;
+      content-visibility: auto;
+      min-height: 50px;
+    }
+    #child { height: 100px; }
+    #spacer { height: 300vh; }
+  `;
+  // TODO (dbaron): Why doesn't padding-top on #container have the same effect
+  // as this spacer?
+  container.innerHTML = `
+    <div id="spacer"></div>
+    <div id="t"></div>
+    <div id="vis">
+      <div id="child"></div>
+    </div>
+  `;
+
+  let t = document.getElementById("t");
+  let vis = document.getElementById("vis");
+  let spacer = document.getElementById("spacer");
+
+  await wait_for_toggle_creation(t);
+
+  let toggle = t.toggles.get("t");
+
+  const kVisibleHeight = 100;
+  const kHiddenHeight = 50;
+
+  await wait_for_content_visibility_auto();
+  assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and offscreen");
+  toggle.value = 1;
+  await wait_for_content_visibility_auto();
+  assert_equals(vis.clientHeight, kHiddenHeight, "with toggle active and offscreen");
+  spacer.remove();
+  await wait_for_content_visibility_auto();
+  assert_equals(vis.clientHeight, kVisibleHeight, "with toggle active and onscreen");
+  toggle.value = 0;
+  await wait_for_content_visibility_auto();
+  assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and onscreen");
+  toggle.value = 1;
+  await wait_for_content_visibility_auto();
+  assert_equals(vis.clientHeight, kVisibleHeight, "with toggle active and onscreen (2)");
+  toggle.value = 0;
+  t.before(spacer);
+  await wait_for_content_visibility_auto();
+  assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and offscreen (2)");
+  spacer.remove();
+  await wait_for_content_visibility_auto();
+  assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and onscreen (2)");
+  toggle.value = 1;
+  await wait_for_content_visibility_auto();
+  assert_equals(vis.clientHeight, kVisibleHeight, "with toggle active and onscreen (3)");
+  t.before(spacer);
+  await wait_for_content_visibility_auto();
+  assert_equals(vis.clientHeight, kHiddenHeight, "with toggle active and offscreen (2)");
+}, "interaction of toggle-visibility and content-visibility: auto");
+
+promise_test(async function() {
+  style.innerText = `
+    #t { toggle-root: t 1 at 0; }
+    #vis {
+      toggle-visibility: toggle t;
+      content-visibility: hidden;
+    }
+    #child { height: 100px; }
+  `;
+  container.innerHTML = `
+    <div id="t"></div>
+    <div id="vis">
+      <div id="child"></div>
+    </div>
+  `;
+
+  let t = document.getElementById("t");
+  let vis = document.getElementById("vis");
+
+  await wait_for_toggle_creation(t);
+
+  let toggle = t.toggles.get("t");
+
+  const kVisibleHeight = 100;
+  const kHiddenHeight = 0;
+
+  assert_equals(vis.clientHeight, kHiddenHeight, "with toggle inactive and offscreen");
+  toggle.value = 1;
+  assert_equals(vis.clientHeight, kHiddenHeight, "with toggle active and offscreen");
+}, "interaction of toggle-visibility and content-visibility: hidden");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-003.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-003.html.ini
new file mode 100644
index 0000000..04214dc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-003.html.ini
@@ -0,0 +1,2 @@
+[available-size-003.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-005.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-005.html.ini
new file mode 100644
index 0000000..be1ab8b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-005.html.ini
@@ -0,0 +1,2 @@
+[available-size-005.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-013.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-013.html.ini
new file mode 100644
index 0000000..223729b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-013.html.ini
@@ -0,0 +1,2 @@
+[available-size-013.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-014.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-014.html.ini
new file mode 100644
index 0000000..ce213f4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/available-size-014.html.ini
@@ -0,0 +1,2 @@
+[available-size-014.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/direction-upright-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/direction-upright-001.html.ini
new file mode 100644
index 0000000..7e8be49
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/direction-upright-001.html.ini
@@ -0,0 +1,2 @@
+[direction-upright-001.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/direction-upright-002.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/direction-upright-002.html.ini
new file mode 100644
index 0000000..f603d89
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/direction-upright-002.html.ini
@@ -0,0 +1,2 @@
+[direction-upright-002.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/logical-physical-mapping-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/logical-physical-mapping-001.html.ini
new file mode 100644
index 0000000..7cfca9a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/logical-physical-mapping-001.html.ini
@@ -0,0 +1,2 @@
+[logical-physical-mapping-001.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/mongolian-orientation-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/mongolian-orientation-001.html.ini
new file mode 100644
index 0000000..2cc002053
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/mongolian-orientation-001.html.ini
@@ -0,0 +1,2 @@
+[mongolian-orientation-001.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/padding-percent-orthogonal-dynamic.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/padding-percent-orthogonal-dynamic.html.ini
new file mode 100644
index 0000000..6fd65e9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/padding-percent-orthogonal-dynamic.html.ini
@@ -0,0 +1,3 @@
+[padding-percent-orthogonal-dynamic.html]
+  [200px minus 100px padding based on #child height]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vlr-in-htb-008.xht.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vlr-in-htb-008.xht.ini
new file mode 100644
index 0000000..ffeaa24
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vlr-in-htb-008.xht.ini
@@ -0,0 +1,2 @@
+[sizing-orthog-vlr-in-htb-008.xht]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vlr-in-htb-020.xht.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vlr-in-htb-020.xht.ini
new file mode 100644
index 0000000..b16eb0ef
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vlr-in-htb-020.xht.ini
@@ -0,0 +1,2 @@
+[sizing-orthog-vlr-in-htb-020.xht]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-008.xht.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-008.xht.ini
new file mode 100644
index 0000000..240d3ff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-008.xht.ini
@@ -0,0 +1,2 @@
+[sizing-orthog-vrl-in-htb-008.xht]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-020.xht.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-020.xht.ini
new file mode 100644
index 0000000..f404fb5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-020.xht.ini
@@ -0,0 +1,2 @@
+[sizing-orthog-vrl-in-htb-020.xht]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/slr-alongside-vlr-floats.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/slr-alongside-vlr-floats.html.ini
new file mode 100644
index 0000000..9c80917
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/slr-alongside-vlr-floats.html.ini
@@ -0,0 +1,2 @@
+[slr-alongside-vlr-floats.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/srl-alongside-vrl-floats.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/srl-alongside-vrl-floats.html.ini
new file mode 100644
index 0000000..c7efce6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/srl-alongside-vrl-floats.html.ini
@@ -0,0 +1,2 @@
+[srl-alongside-vrl-floats.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vlr-003.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vlr-003.html.ini
new file mode 100644
index 0000000..1dbd0c6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vlr-003.html.ini
@@ -0,0 +1,2 @@
+[table-progression-vlr-003.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vlr-004.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vlr-004.html.ini
new file mode 100644
index 0000000..ce406436
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vlr-004.html.ini
@@ -0,0 +1,2 @@
+[table-progression-vlr-004.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vrl-003.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vrl-003.html.ini
new file mode 100644
index 0000000..057fcb2d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vrl-003.html.ini
@@ -0,0 +1,2 @@
+[table-progression-vrl-003.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vrl-004.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vrl-004.html.ini
new file mode 100644
index 0000000..3582aa84
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/table-progression-vrl-004.html.ini
@@ -0,0 +1,2 @@
+[table-progression-vrl-004.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-001.html.ini
new file mode 100644
index 0000000..3643a653
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-001.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-compression-001.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-002.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-002.html.ini
new file mode 100644
index 0000000..1c6816a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-002.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-compression-002.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-003.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-003.html.ini
new file mode 100644
index 0000000..9f669778
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-003.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-compression-003.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-004.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-004.html.ini
new file mode 100644
index 0000000..c0a87c3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-004.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-compression-004.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-005.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-005.html.ini
new file mode 100644
index 0000000..97ce1a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-005.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-compression-005.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-005a.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-005a.html.ini
new file mode 100644
index 0000000..b089a7d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-005a.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-compression-005a.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-006.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-006.html.ini
new file mode 100644
index 0000000..2198aee3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-006.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-compression-006.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-006a.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-006a.html.ini
new file mode 100644
index 0000000..5ec8b89
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-compression-006a.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-compression-006a.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-value-all-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-value-all-001.html.ini
new file mode 100644
index 0000000..fa41ee8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-value-all-001.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-value-all-001.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-value-all-002.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-value-all-002.html.ini
new file mode 100644
index 0000000..bba3a247
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-value-all-002.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-value-all-002.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-value-all-003.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-value-all-003.html.ini
new file mode 100644
index 0000000..4dfb332
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/text-combine-upright-value-all-003.html.ini
@@ -0,0 +1,2 @@
+[text-combine-upright-value-all-003.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-034.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-034.html.ini
new file mode 100644
index 0000000..3f9d15a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-034.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-034.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-035.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-035.html.ini
new file mode 100644
index 0000000..f1fd174
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-035.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-035.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-038.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-038.html.ini
new file mode 100644
index 0000000..3bcf05f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-038.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-038.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-039.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-039.html.ini
new file mode 100644
index 0000000..ac94de4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-039.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-039.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-042.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-042.html.ini
new file mode 100644
index 0000000..504189c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-042.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-042.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-043.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-043.html.ini
new file mode 100644
index 0000000..9d3d789
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-043.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-043.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-046.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-046.html.ini
new file mode 100644
index 0000000..5e129bf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-046.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-046.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-047.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-047.html.ini
new file mode 100644
index 0000000..04f054a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-047.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-047.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-048.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-048.html.ini
new file mode 100644
index 0000000..02c43f5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-048.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-048.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-049.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-049.html.ini
new file mode 100644
index 0000000..7e961b0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-049.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-049.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-050.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-050.html.ini
new file mode 100644
index 0000000..f8b2d8f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-050.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-050.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-051.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-051.html.ini
new file mode 100644
index 0000000..344e4903
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-051.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-051.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-052.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-052.html.ini
new file mode 100644
index 0000000..edb6fb7f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-052.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-052.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-053.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-053.html.ini
new file mode 100644
index 0000000..6c5be36
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-053.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-053.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-054.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-054.html.ini
new file mode 100644
index 0000000..dd7a8a0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-054.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-054.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-055.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-055.html.ini
new file mode 100644
index 0000000..e1baf0f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-055.html.ini
@@ -0,0 +1,2 @@
+[wm-propagation-body-055.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-scroll-offset-vertical-rl.html.ini b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-scroll-offset-vertical-rl.html.ini
new file mode 100644
index 0000000..0e9114c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/wm-propagation-body-scroll-offset-vertical-rl.html.ini
@@ -0,0 +1,3 @@
+[wm-propagation-body-scroll-offset-vertical-rl.html]
+  [Check initial scroll position of viewport.]
+    expected: [PASS, FAIL]
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt
index ed6c7d9..c4f7f27 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 PASS getComputedStyle returns no style for detached element
-FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) assert_equals: expected 0 but got 366
-FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) from iframe's window assert_equals: expected 0 but got 366
-FAIL getComputedStyle returns no style for element outside the flat tree assert_equals: expected 0 but got 366
-FAIL getComputedStyle returns no style for descendant outside the flat tree assert_equals: expected 0 but got 366
+FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) assert_equals: expected 0 but got 367
+FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) from iframe's window assert_equals: expected 0 but got 367
+FAIL getComputedStyle returns no style for element outside the flat tree assert_equals: expected 0 but got 367
+FAIL getComputedStyle returns no style for descendant outside the flat tree assert_equals: expected 0 but got 367
 PASS getComputedStyle returns no style for shadow tree outside of flattened tree
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-pseudo-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-pseudo-expected.txt
index 0fe62f5..b55571e7 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-pseudo-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/getComputedStyle-pseudo-expected.txt
@@ -7,6 +7,6 @@
 PASS Item-based blockification of nonexistent pseudo-elements
 PASS display: contents on pseudo-elements
 PASS Dynamically change to display: contents on pseudo-elements
-FAIL Unknown pseudo-elements assert_equals: Should return an empty style for unknown pseudo-elements starting with double-colon expected 0 but got 366
+FAIL Unknown pseudo-elements assert_equals: Should return an empty style for unknown pseudo-elements starting with double-colon expected 0 but got 367
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/custom-element-registry/per-global-expected.txt b/third_party/blink/web_tests/external/wpt/custom-elements/custom-element-registry/per-global-expected.txt
index b6ce8a3..99e8fe94 100644
--- a/third_party/blink/web_tests/external/wpt/custom-elements/custom-element-registry/per-global-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/custom-elements/custom-element-registry/per-global-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
-PASS Discarding the browsing context must not change window.customElements
 FAIL Navigating from the initial about:blank must not replace window.customElements assert_equals: expected object "[object CustomElementRegistry]" but got object "[object CustomElementRegistry]"
-PASS document.open() must replace window.customElements
+PASS Discarding the browsing context must not change window.customElements
+PASS document.open() must not replace window.customElements
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body.html
index e3be8dac..5574fe0a 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div.html
index 345e818..6fbf692 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <style>
   html, body {
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document.html
index acca8a6..7d07393c 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root.html
index 6009ec8..e85fbac 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window.html
index a1aa7b32..29b09f85 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body.html
index 7545b98..070cadc29 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div.html
index 8884e13..c49d18ac 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <style>
   html, body {
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document.html
index de6009ee..31a55cad 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root.html
index 562635a..b7bacbfc 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window.html
index 75ef3b3..c236059 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-body.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-body.html
index 24f7619..9db12cf 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-body.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-body.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-div.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-div.html
index b3a16e5fd..37367085 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-div.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-div.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <style>
   html, body {
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-document.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-document.html
index 9c0796e..7126228 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-document.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-document.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-root.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-root.html
index 20f1b985..fc641d1 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-root.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-root.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-window.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-window.html
index bed62cd8..f60955c7 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-window.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-window.html
@@ -7,7 +7,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-body.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-body.html
index 09873a9..fe0869b 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-body.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-body.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-div.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-div.html
index d29c573c..e2ca6e7 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-div.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-div.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <style>
   html, body {
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-document.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-document.html
index b080f833..61b716f 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-document.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-document.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-root.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-root.html
index f4e35a7..6b383bc 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-root.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-root.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-window.html b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-window.html
index eb2a6f3..a1e901f5 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-window.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-window.html
@@ -6,7 +6,6 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/wait-for.js"></script>
 <script src="resources/scrolling.js"></script>
 <div class=remove-on-cleanup style="height: 200vh"></div>
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/resources/scrolling.js b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/resources/scrolling.js
index 1d898d8..88e10f5 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/resources/scrolling.js
+++ b/third_party/blink/web_tests/external/wpt/dom/events/non-cancelable-when-passive/resources/scrolling.js
@@ -28,7 +28,7 @@
 
     await new test_driver.Actions()
       .scroll(pos_x, pos_y, delta_x, delta_y).send();
-    await waitFor(() => arrived);
+    await t.step_wait(() => arrived, `Didn't get event ${eventName} on ${target.localName}`);
     assert_equals(cancelable, expectCancelable);
   });
 }
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any-expected.txt
new file mode 100644
index 0000000..508142e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any-expected.txt
@@ -0,0 +1,20 @@
+This is a testharness.js-based test.
+PASS Fetching [GET] URL.createObjectURL(blob) is OK
+PASS Fetching [GET] blob:http://www.web-platform.test:8001/ is KO
+PASS Fetching [POST] URL.createObjectURL(blob) is KO
+PASS Fetching [OPTIONS] URL.createObjectURL(blob) is KO
+PASS Fetching [HEAD] URL.createObjectURL(blob) is KO
+PASS Fetching [PUT] URL.createObjectURL(blob) is KO
+PASS Fetching [DELETE] URL.createObjectURL(blob) is KO
+PASS Fetching [INVALID] URL.createObjectURL(blob) is KO
+PASS Fetching [GET] blob:not-backed-by-a-blob/ is KO
+FAIL Fetching URL.createObjectURL(empty_blob) is OK assert_equals: Content-Type is null expected (string) "" but got (object) null
+FAIL Fetching URL.createObjectURL(empty_type_blob) is OK assert_equals: Content-Type is null expected (string) "" but got (object) null
+PASS Fetching URL.createObjectURL(empty_data_blob) is OK
+FAIL Blob content is not sniffed for a content type [image/png] assert_equals: Content-Type is null expected (string) "" but got (object) null
+FAIL Blob content is not sniffed for a content type [text/xml] assert_equals: Content-Type is null expected (string) "" but got (object) null
+FAIL Set content type to the empty string for slice with invalid content type assert_equals: expected (string) "" but got (object) null
+FAIL Set content type to the empty string for slice with no content type  assert_equals: expected (string) "" but got (object) null
+FAIL Blob.slice should not sniff the content for a content type assert_equals: expected (string) "" but got (object) null
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any.js
index eaf01eb..228574f 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any.js
@@ -45,4 +45,76 @@
 checkKoUrl("blob:not-backed-by-a-blob/", "GET",
            "Fetching [GET] blob:not-backed-by-a-blob/ is KO");
 
+let empty_blob = new Blob([]);
+checkFetchResponse(URL.createObjectURL(empty_blob), "", "", 0,
+                  "Fetching URL.createObjectURL(empty_blob) is OK");
+
+let empty_type_blob = new Blob([], {type: ""});
+checkFetchResponse(URL.createObjectURL(empty_type_blob), "", "", 0,
+                  "Fetching URL.createObjectURL(empty_type_blob) is OK");
+
+let empty_data_blob = new Blob([], {type: "text/plain"});
+checkFetchResponse(URL.createObjectURL(empty_data_blob), "", "text/plain", 0,
+                  "Fetching URL.createObjectURL(empty_data_blob) is OK");
+
+promise_test(function(test) {
+  return fetch("/images/blue.png").then(function(resp) {
+    return resp.arrayBuffer();
+  }).then(function(image_buffer) {
+    let blob = new Blob([image_buffer]);
+    return fetch(URL.createObjectURL(blob)).then(function(resp) {
+      assert_equals(resp.status, 200, "HTTP status is 200");
+      assert_equals(resp.type, "basic", "response type is basic");
+      assert_equals(resp.headers.get("Content-Type"), "", "Content-Type is " + resp.headers.get("Content-Type"));
+    })
+  });
+}, "Blob content is not sniffed for a content type [image/png]");
+
+let simple_xml_string = '<?xml version="1.0" encoding="UTF-8"?><x></x>';
+let xml_blob_no_type = new Blob([simple_xml_string]);
+checkFetchResponse(URL.createObjectURL(xml_blob_no_type), simple_xml_string, "", 45,
+                   "Blob content is not sniffed for a content type [text/xml]");
+
+promise_test(function(test) {
+  let blob = new Blob([], {"type": "text/plain"});
+  let slice = blob.slice(8, 25, "\0");
+  return fetch(URL.createObjectURL(slice)).then(function (resp) {
+    assert_equals(resp.status, 200, "HTTP status is 200");
+    assert_equals(resp.type, "basic", "response type is basic");
+    assert_equals(resp.headers.get("Content-Type"), "");
+    assert_equals(resp.headers.get("Content-Length"), "17");
+    return resp.text();
+  }).then(function(bodyAsText) {
+    assert_equals(bodyAsText, "type with invalid");
+  });
+}, "Set content type to the empty string for slice with invalid content type");
+
+promise_test(function(test) {
+  let blob = new Blob([], {"type": "text/plain"});
+  let slice = blob.slice(8, 20);
+  return fetch(URL.createObjectURL(slice)).then(function (resp) {
+    assert_equals(resp.status, 200, "HTTP status is 200");
+    assert_equals(resp.type, "basic", "response type is basic");
+    assert_equals(resp.headers.get("Content-Type"), "");
+    assert_equals(resp.headers.get("Content-Length"), "12");
+    return resp.text();
+  }).then(function(bodyAsText) {
+    assert_equals(bodyAsText, "type that is");
+  });
+}, "Set content type to the empty string for slice with no content type ");
+
+promise_test(function(test) {
+  let blob = new Blob([simple_xml_string]);
+  let slice = blob.slice(0, 38);
+  return fetch(URL.createObjectURL(slice)).then(function (resp) {
+    assert_equals(resp.status, 200, "HTTP status is 200");
+    assert_equals(resp.type, "basic", "response type is basic");
+    assert_equals(resp.headers.get("Content-Type"), "");
+    assert_equals(resp.headers.get("Content-Length"), "38");
+    return resp.text();
+  }).then(function(bodyAsText) {
+    assert_equals(bodyAsText, '<?xml version="1.0" encoding="UTF-8"?>');
+  });
+}, "Blob.slice should not sniff the content for a content type");
+
 done();
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any.worker-expected.txt
new file mode 100644
index 0000000..508142e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/scheme-blob.sub.any.worker-expected.txt
@@ -0,0 +1,20 @@
+This is a testharness.js-based test.
+PASS Fetching [GET] URL.createObjectURL(blob) is OK
+PASS Fetching [GET] blob:http://www.web-platform.test:8001/ is KO
+PASS Fetching [POST] URL.createObjectURL(blob) is KO
+PASS Fetching [OPTIONS] URL.createObjectURL(blob) is KO
+PASS Fetching [HEAD] URL.createObjectURL(blob) is KO
+PASS Fetching [PUT] URL.createObjectURL(blob) is KO
+PASS Fetching [DELETE] URL.createObjectURL(blob) is KO
+PASS Fetching [INVALID] URL.createObjectURL(blob) is KO
+PASS Fetching [GET] blob:not-backed-by-a-blob/ is KO
+FAIL Fetching URL.createObjectURL(empty_blob) is OK assert_equals: Content-Type is null expected (string) "" but got (object) null
+FAIL Fetching URL.createObjectURL(empty_type_blob) is OK assert_equals: Content-Type is null expected (string) "" but got (object) null
+PASS Fetching URL.createObjectURL(empty_data_blob) is OK
+FAIL Blob content is not sniffed for a content type [image/png] assert_equals: Content-Type is null expected (string) "" but got (object) null
+FAIL Blob content is not sniffed for a content type [text/xml] assert_equals: Content-Type is null expected (string) "" but got (object) null
+FAIL Set content type to the empty string for slice with invalid content type assert_equals: expected (string) "" but got (object) null
+FAIL Set content type to the empty string for slice with no content type  assert_equals: expected (string) "" but got (object) null
+FAIL Blob.slice should not sniff the content for a content type assert_equals: expected (string) "" but got (object) null
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/README.md b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/README.md
new file mode 100644
index 0000000..cc313a1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/README.md
@@ -0,0 +1,11 @@
+# Overlapping navigation and traversal tests
+
+These tests follow the behavior outlined in the
+[session history rewrite](https://github.com/whatwg/html/pull/6315).
+
+<https://github.com/whatwg/html/issues/6927> discusses these results.
+
+We are not yet 100% sure on this behavior, especially for overlapping
+traversal cases where the spec is complex and some of the tests don't
+seem to match any browser. Please feel free to discuss on the spec
+issue.
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/anchor-fragment-history-back-on-click.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/anchor-fragment-history-back-on-click.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/anchor-fragment-history-back-on-click.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/anchor-fragment-history-back-on-click.html
index fe59f17..a081bec 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/anchor-fragment-history-back-on-click.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/anchor-fragment-history-back-on-click.html
@@ -22,8 +22,9 @@
   let navigationsPromise = new Promise(resolve => {
     onpopstate = () => {
       navigations.push(location.hash);
-      if (navigations.length == 2)
-          resolve();
+      if (navigations.length === 2) {
+        resolve();
+      }
     }
   });
 
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-cross-document-nav.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-cross-document-nav.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-cross-document-nav.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-cross-document-nav.html
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-cross-document-traversal.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-cross-document-traversal.html
similarity index 89%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-cross-document-traversal.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-cross-document-traversal.html
index 1173f3a3..341f66a 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-cross-document-traversal.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-cross-document-traversal.html
@@ -5,8 +5,8 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  According to the spec, "traverse the history by a delta" (e.g. history.back())
-  cancels any non-mature navigations.
+  According to the spec, "apply the history step" will set the ongoing
+  navigation to "traversal", canceling any non-mature navigations.
 -->
 
 <body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-same-document-nav.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-same-document-nav.html
similarity index 90%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-same-document-nav.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-same-document-nav.html
index 1b2aeaec..99525cb 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-same-document-nav.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-same-document-nav.html
@@ -6,8 +6,8 @@
 
 <!--
   According to the spec, the "URL and history update steps" (used by
-  pushState()) and the fragment navigation steps, both cancel any ongoing
-  history traversals, but do *not* cancel any ongoing navigations.
+  pushState()) and the fragment navigation steps, do *not* modify the ongoing
+  navigation, i.e. do not cancel any navigations.
 -->
 
 <body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-same-document-traversal.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-same-document-traversal.html
similarity index 84%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-same-document-traversal.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-same-document-traversal.html
index fac66240..2ff91be7 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-same-document-traversal.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-same-document-traversal.html
@@ -5,8 +5,9 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  According to the spec, "traverse the history by a delta" (e.g. history.back())
-  cancels any non-mature navigations.
+  According to the spec, "apply the history step" will set the ongoing
+  navigation to "traversal", canceling any navigation that is still processing
+  in parallel and hasn't yet reached "apply the history step".
 -->
 
 <body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-stop.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-stop.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-nav-stop.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-stop.html
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-cross-document-nav.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-nav.html
similarity index 92%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-cross-document-nav.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-nav.html
index 05d4705d..5141259 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-cross-document-nav.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-nav.html
@@ -6,9 +6,8 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  Apparently if a cross-document traversal is in progress, a cross-document
-  navigation just gets ignored. (Instead of, as you might expect, a race.)
-  This does not match the spec. This test instead asserts browser behavior.
+  According to the spec, if ongoing navigation is "traversal", the navigation
+  fails and nothing happens.
 -->
 
 <body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-traversal-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-traversal-expected.txt
new file mode 100644
index 0000000..bc974a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-traversal-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+PASS cross-document traversals in opposite directions: the result is going nowhere
+FAIL cross-document traversals in opposite directions, second traversal invalid at queuing time but valid at the time it is run: the result is going nowhere assert_unreached: second load event Reached unreachable code
+PASS cross-document traversals in the same (back) direction: the result is going -2 with only one load event
+PASS cross-document traversals in the same (forward) direction: the result is going +2 with only one load event
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-cross-document-traversal.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-traversal.html
similarity index 80%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-cross-document-traversal.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-traversal.html
index ec8b374..97907df 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-cross-document-traversal.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-traversal.html
@@ -5,25 +5,22 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  In the spec, all traversals are queued. However, what "back" and "forward"
-  mean is computed synchronously. So per spec:
+  In the spec, all traversals are queued, and that includes computing what
+  "back" and "forward" mean, based on the "current session history step". The
+  "current session history step" is updated at the end of "apply the history
+  step", at which point the queued steps in "traverse history by a delta" get to
+  run and compute what is back/forward. So the basic structure is:
 
-  - back(), back(): go back 1.
-  - back(), forward(): go forward 1 (if you're not starting from the end).
+  - back(), back(): go back once, then again.
+  - back(), forward(): go back once, then go forward.
 
-  This is not how browsers behave:
+  However, note that these observable effects (e.g., actually loading an
+  intermediate document) are done via queued tasks. Those tasks will end up not
+  running, once we switch the active document due to the second traversal. So
+  the end observable result looks like:
 
-  - Chrome seems to coalesce all traversals and apply them at once, i.e.:
-
-    - back(), back(): go back 2 at once.
-    - back(), forward(): go nowhere.
-
-  - Firefox seems to ignore traverals requests while a traversal is ongoing:
-
-    - back(), back(): go back 1.
-    - back(), forward(): go back 1.
-
-  We assert the Firefox behavior here for now.
+  - back(), back(): go back -2.
+  - back(), forward(): go nowhere.
 -->
 
 <body>
@@ -57,14 +54,11 @@
   iframe.contentWindow.history.forward();
   assert_equals(iframe.contentWindow.location.search, "?2", "must not go forward synchronously");
 
-  await waitForLoad(iframe);
-  assert_equals(iframe.contentWindow.location.search, "?1", "first load event must be going back");
-
   iframe.onload = t.unreached_func("second load event");
 
   await waitForPotentialNetworkLoads(t);
-  assert_equals(iframe.contentWindow.location.search, "?1", "must stay on ?1");
-}, "cross-document traversals in opposite directions: the second is ignored");
+  assert_equals(iframe.contentWindow.location.search, "?2", "must stay on ?2");
+}, "cross-document traversals in opposite directions: the result is going nowhere");
 
 promise_test(async t => {
   const iframe = await createIframe(t);
@@ -86,14 +80,11 @@
   iframe.contentWindow.history.forward();
   assert_equals(iframe.contentWindow.location.search, "?2", "must not go forward synchronously");
 
-  await waitForLoad(iframe);
-  assert_equals(iframe.contentWindow.location.search, "?1", "first load event must be going back");
-
   iframe.onload = t.unreached_func("second load event");
 
   await waitForPotentialNetworkLoads(t);
-  assert_equals(iframe.contentWindow.location.search, "?1", "must stay on ?1");
-}, "cross-document traversals in opposite directions, second traversal invalid at queuing time: the second is ignored");
+  assert_equals(iframe.contentWindow.location.search, "?2", "must stay on ?2");
+}, "cross-document traversals in opposite directions, second traversal invalid at queuing time but valid at the time it is run: the result is going nowhere");
 
 promise_test(async t => {
   const iframe = await createIframe(t);
@@ -119,13 +110,13 @@
   assert_equals(iframe.contentWindow.location.search, "?3", "must not go back synchronously (2)");
 
   await waitForLoad(iframe);
-  assert_equals(iframe.contentWindow.location.search, "?2", "first load event must be going back");
+  assert_equals(iframe.contentWindow.location.search, "?1", "first load event must be going back");
 
   iframe.onload = t.unreached_func("second load event");
 
   await waitForPotentialNetworkLoads(t);
-  assert_equals(iframe.contentWindow.location.search, "?2", "must stay on ?2");
-}, "cross-document traversals in the same (back) direction: the second is ignored");
+  assert_equals(iframe.contentWindow.location.search, "?1", "must stay on ?1");
+}, "cross-document traversals in the same (back) direction: the result is going -2 with only one load event");
 
 promise_test(async t => {
   const iframe = await createIframe(t);
@@ -159,11 +150,11 @@
   assert_equals(iframe.contentWindow.location.search, "?1", "must not go forward synchronously (2)");
 
   await waitForLoad(iframe);
-  assert_equals(iframe.contentWindow.location.search, "?2", "first load event must be going forward");
+  assert_equals(iframe.contentWindow.location.search, "?3", "first load event must be going forward");
 
   iframe.onload = t.unreached_func("second load event");
 
   await waitForPotentialNetworkLoads(t);
-  assert_equals(iframe.contentWindow.location.search, "?2", "must stay on ?2");
-}, "cross-document traversals in the same (forward) direction: the second is ignored");
+  assert_equals(iframe.contentWindow.location.search, "?3", "must stay on ?3");
+}, "cross-document traversals in the same (forward) direction: the result is going +2 with only one load event");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-same-document-nav.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-same-document-nav.html
similarity index 75%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-same-document-nav.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-same-document-nav.html
index 5d3850f..df6258f 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-same-document-nav.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-same-document-nav.html
@@ -5,11 +5,8 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  The spec currently says that same-document navigations must stop traverals,
-  but this does not match browsers: https://github.com/whatwg/html/issues/6773.
-  Browsers also disagree on how far back this should take us. This test assumes
-  a behavior similar to Firefox's, although Firefox is inconsistent and only
-  applies this behavior for fragments, not for pushState().
+  The spec explicitly covers this case, with a Jake diagram:
+  https://whatpr.org/html/6315/browsing-the-web.html#example-sync-navigation-steps-queue-jumping-basic
 -->
 
 <body>
@@ -38,9 +35,9 @@
   assert_equals(iframe.contentWindow.location.search, "?2");
   assert_equals(iframe.contentWindow.location.hash, "#3");
 
-  // Eventually ends up on ?2
-  await t.step_wait(() => iframe.contentWindow.location.search === "?2" && iframe.contentWindow.location.hash === "");
-}, "same-document traversals are not canceled by fragment navigations");
+  // Eventually ends up on ?1
+  await t.step_wait(() => iframe.contentWindow.location.search === "?1" && iframe.contentWindow.location.hash === "");
+}, "same-document traversals + fragment navigations");
 
 promise_test(async t => {
   const iframe = await createIframe(t);
@@ -63,7 +60,7 @@
   iframe.contentWindow.history.pushState(null, "", "?3");
   assert_equals(iframe.contentWindow.location.search, "?3");
 
-  // Eventually ends up on ?2
-  await t.step_wait(() => iframe.contentWindow.location.search === "?2");
-}, "same-document traversals are not canceled by pushState()");
+  // Eventually ends up on ?1
+  await t.step_wait(() => iframe.contentWindow.location.search === "?1");
+}, "same-document traversals + pushState()");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-same-document-traversal.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-same-document-traversal.html
similarity index 80%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-same-document-traversal.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-same-document-traversal.html
index 0a9154c..3c37c46 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-same-document-traversal.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-same-document-traversal.html
@@ -5,22 +5,8 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  In the spec, all traversals are queued. However, what "back" and "forward"
-  mean is computed synchronously. So per spec:
-
-  - back(), back(): go back 1.
-
-  This is not how browsers behave:
-
-  - Chrome seems to coalesce all traversals and apply them at once, i.e.:
-
-    - back(), back(): go back 2 at once.
-
-  - Firefox seems to ignore traverals requests while a traversal is ongoing:
-
-    - back(), back(): go back 1.
-
-  We assert the Firefox behavior here for now.
+  This case is not significantly different from
+  cross-document-traversal-cross-document-traversal.html.
 -->
 
 <body>
@@ -53,15 +39,15 @@
 
   await waitForLoad(iframe);
   assert_equals(iframe.contentWindow.location.search, "?1", "first load event must be going back (search)");
-  assert_equals(iframe.contentWindow.location.hash, "#2", "first load event must be going back (hash)");
+  assert_equals(iframe.contentWindow.location.hash, "", "first load event must be going back (hash)");
 
   iframe.contentWindow.onhashchange = t.unreached_func("hashchange event");
   iframe.onload = t.unreached_func("second load event");
 
   await waitForPotentialNetworkLoads(t);
-  assert_equals(iframe.contentWindow.location.search, "?1", "must stay on ?1#2 (search)");
-  assert_equals(iframe.contentWindow.location.hash, "#2", "must stay on ?1#2 (hash)");
-}, "traversals in the same (back) direction: the second is ignored");
+  assert_equals(iframe.contentWindow.location.search, "?1", "must stay on ?1 (search)");
+  assert_equals(iframe.contentWindow.location.hash, "", "must stay on ?1 (hash)");
+}, "traversals in the same (back) direction: coalesced");
 
 promise_test(async t => {
   const iframe = await createIframe(t);
@@ -96,13 +82,13 @@
 
   await waitForLoad(iframe);
   assert_equals(iframe.contentWindow.location.search, "?2", "first load event must be going forward (search)");
-  assert_equals(iframe.contentWindow.location.hash, "", "first load event must be going forward (hash)");
+  assert_equals(iframe.contentWindow.location.hash, "#3", "first load event must be going forward (hash)");
 
   iframe.contentWindow.onhashchange = t.unreached_func("hashchange event");
   iframe.onload = t.unreached_func("second load event");
 
   await waitForPotentialNetworkLoads(t);
   assert_equals(iframe.contentWindow.location.search, "?2", "must stay on ?2");
-  assert_equals(iframe.contentWindow.location.hash, "", "must stay on ?2");
-}, "traversals in the same (forward) direction: the second is ignored");
+  assert_equals(iframe.contentWindow.location.hash, "#3", "must stay on ?2");
+}, "traversals in the same (forward) direction: coalesced");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-stop.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-stop.html
similarity index 81%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-stop.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-stop.html
index 49d97e7..6202eb9 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/cross-document-traversal-stop.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-traversal-stop.html
@@ -5,9 +5,11 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  The spec currently says that stop() must stop traverals, but this does not
-  match browsers: https://github.com/whatwg/html/issues/6905. This test assumes
-  browser behavior.
+  The spec says that stop() must not stop traverals.
+
+  (Note: the spec also says the UI "stop" button must not stop traversals, but
+  that does not match browsers. See https://github.com/whatwg/html/issues/6905.
+  But that is not what's under test here.)
 -->
 
 <body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/forward-to-pruned-entry.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/forward-to-pruned-entry.html
similarity index 99%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/forward-to-pruned-entry.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/forward-to-pruned-entry.html
index f5f9a2c..8e1c349 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/forward-to-pruned-entry.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/forward-to-pruned-entry.html
@@ -21,5 +21,4 @@
   await new Promise(r => t.step_timeout(r, 20));
   assert_equals(location.hash, "#clobber");
 }, "If forward pruning clobbers the target of a traverse, abort");
-
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-1-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-1-expected.txt
new file mode 100644
index 0000000..16fb3502
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-1-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL parent cancels a pending navigation in a same-origin child assert_false: <iframe> load event does not fire until subsequent navigation is complete expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/nav-cancelation-1.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-1.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/nav-cancelation-1.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-1.html
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-2.sub-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-2.sub-expected.txt
new file mode 100644
index 0000000..d02213b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-2.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL grandparent cancels a pending navigation in a cross-origin grandchild assert_false: Grandchild <iframe> load event doesn't fire before grandparent's load event expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/nav-cancelation-2.sub.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-2.sub.html
similarity index 98%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/nav-cancelation-2.sub.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-2.sub.html
index 62f824f..c081513 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/nav-cancelation-2.sub.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-2.sub.html
@@ -26,7 +26,7 @@
 
 <body>
 
-<iframe src="http://{{domains[www1]}}:{{ports[http][0]}}/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/resources/nav-cancelation-2-helper.html"></iframe>
+<iframe src="http://{{domains[www1]}}:{{ports[http][0]}}/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/resources/nav-cancelation-2-helper.html"></iframe>
 
 <script>
 promise_test(async t => {
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/resources/helpers.mjs b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/resources/helpers.mjs
similarity index 74%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/resources/helpers.mjs
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/resources/helpers.mjs
index d2ecb9d9b..7938497 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/resources/helpers.mjs
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/resources/helpers.mjs
@@ -35,11 +35,18 @@
 // This is used when we want to end the test by asserting some load doesn't
 // happen, but we're not sure how long to wait. We could just wait a long-ish
 // time (e.g. a second), but that makes the tests slow. Instead, assume that
-// network loads take roughly the same time, so by waiting for 2x the duration
-// of a separate iframe load, we would have caught any problems.
+// network loads take roughly the same time. Then, you can use this function to
+// wait a small multiple of the duration of a separate iframe load; this should
+// be long enough to catch any problems.
 export async function waitForPotentialNetworkLoads(t) {
   const before = performance.now();
+
+  // Sometimes we're doing something, like a traversal, which cancels our first
+  // attempt at iframe loading. In that case we bail out after 100 ms and try
+  // again. (Better ideas welcome...)
+  await Promise.race([createIframe(t), delay(t, 100)]);
   await createIframe(t);
+
   const after = performance.now();
   await delay(t, after - before);
 }
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/resources/nav-cancelation-2-helper.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/resources/nav-cancelation-2-helper.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/resources/nav-cancelation-2-helper.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/resources/nav-cancelation-2-helper.html
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/resources/slow.py b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/resources/slow.py
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/resources/slow.py
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/resources/slow.py
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-cross-document-nav.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-cross-document-nav.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-cross-document-nav.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-cross-document-nav.html
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-cross-document-traversal.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-cross-document-traversal.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-cross-document-traversal.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-cross-document-traversal.html
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-same-document-nav.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-same-document-nav.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-same-document-nav.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-same-document-nav.html
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-same-document-traversal.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-same-document-traversal.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-same-document-traversal.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-same-document-traversal.html
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-stop.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-stop.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-nav-stop.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-nav-stop.html
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-cross-document-nav-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-cross-document-nav-expected.txt
new file mode 100644
index 0000000..a2cebc4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-cross-document-nav-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL same-document traversals are not canceled by cross-document navigations step_wait_func: traversal Timed out waiting on condition
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-cross-document-nav.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-cross-document-nav.html
similarity index 60%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-cross-document-nav.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-cross-document-nav.html
index 3978a2c..37960c3 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-cross-document-nav.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-cross-document-nav.html
@@ -6,20 +6,15 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  The spec currently says that cross-document navigations cancel traversals
-  only once they mature. So the traversal and navigation both go through.
-  We use slow.py to ensure the traversal finishes first (although it'd be pretty
-  likely even with /common/blank.html, since same-document traverals should be
-  fast).
+  The spec says that navigations are ignored if there is an ongoing traversal.
 -->
 
 <body>
 <script type="module">
-import { createIframe, delay } from "./resources/helpers.mjs";
+import { createIframe, delay, waitForPotentialNetworkLoads } from "./resources/helpers.mjs";
 
 promise_test(async t => {
   const iframe = await createIframe(t);
-  const slowURL = (new URL("resources/slow.py", location.href)).href;
 
   // Setup
   iframe.contentWindow.location.hash = "#1";
@@ -31,14 +26,17 @@
 
   assert_equals(iframe.contentWindow.location.hash, "#2", "must not go back synchronously");
 
-  iframe.contentWindow.location.href = slowURL;
+  iframe.contentWindow.location.search = "?1";
   assert_equals(iframe.contentWindow.location.search, "", "must not navigate synchronously (search)");
   assert_equals(iframe.contentWindow.location.hash, "#2", "must not navigate synchronously (hash)");
 
-  // Eventually ends up on #2
-  await t.step_wait(() => iframe.contentWindow.location.hash === "#2", "traversal");
+  // Eventually ends up on #1.
+  await t.step_wait(() => iframe.contentWindow.location.hash === "#1", "traversal");
 
-  // And then slow.py
-  await t.step_wait(() => iframe.contentWindow.location.href === slowURL, "navigation");
+  // Never loads a different document.
+  iframe.onload = t.unreached_func("load event");
+  await waitForPotentialNetworkLoads(t);
+  assert_equals(iframe.contentWindow.location.search, "", "must stay on #2 (search)");
+  assert_equals(iframe.contentWindow.location.hash, "#2", "must stay on #2 (hash)");
 }, "same-document traversals are not canceled by cross-document navigations");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-cross-document-traversal.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-cross-document-traversal.html
similarity index 86%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-cross-document-traversal.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-cross-document-traversal.html
index 5dfd3e1..a48f4d4 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-cross-document-traversal.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-cross-document-traversal.html
@@ -5,19 +5,9 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  In the spec, all traversals are queued. However, what "back" and "forward"
-  mean is computed synchronously. So per spec:
-
-  - back(), back(): go back 1.
-  - back(), forward(): go forward 1 (if you're not starting from the end).
-
-  This is not how browsers behave. Furthermore, this case is apparently unlike
-  other multi-traversal test cases: both Chrome and Firefox queue up these
-  traverals, firing events for each of them. I.e.
-
-    - back(), back(): go back 1, go back 1.
-
-  We assert this shared browser behavior here for now.
+  Compare this to cross-document-traversal-cross-document-traversal.html. Since
+  there are no network loads for the first traversal here, it does observably go
+  through. So we end up with both traversals before observable in sequence.
 -->
 
 <body>
@@ -94,5 +84,5 @@
   await waitForLoad(iframe);
   assert_equals(iframe.contentWindow.location.search, "?3", "first load event must be going forward (search)");
   assert_equals(iframe.contentWindow.location.hash, "#2", "first load event must be going forward (hash)");
-}, "traversals in the same (forward) direction: the second is queued up");
+}, "traversals in the same (forward) direction: queued up");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-same-document-nav.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-nav.html
similarity index 71%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-same-document-nav.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-nav.html
index 7142cbb..5094651 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-same-document-nav.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-nav.html
@@ -5,12 +5,10 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  The spec currently says that same-document navigations must stop traverals,
-  but this does not match browsers: https://github.com/whatwg/html/issues/6773.
-  There is a separate interop issue about how the traversal vs. the
-  same-document navigation get ordered. This test assumes a behavior similar to
-  Firefox's, although Firefox is inconsistent and only applies this behavior
-  for fragments, not for pushState().
+  Per spec, same-document navigations ignore the "ongoing navigation" flag and
+  just happen synchronously, then queue onto the session history traversal queue
+  to update the source of truth. However, the traversal was queued first, so it
+  will ignore that update when calculating its endpoint.
 -->
 
 <body>
@@ -33,9 +31,9 @@
   iframe.contentWindow.location.hash = "#3";
   assert_equals(iframe.contentWindow.location.hash, "#3");
 
-  // Eventually ends up on #2
-  await t.step_wait(() => iframe.contentWindow.location.hash === "#2");
-}, "same-document traversals are not canceled by fragment navigations");
+  // Eventually ends up on #1
+  await t.step_wait(() => iframe.contentWindow.location.hash === "#1");
+}, "same-document traversals are not canceled by fragment navigations and calculate their endpoint based on the original placement");
 
 promise_test(async t => {
   const iframe = await createIframe(t);
@@ -53,7 +51,7 @@
   iframe.contentWindow.history.pushState(null, "", "/3");
   assert_equals(iframe.contentWindow.location.pathname, "/3");
 
-  // Eventually ends up on /2
-  await t.step_wait(() => iframe.contentWindow.location.pathname === "/2");
-}, "same-document traversals are not canceled by pushState()");
+  // Eventually ends up on /1
+  await t.step_wait(() => iframe.contentWindow.location.pathname === "/1");
+}, "same-document traversals are not canceled by pushState() and calculate their endpoint based on the original placement");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-same-document-traversal-hashchange.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-hashchange.html
similarity index 88%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-same-document-traversal-hashchange.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-hashchange.html
index 43aefa0..df5ea5c 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-same-document-traversal-hashchange.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-hashchange.html
@@ -5,27 +5,11 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  In the spec, all traversals are queued. However, what "back" and "forward"
-  mean is computed synchronously. So per spec:
-
-  - back(), back(): go back 1.
-  - back(), forward(): go forward 1 (if you're not starting from the end).
-
-  (The spec doesn't care about same or cross-document.)
-
-  This is not how browsers behave:
-
-  - Chrome seems to ignore same-document traversal requests if one is already in flight:
-
-    - back(), back(): go back 1.
-    - back(), forward(): go back 1 (regardless of starting at the end or not).
-
-  - Firefox seems to queue up "back" or "forward" commands:
-
-    - back(), back(): go back 1, then go back 1.
-    - back(), forward(): go back 1, then go forward 1 (regardless of starting at the end or not).
-
-  We assert the Firefox behavior here for now.
+  Compare this to cross-document-traversal-cross-document-traversal.html. Since
+  there are no network loads or document unloads to cancel tasks, both
+  traversals should observably go through. Target step calculation for the
+  second traversal should take place after the first traversal is finished. So
+  we end up with both traversals observable in sequence.
 -->
 
 <body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-same-document-traversal-pushstate.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-pushstate.html
similarity index 88%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-same-document-traversal-pushstate.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-pushstate.html
index 02617338..47c7d6e 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-same-document-traversal-pushstate.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-same-document-traversal-pushstate.html
@@ -5,27 +5,11 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  In the spec, all traversals are queued. However, what "back" and "forward"
-  mean is computed synchronously. So per spec:
-
-  - back(), back(): go back 1.
-  - back(), forward(): go forward 1 (if you're not starting from the end).
-
-  (The spec doesn't care about same or cross-document.)
-
-  This is not how browsers behave:
-
-  - Chrome seems to ignore same-document traversal requests if one is already in flight:
-
-    - back(), back(): go back 1.
-    - back(), forward(): go back 1 (regardless of starting at the end or not).
-
-  - Firefox seems to queue up "back" or "forward" commands:
-
-    - back(), back(): go back 1, then go back 1.
-    - back(), forward(): go back 1, then go forward 1 (regardless of starting at the end or not).
-
-  We assert the Firefox behavior here for now.
+  Compare this to cross-document-traversal-cross-document-traversal.html. Since
+  there are no network loads or document unloads to cancel tasks, both
+  traversals should observably go through. Target step calculation for the
+  second traversal should take place after the first traversal is finished. So
+  we end up with both traversals observable in sequence.
 -->
 
 <body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-stop.html b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-stop.html
similarity index 76%
rename from third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-stop.html
rename to third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-stop.html
index ffa2f14..2f057038 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/same-document-traversal-stop.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/same-document-traversal-stop.html
@@ -5,9 +5,11 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <!--
-  The spec currently says that stop() must stop traverals, but this does not
-  match browsers: https://github.com/whatwg/html/issues/6905. This test assumes
-  browser behavior.
+  The spec says that stop() must not stop traverals.
+
+  (Note: the spec also says the UI "stop" button must not stop traversals, but
+  that does not match browsers. See https://github.com/whatwg/html/issues/6905.
+  But that is not what's under test here.)
 -->
 
 <body>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/README.md b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/README.md
deleted file mode 100644
index cdd7975c..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/tentative/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Overlapping navigation and traversal tests
-
-While developing the [navigation API](https://wicg.github.io/navigation-api/),
-@domenic noticed that cancelation of navigations and history traversals is not
-very well-defined in the spec.
-
-On the spec side, this will probably be fixed as part of, or after, the
-[session history rewrite](https://github.com/whatwg/html/pull/6315).
-
-In the meantime, this directory contains tests which try to match most browsers,
-or picks one of the potential behaviors.
-
-<https://github.com/whatwg/html/issues/6927> discusses these results.
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-history-interface/history-associated-with-document.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-history-interface/history-associated-with-document.window.js
new file mode 100644
index 0000000..94c1b2c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-history-interface/history-associated-with-document.window.js
@@ -0,0 +1,6 @@
+// META: title=the History object must be associated with the Document object, not the Window object
+// META: script=/common/object-association.js
+
+// See https://github.com/whatwg/html/issues/2566.
+
+testIsPerDocument("history");
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/type-change-state-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/type-change-state-expected.txt
deleted file mode 100644
index f8665a4..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/type-change-state-expected.txt
+++ /dev/null
@@ -1,384 +0,0 @@
-This is a testharness.js-based test.
-Found 380 tests; 372 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS change state from hidden to text
-PASS change state from hidden to search
-PASS change state from hidden to tel
-PASS change state from hidden to url
-PASS change state from hidden to email
-PASS change state from hidden to password
-PASS change state from hidden to datetime-local
-PASS change state from hidden to date
-PASS change state from hidden to time
-PASS change state from hidden to number
-PASS change state from hidden to range
-PASS change state from hidden to color
-PASS change state from hidden to checkbox
-PASS change state from hidden to radio
-PASS change state from hidden to file
-PASS change state from hidden to submit
-PASS change state from hidden to image
-PASS change state from hidden to reset
-PASS change state from hidden to button
-PASS change state from text to hidden
-PASS change state from text to search
-PASS change state from text to tel
-PASS change state from text to url
-PASS change state from text to email
-PASS change state from text to password
-PASS change state from text to datetime-local
-PASS change state from text to date
-PASS change state from text to time
-PASS change state from text to number
-PASS change state from text to range
-PASS change state from text to color
-PASS change state from text to checkbox
-PASS change state from text to radio
-PASS change state from text to file
-PASS change state from text to submit
-PASS change state from text to image
-PASS change state from text to reset
-PASS change state from text to button
-PASS change state from search to hidden
-PASS change state from search to text
-PASS change state from search to tel
-PASS change state from search to url
-PASS change state from search to email
-PASS change state from search to password
-PASS change state from search to datetime-local
-PASS change state from search to date
-PASS change state from search to time
-PASS change state from search to number
-PASS change state from search to range
-PASS change state from search to color
-PASS change state from search to checkbox
-PASS change state from search to radio
-PASS change state from search to file
-PASS change state from search to submit
-PASS change state from search to image
-PASS change state from search to reset
-PASS change state from search to button
-PASS change state from tel to hidden
-PASS change state from tel to text
-PASS change state from tel to search
-PASS change state from tel to url
-PASS change state from tel to email
-PASS change state from tel to password
-PASS change state from tel to datetime-local
-PASS change state from tel to date
-PASS change state from tel to time
-PASS change state from tel to number
-PASS change state from tel to range
-PASS change state from tel to color
-PASS change state from tel to checkbox
-PASS change state from tel to radio
-PASS change state from tel to file
-PASS change state from tel to submit
-PASS change state from tel to image
-PASS change state from tel to reset
-PASS change state from tel to button
-PASS change state from url to hidden
-PASS change state from url to text
-PASS change state from url to search
-PASS change state from url to tel
-PASS change state from url to email
-PASS change state from url to password
-PASS change state from url to datetime-local
-PASS change state from url to date
-PASS change state from url to time
-PASS change state from url to number
-PASS change state from url to range
-PASS change state from url to color
-PASS change state from url to checkbox
-PASS change state from url to radio
-PASS change state from url to file
-PASS change state from url to submit
-PASS change state from url to image
-PASS change state from url to reset
-PASS change state from url to button
-PASS change state from email to hidden
-PASS change state from email to text
-PASS change state from email to search
-PASS change state from email to tel
-PASS change state from email to url
-PASS change state from email to password
-PASS change state from email to datetime-local
-PASS change state from email to date
-PASS change state from email to time
-PASS change state from email to number
-PASS change state from email to range
-PASS change state from email to color
-PASS change state from email to checkbox
-PASS change state from email to radio
-PASS change state from email to file
-PASS change state from email to submit
-PASS change state from email to image
-PASS change state from email to reset
-PASS change state from email to button
-PASS change state from password to hidden
-PASS change state from password to text
-PASS change state from password to search
-PASS change state from password to tel
-PASS change state from password to url
-PASS change state from password to email
-PASS change state from password to datetime-local
-PASS change state from password to date
-PASS change state from password to time
-PASS change state from password to number
-PASS change state from password to range
-PASS change state from password to color
-PASS change state from password to checkbox
-PASS change state from password to radio
-PASS change state from password to file
-PASS change state from password to submit
-PASS change state from password to image
-PASS change state from password to reset
-PASS change state from password to button
-PASS change state from datetime-local to hidden
-PASS change state from datetime-local to text
-PASS change state from datetime-local to search
-PASS change state from datetime-local to tel
-PASS change state from datetime-local to url
-PASS change state from datetime-local to email
-PASS change state from datetime-local to password
-PASS change state from datetime-local to date
-PASS change state from datetime-local to time
-PASS change state from datetime-local to number
-PASS change state from datetime-local to range
-PASS change state from datetime-local to color
-FAIL change state from datetime-local to checkbox assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-FAIL change state from datetime-local to radio assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-PASS change state from datetime-local to file
-PASS change state from datetime-local to submit
-PASS change state from datetime-local to image
-PASS change state from datetime-local to reset
-PASS change state from datetime-local to button
-PASS change state from date to hidden
-PASS change state from date to text
-PASS change state from date to search
-PASS change state from date to tel
-PASS change state from date to url
-PASS change state from date to email
-PASS change state from date to password
-PASS change state from date to datetime-local
-PASS change state from date to time
-PASS change state from date to number
-PASS change state from date to range
-PASS change state from date to color
-FAIL change state from date to checkbox assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-FAIL change state from date to radio assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-PASS change state from date to file
-PASS change state from date to submit
-PASS change state from date to image
-PASS change state from date to reset
-PASS change state from date to button
-PASS change state from time to hidden
-PASS change state from time to text
-PASS change state from time to search
-PASS change state from time to tel
-PASS change state from time to url
-PASS change state from time to email
-PASS change state from time to password
-PASS change state from time to datetime-local
-PASS change state from time to date
-PASS change state from time to number
-PASS change state from time to range
-PASS change state from time to color
-FAIL change state from time to checkbox assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-FAIL change state from time to radio assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-PASS change state from time to file
-PASS change state from time to submit
-PASS change state from time to image
-PASS change state from time to reset
-PASS change state from time to button
-PASS change state from number to hidden
-PASS change state from number to text
-PASS change state from number to search
-PASS change state from number to tel
-PASS change state from number to url
-PASS change state from number to email
-PASS change state from number to password
-PASS change state from number to datetime-local
-PASS change state from number to date
-PASS change state from number to time
-PASS change state from number to range
-PASS change state from number to color
-FAIL change state from number to checkbox assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-FAIL change state from number to radio assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-PASS change state from number to file
-PASS change state from number to submit
-PASS change state from number to image
-PASS change state from number to reset
-PASS change state from number to button
-PASS change state from range to hidden
-PASS change state from range to text
-PASS change state from range to search
-PASS change state from range to tel
-PASS change state from range to url
-PASS change state from range to email
-PASS change state from range to password
-PASS change state from range to datetime-local
-PASS change state from range to date
-PASS change state from range to time
-PASS change state from range to number
-PASS change state from range to color
-PASS change state from range to checkbox
-PASS change state from range to radio
-PASS change state from range to file
-PASS change state from range to submit
-PASS change state from range to image
-PASS change state from range to reset
-PASS change state from range to button
-PASS change state from color to hidden
-PASS change state from color to text
-PASS change state from color to search
-PASS change state from color to tel
-PASS change state from color to url
-PASS change state from color to email
-PASS change state from color to password
-PASS change state from color to datetime-local
-PASS change state from color to date
-PASS change state from color to time
-PASS change state from color to number
-PASS change state from color to range
-PASS change state from color to checkbox
-PASS change state from color to radio
-PASS change state from color to file
-PASS change state from color to submit
-PASS change state from color to image
-PASS change state from color to reset
-PASS change state from color to button
-PASS change state from checkbox to hidden
-PASS change state from checkbox to text
-PASS change state from checkbox to search
-PASS change state from checkbox to tel
-PASS change state from checkbox to url
-PASS change state from checkbox to email
-PASS change state from checkbox to password
-PASS change state from checkbox to datetime-local
-PASS change state from checkbox to date
-PASS change state from checkbox to time
-PASS change state from checkbox to number
-PASS change state from checkbox to range
-PASS change state from checkbox to color
-PASS change state from checkbox to radio
-PASS change state from checkbox to file
-PASS change state from checkbox to submit
-PASS change state from checkbox to image
-PASS change state from checkbox to reset
-PASS change state from checkbox to button
-PASS change state from radio to hidden
-PASS change state from radio to text
-PASS change state from radio to search
-PASS change state from radio to tel
-PASS change state from radio to url
-PASS change state from radio to email
-PASS change state from radio to password
-PASS change state from radio to datetime-local
-PASS change state from radio to date
-PASS change state from radio to time
-PASS change state from radio to number
-PASS change state from radio to range
-PASS change state from radio to color
-PASS change state from radio to checkbox
-PASS change state from radio to file
-PASS change state from radio to submit
-PASS change state from radio to image
-PASS change state from radio to reset
-PASS change state from radio to button
-PASS change state from file to hidden
-PASS change state from file to text
-PASS change state from file to search
-PASS change state from file to tel
-PASS change state from file to url
-PASS change state from file to email
-PASS change state from file to password
-PASS change state from file to datetime-local
-PASS change state from file to date
-PASS change state from file to time
-PASS change state from file to number
-PASS change state from file to range
-PASS change state from file to color
-PASS change state from file to checkbox
-PASS change state from file to radio
-PASS change state from file to submit
-PASS change state from file to image
-PASS change state from file to reset
-PASS change state from file to button
-PASS change state from submit to hidden
-PASS change state from submit to text
-PASS change state from submit to search
-PASS change state from submit to tel
-PASS change state from submit to url
-PASS change state from submit to email
-PASS change state from submit to password
-PASS change state from submit to datetime-local
-PASS change state from submit to date
-PASS change state from submit to time
-PASS change state from submit to number
-PASS change state from submit to range
-PASS change state from submit to color
-PASS change state from submit to checkbox
-PASS change state from submit to radio
-PASS change state from submit to file
-PASS change state from submit to image
-PASS change state from submit to reset
-PASS change state from submit to button
-PASS change state from image to hidden
-PASS change state from image to text
-PASS change state from image to search
-PASS change state from image to tel
-PASS change state from image to url
-PASS change state from image to email
-PASS change state from image to password
-PASS change state from image to datetime-local
-PASS change state from image to date
-PASS change state from image to time
-PASS change state from image to number
-PASS change state from image to range
-PASS change state from image to color
-PASS change state from image to checkbox
-PASS change state from image to radio
-PASS change state from image to file
-PASS change state from image to submit
-PASS change state from image to reset
-PASS change state from image to button
-PASS change state from reset to hidden
-PASS change state from reset to text
-PASS change state from reset to search
-PASS change state from reset to tel
-PASS change state from reset to url
-PASS change state from reset to email
-PASS change state from reset to password
-PASS change state from reset to datetime-local
-PASS change state from reset to date
-PASS change state from reset to time
-PASS change state from reset to number
-PASS change state from reset to range
-PASS change state from reset to color
-PASS change state from reset to checkbox
-PASS change state from reset to radio
-PASS change state from reset to file
-PASS change state from reset to submit
-PASS change state from reset to image
-PASS change state from reset to button
-PASS change state from button to hidden
-PASS change state from button to text
-PASS change state from button to search
-PASS change state from button to tel
-PASS change state from button to url
-PASS change state from button to email
-PASS change state from button to password
-PASS change state from button to datetime-local
-PASS change state from button to date
-PASS change state from button to time
-PASS change state from button to number
-PASS change state from button to range
-PASS change state from button to color
-PASS change state from button to checkbox
-PASS change state from button to radio
-PASS change state from button to file
-PASS change state from button to submit
-PASS change state from button to image
-PASS change state from button to reset
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/type-change-state-weekmonth-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/type-change-state-weekmonth-expected.txt
deleted file mode 100644
index f9c1f75..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/type-change-state-weekmonth-expected.txt
+++ /dev/null
@@ -1,86 +0,0 @@
-This is a testharness.js-based test.
-Found 82 tests; 78 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS change state from hidden to month
-PASS change state from hidden to week
-PASS change state from text to month
-PASS change state from text to week
-PASS change state from search to month
-PASS change state from search to week
-PASS change state from tel to month
-PASS change state from tel to week
-PASS change state from url to month
-PASS change state from url to week
-PASS change state from email to month
-PASS change state from email to week
-PASS change state from password to month
-PASS change state from password to week
-PASS change state from datetime-local to month
-PASS change state from datetime-local to week
-PASS change state from date to month
-PASS change state from date to week
-PASS change state from month to hidden
-PASS change state from month to text
-PASS change state from month to search
-PASS change state from month to tel
-PASS change state from month to url
-PASS change state from month to email
-PASS change state from month to password
-PASS change state from month to datetime-local
-PASS change state from month to date
-PASS change state from month to week
-PASS change state from month to time
-PASS change state from month to number
-PASS change state from month to range
-PASS change state from month to color
-FAIL change state from month to checkbox assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-FAIL change state from month to radio assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-PASS change state from month to file
-PASS change state from month to submit
-PASS change state from month to image
-PASS change state from month to reset
-PASS change state from month to button
-PASS change state from week to hidden
-PASS change state from week to text
-PASS change state from week to search
-PASS change state from week to tel
-PASS change state from week to url
-PASS change state from week to email
-PASS change state from week to password
-PASS change state from week to datetime-local
-PASS change state from week to date
-PASS change state from week to month
-PASS change state from week to time
-PASS change state from week to number
-PASS change state from week to range
-PASS change state from week to color
-FAIL change state from week to checkbox assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-FAIL change state from week to radio assert_equals: input.value should be 'on' after change of state expected "on" but got ""
-PASS change state from week to file
-PASS change state from week to submit
-PASS change state from week to image
-PASS change state from week to reset
-PASS change state from week to button
-PASS change state from time to month
-PASS change state from time to week
-PASS change state from number to month
-PASS change state from number to week
-PASS change state from range to month
-PASS change state from range to week
-PASS change state from color to month
-PASS change state from color to week
-PASS change state from checkbox to month
-PASS change state from checkbox to week
-PASS change state from radio to month
-PASS change state from radio to week
-PASS change state from file to month
-PASS change state from file to week
-PASS change state from submit to month
-PASS change state from submit to week
-PASS change state from image to month
-PASS change state from image to week
-PASS change state from reset to month
-PASS change state from reset to week
-PASS change state from button to month
-PASS change state from button to week
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/per-global.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/per-global.window-expected.txt
index 9b493c4..d4cf47b 100644
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/per-global.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/per-global.window-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
-PASS Discarding the browsing context must not change window.navigator
 FAIL Navigating from the initial about:blank must not replace window.navigator assert_equals: expected object "[object Navigator]" but got object "[object Navigator]"
-PASS document.open() must replace window.navigator
-PASS Discarding the browsing context must not change window.clientInformation
+PASS Discarding the browsing context must not change window.navigator
+PASS document.open() must not replace window.navigator
 FAIL Navigating from the initial about:blank must not replace window.clientInformation assert_equals: expected object "[object Navigator]" but got object "[object Navigator]"
-PASS document.open() must replace window.clientInformation
+PASS Discarding the browsing context must not change window.clientInformation
+PASS document.open() must not replace window.clientInformation
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/lint.ignore b/third_party/blink/web_tests/external/wpt/lint.ignore
index 95288fc5..dd3f7b6 100644
--- a/third_party/blink/web_tests/external/wpt/lint.ignore
+++ b/third_party/blink/web_tests/external/wpt/lint.ignore
@@ -201,7 +201,6 @@
 SET TIMEOUT: navigation-timing/*
 SET TIMEOUT: old-tests/submission/Microsoft/history/history_000.htm
 SET TIMEOUT: paint-timing/resources/subframe-painting.html
-SET TIMEOUT: page-unload-beacon/resources/pending_beacon-helper.js
 SET TIMEOUT: performance-timeline/resources/navigation-id-detached-frame-page.html
 SET TIMEOUT: portals/resources/portals-adopt-predecessor-portal.html
 SET TIMEOUT: preload/single-download-preload.html
@@ -229,6 +228,7 @@
 SET TIMEOUT: shadow-dom/slotchange-event.html
 SET TIMEOUT: trusted-types/block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.tentative.html
 SET TIMEOUT: trusted-types/DOMWindowTimers-setTimeout-setInterval.tentative.html
+SET TIMEOUT: unload-beacon/resources/pending_beacon-helper.js
 SET TIMEOUT: user-timing/*
 SET TIMEOUT: web-animations/crashtests/reparent-animating-element-002.html
 SET TIMEOUT: web-animations/timing-model/animations/*
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/META.yml b/third_party/blink/web_tests/external/wpt/page-unload-beacon/META.yml
deleted file mode 100644
index 18b08c1..0000000
--- a/third_party/blink/web_tests/external/wpt/page-unload-beacon/META.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-spec: https://clelland.github.io/page-unload-beacon/spec.html
-suggested_reviewers:
-  - clelland
diff --git a/third_party/blink/web_tests/external/wpt/reporting/reporting-api-honors-limits.https.sub.html b/third_party/blink/web_tests/external/wpt/reporting/reporting-api-honors-limits.https.sub.html
new file mode 100644
index 0000000..4732711
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/reporting/reporting-api-honors-limits.https.sub.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<html>
+<head>
+  <title>Test that the report-api honors buffer limits on a per-report type basis</title>
+  <link rel="author" title="Brent Fulgham" href="bfulgham@apple.com">
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+  <script src="/resources/testdriver.js"></script>
+  <script src="/resources/testdriver-vendor.js"></script>
+</head>
+<body>
+  <script>
+    var t1 = async_test("Test that image does not load");
+
+    promise_test(async function() {
+      for (let i = 0; i < 110; ++i)
+        await test_driver.generate_test_report("" + i);
+    }, "Buffer filled");
+
+    async_test(function(t2) {
+      window.addEventListener("securitypolicyviolation", t2.step_func(function(e) {
+        assert_equals(e.blockedURI, "{{location[scheme]}}://{{location[host]}}/reporting/support/fail.png");
+        assert_equals(e.violatedDirective, "img-src");
+        t2.done();
+      }));
+    }, "Event is fired");
+
+    promise_test(async function(test) {
+      const cspReports = await new Promise(resolve => {
+          let observer = new ReportingObserver(resolve, {types:["csp-violation"], buffered:true});
+          observer.observe();
+      });
+
+      // WebKit generates two CSP reports for the blocked image load (https://bugs.webkit.org/show_bug.cgi?id=153162)
+      assert_true(cspReports.length > 0 && cspReports.length < 3);
+
+      // Ensure that the contents of the report are valid.
+      assert_equals(cspReports[0].type, "csp-violation");
+    }, "CSP Report limits were honored");
+
+    promise_test(async function(test) {
+      const testReports = await new Promise(resolve => {
+          let observer = new ReportingObserver(resolve, {types:["test"], buffered:true});
+          observer.observe();
+      });
+
+      assert_equals(testReports.length, 100);
+
+      for (let i = 0; i < 100; ++i) {
+        assert_equals(testReports[i].type, "test");
+        assert_equals(testReports[i].body.message, "" + (i + 10));
+      }
+    }, "Test Report limits were honored");
+
+    promise_test(async function(test) {
+      const allReports = await new Promise(resolve => {
+          let observer = new ReportingObserver(resolve, {buffered:true});
+          observer.observe();
+      });
+
+      // WebKit generates two CSP reports for the blocked image load (https://bugs.webkit.org/show_bug.cgi?id=153162)
+      // Other browsers produce only one.
+      assert_true(allReports.length >= 101 && allReports.length <= 102);
+    }, "Combined report limits were honored");
+  </script>
+  <img src='/reporting/support/fail.png'
+       onload='t1.unreached_func("The image should not have loaded");'
+       onerror='t1.done();'>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/reporting/reporting-api-honors-limits.https.sub.html.sub.headers b/third_party/blink/web_tests/external/wpt/reporting/reporting-api-honors-limits.https.sub.html.sub.headers
new file mode 100644
index 0000000..3767884
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/reporting/reporting-api-honors-limits.https.sub.html.sub.headers
@@ -0,0 +1,7 @@
+Expires: Mon, 26 Jul 1997 05:00:00 GMT
+Cache-Control: no-store, no-cache, must-revalidate
+Cache-Control: post-check=0, pre-check=0, false
+Pragma: no-cache
+Set-Cookie: reporting-api-honors-limits={{$id:uuid()}}; Path=/reporting
+Reporting-Endpoints: csp-group="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?op=put&reportID={{$id}}"
+Content-Security-Policy: script-src 'self' 'unsafe-inline'; img-src 'none'; report-to csp-group
diff --git a/third_party/blink/web_tests/external/wpt/resources/idlharness-shadowrealm.js b/third_party/blink/web_tests/external/wpt/resources/idlharness-shadowrealm.js
index 05c4a1a..9484ca6 100644
--- a/third_party/blink/web_tests/external/wpt/resources/idlharness-shadowrealm.js
+++ b/third_party/blink/web_tests/external/wpt/resources/idlharness-shadowrealm.js
@@ -21,11 +21,6 @@
  *      dependency (i.e. have already been seen).
  */
 function idl_test_shadowrealm(srcs, deps) {
-    const script_urls = [
-        "/resources/testharness.js",
-        "/resources/WebIDLParser.js",
-        "/resources/idlharness.js",
-    ];
     promise_setup(async t => {
         const realm = new ShadowRealm();
         // https://github.com/web-platform-tests/wpt/issues/31996
@@ -38,44 +33,29 @@
                 isShadowRealm: function() { return true; },
             }; undefined;
         `);
-
-        const ss = await Promise.all(script_urls.map(url => fetch_text(url)));
-        for (const s of ss) {
-            realm.evaluate(s);
-        }
         const specs = await Promise.all(srcs.concat(deps).map(spec => {
             return fetch_text("/interfaces/" + spec + ".idl");
         }));
         const idls = JSON.stringify(specs);
-
-        const results = JSON.parse(await new Promise(
-          realm.evaluate(`(resolve,reject) => {
-              const idls = ${idls};
-              add_completion_callback(function (tests, harness_status, asserts_run) {
-                resolve(JSON.stringify(tests));
-              });
-
-              // Without the wrapping test, testharness.js will think it's done after it has run
-              // the first idlharness test.
-              test(() => {
-                  const idl_array = new IdlArray();
-                  for (let i = 0; i < ${srcs.length}; i++) {
-                      idl_array.add_idls(idls[i]);
-                  }
-                  for (let i = ${srcs.length}; i < ${srcs.length + deps.length}; i++) {
-                      idl_array.add_dependency_idls(idls[i]);
-                  }
-                  idl_array.test();
-              }, "setup");
-          }`)
-        ));
-
-        // We ran the tests in the ShadowRealm and gathered the results. Now treat them as if
-        // we'd run them directly here, so we can see them.
-        for (const {name, status, message} of results) {
-            // TODO: make this an API in testharness.js - needs RFC?
-            promise_test(t => {t.set_status(status, message); t.phase = t.phases.HAS_RESULT; t.done()}, name);
-        }
-    }, "outer setup");
+        await new Promise(
+            realm.evaluate(`(resolve,reject) => {
+                (async () => {
+                    await import("/resources/testharness.js");
+                    await import("/resources/WebIDLParser.js");
+                    await import("/resources/idlharness.js");
+                    const idls = ${idls};
+                    const idl_array = new IdlArray();
+                    for (let i = 0; i < ${srcs.length}; i++) {
+                        idl_array.add_idls(idls[i]);
+                    }
+                    for (let i = ${srcs.length}; i < ${srcs.length + deps.length}; i++) {
+                        idl_array.add_dependency_idls(idls[i]);
+                    }
+                    idl_array.test();
+                })().then(resolve, (e) => reject(e.toString()));
+            }`)
+        );
+        await fetch_tests_from_shadow_realm(realm);
+    });
 }
 // vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker:
diff --git a/third_party/blink/web_tests/external/wpt/resources/testharness.js b/third_party/blink/web_tests/external/wpt/resources/testharness.js
index 9ec32822..423108e 100644
--- a/third_party/blink/web_tests/external/wpt/resources/testharness.js
+++ b/third_party/blink/web_tests/external/wpt/resources/testharness.js
@@ -3871,7 +3871,7 @@
      */
     function begin_shadow_realm_tests(postMessage) {
         if (!(test_environment instanceof ShadowRealmTestEnvironment)) {
-            throw new Error("beign_shadow_realm_tests called in non-Shadow Realm environment");
+            throw new Error("begin_shadow_realm_tests called in non-Shadow Realm environment");
         }
 
         test_environment.begin(function (msg) {
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml b/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml
index 8f5bd75..b8c0b97 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml
@@ -2,3 +2,4 @@
 suggested_reviewers:
   - marcoscaceres
   - cdumez
+  - michaelwasserman
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/active-lock.html b/third_party/blink/web_tests/external/wpt/screen-orientation/active-lock.html
index 84fb603..f71d5f0 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/active-lock.html
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/active-lock.html
@@ -4,22 +4,17 @@
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
 <p id="#fragment"></p>
-<script>
-  promise_test(async t => {
-    await test_driver.bless("request full screen", () => {
-      return document.documentElement.requestFullscreen();
-    });
-    const fragment = document.createElement("p");
-    fragment.id = "fragment";
-    document.body.appendChild(fragment);
-    const { type: preType } = screen.orientation;
-    const isPortrait = preType.startsWith("portrait");
-    const newType = `${isPortrait ? "landscape" : "portrait"}-primary`;
-    const p = screen.orientation.lock(newType);
-    screen.orientation.onchange = t.unreached_func(
-      "change event must not fire"
-    );
+<script type="module">
+  import { makeCleanup } from "./resources/orientation-utils.js";
+  promise_test(async (t) => {
+    t.add_cleanup(makeCleanup());
+    await test_driver.bless("request full screen");
+    await document.documentElement.requestFullscreen();
+    const orientation = screen.orientation.type.startsWith("portrait")
+      ? "landscape"
+      : "portrait";
+    const p = screen.orientation.lock(orientation);
     window.location.href = "#fragment";
     await p;
-  }, "When performing a fragment navigation, the orientation must not change or unlock");
+  }, "When performing a fragment navigation, the change must not abort");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/lock-basic.html b/third_party/blink/web_tests/external/wpt/screen-orientation/lock-basic.html
index 1ae26567..71c8e8e 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/lock-basic.html
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/lock-basic.html
@@ -90,10 +90,10 @@
   });
   const preType = screen.orientation.type;
   const isPortrait = preType.includes("portrait");
-  const newType = `${ isPortrait ? "landscape" : "portrait" }-primary`;
+  const newType = `${ isPortrait ? "landscape" : "portrait" }`;
   const p = screen.orientation.lock(newType);
   assert_equals(screen.orientation.type, preType, "Must not change orientation until next spin of event loop");
   await p;
-  assert_equals(screen.orientation.type, newType);
+  assert_true(screen.orientation.type.startsWith(newType), `Expected type to start with ${newType}`);
 }, "Test that screen.orientation.lock() is actually async");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/lock-sandboxed-iframe.html b/third_party/blink/web_tests/external/wpt/screen-orientation/lock-sandboxed-iframe.html
index b8b856dc..1ce1039 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/lock-sandboxed-iframe.html
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/lock-sandboxed-iframe.html
@@ -35,8 +35,8 @@
 }, "Test without 'allow-orientation-lock' sandboxing directive");
 
 promise_test(async t => {
-  const disallowedIframe = document.getElementById("allowedIframe");
-  disallowedIframe.src = "resources/sandboxed-iframe-locking.html";
+  const allowedIframe = document.getElementById("allowedIframe");
+  allowedIframe.src = "resources/sandboxed-iframe-locking.html";
 
   const message = await wait_result();
 
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/non-fully-active.html b/third_party/blink/web_tests/external/wpt/screen-orientation/non-fully-active.html
new file mode 100644
index 0000000..61066eb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/non-fully-active.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<body>
+<script>
+  async function attachIFrame() {
+    const iframe = document.createElement("iframe");
+    document.body.appendChild(iframe);
+    await new Promise((resolve) => {
+      iframe.onload = resolve;
+      iframe.src = "about:blank";
+    });
+    return iframe;
+  }
+
+  promise_test(async (t) => {
+    const iframe = await attachIFrame();
+    const { orientation } = iframe.contentWindow.screen;
+    const opposite = orientation.type.startsWith("portrait")
+      ? "landscape"
+      : "portrait";
+
+    const frameDOMException = iframe.contentWindow.DOMException;
+    iframe.remove();
+
+    await promise_rejects_dom(
+      t,
+      "InvalidStateError",
+      frameDOMException,
+      orientation.lock(opposite)
+    );
+  }, "Attempting to lock non-fully active documents results in a InvalidStateError");
+
+  promise_test(async (t) => {
+    const iframe = await attachIFrame();
+    const { orientation } = iframe.contentWindow.screen;
+
+    const frameDOMException = iframe.contentWindow.DOMException;
+    iframe.remove();
+
+    assert_throws_dom("InvalidStateError", frameDOMException, () => { orientation.unlock() });
+  }, "Attempting to unlock non-fully active documents results in a InvalidStateError");
+
+  promise_test(async (t) => {
+    const iframe = await attachIFrame();
+    const { orientation } = iframe.contentWindow.screen;
+
+    const opposite = orientation.type.startsWith("portrait")
+      ? "landscape"
+      : "portrait";
+
+    await test_driver.bless("request full screen", null, iframe.contentWindow);
+    await iframe.contentDocument.documentElement.requestFullscreen();
+
+    const p = orientation.lock(opposite);
+
+    const frameDOMException = iframe.contentWindow.DOMException;
+    iframe.remove();
+
+    await promise_rejects_dom(t, "AbortError", frameDOMException, p);
+    assert_throws_dom("InvalidStateError", frameDOMException, () => { orientation.unlock() });
+  }, "Making a document non-fully active while locking results in an AbortError");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event-expected.txt b/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event-expected.txt
index 76af39c..eb540f7 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL Test that orientationchange event is not fired when the orientation does not change. promise_test: Unhandled rejection with value: object "ReferenceError: test_driver is not defined"
-FAIL Test that orientationchange event is fired when the orientation changes. promise_test: Unhandled rejection with value: object "ReferenceError: test_driver is not defined"
+PASS Test that orientationchange event is not fired when the orientation does not change.
+FAIL Test that orientationchange event is fired when the orientation changes. assert_true: The event must be fired first. expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event-subframe.html b/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event-subframe.html
index 0ba0edc..4295e3f5 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event-subframe.html
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event-subframe.html
@@ -24,10 +24,8 @@
       return document.documentElement.requestFullscreen();
     });
     let orientations = [
-      "portrait-primary",
-      "portrait-secondary",
-      "landscape-primary",
-      "landscape-secondary",
+      "portrait",
+      "landscape",
     ];
     if (screen.orientation.type.includes("portrait")) {
       orientations = orientations.reverse();
@@ -37,9 +35,8 @@
     for (const orientation of orientations) {
       await screen.orientation.lock(orientation);
       const message = await messageWatcher.wait_for("message");
-      assert_equals(
-        message.data,
-        orientation,
+      assert_true(
+        message.data.startsWith(orientation),
         "subframe receives orientation change event"
       );
     }
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event.html b/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event.html
index ebe002d9..9c416eb 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event.html
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/onchange-event.html
@@ -9,14 +9,15 @@
     try {
       await document.exitFullscreen();
     } catch (e) {}
+    screen.orientation.unlock();
   });
   await test_driver.bless("request full screen", () => {
     return document.documentElement.requestFullscreen();
   });
-  const type = screen.orientation.type;
+  const type = screen.orientation.type.startsWith("portrait") ? "portrait" : "landscape";
   screen.orientation.onchange = t.unreached_func("change event should not be fired");
   await screen.orientation.lock(type);
-  assert_equals(screen.orientation.type, type);
+  assert_true(screen.orientation.type.startsWith(type));
 }, "Test that orientationchange event is not fired when the orientation does not change.");
 
 promise_test(async t => {
@@ -30,22 +31,24 @@
     return document.documentElement.requestFullscreen();
   });
   let orientations = [
-    'portrait-primary',
-    'portrait-secondary',
-    'landscape-primary',
-    'landscape-secondary'
+    'portrait',
+    'landscape',
   ];
-  if (screen.orientation.type.includes('portrait')) {
+  if (screen.orientation.type.startsWith('portrait')) {
     orientations = orientations.reverse();
   }
   const orientationWatcher = new EventWatcher(t, screen.orientation, 'change');
 
   for (const orientation of orientations) {
     // change event is fired before resolving promise by lock.
-    const promise = screen.orientation.lock(orientation);
-    await orientationWatcher.wait_for('change');
-    await promise;
-    assert_equals(screen.orientation.type, orientation);
+    let lockPromise = screen.orientation.lock(orientation);
+    const result = await Promise.race([
+      lockPromise,
+      orientationWatcher.wait_for('change'),
+    ]);
+    assert_true(result instanceof Event, "The event must be fired first.");
+    assert_true(screen.orientation.type.startsWith(orientation), "The orientation must match");
+    await lockPromise;
   }
 }, "Test that orientationchange event is fired when the orientation changes.");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/orientation-reading.html b/third_party/blink/web_tests/external/wpt/screen-orientation/orientation-reading.html
index 7e6182c6..fdf05c8 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/orientation-reading.html
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/orientation-reading.html
@@ -31,7 +31,12 @@
   await test_driver.bless("request full screen", () => {
     return document.documentElement.requestFullscreen();
   });
-  await screen.orientation.lock("portrait-primary");
+  try {
+    await screen.orientation.lock("portrait-primary");
+  } catch (err) {
+    // implementation might not support locking to portrait-primary
+    return;
+  }
   const orientations =
     screen.orientation.angle === 0
       ? {
@@ -44,20 +49,35 @@
           primaryOrientation2: "portrait-primary",
           secondaryOrientation2: "portrait-secondary",
         };
-  await screen.orientation.lock(orientations.secondaryOrientation1);
+  try {
+    await screen.orientation.lock(orientations.secondaryOrientation1);
+  } catch (err) {
+    // implementation might not support locking to this orientation
+    return;
+  }
   assert_equals(
     screen.orientation.angle,
     180,
     "Secondary orientation 1 angle must be 180"
   );
-  await screen.orientation.lock(orientations.primaryOrientation2);
+  try {
+    await screen.orientation.lock(orientations.primaryOrientation2);
+  } catch (err) {
+    // implementation might not support locking to this orientation
+    return;
+  }
   assert_true(
     screen.orientation.angle == 90 || screen.orientation.angle == 270,
     "Primary orientation 2 angle must be either 90 or 270"
   );
   const primaryOrientation2Angle = screen.orientation.angle;
   const secondaryOrientation2Angle = primaryOrientation2Angle === 90 ? 270 : 90;
-  await screen.orientation.lock(orientations.secondaryOrientation2);
+  try {
+    await screen.orientation.lock(orientations.secondaryOrientation2);
+  } catch (err) {
+    // implementation might not support locking to this orientation
+    return;
+  }
   assert_equals(
     screen.orientation.angle,
     secondaryOrientation2Angle,
@@ -97,8 +117,8 @@
   const orientationWatcher = new EventWatcher(t, orientation, "change");
 
   const newOrientationType =
-    orientationType.includes("portrait") ? "landscape-primary" :
-                                           "portrait-primary";
+    orientationType.includes("portrait") ? "landscape" :
+                                           "portrait";
   const promise = orientation.lock(newOrientationType);
 
   // change event is fired before resolving promise by lock.
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/empty.html b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/empty.html
new file mode 100644
index 0000000..0e76edd6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/empty.html
@@ -0,0 +1 @@
+<!DOCTYPE html>
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/iframe-listen-orientation-change.html b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/iframe-listen-orientation-change.html
index 4cfd37d..68a67f8 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/iframe-listen-orientation-change.html
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/iframe-listen-orientation-change.html
@@ -1,5 +1,9 @@
 <script>
-window.screen.orientation.addEventListener('change', () => {
-  parent.window.postMessage(screen.orientation.type, "*");
-});
+  try {
+    window.screen.orientation.addEventListener("change", () => {
+      parent.window.postMessage(screen.orientation.type, "*");
+    });
+  } catch (err) {
+    parent.window.postMessage(err.message, "*");
+  }
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js
index 85be16c..f2fb045f 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js
@@ -15,3 +15,15 @@
   const isPortrait = currentOrientation.includes("portrait");
   return isPortrait ? "landscape" : "portrait";
 }
+
+export function makeCleanup(initialOrientation = screen.orientation?.type.split(/-/)[0]) {
+  return async () => {
+    if (initialOrientation) {
+      await screen.orientation.lock(initialOrientation);
+    }
+    screen.orientation.unlock();
+    requestAnimationFrame(async () => {
+      await document.exitFullscreen();
+    });
+  }
+}
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/sandboxed-iframe-locking.html b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/sandboxed-iframe-locking.html
index 9e305a0..7f5496b3 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/sandboxed-iframe-locking.html
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/sandboxed-iframe-locking.html
@@ -5,17 +5,17 @@
 test_driver.set_test_context(parent);
 
 // At first, run simple unlock test without lock.
-screen.orientation.unlock();
+screen.orientation?.unlock();
 
 test_driver.bless("request full screen", async () => {
-  await document.documentElement.requestFullscreen();
 
   let msg = "";
   try {
-    await screen.orientation.lock("portrait-primary")
+    await document.documentElement.requestFullscreen();
+    await screen.orientation.lock("portrait")
     msg = screen.orientation.type;
   } catch (error) {
-    msg = error.name;
+    msg = `error: ${error.name} ${error.message}`;
   }
 
   try {
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-timeline-named-scroll-progress-timeline.tentative.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-timeline-named-scroll-progress-timeline.tentative.html
index b31e402..408f62f8 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-timeline-named-scroll-progress-timeline.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/animation-timeline-named-scroll-progress-timeline.tentative.html
@@ -257,6 +257,7 @@
   // Ensure that #main (an ancestor of the scroller) needs style recalc.
   main.style.background = 'lightgray';
   sibling.style.scrollTimelineName = 'timeline';
+  await waitForNextFrame();
   assert_equals(getComputedStyle(target).translate, '100px');
 
   main.remove();
@@ -301,6 +302,7 @@
 
   scroller.style.scrollTimelineName = 'timeline';
   target.style.animation = 'anim 10s linear timeline';
+  await waitForNextFrame();
 
   assert_equals(getComputedStyle(target).translate, '100px');
 
@@ -351,6 +353,7 @@
 
   scroller.style.scrollTimelineName = 'timeline';
   target.style.animation = 'anim 10s linear timeline';
+  await waitForNextFrame();
 
   assert_equals(getComputedStyle(target).translate, '100px');
 
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/progress-based-animation-animation-longhand-properties.tentative.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/progress-based-animation-animation-longhand-properties.tentative.html
index 43401aca..17604e5 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/progress-based-animation-animation-longhand-properties.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/progress-based-animation-animation-longhand-properties.tentative.html
@@ -104,10 +104,12 @@
 
   // Let animation become 50% in the 1st iteration.
   target.style.animationIterationCount = '2';
+  await waitForNextFrame();
   assert_equals(getComputedStyle(target).translate, '50px');
 
   // Let animation become 0% in the 2nd iteration.
   target.style.animationIterationCount = '4';
+  await waitForNextFrame();
   assert_equals(getComputedStyle(target).translate, '0px');
 }, 'animation-iteration-count');
 
@@ -217,6 +219,7 @@
 
   await scrollTop(scroller, 20); // [0, 100].
   target.style.animationDelay = '-5s';
+  await waitForNextFrame();
   assert_equals(getComputedStyle(target).translate, '60px');
 }, 'animation-delay with a negative value');
 
@@ -234,6 +237,7 @@
   assert_equals(getComputedStyle(target).translate, 'none');
 
   target.style.animationFillMode = 'backwards';
+  await waitForNextFrame();
   assert_equals(getComputedStyle(target).translate, '0px');
 }, 'animation-fill-mode');
 
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-default-iframe-print.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-default-iframe-print.html
index fc8e4f1..6349622 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-default-iframe-print.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-default-iframe-print.html
@@ -5,6 +5,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-animations-2/#animation-timeline">
 <meta name="assert" content="CSS animation correctly updates values when using the default scroll() timeline">
 <link rel="match" href="scroll-timeline-default-iframe-ref.html">
+<meta name="fuzzy" content="25;100">
 
 <iframe id="target" width="400" height="400" srcdoc='
   <html>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-document-scroller-quirks.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-document-scroller-quirks.html
new file mode 100644
index 0000000..ca40161
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-document-scroller-quirks.html
@@ -0,0 +1,26 @@
+<!-- Quirks mode -->
+<title>Tests the document scroller in quirks mode</title>
+<link rel="help" href="https://drafts.csswg.org/scroll-animations-1/#scroll-notation">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1180575">
+<link rel="author" href="mailto:andruud@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/scroll-animations/scroll-timelines/testcommon.js"></script>
+<script src="/css/css-animations/support/testcommon.js"></script>
+<style>
+  @keyframes anim {
+    from { z-index: 100; }
+    to { z-index: 100; }
+  }
+  #element {
+    animation: anim forwards scroll(root);
+  }
+</style>
+<div id=element></div>
+
+<script>
+promise_test(async () => {
+  await waitForNextFrame();
+  assert_equals(getComputedStyle(element).zIndex, "100");
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-dynamic.tentative.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-dynamic.tentative.html
index 7bf35cd..c827d10 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-dynamic.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-dynamic.tentative.html
@@ -71,6 +71,7 @@
     // Verify that the computed style is as expected immediately after the
     // rule change took place.
     instantiate(async (element, expected) => {
+      await waitForNextFrame();
       assert_equals(getComputedStyle(element).width, expected);
     }, description + ' [immediate]');
 
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-in-container-query.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-in-container-query.html
index f74fa59..0c216c7 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-in-container-query.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-in-container-query.html
@@ -60,8 +60,9 @@
     assert_equals(getComputedStyle(element).backgroundColor, 'rgb(100, 100, 100)');
     // This causes the timeline to be created.
     outer.style.width = '250px';
-    // Check value with getComputedStyle immediately.
-    assert_equals(getComputedStyle(element).backgroundColor, 'rgb(150, 150, 150)');
+    // Check value with getComputedStyle immediately, which is the unanimated
+    // value since the scroll timeline is inactive before the next frame.
+    assert_equals(getComputedStyle(element).backgroundColor, 'rgb(0, 0, 0)');
     // Also check value after one frame.
     await waitForNextFrame();
     assert_equals(getComputedStyle(element).backgroundColor, 'rgb(150, 150, 150)');
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-paused-animations.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-paused-animations.html
index a8117fa..b7611fb 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-paused-animations.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-paused-animations.html
@@ -36,6 +36,8 @@
   t.add_cleanup(resetScrollPosition);
 
   div.style.animation = 'anim 100s linear paused scroll(root)';
+  await waitForNextFrame();
+
   const anim = div.getAnimations()[0];
   await anim.ready;
   assert_percents_equal(anim.currentTime, 0, 'timeline time reset');
@@ -55,6 +57,8 @@
   await waitForNextFrame();
 
   div.style.animation = 'anim 100s linear forwards scroll(root)';
+  await waitForNextFrame();
+
   const anim = div.getAnimations()[0];
   await anim.ready;
   assert_percents_equal(anim.currentTime, 0, 'timeline time reset');
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-responsiveness-from-endpoint.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-responsiveness-from-endpoint.html
index 5555fd0..180704ee 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-responsiveness-from-endpoint.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-responsiveness-from-endpoint.html
@@ -32,6 +32,8 @@
   await waitForNextFrame();
 
   div.style.animation = 'anim 100s linear scroll(root)';
+  await waitForNextFrame();
+
   const anim = div.getAnimations()[0];
   await anim.ready;
   assert_percents_equal(anim.timeline.currentTime, 0,
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-sibling-gcs.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-sibling-gcs.html
index 21d5b8c..8500b39 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-sibling-gcs.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/scroll-timeline-sibling-gcs.html
@@ -42,6 +42,7 @@
     // Unknown timeline, time held at zero.
     assert_equals(getComputedStyle(element).backgroundColor, 'rgb(100, 100, 100)');
     scroller.style.scrollTimeline = 'timeline';
+    await waitForNextFrame();
     assert_equals(getComputedStyle(element).backgroundColor, 'rgb(150, 150, 150)');
   }, 'Timelines appearing on preceding siblings are visible to getComputedStyle');
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-dynamic.html b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-dynamic.html
index 483fa36..545e735 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-dynamic.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/view-timeline-dynamic.html
@@ -63,14 +63,17 @@
 
     // scrollTop=50 is 75% for div75.
     div75.classList.add('timeline');
+    await waitForNextFrame();
     assert_equals(getComputedStyle(target).zIndex, '75');
 
     // scrollTop=50 is 25% for div25.
     div25.classList.add('timeline');
+    await waitForNextFrame();
     assert_equals(getComputedStyle(target).zIndex, '25');
 
     // scrollTop=50 is before the timeline start for div_before.
     div_before.classList.add('timeline');
+    await waitForNextFrame();
     assert_equals(getComputedStyle(target).zIndex, '-1');
     // Scroll to 25% (for div_before) to verify that we're linked to that
     // timeline.
@@ -80,6 +83,7 @@
     // Now we should be back to div25's timeline, although with the new
     // scrollTop=150, it's actually at 75%.
     div_before.classList.remove('timeline');
+    await waitForNextFrame();
     assert_equals(getComputedStyle(target).zIndex, '75');
   }, 'Dynamically changing view-timeline-name');
 </script>
@@ -110,6 +114,7 @@
 
     assert_equals(getComputedStyle(target).zIndex, '25');
     timeline.style.viewTimelineAxis = 'horizontal';
+    await waitForNextFrame();
     assert_equals(getComputedStyle(target).zIndex, '10');
   }, 'Dynamically changing view-timeline-axis');
 </script>
@@ -139,6 +144,7 @@
 
     assert_equals(getComputedStyle(target).zIndex, '25');
     timeline.style.viewTimelineInset = '0px 50px';
+    await waitForNextFrame();
     assert_equals(getComputedStyle(target).zIndex, '0');
   }, 'Dynamically changing view-timeline-inset');
 </script>
@@ -167,4 +173,4 @@
     timeline.style.display = 'none';
     assert_equals(getComputedStyle(target).zIndex, '-1');
   }, 'Element with view-timeline becoming display:none');
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInFill-01-expected.txt b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInFill-01-expected.txt
index 0aade2c..2f0e784 100644
--- a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInFill-01-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInFill-01-expected.txt
@@ -1,10 +1,10 @@
 This is a testharness.js-based test.
 FAIL SVGGeometryElement.prototype.isPointInFill, no arguments. Failed to execute 'isPointInFill' on 'SVGGeometryElement': 1 argument required, but only 0 present.
-PASS SVGGeometryElement.prototype.isPointInFill, non-finite argument.
-PASS SVGGeometryElement.prototype.isPointInFill, functional test.
-PASS SVGGeometryElement.prototype.isPointInFill, points on the shape boundary are inside.
-PASS SVGGeometryElement.prototype.isPointInFill, 'fill-rule'.
-PASS SVGGeometryElement.prototype.isPointInFill, 'visibility' and 'pointer-events' have no effect.
-PASS SVGGeometryElement.prototype.isPointInFill, 'clip-rule' never overrides 'fill-rule'.
+FAIL SVGGeometryElement.prototype.isPointInFill, non-finite argument. Failed to execute 'isPointInFill' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInFill, functional test. Failed to execute 'isPointInFill' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInFill, points on the shape boundary are inside. adaptPoint is not defined
+FAIL SVGGeometryElement.prototype.isPointInFill, 'fill-rule'. Failed to execute 'isPointInFill' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInFill, 'visibility' and 'pointer-events' have no effect. Failed to execute 'isPointInFill' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInFill, 'clip-rule' never overrides 'fill-rule'. Failed to execute 'isPointInFill' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInFill-01.svg b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInFill-01.svg
index 326c5229..3fdeee21 100644
--- a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInFill-01.svg
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInFill-01.svg
@@ -25,16 +25,6 @@
   <script><![CDATA[
     'use strict';
 
-    setup(function() {
-      window.myPoint = document.documentElement.createSVGPoint();
-    });
-
-    function adaptPoint(point) {
-      myPoint.x = point.x;
-      myPoint.y = point.y;
-      return myPoint;
-    }
-
     const pointsToTest = [
       { x: 150, y: 150 },
       { x: 275, y: 150 },
@@ -45,13 +35,13 @@
     function testPoints(element) {
       const expected = [true, true, true, false, false];
       pointsToTest.forEach(function(point, index) {
-        assert_equals(element.isPointInFill(adaptPoint(point)),
+        assert_equals(element.isPointInFill(point),
                       expected[index], "point at " + point.x + ", " + point.y);
       });
     }
     function testResultVector(element) {
       return pointsToTest.map(function(point) {
-        return element.isPointInFill(adaptPoint(point));
+        return element.isPointInFill(point);
       });
     }
 
@@ -64,12 +54,12 @@
 
     test(function() {
       let circleAtOrigin = document.getElementById("circle-at-origin");
-      assert_false(circleAtOrigin.isPointInFill(adaptPoint({ x: NaN, y: 0 })), "x is NaN");
-      assert_false(circleAtOrigin.isPointInFill(adaptPoint({ x: Infinity, y: 0 })), "x is Infinity");
-      assert_false(circleAtOrigin.isPointInFill(adaptPoint({ x: -Infinity, y: 0 })), "x is -Infinity");
-      assert_false(circleAtOrigin.isPointInFill(adaptPoint({ x: 0, y: NaN })), "y is NaN");
-      assert_false(circleAtOrigin.isPointInFill(adaptPoint({ x: 0, y: Infinity })), "y is Infinity");
-      assert_false(circleAtOrigin.isPointInFill(adaptPoint({ x: 0, y: -Infinity })), "y is -Infinity");
+      assert_false(circleAtOrigin.isPointInFill({ x: NaN, y: 0 }), "x is NaN");
+      assert_false(circleAtOrigin.isPointInFill({ x: Infinity, y: 0 }), "x is Infinity");
+      assert_false(circleAtOrigin.isPointInFill({ x: -Infinity, y: 0 }), "x is -Infinity");
+      assert_false(circleAtOrigin.isPointInFill({ x: 0, y: NaN }), "y is NaN");
+      assert_false(circleAtOrigin.isPointInFill({ x: 0, y: Infinity }), "y is Infinity");
+      assert_false(circleAtOrigin.isPointInFill({ x: 0, y: -Infinity }), "y is -Infinity");
     }, document.title + ", non-finite argument.");
 
     test(function() {
@@ -98,9 +88,9 @@
 
     test(function() {
       let evenOdd = document.getElementById("rectangular-outline-evenodd");
-      assert_false(evenOdd.isPointInFill(adaptPoint({ x: 250, y: 250 })));
+      assert_false(evenOdd.isPointInFill({ x: 250, y: 250 }));
       let nonZeroWinding = document.getElementById("rectangular-outline-nonzero");
-      assert_true(nonZeroWinding.isPointInFill(adaptPoint({ x: 360, y: 250 })));
+      assert_true(nonZeroWinding.isPointInFill({ x: 360, y: 250 }));
     }, document.title + ", 'fill-rule'.");
 
     test(function() {
@@ -128,7 +118,7 @@
 
     test(function() {
       let nonZeroWinding = document.getElementById("rectangular-outline-nonzero-in-clip");
-      assert_true(nonZeroWinding.isPointInFill(adaptPoint({ x: 250, y: 250 })));
+      assert_true(nonZeroWinding.isPointInFill({ x: 250, y: 250 }));
     }, document.title + ", 'clip-rule' never overrides 'fill-rule'.");
     ]]></script>
 </svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInStroke-01-expected.txt b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInStroke-01-expected.txt
index ec8b928c..6d622c0 100644
--- a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInStroke-01-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInStroke-01-expected.txt
@@ -1,14 +1,14 @@
 This is a testharness.js-based test.
 FAIL SVGGeometryElement.prototype.isPointInStroke, no arguments. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': 1 argument required, but only 0 present.
-PASS SVGGeometryElement.prototype.isPointInStroke, non-finite argument.
-PASS SVGGeometryElement.prototype.isPointInStroke, functional test.
-PASS SVGGeometryElement.prototype.isPointInStroke, 'stroke-dasharray'.
-PASS SVGGeometryElement.prototype.isPointInStroke, 'stroke-dashoffset'.
-PASS SVGGeometryElement.prototype.isPointInStroke, 'stroke-miterlimit'.
-PASS SVGGeometryElement.prototype.isPointInStroke, 'stroke-linejoin'.
-PASS SVGGeometryElement.prototype.isPointInStroke, 'stroke-linecap'.
-PASS SVGGeometryElement.prototype.isPointInStroke, 'pathLength'.
-PASS SVGGeometryElement.prototype.isPointInStroke, 'vector-effect'.
-PASS SVGGeometryElement.prototype.isPointInStroke, 'visibility' and 'pointer-events' have no effect.
+FAIL SVGGeometryElement.prototype.isPointInStroke, non-finite argument. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInStroke, functional test. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInStroke, 'stroke-dasharray'. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInStroke, 'stroke-dashoffset'. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInStroke, 'stroke-miterlimit'. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInStroke, 'stroke-linejoin'. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInStroke, 'stroke-linecap'. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInStroke, 'pathLength'. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInStroke, 'vector-effect'. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
+FAIL SVGGeometryElement.prototype.isPointInStroke, 'visibility' and 'pointer-events' have no effect. Failed to execute 'isPointInStroke' on 'SVGGeometryElement': parameter 1 is not of type 'SVGPoint'.
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInStroke-01.svg b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInStroke-01.svg
index 5864c43..78ba96d 100644
--- a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInStroke-01.svg
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.isPointInStroke-01.svg
@@ -40,16 +40,6 @@
   <script><![CDATA[
     'use strict';
 
-    setup(function() {
-      window.myPoint = document.documentElement.createSVGPoint();
-    });
-
-    function adaptPoint(point) {
-      myPoint.x = point.x;
-      myPoint.y = point.y;
-      return myPoint;
-    }
-
     const pointsToTest = [
       { x: 275, y: 250 },  // outer stroke
       { x: 300, y: 200 },  // inner stroke
@@ -60,13 +50,13 @@
     function testPoints(element) {
       const expected = [true, true, false, false, false];
       pointsToTest.forEach(function(point, index) {
-        assert_equals(element.isPointInStroke(adaptPoint(point)),
+        assert_equals(element.isPointInStroke(point),
                       expected[index], "point at " + point.x + ", " + point.y);
       });
     }
     function testResultVector(element) {
       return pointsToTest.map(function(point) {
-        return element.isPointInStroke(adaptPoint(point));
+        return element.isPointInStroke(point);
       });
     }
 
@@ -79,12 +69,12 @@
 
     test(function() {
       let strokeAtOrigin = document.getElementById("circle-with-stroke-intersecting-origin");
-      assert_false(strokeAtOrigin.isPointInStroke(adaptPoint({ x: NaN, y: 0 }))), "x is NaN";
-      assert_false(strokeAtOrigin.isPointInStroke(adaptPoint({ x: Infinity, y: 0 })), "x is Infinity");
-      assert_false(strokeAtOrigin.isPointInStroke(adaptPoint({ x: -Infinity, y: 0 })), "x is -Infinity");
-      assert_false(strokeAtOrigin.isPointInStroke(adaptPoint({ x: 0, y: NaN })), "y is NaN");
-      assert_false(strokeAtOrigin.isPointInStroke(adaptPoint({ x: 0, y: Infinity })), "y is Infinity");
-      assert_false(strokeAtOrigin.isPointInStroke(adaptPoint({ x: 0, y: -Infinity })), "y is -Infinity");
+      assert_false(strokeAtOrigin.isPointInStroke({ x: NaN, y: 0 })), "x is NaN";
+      assert_false(strokeAtOrigin.isPointInStroke({ x: Infinity, y: 0 }), "x is Infinity");
+      assert_false(strokeAtOrigin.isPointInStroke({ x: -Infinity, y: 0 }), "x is -Infinity");
+      assert_false(strokeAtOrigin.isPointInStroke({ x: 0, y: NaN }), "y is NaN");
+      assert_false(strokeAtOrigin.isPointInStroke({ x: 0, y: Infinity }), "y is Infinity");
+      assert_false(strokeAtOrigin.isPointInStroke({ x: 0, y: -Infinity }), "y is -Infinity");
     }, document.title + ", non-finite argument.");
 
     test(function() {
@@ -93,45 +83,45 @@
 
     test(function() {
       let rectWithDashes = document.getElementById("rect-with-dash-array");
-      assert_true(rectWithDashes.isPointInStroke(adaptPoint({ x: 250, y: 48 })));
-      assert_false(rectWithDashes.isPointInStroke(adaptPoint({ x: 302, y: 100 })));
+      assert_true(rectWithDashes.isPointInStroke({ x: 250, y: 48 }));
+      assert_false(rectWithDashes.isPointInStroke({ x: 302, y: 100 }));
     }, document.title + ", 'stroke-dasharray'.");
 
     test(function() {
       let rectWithOffsetDashes = document.getElementById("rect-with-dash-offset");
-      assert_false(rectWithOffsetDashes.isPointInStroke(adaptPoint({ x: 250, y: 178 })));
-      assert_true(rectWithOffsetDashes.isPointInStroke(adaptPoint({ x: 302, y: 230 })));
+      assert_false(rectWithOffsetDashes.isPointInStroke({ x: 250, y: 178 }));
+      assert_true(rectWithOffsetDashes.isPointInStroke({ x: 302, y: 230 }));
     }, document.title + ", 'stroke-dashoffset'.");
 
     test(function() {
       let polyWithMiter = document.getElementById("poly-with-miter");
-      assert_true(polyWithMiter.isPointInStroke(adaptPoint({ x: 110, y: 320 })));
-      assert_false(polyWithMiter.isPointInStroke(adaptPoint({ x: 113, y: 320 })));
+      assert_true(polyWithMiter.isPointInStroke({ x: 110, y: 320 }));
+      assert_false(polyWithMiter.isPointInStroke({ x: 113, y: 320 }));
       let polyWithMiterLimit10 = document.getElementById("poly-with-miter-limit-10");
-      assert_true(polyWithMiterLimit10.isPointInStroke(adaptPoint({ x: 223, y: 320 })));
+      assert_true(polyWithMiterLimit10.isPointInStroke({ x: 223, y: 320 }));
     }, document.title + ", 'stroke-miterlimit'.");
 
     test(function() {
       let polyWithRoundJoin = document.getElementById("poly-with-linejoin-round");
-      assert_true(polyWithRoundJoin.isPointInStroke(adaptPoint({ x: 334, y: 320 })));
-      assert_false(polyWithRoundJoin.isPointInStroke(adaptPoint({ x: 336, y: 320 })));
+      assert_true(polyWithRoundJoin.isPointInStroke({ x: 334, y: 320 }));
+      assert_false(polyWithRoundJoin.isPointInStroke({ x: 336, y: 320 }));
     }, document.title + ", 'stroke-linejoin'.");
 
     test(function() {
       let lineWithRoundCap = document.getElementById("line-with-round-linecap");
-      assert_true(lineWithRoundCap.isPointInStroke(adaptPoint({ x: 25, y: 300 })));
+      assert_true(lineWithRoundCap.isPointInStroke({ x: 25, y: 300 }));
     }, document.title + ", 'stroke-linecap'.");
 
     test(function() {
       let rectWithPathLength = document.getElementById("rect-with-path-length");
-      assert_true(rectWithPathLength.isPointInStroke(adaptPoint({ x: 250, y: 308 })));
-      assert_false(rectWithPathLength.isPointInStroke(adaptPoint({ x: 250, y: 412 })));
+      assert_true(rectWithPathLength.isPointInStroke({ x: 250, y: 308 }));
+      assert_false(rectWithPathLength.isPointInStroke({ x: 250, y: 412 }));
     }, document.title + ", 'pathLength'.");
 
     test(function() {
       let circleWithNSS = document.getElementById("circle-with-non-scaling-stroke");
-      assert_true(circleWithNSS.isPointInStroke(adaptPoint({ x: 9.975, y: 20 })));
-      assert_false(circleWithNSS.isPointInStroke(adaptPoint({ x: 9.9, y: 20 })));
+      assert_true(circleWithNSS.isPointInStroke({ x: 9.975, y: 20 }));
+      assert_false(circleWithNSS.isPointInStroke({ x: 9.9, y: 20 }));
     }, document.title + ", 'vector-effect'.");
 
     test(function() {
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGPoint-expected.txt b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGPoint-expected.txt
new file mode 100644
index 0000000..7fe069fb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGPoint-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL SVGPoint interface assert_throws_js: function "function() { point.x = NaN; }" did not throw
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGPoint.html b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGPoint.html
new file mode 100644
index 0000000..cdf44e2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGPoint.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<title>SVGPoint interface</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  let svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+  let point = svgElement.createSVGPoint();
+
+  // Check initial point values.
+  assert_equals(point.x, 0);
+  assert_equals(point.y, 0);
+
+  point.y = 2;
+
+  // Check setting valid arguments.
+  assert_equals(point.x, 0);
+  assert_equals(point.y, 2);
+
+  // Check setting invalid arguments.
+  assert_throws_js(TypeError, function() { point.x = NaN; });
+  assert_throws_js(TypeError, function() { point.x = Infinity; });
+  assert_equals(point.x, 0);
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/unload-beacon/META.yml b/third_party/blink/web_tests/external/wpt/unload-beacon/META.yml
new file mode 100644
index 0000000..70848e7c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/unload-beacon/META.yml
@@ -0,0 +1,3 @@
+spec: https://wicg.github.io/unload-beacon/
+suggested_reviewers:
+  - clelland
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_beacon-basic.tentative.window.js b/third_party/blink/web_tests/external/wpt/unload-beacon/pending_beacon-basic.tentative.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_beacon-basic.tentative.window.js
rename to third_party/blink/web_tests/external/wpt/unload-beacon/pending_beacon-basic.tentative.window.js
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_beacon-deactivate.tentative.window.js b/third_party/blink/web_tests/external/wpt/unload-beacon/pending_beacon-deactivate.tentative.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_beacon-deactivate.tentative.window.js
rename to third_party/blink/web_tests/external/wpt/unload-beacon/pending_beacon-deactivate.tentative.window.js
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_beacon-sendnow.tentative.window.js b/third_party/blink/web_tests/external/wpt/unload-beacon/pending_beacon-sendnow.tentative.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_beacon-sendnow.tentative.window.js
rename to third_party/blink/web_tests/external/wpt/unload-beacon/pending_beacon-sendnow.tentative.window.js
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_get_beacon-cors.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/unload-beacon/pending_get_beacon-cors.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_get_beacon-cors.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/unload-beacon/pending_get_beacon-cors.tentative.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_get_beacon-send.tentative.window.js b/third_party/blink/web_tests/external/wpt/unload-beacon/pending_get_beacon-send.tentative.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_get_beacon-send.tentative.window.js
rename to third_party/blink/web_tests/external/wpt/unload-beacon/pending_get_beacon-send.tentative.window.js
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_post_beacon-cors.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/unload-beacon/pending_post_beacon-cors.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_post_beacon-cors.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/unload-beacon/pending_post_beacon-cors.tentative.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_post_beacon-sendwithdata.tentative.window.js b/third_party/blink/web_tests/external/wpt/unload-beacon/pending_post_beacon-sendwithdata.tentative.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/pending_post_beacon-sendwithdata.tentative.window.js
rename to third_party/blink/web_tests/external/wpt/unload-beacon/pending_post_beacon-sendwithdata.tentative.window.js
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/resources/get_beacon.py b/third_party/blink/web_tests/external/wpt/unload-beacon/resources/get_beacon.py
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/resources/get_beacon.py
rename to third_party/blink/web_tests/external/wpt/unload-beacon/resources/get_beacon.py
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/resources/pending_beacon-helper.js b/third_party/blink/web_tests/external/wpt/unload-beacon/resources/pending_beacon-helper.js
similarity index 97%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/resources/pending_beacon-helper.js
rename to third_party/blink/web_tests/external/wpt/unload-beacon/resources/pending_beacon-helper.js
index 636e8d8..067bf60c 100644
--- a/third_party/blink/web_tests/external/wpt/page-unload-beacon/resources/pending_beacon-helper.js
+++ b/third_party/blink/web_tests/external/wpt/unload-beacon/resources/pending_beacon-helper.js
@@ -92,7 +92,7 @@
 
 function generateSetBeaconURL(uuid, options) {
   const host = (options && options.host) || '';
-  let url = `${host}/page-unload-beacon/resources/set_beacon.py?uuid=${uuid}`;
+  let url = `${host}/unload-beacon/resources/set_beacon.py?uuid=${uuid}`;
   if (options) {
     if (options.expectOrigin !== undefined) {
       url = `${url}&expectOrigin=${options.expectOrigin}`;
@@ -141,7 +141,7 @@
   const res = await poll(
       async () => {
         const res = await fetch(
-            `/page-unload-beacon/resources/get_beacon.py?uuid=${uuid}`,
+            `/unload-beacon/resources/get_beacon.py?uuid=${uuid}`,
             {cache: 'no-store'});
         return await res.json();
       },
diff --git a/third_party/blink/web_tests/external/wpt/page-unload-beacon/resources/set_beacon.py b/third_party/blink/web_tests/external/wpt/unload-beacon/resources/set_beacon.py
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/page-unload-beacon/resources/set_beacon.py
rename to third_party/blink/web_tests/external/wpt/unload-beacon/resources/set_beacon.py
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-copyTo.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-copyTo.any.js
index d2d04c5..79ba3c6 100644
--- a/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-copyTo.any.js
+++ b/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-copyTo.any.js
@@ -15,6 +15,22 @@
   return new VideoFrame(data, init);
 }
 
+const NV12_DATA = new Uint8Array([
+      1, 2, 3, 4,   // y
+      5, 6, 7, 8,
+      9, 10, 11, 12 // uv
+  ]);
+
+function makeNV12_4x2() {
+  const init = {
+      format: 'NV12',
+      timestamp: 0,
+      codedWidth: 4,
+      codedHeight: 2,
+  };
+  return new VideoFrame(NV12_DATA, init);
+}
+
 promise_test(async t => {
   const frame = makeI420_4x2();
   frame.close();
@@ -52,6 +68,24 @@
 }, 'Test RGBA frame.');
 
 promise_test(async t => {
+  const frame = makeNV12_4x2();
+  const expectedLayout = [
+      {offset: 0, stride: 4},
+      {offset: 8, stride: 4},
+  ];
+  const expectedData = new Uint8Array([
+      1,2,3,4,
+      5,6,7,8,
+      9,10,11,12
+  ]);
+  assert_equals(frame.allocationSize(), expectedData.length, 'allocationSize()');
+  const data = new Uint8Array(expectedData.length);
+  const layout = await frame.copyTo(data);
+  assert_layout_equals(layout, expectedLayout);
+  assert_buffer_equals(data, expectedData);
+}, 'Test NV12 frame.');
+
+promise_test(async t => {
   const frame = makeI420_4x2();
   const data = new Uint8Array(11);
   await promise_rejects_js(t, TypeError, frame.copyTo(data));
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/sync.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/sync.py
index 05f3e62..015ebd3 100644
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/sync.py
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/sync.py
@@ -239,17 +239,19 @@
         :param condition: A callable function whose return value will
             be returned by this function.
         """
-        result = None
-        traceback = None
-
         async def poll():
             result = None
+            traceback = None
+            start = self.clock.time()
+            end = start + self.timeout
 
-            while True:
+            while not self.clock.time() >= end:
                 next = self.clock.time() + self.interval
 
                 try:
                     result = condition(self.session)
+                except (KeyboardInterrupt, SystemExit):
+                    raise
                 except self.exceptions:
                     _, _, traceback = sys.exc_info()
 
@@ -262,13 +264,13 @@
 
                 await asyncio.sleep(interval_new)
 
-        try :
-            result = await asyncio.wait_for(poll(), timeout=self.timeout)
-        except asyncio.TimeoutError:
             if self.exc_cls is not None:
-                message = f"Timed out after {self.timeout} seconds"
+                elapsed = round((self.clock.time() - start), 1)
+                message = f"Timed out after {elapsed} seconds"
                 if self.exc_msg is not None:
                     message = f"{message} with message: {self.exc_msg}"
                 raise self.exc_cls(message=message).with_traceback(traceback)
             else:
                 return result
+
+        return await poll()
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats-expected.txt
index 66839af..a1cbb24 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 237 tests; 215 PASS, 22 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 245 tests; 215 PASS, 30 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS getStats succeeds
 PASS Validating stats
 PASS codec's payloadType
@@ -164,6 +164,14 @@
 PASS media-source's timestamp
 PASS media-source's type
 PASS media-source's id
+FAIL media-playout's synthesizedSamplesDuration assert_true: Is synthesizedSamplesDuration present expected true got false
+FAIL media-playout's synthesizedSamplesEvents assert_true: Is synthesizedSamplesEvents present expected true got false
+FAIL media-playout's totalSamplesDuration assert_true: Is totalSamplesDuration present expected true got false
+FAIL media-playout's totalPlayoutDelay assert_true: Is totalPlayoutDelay present expected true got false
+FAIL media-playout's totalSamplesCount assert_true: Is totalSamplesCount present expected true got false
+FAIL media-playout's timestamp assert_true: Is timestamp present expected true got false
+FAIL media-playout's type assert_true: Is type present expected true got false
+FAIL media-playout's id assert_true: Is id present expected true got false
 PASS transport's packetsSent
 PASS transport's packetsReceived
 PASS transport's bytesSent
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats.html b/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats.html
index f59f5d8..22b514e 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats.html
@@ -30,6 +30,7 @@
     audio: "RTCAudioSourceStats",
     video: "RTCVideoSourceStats"
   },
+  "media-playout": "RTCAudioPlayoutStats",
   "sender": {
     audio: "RTCAudioSenderStats",
     video: "RTCVideoSenderStats"
diff --git a/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-listing-expected.txt b/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-listing-expected.txt
index fa491095..2649de6 100644
--- a/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-listing-expected.txt
+++ b/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-listing-expected.txt
@@ -197,6 +197,7 @@
 grid-template-rows: none
 height: 0px
 hyphenate-character: auto
+hyphenate-limit-chars: auto
 hyphens: manual
 image-orientation: from-image
 image-rendering: auto
diff --git a/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt b/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
index ee430d5..c306abe 100644
--- a/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
+++ b/third_party/blink/web_tests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
@@ -197,6 +197,7 @@
 grid-template-rows: none
 height: auto
 hyphenate-character: auto
+hyphenate-limit-chars: auto
 hyphens: manual
 image-orientation: from-image
 image-rendering: auto
diff --git a/third_party/blink/web_tests/fast/forms/color-scheme/media/video-playback-speed-menu.html b/third_party/blink/web_tests/fast/forms/color-scheme/media/video-playback-speed-menu.html
new file mode 100644
index 0000000..c8b4ec7
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/color-scheme/media/video-playback-speed-menu.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<script src="../../../../media/media-file.js"></script>
+<script src="../../../../media/video-paint-test.js"></script>
+<script src="../../../../media/media-controls.js"></script>
+<script src="../../../../media/overflow-menu.js"></script>
+<meta name="color-scheme" content="light dark">
+
+<body style="padding-top: 200px; padding-left: 100px">
+    <video controls></video>
+    <script>
+        var video = document.querySelector("video");
+        enableTestMode(video);
+        video.onloadeddata = function () {
+            var overflowMenu = getOverflowMenuButton(video);
+            var coords = elementCoordinates(overflowMenu);
+            clickAtCoordinates(coords[0], coords[1]);
+
+            // Navigate to the Playback Speed sub-menu
+            eventSender.keyDown('ArrowUp');
+            eventSender.keyDown('Enter');
+        };
+        setVideoSrcAndWaitForFirstFrame("../../../../media/content/test.ogv");
+    </script>
+</body>
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/pasteboard/copy-standalone-image-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/pasteboard/copy-standalone-image-expected.txt
index 68a8603..9d18a82 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/pasteboard/copy-standalone-image-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/pasteboard/copy-standalone-image-expected.txt
@@ -16,6 +16,7 @@
       LayoutBlockFlow (anonymous) at (0,92) size 784x154
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {DIV} at (0,246) size 784x131 [border: (2px solid #FF0000)]
+        LayoutImage {IMG} at (14,14) size 76x103
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,100) size 304x154 clip at (10,102) size 300x150
   LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px solid #0000FF)]
@@ -24,8 +25,5 @@
     layer at (0,0) size 300x150
       LayoutBlockFlow {HTML} at (0,0) size 300x150
         LayoutBlockFlow {BODY} at (0,0) size 300x150
-    layer at (0,0) size 76x103
-      LayoutImage {IMG} at (0,0) size 76x103
-layer at (22,268) size 76x103
-  LayoutImage {IMG} at (14,14) size 76x103
+          LayoutImage {IMG} at (0,0) size 76x103
 caret: position 1 of child 0 {IMG} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/pasteboard/copy-standalone-oriented-image-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/pasteboard/copy-standalone-oriented-image-expected.txt
index d2e34493..20cdfffd 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/pasteboard/copy-standalone-oriented-image-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/pasteboard/copy-standalone-oriented-image-expected.txt
@@ -16,6 +16,7 @@
       LayoutBlockFlow (anonymous) at (0,92) size 784x154
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {DIV} at (0,246) size 784x128 [border: (2px solid #FF0000)]
+        LayoutImage {IMG} at (14,14) size 50x100
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,100) size 304x154 clip at (10,102) size 300x150
   LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px solid #0000FF)]
@@ -24,8 +25,5 @@
     layer at (0,0) size 300x150
       LayoutBlockFlow {HTML} at (0,0) size 300x150
         LayoutBlockFlow {BODY} at (0,0) size 300x150
-    layer at (0,0) size 50x100
-      LayoutImage {IMG} at (0,0) size 50x100
-layer at (22,268) size 50x100
-  LayoutImage {IMG} at (14,14) size 50x100
+          LayoutImage {IMG} at (0,0) size 50x100
 caret: position 1 of child 0 {IMG} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/4402375-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/4402375-expected.txt
index 191188af..25fb92f 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/4402375-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/4402375-expected.txt
@@ -19,11 +19,10 @@
           text run at (413,0) width 330: "The image should not be selected, and should not be"
           text run at (0,20) width 598: "included in the selection rect (you won't see the selection rect when you run this test manually)."
       LayoutBlockFlow {DIV} at (0,130) size 784x20
+        LayoutImage (floating) {IMG} at (708,0) size 76x103
         LayoutText {#text} at (0,0) size 178x19
           text run at (0,0) width 178: "This text should be selected."
 layer at (8,64) size 784x2 clip at (0,0) size 0x0
   LayoutBlockFlow {HR} at (0,56) size 784x2 [border: (1px inset #EEEEEE)]
-layer at (716,138) size 76x103
-  LayoutImage (floating) {IMG} at (708,0) size 76x103
 selection start: position 0 of child 1 {#text} of child 6 {DIV} of body
 selection end:   position 29 of child 1 {#text} of child 6 {DIV} of body
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/drag-to-contenteditable-iframe-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/drag-to-contenteditable-iframe-expected.txt
index 3806168..5cb446d 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/drag-to-contenteditable-iframe-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/drag-to-contenteditable-iframe-expected.txt
@@ -9,6 +9,7 @@
       LayoutBlockFlow (anonymous) at (0,0) size 800x213
         LayoutText {#text} at (208,193) size 4x19
           text run at (208,193) width 4: " "
+        LayoutImage {IMG} at (212,105) size 76x103
         LayoutText {#text} at (0,0) size 0x0
       LayoutBlockFlow {UL} at (0,229) size 800x20
         LayoutListItem {LI} at (40,0) size 760x20
@@ -22,8 +23,5 @@
     layer at (0,0) size 200x200
       LayoutBlockFlow {HTML} at (0,0) size 200x200
         LayoutBlockFlow {BODY} at (8,8) size 184x184 [bgcolor=#FFFFE0]
+          LayoutImage {IMG} at (0,0) size 76x103
           LayoutText {#text} at (0,0) size 0x0
-    layer at (8,8) size 76x103
-      LayoutImage {IMG} at (0,0) size 76x103
-layer at (212,105) size 76x103
-  LayoutImage {IMG} at (212,105) size 76x103
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/select-missing-image-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/select-missing-image-expected.txt
index 65e1757..fff577e0 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/select-missing-image-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/editing/selection/select-missing-image-expected.txt
@@ -11,10 +11,9 @@
   LayoutBlockFlow {IMG} at (14,14) size 550x100
 layer at (22,22) size 550x100 clip at (23,23) size 548x98
   LayoutBlockFlow {SPAN} at (0,0) size 550x100 [border: (1px solid #C0C0C0)]
+    LayoutImage (floating) {IMG} at (2,2) size 16x16
     LayoutInline {SPAN} at (18,2) size 480x27
       LayoutText {#text} at (18,2) size 480x27
         text run at (18,2) width 480: "Should see selection tint over this missing image."
-layer at (24,24) size 16x16
-  LayoutImage (floating) {IMG} at (2,2) size 16x16
 selection start: position 0 of child 1 {IMG} of child 1 {DIV} of body
 selection end:   position 1 of child 1 {IMG} of child 1 {DIV} of body
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt
index 49adafd..ed6c7d9 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/cssom/getComputedStyle-detached-subtree-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 PASS getComputedStyle returns no style for detached element
-FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) assert_equals: expected 0 but got 365
-FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) from iframe's window assert_equals: expected 0 but got 365
-FAIL getComputedStyle returns no style for element outside the flat tree assert_equals: expected 0 but got 365
-FAIL getComputedStyle returns no style for descendant outside the flat tree assert_equals: expected 0 but got 365
+FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) assert_equals: expected 0 but got 366
+FAIL getComputedStyle returns no style for element in non-rendered iframe (display: none) from iframe's window assert_equals: expected 0 but got 366
+FAIL getComputedStyle returns no style for element outside the flat tree assert_equals: expected 0 but got 366
+FAIL getComputedStyle returns no style for descendant outside the flat tree assert_equals: expected 0 but got 366
 PASS getComputedStyle returns no style for shadow tree outside of flattened tree
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/cssom/getComputedStyle-pseudo-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/cssom/getComputedStyle-pseudo-expected.txt
index 5ab221bc..0fe62f5 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/cssom/getComputedStyle-pseudo-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/cssom/getComputedStyle-pseudo-expected.txt
@@ -7,6 +7,6 @@
 PASS Item-based blockification of nonexistent pseudo-elements
 PASS display: contents on pseudo-elements
 PASS Dynamically change to display: contents on pseudo-elements
-FAIL Unknown pseudo-elements assert_equals: Should return an empty style for unknown pseudo-elements starting with double-colon expected 0 but got 365
+FAIL Unknown pseudo-elements assert_equals: Should return an empty style for unknown pseudo-elements starting with double-colon expected 0 but got 366
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/getComputedStyle/computed-style-listing-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/getComputedStyle/computed-style-listing-expected.txt
index 1045aac..bfa18ee 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/getComputedStyle/computed-style-listing-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/getComputedStyle/computed-style-listing-expected.txt
@@ -197,6 +197,7 @@
 grid-template-rows: none
 height: 0px
 hyphenate-character: auto
+hyphenate-limit-chars: auto
 hyphens: manual
 image-orientation: from-image
 image-rendering: auto
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
index be19a1e8..4777adf4 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
@@ -197,6 +197,7 @@
 grid-template-rows: none
 height: auto
 hyphenate-character: auto
+hyphenate-limit-chars: auto
 hyphens: manual
 image-orientation: from-image
 image-rendering: auto
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/svg/css/getComputedStyle-listing-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/svg/css/getComputedStyle-listing-expected.txt
index 46f8e1a9..2e7be02 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/svg/css/getComputedStyle-listing-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/svg/css/getComputedStyle-listing-expected.txt
@@ -197,6 +197,7 @@
 grid-template-rows: none
 height: 100px
 hyphenate-character: auto
+hyphenate-limit-chars: auto
 hyphens: manual
 image-orientation: from-image
 image-rendering: auto
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/webexposed/css-properties-as-js-properties-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/webexposed/css-properties-as-js-properties-expected.txt
index 1fc2cf8..aff38bf 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/webexposed/css-properties-as-js-properties-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/webexposed/css-properties-as-js-properties-expected.txt
@@ -219,6 +219,7 @@
 gridTemplateRows
 height
 hyphenateCharacter
+hyphenateLimitChars
 hyphens
 imageOrientation
 imageRendering
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/webexposed/css-property-listing-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/webexposed/css-property-listing-expected.txt
index 08614c3..e62a65b 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/webexposed/css-property-listing-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/webexposed/css-property-listing-expected.txt
@@ -213,6 +213,7 @@
     grid-template-rows
     height
     hyphenate-character
+    hyphenate-limit-chars
     hyphens
     image-orientation
     image-rendering
diff --git a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-2.sub-expected.txt b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-2.sub-expected.txt
new file mode 100644
index 0000000..8a40bab
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/nav-cancelation-2.sub-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL grandparent cancels a pending navigation in a cross-origin grandchild assert_false: Grandchild <iframe>'s load event does not fire at least one task after the grandparent's window load event fires. It should only fire when its subsequent navigation is complete expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/linux/editing/pasteboard/copy-standalone-image-expected.txt b/third_party/blink/web_tests/platform/linux/editing/pasteboard/copy-standalone-image-expected.txt
index 0ffb2adc..23315f6e 100644
--- a/third_party/blink/web_tests/platform/linux/editing/pasteboard/copy-standalone-image-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/editing/pasteboard/copy-standalone-image-expected.txt
@@ -2,7 +2,7 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -16,16 +16,14 @@
       LayoutNGBlockFlow (anonymous) at (0,92) size 784x154
         LayoutText {#text} at (0,0) size 0x0
       LayoutNGBlockFlow {DIV} at (0,246) size 784x131 [border: (2px solid #FF0000)]
+        LayoutImage {IMG} at (14,14) size 76x103
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,100) size 304x154 clip at (10,102) size 300x150
   LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px solid #0000FF)]
     layer at (0,0) size 300x150
-      LayoutView at (0,0) size 300x150
+      LayoutNGView at (0,0) size 300x150
     layer at (0,0) size 300x150
       LayoutNGBlockFlow {HTML} at (0,0) size 300x150
         LayoutNGBlockFlow {BODY} at (0,0) size 300x150
-    layer at (0,0) size 76x103
-      LayoutImage {IMG} at (0,0) size 76x103
-layer at (22,268) size 76x103
-  LayoutImage {IMG} at (14,14) size 76x103
+          LayoutImage {IMG} at (0,0) size 76x103
 caret: position 1 of child 0 {IMG} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/linux/editing/pasteboard/copy-standalone-oriented-image-expected.txt b/third_party/blink/web_tests/platform/linux/editing/pasteboard/copy-standalone-oriented-image-expected.txt
index 27b80d657..454295c 100644
--- a/third_party/blink/web_tests/platform/linux/editing/pasteboard/copy-standalone-oriented-image-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/editing/pasteboard/copy-standalone-oriented-image-expected.txt
@@ -2,7 +2,7 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -16,16 +16,14 @@
       LayoutNGBlockFlow (anonymous) at (0,92) size 784x154
         LayoutText {#text} at (0,0) size 0x0
       LayoutNGBlockFlow {DIV} at (0,246) size 784x128 [border: (2px solid #FF0000)]
+        LayoutImage {IMG} at (14,14) size 50x100
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,100) size 304x154 clip at (10,102) size 300x150
   LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px solid #0000FF)]
     layer at (0,0) size 300x150
-      LayoutView at (0,0) size 300x150
+      LayoutNGView at (0,0) size 300x150
     layer at (0,0) size 300x150
       LayoutNGBlockFlow {HTML} at (0,0) size 300x150
         LayoutNGBlockFlow {BODY} at (0,0) size 300x150
-    layer at (0,0) size 50x100
-      LayoutImage {IMG} at (0,0) size 50x100
-layer at (22,268) size 50x100
-  LayoutImage {IMG} at (14,14) size 50x100
+          LayoutImage {IMG} at (0,0) size 50x100
 caret: position 1 of child 0 {IMG} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/linux/editing/selection/4402375-expected.txt b/third_party/blink/web_tests/platform/linux/editing/selection/4402375-expected.txt
index 5f216e89..2bbac854 100644
--- a/third_party/blink/web_tests/platform/linux/editing/selection/4402375-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/editing/selection/4402375-expected.txt
@@ -1,6 +1,6 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -18,11 +18,10 @@
           text run at (0,0) width 743: "This test uses a right aligned image next to some left aligned text. The image should not be selected, and should not be"
           text run at (0,20) width 598: "included in the selection rect (you won't see the selection rect when you run this test manually)."
       LayoutNGBlockFlow {DIV} at (0,130) size 784x20
+        LayoutImage (floating) {IMG} at (708,0) size 76x103
         LayoutText {#text} at (0,0) size 178x19
           text run at (0,0) width 178: "This text should be selected."
 layer at (8,64) size 784x2 clip at (0,0) size 0x0
   LayoutNGBlockFlow {HR} at (0,56) size 784x2 [border: (1px inset #EEEEEE)]
-layer at (716,138) size 76x103
-  LayoutImage (floating) {IMG} at (708,0) size 76x103
 selection start: position 0 of child 1 {#text} of child 6 {DIV} of body
 selection end:   position 29 of child 1 {#text} of child 6 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/linux/editing/selection/drag-to-contenteditable-iframe-expected.txt b/third_party/blink/web_tests/platform/linux/editing/selection/drag-to-contenteditable-iframe-expected.txt
index 25d5be6..c2c8dbd 100644
--- a/third_party/blink/web_tests/platform/linux/editing/selection/drag-to-contenteditable-iframe-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/editing/selection/drag-to-contenteditable-iframe-expected.txt
@@ -2,13 +2,14 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (0,0) size 800x584
       LayoutNGBlockFlow (anonymous) at (0,0) size 800x213
         LayoutText {#text} at (208,193) size 4x19
           text run at (208,193) width 4: " "
+        LayoutImage {IMG} at (212,105) size 76x103
         LayoutText {#text} at (0,0) size 0x0
       LayoutNGBlockFlow {UL} at (0,229) size 800x20
         LayoutNGListItem {LI} at (40,0) size 760x20
@@ -20,12 +21,9 @@
 layer at (0,0) size 208x208 clip at (4,4) size 200x200
   LayoutIFrame {IFRAME} at (0,0) size 208x208 [border: (4px solid #000000)]
     layer at (0,0) size 200x200
-      LayoutView at (0,0) size 200x200
+      LayoutNGView at (0,0) size 200x200
     layer at (0,0) size 200x200
       LayoutNGBlockFlow {HTML} at (0,0) size 200x200
         LayoutNGBlockFlow {BODY} at (8,8) size 184x184 [bgcolor=#FFFFE0]
+          LayoutImage {IMG} at (0,0) size 76x103
           LayoutText {#text} at (0,0) size 0x0
-    layer at (8,8) size 76x103
-      LayoutImage {IMG} at (0,0) size 76x103
-layer at (212,105) size 76x103
-  LayoutImage {IMG} at (212,105) size 76x103
diff --git a/third_party/blink/web_tests/platform/linux/editing/selection/select-missing-image-expected.txt b/third_party/blink/web_tests/platform/linux/editing/selection/select-missing-image-expected.txt
index 94aa2c0..de3cbc6d 100644
--- a/third_party/blink/web_tests/platform/linux/editing/selection/select-missing-image-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/editing/selection/select-missing-image-expected.txt
@@ -1,7 +1,7 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -11,10 +11,9 @@
   LayoutNGBlockFlow {IMG} at (14,14) size 550x100
 layer at (22,22) size 550x100 clip at (23,23) size 548x98
   LayoutNGBlockFlow {SPAN} at (0,0) size 550x100 [border: (1px solid #C0C0C0)]
+    LayoutImage (floating) {IMG} at (2,2) size 16x16
     LayoutInline {SPAN} at (18,2) size 480x27
       LayoutText {#text} at (18,2) size 480x27
         text run at (18,2) width 480: "Should see selection tint over this missing image."
-layer at (24,24) size 16x16
-  LayoutImage (floating) {IMG} at (2,2) size 16x16
 selection start: position 0 of child 1 {IMG} of child 1 {DIV} of body
 selection end:   position 1 of child 1 {IMG} of child 1 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
new file mode 100644
index 0000000..01706390
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 84adc6be..d4a1f2a 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
new file mode 100644
index 0000000..22f9221
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
new file mode 100644
index 0000000..5b6d7800
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-3-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-3-expected.txt
deleted file mode 100644
index 897df4c..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-3-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL NodeList (static collection) "length" getter tampered assert_equals: expected -1 but got 50
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/selection/khmer-selection-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/selection/khmer-selection-expected.png
deleted file mode 100644
index d34eed0..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/selection/khmer-selection-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/screen-capture/permissions-policy-audio+video.https.sub-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/screen-capture/permissions-policy-audio+video.https.sub-expected.txt
new file mode 100644
index 0000000..f284475
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/external/wpt/screen-capture/permissions-policy-audio+video.https.sub-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS Default "display-capture" permissions policy ["self"] allows the top-level document.
+PASS Default "display-capture" permissions policy ["self"] allows same-origin iframes.
+FAIL Default "display-capture" permissions policy ["self"] disallows cross-origin iframes. assert_equals: element click intercepted error. expected "NotAllowedError" but got "Error"
+PASS permissions policy "display-capture" can be enabled in cross-origin iframes using "allow" attribute.
+PASS permissions policy "display-capture" can be disabled in same-origin iframes using "allow" attribute.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/screen-capture/permissions-policy-audio+video.https.sub-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/screen-capture/permissions-policy-audio+video.https.sub-expected.txt
new file mode 100644
index 0000000..030c825
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/screen-capture/permissions-policy-audio+video.https.sub-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS Default "display-capture" permissions policy ["self"] allows the top-level document.
+PASS Default "display-capture" permissions policy ["self"] allows same-origin iframes.
+FAIL Default "display-capture" permissions policy ["self"] disallows cross-origin iframes. assert_equals: element click intercepted error. expected "NotAllowedError" but got "Error"
+FAIL permissions policy "display-capture" can be enabled in cross-origin iframes using "allow" attribute. assert_equals: element click intercepted error. expected "#OK" but got "Error"
+PASS permissions policy "display-capture" can be disabled in same-origin iframes using "allow" attribute.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/screen-capture/permissions-policy-video.https.sub-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/screen-capture/permissions-policy-video.https.sub-expected.txt
new file mode 100644
index 0000000..030c825
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/external/wpt/screen-capture/permissions-policy-video.https.sub-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+PASS Default "display-capture" permissions policy ["self"] allows the top-level document.
+PASS Default "display-capture" permissions policy ["self"] allows same-origin iframes.
+FAIL Default "display-capture" permissions policy ["self"] disallows cross-origin iframes. assert_equals: element click intercepted error. expected "NotAllowedError" but got "Error"
+FAIL permissions policy "display-capture" can be enabled in cross-origin iframes using "allow" attribute. assert_equals: element click intercepted error. expected "#OK" but got "Error"
+PASS permissions policy "display-capture" can be disabled in same-origin iframes using "allow" attribute.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac11/external/wpt/screen-orientation/lock-basic-expected.txt b/third_party/blink/web_tests/platform/mac-mac11/external/wpt/screen-orientation/lock-basic-expected.txt
new file mode 100644
index 0000000..15abdf4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11/external/wpt/screen-orientation/lock-basic-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS Test that screen.orientation.unlock() doesn't throw when there is no lock with fullscreen
+PASS Test that screen.orientation.unlock() doesn't throw when there is no lock
+PASS Test that screen.orientation.unlock() returns a void value
+PASS Test that screen.orientation.lock returns a promise which will be fulfilled with a void value.
+FAIL Test that screen.orientation.lock returns a pending promise. assert_true: expected true got false
+FAIL Test that screen.orientation.lock() is actually async assert_true: Expected type to start with landscape expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac11/external/wpt/screen-orientation/lock-sandboxed-iframe-expected.txt b/third_party/blink/web_tests/platform/mac-mac11/external/wpt/screen-orientation/lock-sandboxed-iframe-expected.txt
new file mode 100644
index 0000000..d187cce1
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11/external/wpt/screen-orientation/lock-sandboxed-iframe-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Test without 'allow-orientation-lock' sandboxing directive assert_equals: screen.lockOrientation() throws a SecurityError expected "SecurityError" but got "error: SecurityError Failed to execute 'lock' on 'ScreenOrientation': The window is sandboxed and lacks the 'allow-orientation-lock' flag."
+PASS Test with 'allow-orientation-lock' sandboxing directive
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/external/wpt/screen-orientation/lock-basic-expected.txt b/third_party/blink/web_tests/platform/mac-mac12-arm64/external/wpt/screen-orientation/lock-basic-expected.txt
new file mode 100644
index 0000000..15abdf4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/external/wpt/screen-orientation/lock-basic-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS Test that screen.orientation.unlock() doesn't throw when there is no lock with fullscreen
+PASS Test that screen.orientation.unlock() doesn't throw when there is no lock
+PASS Test that screen.orientation.unlock() returns a void value
+PASS Test that screen.orientation.lock returns a promise which will be fulfilled with a void value.
+FAIL Test that screen.orientation.lock returns a pending promise. assert_true: expected true got false
+FAIL Test that screen.orientation.lock() is actually async assert_true: Expected type to start with landscape expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/external/wpt/screen-orientation/lock-sandboxed-iframe-expected.txt b/third_party/blink/web_tests/platform/mac-mac12-arm64/external/wpt/screen-orientation/lock-sandboxed-iframe-expected.txt
new file mode 100644
index 0000000..d187cce1
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/external/wpt/screen-orientation/lock-sandboxed-iframe-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Test without 'allow-orientation-lock' sandboxing directive assert_equals: screen.lockOrientation() throws a SecurityError expected "SecurityError" but got "error: SecurityError Failed to execute 'lock' on 'ScreenOrientation': The window is sandboxed and lacks the 'allow-orientation-lock' flag."
+PASS Test with 'allow-orientation-lock' sandboxing directive
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/editing/pasteboard/copy-standalone-image-expected.txt b/third_party/blink/web_tests/platform/mac/editing/pasteboard/copy-standalone-image-expected.txt
index 994c1d3..927f7745 100644
--- a/third_party/blink/web_tests/platform/mac/editing/pasteboard/copy-standalone-image-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/editing/pasteboard/copy-standalone-image-expected.txt
@@ -2,7 +2,7 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -16,16 +16,14 @@
       LayoutNGBlockFlow (anonymous) at (0,86) size 784x154
         LayoutText {#text} at (0,0) size 0x0
       LayoutNGBlockFlow {DIV} at (0,240) size 784x131 [border: (2px solid #FF0000)]
+        LayoutImage {IMG} at (14,14) size 76x103
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,94) size 304x154 clip at (10,96) size 300x150
   LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px solid #0000FF)]
     layer at (0,0) size 300x150
-      LayoutView at (0,0) size 300x150
+      LayoutNGView at (0,0) size 300x150
     layer at (0,0) size 300x150
       LayoutNGBlockFlow {HTML} at (0,0) size 300x150
         LayoutNGBlockFlow {BODY} at (0,0) size 300x150
-    layer at (0,0) size 76x103
-      LayoutImage {IMG} at (0,0) size 76x103
-layer at (22,262) size 76x103
-  LayoutImage {IMG} at (14,14) size 76x103
+          LayoutImage {IMG} at (0,0) size 76x103
 caret: position 1 of child 0 {IMG} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/mac/editing/pasteboard/copy-standalone-oriented-image-expected.txt b/third_party/blink/web_tests/platform/mac/editing/pasteboard/copy-standalone-oriented-image-expected.txt
index 36666aee..09ca434 100644
--- a/third_party/blink/web_tests/platform/mac/editing/pasteboard/copy-standalone-oriented-image-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/editing/pasteboard/copy-standalone-oriented-image-expected.txt
@@ -2,7 +2,7 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -16,16 +16,14 @@
       LayoutNGBlockFlow (anonymous) at (0,86) size 784x154
         LayoutText {#text} at (0,0) size 0x0
       LayoutNGBlockFlow {DIV} at (0,240) size 784x128 [border: (2px solid #FF0000)]
+        LayoutImage {IMG} at (14,14) size 50x100
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,94) size 304x154 clip at (10,96) size 300x150
   LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px solid #0000FF)]
     layer at (0,0) size 300x150
-      LayoutView at (0,0) size 300x150
+      LayoutNGView at (0,0) size 300x150
     layer at (0,0) size 300x150
       LayoutNGBlockFlow {HTML} at (0,0) size 300x150
         LayoutNGBlockFlow {BODY} at (0,0) size 300x150
-    layer at (0,0) size 50x100
-      LayoutImage {IMG} at (0,0) size 50x100
-layer at (22,262) size 50x100
-  LayoutImage {IMG} at (14,14) size 50x100
+          LayoutImage {IMG} at (0,0) size 50x100
 caret: position 1 of child 0 {IMG} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/mac/editing/selection/4402375-expected.txt b/third_party/blink/web_tests/platform/mac/editing/selection/4402375-expected.txt
index 4126221f..114f1b6b 100644
--- a/third_party/blink/web_tests/platform/mac/editing/selection/4402375-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/editing/selection/4402375-expected.txt
@@ -1,6 +1,6 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -18,11 +18,10 @@
           text run at (0,0) width 759: "This test uses a right aligned image next to some left aligned text. The image should not be selected, and should not be"
           text run at (0,18) width 612: "included in the selection rect (you won't see the selection rect when you run this test manually)."
       LayoutNGBlockFlow {DIV} at (0,122) size 784x18
+        LayoutImage (floating) {IMG} at (708,0) size 76x103
         LayoutText {#text} at (0,0) size 182x18
           text run at (0,0) width 182: "This text should be selected."
 layer at (8,60) size 784x2 clip at (0,0) size 0x0
   LayoutNGBlockFlow {HR} at (0,52) size 784x2 [border: (1px inset #EEEEEE)]
-layer at (716,130) size 76x103
-  LayoutImage (floating) {IMG} at (708,0) size 76x103
 selection start: position 0 of child 1 {#text} of child 6 {DIV} of body
 selection end:   position 29 of child 1 {#text} of child 6 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/mac/editing/selection/drag-to-contenteditable-iframe-expected.txt b/third_party/blink/web_tests/platform/mac/editing/selection/drag-to-contenteditable-iframe-expected.txt
index 562b615..1ac5b1c 100644
--- a/third_party/blink/web_tests/platform/mac/editing/selection/drag-to-contenteditable-iframe-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/editing/selection/drag-to-contenteditable-iframe-expected.txt
@@ -2,13 +2,14 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (0,0) size 800x584
       LayoutNGBlockFlow (anonymous) at (0,0) size 800x212
         LayoutText {#text} at (208,194) size 4x18
           text run at (208,194) width 4: " "
+        LayoutImage {IMG} at (212,105) size 76x103
         LayoutText {#text} at (0,0) size 0x0
       LayoutNGBlockFlow {UL} at (0,228) size 800x18
         LayoutNGListItem {LI} at (40,0) size 760x18
@@ -20,12 +21,9 @@
 layer at (0,0) size 208x208 clip at (4,4) size 200x200
   LayoutIFrame {IFRAME} at (0,0) size 208x208 [border: (4px solid #000000)]
     layer at (0,0) size 200x200
-      LayoutView at (0,0) size 200x200
+      LayoutNGView at (0,0) size 200x200
     layer at (0,0) size 200x200
       LayoutNGBlockFlow {HTML} at (0,0) size 200x200
         LayoutNGBlockFlow {BODY} at (8,8) size 184x184 [bgcolor=#FFFFE0]
+          LayoutImage {IMG} at (0,0) size 76x103
           LayoutText {#text} at (0,0) size 0x0
-    layer at (8,8) size 76x103
-      LayoutImage {IMG} at (0,0) size 76x103
-layer at (212,105) size 76x103
-  LayoutImage {IMG} at (212,105) size 76x103
diff --git a/third_party/blink/web_tests/platform/mac/editing/selection/select-missing-image-expected.txt b/third_party/blink/web_tests/platform/mac/editing/selection/select-missing-image-expected.txt
index 5e45b58..15eeb67 100644
--- a/third_party/blink/web_tests/platform/mac/editing/selection/select-missing-image-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/editing/selection/select-missing-image-expected.txt
@@ -1,7 +1,7 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -11,10 +11,9 @@
   LayoutNGBlockFlow {IMG} at (14,14) size 550x100
 layer at (22,22) size 550x100 clip at (23,23) size 548x98
   LayoutNGBlockFlow {SPAN} at (0,0) size 550x100 [border: (1px solid #C0C0C0)]
+    LayoutImage (floating) {IMG} at (2,2) size 16x16
     LayoutInline {SPAN} at (18,2) size 475x28
       LayoutText {#text} at (18,2) size 475x28
         text run at (18,2) width 475: "Should see selection tint over this missing image."
-layer at (24,24) size 16x16
-  LayoutImage (floating) {IMG} at (2,2) size 16x16
 selection start: position 0 of child 1 {IMG} of child 1 {DIV} of body
 selection end:   position 1 of child 1 {IMG} of child 1 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
new file mode 100644
index 0000000..4554526
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index e343e2f7..48b7c565 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
new file mode 100644
index 0000000..e5cc88e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
new file mode 100644
index 0000000..d0cd4ec
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/editing/pasteboard/copy-standalone-image-expected.txt b/third_party/blink/web_tests/platform/win/editing/pasteboard/copy-standalone-image-expected.txt
index 38d6f83..f556d00 100644
--- a/third_party/blink/web_tests/platform/win/editing/pasteboard/copy-standalone-image-expected.txt
+++ b/third_party/blink/web_tests/platform/win/editing/pasteboard/copy-standalone-image-expected.txt
@@ -2,7 +2,7 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -16,16 +16,14 @@
       LayoutNGBlockFlow (anonymous) at (0,92) size 784x154
         LayoutText {#text} at (0,0) size 0x0
       LayoutNGBlockFlow {DIV} at (0,246) size 784x131 [border: (2px solid #FF0000)]
+        LayoutImage {IMG} at (14,14) size 76x103
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,100) size 304x154 clip at (10,102) size 300x150
   LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px solid #0000FF)]
     layer at (0,0) size 300x150
-      LayoutView at (0,0) size 300x150
+      LayoutNGView at (0,0) size 300x150
     layer at (0,0) size 300x150
       LayoutNGBlockFlow {HTML} at (0,0) size 300x150
         LayoutNGBlockFlow {BODY} at (0,0) size 300x150
-    layer at (0,0) size 76x103
-      LayoutImage {IMG} at (0,0) size 76x103
-layer at (22,268) size 76x103
-  LayoutImage {IMG} at (14,14) size 76x103
+          LayoutImage {IMG} at (0,0) size 76x103
 caret: position 1 of child 0 {IMG} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/win/editing/pasteboard/copy-standalone-oriented-image-expected.txt b/third_party/blink/web_tests/platform/win/editing/pasteboard/copy-standalone-oriented-image-expected.txt
index 7e1da42..d57bebe3 100644
--- a/third_party/blink/web_tests/platform/win/editing/pasteboard/copy-standalone-oriented-image-expected.txt
+++ b/third_party/blink/web_tests/platform/win/editing/pasteboard/copy-standalone-oriented-image-expected.txt
@@ -2,7 +2,7 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -16,16 +16,14 @@
       LayoutNGBlockFlow (anonymous) at (0,92) size 784x154
         LayoutText {#text} at (0,0) size 0x0
       LayoutNGBlockFlow {DIV} at (0,246) size 784x128 [border: (2px solid #FF0000)]
+        LayoutImage {IMG} at (14,14) size 50x100
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,100) size 304x154 clip at (10,102) size 300x150
   LayoutIFrame {IFRAME} at (0,0) size 304x154 [border: (2px solid #0000FF)]
     layer at (0,0) size 300x150
-      LayoutView at (0,0) size 300x150
+      LayoutNGView at (0,0) size 300x150
     layer at (0,0) size 300x150
       LayoutNGBlockFlow {HTML} at (0,0) size 300x150
         LayoutNGBlockFlow {BODY} at (0,0) size 300x150
-    layer at (0,0) size 50x100
-      LayoutImage {IMG} at (0,0) size 50x100
-layer at (22,268) size 50x100
-  LayoutImage {IMG} at (14,14) size 50x100
+          LayoutImage {IMG} at (0,0) size 50x100
 caret: position 1 of child 0 {IMG} of child 7 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/win/editing/selection/4402375-expected.txt b/third_party/blink/web_tests/platform/win/editing/selection/4402375-expected.txt
index 645be2e..a061f2d 100644
--- a/third_party/blink/web_tests/platform/win/editing/selection/4402375-expected.txt
+++ b/third_party/blink/web_tests/platform/win/editing/selection/4402375-expected.txt
@@ -1,6 +1,6 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -18,11 +18,10 @@
           text run at (0,0) width 772: "This test uses a right aligned image next to some left aligned text. The image should not be selected, and should not be included in"
           text run at (0,20) width 497: "the selection rect (you won't see the selection rect when you run this test manually)."
       LayoutNGBlockFlow {DIV} at (0,130) size 784x20
+        LayoutImage (floating) {IMG} at (708,0) size 76x103
         LayoutText {#text} at (0,0) size 170x19
           text run at (0,0) width 170: "This text should be selected."
 layer at (8,64) size 784x2 clip at (0,0) size 0x0
   LayoutNGBlockFlow {HR} at (0,56) size 784x2 [border: (1px inset #EEEEEE)]
-layer at (716,138) size 76x103
-  LayoutImage (floating) {IMG} at (708,0) size 76x103
 selection start: position 0 of child 1 {#text} of child 6 {DIV} of body
 selection end:   position 29 of child 1 {#text} of child 6 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/win/editing/selection/drag-to-contenteditable-iframe-expected.txt b/third_party/blink/web_tests/platform/win/editing/selection/drag-to-contenteditable-iframe-expected.txt
index 1313490..8f52bec3 100644
--- a/third_party/blink/web_tests/platform/win/editing/selection/drag-to-contenteditable-iframe-expected.txt
+++ b/third_party/blink/web_tests/platform/win/editing/selection/drag-to-contenteditable-iframe-expected.txt
@@ -2,13 +2,14 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (0,0) size 800x584
       LayoutNGBlockFlow (anonymous) at (0,0) size 800x213
         LayoutText {#text} at (208,193) size 4x19
           text run at (208,193) width 4: " "
+        LayoutImage {IMG} at (212,105) size 76x103
         LayoutText {#text} at (0,0) size 0x0
       LayoutNGBlockFlow {UL} at (0,229) size 800x20
         LayoutNGListItem {LI} at (40,0) size 760x20
@@ -20,12 +21,9 @@
 layer at (0,0) size 208x208 clip at (4,4) size 200x200
   LayoutIFrame {IFRAME} at (0,0) size 208x208 [border: (4px solid #000000)]
     layer at (0,0) size 200x200
-      LayoutView at (0,0) size 200x200
+      LayoutNGView at (0,0) size 200x200
     layer at (0,0) size 200x200
       LayoutNGBlockFlow {HTML} at (0,0) size 200x200
         LayoutNGBlockFlow {BODY} at (8,8) size 184x184 [bgcolor=#FFFFE0]
+          LayoutImage {IMG} at (0,0) size 76x103
           LayoutText {#text} at (0,0) size 0x0
-    layer at (8,8) size 76x103
-      LayoutImage {IMG} at (0,0) size 76x103
-layer at (212,105) size 76x103
-  LayoutImage {IMG} at (212,105) size 76x103
diff --git a/third_party/blink/web_tests/platform/win/editing/selection/select-missing-image-expected.txt b/third_party/blink/web_tests/platform/win/editing/selection/select-missing-image-expected.txt
index b78203b..a4d19bd6 100644
--- a/third_party/blink/web_tests/platform/win/editing/selection/select-missing-image-expected.txt
+++ b/third_party/blink/web_tests/platform/win/editing/selection/select-missing-image-expected.txt
@@ -1,7 +1,7 @@
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
+  LayoutNGView at (0,0) size 800x600
 layer at (0,0) size 800x600
   LayoutNGBlockFlow {HTML} at (0,0) size 800x600
     LayoutNGBlockFlow {BODY} at (8,8) size 784x584
@@ -11,10 +11,9 @@
   LayoutNGBlockFlow {IMG} at (14,14) size 550x100
 layer at (22,22) size 550x100 clip at (23,23) size 548x98
   LayoutNGBlockFlow {SPAN} at (0,0) size 550x100 [border: (1px solid #C0C0C0)]
+    LayoutImage (floating) {IMG} at (2,2) size 16x16
     LayoutInline {SPAN} at (18,2) size 467x27
       LayoutText {#text} at (18,2) size 467x27
         text run at (18,2) width 467: "Should see selection tint over this missing image."
-layer at (24,24) size 16x16
-  LayoutImage (floating) {IMG} at (2,2) size 16x16
 selection start: position 0 of child 1 {IMG} of child 1 {DIV} of body
 selection end:   position 1 of child 1 {IMG} of child 1 {DIV} of body
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/screen-orientation/lock-basic-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/screen-orientation/lock-basic-expected.txt
new file mode 100644
index 0000000..15abdf4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/screen-orientation/lock-basic-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS Test that screen.orientation.unlock() doesn't throw when there is no lock with fullscreen
+PASS Test that screen.orientation.unlock() doesn't throw when there is no lock
+PASS Test that screen.orientation.unlock() returns a void value
+PASS Test that screen.orientation.lock returns a promise which will be fulfilled with a void value.
+FAIL Test that screen.orientation.lock returns a pending promise. assert_true: expected true got false
+FAIL Test that screen.orientation.lock() is actually async assert_true: Expected type to start with landscape expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/screen-orientation/lock-sandboxed-iframe-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/screen-orientation/lock-sandboxed-iframe-expected.txt
new file mode 100644
index 0000000..d187cce1
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/screen-orientation/lock-sandboxed-iframe-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Test without 'allow-orientation-lock' sandboxing directive assert_equals: screen.lockOrientation() throws a SecurityError expected "SecurityError" but got "error: SecurityError Failed to execute 'lock' on 'ScreenOrientation': The window is sandboxed and lacks the 'allow-orientation-lock' flag."
+PASS Test with 'allow-orientation-lock' sandboxing directive
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
new file mode 100644
index 0000000..3cfe4bb
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 458abc1..9ed10fc 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
new file mode 100644
index 0000000..7610717
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
new file mode 100644
index 0000000..125a284
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-playback-speed-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/printing/abspos-multicol-with-abspos-expected.html b/third_party/blink/web_tests/printing/abspos-multicol-with-abspos-expected.html
new file mode 100644
index 0000000..2fcb6dc
--- /dev/null
+++ b/third_party/blink/web_tests/printing/abspos-multicol-with-abspos-expected.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script>
+  testRunner.setPrinting();
+  internals.settings.setShouldPrintBackgrounds(true);
+</script>
+<div style="float:left; width:100px; height:100px; margin-right:100px; background:blue;"></div>
+<div style="float:left; width:100px; height:100px; background:blue;"></div>
diff --git a/third_party/blink/web_tests/printing/abspos-multicol-with-abspos.html b/third_party/blink/web_tests/printing/abspos-multicol-with-abspos.html
new file mode 100644
index 0000000..dcac0303
--- /dev/null
+++ b/third_party/blink/web_tests/printing/abspos-multicol-with-abspos.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<script>
+  testRunner.setPrinting();
+  internals.settings.setShouldPrintBackgrounds(true);
+</script>
+<div style="position:absolute; columns:2; gap:0; width:400px; height:100px; column-fill:auto;">
+  <div style="position:relative;">
+    <div style="position:absolute; width:100px; height:200px; background:blue;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/svg/css/getComputedStyle-listing-expected.txt b/third_party/blink/web_tests/svg/css/getComputedStyle-listing-expected.txt
index a6bea8a..7f33d76 100644
--- a/third_party/blink/web_tests/svg/css/getComputedStyle-listing-expected.txt
+++ b/third_party/blink/web_tests/svg/css/getComputedStyle-listing-expected.txt
@@ -197,6 +197,7 @@
 grid-template-rows: none
 height: 100px
 hyphenate-character: auto
+hyphenate-limit-chars: auto
 hyphens: manual
 image-orientation: from-image
 image-rendering: auto
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 09c9dc6d..6958689 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -10362,6 +10362,12 @@
     method dpcm
     method dpi
     method dppx
+    method dvb
+    method dvh
+    method dvi
+    method dvmax
+    method dvmin
+    method dvw
     method em
     method escape
     method ex
@@ -10369,6 +10375,12 @@
     method grad
     method in
     method kHz
+    method lvb
+    method lvh
+    method lvi
+    method lvmax
+    method lvmin
+    method lvw
     method mm
     method ms
     method number
@@ -10381,8 +10393,16 @@
     method rem
     method s
     method supports
+    method svb
+    method svh
+    method svi
+    method svmax
+    method svmin
+    method svw
     method turn
+    method vb
     method vh
+    method vi
     method vmax
     method vmin
     method vw
diff --git a/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt b/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt
index 2bbefe07..9298f82 100644
--- a/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt
+++ b/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt
@@ -219,6 +219,7 @@
 gridTemplateRows
 height
 hyphenateCharacter
+hyphenateLimitChars
 hyphens
 imageOrientation
 imageRendering
diff --git a/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt
index cfbf1cc..4481103 100644
--- a/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt
@@ -213,6 +213,7 @@
     grid-template-rows
     height
     hyphenate-character
+    hyphenate-limit-chars
     hyphens
     image-orientation
     image-rendering
diff --git a/third_party/ipcz/include/ipcz/ipcz.h b/third_party/ipcz/include/ipcz/ipcz.h
index 4c4f6f2..cffbc11 100644
--- a/third_party/ipcz/include/ipcz/ipcz.h
+++ b/third_party/ipcz/include/ipcz/ipcz.h
@@ -741,6 +741,18 @@
 // by any amount. Edge-triggered.
 #define IPCZ_TRAP_CONSUMED_REMOTE_PARCEL IPCZ_FLAG_BIT(8)
 
+// Indicates that the trap event is being fired from within the extent of an
+// ipcz API call (i.e., as opposed to being fired from within the extent of an
+// incoming driver transport notification.) For example if a trap is monitoring
+// a portal for incoming parcels, and the application puts a parcel into the
+// portal's peer on the same node, the trap event will be fired within the
+// extent of the corresponding Put() call, and this flag will be set on the
+// event.
+//
+// This flag is ignored when specifying conditions to watch for Trap(), and it
+// may be set on any event dispatched to an IpczTrapEventHandler.
+#define IPCZ_TRAP_WITHIN_API_CALL IPCZ_FLAG_BIT(9)
+
 // A structure describing portal conditions necessary to trigger a trap and
 // invoke its event handler.
 struct IPCZ_ALIGN(8) IpczTrapConditions {
diff --git a/third_party/ipcz/src/BUILD.gn b/third_party/ipcz/src/BUILD.gn
index 1884f9a4..8b98d75 100644
--- a/third_party/ipcz/src/BUILD.gn
+++ b/third_party/ipcz/src/BUILD.gn
@@ -229,6 +229,7 @@
     "ipcz/node_messages.h",
     "ipcz/node_name.h",
     "ipcz/node_type.h",
+    "ipcz/operation_context.h",
     "ipcz/parcel.h",
     "ipcz/parcel_queue.h",
     "ipcz/portal.h",
diff --git a/third_party/ipcz/src/connect_test.cc b/third_party/ipcz/src/connect_test.cc
index 1e6cc9a..36b549b7 100644
--- a/third_party/ipcz/src/connect_test.cc
+++ b/third_party/ipcz/src/connect_test.cc
@@ -317,8 +317,7 @@
   CloseAll({b, client});
 }
 
-// TODOD(crbug.com/1374114): Fix flakiness and re-enable
-MULTINODE_TEST(ConnectTest, DISABLED_MultiBrokerIntroductions) {
+MULTINODE_TEST(ConnectTest, MultiBrokerIntroductions) {
   // This test covers introductions in a multi-broker network. There are four
   // test nodes involved here: the main node (this one, call it A), a secondary
   // broker B launched with the BrokerWithClientNode body defined above; and
diff --git a/third_party/ipcz/src/ipcz/local_router_link.cc b/third_party/ipcz/src/ipcz/local_router_link.cc
index e2c983c..6091424 100644
--- a/third_party/ipcz/src/ipcz/local_router_link.cc
+++ b/third_party/ipcz/src/ipcz/local_router_link.cc
@@ -112,20 +112,22 @@
   parcel.AllocateData(num_bytes, allow_partial, /*memory=*/nullptr);
 }
 
-void LocalRouterLink::AcceptParcel(Parcel& parcel) {
+void LocalRouterLink::AcceptParcel(const OperationContext& context,
+                                   Parcel& parcel) {
   if (Ref<Router> receiver = state_->GetRouter(side_.opposite())) {
     if (state_->type() == LinkType::kCentral) {
-      receiver->AcceptInboundParcel(parcel);
+      receiver->AcceptInboundParcel(context, parcel);
     } else {
       ABSL_ASSERT(state_->type() == LinkType::kBridge);
-      receiver->AcceptOutboundParcel(parcel);
+      receiver->AcceptOutboundParcel(context, parcel);
     }
   }
 }
 
-void LocalRouterLink::AcceptRouteClosure(SequenceNumber sequence_length) {
+void LocalRouterLink::AcceptRouteClosure(const OperationContext& context,
+                                         SequenceNumber sequence_length) {
   if (Ref<Router> receiver = state_->GetRouter(side_.opposite())) {
-    receiver->AcceptRouteClosureFrom(state_->type(), sequence_length);
+    receiver->AcceptRouteClosureFrom(context, state_->type(), sequence_length);
   }
 }
 
@@ -137,15 +139,15 @@
   return &state_->link_state().GetQueueState(side_);
 }
 
-void LocalRouterLink::SnapshotPeerQueueState() {
+void LocalRouterLink::SnapshotPeerQueueState(const OperationContext& context) {
   if (Ref<Router> receiver = state_->GetRouter(side_.opposite())) {
-    receiver->SnapshotPeerQueueState();
+    receiver->SnapshotPeerQueueState(context);
   }
 }
 
-void LocalRouterLink::AcceptRouteDisconnected() {
+void LocalRouterLink::AcceptRouteDisconnected(const OperationContext& context) {
   if (Ref<Router> receiver = state_->GetRouter(side_.opposite())) {
-    receiver->AcceptRouteDisconnectedFrom(state_->type());
+    receiver->AcceptRouteDisconnectedFrom(context, state_->type());
   }
 }
 
@@ -171,10 +173,11 @@
   state_->link_state().Unlock(side_);
 }
 
-bool LocalRouterLink::FlushOtherSideIfWaiting() {
+bool LocalRouterLink::FlushOtherSideIfWaiting(const OperationContext& context) {
   const LinkSide other_side = side_.opposite();
   if (state_->link_state().ResetWaitingBit(other_side)) {
-    state_->GetRouter(other_side)->Flush(Router::kForceProxyBypassAttempt);
+    state_->GetRouter(other_side)
+        ->Flush(context, Router::kForceProxyBypassAttempt);
     return true;
   }
   return false;
@@ -189,24 +192,28 @@
          allowed_source == bypass_request_source;
 }
 
-void LocalRouterLink::BypassPeer(const NodeName& bypass_target_node,
+void LocalRouterLink::BypassPeer(const OperationContext& context,
+                                 const NodeName& bypass_target_node,
                                  SublinkId bypass_target_sublink) {
   // Not implemented, and never called on local links.
   ABSL_ASSERT(false);
 }
 
-void LocalRouterLink::StopProxying(SequenceNumber inbound_sequence_length,
+void LocalRouterLink::StopProxying(const OperationContext& context,
+                                   SequenceNumber inbound_sequence_length,
                                    SequenceNumber outbound_sequence_length) {
   // Not implemented, and never called on local links.
   ABSL_ASSERT(false);
 }
 
-void LocalRouterLink::ProxyWillStop(SequenceNumber inbound_sequence_length) {
+void LocalRouterLink::ProxyWillStop(const OperationContext& context,
+                                    SequenceNumber inbound_sequence_length) {
   // Not implemented, and never called on local links.
   ABSL_ASSERT(false);
 }
 
 void LocalRouterLink::BypassPeerWithLink(
+    const OperationContext& context,
     SublinkId new_sublink,
     FragmentRef<RouterLinkState> new_link_state,
     SequenceNumber inbound_sequence_length) {
@@ -215,6 +222,7 @@
 }
 
 void LocalRouterLink::StopProxyingToLocalPeer(
+    const OperationContext& context,
     SequenceNumber outbound_sequence_length) {
   // Not implemented, and never called on local links.
   ABSL_ASSERT(false);
diff --git a/third_party/ipcz/src/ipcz/local_router_link.h b/third_party/ipcz/src/ipcz/local_router_link.h
index df71443a..ccf33f2e 100644
--- a/third_party/ipcz/src/ipcz/local_router_link.h
+++ b/third_party/ipcz/src/ipcz/local_router_link.h
@@ -41,27 +41,33 @@
   void AllocateParcelData(size_t num_bytes,
                           bool allow_partial,
                           Parcel& parcel) override;
-  void AcceptParcel(Parcel& parcel) override;
-  void AcceptRouteClosure(SequenceNumber sequence_length) override;
-  void AcceptRouteDisconnected() override;
+  void AcceptParcel(const OperationContext& context, Parcel& parcel) override;
+  void AcceptRouteClosure(const OperationContext& context,
+                          SequenceNumber sequence_length) override;
+  void AcceptRouteDisconnected(const OperationContext& context) override;
   AtomicQueueState* GetPeerQueueState() override;
   AtomicQueueState* GetLocalQueueState() override;
-  void SnapshotPeerQueueState() override;
+  void SnapshotPeerQueueState(const OperationContext& context) override;
   void MarkSideStable() override;
   bool TryLockForBypass(const NodeName& bypass_request_source) override;
   bool TryLockForClosure() override;
   void Unlock() override;
-  bool FlushOtherSideIfWaiting() override;
+  bool FlushOtherSideIfWaiting(const OperationContext& context) override;
   bool CanNodeRequestBypass(const NodeName& bypass_request_source) override;
-  void BypassPeer(const NodeName& bypass_target_node,
+  void BypassPeer(const OperationContext& context,
+                  const NodeName& bypass_target_node,
                   SublinkId bypass_target_sublink) override;
-  void StopProxying(SequenceNumber inbound_sequence_length,
+  void StopProxying(const OperationContext& context,
+                    SequenceNumber inbound_sequence_length,
                     SequenceNumber outbound_sequence_length) override;
-  void ProxyWillStop(SequenceNumber inbound_sequence_length) override;
-  void BypassPeerWithLink(SublinkId new_sublink,
+  void ProxyWillStop(const OperationContext& context,
+                     SequenceNumber inbound_sequence_length) override;
+  void BypassPeerWithLink(const OperationContext& context,
+                          SublinkId new_sublink,
                           FragmentRef<RouterLinkState> new_link_state,
                           SequenceNumber inbound_sequence_length) override;
   void StopProxyingToLocalPeer(
+      const OperationContext& context,
       SequenceNumber outbound_sequence_length) override;
   void Deactivate() override;
   std::string Describe() const override;
diff --git a/third_party/ipcz/src/ipcz/node.cc b/third_party/ipcz/src/ipcz/node.cc
index 47fcc96..f2fc29e 100644
--- a/third_party/ipcz/src/ipcz/node.cc
+++ b/third_party/ipcz/src/ipcz/node.cc
@@ -142,7 +142,9 @@
     auto [it, inserted] = connections_.insert({remote_node_name, connection});
     if (!inserted) {
       lock.Release();
-      connection.link->Deactivate();
+
+      const OperationContext context{OperationContext::kTransportNotification};
+      connection.link->Deactivate(context);
       return false;
     }
 
@@ -352,6 +354,12 @@
   std::unique_ptr<PendingIntroduction> pending_introduction;
   {
     absl::MutexLock lock(&mutex_);
+    if (type_ == Type::kNormal && !broker_link_) {
+      // If we've lost our broker connection, we should ignore any further
+      // introductions that arrive.
+      return;
+    }
+
     auto [connection_it, inserted] =
         connections_.insert({name,
                              {
@@ -432,7 +440,8 @@
   return true;
 }
 
-void Node::DropConnection(const NodeName& name) {
+void Node::DropConnection(const OperationContext& context,
+                          const NodeName& name) {
   Ref<NodeLink> link;
   std::vector<NodeName> pending_introductions;
   bool lost_broker = false;
@@ -463,7 +472,7 @@
     }
 
     // Accumulate the set of currently pending introductions. If any of them are
-    // awaiting a response from the dropped link, theie expectations will be
+    // awaiting a response from the dropped link, their expectations will be
     // updated accordingly by NotifyIntroductionFailed() below.
     pending_introductions.reserve(pending_introductions_.size());
     for (auto& [target, intro] : pending_introductions_) {
@@ -471,7 +480,7 @@
     }
   }
 
-  link->Deactivate();
+  link->Deactivate(context);
 
   if (lost_broker) {
     CancelAllIntroductions();
@@ -553,8 +562,9 @@
     other_brokers_.clear();
   }
 
+  const OperationContext context{OperationContext::kAPICall};
   for (const auto& entry : connections) {
-    entry.second.link->Deactivate();
+    entry.second.link->Deactivate(context);
   }
 
   CancelAllIntroductions();
diff --git a/third_party/ipcz/src/ipcz/node.h b/third_party/ipcz/src/ipcz/node.h
index 1e03123f..ee9a223f 100644
--- a/third_party/ipcz/src/ipcz/node.h
+++ b/third_party/ipcz/src/ipcz/node.h
@@ -17,6 +17,7 @@
 #include "ipcz/node_messages.h"
 #include "ipcz/node_name.h"
 #include "ipcz/node_type.h"
+#include "ipcz/operation_context.h"
 #include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
 #include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
 #include "third_party/abseil-cpp/absl/synchronization/mutex.h"
@@ -156,7 +157,7 @@
   bool AcceptRelayedMessage(msg::AcceptRelayedMessage& accept);
 
   // Drops this node's connection to the named node, if one exists.
-  void DropConnection(const NodeName& name);
+  void DropConnection(const OperationContext& context, const NodeName& name);
 
   // Asynchronously waits for this Node to acquire a broker link and then
   // invokes `callback` with it. If this node already has a broker link then the
diff --git a/third_party/ipcz/src/ipcz/node_connector.cc b/third_party/ipcz/src/ipcz/node_connector.cc
index cc83918..41a64de55 100644
--- a/third_party/ipcz/src/ipcz/node_connector.cc
+++ b/third_party/ipcz/src/ipcz/node_connector.cc
@@ -14,6 +14,7 @@
 #include "ipcz/link_type.h"
 #include "ipcz/node_link.h"
 #include "ipcz/node_link_memory.h"
+#include "ipcz/operation_context.h"
 #include "ipcz/portal.h"
 #include "ipcz/remote_router_link.h"
 #include "ipcz/router.h"
@@ -612,26 +613,29 @@
 
 void NodeConnector::EstablishWaitingPortals(Ref<NodeLink> to_link,
                                             size_t max_valid_portals) {
+  // All paths to this function come from a transport notification.
+  const OperationContext context{OperationContext::kTransportNotification};
+
   ABSL_ASSERT(to_link != nullptr || max_valid_portals == 0);
   const size_t num_valid_portals =
       std::min(max_valid_portals, waiting_portals_.size());
   for (size_t i = 0; i < num_valid_portals; ++i) {
     const Ref<Router> router = waiting_portals_[i]->router();
     Ref<RouterLink> link = to_link->AddRemoteRouterLink(
-        SublinkId(i), to_link->memory().GetInitialRouterLinkState(i),
+        context, SublinkId(i), to_link->memory().GetInitialRouterLinkState(i),
         LinkType::kCentral, to_link->link_side(), router);
     if (link) {
-      router->SetOutwardLink(std::move(link));
+      router->SetOutwardLink(context, std::move(link));
     } else {
-      router->AcceptRouteDisconnectedFrom(LinkType::kCentral);
+      router->AcceptRouteDisconnectedFrom(context, LinkType::kCentral);
     }
   }
 
   // Elicit immediate peer closure on any surplus portals that were established
   // on this side of the link.
   for (size_t i = num_valid_portals; i < waiting_portals_.size(); ++i) {
-    waiting_portals_[i]->router()->AcceptRouteClosureFrom(LinkType::kCentral,
-                                                          SequenceNumber(0));
+    waiting_portals_[i]->router()->AcceptRouteClosureFrom(
+        context, LinkType::kCentral, SequenceNumber(0));
   }
 }
 
diff --git a/third_party/ipcz/src/ipcz/node_link.cc b/third_party/ipcz/src/ipcz/node_link.cc
index 63ccee5..0fb03fe 100644
--- a/third_party/ipcz/src/ipcz/node_link.cc
+++ b/third_party/ipcz/src/ipcz/node_link.cc
@@ -22,6 +22,7 @@
 #include "ipcz/node_connector.h"
 #include "ipcz/node_link_memory.h"
 #include "ipcz/node_messages.h"
+#include "ipcz/operation_context.h"
 #include "ipcz/parcel.h"
 #include "ipcz/portal.h"
 #include "ipcz/remote_router_link.h"
@@ -123,12 +124,13 @@
 }
 
 Ref<RemoteRouterLink> NodeLink::AddRemoteRouterLink(
+    const OperationContext& context,
     SublinkId sublink,
     FragmentRef<RouterLinkState> link_state,
     LinkType type,
     LinkSide side,
     Ref<Router> router) {
-  auto link = RemoteRouterLink::Create(WrapRefCounted(this), sublink,
+  auto link = RemoteRouterLink::Create(context, WrapRefCounted(this), sublink,
                                        std::move(link_state), type, side);
 
   absl::MutexLock lock(&mutex_);
@@ -320,7 +322,7 @@
   }
 }
 
-void NodeLink::Deactivate() {
+void NodeLink::Deactivate(const OperationContext& context) {
   {
     absl::MutexLock lock(&mutex_);
     if (activation_state_ != kActive) {
@@ -329,7 +331,7 @@
     activation_state_ = kDeactivated;
   }
 
-  OnTransportError();
+  HandleTransportError(context);
   transport_->Deactivate();
   memory_->SetNodeLink(nullptr);
 }
@@ -613,8 +615,10 @@
     return true;
   }
 
+  const OperationContext context{OperationContext::kTransportNotification};
   return sublink->receiver->AcceptRouteClosureFrom(
-      sublink->router_link->GetType(), route_closed.params().sequence_length);
+      context, sublink->router_link->GetType(),
+      route_closed.params().sequence_length);
 }
 
 bool NodeLink::OnRouteDisconnected(msg::RouteDisconnected& route_closed) {
@@ -626,13 +630,15 @@
   DVLOG(4) << "Accepting RouteDisconnected at "
            << sublink->router_link->Describe();
 
+  const OperationContext context{OperationContext::kTransportNotification};
   return sublink->receiver->AcceptRouteDisconnectedFrom(
-      sublink->router_link->GetType());
+      context, sublink->router_link->GetType());
 }
 
 bool NodeLink::OnSnapshotPeerQueueState(msg::SnapshotPeerQueueState& snapshot) {
+  const OperationContext context{OperationContext::kTransportNotification};
   if (Ref<Router> router = GetRouter(snapshot.params().sublink)) {
-    router->SnapshotPeerQueueState();
+    router->SnapshotPeerQueueState(context);
   }
   return true;
 }
@@ -645,7 +651,8 @@
 
   // NOTE: This request is authenticated by the receiving Router, within
   // BypassPeer().
-  return sublink->receiver->BypassPeer(*sublink->router_link,
+  const OperationContext context{OperationContext::kTransportNotification};
+  return sublink->receiver->BypassPeer(context, *sublink->router_link,
                                        bypass.params().bypass_target_node,
                                        bypass.params().bypass_target_sublink);
 }
@@ -678,8 +685,9 @@
     return false;
   }
 
+  const OperationContext context{OperationContext::kTransportNotification};
   return receiver->AcceptBypassLink(
-      *this, accept.params().new_sublink, std::move(link_state),
+      context, *this, accept.params().new_sublink, std::move(link_state),
       accept.params().inbound_sequence_length_from_bypassed_link);
 }
 
@@ -689,7 +697,8 @@
     return true;
   }
 
-  return router->StopProxying(stop.params().inbound_sequence_length,
+  const OperationContext context{OperationContext::kTransportNotification};
+  return router->StopProxying(context, stop.params().inbound_sequence_length,
                               stop.params().outbound_sequence_length);
 }
 
@@ -699,8 +708,9 @@
     return true;
   }
 
+  const OperationContext context{OperationContext::kTransportNotification};
   return router->NotifyProxyWillStop(
-      will_stop.params().inbound_sequence_length);
+      context, will_stop.params().inbound_sequence_length);
 }
 
 bool NodeLink::OnBypassPeerWithLink(msg::BypassPeerWithLink& bypass) {
@@ -714,7 +724,9 @@
   if (link_state.is_null()) {
     return false;
   }
-  return router->AcceptBypassLink(*this, bypass.params().new_sublink,
+
+  const OperationContext context{OperationContext::kTransportNotification};
+  return router->AcceptBypassLink(context, *this, bypass.params().new_sublink,
                                   std::move(link_state),
                                   bypass.params().inbound_sequence_length);
 }
@@ -725,13 +737,15 @@
     return true;
   }
 
+  const OperationContext context{OperationContext::kTransportNotification};
   return router->StopProxyingToLocalPeer(
-      stop.params().outbound_sequence_length);
+      context, stop.params().outbound_sequence_length);
 }
 
 bool NodeLink::OnFlushRouter(msg::FlushRouter& flush) {
   if (Ref<Router> router = GetRouter(flush.params().sublink)) {
-    router->Flush(Router::kForceProxyBypassAttempt);
+    const OperationContext context{OperationContext::kTransportNotification};
+    router->Flush(context, Router::kForceProxyBypassAttempt);
   }
   return true;
 }
@@ -786,6 +800,11 @@
 }
 
 void NodeLink::OnTransportError() {
+  const OperationContext context{OperationContext::kTransportNotification};
+  HandleTransportError(context);
+}
+
+void NodeLink::HandleTransportError(const OperationContext& context) {
   SublinkMap sublinks;
   {
     absl::MutexLock lock(&mutex_);
@@ -796,11 +815,11 @@
     DVLOG(4) << "NodeLink disconnection dropping "
              << sublink.router_link->Describe() << " which is bound to router "
              << sublink.receiver.get();
-    sublink.receiver->NotifyLinkDisconnected(*sublink.router_link);
+    sublink.receiver->NotifyLinkDisconnected(context, *sublink.router_link);
   }
 
   Ref<NodeLink> self = WrapRefCounted(this);
-  node_->DropConnection(remote_node_name_);
+  node_->DropConnection(context, remote_node_name_);
 }
 
 void NodeLink::WaitForParcelFragmentToResolve(
@@ -920,18 +939,19 @@
     return true;
   }
 
+  const OperationContext context{OperationContext::kTransportNotification};
   parcel.set_remote_source(WrapRefCounted(this));
   const LinkType link_type = sublink->router_link->GetType();
   if (link_type.is_outward()) {
     DVLOG(4) << "Accepting inbound " << parcel.Describe() << " at "
              << sublink->router_link->Describe();
-    return sublink->receiver->AcceptInboundParcel(parcel);
+    return sublink->receiver->AcceptInboundParcel(context, parcel);
   }
 
   ABSL_ASSERT(link_type.is_peripheral_inward());
   DVLOG(4) << "Accepting outbound " << parcel.Describe() << " at "
            << sublink->router_link->Describe();
-  return sublink->receiver->AcceptOutboundParcel(parcel);
+  return sublink->receiver->AcceptOutboundParcel(context, parcel);
 }
 
 NodeLink::Sublink::Sublink(Ref<RemoteRouterLink> router_link,
diff --git a/third_party/ipcz/src/ipcz/node_link.h b/third_party/ipcz/src/ipcz/node_link.h
index d046de20..fcd412a 100644
--- a/third_party/ipcz/src/ipcz/node_link.h
+++ b/third_party/ipcz/src/ipcz/node_link.h
@@ -103,6 +103,7 @@
   // shared RouterLinkState structure for the new link. Only central links
   // require a RouterLinkState.
   Ref<RemoteRouterLink> AddRemoteRouterLink(
+      const OperationContext& context,
       SublinkId sublink,
       FragmentRef<RouterLinkState> link_state,
       LinkType type,
@@ -200,7 +201,7 @@
   // Must only be called on an activated NodeLink, either one which was created
   // with CreateActive(), or one which was activated later by calling
   // Activate().
-  void Deactivate();
+  void Deactivate(const OperationContext& context);
 
   // Finalizes serialization of DriverObjects within `message` and transmits it
   // to the NodeLink's peer, either over the DriverTransport or through shared
@@ -258,6 +259,8 @@
   bool OnAcceptRelayedMessage(msg::AcceptRelayedMessage& accept) override;
   void OnTransportError() override;
 
+  void HandleTransportError(const OperationContext& context);
+
   // Invoked when we receive a Parcel whose data fragment resides in a buffer
   // not yet known to the local node. This schedules the parcel for acceptance
   // as soon as that buffer is available.
diff --git a/third_party/ipcz/src/ipcz/node_link_test.cc b/third_party/ipcz/src/ipcz/node_link_test.cc
index 99f7619..29c26eb 100644
--- a/third_party/ipcz/src/ipcz/node_link_test.cc
+++ b/third_party/ipcz/src/ipcz/node_link_test.cc
@@ -10,6 +10,7 @@
 #include "ipcz/link_side.h"
 #include "ipcz/link_type.h"
 #include "ipcz/node_link_memory.h"
+#include "ipcz/operation_context.h"
 #include "ipcz/remote_router_link.h"
 #include "ipcz/router.h"
 #include "ipcz/sublink_id.h"
@@ -61,15 +62,21 @@
   Ref<Node> node1 = MakeRefCounted<Node>(Node::Type::kNormal, kDriver,
                                          IPCZ_INVALID_DRIVER_HANDLE);
 
+  // The choice of OperationContext is arbitrary and irrelevant for this test.
+  const OperationContext context{OperationContext::kTransportNotification};
   auto [link0, link1] = LinkNodes(node0, node1);
   auto router0 = MakeRefCounted<Router>();
   auto router1 = MakeRefCounted<Router>();
   FragmentRef<RouterLinkState> link_state =
       link0->memory().GetInitialRouterLinkState(0);
-  router0->SetOutwardLink(link0->AddRemoteRouterLink(
-      SublinkId(0), link_state, LinkType::kCentral, LinkSide::kA, router0));
-  router1->SetOutwardLink(link1->AddRemoteRouterLink(
-      SublinkId(0), link_state, LinkType::kCentral, LinkSide::kB, router1));
+  router0->SetOutwardLink(
+      context,
+      link0->AddRemoteRouterLink(context, SublinkId(0), link_state,
+                                 LinkType::kCentral, LinkSide::kA, router0));
+  router1->SetOutwardLink(
+      context,
+      link1->AddRemoteRouterLink(context, SublinkId(0), link_state,
+                                 LinkType::kCentral, LinkSide::kB, router1));
   link_state->status = RouterLinkState::kStable;
 
   EXPECT_FALSE(router1->IsPeerClosed());
@@ -77,8 +84,8 @@
   EXPECT_TRUE(router1->IsPeerClosed());
   router1->CloseRoute();
 
-  link0->Deactivate();
-  link1->Deactivate();
+  link0->Deactivate(context);
+  link1->Deactivate(context);
 }
 
 }  // namespace
diff --git a/third_party/ipcz/src/ipcz/operation_context.h b/third_party/ipcz/src/ipcz/operation_context.h
new file mode 100644
index 0000000..0d6c0ba
--- /dev/null
+++ b/third_party/ipcz/src/ipcz/operation_context.h
@@ -0,0 +1,46 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPCZ_SRC_IPCZ_OPERATION_CONTEXT_H_
+#define IPCZ_SRC_IPCZ_OPERATION_CONTEXT_H_
+
+namespace ipcz {
+
+// Structure to capture any relevant context regarding an ongoing ipcz
+// operation. This is plumbed throughout methods on Router and other related
+// objects as needed to provide context for any events emitted by ipcz.
+struct OperationContext {
+  // Indicates the nature of the innermost entry point into ipcz for the current
+  // call stack. For any call stack within ipcz which propagates an
+  // OperationContext, the correct EntryPoint can be deduced by walking up the
+  // stack until hitting either an API entry point (i.e. an explicit IpczAPI
+  // function invocation) OR a driver transport notification (i.e. an
+  // IpczTransportActivityHandler invocation.)
+  enum class EntryPoint {
+    // The current innermost stack frame entering ipcz is a direct IpczAPI call.
+    kAPICall,
+
+    // The current innermost stack frame entering ipcz is a driver transport
+    // activity notification.
+    kTransportNotification,
+  };
+
+  static constexpr EntryPoint kAPICall = EntryPoint::kAPICall;
+  static constexpr EntryPoint kTransportNotification =
+      EntryPoint::kTransportNotification;
+
+  explicit OperationContext(EntryPoint entry_point)
+      : entry_point_(entry_point) {}
+  OperationContext(const OperationContext&) = default;
+  OperationContext& operator=(const OperationContext&) = default;
+
+  bool is_api_call() const { return entry_point_ == kAPICall; }
+
+ private:
+  EntryPoint entry_point_;
+};
+
+}  // namespace ipcz
+
+#endif  // IPCZ_SRC_IPCZ_OPERATION_CONTEXT_H_
diff --git a/third_party/ipcz/src/ipcz/portal.cc b/third_party/ipcz/src/ipcz/portal.cc
index babfcd5..fd8d645 100644
--- a/third_party/ipcz/src/ipcz/portal.cc
+++ b/third_party/ipcz/src/ipcz/portal.cc
@@ -10,6 +10,7 @@
 
 #include "ipcz/api_object.h"
 #include "ipcz/local_router_link.h"
+#include "ipcz/operation_context.h"
 #include "ipcz/router.h"
 #include "third_party/abseil-cpp/absl/types/span.h"
 #include "util/log.h"
@@ -47,10 +48,11 @@
   DVLOG(5) << "Created new portal pair with routers " << routers.first.get()
            << " and " << routers.second.get();
 
+  const OperationContext context{OperationContext::kAPICall};
   auto links = LocalRouterLink::CreatePair(LinkType::kCentral, routers,
                                            LocalRouterLink::kStable);
-  routers.first->SetOutwardLink(std::move(links.first));
-  routers.second->SetOutwardLink(std::move(links.second));
+  routers.first->SetOutwardLink(context, std::move(links.first));
+  routers.second->SetOutwardLink(context, std::move(links.second));
   return {MakeRefCounted<Portal>(node, std::move(routers.first)),
           MakeRefCounted<Portal>(node, std::move(routers.second))};
 }
diff --git a/third_party/ipcz/src/ipcz/remote_router_link.cc b/third_party/ipcz/src/ipcz/remote_router_link.cc
index 69a85501..a2dbc96 100644
--- a/third_party/ipcz/src/ipcz/remote_router_link.cc
+++ b/third_party/ipcz/src/ipcz/remote_router_link.cc
@@ -19,7 +19,8 @@
 
 namespace ipcz {
 
-RemoteRouterLink::RemoteRouterLink(Ref<NodeLink> node_link,
+RemoteRouterLink::RemoteRouterLink(const OperationContext& context,
+                                   Ref<NodeLink> node_link,
                                    SublinkId sublink,
                                    FragmentRef<RouterLinkState> link_state,
                                    LinkType type,
@@ -33,7 +34,7 @@
   ABSL_ASSERT(type.is_central() == !link_state.is_null());
 
   if (type.is_central()) {
-    SetLinkState(std::move(link_state));
+    SetLinkState(context, std::move(link_state));
   }
 }
 
@@ -41,16 +42,18 @@
 
 // static
 Ref<RemoteRouterLink> RemoteRouterLink::Create(
+    const OperationContext& context,
     Ref<NodeLink> node_link,
     SublinkId sublink,
     FragmentRef<RouterLinkState> link_state,
     LinkType type,
     LinkSide side) {
-  return AdoptRef(new RemoteRouterLink(std::move(node_link), sublink,
+  return AdoptRef(new RemoteRouterLink(context, std::move(node_link), sublink,
                                        std::move(link_state), type, side));
 }
 
-void RemoteRouterLink::SetLinkState(FragmentRef<RouterLinkState> state) {
+void RemoteRouterLink::SetLinkState(const OperationContext& context,
+                                    FragmentRef<RouterLinkState> state) {
   ABSL_ASSERT(type_.is_central());
   ABSL_ASSERT(!state.is_null());
 
@@ -60,9 +63,9 @@
     FragmentDescriptor descriptor = state.fragment().descriptor();
     memory->WaitForBufferAsync(
         descriptor.buffer_id(),
-        [self = WrapRefCounted(this), memory, descriptor] {
-          self->SetLinkState(memory->AdoptFragmentRef<RouterLinkState>(
-              memory->GetFragment(descriptor)));
+        [self = WrapRefCounted(this), memory, descriptor, context] {
+          self->SetLinkState(context, memory->AdoptFragmentRef<RouterLinkState>(
+                                          memory->GetFragment(descriptor)));
         });
     return;
   }
@@ -95,7 +98,7 @@
     MarkSideStable();
   }
   if (Ref<Router> router = node_link()->GetRouter(sublink_)) {
-    router->Flush(Router::kForceProxyBypassAttempt);
+    router->Flush(context, Router::kForceProxyBypassAttempt);
   }
 }
 
@@ -133,7 +136,8 @@
   parcel.AllocateData(num_bytes, allow_partial, &node_link()->memory());
 }
 
-void RemoteRouterLink::AcceptParcel(Parcel& parcel) {
+void RemoteRouterLink::AcceptParcel(const OperationContext& context,
+                                    Parcel& parcel) {
   const absl::Span<Ref<APIObject>> objects = parcel.objects_view();
 
   msg::AcceptParcel accept;
@@ -233,7 +237,8 @@
 
         Ref<Router> router = Portal::FromObject(&object)->router();
         ABSL_ASSERT(portal_index < num_portals);
-        router->SerializeNewRouter(*node_link(), descriptors[portal_index]);
+        router->SerializeNewRouter(context, *node_link(),
+                                   descriptors[portal_index]);
         routers_to_proxy[portal_index] = std::move(router);
         ++portal_index;
         break;
@@ -278,7 +283,8 @@
   // any routers whose routes have just been extended to the destination.
   ABSL_ASSERT(routers_to_proxy.size() == descriptors.size());
   for (size_t i = 0; i < routers_to_proxy.size(); ++i) {
-    routers_to_proxy[i]->BeginProxyingToNewRouter(*node_link(), descriptors[i]);
+    routers_to_proxy[i]->BeginProxyingToNewRouter(context, *node_link(),
+                                                  descriptors[i]);
   }
 
   // Finally, a Parcel will normally close all attached objects when destroyed.
@@ -289,7 +295,8 @@
   }
 }
 
-void RemoteRouterLink::AcceptRouteClosure(SequenceNumber sequence_length) {
+void RemoteRouterLink::AcceptRouteClosure(const OperationContext& context,
+                                          SequenceNumber sequence_length) {
   msg::RouteClosed route_closed;
   route_closed.params().sublink = sublink_;
   route_closed.params().sequence_length = sequence_length;
@@ -310,13 +317,14 @@
   return nullptr;
 }
 
-void RemoteRouterLink::SnapshotPeerQueueState() {
+void RemoteRouterLink::SnapshotPeerQueueState(const OperationContext& context) {
   msg::SnapshotPeerQueueState snapshot;
   snapshot.params().sublink = sublink_;
   node_link()->Transmit(snapshot);
 }
 
-void RemoteRouterLink::AcceptRouteDisconnected() {
+void RemoteRouterLink::AcceptRouteDisconnected(
+    const OperationContext& context) {
   msg::RouteDisconnected route_disconnected;
   route_disconnected.params().sublink = sublink_;
   node_link()->Transmit(route_disconnected);
@@ -350,7 +358,8 @@
   }
 }
 
-bool RemoteRouterLink::FlushOtherSideIfWaiting() {
+bool RemoteRouterLink::FlushOtherSideIfWaiting(
+    const OperationContext& context) {
   RouterLinkState* state = GetLinkState();
   if (!state || !state->ResetWaitingBit(side_.opposite())) {
     return false;
@@ -378,7 +387,8 @@
   node_link()->RemoveRemoteRouterLink(sublink_);
 }
 
-void RemoteRouterLink::BypassPeer(const NodeName& bypass_target_node,
+void RemoteRouterLink::BypassPeer(const OperationContext& context,
+                                  const NodeName& bypass_target_node,
                                   SublinkId bypass_target_sublink) {
   msg::BypassPeer bypass;
   bypass.params().sublink = sublink_;
@@ -388,7 +398,8 @@
   node_link()->Transmit(bypass);
 }
 
-void RemoteRouterLink::StopProxying(SequenceNumber inbound_sequence_length,
+void RemoteRouterLink::StopProxying(const OperationContext& context,
+                                    SequenceNumber inbound_sequence_length,
                                     SequenceNumber outbound_sequence_length) {
   msg::StopProxying stop;
   stop.params().sublink = sublink_;
@@ -397,7 +408,8 @@
   node_link()->Transmit(stop);
 }
 
-void RemoteRouterLink::ProxyWillStop(SequenceNumber inbound_sequence_length) {
+void RemoteRouterLink::ProxyWillStop(const OperationContext& context,
+                                     SequenceNumber inbound_sequence_length) {
   msg::ProxyWillStop will_stop;
   will_stop.params().sublink = sublink_;
   will_stop.params().inbound_sequence_length = inbound_sequence_length;
@@ -405,6 +417,7 @@
 }
 
 void RemoteRouterLink::BypassPeerWithLink(
+    const OperationContext& context,
     SublinkId new_sublink,
     FragmentRef<RouterLinkState> new_link_state,
     SequenceNumber inbound_sequence_length) {
@@ -418,6 +431,7 @@
 }
 
 void RemoteRouterLink::StopProxyingToLocalPeer(
+    const OperationContext& context,
     SequenceNumber outbound_sequence_length) {
   msg::StopProxyingToLocalPeer stop;
   stop.params().sublink = sublink_;
diff --git a/third_party/ipcz/src/ipcz/remote_router_link.h b/third_party/ipcz/src/ipcz/remote_router_link.h
index a5988d28..970bf55 100644
--- a/third_party/ipcz/src/ipcz/remote_router_link.h
+++ b/third_party/ipcz/src/ipcz/remote_router_link.h
@@ -42,7 +42,8 @@
   // of link it is -- which for remote links must be either kCentral,
   // kPeripheralInward, or kPeripheralOutward. If the link is kCentral, a
   // non-null `link_state` must be provided for the link's RouterLinkState.
-  static Ref<RemoteRouterLink> Create(Ref<NodeLink> node_link,
+  static Ref<RemoteRouterLink> Create(const OperationContext& context,
+                                      Ref<NodeLink> node_link,
                                       SublinkId sublink,
                                       FragmentRef<RouterLinkState> link_state,
                                       LinkType type,
@@ -60,33 +61,40 @@
   void AllocateParcelData(size_t num_bytes,
                           bool allow_partial,
                           Parcel& parcel) override;
-  void AcceptParcel(Parcel& parcel) override;
-  void AcceptRouteClosure(SequenceNumber sequence_length) override;
-  void AcceptRouteDisconnected() override;
+  void AcceptParcel(const OperationContext& context, Parcel& parcel) override;
+  void AcceptRouteClosure(const OperationContext& context,
+                          SequenceNumber sequence_length) override;
+  void AcceptRouteDisconnected(const OperationContext& context) override;
   AtomicQueueState* GetPeerQueueState() override;
   AtomicQueueState* GetLocalQueueState() override;
-  void SnapshotPeerQueueState() override;
+  void SnapshotPeerQueueState(const OperationContext& context) override;
   void MarkSideStable() override;
   bool TryLockForBypass(const NodeName& bypass_request_source) override;
   bool TryLockForClosure() override;
   void Unlock() override;
-  bool FlushOtherSideIfWaiting() override;
+  bool FlushOtherSideIfWaiting(const OperationContext& context) override;
   bool CanNodeRequestBypass(const NodeName& bypass_request_source) override;
-  void BypassPeer(const NodeName& bypass_target_node,
+  void BypassPeer(const OperationContext& context,
+                  const NodeName& bypass_target_node,
                   SublinkId bypass_request_sublink) override;
-  void StopProxying(SequenceNumber inbound_sequence_length,
+  void StopProxying(const OperationContext& context,
+                    SequenceNumber inbound_sequence_length,
                     SequenceNumber outbound_sequence_length) override;
-  void ProxyWillStop(SequenceNumber inbound_sequence_length) override;
-  void BypassPeerWithLink(SublinkId new_sublink,
+  void ProxyWillStop(const OperationContext& context,
+                     SequenceNumber inbound_sequence_length) override;
+  void BypassPeerWithLink(const OperationContext& context,
+                          SublinkId new_sublink,
                           FragmentRef<RouterLinkState> new_link_state,
                           SequenceNumber inbound_sequence_length) override;
   void StopProxyingToLocalPeer(
+      const OperationContext& context,
       SequenceNumber outbound_sequence_length) override;
   void Deactivate() override;
   std::string Describe() const override;
 
  private:
-  RemoteRouterLink(Ref<NodeLink> node_link,
+  RemoteRouterLink(const OperationContext& context,
+                   Ref<NodeLink> node_link,
                    SublinkId sublink,
                    FragmentRef<RouterLinkState> link_state,
                    LinkType type,
@@ -96,7 +104,8 @@
 
   // Sets this link's RouterLinkState. `state` must be pending or addressable
   // and this must be a central link.
-  void SetLinkState(FragmentRef<RouterLinkState> state);
+  void SetLinkState(const OperationContext& context,
+                    FragmentRef<RouterLinkState> state);
 
   const Ref<NodeLink> node_link_;
   const SublinkId sublink_;
diff --git a/third_party/ipcz/src/ipcz/router.cc b/third_party/ipcz/src/ipcz/router.cc
index 20d644b9..ba69842 100644
--- a/third_party/ipcz/src/ipcz/router.cc
+++ b/third_party/ipcz/src/ipcz/router.cc
@@ -13,6 +13,7 @@
 #include "ipcz/ipcz.h"
 #include "ipcz/local_router_link.h"
 #include "ipcz/node_link.h"
+#include "ipcz/operation_context.h"
 #include "ipcz/remote_router_link.h"
 #include "ipcz/sequence_number.h"
 #include "ipcz/trap_event_dispatcher.h"
@@ -160,28 +161,30 @@
     }
   }
 
+  const OperationContext context{OperationContext::kAPICall};
   if (link) {
-    link->AcceptParcel(parcel);
+    link->AcceptParcel(context, parcel);
   } else {
-    Flush();
+    Flush(context);
   }
   return IPCZ_RESULT_OK;
 }
 
 void Router::CloseRoute() {
+  const OperationContext context{OperationContext::kAPICall};
   TrapEventDispatcher dispatcher;
   Ref<RouterLink> link;
   {
     absl::MutexLock lock(&mutex_);
     outbound_parcels_.SetFinalSequenceLength(
         outbound_parcels_.GetCurrentSequenceLength());
-    traps_.RemoveAll(dispatcher);
+    traps_.RemoveAll(context, dispatcher);
   }
-
-  Flush();
+  Flush(context);
 }
 
-void Router::SetOutwardLink(Ref<RouterLink> link) {
+void Router::SetOutwardLink(const OperationContext& context,
+                            Ref<RouterLink> link) {
   ABSL_ASSERT(link);
 
   {
@@ -201,12 +204,12 @@
 
   if (link) {
     // If the link wasn't adopted, this Router has already been disconnected.
-    link->AcceptRouteDisconnected();
+    link->AcceptRouteDisconnected(context);
     link->Deactivate();
     return;
   }
 
-  Flush(kForceProxyBypassAttempt);
+  Flush(context, kForceProxyBypassAttempt);
 }
 
 size_t Router::GetOutboundCapacityInBytes(const IpczPutLimits& limits) {
@@ -214,7 +217,8 @@
     return 0;
   }
 
-  SnapshotPeerQueueState();
+  const OperationContext context{OperationContext::kAPICall};
+  SnapshotPeerQueueState(context);
 
   absl::MutexLock lock(&mutex_);
   if (status_.num_remote_parcels >= limits.max_queued_parcels ||
@@ -237,7 +241,8 @@
   return available_capacity - num_bytes_pending;
 }
 
-bool Router::AcceptInboundParcel(Parcel& parcel) {
+bool Router::AcceptInboundParcel(const OperationContext& context,
+                                 Parcel& parcel) {
   TrapEventDispatcher dispatcher;
   {
     absl::MutexLock lock(&mutex_);
@@ -252,16 +257,17 @@
       // If this is a terminal router, we may have trap events to fire.
       status_.num_local_parcels = inbound_parcels_.GetNumAvailableElements();
       status_.num_local_bytes = inbound_parcels_.GetTotalAvailableElementSize();
-      traps_.UpdatePortalStatus(status_, TrapSet::UpdateReason::kNewLocalParcel,
-                                dispatcher);
+      traps_.UpdatePortalStatus(
+          context, status_, TrapSet::UpdateReason::kNewLocalParcel, dispatcher);
     }
   }
 
-  Flush();
+  Flush(context);
   return true;
 }
 
-bool Router::AcceptOutboundParcel(Parcel& parcel) {
+bool Router::AcceptOutboundParcel(const OperationContext& context,
+                                  Parcel& parcel) {
   {
     absl::MutexLock lock(&mutex_);
 
@@ -282,11 +288,12 @@
     }
   }
 
-  Flush();
+  Flush(context);
   return true;
 }
 
-bool Router::AcceptRouteClosureFrom(LinkType link_type,
+bool Router::AcceptRouteClosureFrom(const OperationContext& context,
+                                    LinkType link_type,
                                     SequenceNumber sequence_length) {
   TrapEventDispatcher dispatcher;
   {
@@ -306,8 +313,8 @@
         }
         status_.num_remote_bytes = 0;
         status_.num_remote_parcels = 0;
-        traps_.UpdatePortalStatus(status_, TrapSet::UpdateReason::kPeerClosed,
-                                  dispatcher);
+        traps_.UpdatePortalStatus(
+            context, status_, TrapSet::UpdateReason::kPeerClosed, dispatcher);
       }
     } else if (link_type.is_peripheral_inward()) {
       if (!outbound_parcels_.SetFinalSequenceLength(sequence_length)) {
@@ -324,11 +331,12 @@
     }
   }
 
-  Flush();
+  Flush(context);
   return true;
 }
 
-bool Router::AcceptRouteDisconnectedFrom(LinkType link_type) {
+bool Router::AcceptRouteDisconnectedFrom(const OperationContext& context,
+                                         LinkType link_type) {
   TrapEventDispatcher dispatcher;
   absl::InlinedVector<Ref<RouterLink>, 4> forwarding_links;
   {
@@ -361,24 +369,24 @@
       }
       status_.num_remote_parcels = 0;
       status_.num_remote_bytes = 0;
-      traps_.UpdatePortalStatus(status_, TrapSet::UpdateReason::kPeerClosed,
-                                dispatcher);
+      traps_.UpdatePortalStatus(context, status_,
+                                TrapSet::UpdateReason::kPeerClosed, dispatcher);
     }
   }
 
   for (const Ref<RouterLink>& link : forwarding_links) {
     if (link) {
       DVLOG(4) << "Forwarding disconnection over " << link->Describe();
-      link->AcceptRouteDisconnected();
+      link->AcceptRouteDisconnected(context);
       link->Deactivate();
     }
   }
 
-  Flush();
+  Flush(context);
   return true;
 }
 
-void Router::SnapshotPeerQueueState() {
+void Router::SnapshotPeerQueueState(const OperationContext& context) {
   TrapEventDispatcher dispatcher;
   absl::ReleasableMutexLock lock(&mutex_);
   Ref<RouterLink> outward_link = outward_edge_.primary_link();
@@ -390,8 +398,9 @@
   if (!peer_state) {
     lock.Release();
     // Try again after we have RouterLinkState access.
-    outward_link->WaitForLinkStateAsync(
-        [self = WrapRefCounted(this)] { self->SnapshotPeerQueueState(); });
+    outward_link->WaitForLinkStateAsync([self = WrapRefCounted(this), context] {
+      self->SnapshotPeerQueueState(context);
+    });
     return;
   }
 
@@ -399,8 +408,8 @@
   const AtomicQueueState::QueryResult state =
       peer_state->Query({.monitor_parcels = false, .monitor_bytes = false});
   UpdateStatusForPeerQueueState(state);
-  traps_.UpdatePortalStatus(status_, TrapSet::UpdateReason::kRemoteActivity,
-                            dispatcher);
+  traps_.UpdatePortalStatus(context, status_,
+                            TrapSet::UpdateReason::kRemoteActivity, dispatcher);
   if (!traps_.need_remote_state()) {
     return;
   }
@@ -420,8 +429,8 @@
       .monitor_parcels = traps_.need_remote_parcels(),
       .monitor_bytes = traps_.need_remote_bytes(),
   }));
-  traps_.UpdatePortalStatus(status_, TrapSet::UpdateReason::kRemoteActivity,
-                            dispatcher);
+  traps_.UpdatePortalStatus(context, status_,
+                            TrapSet::UpdateReason::kRemoteActivity, dispatcher);
 }
 
 IpczResult Router::GetNextInboundParcel(IpczGetFlags flags,
@@ -430,6 +439,7 @@
                                         IpczHandle* handles,
                                         size_t* num_handles,
                                         IpczHandle* validator) {
+  const OperationContext context{OperationContext::kAPICall};
   TrapEventDispatcher dispatcher;
   Ref<RouterLink> link_to_notify;
   Ref<NodeLink> remote_source;
@@ -478,15 +488,16 @@
     if (inbound_parcels_.IsSequenceFullyConsumed()) {
       status_.flags |= IPCZ_PORTAL_STATUS_DEAD;
     }
-    traps_.UpdatePortalStatus(
-        status_, TrapSet::UpdateReason::kLocalParcelConsumed, dispatcher);
+    traps_.UpdatePortalStatus(context, status_,
+                              TrapSet::UpdateReason::kLocalParcelConsumed,
+                              dispatcher);
     if (RefreshLocalQueueState()) {
       link_to_notify = outward_edge_.primary_link();
     }
   }
 
   if (link_to_notify) {
-    link_to_notify->SnapshotPeerQueueState();
+    link_to_notify->SnapshotPeerQueueState(context);
   }
 
   if (validator) {
@@ -530,6 +541,7 @@
 IpczResult Router::CommitGetNextIncomingParcel(size_t num_data_bytes_consumed,
                                                absl::Span<IpczHandle> handles,
                                                IpczHandle* validator) {
+  const OperationContext context{OperationContext::kAPICall};
   Ref<RouterLink> link_to_notify;
   Ref<NodeLink> remote_source;
   TrapEventDispatcher dispatcher;
@@ -560,15 +572,16 @@
     if (inbound_parcels_.IsSequenceFullyConsumed()) {
       status_.flags |= IPCZ_PORTAL_STATUS_DEAD;
     }
-    traps_.UpdatePortalStatus(
-        status_, TrapSet::UpdateReason::kLocalParcelConsumed, dispatcher);
+    traps_.UpdatePortalStatus(context, status_,
+                              TrapSet::UpdateReason::kLocalParcelConsumed,
+                              dispatcher);
     if (RefreshLocalQueueState()) {
       link_to_notify = outward_edge_.primary_link();
     }
   }
 
   if (link_to_notify) {
-    link_to_notify->SnapshotPeerQueueState();
+    link_to_notify->SnapshotPeerQueueState(context);
   }
 
   if (validator) {
@@ -653,15 +666,21 @@
     other->bridge_->SetPrimaryLink(std::move(links.second));
   }
 
-  Flush();
+  const OperationContext context{OperationContext::kAPICall};
+  Flush(context);
   return IPCZ_RESULT_OK;
 }
 
 // static
 Ref<Router> Router::Deserialize(const RouterDescriptor& descriptor,
                                 NodeLink& from_node_link) {
+  // All Router deserialization occurs as a direct result of some transport
+  // notification.
+  const OperationContext context{OperationContext::kTransportNotification};
+
   bool disconnected = false;
   auto router = MakeRefCounted<Router>();
+  Ref<RemoteRouterLink> new_outward_link;
   {
     absl::MutexLock lock(&router->mutex_);
     router->outbound_parcels_.ResetSequence(
@@ -683,130 +702,352 @@
       }
     }
 
-    Ref<RemoteRouterLink> new_link = from_node_link.AddRemoteRouterLink(
-        descriptor.new_sublink, nullptr, LinkType::kPeripheralOutward,
-        LinkSide::kB, router);
-    if (new_link) {
-      router->outward_edge_.SetPrimaryLink(std::move(new_link));
+    if (descriptor.proxy_already_bypassed) {
+      // When split from a local peer, our remote counterpart (our remote peer's
+      // former local peer) will use this link to forward parcels it already
+      // received from our peer. This link decays like any other decaying link
+      // once its usefulness has expired.
+      //
+      // The sequence length toward this link is the current outbound sequence
+      // length, which is to say, we will not be sending any parcels that way.
+      // The sequence length from the link is whatever had already been sent
+      // to our counterpart back on the peer's node.
+      Ref<RemoteRouterLink> new_decaying_link =
+          from_node_link.AddRemoteRouterLink(
+              context, descriptor.new_decaying_sublink, nullptr,
+              LinkType::kPeripheralOutward, LinkSide::kB, router);
+      if (!new_decaying_link) {
+        return nullptr;
+      }
+      router->outward_edge_.SetPrimaryLink(std::move(new_decaying_link));
+      router->outward_edge_.BeginPrimaryLinkDecay();
+      router->outward_edge_.set_length_to_decaying_link(
+          router->outbound_parcels_.current_sequence_number());
+      router->outward_edge_.set_length_from_decaying_link(
+          descriptor.decaying_incoming_sequence_length > SequenceNumber(0)
+              ? descriptor.decaying_incoming_sequence_length
+              : descriptor.next_incoming_sequence_number);
+
+      new_outward_link = from_node_link.AddRemoteRouterLink(
+          context, descriptor.new_sublink,
+          from_node_link.memory().AdoptFragmentRef<RouterLinkState>(
+              from_node_link.memory().GetFragment(
+                  descriptor.new_link_state_fragment)),
+          LinkType::kCentral, LinkSide::kB, router);
+      if (!new_outward_link) {
+        return nullptr;
+      }
+      router->outward_edge_.SetPrimaryLink(new_outward_link);
 
       DVLOG(4) << "Route extended from "
                << from_node_link.remote_node_name().ToString() << " to "
                << from_node_link.local_node_name().ToString() << " via sublink "
-               << descriptor.new_sublink;
-    } else if (!descriptor.peer_closed) {
-      // The new portal is DOA, either because the associated NodeLink is dead,
-      // or the sublink ID was already in use. The latter implies a bug or bad
-      // behavior, but it should be harmless to ignore beyond this point.
-      disconnected = true;
+               << descriptor.new_sublink << " and decaying sublink "
+               << descriptor.new_decaying_sublink;
+    } else {
+      if (!descriptor.new_link_state_fragment.is_null()) {
+        // No RouterLinkState fragment should be provided for this new
+        // peripheral link.
+        return nullptr;
+      }
+      new_outward_link = from_node_link.AddRemoteRouterLink(
+          context, descriptor.new_sublink, nullptr,
+          LinkType::kPeripheralOutward, LinkSide::kB, router);
+      if (new_outward_link) {
+        router->outward_edge_.SetPrimaryLink(new_outward_link);
+
+        DVLOG(4) << "Route extended from "
+                 << from_node_link.remote_node_name().ToString() << " to "
+                 << from_node_link.local_node_name().ToString()
+                 << " via sublink " << descriptor.new_sublink;
+      } else if (!descriptor.peer_closed) {
+        // The new portal is DOA, either because the associated NodeLink is
+        // dead, or the sublink ID was already in use. The latter implies a bug
+        // or bad behavior, but it should be harmless to ignore beyond this
+        // point.
+        disconnected = true;
+      }
     }
   }
 
   if (disconnected) {
     DVLOG(4) << "Disconnected new Router immediately after deserialization";
-    router->AcceptRouteDisconnectedFrom(LinkType::kPeripheralOutward);
+    router->AcceptRouteDisconnectedFrom(context, LinkType::kPeripheralOutward);
+  } else if (descriptor.proxy_peer_node_name.is_valid()) {
+    // The source router rolled some peer bypass details into our descriptor to
+    // avoid some IPC overhead. We can begin bypassing the proxy now.
+    ABSL_ASSERT(new_outward_link);
+    router->BypassPeer(context, *new_outward_link,
+                       descriptor.proxy_peer_node_name,
+                       descriptor.proxy_peer_sublink);
   }
-  router->Flush(kForceProxyBypassAttempt);
+
+  router->Flush(context, kForceProxyBypassAttempt);
   return router;
 }
 
-void Router::SerializeNewRouter(NodeLink& to_node_link,
+void Router::SerializeNewRouter(const OperationContext& context,
+                                NodeLink& to_node_link,
                                 RouterDescriptor& descriptor) {
   TrapEventDispatcher dispatcher;
-  const SublinkId new_sublink = to_node_link.memory().AllocateSublinkIds(1);
-  descriptor.new_sublink = new_sublink;
+  Ref<Router> local_peer;
+  bool initiate_proxy_bypass = false;
   {
     absl::MutexLock lock(&mutex_);
-    traps_.RemoveAll(dispatcher);
-
-    descriptor.next_outgoing_sequence_number =
-        outbound_parcels_.GetCurrentSequenceLength();
-    descriptor.num_bytes_produced =
-        outbound_parcels_.total_consumed_element_size();
-    descriptor.next_incoming_sequence_number =
-        inbound_parcels_.current_sequence_number();
-    descriptor.num_bytes_consumed =
-        inbound_parcels_.total_consumed_element_size();
-
-    // Initialize an inward edge but with no link yet. This ensures that we
-    // don't look like a terminal router while waiting for a link to be set,
-    // which can only happen after `descriptor` is transmitted.
-    inward_edge_.emplace();
-
-    if (status_.flags & IPCZ_PORTAL_STATUS_PEER_CLOSED) {
-      descriptor.peer_closed = true;
-      descriptor.closed_peer_sequence_length =
-          *inbound_parcels_.final_sequence_length();
-
-      // Ensure that the new edge decays its link as soon as it has one, since
-      // we know the link will not be used.
-      inward_edge_->BeginPrimaryLinkDecay();
-      inward_edge_->set_length_to_decaying_link(
-          *inbound_parcels_.final_sequence_length());
-      inward_edge_->set_length_from_decaying_link(
-          outbound_parcels_.current_sequence_number());
-    }
-
-    // Once `descriptor` is transmitted to the destination node and the new
-    // Router is created there, it may immediately begin transmitting messages
-    // back to this node regarding `new_sublink`. We establish a new
-    // RemoteRouterLink now and register it to `new_sublink` on `to_node_link`,
-    // so that any such incoming messages are routed to `this`.
-    //
-    // NOTE: We do not yet provide `this` itself with a reference to the new
-    // RemoteRouterLink, because it's not yet safe for us to send messages to
-    // the remote node regarding `new_sublink`. `descriptor` must be transmitted
-    // first.
-    Ref<RemoteRouterLink> new_link = to_node_link.AddRemoteRouterLink(
-        new_sublink, nullptr, LinkType::kPeripheralInward, LinkSide::kA,
-        WrapRefCounted(this));
-
-    DVLOG(4) << "Router " << this << " extending route with tentative new "
-             << new_link->Describe();
+    traps_.RemoveAll(context, dispatcher);
+    local_peer = outward_edge_.GetLocalPeer();
+    initiate_proxy_bypass = outward_edge_.primary_link() &&
+                            outward_edge_.primary_link()->TryLockForBypass(
+                                to_node_link.remote_node_name());
   }
+
+  if (local_peer && initiate_proxy_bypass &&
+      SerializeNewRouterWithLocalPeer(context, to_node_link, descriptor,
+                                      local_peer)) {
+    return;
+  }
+
+  SerializeNewRouterAndConfigureProxy(context, to_node_link, descriptor,
+                                      initiate_proxy_bypass);
 }
 
-void Router::BeginProxyingToNewRouter(NodeLink& to_node_link,
+bool Router::SerializeNewRouterWithLocalPeer(const OperationContext& context,
+                                             NodeLink& to_node_link,
+                                             RouterDescriptor& descriptor,
+                                             Ref<Router> local_peer) {
+  MultiMutexLock lock(&mutex_, &local_peer->mutex_);
+  if (local_peer->outward_edge_.GetLocalPeer() != this) {
+    // If the peer was closed, its link to us may already be invalidated.
+    return false;
+  }
+
+  FragmentRef<RouterLinkState> new_link_state =
+      to_node_link.memory().TryAllocateRouterLinkState();
+  if (!new_link_state.is_addressable()) {
+    // If we couldn't allocate a RouterLinkState for a new central link, then
+    // we can't replace the central link yet. Fall back to the proxying case.
+    return false;
+  }
+
+  const SequenceNumber proxy_inbound_sequence_length =
+      local_peer->outbound_parcels_.current_sequence_number();
+
+  // The local peer no longer needs its link to us. We'll give it a new
+  // outward link in BeginProxyingToNewRouter() after this descriptor is
+  // transmitted.
+  local_peer->outward_edge_.ReleasePrimaryLink();
+
+  // The primary new sublink to the destination node will act as the route's
+  // new central link between our local peer and the new remote router.
+  //
+  // An additional sublink is allocated to act as a decaying inward link from
+  // this router to the new one, so we can forward any inbound parcels that have
+  // already been queued here.
+  const SublinkId new_sublink = to_node_link.memory().AllocateSublinkIds(2);
+  const SublinkId decaying_sublink = SublinkId(new_sublink.value() + 1);
+
+  // Register the new routes on the NodeLink. Note that we don't provide them to
+  // any routers yet since we don't want the routers using them until this
+  // descriptor is transmitted to its destination node. The links will be
+  // adopted after transmission in BeginProxyingToNewRouter().
+  Ref<RouterLink> new_link = to_node_link.AddRemoteRouterLink(
+      context, new_sublink, new_link_state, LinkType::kCentral, LinkSide::kA,
+      local_peer);
+
+  to_node_link.AddRemoteRouterLink(context, decaying_sublink, nullptr,
+                                   LinkType::kPeripheralInward, LinkSide::kA,
+                                   WrapRefCounted(this));
+
+  descriptor.new_sublink = new_sublink;
+  descriptor.new_link_state_fragment = new_link_state.release().descriptor();
+  descriptor.new_decaying_sublink = decaying_sublink;
+  descriptor.proxy_already_bypassed = true;
+  descriptor.next_outgoing_sequence_number =
+      outbound_parcels_.GetCurrentSequenceLength();
+  descriptor.num_bytes_produced =
+      outbound_parcels_.total_consumed_element_size();
+  descriptor.next_incoming_sequence_number =
+      inbound_parcels_.current_sequence_number();
+  descriptor.num_bytes_consumed =
+      inbound_parcels_.total_consumed_element_size();
+  descriptor.decaying_incoming_sequence_length = proxy_inbound_sequence_length;
+
+  DVLOG(4) << "Splitting local pair to move router with outbound sequence "
+           << "length " << descriptor.next_outgoing_sequence_number
+           << " and current inbound sequence number "
+           << descriptor.next_incoming_sequence_number;
+
+  if (inbound_parcels_.final_sequence_length()) {
+    descriptor.peer_closed = true;
+    descriptor.closed_peer_sequence_length =
+        *inbound_parcels_.final_sequence_length();
+  }
+
+  // Initialize an inward edge that will immediately begin decaying once it has
+  // a link (established in BeginProxyingToNewRouter()).
+  inward_edge_.emplace();
+  inward_edge_->BeginPrimaryLinkDecay();
+  inward_edge_->set_length_to_decaying_link(proxy_inbound_sequence_length);
+  inward_edge_->set_length_from_decaying_link(
+      outbound_parcels_.GetCurrentSequenceLength());
+  return true;
+}
+
+void Router::SerializeNewRouterAndConfigureProxy(
+    const OperationContext& context,
+    NodeLink& to_node_link,
+    RouterDescriptor& descriptor,
+    bool initiate_proxy_bypass) {
+  const SublinkId new_sublink = to_node_link.memory().AllocateSublinkIds(1);
+
+  absl::MutexLock lock(&mutex_);
+  descriptor.new_sublink = new_sublink;
+  descriptor.new_link_state_fragment = FragmentDescriptor();
+  descriptor.proxy_already_bypassed = false;
+  descriptor.next_outgoing_sequence_number =
+      outbound_parcels_.GetCurrentSequenceLength();
+  descriptor.num_bytes_produced =
+      outbound_parcels_.total_consumed_element_size();
+  descriptor.next_incoming_sequence_number =
+      inbound_parcels_.current_sequence_number();
+  descriptor.num_bytes_consumed =
+      inbound_parcels_.total_consumed_element_size();
+
+  // Initialize an inward edge but with no link yet. This ensures that we
+  // don't look like a terminal router while waiting for a link to be set,
+  // which can only happen after `descriptor` is transmitted.
+  inward_edge_.emplace();
+
+  if (status_.flags & IPCZ_PORTAL_STATUS_PEER_CLOSED) {
+    descriptor.peer_closed = true;
+    descriptor.closed_peer_sequence_length =
+        *inbound_parcels_.final_sequence_length();
+
+    // Ensure that the new edge decays its link as soon as it has one, since
+    // we know the link will not be used.
+    inward_edge_->BeginPrimaryLinkDecay();
+    inward_edge_->set_length_to_decaying_link(
+        *inbound_parcels_.final_sequence_length());
+    inward_edge_->set_length_from_decaying_link(
+        outbound_parcels_.current_sequence_number());
+  } else if (initiate_proxy_bypass && outward_edge_.primary_link()) {
+    RemoteRouterLink* remote_link =
+        outward_edge_.primary_link()->AsRemoteRouterLink();
+    if (remote_link) {
+      descriptor.proxy_peer_node_name =
+          remote_link->node_link()->remote_node_name();
+      descriptor.proxy_peer_sublink = remote_link->sublink();
+      DVLOG(4) << "Will initiate proxy bypass immediately on deserialization "
+               << "with peer at " << descriptor.proxy_peer_node_name.ToString()
+               << " and peer route to proxy on sublink "
+               << descriptor.proxy_peer_sublink;
+
+      inward_edge_->BeginPrimaryLinkDecay();
+      outward_edge_.BeginPrimaryLinkDecay();
+    } else {
+      // The link was locked in anticipation of initiating a proxy bypass, but
+      // that's no longer going to happen.
+      outward_edge_.primary_link()->Unlock();
+    }
+  }
+
+  // Once `descriptor` is transmitted to the destination node and the new
+  // Router is created there, it may immediately begin transmitting messages
+  // back to this node regarding `new_sublink`. We establish a new
+  // RemoteRouterLink now and register it to `new_sublink` on `to_node_link`,
+  // so that any such incoming messages are routed to `this`.
+  //
+  // NOTE: We do not yet provide `this` itself with a reference to the new
+  // RemoteRouterLink, because it's not yet safe for us to send messages to
+  // the remote node regarding `new_sublink`. `descriptor` must be transmitted
+  // first.
+  Ref<RemoteRouterLink> new_link = to_node_link.AddRemoteRouterLink(
+      context, new_sublink, nullptr, LinkType::kPeripheralInward, LinkSide::kA,
+      WrapRefCounted(this));
+  DVLOG(4) << "Router " << this << " extending route with tentative new "
+           << new_link->Describe();
+}
+
+void Router::BeginProxyingToNewRouter(const OperationContext& context,
+                                      NodeLink& to_node_link,
                                       const RouterDescriptor& descriptor) {
-  // Acquire a reference to the RemoteRouterLink created by an earlier call to
-  // SerializeNewRouter(). If the NodeLink has already been disconnected, this
+  Ref<RouterLink> peer_link;
+  Ref<Router> local_peer;
+
+  // Acquire references to RemoteRouterLink(s) created by an earlier call to
+  // SerializeNewRouter(). If the NodeLink has already been disconnected, these
   // may be null.
-  if (auto new_sublink = to_node_link.GetSublink(descriptor.new_sublink)) {
-    Ref<RemoteRouterLink> new_router_link = new_sublink->router_link;
-    {
-      absl::MutexLock lock(&mutex_);
-      ABSL_ASSERT(inward_edge_);
+  auto new_sublink = to_node_link.GetSublink(descriptor.new_sublink);
+  auto new_decaying_sublink =
+      to_node_link.GetSublink(descriptor.new_decaying_sublink);
+  if (!new_sublink) {
+    Flush(context, kForceProxyBypassAttempt);
+    return;
+  }
 
-      // If the new router has already been closed or disconnected, we will
-      // discard the new link to it.
-      if (!outbound_parcels_.final_sequence_length() && !is_disconnected_) {
-        DVLOG(4) << "Router " << this << " will proxy to new router over "
-                 << new_router_link->Describe();
+  Ref<RemoteRouterLink> new_primary_link = new_sublink->router_link;
+  Ref<RemoteRouterLink> new_decaying_link;
+  {
+    absl::MutexLock lock(&mutex_);
+    ABSL_ASSERT(inward_edge_);
 
-        inward_edge_->SetPrimaryLink(std::move(new_router_link));
+    if (descriptor.proxy_already_bypassed) {
+      peer_link = outward_edge_.ReleasePrimaryLink();
+      local_peer = peer_link ? peer_link->GetLocalPeer() : nullptr;
+      new_decaying_link =
+          new_decaying_sublink ? new_decaying_sublink->router_link : nullptr;
+    }
 
-        Ref<RouterLink> outward_link = outward_edge_.primary_link();
-        if (outward_link && outward_edge_.is_stable() &&
-            inward_edge_->is_stable()) {
-          outward_link->MarkSideStable();
-        }
+    if (local_peer && new_decaying_link && !is_disconnected_) {
+      // We've already bypassed this router. Use the new decaying link for our
+      // inward edge in case we need to forward parcels to the new router. The
+      // new primary link will be adopted by our peer further below.
+      inward_edge_->SetPrimaryLink(std::move(new_decaying_link));
+    } else if (!outbound_parcels_.final_sequence_length() &&
+               !new_decaying_link && !is_disconnected_) {
+      DVLOG(4) << "Router " << this << " will proxy to new router over "
+               << new_primary_link->Describe();
+      inward_edge_->SetPrimaryLink(std::move(new_primary_link));
+
+      Ref<RouterLink> outward_link = outward_edge_.primary_link();
+      if (outward_link && outward_edge_.is_stable() &&
+          inward_edge_->is_stable()) {
+        outward_link->MarkSideStable();
       }
     }
+  }
 
-    if (new_router_link) {
-      // The link was not adopted, so deactivate and discard it.
-      DVLOG(4) << "Dropping link to new router " << new_router_link->Describe();
-      new_router_link->AcceptRouteDisconnected();
-      new_router_link->Deactivate();
-      return;
-    }
+  if (local_peer && new_primary_link && !new_decaying_link) {
+    // If we have a `local_peer` and no decaying link, this means the decaying
+    // link was successfully adopted for our own inward edge; and the primary
+    // link is therefore meant to serve as our local peer's new outward link
+    // directly to the new remote router.
+    local_peer->SetOutwardLink(context, std::move(new_primary_link));
+  }
+
+  // New links were not adopted, implying that the new router has already been
+  // closed or disconnected.
+  if (new_primary_link) {
+    DVLOG(4) << "Dropping link to new router " << new_primary_link->Describe();
+    new_primary_link->AcceptRouteDisconnected(context);
+    new_primary_link->Deactivate();
+  }
+  if (new_decaying_link) {
+    DVLOG(4) << "Dropping link to new router " << new_decaying_link->Describe();
+    new_decaying_link->AcceptRouteDisconnected(context);
+    new_decaying_link->Deactivate();
   }
 
   // We may have inbound parcels queued which need to be forwarded to the new
   // Router, so give them a chance to be flushed out.
-  Flush(kForceProxyBypassAttempt);
+  Flush(context, kForceProxyBypassAttempt);
+  if (local_peer) {
+    local_peer->Flush(context, kForceProxyBypassAttempt);
+  }
 }
 
-bool Router::BypassPeer(RemoteRouterLink& requestor,
+bool Router::BypassPeer(const OperationContext& context,
+                        RemoteRouterLink& requestor,
                         const NodeName& bypass_target_node,
                         SublinkId bypass_target_sublink) {
   NodeLink& from_node_link = *requestor.node_link();
@@ -838,7 +1079,7 @@
         from_node_link.node()->GetLink(bypass_target_node);
     if (link_to_bypass_target) {
       return BypassPeerWithNewRemoteLink(
-          requestor, *link_to_bypass_target, bypass_target_sublink,
+          context, requestor, *link_to_bypass_target, bypass_target_sublink,
           link_to_bypass_target->memory().TryAllocateRouterLinkState());
     }
 
@@ -846,25 +1087,28 @@
     from_node_link.node()->EstablishLink(
         bypass_target_node,
         [router = WrapRefCounted(this), requestor = WrapRefCounted(&requestor),
-         bypass_target_sublink](NodeLink* link_to_bypass_target) {
+         bypass_target_sublink, context](NodeLink* link_to_bypass_target) {
           if (!link_to_bypass_target) {
             DLOG(ERROR) << "Disconnecting Router due to failed introduction";
-            router->AcceptRouteDisconnectedFrom(LinkType::kPeripheralOutward);
+            router->AcceptRouteDisconnectedFrom(context,
+                                                LinkType::kPeripheralOutward);
             return;
           }
 
           router->BypassPeerWithNewRemoteLink(
-              *requestor, *link_to_bypass_target, bypass_target_sublink,
+              context, *requestor, *link_to_bypass_target,
+              bypass_target_sublink,
               link_to_bypass_target->memory().TryAllocateRouterLinkState());
         });
     return true;
   }
 
   // The second case is when the proxy's outward peer lives on our own node.
-  return BypassPeerWithNewLocalLink(requestor, bypass_target_sublink);
+  return BypassPeerWithNewLocalLink(context, requestor, bypass_target_sublink);
 }
 
 bool Router::AcceptBypassLink(
+    const OperationContext& context,
     NodeLink& new_node_link,
     SublinkId new_sublink,
     FragmentRef<RouterLinkState> new_link_state,
@@ -907,7 +1151,7 @@
     // By convention the initiator of a bypass assumes side A of the bypass
     // link, so we assume side B.
     new_link = new_node_link.AddRemoteRouterLink(
-        new_sublink, std::move(new_link_state), LinkType::kCentral,
+        context, new_sublink, std::move(new_link_state), LinkType::kCentral,
         LinkSide::kB, WrapRefCounted(this));
 
     if (new_link) {
@@ -925,7 +1169,7 @@
   }
 
   if (!new_link) {
-    AcceptRouteDisconnectedFrom(LinkType::kCentral);
+    AcceptRouteDisconnectedFrom(context, LinkType::kCentral);
     return true;
   }
 
@@ -933,20 +1177,21 @@
     // If the new link goes to the same place as the old link, we only need
     // to tell the proxy there to stop proxying. It has already conspired with
     // its local outward peer.
-    old_link->StopProxyingToLocalPeer(length_to_proxy_from_us);
+    old_link->StopProxyingToLocalPeer(context, length_to_proxy_from_us);
   } else {
     // Otherwise, tell the proxy to stop proxying and let its inward peer (our
     // new outward peer) know that the proxy will stop.
-    old_link->StopProxying(length_to_proxy_from_us,
+    old_link->StopProxying(context, length_to_proxy_from_us,
                            inbound_sequence_length_from_bypassed_link);
-    new_link->ProxyWillStop(length_to_proxy_from_us);
+    new_link->ProxyWillStop(context, length_to_proxy_from_us);
   }
 
-  Flush();
+  Flush(context);
   return true;
 }
 
-bool Router::StopProxying(SequenceNumber inbound_sequence_length,
+bool Router::StopProxying(const OperationContext& context,
+                          SequenceNumber inbound_sequence_length,
                           SequenceNumber outbound_sequence_length) {
   Ref<Router> bridge_peer;
   {
@@ -999,14 +1244,15 @@
         outbound_sequence_length);
   }
 
-  Flush();
+  Flush(context);
   if (bridge_peer) {
-    bridge_peer->Flush();
+    bridge_peer->Flush(context);
   }
   return true;
 }
 
-bool Router::NotifyProxyWillStop(SequenceNumber inbound_sequence_length) {
+bool Router::NotifyProxyWillStop(const OperationContext& context,
+                                 SequenceNumber inbound_sequence_length) {
   {
     absl::MutexLock lock(&mutex_);
     if (outward_edge_.is_stable()) {
@@ -1022,11 +1268,12 @@
     outward_edge_.set_length_from_decaying_link(inbound_sequence_length);
   }
 
-  Flush();
+  Flush(context);
   return true;
 }
 
-bool Router::StopProxyingToLocalPeer(SequenceNumber outbound_sequence_length) {
+bool Router::StopProxyingToLocalPeer(const OperationContext& context,
+                                     SequenceNumber outbound_sequence_length) {
   Ref<Router> local_peer;
   Ref<Router> bridge_peer;
   {
@@ -1106,15 +1353,16 @@
     return false;
   }
 
-  Flush();
-  local_peer->Flush();
+  Flush(context);
+  local_peer->Flush(context);
   if (bridge_peer) {
-    bridge_peer->Flush();
+    bridge_peer->Flush(context);
   }
   return true;
 }
 
-void Router::NotifyLinkDisconnected(RemoteRouterLink& link) {
+void Router::NotifyLinkDisconnected(const OperationContext& context,
+                                    RemoteRouterLink& link) {
   {
     absl::MutexLock lock(&mutex_);
     if (outward_edge_.primary_link() == &link) {
@@ -1133,13 +1381,13 @@
   }
 
   if (link.GetType().is_outward()) {
-    AcceptRouteDisconnectedFrom(LinkType::kPeripheralOutward);
+    AcceptRouteDisconnectedFrom(context, LinkType::kPeripheralOutward);
   } else {
-    AcceptRouteDisconnectedFrom(LinkType::kPeripheralInward);
+    AcceptRouteDisconnectedFrom(context, LinkType::kPeripheralInward);
   }
 }
 
-void Router::Flush(FlushBehavior behavior) {
+void Router::Flush(const OperationContext& context, FlushBehavior behavior) {
   Ref<RouterLink> outward_link;
   Ref<RouterLink> inward_link;
   Ref<RouterLink> bridge_link;
@@ -1271,7 +1519,7 @@
   }
 
   for (ParcelToFlush& parcel : parcels_to_flush) {
-    parcel.link->AcceptParcel(parcel.parcel);
+    parcel.link->AcceptParcel(context, parcel.parcel);
   }
 
   if (outward_link_decayed) {
@@ -1284,26 +1532,29 @@
 
   if (bridge_link && outward_link && !inward_link && !decaying_inward_link &&
       !decaying_outward_link) {
-    MaybeStartBridgeBypass();
+    MaybeStartBridgeBypass(context);
   }
 
   if (dead_outward_link) {
     if (final_outward_sequence_length) {
-      dead_outward_link->AcceptRouteClosure(*final_outward_sequence_length);
+      dead_outward_link->AcceptRouteClosure(context,
+                                            *final_outward_sequence_length);
     }
     dead_outward_link->Deactivate();
   }
 
   if (dead_inward_link) {
     if (final_inward_sequence_length) {
-      dead_inward_link->AcceptRouteClosure(*final_inward_sequence_length);
+      dead_inward_link->AcceptRouteClosure(context,
+                                           *final_inward_sequence_length);
     }
     dead_inward_link->Deactivate();
   }
 
   if (dead_bridge_link) {
     if (final_inward_sequence_length) {
-      dead_bridge_link->AcceptRouteClosure(*final_inward_sequence_length);
+      dead_bridge_link->AcceptRouteClosure(context,
+                                           *final_inward_sequence_length);
     }
   }
 
@@ -1313,11 +1564,11 @@
   }
 
   if (snapshot_peer_queue_state) {
-    SnapshotPeerQueueState();
+    SnapshotPeerQueueState(context);
   }
 
   if (peer_needs_local_state_update) {
-    outward_link->SnapshotPeerQueueState();
+    outward_link->SnapshotPeerQueueState(context);
   }
 
   if (!dropped_last_decaying_link && behavior != kForceProxyBypassAttempt) {
@@ -1325,12 +1576,12 @@
     return;
   }
 
-  if (inward_link && MaybeStartSelfBypass()) {
+  if (inward_link && MaybeStartSelfBypass(context)) {
     return;
   }
 
   if (outward_link) {
-    outward_link->FlushOtherSideIfWaiting();
+    outward_link->FlushOtherSideIfWaiting(context);
   }
 }
 
@@ -1400,7 +1651,7 @@
       saturated_cast<size_t>(num_bytes_produced - num_bytes_consumed);
 }
 
-bool Router::MaybeStartSelfBypass() {
+bool Router::MaybeStartSelfBypass(const OperationContext& context) {
   Ref<RemoteRouterLink> remote_inward_link;
   Ref<RemoteRouterLink> remote_outward_link;
   Ref<Router> local_outward_peer;
@@ -1455,7 +1706,7 @@
              << remote_outward_link->Describe();
 
     remote_inward_link->BypassPeer(
-        remote_outward_link->node_link()->remote_node_name(),
+        context, remote_outward_link->node_link()->remote_node_name(),
         remote_outward_link->sublink());
     return true;
   }
@@ -1464,22 +1715,24 @@
   // establish the bypass link immediately and send it to the remote inward
   // peer.
   return StartSelfBypassToLocalPeer(
-      *local_outward_peer, *remote_inward_link,
+      context, *local_outward_peer, *remote_inward_link,
       remote_inward_link->node_link()->memory().TryAllocateRouterLinkState());
 }
 
 bool Router::StartSelfBypassToLocalPeer(
+    const OperationContext& context,
     Router& local_outward_peer,
     RemoteRouterLink& inward_link,
     FragmentRef<RouterLinkState> new_link_state) {
   if (new_link_state.is_null()) {
     NodeLinkMemory& memory = inward_link.node_link()->memory();
     memory.AllocateRouterLinkState(
-        [router = WrapRefCounted(this),
+        [router = WrapRefCounted(this), context,
          local_outward_peer = WrapRefCounted(&local_outward_peer),
          inward_link = WrapRefCounted(&inward_link)](
             FragmentRef<RouterLinkState> new_link_state) {
-          router->StartSelfBypassToLocalPeer(*local_outward_peer, *inward_link,
+          router->StartSelfBypassToLocalPeer(context, *local_outward_peer,
+                                             *inward_link,
                                              std::move(new_link_state));
         });
     return true;
@@ -1520,25 +1773,26 @@
     inward_edge_->set_length_to_decaying_link(length_from_outward_peer);
 
     new_link = inward_link.node_link()->AddRemoteRouterLink(
-        new_sublink, new_link_state, LinkType::kCentral, LinkSide::kA,
+        context, new_sublink, new_link_state, LinkType::kCentral, LinkSide::kA,
         WrapRefCounted(&local_outward_peer));
   }
 
   if (!new_link) {
-    AcceptRouteDisconnectedFrom(LinkType::kCentral);
+    AcceptRouteDisconnectedFrom(context, LinkType::kCentral);
     return false;
   }
 
   // Inform our inward peer on another node that they can bypass us using the
   // new link we just created to our own outward local peer. Once that message
   // is sent, it's safe for that local peer to adopt the new link.
-  inward_link.BypassPeerWithLink(new_sublink, std::move(new_link_state),
+  inward_link.BypassPeerWithLink(context, new_sublink,
+                                 std::move(new_link_state),
                                  length_from_outward_peer);
-  local_outward_peer.SetOutwardLink(std::move(new_link));
+  local_outward_peer.SetOutwardLink(context, std::move(new_link));
   return true;
 }
 
-void Router::MaybeStartBridgeBypass() {
+void Router::MaybeStartBridgeBypass(const OperationContext& context) {
   Ref<Router> first_bridge = WrapRefCounted(this);
   Ref<Router> second_bridge;
   {
@@ -1613,7 +1867,7 @@
       second_bridge->bridge_->BeginPrimaryLinkDecay();
     }
     second_remote_link->BypassPeer(
-        first_remote_link->node_link()->remote_node_name(),
+        context, first_remote_link->node_link()->remote_node_name(),
         first_remote_link->sublink());
     return;
   }
@@ -1624,10 +1878,12 @@
   // it's a bit more complex than the cases above and below.
   if (!second_local_peer) {
     StartBridgeBypassFromLocalPeer(
+        context,
         second_remote_link->node_link()->memory().TryAllocateRouterLinkState());
     return;
   } else if (!first_local_peer) {
     second_bridge->StartBridgeBypassFromLocalPeer(
+        context,
         first_remote_link->node_link()->memory().TryAllocateRouterLinkState());
     return;
   }
@@ -1680,13 +1936,14 @@
     second_local_peer->outward_edge_.SetPrimaryLink(std::move(links.second));
   }
 
-  first_bridge->Flush();
-  second_bridge->Flush();
-  first_local_peer->Flush();
-  second_local_peer->Flush();
+  first_bridge->Flush(context);
+  second_bridge->Flush(context);
+  first_local_peer->Flush(context);
+  second_local_peer->Flush(context);
 }
 
 void Router::StartBridgeBypassFromLocalPeer(
+    const OperationContext& context,
     FragmentRef<RouterLinkState> link_state) {
   Ref<Router> local_peer;
   Ref<Router> other_bridge;
@@ -1721,9 +1978,10 @@
     // We need a new RouterLinkState on the remote link before we can complete
     // this operation.
     remote_link->node_link()->memory().AllocateRouterLinkState(
-        [router = WrapRefCounted(this)](FragmentRef<RouterLinkState> state) {
+        [router = WrapRefCounted(this),
+         context](FragmentRef<RouterLinkState> state) {
           if (!state.is_null()) {
-            router->StartBridgeBypassFromLocalPeer(std::move(state));
+            router->StartBridgeBypassFromLocalPeer(context, std::move(state));
           }
         });
     return;
@@ -1739,7 +1997,8 @@
   const SublinkId bypass_sublink =
       node_link_to_peer->memory().AllocateSublinkIds(1);
   Ref<RemoteRouterLink> new_link = node_link_to_peer->AddRemoteRouterLink(
-      bypass_sublink, link_state, LinkType::kCentral, LinkSide::kA, local_peer);
+      context, bypass_sublink, link_state, LinkType::kCentral, LinkSide::kA,
+      local_peer);
   {
     MultiMutexLock lock(&mutex_, &other_bridge->mutex_, &local_peer->mutex_);
 
@@ -1765,15 +2024,16 @@
     other_bridge_edge.set_length_from_decaying_link(length_from_local_peer);
   }
 
-  remote_link->BypassPeerWithLink(bypass_sublink, std::move(link_state),
-                                  length_from_local_peer);
-  local_peer->SetOutwardLink(std::move(new_link));
-  Flush();
-  other_bridge->Flush();
-  local_peer->Flush();
+  remote_link->BypassPeerWithLink(
+      context, bypass_sublink, std::move(link_state), length_from_local_peer);
+  local_peer->SetOutwardLink(context, std::move(new_link));
+  Flush(context);
+  other_bridge->Flush(context);
+  local_peer->Flush(context);
 }
 
 bool Router::BypassPeerWithNewRemoteLink(
+    const OperationContext& context,
     RemoteRouterLink& requestor,
     NodeLink& node_link,
     SublinkId bypass_target_sublink,
@@ -1783,9 +2043,9 @@
     // RouterLinkState.
     node_link.memory().AllocateRouterLinkState(
         [router = WrapRefCounted(this), requestor = WrapRefCounted(&requestor),
-         node_link = WrapRefCounted(&node_link),
+         node_link = WrapRefCounted(&node_link), context,
          bypass_target_sublink](FragmentRef<RouterLinkState> new_link_state) {
-          router->BypassPeerWithNewRemoteLink(*requestor, *node_link,
+          router->BypassPeerWithNewRemoteLink(context, *requestor, *node_link,
                                               bypass_target_sublink,
                                               std::move(new_link_state));
         });
@@ -1812,16 +2072,16 @@
 
     length_to_decaying_link = outbound_parcels_.current_sequence_number();
     outward_edge_.set_length_to_decaying_link(length_to_decaying_link);
-    new_link = node_link.AddRemoteRouterLink(new_sublink, new_link_state,
-                                             LinkType::kCentral, LinkSide::kA,
-                                             WrapRefCounted(this));
+    new_link = node_link.AddRemoteRouterLink(
+        context, new_sublink, new_link_state, LinkType::kCentral, LinkSide::kA,
+        WrapRefCounted(this));
   }
 
   if (!new_link) {
     // The NodeLink was disconnected before we could create a new link for
     // this Router. This is not the requestor's fault, so it's not treated as
     // an error.
-    AcceptRouteDisconnectedFrom(LinkType::kCentral);
+    AcceptRouteDisconnectedFrom(context, LinkType::kCentral);
     return true;
   }
 
@@ -1841,11 +2101,12 @@
   // above message. Otherwise the router might race on another thread to send
   // messages via `new_sublink`, and the remote node would have no idea where
   // to route them.
-  SetOutwardLink(std::move(new_link));
+  SetOutwardLink(context, std::move(new_link));
   return true;
 }
 
-bool Router::BypassPeerWithNewLocalLink(RemoteRouterLink& requestor,
+bool Router::BypassPeerWithNewLocalLink(const OperationContext& context,
+                                        RemoteRouterLink& requestor,
                                         SublinkId bypass_target_sublink) {
   NodeLink& from_node_link = *requestor.node_link();
   const Ref<Router> new_local_peer =
@@ -1853,7 +2114,7 @@
   if (!new_local_peer) {
     // The peer may have already been destroyed or disconnected from the proxy
     // by the time we get here.
-    AcceptRouteDisconnectedFrom(LinkType::kPeripheralOutward);
+    AcceptRouteDisconnectedFrom(context, LinkType::kPeripheralOutward);
     return true;
   }
 
@@ -1901,11 +2162,11 @@
     new_local_peer->outward_edge_.SetPrimaryLink(std::move(links.second));
   }
 
-  link_from_new_local_peer_to_proxy->StopProxying(length_from_proxy_to_us,
-                                                  length_to_proxy_from_us);
+  link_from_new_local_peer_to_proxy->StopProxying(
+      context, length_from_proxy_to_us, length_to_proxy_from_us);
 
-  Flush();
-  new_local_peer->Flush();
+  Flush(context);
+  new_local_peer->Flush(context);
   return true;
 }
 
diff --git a/third_party/ipcz/src/ipcz/router.h b/third_party/ipcz/src/ipcz/router.h
index aa92509..eb43fb5 100644
--- a/third_party/ipcz/src/ipcz/router.h
+++ b/third_party/ipcz/src/ipcz/router.h
@@ -10,6 +10,7 @@
 
 #include "ipcz/fragment_ref.h"
 #include "ipcz/ipcz.h"
+#include "ipcz/operation_context.h"
 #include "ipcz/parcel_queue.h"
 #include "ipcz/route_edge.h"
 #include "ipcz/router_descriptor.h"
@@ -105,7 +106,8 @@
   // in active use by another Router, as `this` Router may already be in a
   // transitional state and must be able to block decay around `link` from
   // within this call.
-  void SetOutwardLink(Ref<RouterLink> link);
+  void SetOutwardLink(const OperationContext& context,
+                      const Ref<RouterLink> link);
 
   // Returns a best-effort estimation of the maximum parcel size (in bytes) that
   // can be sent outward from this router without the receiving portal exceeding
@@ -118,23 +120,27 @@
   size_t GetInboundCapacityInBytes(const IpczPutLimits& limits);
 
   // Accepts an inbound parcel from the outward edge of this router, either to
-  // queue it for retrieval or forward it further inward.
-  bool AcceptInboundParcel(Parcel& parcel);
+  // queue it for retrieval or forward it further inward. `source` indicates
+  // whether the parcel is arriving as a direct result of some local ipcz API
+  // call, or if it came from a remote node.
+  bool AcceptInboundParcel(const OperationContext& context, Parcel& parcel);
 
   // Accepts an outbound parcel here from some other Router. The parcel is
   // transmitted immediately or queued for later transmission over the Router's
   // outward link. Called only on proxying Routers.
-  bool AcceptOutboundParcel(Parcel& parcel);
+  bool AcceptOutboundParcel(const OperationContext& context, Parcel& parcel);
 
   // Accepts notification that the other end of the route has been closed and
   // that the closed end transmitted a total of `sequence_length` parcels before
-  // closing.
-  bool AcceptRouteClosureFrom(LinkType link_type,
+  // closing. `source` indicates whether the portal's peer was closed locally,
+  // or if we were notified of its closure from a remote node.
+  bool AcceptRouteClosureFrom(const OperationContext& context,
+                              LinkType link_type,
                               SequenceNumber sequence_length);
 
   // Queries the remote peer's queue state and performs any local state upates
-  // needed to reflect it.
-  void SnapshotPeerQueueState();
+  // needed to reflect it. `source` indicates why the snapshot is being taken.
+  void SnapshotPeerQueueState(const OperationContext& context);
 
   // Accepts notification from a link bound to this Router that some node along
   // the route (in the direction of that link) has been disconnected, e.g. due
@@ -143,7 +149,8 @@
   // deliver the complete sequence of parcels transmitted from that end of the
   // route. `link_type` specifies the type of link which is propagating the
   // notification to this rouer.
-  bool AcceptRouteDisconnectedFrom(LinkType link_type);
+  bool AcceptRouteDisconnectedFrom(const OperationContext& context,
+                                   LinkType link_type);
 
   // Retrieves the next available inbound parcel from this Router, if present.
   IpczResult GetNextInboundParcel(IpczGetFlags flags,
@@ -187,12 +194,15 @@
   // Serializes a description of a new Router which will be used to extend this
   // Router's route across `to_node_link` by introducing a new Router on the
   // remote node.
-  void SerializeNewRouter(NodeLink& to_node_link, RouterDescriptor& descriptor);
+  void SerializeNewRouter(const OperationContext& context,
+                          NodeLink& to_node_link,
+                          RouterDescriptor& descriptor);
 
   // Configures this Router to begin proxying incoming parcels toward (and
   // outgoing parcels from) the Router described by `descriptor`, living on the
   // remote node of `to_node_link`.
-  void BeginProxyingToNewRouter(NodeLink& to_node_link,
+  void BeginProxyingToNewRouter(const OperationContext& context,
+                                NodeLink& to_node_link,
                                 const RouterDescriptor& descriptor);
 
   // Notifies this router that it should reach out to its outward peer's own
@@ -221,7 +231,8 @@
   // invalid. Note that a return value of true does not necessarily imply that
   // bypass was or will be successful (e.g. it may silently fail due to lost
   // node connections).
-  bool BypassPeer(RemoteRouterLink& requestor,
+  bool BypassPeer(const OperationContext& context,
+                  RemoteRouterLink& requestor,
                   const NodeName& bypass_target_node,
                   SublinkId bypass_target_sublink);
 
@@ -245,6 +256,7 @@
   // RouterLinkState's `allowed_bypass_request_source` field. This method
   // authenticates the request accordingly.
   bool AcceptBypassLink(
+      const OperationContext& context,
       NodeLink& new_node_link,
       SublinkId new_sublink,
       FragmentRef<RouterLinkState> new_link_state,
@@ -257,7 +269,8 @@
   //
   // Returns true if and only if this router is a proxy with decaying inward and
   // outward links. Otherwise returns false, indicating an invalid request.
-  bool StopProxying(SequenceNumber inbound_sequence_length,
+  bool StopProxying(const OperationContext& context,
+                    SequenceNumber inbound_sequence_length,
                     SequenceNumber outbound_sequence_length);
 
   // Configures the final length of the inbound parcel sequence coming from the
@@ -268,7 +281,8 @@
   // Returns true if this router has a decaying outward link -- implying that
   // its outward peer is a proxy -- or the router has been disconnected.
   // Otherwise the request is invalid and this returns false.
-  bool NotifyProxyWillStop(SequenceNumber inbound_sequence_length);
+  bool NotifyProxyWillStop(const OperationContext& context,
+                           SequenceNumber inbound_sequence_length);
 
   // Configures the final sequence length of outbound parcels to expect on this
   // proxying Router's decaying inward link. Once this is set and the decaying
@@ -276,7 +290,8 @@
   //
   // Returns true if the request is valid, meaning that this Router is a proxy
   // whose outward peer is local to the same node. Otherwise this returns false.
-  bool StopProxyingToLocalPeer(SequenceNumber outbound_sequence_length);
+  bool StopProxyingToLocalPeer(const OperationContext& context,
+                               SequenceNumber outbound_sequence_length);
 
   // Notifies this Router that one of its links has been disconnected from a
   // remote node. The link is identified by a combination of a specific NodeLink
@@ -290,7 +305,8 @@
   // For a proxying router which is generally only kept alive by the links
   // which are bound to it, this call will typically be followed by imminent
   // destruction of this Router once the caller releases its own reference.
-  void NotifyLinkDisconnected(RemoteRouterLink& link);
+  void NotifyLinkDisconnected(const OperationContext& context,
+                              RemoteRouterLink& link);
 
   // Flushes any inbound or outbound parcels, as well as any route closure
   // notifications. RouterLinks which are no longer needed for the operation of
@@ -312,8 +328,11 @@
   // invoke Flush() may also elicit state changes that can unblock a bypass
   // operation. These operatoins may specify kForceProxyBypassAttempt in such
   // cases.
+  //
+  // `source` indicates why the flush is occurring.
   enum FlushBehavior { kDefault, kForceProxyBypassAttempt };
-  void Flush(FlushBehavior behavior = kDefault);
+  void Flush(const OperationContext& context,
+             FlushBehavior behavior = kDefault);
 
  private:
   ~Router() override;
@@ -342,7 +361,7 @@
   // last decaying link, or if Flush() was called with kForceProxyBypassAttempt,
   // indicating that some significant state has changed on the route which might
   // unblock our bypass.
-  bool MaybeStartSelfBypass();
+  bool MaybeStartSelfBypass(const OperationContext& context);
 
   // Starts bypass of this Router when its outward peer lives on the same node.
   // This must only be called once the central link is already locked. If
@@ -353,7 +372,8 @@
   // Returns true if and only if self-bypass has been initiated by reaching out
   // to this router's inward peer with with a BypassPeer() or
   // BypassPeerWithLink() request. Otherwise returns false.
-  bool StartSelfBypassToLocalPeer(Router& local_outward_peer,
+  bool StartSelfBypassToLocalPeer(const OperationContext& context,
+                                  Router& local_outward_peer,
                                   RemoteRouterLink& inward_link,
                                   FragmentRef<RouterLinkState> new_link_state);
 
@@ -362,7 +382,7 @@
   // other side. This method will attempt to lock this Router's outward link as
   // well as the outward link of this Router's bridge peer. If either fails,
   // both are left unlocked and this operation cannot yet proceed.
-  void MaybeStartBridgeBypass();
+  void MaybeStartBridgeBypass(const OperationContext& context);
 
   // Starts bypass of this Router, which must be on a bridge link and must have
   // a local outward peer link. The router on the other side of the bridge must
@@ -370,7 +390,8 @@
   // establish a new remote link to that peer to bypass the entire bridge. If
   // `link_state` is null, the operation will be deferred until a fragment can
   // be allocated.
-  void StartBridgeBypassFromLocalPeer(FragmentRef<RouterLinkState> link_state);
+  void StartBridgeBypassFromLocalPeer(const OperationContext& context,
+                                      FragmentRef<RouterLinkState> link_state);
 
   // Attempts to bypass the link identified by `requestor` in favor of a new
   // link that runs over `node_link`. If `new_link_state` is non-null, it will
@@ -378,7 +399,8 @@
   // will be allocated asynchronously before proceeding.
   //
   // Returns true if and only if this request was valid.
-  bool BypassPeerWithNewRemoteLink(RemoteRouterLink& requestor,
+  bool BypassPeerWithNewRemoteLink(const OperationContext& context,
+                                   RemoteRouterLink& requestor,
                                    NodeLink& node_link,
                                    SublinkId bypass_target_sublink,
                                    FragmentRef<RouterLinkState> new_link_state);
@@ -388,9 +410,31 @@
   // NodeLink as `requestor`.
   //
   // Returns true if and only if this request was valid.
-  bool BypassPeerWithNewLocalLink(RemoteRouterLink& requestor,
+  bool BypassPeerWithNewLocalLink(const OperationContext& context,
+                                  RemoteRouterLink& requestor,
                                   SublinkId bypass_target_sublink);
 
+  // Optimized Router serialization case when the Router's peer is local to the
+  // same node and the existing (local) central link can be replaced with a new
+  // remote link, without establishing an intermediate proxy. Returns true on
+  // success, or false indicating that the caller must fall back onto the slower
+  // Router serialization path defined below.
+  bool SerializeNewRouterWithLocalPeer(const OperationContext& context,
+                                       NodeLink& to_node_link,
+                                       RouterDescriptor& descriptor,
+                                       Ref<Router> local_peer);
+
+  // Default Router serialization case when the serializing Router must stay
+  // behind as an intermediate proxy between its (remote) peer and the newly
+  // established Router that will result from this serialization. As an
+  // optimization, `initiate_proxy_bypass` may be true if the serializing router
+  // is on the central link and was able to lock that link for bypass prior to
+  // serialization.
+  void SerializeNewRouterAndConfigureProxy(const OperationContext& context,
+                                           NodeLink& to_node_link,
+                                           RouterDescriptor& descriptor,
+                                           bool initiate_proxy_bypass);
+
   absl::Mutex mutex_;
 
   // The current computed portal status to be reflected by a portal controlling
diff --git a/third_party/ipcz/src/ipcz/router_descriptor.h b/third_party/ipcz/src/ipcz/router_descriptor.h
index 77f3592..9cb539b0 100644
--- a/third_party/ipcz/src/ipcz/router_descriptor.h
+++ b/third_party/ipcz/src/ipcz/router_descriptor.h
@@ -31,10 +31,22 @@
   // end.
   SequenceNumber closed_peer_sequence_length;
 
-  // A new sublink and RouterLinkState fragment allocated by the sender on the
-  // NodeLink which sends this descriptor. The sublink is used as a peripheral
-  // link, inward to (and outward from) the new router.
+  // A new sublink allocated by the sender on the NodeLink which sends this
+  // descriptor. The sublink may be used as a peripheral link, inward to (and
+  // outward from) the new router, or it may be used the route's central link
+  // if and only if `proxy_already_bypassed` is true below. In the latter case,
+  // `new_link_state_fragment` must be valid and is used as the new central
+  // link's RouterLinkState.
   SublinkId new_sublink;
+  FragmentDescriptor new_link_state_fragment;
+
+  // When `proxy_already_bypassed` is true below, this is another new sublink
+  // allocated by the sender on the NodeLink which sends this descriptor. This
+  // sublink is used as peripheral link to the new router's outward -- peer back
+  // on the sending node -- as a way for that router to forward any inbound
+  // parcels that were still queued or in flight when this router was
+  // serialized.
+  SublinkId new_decaying_sublink;
 
   // The SequenceNumber of the next outbound parcel which can be produced by
   // this router.
@@ -46,6 +58,15 @@
   // The SequenceNumber of the next inbound parcel expected by this router.
   SequenceNumber next_incoming_sequence_number;
 
+  // The total length of the sequence of parcels expected on the decaying link
+  // established by `new_decaying_sublink`, if and only if
+  // `proxy_already_bypassed` is true. The decaying link is expected to receive
+  // only parcels between `next_incoming_sequence_number` (inclusive) and
+  // `decaying_incoming_sequence_length` (exclusive). If those fields are equal
+  // then the decaying link should be ignored and `new_decaying_sublink` may
+  // not be valid.
+  SequenceNumber decaying_incoming_sequence_length;
+
   // The total number of incoming bytes consumed from router's portal so far.
   uint64_t num_bytes_consumed;
 
@@ -56,6 +77,27 @@
   // parcels sent from that end, and `next_incoming_sequence_number` can be used
   // to determine whether there are any parcels left to receive.
   bool peer_closed : 1;
+
+  // Indicates that, as an optimization, the sender was able to circumvent the
+  // usual process of first establishing a peripheral link and then initiating
+  // proxy bypass. Instead the outward peer of this new router is already
+  // configured to route messages directly to the new router, and its former
+  // (and local) outward peer is configured to proxy any previously queued or
+  // in-flight messages to us over the decaying link described above.
+  bool proxy_already_bypassed : 1;
+
+  // Reserved padding out to the next 8-byte boundary.
+  uint8_t reserved0[7];
+
+  // These fields are set if and only if proxy bypass should be initiated
+  // immediately on deserialization of the new Router. The deserializing node
+  // must contact `proxy_peer_node_name` with the name of the node who sent this
+  // descriptor, along with `proxy_peer_sublink` (an existing sublink
+  // between those two nodes, identifying the link we want to bypass). These
+  // fields may be set as an optimization to avoid additional messaging overhead
+  // in the common case of transferring a yet-unused portal.
+  NodeName proxy_peer_node_name;
+  SublinkId proxy_peer_sublink;
 };
 
 }  // namespace ipcz
diff --git a/third_party/ipcz/src/ipcz/router_link.h b/third_party/ipcz/src/ipcz/router_link.h
index 97a55ed..a8031b3 100644
--- a/third_party/ipcz/src/ipcz/router_link.h
+++ b/third_party/ipcz/src/ipcz/router_link.h
@@ -14,6 +14,7 @@
 #include "ipcz/fragment_ref.h"
 #include "ipcz/link_type.h"
 #include "ipcz/node_name.h"
+#include "ipcz/operation_context.h"
 #include "ipcz/router_link_state.h"
 #include "ipcz/sequence_number.h"
 #include "ipcz/sublink_id.h"
@@ -69,18 +70,20 @@
 
   // Passes a parcel to the Router on the other side of this link to be queued
   // and/or router further.
-  virtual void AcceptParcel(Parcel& parcel) = 0;
+  virtual void AcceptParcel(const OperationContext& context,
+                            Parcel& parcel) = 0;
 
   // Notifies the Router on the other side of the link that the route has been
   // closed from this side. `sequence_length` is the total number of parcels
   // transmitted from the closed side before it was closed.
-  virtual void AcceptRouteClosure(SequenceNumber sequence_length) = 0;
+  virtual void AcceptRouteClosure(const OperationContext& context,
+                                  SequenceNumber sequence_length) = 0;
 
   // Notifies the Router on the other side of the link that the route has been
   // unexpectedly disconnected from this side. Unlike clean route closure above,
   // in this case we don't know the final sequence length and can't guarantee
   // delivery of any further parcels.
-  virtual void AcceptRouteDisconnected() = 0;
+  virtual void AcceptRouteDisconnected(const OperationContext& context) = 0;
 
   // Returns the AtomicQueueState for the other side of this link if available.
   // Otherwise returns null.
@@ -93,7 +96,7 @@
   // Notifies the other side that this side has updated its visible queue state
   // in some way which may be interesting to them. This should be called
   // sparingly to avoid redundant IPC traffic and redundant idle wakes.
-  virtual void SnapshotPeerQueueState() = 0;
+  virtual void SnapshotPeerQueueState(const OperationContext& context) = 0;
 
   // Signals that this side of the link is in a stable state suitable for one
   // side or the other to lock the link, either for bypass or closure
@@ -128,7 +131,7 @@
   // itself as waiting for both sides of the link to become stable, and both
   // sides of the link are stable. Returns true if and only if a flush was
   // actually issued to the other side.
-  virtual bool FlushOtherSideIfWaiting() = 0;
+  virtual bool FlushOtherSideIfWaiting(const OperationContext& context) = 0;
 
   // Indicates whether this link can be bypassed by a request from the named
   // node to one side of the link. True if and only if the proxy on the other
@@ -140,7 +143,8 @@
   // on this side. `bypass_target_node` is the name node where the router's
   // outward peer lives, and `bypass_target_sublink` identifies the link between
   // that router and the router on the other side of this link.
-  virtual void BypassPeer(const NodeName& bypass_target_node,
+  virtual void BypassPeer(const OperationContext& context,
+                          const NodeName& bypass_target_node,
                           SublinkId bypass_target_sublink) = 0;
 
   // Informs the router on the other side of this link about when it can drop
@@ -150,14 +154,16 @@
   // `outbound_sequence_length` is the final length of the parcel sequence the
   // router must expect to receive from its inward peer and forward to its
   // outward peer.
-  virtual void StopProxying(SequenceNumber inbound_sequence_length,
+  virtual void StopProxying(const OperationContext& context,
+                            SequenceNumber inbound_sequence_length,
                             SequenceNumber outbound_sequence_length) = 0;
 
   // Informs the router on the other side of this link that the router it most
   // recently bypassed will stop sending it parcels once the router's inbound
   // sequence length reaches `inbound_sequence_length`, at which point the
   // router's link to the proxy can be dropped.
-  virtual void ProxyWillStop(SequenceNumber inbound_sequence_length) = 0;
+  virtual void ProxyWillStop(const OperationContext& context,
+                             SequenceNumber inbound_sequence_length) = 0;
 
   // Informs the router on the other side of this link that its outward peer
   // (and the router on this side of this link) can be bypassed, and provides a
@@ -165,7 +171,8 @@
   // `new_link_state` is a freshly allocated RouterLinkState fragment for the
   // new link, and `inbound_sequence_length` is the current inbound sequence
   // length of the router on this side of the link.
-  virtual void BypassPeerWithLink(SublinkId new_sublink,
+  virtual void BypassPeerWithLink(const OperationContext& context,
+                                  SublinkId new_sublink,
                                   FragmentRef<RouterLinkState> new_link_state,
                                   SequenceNumber inbound_sequence_length) = 0;
 
@@ -177,6 +184,7 @@
   // router on this side of the link at the moment it switches to the new link
   // for its outward transmissions.
   virtual void StopProxyingToLocalPeer(
+      const OperationContext& context,
       SequenceNumber outbound_sequence_length) = 0;
 
   // Deactivates this RouterLink to sever any binding it may have to a specific
diff --git a/third_party/ipcz/src/ipcz/router_link_test.cc b/third_party/ipcz/src/ipcz/router_link_test.cc
index d153c2fd..36c23ff 100644
--- a/third_party/ipcz/src/ipcz/router_link_test.cc
+++ b/third_party/ipcz/src/ipcz/router_link_test.cc
@@ -17,6 +17,7 @@
 #include "ipcz/node.h"
 #include "ipcz/node_link.h"
 #include "ipcz/node_name.h"
+#include "ipcz/operation_context.h"
 #include "ipcz/remote_router_link.h"
 #include "ipcz/router.h"
 #include "ipcz/router_link_state.h"
@@ -85,13 +86,17 @@
                                      FragmentRef<RouterLinkState> a_state,
                                      Ref<Router> b,
                                      FragmentRef<RouterLinkState> b_state) {
+    // The choice of OperationContext is arbitrary and irrelevant for this test.
+    const OperationContext context{OperationContext::kTransportNotification};
     const SublinkId sublink = node_link_a_->memory().AllocateSublinkIds(1);
-    Ref<RemoteRouterLink> a_link = node_link_a_->AddRemoteRouterLink(
-        sublink, std::move(a_state), LinkType::kCentral, LinkSide::kA, a);
-    Ref<RemoteRouterLink> b_link = node_link_b_->AddRemoteRouterLink(
-        sublink, std::move(b_state), LinkType::kCentral, LinkSide::kB, b);
-    a->SetOutwardLink(a_link);
-    b->SetOutwardLink(b_link);
+    Ref<RemoteRouterLink> a_link =
+        node_link_a_->AddRemoteRouterLink(context, sublink, std::move(a_state),
+                                          LinkType::kCentral, LinkSide::kA, a);
+    Ref<RemoteRouterLink> b_link =
+        node_link_b_->AddRemoteRouterLink(context, sublink, std::move(b_state),
+                                          LinkType::kCentral, LinkSide::kB, b);
+    a->SetOutwardLink(context, a_link);
+    b->SetOutwardLink(context, b_link);
     return {a_link, b_link};
   }
 
@@ -126,12 +131,14 @@
                        public testing::WithParamInterface<RouterLinkTestMode> {
  public:
   void SetUp() override {
+    // The choice of OperationContext is arbitrary and irrelevant for this test.
+    const OperationContext context{OperationContext::kTransportNotification};
     switch (GetParam()) {
       case RouterLinkTestMode::kLocal:
         std::tie(a_link_, b_link_) =
             LocalRouterLink::CreatePair(LinkType::kCentral, {a_, b_});
-        a_->SetOutwardLink(a_link_);
-        b_->SetOutwardLink(b_link_);
+        a_->SetOutwardLink(context, a_link_);
+        b_->SetOutwardLink(context, b_link_);
         break;
 
       case RouterLinkTestMode::kRemote: {
@@ -223,9 +230,11 @@
   link_state().status = RouterLinkState::kUnstable;
 
   // FlushOtherSideIfWaiting() does nothing if the other side is not, in fact,
-  // waiting for something.
-  EXPECT_FALSE(a_link().FlushOtherSideIfWaiting());
-  EXPECT_FALSE(b_link().FlushOtherSideIfWaiting());
+  // waiting for something. The choice of OperationContext is arbitrary and
+  // irrelevant for this test.
+  const OperationContext context{OperationContext::kTransportNotification};
+  EXPECT_FALSE(a_link().FlushOtherSideIfWaiting(context));
+  EXPECT_FALSE(b_link().FlushOtherSideIfWaiting(context));
   EXPECT_EQ(RouterLinkState::kUnstable, link_status());
 
   // Mark B stable and try to lock the link. Since A is not yet stable, this
@@ -240,7 +249,7 @@
   a_link().MarkSideStable();
   EXPECT_EQ(RouterLinkState::kStable | RouterLinkState::kSideBWaiting,
             link_status());
-  EXPECT_TRUE(a_link().FlushOtherSideIfWaiting());
+  EXPECT_TRUE(a_link().FlushOtherSideIfWaiting(context));
   EXPECT_EQ(RouterLinkState::kStable, link_status());
 }
 
diff --git a/third_party/ipcz/src/ipcz/trap_set.cc b/third_party/ipcz/src/ipcz/trap_set.cc
index 253d070..c0d26cd 100644
--- a/third_party/ipcz/src/ipcz/trap_set.cc
+++ b/third_party/ipcz/src/ipcz/trap_set.cc
@@ -111,19 +111,23 @@
   return IPCZ_RESULT_OK;
 }
 
-void TrapSet::UpdatePortalStatus(const IpczPortalStatus& status,
+void TrapSet::UpdatePortalStatus(const OperationContext& context,
+                                 const IpczPortalStatus& status,
                                  UpdateReason reason,
                                  TrapEventDispatcher& dispatcher) {
   last_known_status_ = status;
   for (auto* it = traps_.begin(); it != traps_.end();) {
     const Trap& trap = *it;
-    const IpczTrapConditionFlags flags =
+    IpczTrapConditionFlags flags =
         GetSatisfiedConditionsForUpdate(trap.conditions, reason, status);
     if (!flags) {
       ++it;
       continue;
     }
 
+    if (context.is_api_call()) {
+      flags |= IPCZ_TRAP_WITHIN_API_CALL;
+    }
     dispatcher.DeferEvent(trap.handler, trap.context, flags, status);
     it = traps_.erase(it);
     if (NeedRemoteParcels(flags)) {
@@ -135,9 +139,14 @@
   }
 }
 
-void TrapSet::RemoveAll(TrapEventDispatcher& dispatcher) {
+void TrapSet::RemoveAll(const OperationContext& context,
+                        TrapEventDispatcher& dispatcher) {
+  IpczTrapConditionFlags flags = IPCZ_TRAP_REMOVED;
+  if (context.is_api_call()) {
+    flags |= IPCZ_TRAP_WITHIN_API_CALL;
+  }
   for (const Trap& trap : traps_) {
-    dispatcher.DeferEvent(trap.handler, trap.context, IPCZ_TRAP_REMOVED,
+    dispatcher.DeferEvent(trap.handler, trap.context, flags,
                           last_known_status_);
   }
   traps_.clear();
diff --git a/third_party/ipcz/src/ipcz/trap_set.h b/third_party/ipcz/src/ipcz/trap_set.h
index 3af196b4..a772796 100644
--- a/third_party/ipcz/src/ipcz/trap_set.h
+++ b/third_party/ipcz/src/ipcz/trap_set.h
@@ -8,6 +8,7 @@
 #include <cstdint>
 
 #include "ipcz/ipcz.h"
+#include "ipcz/operation_context.h"
 #include "third_party/abseil-cpp/absl/container/inlined_vector.h"
 
 namespace ipcz {
@@ -85,13 +86,15 @@
   // If the state change is interesting to any trap in the set, an appropriate
   // event may be appended to `dispatcher` for imminent dispatch and the trap is
   // removed from the set before returning.
-  void UpdatePortalStatus(const IpczPortalStatus& status,
+  void UpdatePortalStatus(const OperationContext& context,
+                          const IpczPortalStatus& status,
                           UpdateReason reason,
                           TrapEventDispatcher& dispatcher);
 
   // Immediately removes all traps from the set. Every trap present appends an
   // IPCZ_TRAP_REMOVED event to `dispatcher` before removal.
-  void RemoveAll(TrapEventDispatcher& dispatcher);
+  void RemoveAll(const OperationContext& context,
+                 TrapEventDispatcher& dispatcher);
 
  private:
   struct Trap {
diff --git a/third_party/ipcz/src/trap_test.cc b/third_party/ipcz/src/trap_test.cc
index 6e53a39..d23c0a9 100644
--- a/third_party/ipcz/src/trap_test.cc
+++ b/third_party/ipcz/src/trap_test.cc
@@ -40,12 +40,14 @@
       .flags = IPCZ_TRAP_NEW_LOCAL_PARCEL,
   };
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_REMOVED, e.condition_flags);
+              EXPECT_EQ(IPCZ_TRAP_REMOVED | IPCZ_TRAP_WITHIN_API_CALL,
+                        e.condition_flags);
               parcel_trap_removed = true;
             }));
   conditions.flags = IPCZ_TRAP_PEER_CLOSED;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_REMOVED, e.condition_flags);
+              EXPECT_EQ(IPCZ_TRAP_REMOVED | IPCZ_TRAP_WITHIN_API_CALL,
+                        e.condition_flags);
               closure_trap_removed = true;
             }));
 
@@ -67,7 +69,8 @@
   };
   bool received_event = false;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_PEER_CLOSED, e.condition_flags);
+              EXPECT_EQ(IPCZ_TRAP_PEER_CLOSED | IPCZ_TRAP_WITHIN_API_CALL,
+                        e.condition_flags);
               received_event = true;
             }));
 
@@ -96,7 +99,9 @@
   };
   bool received_event = false;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS, e.condition_flags);
+              EXPECT_EQ(
+                  IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS | IPCZ_TRAP_WITHIN_API_CALL,
+                  e.condition_flags);
               received_event = true;
             }));
 
@@ -118,7 +123,9 @@
   received_event = false;
   conditions.min_local_parcels = 2;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS, e.condition_flags);
+              EXPECT_EQ(
+                  IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS | IPCZ_TRAP_WITHIN_API_CALL,
+                  e.condition_flags);
               received_event = true;
             }));
 
@@ -150,7 +157,9 @@
   };
   bool received_event = false;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_ABOVE_MIN_LOCAL_BYTES, e.condition_flags);
+              EXPECT_EQ(
+                  IPCZ_TRAP_ABOVE_MIN_LOCAL_BYTES | IPCZ_TRAP_WITHIN_API_CALL,
+                  e.condition_flags);
               received_event = true;
             }));
 
@@ -184,7 +193,8 @@
   };
   bool received_event = false;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL, e.condition_flags);
+              EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL | IPCZ_TRAP_WITHIN_API_CALL,
+                        e.condition_flags);
               received_event = true;
             }));
 
@@ -194,7 +204,8 @@
 
   received_event = false;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL, e.condition_flags);
+              EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL | IPCZ_TRAP_WITHIN_API_CALL,
+                        e.condition_flags);
               received_event = true;
             }));
 
@@ -214,7 +225,8 @@
   };
   bool received_event = false;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_DEAD, e.condition_flags);
+              EXPECT_EQ(IPCZ_TRAP_DEAD | IPCZ_TRAP_WITHIN_API_CALL,
+                        e.condition_flags);
               received_event = true;
             }));
 
@@ -255,19 +267,22 @@
       .flags = IPCZ_TRAP_NEW_LOCAL_PARCEL,
   };
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL, e.condition_flags);
+              EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL | IPCZ_TRAP_WITHIN_API_CALL,
+                        e.condition_flags);
               observed_parcel = true;
             }));
 
   conditions.flags = IPCZ_TRAP_PEER_CLOSED;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_PEER_CLOSED, e.condition_flags);
+              EXPECT_EQ(IPCZ_TRAP_PEER_CLOSED | IPCZ_TRAP_WITHIN_API_CALL,
+                        e.condition_flags);
               observed_closure = true;
             }));
 
   conditions.flags = IPCZ_TRAP_DEAD;
   EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
-              EXPECT_EQ(IPCZ_TRAP_DEAD, e.condition_flags);
+              EXPECT_EQ(IPCZ_TRAP_DEAD | IPCZ_TRAP_WITHIN_API_CALL,
+                        e.condition_flags);
               observed_death = true;
             }));
 
diff --git a/third_party/omnibox_proto/groups.proto b/third_party/omnibox_proto/groups.proto
index 53bb8b9..0d6abf7a 100644
--- a/third_party/omnibox_proto/groups.proto
+++ b/third_party/omnibox_proto/groups.proto
@@ -80,7 +80,7 @@
   GROUP_MOBILE_CLIPBOARD = 30002;
 
   // Reserved for personalized zero-prefix suggestions.
-  // Produced by ZeroSuggestProvider and LocalHistoryZeroSuggestProvider.
+  // Produced by LocalHistoryZeroSuggestProvider and maybe ZeroSuggestProvider.
   GROUP_PERSONALIZED_ZERO_SUGGEST = 40000;
 
   // Cross platform suggestions with vanilla visual representation (i.e.
@@ -118,20 +118,25 @@
   // - Organic Repeatable Queries
   SECTION_MOBILE_MOST_VISITED = 3;
 
+  // Local history zero-prefix suggestions. Will be overwritten by the
+  // dynamically assigned section for GROUP_PERSONALIZED_ZERO_SUGGEST if found
+  // in the server response.
+  SECTION_LOCAL_HISTORY_ZPS = 4;
+
   // A contiguous range reserved for remote zero-prefix suggestions.
   // The sections are dynamically assigned to the groups found in the server
   // response based on the order in which they appear in the results.
   // Accommodates up to 10 distinct suggestion groups in the server response.
-  SECTION_REMOTE_ZPS_1 = 4;
-  SECTION_REMOTE_ZPS_2 = 5;
-  SECTION_REMOTE_ZPS_3 = 6;
-  SECTION_REMOTE_ZPS_4 = 7;
-  SECTION_REMOTE_ZPS_5 = 8;
-  SECTION_REMOTE_ZPS_6 = 9;
-  SECTION_REMOTE_ZPS_7 = 10;
-  SECTION_REMOTE_ZPS_8 = 11;
-  SECTION_REMOTE_ZPS_9 = 12;
-  SECTION_REMOTE_ZPS_10 = 13;
+  SECTION_REMOTE_ZPS_1 = 5;
+  SECTION_REMOTE_ZPS_2 = 6;
+  SECTION_REMOTE_ZPS_3 = 7;
+  SECTION_REMOTE_ZPS_4 = 8;
+  SECTION_REMOTE_ZPS_5 = 9;
+  SECTION_REMOTE_ZPS_6 = 10;
+  SECTION_REMOTE_ZPS_7 = 11;
+  SECTION_REMOTE_ZPS_8 = 12;
+  SECTION_REMOTE_ZPS_9 = 13;
+  SECTION_REMOTE_ZPS_10 = 14;
 
   // Cross platform suggestions with vanilla visual representation (i.e.
   // vertical, primary column, and no header), but useful for sorting.
diff --git a/tools/accessibility/inspect/ax_dump_tree.cc b/tools/accessibility/inspect/ax_dump_tree.cc
index bcc33c46..4d6d8e5 100644
--- a/tools/accessibility/inspect/ax_dump_tree.cc
+++ b/tools/accessibility/inspect/ax_dump_tree.cc
@@ -8,6 +8,7 @@
 
 #include "base/at_exit.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "content/public/browser/ax_inspect_factory.h"
@@ -97,7 +98,7 @@
       LOG(ERROR) << "Unknown API type: " << api_str;
       return 1;
     }
-    if (std::find(apis.begin(), apis.end(), api) == apis.end()) {
+    if (!base::Contains(apis, api)) {
       LOG(ERROR) << "Unsupported API for this platform: "
                  << static_cast<std::string>(api);
       return 1;
diff --git a/tools/clang/plugins/tests/blink_discouraged_type.txt b/tools/clang/plugins/tests/blink_discouraged_type.txt
index 49396ad..ea18db36 100644
--- a/tools/clang/plugins/tests/blink_discouraged_type.txt
+++ b/tools/clang/plugins/tests/blink_discouraged_type.txt
@@ -1,23 +1,23 @@
 In file included from blink_discouraged_type.cpp:5:
-./third_party/blink/renderer/discouraged_type.h:29:20: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:31:20: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   std::vector<int> v1;
                    ^
-./third_party/blink/renderer/discouraged_type.h:34:21: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:36:21: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   nested::IntVector v2a;
                     ^
-./third_party/blink/renderer/discouraged_type.h:35:15: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:37:15: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   FloatVector v2b;
               ^
-./third_party/blink/renderer/discouraged_type.h:36:16: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:38:16: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   FloatVector2 v2c;
                ^
-./third_party/blink/renderer/discouraged_type.h:39:21: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:41:21: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   std::vector<char> v_array[4][4];
                     ^
-./third_party/blink/renderer/discouraged_type.h:71:22: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:73:22: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
     std::vector<int> v;
                      ^
-./third_party/blink/renderer/discouraged_type.h:80:18: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:82:18: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   std::vector<T> v1;
                  ^
 7 warnings generated.
diff --git a/tools/clang/plugins/tests/blink_discouraged_type.txt.actual b/tools/clang/plugins/tests/blink_discouraged_type.txt.actual
index 49396ad..ea18db36 100644
--- a/tools/clang/plugins/tests/blink_discouraged_type.txt.actual
+++ b/tools/clang/plugins/tests/blink_discouraged_type.txt.actual
@@ -1,23 +1,23 @@
 In file included from blink_discouraged_type.cpp:5:
-./third_party/blink/renderer/discouraged_type.h:29:20: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:31:20: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   std::vector<int> v1;
                    ^
-./third_party/blink/renderer/discouraged_type.h:34:21: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:36:21: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   nested::IntVector v2a;
                     ^
-./third_party/blink/renderer/discouraged_type.h:35:15: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:37:15: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   FloatVector v2b;
               ^
-./third_party/blink/renderer/discouraged_type.h:36:16: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:38:16: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   FloatVector2 v2c;
                ^
-./third_party/blink/renderer/discouraged_type.h:39:21: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:41:21: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   std::vector<char> v_array[4][4];
                     ^
-./third_party/blink/renderer/discouraged_type.h:71:22: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:73:22: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
     std::vector<int> v;
                      ^
-./third_party/blink/renderer/discouraged_type.h:80:18: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
+./third_party/blink/renderer/discouraged_type.h:82:18: warning: [blink-style] 'std::vector' is discouraged for data members in blink renderer. Use WTF::Vector if possible. If the usage is necessary, add ALLOW_DISCOURAGED_TYPE(reason) to the data member or the type alias to suppress this message.
   std::vector<T> v1;
                  ^
 7 warnings generated.
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer_main.cc b/tools/ipc_fuzzer/fuzzer/fuzzer_main.cc
index 020dfe1..f3d5bbf 100644
--- a/tools/ipc_fuzzer/fuzzer/fuzzer_main.cc
+++ b/tools/ipc_fuzzer/fuzzer/fuzzer_main.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/strings/string_split.h"
 #include "ipc/ipc_message_macros.h"
 #include "tools/ipc_fuzzer/fuzzer/fuzzer.h"
@@ -184,8 +185,7 @@
     IPC::Message* msg = message_vector[i].get();
     // If an explicit type set is specified, make sure we should be mutating
     // this message type on this run.
-    if (!type_set.empty() && type_set.end() == std::find(
-            type_set.begin(), type_set.end(), msg->type())) {
+    if (!type_set.empty() && !base::Contains(type_set, msg->type())) {
       continue;
     }
     std::unique_ptr<IPC::Message> new_message =
diff --git a/tools/linux/dump-static-initializers.py b/tools/linux/dump-static-initializers.py
index 4cc8ea0..b4265d71 100755
--- a/tools/linux/dump-static-initializers.py
+++ b/tools/linux/dump-static-initializers.py
@@ -3,291 +3,232 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Dump functions called by static intializers in a Linux Release binary.
+"""Dumps the names, addresses, and disassmebly of static initializers.
 
 Usage example:
   tools/linux/dump-static-intializers.py out/Release/chrome
 
-A brief overview of static initialization:
-1) the compiler writes out, per object file, a function that contains
-   the static intializers for that file.
-2) the compiler also writes out a pointer to that function in a special
-   section.
-3) at link time, the linker concatenates the function pointer sections
-   into a single list of all initializers.
-4) at run time, on startup the binary runs all function pointers.
-
-The functions in (1) all have mangled names of the form
-  _GLOBAL__I_foobar.cc or __cxx_global_var_initN
-using objdump, we can disassemble those functions and dump all symbols that
-they reference.
+For an explanation of static initializers, see: //docs/static_initializers.md.
 """
 
-# Needed so pylint does not complain about print('', end='').
-from __future__ import print_function
-
-import optparse
+import argparse
+import json
 import os
-import re
+import pathlib
 import subprocess
 import sys
 
-# A map of symbol => informative text about it.
-NOTES = {
-  '__cxa_atexit@plt': 'registers a dtor to run at exit',
-  'std::__ioinit': '#includes <iostream>, use <ostream> instead',
-}
+_TOOLCHAIN_PREFIX = str(
+    pathlib.Path(__file__).parents[2] / 'third_party' / 'llvm-build' /
+    'Release+Asserts' / 'bin' / 'llvm-')
 
-# Determine whether this is a git checkout (as opposed to e.g. svn).
-IS_GIT_WORKSPACE = (subprocess.Popen(
-    ['git', 'rev-parse'], stderr=subprocess.PIPE).wait() == 0)
+# It is too slow to dump disassembly for a lot of symbols.
+_MAX_DISASSEMBLY_SYMBOLS = 10
 
 
-class Demangler:
-  """A wrapper around c++filt to provide a function to demangle symbols."""
-
-  def __init__(self, toolchain):
-    # llvm toolchain uses cxx rather than c++.
-    path = toolchain + 'cxxfilt'
-    if not os.path.exists(path):
-      path = toolchain + 'c++filt'
-    if not os.path.exists(path):
-      # Android currently has an issue where the llvm toolchain in the ndk does
-      # not contain c++filt. Hopefully fixed in next NDK update...
-      path = 'c++filt'
-    self.cppfilt = subprocess.Popen([path],
-                                    stdin=subprocess.PIPE,
-                                    stdout=subprocess.PIPE,
-                                    universal_newlines=True)
-
-  def Demangle(self, sym):
-    """Given mangled symbol |sym|, return its demangled form."""
-    self.cppfilt.stdin.write(sym + '\n')
-    self.cppfilt.stdin.flush()
-    return self.cppfilt.stdout.readline().strip()
+def _ParseNm(binary, addresses):
+  # Example output:
+  # 000000000de66bd0 0000000000000026 t _GLOBAL__sub_I_add.cc
+  output = subprocess.check_output(
+      [_TOOLCHAIN_PREFIX + 'nm', '--print-size', binary], encoding='utf8')
+  addresses = set(addresses)
+  ret = {}
+  for line in output.splitlines():
+    parts = line.split()
+    if len(parts) != 4:
+      continue
+    address = int(parts[0], 16)
+    if address in addresses:
+      ret[address] = int(parts[1], 16)
+  return ret
 
 
-# Matches for example: "cert_logger.pb.cc", capturing "cert_logger".
-protobuf_filename_re = re.compile(r'(.*)\.pb\.cc$')
-def QualifyFilenameAsProto(filename):
-  """Attempt to qualify a bare |filename| with a src-relative path, assuming it
-  is a protoc-generated file.  If a single match is found, it is returned.
-  Otherwise the original filename is returned."""
-  if not IS_GIT_WORKSPACE:
-    return filename
-  match = protobuf_filename_re.match(filename)
-  if not match:
-    return filename
-  basename = match.groups(0)
-  cmd = ['git', 'ls-files', '--', '*/%s.proto' % basename]
-  gitlsfiles = subprocess.Popen(cmd,
-                                stdout=subprocess.PIPE,
-                                universal_newlines=True)
-  candidate = filename
-  for line in gitlsfiles.stdout:
-    if candidate != filename:
-      return filename # Multiple hits, can't help.
-    candidate = line.strip()
-  return candidate
+def _Disassemble(binary, start, end):
+  cmd = [
+      _TOOLCHAIN_PREFIX + 'objdump',
+      binary,
+      '--disassemble',
+      '--source',
+      '--demangle',
+      '--start-address=0x%x' % start,
+      '--stop-address=0x%x' % end,
+  ]
+  stdout = subprocess.check_output(cmd, encoding='utf8')
+  all_lines = stdout.splitlines(keepends=True)
+  source_lines = [l for l in all_lines if l.startswith(';')]
+  ret = []
+  if source_lines:
+    ret = ['Showing source lines that appear in the symbol (via objdump).\n']
+  else:
+    ret = [
+        'Symbol missing source lines. Showing raw disassembly (via objdump).\n'
+    ]
+  lines = source_lines or all_lines
+  if len(lines) > 10:
+    ret += ['This might be verbose due to inlined functions.\n']
+  ret += lines
+  return ''.join(ret)
 
 
-# Regex matching the substring of a symbol's demangled text representation most
-# likely to appear in a source file.
-# Example: "v8::internal::Builtins::InitBuiltinFunctionTable()" becomes
-# "InitBuiltinFunctionTable", since the first (optional & non-capturing) group
-# picks up any ::-qualification and the last fragment picks up a suffix that
-# starts with an opener.
-symbol_code_name_re = re.compile(r'^(?:[^(<[]*::)?([^:(<[]*).*?$')
-def QualifyFilename(filename, symbol):
-  """Given a bare filename and a symbol that occurs in it, attempt to qualify
-  it with a src-relative path.  If more than one file matches, return the
-  original filename."""
-  if not IS_GIT_WORKSPACE:
-    return filename
-  match = symbol_code_name_re.match(symbol)
-  if not match:
-    return filename
-  symbol = match.group(1)
-  cmd = ['git', 'grep', '-l', symbol, '--', '*/' + filename]
-  gitgrep = subprocess.Popen(cmd,
-                             stdout=subprocess.PIPE,
-                             universal_newlines=True)
-  candidate = filename
-  for line in gitgrep.stdout:
-    if candidate != filename:  # More than one candidate; return bare filename.
-      return filename
-    candidate = line.strip()
-  return candidate
+def _DumpInitArray(binary):
+  cmd = [_TOOLCHAIN_PREFIX + 'readobj', '--hex-dump=.init_array', binary]
+  output = subprocess.check_output(cmd, encoding='utf8')
+  # Example output:
+  # File: lib.unstripped/libmonochrome_64.so
+  # Format: elf64-littleaarch64
+  # Arch: aarch64
+  # AddressSize: 64bit
+  # LoadName: libmonochrome_64.so
+  # Hex dump of section '.init_array':
+  # 0x091f6198 14f80204 00000000 c0cf3003 00000000 ..........0.....
+  # 0x091f61a8 68c70104 00000000                   h........^F.....
+  is_64_bit = False
+  is_arm = False
+  byte_order = 'little'
+  ret = []
+  for line in output.splitlines():
+    if line.startswith('Format:') and 'big' in line:
+      byte_order = 'big'
+      continue
+    if line == 'Arch: arm':
+      is_arm = True
+      continue
+    if line == 'AddressSize: 64bit':
+      is_64_bit = True
+      continue
+    if not line.startswith('0x'):
+      continue
+    init_array_address = int(line[:10], 16)
+    parts = line[10:-16].split()
+    assert len(parts) <= 4, 'Too many parts: ' + line
+    if is_64_bit:
+      parts = [parts[i] + parts[i + 1] for i in range(0, len(parts), 2)]
+    arrays = (bytearray.fromhex(p) for p in parts)
+    for a in arrays:
+      address = int.from_bytes(a, byteorder=byte_order, signed=False)
+      if is_arm:
+        address = address & ~1  # Adjust for arm thumb addresses being odd.
+      ret.append((init_array_address, address))
+      init_array_address += 8 if is_64_bit else 4
+  return ret
 
 
-# Regex matching nm output for the symbols we're interested in. The two formats
-# we are interested in are _GLOBAL__sub_I_<filename> and _cxx_global_var_initN.
-# See test_ParseNmLine for examples.
-nm_re = re.compile(
-    r'''(\S+)\s(\S+)\st\s                # Symbol start address and size
-        (
-          (?:_ZN12)?_GLOBAL__(?:sub_)?I_ # Pattern with filename
-        |
-          __cxx_global_var_init\d*       # Pattern without filename
-        )(.*)                            # capture the filename''',
-    re.X)
-def ParseNmLine(line):
-  """Parse static initializers from a line of nm output.
-
-  Given a line of nm output, parse static initializers as a
-  (file, start, size, symbol) tuple."""
-  match = nm_re.match(line)
-  if match:
-    addr, size, prefix, filename = match.groups()
-    return (filename, int(addr, 16), int(size, 16), prefix+filename)
-  return None
+def _DumpRelativeRelocations(binary):
+  # Example output from: llvm-readobj --relocations chrome
+  # File: chrome
+  # Format: elf64-x86-64
+  # Arch: x86_64
+  # AddressSize: 64bit
+  # LoadName: <Not found>
+  # Relocations [
+  #   Section (10) .rela.dyn {
+  #     0x26C2AD88 R_X86_64_RELATIVE - 0xA6DABE0
+  #     0x26C2AD90 R_X86_64_RELATIVE - 0xA6DC2B0
+  # ...
+  cmd = [_TOOLCHAIN_PREFIX + 'readobj', '--relocations', binary]
+  lines = subprocess.check_output(cmd, encoding='utf8').splitlines()
+  ret = {}
+  for line in lines:
+    if 'RELATIVE' in line:
+      parts = line.split()
+      ret[int(parts[0], 16)] = int(parts[-1], 16)
+  return ret
 
 
-def test_ParseNmLine():
-  """Verify the nm_re regex matches some sample lines."""
-  parse = ParseNmLine(
-    '0000000001919920 0000000000000008 t '
-    '_ZN12_GLOBAL__I_safe_browsing_service.cc')
-  assert parse == ('safe_browsing_service.cc', 26319136, 8,
-                   '_ZN12_GLOBAL__I_safe_browsing_service.cc'), parse
-
-  parse = ParseNmLine(
-    '00000000026b9eb0 0000000000000024 t '
-    '_GLOBAL__sub_I_extension_specifics.pb.cc')
-  assert parse == ('extension_specifics.pb.cc', 40607408, 36,
-                   '_GLOBAL__sub_I_extension_specifics.pb.cc'), parse
-
-  parse = ParseNmLine(
-    '0000000002e75a60 0000000000000016 t __cxx_global_var_init')
-  assert parse == ('', 48716384, 22, '__cxx_global_var_init'), parse
-
-  parse = ParseNmLine(
-    '0000000002e75a60 0000000000000016 t __cxx_global_var_init89')
-  assert parse == ('', 48716384, 22, '__cxx_global_var_init89'), parse
+def _ResolveRelativeAddresses(binary, address_tuples):
+  relocations_dict = None
+  ret = []
+  for init_address, address in address_tuples:
+    if address == 0:
+      if relocations_dict is None:
+        relocations_dict = _DumpRelativeRelocations(binary)
+      address = relocations_dict.get(init_address)
+      if address is None:
+        raise Exception('Failed to resolve relocation for address: ' +
+                        hex(init_address))
+    ret.append(address)
+  return ret
 
 
-# Just always run the test; it is fast enough.
-test_ParseNmLine()
-
-
-def ParseNm(toolchain, binary):
-  """Yield static initializers for the given binary.
-
-  Given a binary, yield static initializers as (file, start, size, symbol)
-  tuples."""
-  nm = subprocess.Popen([toolchain + 'nm', '-S', binary],
-                        stdout=subprocess.PIPE,
-                        universal_newlines=True)
-  for line in nm.stdout:
-    parse = ParseNmLine(line)
-    if parse:
-      yield parse
-
-
-# Regex matching objdump output for the symbols we're interested in.
-# Example line:
-#     12354ab:  (disassembly, including <FunctionReference>)
-disassembly_re = re.compile(r'^\s+[0-9a-f]+:.*<(\S+)>')
-def ExtractSymbolReferences(toolchain, binary, start, end, symbol):
-  """Given a span of addresses, returns symbol references from disassembly."""
-  cmd = [toolchain + 'objdump', binary, '--disassemble',
-         '--start-address=0x%x' % start, '--stop-address=0x%x' % end]
-  objdump = subprocess.Popen(cmd,
-                             stdout=subprocess.PIPE,
-                             universal_newlines=True)
-
-  refs = set()
-  for line in objdump.stdout:
-    if '__static_initialization_and_destruction' in line:
-      raise RuntimeError('code mentions '
-                         '__static_initialization_and_destruction; '
-                         'did you accidentally run this on a Debug binary?')
-    match = disassembly_re.search(line)
-    if match:
-      (ref,) = match.groups()
-      if ref.startswith('.LC') or ref.startswith('_DYNAMIC'):
-        # Ignore these, they are uninformative.
-        continue
-      if re.match(symbol, ref):
-        # Probably a relative jump within this function.
-        continue
-      refs.add(ref)
-
-  return sorted(refs)
+def _SymbolizeAddresses(binary, addresses):
+  # Example output from: llvm-symbolizer -e chrome \
+  #    --output-style=JSON --functions 0x3323430 0x403a768 0x5489b98
+  # [{"Address":"0xa6afdd0","ModuleName":"chrome","Symbol":[...]}, ...]
+  # Where Symbol = {"Column":24,"Discriminator":0,"FileName":"...",
+  #    "FunctionName":"MaybeStartBackgroundThread","Line":85,
+  #    "StartAddress":"0xa6afdd0","StartFileName":"","StartLine":0}
+  ret = {}
+  if not addresses:
+    return ret
+  cmd = [
+      _TOOLCHAIN_PREFIX + 'symbolizer', '-e', binary, '--functions',
+      '--output-style=JSON'
+  ] + [hex(a) for a in addresses]
+  output = subprocess.check_output(cmd, encoding='utf8')
+  for main_entry in json.loads(output):
+    # Multiple symbol entries can exist due to inlining. Last entry is the
+    # outer-most symbol.
+    symbols = main_entry['Symbol']
+    name_entry = symbols[-1]
+    # Take the last entry that has a line number as the best filename.
+    file_entry = next((x for x in symbols[::-1] if x['Line'] != 0), name_entry)
+    address = int(main_entry['Address'], 16)
+    filename = file_entry['FileName']
+    line = file_entry['Line']
+    if line:
+      filename += f':{line}'
+    ret[address] = (filename, name_entry['FunctionName'])
+  return ret
 
 
 def main():
-  parser = optparse.OptionParser(usage='%prog [option] filename')
-  parser.add_option('-d', '--diffable', dest='diffable',
-                    action='store_true', default=False,
-                    help='Prints the filename on each line, for more easily '
-                         'diff-able output. (Used by sizes.py)')
-  parser.add_option('-t', '--toolchain-prefix', dest='toolchain',
-                    action='store', default='',
-                    help='Toolchain prefix to append to all tool invocations '
-                         '(nm, objdump).')
-  opts, args = parser.parse_args()
-  if len(args) != 1:
-    parser.error('missing filename argument')
-    return 1
-  binary = args[0]
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--json',
+                      action='store_true',
+                      help='Output in JSON format')
+  parser.add_argument('binary', help='The non-stripped binary to analyze.')
+  args = parser.parse_args()
 
-  demangler = Demangler(opts.toolchain)
-  file_count = 0
-  initializer_count = 0
+  address_tuples = _DumpInitArray(args.binary)
+  addresses = _ResolveRelativeAddresses(args.binary, address_tuples)
+  symbolized_by_address = _SymbolizeAddresses(args.binary, addresses)
 
-  files = ParseNm(opts.toolchain, binary)
-  if opts.diffable:
-    files = sorted(files)
-  for filename, addr, size, symbol in files:
-    file_count += 1
-    ref_output = []
+  skip_disassembly = len(addresses) > _MAX_DISASSEMBLY_SYMBOLS
+  if skip_disassembly:
+    sys.stderr.write('Not collection disassembly due to the large number of '
+                     'results.\n')
+  else:
+    size_by_address = _ParseNm(args.binary, addresses)
 
-    qualified_filename = QualifyFilenameAsProto(filename)
-
-    if size == 2:
-      # gcc generates a two-byte 'repz retq' initializer when there is a
-      # ctor even when the ctor is empty.  This is fixed in gcc 4.6, but
-      # Android uses gcc 4.4.
-      ref_output.append('[empty ctor, but it still has cost on gcc <4.6]')
+  entries = []
+  for address in addresses:
+    filename, symbol_name = symbolized_by_address[address]
+    if skip_disassembly:
+      disassembly = ''
     else:
-      for ref in ExtractSymbolReferences(opts.toolchain, binary, addr,
-                                         addr+size, symbol):
-        initializer_count += 1
-
-        ref = demangler.Demangle(ref)
-        if qualified_filename == filename:
-          qualified_filename = QualifyFilename(filename, ref)
-
-        note = ''
-        if ref in NOTES:
-          note = NOTES[ref]
-        elif ref.endswith('_2eproto()'):
-          note = 'protocol compiler bug: crbug.com/105626'
-
-        if note:
-          ref_output.append('%s [%s]' % (ref, note))
-        else:
-          ref_output.append(ref)
-
-    if opts.diffable:
-      if ref_output:
-        print('\n'.join(
-            '# ' + qualified_filename + ' ' + r for r in ref_output))
+      size = size_by_address.get(address, 0)
+      if size == 0:
+        disassembly = ('Not showing disassembly because of unknown symbol size '
+                       '(assembly symbols sometimes omit size).\n')
       else:
-        print('# %s: (empty initializer list)' % qualified_filename)
-    else:
-      print('%s (initializer offset 0x%x size 0x%x)' % (qualified_filename,
-                                                        addr, size))
-      print(''.join('  %s\n' % r for r in ref_output))
+        disassembly = _Disassemble(args.binary, address, address + size)
+    entries.append({
+        'address': address,
+        'disassembly': disassembly,
+        'filename': filename,
+        'symbol_name': symbol_name,
+    })
 
-  if opts.diffable:
-    print('#', end=' ')
-  print('Found %d static initializers in %d files.' % (initializer_count,
-                                                       file_count))
+  if args.json:
+    print(json.dumps({'entries': entries}))
+    return
 
-  return 0
+  for e in entries:
+    print(f'# 0x{e["address"]:x} {e["filename"]} {e["symbol_name"]}')
+    print(e['disassembly'])
+
+  print(f'Found {len(entries)} files containing static initializers.')
 
 
 if '__main__' == __name__:
-  sys.exit(main())
+  main()
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index a418232a..e430cac 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -3237,7 +3237,7 @@
     ],
 
     'official_goma_fuchsia_arm64_perf': [
-      'official', 'goma', 'minimal_symbols', 'fuchsia', 'fuchsia_include_sd_images', 'arm64', 'ffmpeg_branding_chrome', 'proprietary_codecs', 'test_isolate_no_emulator', 'fuchsia_cfv2_script'
+      'cast_receiver_size_optimized_internal', 'official', 'goma', 'minimal_symbols', 'fuchsia', 'fuchsia_include_sd_images', 'arm64', 'ffmpeg_branding_chrome', 'proprietary_codecs', 'test_isolate_no_emulator', 'fuchsia_cfv2_script'
     ],
 
     'official_goma_fuchsia_x64_perf': [
@@ -3872,6 +3872,10 @@
       'args_file': '//build/config/fuchsia/size_optimized_cast_receiver_args.gn',
     },
 
+    'cast_receiver_size_optimized_internal': {
+      'args_file': '//build/config/fuchsia/size_optimized_cast_receiver_args_internal.gn',
+    },
+
     'cfi': {
       'gn_args': 'is_cfi=true',
     },
diff --git a/tools/mb/mb_config_expectations/chromium.perf.fyi.json b/tools/mb/mb_config_expectations/chromium.perf.fyi.json
index 98fe5a2b..d4f4854 100644
--- a/tools/mb/mb_config_expectations/chromium.perf.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.perf.fyi.json
@@ -43,6 +43,7 @@
     }
   },
   "fuchsia-builder-perf-arm64": {
+    "args_file": "//build/config/fuchsia/size_optimized_cast_receiver_args_internal.gn",
     "gn_args": {
       "ffmpeg_branding": "Chrome",
       "fuchsia_additional_boot_images": [
@@ -61,6 +62,7 @@
     }
   },
   "fuchsia-builder-perf-fyi": {
+    "args_file": "//build/config/fuchsia/size_optimized_cast_receiver_args_internal.gn",
     "gn_args": {
       "ffmpeg_branding": "Chrome",
       "fuchsia_additional_boot_images": [
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.perf.json b/tools/mb/mb_config_expectations/tryserver.chromium.perf.json
index f743ea4..189f792 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.perf.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.perf.json
@@ -74,6 +74,7 @@
     }
   },
   "Fuchsia Builder Perf": {
+    "args_file": "//build/config/fuchsia/size_optimized_cast_receiver_args_internal.gn",
     "gn_args": {
       "ffmpeg_branding": "Chrome",
       "fuchsia_additional_boot_images": [
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 81e983a2..2e744131 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -34945,6 +34945,8 @@
   <suffix name="PreviewsOmniboxUI"
       label="For the Previews UI in the Android Omnibox feature."/>
   <suffix name="PriceDropNTP" label="For PriceDropNTP feature."/>
+  <suffix name="PriceTrackingInSidePanel"
+      label="For PriceTrackingInSidePanelFeature feature."/>
   <suffix name="ProfileSwitch"
       label="In product help for switching profiles using the profile menu."/>
   <suffix name="PwaInstallAvailableFeature"
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index c6b702b..4d119a45 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3070,8 +3070,14 @@
   <int value="2" label="Showing the banner"/>
   <int value="3" label="preventDefault() not called"/>
   <int value="4" label="preventDefault() called"/>
-  <int value="5" label="prompt() called after preventDefault()"/>
-  <int value="6" label="prompt() not called after preventDefault()"/>
+  <int value="5" label="prompt() called after preventDefault() (deprecated)"/>
+  <int value="6"
+      label="prompt() not called after preventDefault() (deprecated)"/>
+  <int value="7" label="prompt() called early"/>
+  <int value="8" label="prompt() called after preventDefault()"/>
+  <int value="9" label="prompt() called without preventDefault()"/>
+  <int value="10" label="prompt() not called after preventDefault()"/>
+  <int value="11" label="prompt() not called without preventDefault()"/>
 </enum>
 
 <enum name="AppBannersDismissEvent">
@@ -24716,19 +24722,6 @@
   <int value="8" label="DSP set to new engine with no previous value in prefs"/>
 </enum>
 
-<enum name="DefaultTouchBarActions">
-  <int value="0" label="Back"/>
-  <int value="1" label="Forward"/>
-  <int value="2" label="Stop"/>
-  <int value="3" label="Reload"/>
-  <int value="4" label="Home"/>
-  <int value="5" label="Search"/>
-  <int value="6" label="Star"/>
-  <int value="7" label="New Tab"/>
-  <int value="8" label="Credit Card Autofill"/>
-  <int value="9" label="Text Suggestion"/>
-</enum>
-
 <enum name="DefaultWebClientState">
   <int value="0" label="Not default">Chrome is not the default web client.</int>
   <int value="1" label="Is default">Chrome is the default web client.</int>
@@ -32620,6 +32613,7 @@
   <int value="1022" label="IsolatedWebAppInstallForceList"/>
   <int value="1023" label="DeskAPIThirdPartyAllowlist"/>
   <int value="1024" label="VirtualKeyboardResizesLayoutByDefault"/>
+  <int value="1025" label="HindiInscriptLayoutEnabled"/>
 </enum>
 
 <enum name="EnterprisePoliciesSources">
@@ -35773,6 +35767,7 @@
   <int value="1722" label="AUTOTESTPRIVATE_MAKEFUSEBOXTEMPDIR"/>
   <int value="1723" label="AUTOTESTPRIVATE_REMOVEFUSEBOXTEMPDIR"/>
   <int value="1724" label="AUTOTESTPRIVATE_GETTHROUGHPUTTRACKERDATA"/>
+  <int value="1725" label="ENTERPRISE_REMOTEAPPS_SORTLAUNCHER"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -36874,6 +36869,20 @@
       label="Settings - remove confirmed on remove saved device dialog"/>
 </enum>
 
+<enum name="FastPairTrackedModelID">
+  <int value="0" label="Other"/>
+  <int value="1" label="JBLTUNE125TWS"/>
+  <int value="2" label="OnePlusBudsZ"/>
+  <int value="3" label="JBLTUNE225TWS"/>
+  <int value="4" label="SonyWF1000XM3"/>
+  <int value="5" label="RealmeBudsAir2"/>
+  <int value="6" label="JBLLIVE400BT"/>
+  <int value="7" label="JBLLIVE300TWS"/>
+  <int value="8" label="PixelBuds"/>
+  <int value="9" label="PixelBudsASeries"/>
+  <int value="10" label="PixelBudsPro"/>
+</enum>
+
 <enum name="FastPairVersion">
   <int value="0" label="v1"/>
   <int value="1" label="v2"/>
@@ -54707,6 +54716,19 @@
   <int value="8026721" label="Zaza"/>
 </enum>
 
+<enum name="LanguagePackFeatureIds">
+<!-- This must be kept current with FeatureIdsEnum in
+chromeos/ash/components/language/language_packs/language_pack_manager.cc -->
+
+  <summary>
+    List of all the Features that are supported by Language Packs. A Feature is
+    a synonym for client.
+  </summary>
+  <int value="0" label="UNKNOWN"/>
+  <int value="1" label="HANDWRITING"/>
+  <int value="2" label="TTS"/>
+</enum>
+
 <enum name="LanguagePackLanguageCodes">
   <summary>
     Hash values of language codes that correspond to a Language Pack. The hash
@@ -59315,6 +59337,8 @@
   <int value="-589096918" label="ash-enable-fullscreen-app-list"/>
   <int value="-588669613"
       label="OmniboxClobberIsZeroSuggestEntrypoint:enabled"/>
+  <int value="-588163454"
+      label="AccessibilitySelectToSpeakHoverTextImprovements:enabled"/>
   <int value="-585508682" label="DownloadRange:enabled"/>
   <int value="-584866456" label="LacrosProfileMigrationForceOff:disabled"/>
   <int value="-583842972"
@@ -61171,6 +61195,7 @@
   <int value="550741462" label="WebAppBorderless:disabled"/>
   <int value="552317551" label="MediaAppHandlesPdf:disabled"/>
   <int value="552421509" label="AssistMultiWordExpanded:enabled"/>
+  <int value="553197994" label="FedCmMetricsEndpoint:enabled"/>
   <int value="555959995" label="ChromeSharingHub:enabled"/>
   <int value="556555487"
       label="AutofillDoNotUploadSaveUnsupportedCards:disabled"/>
@@ -61477,6 +61502,8 @@
   <int value="731779469" label="BlinkHeapUnifiedGarbageCollection:enabled"/>
   <int value="732703958" label="enable-gesture-tap-highlight"/>
   <int value="734900932" label="RecurrentInterstitialFeature:enabled"/>
+  <int value="735180038"
+      label="AccessibilitySelectToSpeakHoverTextImprovements:disabled"/>
   <int value="735393448" label="InsertKeyToggleMode:disabled"/>
   <int value="736911267" label="ExperimentalCrostiniUI:disabled"/>
   <int value="737195667" label="AutofillPageLanguageDetection:enabled"/>
@@ -61805,6 +61832,7 @@
   <int value="939366135" label="DownloadsLocationChange:disabled"/>
   <int value="939554480" label="enable-credit-card-scan"/>
   <int value="939603162" label="BackgroundLoadingForDownloads:disabled"/>
+  <int value="940302066" label="OmniboxUniformRowHeight:disabled"/>
   <int value="941036016" label="ContentSuggestionsSettings:disabled"/>
   <int value="941883332" label="ProactiveTabFreezeAndDiscard:disabled"/>
   <int value="941948340" label="PlaybackSpeedButton:enabled"/>
@@ -63093,6 +63121,7 @@
   <int value="1731522433" label="enable-offer-store-unmasked-wallet-cards"/>
   <int value="1731612996" label="CrostiniFiles:disabled"/>
   <int value="1733390925" label="force-enable-stylus-tools"/>
+  <int value="1733740363" label="FedCmMetricsEndpoint:disabled"/>
   <int value="1734685331" label="NtpShoppingTasksModule:enabled"/>
   <int value="1735934914" label="OverlayScrollbarFlashWhenMouseEnter:disabled"/>
   <int value="1736698988" label="FsNosymfollow:disabled"/>
@@ -63776,6 +63805,7 @@
   <int value="2142979536" label="EnableManualFallbacksFilling:disabled"/>
   <int value="2144581598" label="UpcomingSharingFeatures:enabled"/>
   <int value="2145140507" label="WebViewRecordAppDataDirectorySize:enabled"/>
+  <int value="2147448086" label="OmniboxUniformRowHeight:enabled"/>
 </enum>
 
 <enum name="LoginDatabaseInitError">
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index a4f2f53..e0dc1d7 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -4573,6 +4573,19 @@
   </summary>
 </histogram>
 
+<histogram name="Android.WebView.OptionallyBlockableMixedContentLoaded.Mode"
+    enum="WebViewMixedContentMode" expires_after="2023-08-25">
+  <owner>ntfschr@chromium.org</owner>
+  <owner>carlosil@chromium.org</owner>
+  <owner>src/android_webview/OWNERS</owner>
+  <summary>
+    Records the mixed content mode set when an app loads optionally blockable
+    mixed content (images, audio, or video). This histogram is logged on page
+    load, once per subresource (i.e. a single page load can cause multiple
+    records if the page contains multiple mixed content subresources).
+  </summary>
+</histogram>
+
 <histogram name="Android.WebView.OriginsVisited" units="origins"
     expires_after="2023-02-15">
   <owner>mvanouwerkerk@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index af860537..704db37 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -2083,6 +2083,19 @@
   <token key="TabletOrClamshell" variants="DisplayModes"/>
 </histogram>
 
+<histogram
+    name="Apps.Launcher.DragReorderAnimationSmoothness.{TabletOrClamshell}"
+    units="%" expires_after="M112">
+  <owner>mmourgos@chromium.org</owner>
+  <owner>chromeos-launcher@google.com</owner>
+  <summary>
+    Emitted when an app list drag reorder animation completes. Reports the
+    smoothness of this animation. 100% represents the ideally smooth 60 frames
+    per second.
+  </summary>
+  <token key="TabletOrClamshell" variants="DisplayModes"/>
+</histogram>
+
 <histogram name="Apps.Launcher.InstallAppFromLinkResult"
     enum="WebAppInstallResultCode" expires_after="2022-09-25">
   <owner>dmurph@chromium.org</owner>
@@ -2123,7 +2136,7 @@
   <owner>andrewxu@chromium.org</owner>
   <owner>chromeos-launcher@google.com</owner>
   <summary>
-    Emitted when the app list reorder animation completes. Reports the
+    Emitted when the app list sort reorder animation completes. Reports the
     smoothness of this animation. 100% represents the ideally smooth 60 frames
     per second.
   </summary>
diff --git a/tools/metrics/histograms/metadata/bluetooth/histograms.xml b/tools/metrics/histograms/metadata/bluetooth/histograms.xml
index a684fa72..3c98e84 100644
--- a/tools/metrics/histograms/metadata/bluetooth/histograms.xml
+++ b/tools/metrics/histograms/metadata/bluetooth/histograms.xml
@@ -194,6 +194,40 @@
   </token>
 </histogram>
 
+<histogram
+    name="Bluetooth.ChromeOS.FastPair.AccountKey.Write.Result.{FastPairPairingProtocol}.{FastPairTrackedModelID}"
+    enum="BooleanSuccess" expires_after="2023-02-26">
+  <owner>dclasson@google.com</owner>
+  <owner>julietlevesque@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records success or failure of writing an account key to a device, split per
+    protocol and per Model ID. Emitted on the OnPairFailure event and the
+    OnDevicePaired event in the Fast Pair flow.
+  </summary>
+  <token key="FastPairPairingProtocol">
+    <variant name="InitialPairingProtocol" summary="initial pairing protocol"/>
+    <variant name="RetroactivePairingProtocol"
+        summary="retroactive pairing protocol"/>
+    <variant name="SubsequentPairingProtocol"
+        summary="subsequent pairing protocol"/>
+  </token>
+  <token key="FastPairTrackedModelID">
+    <variant name="JBLLIVE300TWS" summary="JBL LIVE 300 TWS"/>
+    <variant name="JBLLIVE400BT" summary="JBL LIVE 400 BT"/>
+    <variant name="JBLTUNE125TWS" summary="JBL TUNE 125 TWS"/>
+    <variant name="JBLTUNE225TWS" summary="JBL TUNE 225 TWS"/>
+    <variant name="OnePlusBudsZ" summary="OnePlus Buds Z"/>
+    <variant name="Other"
+        summary="A headset that isn't one of the tracked models."/>
+    <variant name="PixelBuds" summary="Pixel Buds V1"/>
+    <variant name="PixelBudsASeries" summary="Pixel buds A-series"/>
+    <variant name="PixelBudsPro" summary="Pixel buds pro"/>
+    <variant name="RealmeBudsAir2" summary="Realme Buds Air 2"/>
+    <variant name="SonyWF1000XM3" summary="Sony WF-1000 XM3"/>
+  </token>
+</histogram>
+
 <histogram name="Bluetooth.ChromeOS.FastPair.AccountKey.Write.TotalTime"
     units="ms" expires_after="2023-02-26">
   <owner>shanefitz@google.com</owner>
@@ -313,6 +347,39 @@
 </histogram>
 
 <histogram
+    name="Bluetooth.ChromeOS.FastPair.EngagementFunnel.Steps.{FastPairPairingProtocol}.{FastPairTrackedModelID}"
+    enum="FastPairEngagementFlowEvent" expires_after="2023-02-26">
+  <owner>dclasson@google.com</owner>
+  <owner>julietlevesque@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records each step in the Fast Pair flow, split per protocol and per Model
+    ID. Emitted when the discovery UI is shown, the discovery UI is dismissed,
+    pairing progress begins, pairing fails, pairing succeeded, the error UI is
+    dismissed, and/or when the setting button on the error UI is pressed.
+  </summary>
+  <token key="FastPairPairingProtocol">
+    <variant name="InitialPairingProtocol" summary="initial pairing protocol"/>
+    <variant name="SubsequentPairingProtocol"
+        summary="subsequent pairing protocol"/>
+  </token>
+  <token key="FastPairTrackedModelID">
+    <variant name="JBLLIVE300TWS" summary="JBL LIVE 300 TWS"/>
+    <variant name="JBLLIVE400BT" summary="JBL LIVE 400 BT"/>
+    <variant name="JBLTUNE125TWS" summary="JBL TUNE 125 TWS"/>
+    <variant name="JBLTUNE225TWS" summary="JBL TUNE 225 TWS"/>
+    <variant name="OnePlusBudsZ" summary="OnePlus Buds Z"/>
+    <variant name="Other"
+        summary="A headset that isn't one of the tracked models."/>
+    <variant name="PixelBuds" summary="Pixel Buds V1"/>
+    <variant name="PixelBudsASeries" summary="Pixel buds A-series"/>
+    <variant name="PixelBudsPro" summary="Pixel buds pro"/>
+    <variant name="RealmeBudsAir2" summary="realme Buds Air 2"/>
+    <variant name="SonyWF1000XM3" summary="Sony WF-1000 XM3"/>
+  </token>
+</histogram>
+
+<histogram
     name="Bluetooth.ChromeOS.FastPair.FastPairDataEncryptor.CreateResult"
     enum="BooleanSuccess" expires_after="2023-02-26">
   <owner>shanefitz@google.com</owner>
@@ -852,6 +919,34 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Bluetooth.ChromeOS.FastPair.RetroactiveEngagementFunnel.Steps.{FastPairTrackedModelID}"
+    enum="FastPairRetroactiveEngagementFlowEvent" expires_after="2023-02-26">
+  <owner>dclasson@google.com</owner>
+  <owner>julietlevesque@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records each step in the Retroactive Pair flow, split per Model ID. Emitted
+    when the associate account UI is shown, the associate account UI is
+    dismissed, the save to account button is pressed on the associate account
+    UI, and when the learn more button is pressed on the associate account UI.
+  </summary>
+  <token key="FastPairTrackedModelID">
+    <variant name="JBLLIVE300TWS" summary="JBL LIVE 300 TWS"/>
+    <variant name="JBLLIVE400BT" summary="JBL LIVE 400 BT"/>
+    <variant name="JBLTUNE125TWS" summary="JBL TUNE 125 TWS"/>
+    <variant name="JBLTUNE225TWS" summary="JBL TUNE 225 TWS"/>
+    <variant name="OnePlusBudsZ" summary="OnePlus Buds Z"/>
+    <variant name="Other"
+        summary="A headset that isn't one of the tracked models."/>
+    <variant name="PixelBuds" summary="Pixel Buds V1"/>
+    <variant name="PixelBudsASeries" summary="Pixel buds A-series"/>
+    <variant name="PixelBudsPro" summary="Pixel buds pro"/>
+    <variant name="RealmeBudsAir2" summary="Realme Buds Air 2"/>
+    <variant name="SonyWF1000XM3" summary="Sony WF-1000 XM3"/>
+  </token>
+</histogram>
+
 <histogram name="Bluetooth.ChromeOS.FastPair.RetroactivePairing.Result"
     enum="BooleanSuccess" expires_after="2023-02-26">
   <owner>shanefitz@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index 3cc1102..248d277a 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1323,6 +1323,17 @@
   </summary>
 </histogram>
 
+<histogram name="ChromeOS.LanguagePacks.GetPackState.FeatureId"
+    enum="LanguagePackFeatureIds" expires_after="2023-01-30">
+  <owner>claudiomagni@chromium.org</owner>
+  <owner>mlcui@google.com</owner>
+  <owner>dvallet@chromium.org</owner>
+  <summary>
+    Records which feature requested a Pack from Language Packs Manager;
+    specifically an entry is recorded each time GetPackState is called.
+  </summary>
+</histogram>
+
 <histogram name="ChromeOS.LanguagePacks.GetPackState.LanguageCode"
     enum="LanguagePackLanguageCodes" expires_after="2023-01-30">
   <owner>claudiomagni@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml
index b5c47f7..427bda19 100644
--- a/tools/metrics/histograms/metadata/content/histograms.xml
+++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -688,6 +688,52 @@
   </summary>
 </histogram>
 
+<histogram name="ContentSuggestions.Feed.ContentLifetime.InvalidAge" units="ms"
+    expires_after="2023-03-01">
+  <owner>birnie@google.com</owner>
+  <owner>feed@chromium.org</owner>
+  <summary>
+    Android: The invalid age lifetime of content fetched from the server.
+    Reported when new content is served to the feed from the server. This
+    provides a measure of how stale feed content is from the client side.
+  </summary>
+</histogram>
+
+<histogram name="ContentSuggestions.Feed.ContentLifetime.InvalidAgeIsPresent"
+    enum="Boolean" expires_after="2023-03-01">
+  <owner>birnie@google.com</owner>
+  <owner>feed@chromium.org</owner>
+  <summary>
+    Android: If the content lifetime of a feed response has a non zero invalid
+    age when fetched from the server. Reported when new content is served to the
+    feed from the server. This provides a measure of how stale feed content is
+    from the client side.
+  </summary>
+</histogram>
+
+<histogram name="ContentSuggestions.Feed.ContentLifetime.StaleAge" units="ms"
+    expires_after="2023-03-01">
+  <owner>birnie@google.com</owner>
+  <owner>feed@chromium.org</owner>
+  <summary>
+    Android: The stale age lifetime of content fetched from the server. Reported
+    when new content is served to the feed from the server. This provides a
+    measure of how stale feed content is from the client side.
+  </summary>
+</histogram>
+
+<histogram name="ContentSuggestions.Feed.ContentLifetime.StaleAgeIsPresent"
+    enum="Boolean" expires_after="2023-03-01">
+  <owner>birnie@google.com</owner>
+  <owner>feed@chromium.org</owner>
+  <summary>
+    Android: If the content lifetime of a feed response has a non zero stale age
+    when fetched from the server. Reported when new content is served to the
+    feed from the server. This provides a measure of how stale feed content is
+    from the client side.
+  </summary>
+</histogram>
+
 <histogram name="ContentSuggestions.Feed.Controls.Actions"
     enum="FeedControlsActions" expires_after="never">
 <!-- expires-never: tracked as an important feed metric. -->
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
index fb24f706..0c96a574 100644
--- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
+++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -182,6 +182,9 @@
   <variant name="IPH_PriceDropNTP"
       summary="the in product help message to inform users that a price drop
                has occurred in a tab"/>
+  <variant name="IPH_PriceTrackingInSidePanel"
+      summary="first time user tracks a product to educate them to see the
+               price tracking list in side panel"/>
   <variant name="IPH_ProfileSwitch"
       summary="switching profiles using the profile menu"/>
   <variant name="IPH_PwaInstallAvailableFeature"
diff --git a/tools/metrics/histograms/metadata/fingerprint/histograms.xml b/tools/metrics/histograms/metadata/fingerprint/histograms.xml
index 7225953..23316e61 100644
--- a/tools/metrics/histograms/metadata/fingerprint/histograms.xml
+++ b/tools/metrics/histograms/metadata/fingerprint/histograms.xml
@@ -156,7 +156,17 @@
     expires_after="2023-04-05">
   <owner>tomhughes@chromium.org</owner>
   <owner>chromeos-fingerprint@google.com</owner>
-  <summary>Counts the number of fingers enrolled by the user.</summary>
+  <summary>
+    Counts the number of fingers enrolled by the user.
+
+    This metric is reported in biod when the first user logs in. It is not
+    reported when a secondary user logs in, nor when all users log-off, nor when
+    the primary user uses fingerprint unlock. It may be reported again if
+    session_manage crashes.
+
+    This metric is emitted in SendStatsOnLogin() along with
+    Fingerprint.UnlockEnabled.
+  </summary>
 </histogram>
 
 <histogram name="Fingerprint.Unlock.Match.PositiveMatchSecretCorrect"
@@ -283,8 +293,17 @@
   <owner>tomhughes@chromium.org</owner>
   <owner>chromeos-fingerprint@google.com</owner>
   <summary>
-    Track whether fingerprint is enabled to unlock the screen, when the user
-    logs in.
+    Indicates whether at least one finger is enrolled, which effectively permits
+    fingerprint unlock.
+
+    This metric is reported in biod when the first user logs in. It is not
+    reported when a secondary user logs in, nor when all users log-off, nor when
+    the primary user uses fingerprint unlock. It may be reported again if
+    session_manage crashes. It does not take into account if policy has
+    subsequently disabled fingerprint unlock.
+
+    This metric is emitted in SendStatsOnLogin() along with
+    Fingerprint.Unlock.EnrolledFingerCount.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 74e359e..995fe1f0 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -3429,6 +3429,20 @@
   </summary>
 </histogram>
 
+<histogram name="Conversions.AggregatableReport.ExtraReportDelay" units="ms"
+    expires_after="M117">
+  <owner>linnan@chromium.org</owner>
+  <owner>johnidel@chromium.org</owner>
+  <owner>measurement-api-dev+metrics@google.com</owner>
+  <summary>
+    Records the &quot;extra&quot; non-scheduled time it took to send a
+    particular aggregatable attribution report. This is primarily due to a
+    report's scheduled report time taking place while the browser is closed or
+    there is network issue. Recorded when an aggregatable report is to be
+    assembled.
+  </summary>
+</histogram>
+
 <histogram name="Conversions.AggregatableReport.FilteredTriggerDataPercentage"
     units="%" expires_after="M117">
   <owner>linnan@chromium.org</owner>
@@ -3482,6 +3496,21 @@
   </summary>
 </histogram>
 
+<histogram name="Conversions.AggregatableReport.SchedulerReportDelay"
+    units="ms" expires_after="M117">
+  <owner>linnan@chromium.org</owner>
+  <owner>johnidel@chromium.org</owner>
+  <owner>measurement-api-dev+metrics@google.com</owner>
+  <summary>
+    Records the time difference from when the report was intended to be sent,
+    and the actual report time. This is different from
+    Conversions.AggregatableReport.ExtraReportDelay because it uses the send
+    attempt report time, rather than initial report time assigned by the API.
+    Accounts for any delays in Chrome scheduling the report. Recorded when an
+    aggregatabl report is to be assembled.
+  </summary>
+</histogram>
+
 <histogram
     name="Conversions.AggregatableReport.TimeFromTriggerToReportAssembly"
     units="minutes" expires_after="M117">
@@ -4027,6 +4056,21 @@
   </summary>
 </histogram>
 
+<histogram name="Conversions.SchedulerReportDelay" units="ms"
+    expires_after="M117">
+  <owner>linnan@chromium.org</owner>
+  <owner>johnidel@chromium.org</owner>
+  <owner>measurement-api-dev+metrics@google.com</owner>
+  <summary>
+    Records the time difference from when the report was intended to be sent,
+    and the actual report time. This is different from
+    Conversions.ExtraReportDelay2 because it uses the send attempt report time,
+    rather than initial report time assigned by the API. Accounts for any delays
+    in Chrome scheduling the report. Recorded when an event-level report is to
+    be sent.
+  </summary>
+</histogram>
+
 <histogram name="Conversions.SourceDataHandleStatus"
     enum="ConversionDataHandleStatus" expires_after="M117">
   <owner>linnan@chromium.org</owner>
@@ -13979,13 +14023,6 @@
   </summary>
 </histogram>
 
-<histogram name="TouchBar.Default.Metrics" enum="DefaultTouchBarActions"
-    expires_after="2022-09-11">
-  <owner>ellyjones@chromium.org</owner>
-  <owner>chrome-mac-dev@google.com</owner>
-  <summary>Tracks the usage of the default touch bar buttons.</summary>
-</histogram>
-
 <histogram name="Touchpad.Acceleration.Changed" enum="BooleanEnabled"
     expires_after="M87">
   <owner>zentaro@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/performance_manager/histograms.xml b/tools/metrics/histograms/metadata/performance_manager/histograms.xml
index 642d86c..431fec5 100644
--- a/tools/metrics/histograms/metadata/performance_manager/histograms.xml
+++ b/tools/metrics/histograms/metadata/performance_manager/histograms.xml
@@ -15,7 +15,7 @@
 <histograms>
 
 <histogram name="PerformanceManager.UserTuning.EfficiencyMode"
-    enum="EfficiencyMode" expires_after="2022-11-05">
+    enum="EfficiencyMode" expires_after="2023-05-05">
   <owner>anthonyvd@chromium.org</owner>
   <owner>chrome-catan@google.com</owner>
   <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 002066df..7c97b6eb 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -2154,6 +2154,11 @@
       AutofillAssistantIntent was not undefined.
     </summary>
   </metric>
+  <metric name="AutofillFills">
+    <summary>
+      Number of Autofill fills invoked by the user on the current form.
+    </summary>
+  </metric>
   <metric name="FillingAcceptance">
     <summary>
       Has value 1 if user accepted the suggestion to fill values on a submitted
@@ -2192,6 +2197,21 @@
       corresponded to the submitted data.
     </summary>
   </metric>
+  <metric name="FlowId">
+    <summary>
+      Hashed GUID linking together multiple emissions of this event if emitted
+      within a 20 minutes timeframe.
+    </summary>
+  </metric>
+  <metric name="FormElementUserModifications">
+    <summary>
+      Number of times a user focused on a form element and changed its value.
+      Consecutive value changes on the same form element are not counted,
+      neither are JS invoked changes. Also, re-focusing a form element and
+      changing its value is only counted if another form element's value was
+      changed in the meantime.
+    </summary>
+  </metric>
   <metric name="FormTypes">
     <summary>
       Type of form. Stored as bitvector. A set ith bit implies enum FormType's
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 65fdc159..9a2ab3cf 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "win": {
-            "hash": "149ebb6934644c56b8afc439bbb8aea028c5c6d7",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/151fcca63ab82dff5e976dc39a3529dcecec0097/trace_processor_shell.exe"
+            "hash": "3da2cdfddc36c31141046dc516099e57791b2594",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/280f0b23c5c8b98248cf0ccf3d011c4fd4bb74f5/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "mac": {
-            "hash": "bdcf41f20eed52f8ec742667c872422a528047b9",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/129b11632395a84eb3307d72fde9a90945e18619/trace_processor_shell"
+            "hash": "3302b89593a5c523e29cd864645e9aa03be8116f",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/280f0b23c5c8b98248cf0ccf3d011c4fd4bb74f5/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "e1ad4861384b06d911a65f035317914b8cc975c6",
             "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "29ea2dc97e09e8e9a6ec275957ae58a58e89a5c8",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/151fcca63ab82dff5e976dc39a3529dcecec0097/trace_processor_shell"
+            "hash": "b35f0131b281b677c3b3807b61239059e8e34400",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/280f0b23c5c8b98248cf0ccf3d011c4fd4bb74f5/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/symsrc/README.chromium b/tools/symsrc/README.chromium
index bec00df..77bb5bb5 100644
--- a/tools/symsrc/README.chromium
+++ b/tools/symsrc/README.chromium
@@ -11,16 +11,17 @@
 testing without rebuilding.
 4) Make sure that you have origin/main checked out when testing because the
 current commit hash will be embedded into the PDB and it must be a landed commit
-or else the source-code retrieval will work.
-5) Run the script using a command similar to this:
-  vpython3 source_index.py out\release\base_unittests.exe.pdb --build-dir=out\release --toolchain-dir=third_party\depot_tools\win_toolchain\vs_files\3bda71a11e
+or else the source-code retrieval will not work.
+5) Run the script using a command similar to this (the hash at the end will
+vary):
+  vpython3 tools\symsrc\source_index.py out\release\base_unittests.exe.pdb --build-dir=out\release --toolchain-dir=third_party\depot_tools\win_toolchain\vs_files\3bda71a11e
 6) Rename the base directory so that the debugger cannot find its source files
 so that it is forced to use source indexing.
     ren base foo
 7) Make sure source-server is enabled in your debugger, and optionally enable
 verbose diagnostics. I used Visual Studio.
 8) Debug base_unittests.exe. Step in to start debugging. Ideally the
-source-server command to be executed will be shown), but that depends on your
+source-server command to be executed will be shown, but that depends on your
 debugger settings. A typical command would be:
   cmd /c "mkdir "C:\Users\BRUCED~1\AppData\Local\SOURCE~1\base\test\run_all_unittests.cc\91280017b199c3d37c7ef48683cfae9c8371342b" & python3 -c "import urllib.request, base64;url = \"https://chromium.googlesource.com/chromium/src.git/+/91280017b199c3d37c7ef48683cfae9c8371342b/base/test/run_all_unittests.cc?format=TEXT\";u = urllib.request.urlopen(url);open(r\"C:\Users\BRUCED~1\AppData\Local\SOURCE~1\base\test\run_all_unittests.cc\91280017b199c3d37c7ef48683cfae9c8371342b\run_all_unittests.cc\", \"wb\").write(base64.b64decode(u.read()))"
 You can manually run this command to confirm that it works.
@@ -28,13 +29,10 @@
 file and will display it. It should be in a path similar to this one:
   C:\Users\brucedawson\AppData\Local\SourceServer\base\test\run_all_unittests.cc\91280017b199c3d37c7ef48683cfae9c8371342b\run_all_unittests.cc
 10) You can manually inspect the results and look for unexpected changes by
-using this command:
+using these commands:
 
-    pdbstr -r -p:test.pdb -s:srcsrv >results.txt
-
-pdbstr can be found in this directory:
-
-    C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\srcsrv
+    set path=%path%;C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\srcsrv
+    pdbstr -r -p:out\release\base_unittests.exe.pdb -s:srcsrv >results.txt
 
 In Chrome official builds this script is invoked in the official symbols step by
   recipes\recipe_modules\chrome\resources\official_utils.py
diff --git a/tools/typescript/definitions/chrome_test.d.ts b/tools/typescript/definitions/chrome_test.d.ts
index 5ff2c4a..ca77066 100644
--- a/tools/typescript/definitions/chrome_test.d.ts
+++ b/tools/typescript/definitions/chrome_test.d.ts
@@ -12,6 +12,7 @@
     export function assertTrue(value: boolean, message?: string): asserts value;
     export function fail(message?: string): never;
     export function runTests(tests: Array<() => void>): void;
+    export function runWithUserGesture(callback: () => void): void;
     export function succeed(message?: string): void;
   }
 }
diff --git a/tools/typescript/definitions/settings_private.d.ts b/tools/typescript/definitions/settings_private.d.ts
index 905a3ba..2220a0d 100644
--- a/tools/typescript/definitions/settings_private.d.ts
+++ b/tools/typescript/definitions/settings_private.d.ts
@@ -35,15 +35,25 @@
         PARENT_SUPERVISED = 'PARENT_SUPERVISED',
       }
 
-      export interface PrefObject {
+      // TODO(crbug/1373934) Update existing usages of PrefObject to be typed,
+      // removing the need to use any here.
+      export interface PrefObject<T = any> {
         key: string;
-        type: PrefType;
-        value: any;
+        type:
+            // clang-format off
+            T extends boolean ? PrefType.BOOLEAN :
+            T extends number ? PrefType.NUMBER :
+            T extends string ? PrefType.STRING | PrefType.URL :
+            T extends unknown[] ? PrefType.LIST :
+            T extends Record<string|number, unknown> ? PrefType.DICTIONARY :
+            never;
+        // clang-format on
+        value: T;
         controlledBy?: ControlledBy;
         controlledByName?: string;
         enforcement?: Enforcement;
-        recommendedValue?: any;
-        userSelectableValues?: any[];
+        recommendedValue?: T;
+        userSelectableValues?: T[];
         userControlDisabled?: boolean;
         extensionId?: string;
         extensionCanBeDisabled?: boolean;
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
index cbfa5fa..bb69ef7 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
@@ -5,6 +5,7 @@
 #ifndef UI_ACCELERATED_WIDGET_MAC_CA_RENDERER_LAYER_TREE_H_
 #define UI_ACCELERATED_WIDGET_MAC_CA_RENDERER_LAYER_TREE_H_
 
+#include <CoreVideo/CoreVideo.h>
 #include <IOSurface/IOSurface.h>
 #include <QuartzCore/QuartzCore.h>
 
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index 6e7186a..d55a4528 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -207,6 +207,15 @@
   return base::FeatureList::IsEnabled(
       ::features::kAccessibilitySelectToSpeakPrefsMigration);
 }
+
+BASE_FEATURE(kAccessibilitySelectToSpeakHoverTextImprovements,
+             "AccessibilitySelectToSpeakHoverTextImprovements",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+bool IsAccessibilitySelectToSpeakHoverTextImprovementsEnabled() {
+  return base::FeatureList::IsEnabled(
+      ::features::kAccessibilitySelectToSpeakHoverTextImprovements);
+}
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 BASE_FEATURE(kAugmentExistingImageLabels,
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h
index 0ed7024..4581bf040 100644
--- a/ui/accessibility/accessibility_features.h
+++ b/ui/accessibility/accessibility_features.h
@@ -155,6 +155,13 @@
 // Returns true if AccessibilitySelectToSpeakPrefsMigration enabled.
 AX_BASE_EXPORT bool IsAccessibilitySelectToSpeakPrefsMigrationEnabled();
 
+// Enables AccessibilitySelectToSpeakHoverTextImprovements.
+AX_BASE_EXPORT BASE_DECLARE_FEATURE(
+    kAccessibilitySelectToSpeakHoverTextImprovements);
+
+// Returns true if AccessibilitySelectToSpeakHoverTextImprovements is enabled.
+AX_BASE_EXPORT bool IsAccessibilitySelectToSpeakHoverTextImprovementsEnabled();
+
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Enables Get Image Descriptions to augment existing images labels,
diff --git a/ui/accessibility/platform/BUILD.gn b/ui/accessibility/platform/BUILD.gn
index 029fa101..6437916 100644
--- a/ui/accessibility/platform/BUILD.gn
+++ b/ui/accessibility/platform/BUILD.gn
@@ -179,6 +179,8 @@
         "inspect/ax_event_recorder_win_uia.h",
         "inspect/ax_inspect_utils_win.cc",
         "inspect/ax_inspect_utils_win.h",
+        "inspect/ax_tree_formatter_uia_win.cc",
+        "inspect/ax_tree_formatter_uia_win.h",
         "uia_registrar_win.cc",
         "uia_registrar_win.h",
       ]
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index f22c3c78..cf6ffdd 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -4,7 +4,6 @@
 
 #include "ui/accessibility/platform/ax_platform_node_base.h"
 
-#include <algorithm>
 #include <iomanip>
 #include <limits>
 #include <set>
@@ -15,6 +14,7 @@
 #include "base/cpu_reduction_experiment.h"
 #include "base/no_destructor.h"
 #include "base/numerics/checked_math.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -1770,8 +1770,8 @@
   if (hypertext_.hyperlinks.empty())
     return -1;
 
-  auto iterator = std::find(hypertext_.hyperlinks.begin(),
-                            hypertext_.hyperlinks.end(), child->GetUniqueId());
+  auto iterator =
+      base::ranges::find(hypertext_.hyperlinks, child->GetUniqueId());
   if (iterator == hypertext_.hyperlinks.end())
     return -1;
 
@@ -1902,9 +1902,14 @@
 
     // If the endpoint is after this node, then return the node's
     // hypertext length, otherwise 0 as the endpoint points before the node.
-    if (endpoint_offset >
-        static_cast<int>(*closest_ancestor->GetIndexInParent()))
+    absl::optional<size_t> index_in_parent =
+        closest_ancestor->GetIndexInParent();
+    DCHECK(index_in_parent)
+        << "No index in parent for ancestor: " << *closest_ancestor;
+    if (index_in_parent &&
+        endpoint_offset > static_cast<int>(*index_in_parent)) {
       return static_cast<int>(GetHypertext().size());
+    }
     return 0;
   }
 
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
index 43d40a2..7008aa5 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "base/containers/contains.h"
 #include "base/no_destructor.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_constants.mojom.h"
@@ -926,7 +927,7 @@
   std::vector<ui::AXPlatformNode*> nodes;
   for (int32_t target_id : target_ids) {
     if (ui::AXPlatformNode* node = GetFromNodeID(target_id)) {
-      if (std::find(nodes.begin(), nodes.end(), node) == nodes.end())
+      if (!base::Contains(nodes, node))
         nodes.push_back(node);
     }
   }
diff --git a/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc b/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
index 82b2408..47c0635 100644
--- a/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
+++ b/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
@@ -4,6 +4,7 @@
 
 #include "ui/accessibility/platform/inspect/ax_tree_formatter_base.h"
 
+#include "base/containers/contains.h"
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -171,9 +172,7 @@
 
     // Filter out if doesn't match line index (if specified).
     if (!property_node.line_indexes.empty() &&
-        std::find(property_node.line_indexes.begin(),
-                  property_node.line_indexes.end(),
-                  line_index) == property_node.line_indexes.end()) {
+        !base::Contains(property_node.line_indexes, line_index)) {
       continue;
     }
 
diff --git a/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc b/ui/accessibility/platform/inspect/ax_tree_formatter_uia_win.cc
similarity index 85%
rename from content/browser/accessibility/accessibility_tree_formatter_uia_win.cc
rename to ui/accessibility/platform/inspect/ax_tree_formatter_uia_win.cc
index fa2138c1..a4ba719 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc
+++ b/ui/accessibility/platform/inspect/ax_tree_formatter_uia_win.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 "content/browser/accessibility/accessibility_tree_formatter_uia_win.h"
+#include "ui/accessibility/platform/inspect/ax_tree_formatter_uia_win.h"
 
 #include <math.h>
 #include <oleacc.h>
@@ -34,15 +34,10 @@
 #include "ui/accessibility/platform/uia_registrar_win.h"
 #include "ui/gfx/win/hwnd_util.h"
 
-using ui::BstrToUTF8;
-using ui::UiaIdentifierToStringUTF8;
-using ui::UiaLiveSettingToString;
-using ui::UiaOrientationToString;
-
 namespace {
 
 std::string UiaIdentifierToCondensedString(int32_t id) {
-  std::string identifier = UiaIdentifierToStringUTF8(id);
+  std::string identifier = ui::UiaIdentifierToStringUTF8(id);
   if (id >= UIA_RuntimeIdPropertyId && id <= UIA_HeadingLevelPropertyId) {
     // remove leading 'UIA_' and trailing 'PropertyId'
     return identifier.substr(4, identifier.size() - 14);
@@ -190,7 +185,7 @@
 
 }  // namespace
 
-namespace content {
+namespace ui {
 
 // This is the list of interesting properties to dump.
 //
@@ -204,52 +199,52 @@
 // to be dumped a second time here (e.g., Grid*, GridItem*, RangeValue*, etc.).
 
 // static
-const long AccessibilityTreeFormatterUia::properties_[] = {
+const long AXTreeFormatterUia::properties_[] = {
     // UIA_RuntimeIdPropertyId                          // 30000
-    UIA_BoundingRectanglePropertyId,                    // 30001
+    UIA_BoundingRectanglePropertyId,  // 30001
     // UIA_ProcessIdPropertyId                          // 30002
-    UIA_ControlTypePropertyId,                          // 30003
-    UIA_LocalizedControlTypePropertyId,                 // 30004
-    UIA_NamePropertyId,                                 // 30005
-    UIA_AcceleratorKeyPropertyId,                       // 30006
-    UIA_AccessKeyPropertyId,                            // 30007
-    UIA_HasKeyboardFocusPropertyId,                     // 30008
-    UIA_IsKeyboardFocusablePropertyId,                  // 30009
-    UIA_IsEnabledPropertyId,                            // 30010
-    UIA_AutomationIdPropertyId,                         // 30011
-    UIA_ClassNamePropertyId,                            // 30012
-    UIA_HelpTextPropertyId,                             // 30013
-    UIA_ClickablePointPropertyId,                       // 30014
-    UIA_CulturePropertyId,                              // 30015
-    UIA_IsControlElementPropertyId,                     // 30016
-    UIA_IsContentElementPropertyId,                     // 30017
-    UIA_LabeledByPropertyId,                            // 30018
-    UIA_IsPasswordPropertyId,                           // 30019
+    UIA_ControlTypePropertyId,           // 30003
+    UIA_LocalizedControlTypePropertyId,  // 30004
+    UIA_NamePropertyId,                  // 30005
+    UIA_AcceleratorKeyPropertyId,        // 30006
+    UIA_AccessKeyPropertyId,             // 30007
+    UIA_HasKeyboardFocusPropertyId,      // 30008
+    UIA_IsKeyboardFocusablePropertyId,   // 30009
+    UIA_IsEnabledPropertyId,             // 30010
+    UIA_AutomationIdPropertyId,          // 30011
+    UIA_ClassNamePropertyId,             // 30012
+    UIA_HelpTextPropertyId,              // 30013
+    UIA_ClickablePointPropertyId,        // 30014
+    UIA_CulturePropertyId,               // 30015
+    UIA_IsControlElementPropertyId,      // 30016
+    UIA_IsContentElementPropertyId,      // 30017
+    UIA_LabeledByPropertyId,             // 30018
+    UIA_IsPasswordPropertyId,            // 30019
     // UIA_NativeWindowHandlePropertyId                 // 30020
-    UIA_ItemTypePropertyId,                             // 30021
-    UIA_IsOffscreenPropertyId,                          // 30022
-    UIA_OrientationPropertyId,                          // 30023
-    UIA_FrameworkIdPropertyId,                          // 30024
-    UIA_IsRequiredForFormPropertyId,                    // 30025
-    UIA_ItemStatusPropertyId,                           // 30026
-    UIA_IsDockPatternAvailablePropertyId,               // 30027
-    UIA_IsExpandCollapsePatternAvailablePropertyId,     // 30028
-    UIA_IsGridItemPatternAvailablePropertyId,           // 30029
-    UIA_IsGridPatternAvailablePropertyId,               // 30030
-    UIA_IsInvokePatternAvailablePropertyId,             // 30031
-    UIA_IsMultipleViewPatternAvailablePropertyId,       // 30032
-    UIA_IsRangeValuePatternAvailablePropertyId,         // 30033
-    UIA_IsScrollPatternAvailablePropertyId,             // 30034
-    UIA_IsScrollItemPatternAvailablePropertyId,         // 30035
-    UIA_IsSelectionItemPatternAvailablePropertyId,      // 30036
-    UIA_IsSelectionPatternAvailablePropertyId,          // 30037
-    UIA_IsTablePatternAvailablePropertyId,              // 30038
-    UIA_IsTableItemPatternAvailablePropertyId,          // 30039
-    UIA_IsTextPatternAvailablePropertyId,               // 30040
-    UIA_IsTogglePatternAvailablePropertyId,             // 30041
-    UIA_IsTransformPatternAvailablePropertyId,          // 30042
-    UIA_IsValuePatternAvailablePropertyId,              // 30043
-    UIA_IsWindowPatternAvailablePropertyId,             // 30044
+    UIA_ItemTypePropertyId,                          // 30021
+    UIA_IsOffscreenPropertyId,                       // 30022
+    UIA_OrientationPropertyId,                       // 30023
+    UIA_FrameworkIdPropertyId,                       // 30024
+    UIA_IsRequiredForFormPropertyId,                 // 30025
+    UIA_ItemStatusPropertyId,                        // 30026
+    UIA_IsDockPatternAvailablePropertyId,            // 30027
+    UIA_IsExpandCollapsePatternAvailablePropertyId,  // 30028
+    UIA_IsGridItemPatternAvailablePropertyId,        // 30029
+    UIA_IsGridPatternAvailablePropertyId,            // 30030
+    UIA_IsInvokePatternAvailablePropertyId,          // 30031
+    UIA_IsMultipleViewPatternAvailablePropertyId,    // 30032
+    UIA_IsRangeValuePatternAvailablePropertyId,      // 30033
+    UIA_IsScrollPatternAvailablePropertyId,          // 30034
+    UIA_IsScrollItemPatternAvailablePropertyId,      // 30035
+    UIA_IsSelectionItemPatternAvailablePropertyId,   // 30036
+    UIA_IsSelectionPatternAvailablePropertyId,       // 30037
+    UIA_IsTablePatternAvailablePropertyId,           // 30038
+    UIA_IsTableItemPatternAvailablePropertyId,       // 30039
+    UIA_IsTextPatternAvailablePropertyId,            // 30040
+    UIA_IsTogglePatternAvailablePropertyId,          // 30041
+    UIA_IsTransformPatternAvailablePropertyId,       // 30042
+    UIA_IsValuePatternAvailablePropertyId,           // 30043
+    UIA_IsWindowPatternAvailablePropertyId,          // 30044
     // UIA_Value*                                       // 30045-30046
     // UIA_RangeValue*                                  // 30047-30052
     // UIA_Scroll*                                      // 30053-30058
@@ -277,12 +272,12 @@
     // UIA_TransformCanRotatePropertyId,                // 30089
     UIA_IsLegacyIAccessiblePatternAvailablePropertyId,  // 30090
     // UIA_LegacyIAccessible*                           // 30091-30100
-    UIA_AriaRolePropertyId,                             // 30101
-    UIA_AriaPropertiesPropertyId,                       // 30102
-    UIA_IsDataValidForFormPropertyId,                   // 30103
-    UIA_ControllerForPropertyId,                        // 30104
-    UIA_DescribedByPropertyId,                          // 30105
-    UIA_FlowsToPropertyId,                              // 30106
+    UIA_AriaRolePropertyId,            // 30101
+    UIA_AriaPropertiesPropertyId,      // 30102
+    UIA_IsDataValidForFormPropertyId,  // 30103
+    UIA_ControllerForPropertyId,       // 30104
+    UIA_DescribedByPropertyId,         // 30105
+    UIA_FlowsToPropertyId,             // 30106
     // UIA_ProviderDescriptionPropertyId                // 30107
     UIA_IsItemContainerPatternAvailablePropertyId,      // 30108
     UIA_IsVirtualizedItemPatternAvailablePropertyId,    // 30109
@@ -352,7 +347,7 @@
     UIA_HeadingLevelPropertyId,                         // 30173
 };
 
-const long AccessibilityTreeFormatterUia::patterns_[] = {
+const long AXTreeFormatterUia::patterns_[] = {
     UIA_SelectionPatternId,       // 10001
     UIA_ValuePatternId,           // 10002
     UIA_RangeValuePatternId,      // 10003
@@ -367,7 +362,7 @@
     UIA_AnnotationPatternId,      // 10023
 };
 
-const long AccessibilityTreeFormatterUia::pattern_properties_[] = {
+const long AXTreeFormatterUia::pattern_properties_[] = {
     UIA_ValueValuePropertyId,                         // 30045
     UIA_ValueIsReadOnlyPropertyId,                    // 30046
     UIA_RangeValueValuePropertyId,                    // 30047
@@ -399,7 +394,7 @@
     UIA_ToggleToggleStatePropertyId,                  // 30086
 };
 
-AccessibilityTreeFormatterUia::AccessibilityTreeFormatterUia() {
+AXTreeFormatterUia::AXTreeFormatterUia() {
   // Create an instance of the CUIAutomation class.
   CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER,
                    IID_IUIAutomation, &uia_);
@@ -408,9 +403,9 @@
   BuildCustomPropertiesMap();
 }
 
-AccessibilityTreeFormatterUia::~AccessibilityTreeFormatterUia() {}
+AXTreeFormatterUia::~AXTreeFormatterUia() {}
 
-void AccessibilityTreeFormatterUia::AddDefaultFilters(
+void AXTreeFormatterUia::AddDefaultFilters(
     std::vector<AXPropertyFilter>* property_filters) {
   // Too noisy: IsKeyboardFocusable, IsDataValidForForm, UIA_ScrollPatternId,
   //  Value.IsReadOnly
@@ -468,7 +463,7 @@
           "=*");
 }
 
-base::Value::Dict AccessibilityTreeFormatterUia::BuildTree(
+base::Value::Dict AXTreeFormatterUia::BuildTree(
     ui::AXPlatformNodeDelegate* start) const {
   Microsoft::WRL::ComPtr<IUIAutomationElement> start_element;
   GetUIAElementFromDelegate(start, uia_.Get(), &start_element);
@@ -505,7 +500,7 @@
   return tree;
 }
 
-base::Value::Dict AccessibilityTreeFormatterUia::BuildTreeForSelector(
+base::Value::Dict AXTreeFormatterUia::BuildTreeForSelector(
     const AXTreeSelector& selector) const {
   HWND hwnd = GetHWNDBySelector(selector);
 
@@ -524,7 +519,7 @@
   return tree;
 }
 
-base::Value::Dict AccessibilityTreeFormatterUia::BuildNode(
+base::Value::Dict AXTreeFormatterUia::BuildNode(
     ui::AXPlatformNodeDelegate* node) const {
   Microsoft::WRL::ComPtr<IUIAutomationElement> uia_element;
   GetUIAElementFromDelegate(node, uia_.Get(), &uia_element);
@@ -541,11 +536,10 @@
   return tree;
 }
 
-void AccessibilityTreeFormatterUia::RecursiveBuildTree(
-    IUIAutomationElement* uncached_node,
-    int root_x,
-    int root_y,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::RecursiveBuildTree(IUIAutomationElement* uncached_node,
+                                            int root_x,
+                                            int root_y,
+                                            base::Value::Dict* dict) const {
   // Process this node.
   AddProperties(uncached_node, root_x, root_y, dict);
 
@@ -573,11 +567,10 @@
   dict->Set(kChildrenDictAttr, std::move(child_list));
 }
 
-void AccessibilityTreeFormatterUia::AddProperties(
-    IUIAutomationElement* uncached_node,
-    int root_x,
-    int root_y,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddProperties(IUIAutomationElement* uncached_node,
+                                       int root_x,
+                                       int root_y,
+                                       base::Value::Dict* dict) const {
   // Update the cache for this node's information.
   Microsoft::WRL::ComPtr<IUIAutomationElement> node;
   uncached_node->BuildUpdatedCache(element_cache_request_.Get(), &node);
@@ -606,7 +599,7 @@
   AddCustomProperties(node.Get(), dict);
 }
 
-void AccessibilityTreeFormatterUia::AddAnnotationProperties(
+void AXTreeFormatterUia::AddAnnotationProperties(
     IUIAutomationElement* node,
     base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationAnnotationPattern> annotation_pattern;
@@ -645,7 +638,7 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddExpandCollapseProperties(
+void AXTreeFormatterUia::AddExpandCollapseProperties(
     IUIAutomationElement* node,
     base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationExpandCollapsePattern>
@@ -677,9 +670,8 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddGridProperties(
-    IUIAutomationElement* node,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddGridProperties(IUIAutomationElement* node,
+                                           base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationGridPattern> grid_pattern;
   if (SUCCEEDED(node->GetCachedPatternAs(UIA_GridPatternId,
                                          IID_PPV_ARGS(&grid_pattern))) &&
@@ -695,9 +687,8 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddGridItemProperties(
-    IUIAutomationElement* node,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddGridItemProperties(IUIAutomationElement* node,
+                                               base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationGridItemPattern> grid_item_pattern;
   if (SUCCEEDED(node->GetCachedPatternAs(UIA_GridItemPatternId,
                                          IID_PPV_ARGS(&grid_item_pattern))) &&
@@ -727,7 +718,7 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddRangeValueProperties(
+void AXTreeFormatterUia::AddRangeValueProperties(
     IUIAutomationElement* node,
     base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationRangeValuePattern> range_value_pattern;
@@ -761,9 +752,8 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddScrollProperties(
-    IUIAutomationElement* node,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddScrollProperties(IUIAutomationElement* node,
+                                             base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationScrollPattern> scroll_pattern;
   if (SUCCEEDED(node->GetCachedPatternAs(UIA_ScrollPatternId,
                                          IID_PPV_ARGS(&scroll_pattern))) &&
@@ -808,9 +798,8 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddSelectionProperties(
-    IUIAutomationElement* node,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddSelectionProperties(IUIAutomationElement* node,
+                                                base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationSelectionPattern> selection_pattern;
   if (SUCCEEDED(node->GetCachedPatternAs(UIA_SelectionPatternId,
                                          IID_PPV_ARGS(&selection_pattern))) &&
@@ -830,7 +819,7 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddSelectionItemProperties(
+void AXTreeFormatterUia::AddSelectionItemProperties(
     IUIAutomationElement* node,
     base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationSelectionItemPattern>
@@ -851,9 +840,8 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddTableProperties(
-    IUIAutomationElement* node,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddTableProperties(IUIAutomationElement* node,
+                                            base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationTablePattern> table_pattern;
   if (SUCCEEDED(node->GetCachedPatternAs(UIA_TablePatternId,
                                          IID_PPV_ARGS(&table_pattern))) &&
@@ -878,9 +866,8 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddToggleProperties(
-    IUIAutomationElement* node,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddToggleProperties(IUIAutomationElement* node,
+                                             base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationTogglePattern> toggle_pattern;
   if (SUCCEEDED(node->GetCachedPatternAs(UIA_TogglePatternId,
                                          IID_PPV_ARGS(&toggle_pattern))) &&
@@ -904,9 +891,8 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddValueProperties(
-    IUIAutomationElement* node,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddValueProperties(IUIAutomationElement* node,
+                                            base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationValuePattern> value_pattern;
   if (SUCCEEDED(node->GetCachedPatternAs(UIA_ValuePatternId,
                                          IID_PPV_ARGS(&value_pattern))) &&
@@ -922,9 +908,8 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::AddWindowProperties(
-    IUIAutomationElement* node,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddWindowProperties(IUIAutomationElement* node,
+                                             base::Value::Dict* dict) const {
   Microsoft::WRL::ComPtr<IUIAutomationWindowPattern> window_pattern;
   if (SUCCEEDED(node->GetCachedPatternAs(UIA_WindowPatternId,
                                          IID_PPV_ARGS(&window_pattern))) &&
@@ -936,15 +921,14 @@
   }
 }
 
-std::map<long, std::string>&
-AccessibilityTreeFormatterUia::GetCustomPropertiesMap() const {
+std::map<long, std::string>& AXTreeFormatterUia::GetCustomPropertiesMap()
+    const {
   static base::NoDestructor<std::map<long, std::string>> custom_properties_map;
   return *custom_properties_map;
 }
 
-void AccessibilityTreeFormatterUia::AddCustomProperties(
-    IUIAutomationElement* node,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::AddCustomProperties(IUIAutomationElement* node,
+                                             base::Value::Dict* dict) const {
   // Custom properties need to be added separately.
   for (const auto& property : GetCustomPropertiesMap()) {
     base::win::ScopedVariant variant;
@@ -955,8 +939,7 @@
   }
 }
 
-std::string AccessibilityTreeFormatterUia::GetPropertyName(
-    long property_id) const {
+std::string AXTreeFormatterUia::GetPropertyName(long property_id) const {
   // We cannot infer the property name from a custom property id, so we get it
   // from the map we created manually in `BuildCustomPropertiesMap()`.
   auto property = GetCustomPropertiesMap().find(property_id);
@@ -966,12 +949,11 @@
   return UiaIdentifierToCondensedString(property_id);
 }
 
-void AccessibilityTreeFormatterUia::WriteProperty(
-    long propertyId,
-    const base::win::ScopedVariant& var,
-    base::Value::Dict* dict,
-    int root_x,
-    int root_y) const {
+void AXTreeFormatterUia::WriteProperty(long propertyId,
+                                       const base::win::ScopedVariant& var,
+                                       base::Value::Dict* dict,
+                                       int root_x,
+                                       int root_y) const {
   switch (var.type()) {
     case VT_EMPTY:
     case VT_NULL:
@@ -1024,10 +1006,9 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::WriteI4Property(
-    long propertyId,
-    long lval,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::WriteI4Property(long propertyId,
+                                         long lval,
+                                         base::Value::Dict* dict) const {
   switch (propertyId) {
     case UIA_ControlTypePropertyId:
       dict->SetByDottedPath(GetPropertyName(propertyId),
@@ -1048,10 +1029,9 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::WriteUnknownProperty(
-    long propertyId,
-    IUnknown* unk,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::WriteUnknownProperty(long propertyId,
+                                              IUnknown* unk,
+                                              base::Value::Dict* dict) const {
   switch (propertyId) {
     case UIA_ControllerForPropertyId:
     case UIA_DescribedByPropertyId:
@@ -1075,12 +1055,11 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::WriteRectangleProperty(
-    long propertyId,
-    const VARIANT& value,
-    int root_x,
-    int root_y,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::WriteRectangleProperty(long propertyId,
+                                                const VARIANT& value,
+                                                int root_x,
+                                                int root_y,
+                                                base::Value::Dict* dict) const {
   CHECK(value.vt == (VT_ARRAY | VT_R8));
 
   double* data = nullptr;
@@ -1096,10 +1075,9 @@
   SafeArrayUnaccessData(value.parray);
 }
 
-void AccessibilityTreeFormatterUia::WriteElementArray(
-    long propertyId,
-    IUIAutomationElementArray* array,
-    base::Value::Dict* dict) const {
+void AXTreeFormatterUia::WriteElementArray(long propertyId,
+                                           IUIAutomationElementArray* array,
+                                           base::Value::Dict* dict) const {
   int count;
   array->get_Length(&count);
   std::u16string element_list;
@@ -1123,7 +1101,7 @@
   }
 }
 
-std::u16string AccessibilityTreeFormatterUia::GetNodeName(
+std::u16string AXTreeFormatterUia::GetNodeName(
     IUIAutomationElement* uncached_node) const {
   // Update the cache for this node.
   if (uncached_node) {
@@ -1142,7 +1120,7 @@
   return std::u16string();
 }
 
-void AccessibilityTreeFormatterUia::BuildCacheRequests() {
+void AXTreeFormatterUia::BuildCacheRequests() {
   // Create cache request for requesting children of a node.
   uia_->CreateCacheRequest(&children_cache_request_);
   CHECK(children_cache_request_.Get());
@@ -1177,13 +1155,13 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::BuildCustomPropertiesMap() {
+void AXTreeFormatterUia::BuildCustomPropertiesMap() {
   GetCustomPropertiesMap().insert(
       {ui::UiaRegistrarWin::GetInstance().GetVirtualContentPropertyId(),
        "VirtualContent"});
 }
 
-std::string AccessibilityTreeFormatterUia::ProcessTreeForOutput(
+std::string AXTreeFormatterUia::ProcessTreeForOutput(
     const base::Value::Dict& dict) const {
   std::string line;
 
@@ -1243,7 +1221,7 @@
   return line;
 }
 
-void AccessibilityTreeFormatterUia::ProcessPropertyForOutput(
+void AXTreeFormatterUia::ProcessPropertyForOutput(
     const std::string& property_name,
     const base::Value::Dict& dict,
     std::string& line) const {
@@ -1253,10 +1231,9 @@
   }
 }
 
-void AccessibilityTreeFormatterUia::ProcessValueForOutput(
-    const std::string& name,
-    const base::Value& value,
-    std::string& line) const {
+void AXTreeFormatterUia::ProcessValueForOutput(const std::string& name,
+                                               const base::Value& value,
+                                               std::string& line) const {
   switch (value.type()) {
     case base::Value::Type::STRING: {
       WriteAttribute(false,
@@ -1299,4 +1276,4 @@
   }
 }
 
-}  // namespace content
+}  // namespace ui
diff --git a/content/browser/accessibility/accessibility_tree_formatter_uia_win.h b/ui/accessibility/platform/inspect/ax_tree_formatter_uia_win.h
similarity index 90%
rename from content/browser/accessibility/accessibility_tree_formatter_uia_win.h
rename to ui/accessibility/platform/inspect/ax_tree_formatter_uia_win.h
index 72f7d3a..a5f8f0a 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_uia_win.h
+++ b/ui/accessibility/platform/inspect/ax_tree_formatter_uia_win.h
@@ -1,8 +1,8 @@
 // Copyright 2019 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-#ifndef CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_TREE_FORMATTER_UIA_WIN_H_
-#define CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_TREE_FORMATTER_UIA_WIN_H_
+#ifndef UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_TREE_FORMATTER_UIA_WIN_H_
+#define UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_TREE_FORMATTER_UIA_WIN_H_
 
 #include "ui/accessibility/platform/inspect/ax_tree_formatter_base.h"
 
@@ -16,13 +16,14 @@
 #include <vector>
 
 #include "base/win/scoped_variant.h"
+#include "ui/accessibility/ax_export.h"
 
-namespace content {
+namespace ui {
 
-class AccessibilityTreeFormatterUia : public ui::AXTreeFormatterBase {
+class AX_EXPORT AXTreeFormatterUia : public ui::AXTreeFormatterBase {
  public:
-  AccessibilityTreeFormatterUia();
-  ~AccessibilityTreeFormatterUia() override;
+  AXTreeFormatterUia();
+  ~AXTreeFormatterUia() override;
 
   // AccessibilityTreeFormatterBase:
   base::Value::Dict BuildTree(ui::AXPlatformNodeDelegate* start) const override;
@@ -111,6 +112,6 @@
   Microsoft::WRL::ComPtr<IUIAutomationCacheRequest> children_cache_request_;
 };
 
-}  // namespace content
+}  // namespace ui
 
-#endif  // CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_TREE_FORMATTER_UIA_WIN_H_
+#endif  // UI_ACCESSIBILITY_PLATFORM_INSPECT_AX_TREE_FORMATTER_UIA_WIN_H_
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc
index b67723c..2dab699 100644
--- a/ui/android/view_android.cc
+++ b/ui/android/view_android.cc
@@ -4,7 +4,6 @@
 
 #include "ui/android/view_android.h"
 
-#include <algorithm>
 #include <cmath>
 #include <utility>
 
@@ -12,6 +11,7 @@
 #include "base/android/jni_string.h"
 #include "base/containers/adapters.h"
 #include "base/containers/contains.h"
+#include "base/ranges/algorithm.h"
 #include "cc/layers/layer.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -208,7 +208,7 @@
 
 void ViewAndroid::MoveToFront(ViewAndroid* child) {
   DCHECK(child);
-  auto it = std::find(children_.begin(), children_.end(), child);
+  auto it = base::ranges::find(children_, child);
   DCHECK(it != children_.end());
 
   // Top element is placed at the end of the list.
@@ -218,7 +218,7 @@
 
 void ViewAndroid::MoveToBack(ViewAndroid* child) {
   DCHECK(child);
-  auto it = std::find(children_.begin(), children_.end(), child);
+  auto it = base::ranges::find(children_, child);
   DCHECK(it != children_.end());
 
   // Bottom element is placed at the beginning of the list.
@@ -313,8 +313,7 @@
 
   if (GetWindowAndroid())
     child->OnDetachedFromWindow();
-  std::list<ViewAndroid*>::iterator it =
-      std::find(children_.begin(), children_.end(), child);
+  std::list<ViewAndroid*>::iterator it = base::ranges::find(children_, child);
   DCHECK(it != children_.end());
   children_.erase(it);
   child->parent_ = nullptr;
diff --git a/ui/aura/test/test_windows.cc b/ui/aura/test/test_windows.cc
index 864f8ae..f13aa39 100644
--- a/ui/aura/test/test_windows.cc
+++ b/ui/aura/test/test_windows.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
@@ -65,10 +66,8 @@
   DCHECK_EQ(upper->parent(), lower->parent());
   DCHECK_NE(upper, lower);
   const std::vector<T*>& children = upper->parent()->children();
-  const size_t upper_i =
-      std::find(children.begin(), children.end(), upper) - children.begin();
-  const size_t lower_i =
-      std::find(children.begin(), children.end(), lower) - children.begin();
+  const size_t upper_i = base::ranges::find(children, upper) - children.begin();
+  const size_t lower_i = base::ranges::find(children, lower) - children.begin();
   return upper_i > lower_i;
 }
 
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index c41d5cd..024c2db5 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 
-#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
@@ -18,6 +17,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/observer_list.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -1046,7 +1046,7 @@
   if (child->OwnsLayer())
     layer()->Remove(child->layer());
   child->parent_ = nullptr;
-  auto i = std::find(children_.begin(), children_.end(), child);
+  auto i = base::ranges::find(children_, child);
   DCHECK(i != children_.end());
   children_.erase(i);
   child->OnParentChanged();
@@ -1079,9 +1079,9 @@
     return;
 
   const size_t child_i =
-      std::find(children_.begin(), children_.end(), child) - children_.begin();
+      base::ranges::find(children_, child) - children_.begin();
   const size_t target_i =
-      std::find(children_.begin(), children_.end(), target) - children_.begin();
+      base::ranges::find(children_, target) - children_.begin();
 
   DCHECK_LT(child_i, children_.size()) << "Child was not in list of children!";
   DCHECK_LT(target_i, children_.size())
diff --git a/ui/aura/window_tracker.cc b/ui/aura/window_tracker.cc
index 7629261..934f3c876 100644
--- a/ui/aura/window_tracker.cc
+++ b/ui/aura/window_tracker.cc
@@ -5,6 +5,7 @@
 #include "ui/aura/window_tracker.h"
 
 #include "base/containers/contains.h"
+#include "base/ranges/algorithm.h"
 #include "ui/aura/window.h"
 
 namespace aura {
@@ -35,7 +36,7 @@
 }
 
 void WindowTracker::Remove(Window* window) {
-  auto iter = std::find(windows_.begin(), windows_.end(), window);
+  auto iter = base::ranges::find(windows_, window);
   if (iter != windows_.end()) {
     window->RemoveObserver(this);
     windows_.erase(iter);
diff --git a/ui/base/cocoa/touch_bar_util.h b/ui/base/cocoa/touch_bar_util.h
index a76182b..a352cdd8 100644
--- a/ui/base/cocoa/touch_bar_util.h
+++ b/ui/base/cocoa/touch_bar_util.h
@@ -12,25 +12,6 @@
 
 namespace ui {
 
-// The touch bar actions that are being recorded in a histogram. These values
-// should not be re-ordered or removed.
-enum TouchBarAction {
-  BACK = 0,
-  FORWARD,
-  STOP,
-  RELOAD,
-  HOME,
-  SEARCH,
-  STAR,
-  NEW_TAB,
-  CREDIT_CARD_AUTOFILL,
-  TEXT_SUGGESTION,
-  TOUCH_BAR_ACTION_COUNT
-};
-
-// Logs the sample's UMA metrics into the DefaultTouchBar.Metrics histogram.
-COMPONENT_EXPORT(UI_BASE) void LogTouchBarUMA(TouchBarAction command);
-
 // Creates a touch bar identifier with the given |id|.
 COMPONENT_EXPORT(UI_BASE) NSString* GetTouchBarId(NSString* touch_bar_id);
 
diff --git a/ui/base/cocoa/touch_bar_util.mm b/ui/base/cocoa/touch_bar_util.mm
index 568ea3a6..6e29829 100644
--- a/ui/base/cocoa/touch_bar_util.mm
+++ b/ui/base/cocoa/touch_bar_util.mm
@@ -5,16 +5,10 @@
 #import "ui/base/cocoa/touch_bar_util.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
 
 namespace ui {
 
-void LogTouchBarUMA(TouchBarAction command) {
-  UMA_HISTOGRAM_ENUMERATION("TouchBar.Default.Metrics", command,
-                            TOUCH_BAR_ACTION_COUNT);
-}
-
 NSString* GetTouchBarId(NSString* touch_bar_id) {
   NSString* chrome_bundle_id =
       base::SysUTF8ToNSString(base::mac::BaseBundleID());
diff --git a/ui/base/ime/ash/ime_bridge.cc b/ui/base/ime/ash/ime_bridge.cc
index 40eea2f..b2bbfa3 100644
--- a/ui/base/ime/ash/ime_bridge.cc
+++ b/ui/base/ime/ash/ime_bridge.cc
@@ -13,7 +13,7 @@
                              ui::TEXT_INPUT_MODE_DEFAULT,
                              0,
                              ui::TextInputClient::FOCUS_REASON_NONE,
-                             false /* should_do_learning */) {}
+                             PersonalizationMode::kDisabled) {}
 
 IMEBridge::~IMEBridge() = default;
 
diff --git a/ui/base/ime/ash/input_method_ash.cc b/ui/base/ime/ash/input_method_ash.cc
index 04224cf..0a6a03a 100644
--- a/ui/base/ime/ash/input_method_ash.cc
+++ b/ui/base/ime/ash/input_method_ash.cc
@@ -205,7 +205,7 @@
   if (engine) {
     ui::TextInputMethod::InputContext context(
         GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
-        GetClientFocusReason(), GetClientShouldDoLearning());
+        GetClientFocusReason(), GetClientPersonalizationMode());
     // When focused input client is not changed, a text input type change
     // should cause blur/focus events to engine. The focus in to or out from
     // password field should also notify engine.
@@ -366,7 +366,7 @@
   if (GetEngine()) {
     ui::TextInputMethod::InputContext context(
         GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
-        GetClientFocusReason(), GetClientShouldDoLearning());
+        GetClientFocusReason(), GetClientPersonalizationMode());
     GetEngine()->FocusIn(context);
   }
 
@@ -572,7 +572,7 @@
 
   ui::TextInputMethod::InputContext context(
       GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
-      GetClientFocusReason(), GetClientShouldDoLearning());
+      GetClientFocusReason(), GetClientPersonalizationMode());
   ui::IMEBridge::Get()->SetCurrentInputContext(context);
 }
 
@@ -855,9 +855,10 @@
   return client ? client->CanComposeInline() : true;
 }
 
-bool InputMethodAsh::GetClientShouldDoLearning() const {
+PersonalizationMode InputMethodAsh::GetClientPersonalizationMode() const {
   TextInputClient* client = GetTextInputClient();
-  return client && client->ShouldDoLearning();
+  return client && client->ShouldDoLearning() ? PersonalizationMode::kEnabled
+                                              : PersonalizationMode::kDisabled;
 }
 
 int InputMethodAsh::GetTextInputFlags() const {
diff --git a/ui/base/ime/ash/input_method_ash.h b/ui/base/ime/ash/input_method_ash.h
index c401f3cc..88252f1 100644
--- a/ui/base/ime/ash/input_method_ash.h
+++ b/ui/base/ime/ash/input_method_ash.h
@@ -14,6 +14,7 @@
 #include "base/callback_forward.h"
 #include "base/component_export.h"
 #include "base/memory/weak_ptr.h"
+#include "ui/base/ime/ash/text_input_method.h"
 #include "ui/base/ime/ash/text_input_target.h"
 #include "ui/base/ime/ash/typing_session_manager.h"
 #include "ui/base/ime/character_composer.h"
@@ -176,7 +177,7 @@
 
   // Check whether text entered into the focused text input client should be
   // used to improve typing suggestions for the user.
-  bool GetClientShouldDoLearning() const;
+  PersonalizationMode GetClientPersonalizationMode() const;
 
   // Gets the text input flags of the focused text input client. Returns
   // 0 if there is no focused client.
diff --git a/ui/base/ime/ash/mock_ime_engine_handler.cc b/ui/base/ime/ash/mock_ime_engine_handler.cc
index ce408f7f..a5d34aa 100644
--- a/ui/base/ime/ash/mock_ime_engine_handler.cc
+++ b/ui/base/ime/ash/mock_ime_engine_handler.cc
@@ -17,7 +17,7 @@
                                ui::TEXT_INPUT_MODE_DEFAULT,
                                ui::TEXT_INPUT_FLAG_NONE,
                                ui::TextInputClient::FOCUS_REASON_NONE,
-                               false /* should_do_learning */),
+                               ui::PersonalizationMode::kDisabled),
       last_set_surrounding_cursor_pos_(0),
       last_set_surrounding_anchor_pos_(0) {}
 
diff --git a/ui/base/ime/ash/text_input_method.h b/ui/base/ime/ash/text_input_method.h
index 695b50c..8cb0fa2 100644
--- a/ui/base/ime/ash/text_input_method.h
+++ b/ui/base/ime/ash/text_input_method.h
@@ -37,6 +37,18 @@
 };
 }  // namespace ime
 
+enum class PersonalizationMode {
+  // The input method MUST not use anything from the input field to update any
+  // personalized data (e.g. to improve suggestions quality). Personalization
+  // could be disabled if the content is privacy-sensitive (e.g. incognito mode
+  // in
+  // Chrome browser), or if using personalization does not make sense (e.g.
+  // playing a typing game may pollute the dictionary with uncommon words).
+  kDisabled,
+  // The input method MAY use the input field contents for personalization.
+  kEnabled
+};
+
 // An interface representing an input method that can read and manipulate text
 // in a TextInputTarget. For example, this can represent a Japanese input method
 // that can compose and insert Japanese characters into a TextInputTarget.
@@ -53,12 +65,12 @@
                  TextInputMode mode,
                  int flags,
                  TextInputClient::FocusReason focus_reason,
-                 bool should_do_learning)
+                 PersonalizationMode personalization_mode)
         : type(type),
           mode(mode),
           flags(flags),
           focus_reason(focus_reason),
-          should_do_learning(should_do_learning) {}
+          personalization_mode(personalization_mode) {}
     TextInputType type;
     TextInputMode mode;
     // Flags for web input fields. Please refer to WebTextInputType.
@@ -67,7 +79,7 @@
     TextInputClient::FocusReason focus_reason;
     // Whether text entered in this field should be used to improve typing
     // suggestions for the user.
-    bool should_do_learning;
+    PersonalizationMode personalization_mode;
   };
 
   virtual ~TextInputMethod() = default;
diff --git a/ui/base/metadata/metadata_unittest.cc b/ui/base/metadata/metadata_unittest.cc
index a3c0848e..90a9f40 100644
--- a/ui/base/metadata/metadata_unittest.cc
+++ b/ui/base/metadata/metadata_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback_list.h"
+#include "base/containers/contains.h"
 #include "base/strings/string_number_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -205,8 +206,7 @@
   UM::ClassMetaData* test_class_meta = MetadataTestClass::MetaData();
 
   const auto& cache_meta = cache->GetCachedTypes();
-  EXPECT_NE(std::find(cache_meta.begin(), cache_meta.end(), test_class_meta),
-            cache_meta.end());
+  EXPECT_TRUE(base::Contains(cache_meta, test_class_meta));
 }
 
 TEST_F(MetadataTest, TestMetaDataFile) {
diff --git a/ui/base/models/dialog_model.cc b/ui/base/models/dialog_model.cc
index 5fb9c16..aa4ff03 100644
--- a/ui/base/models/dialog_model.cc
+++ b/ui/base/models/dialog_model.cc
@@ -9,6 +9,7 @@
 #include "base/ranges/algorithm.h"
 #include "ui/base/interaction/element_identifier.h"
 #include "ui/base/models/dialog_model_field.h"
+#include "ui/base/ui_base_types.h"
 
 namespace ui {
 
@@ -78,6 +79,26 @@
   return *this;
 }
 
+DialogModel::Builder& DialogModel::Builder::OverrideDefaultButton(
+    DialogButton button) {
+  // This can only be called once.
+  DCHECK(!model_->override_default_button_);
+  // Confirm the button exists.
+  switch (button) {
+    case DIALOG_BUTTON_NONE:
+      NOTREACHED();
+      break;
+    case DIALOG_BUTTON_OK:
+      DCHECK(model_->ok_button_);
+      break;
+    case DIALOG_BUTTON_CANCEL:
+      DCHECK(model_->cancel_button_);
+      break;
+  }
+  model_->override_default_button_ = button;
+  return *this;
+}
+
 DialogModel::Builder& DialogModel::Builder::SetInitiallyFocusedField(
     ElementIdentifier id) {
   // This must be called with a non-null id
diff --git a/ui/base/models/dialog_model.h b/ui/base/models/dialog_model.h
index 26707ac..c8f0375 100644
--- a/ui/base/models/dialog_model.h
+++ b/ui/base/models/dialog_model.h
@@ -283,6 +283,10 @@
       return *this;
     }
 
+    // Overrides default button. Can only be called once. The new default button
+    // must exist.
+    Builder& OverrideDefaultButton(DialogButton button);
+
     // Sets which field should be initially focused in the dialog model. Must be
     // called after that field has been added. Can only be called once.
     Builder& SetInitiallyFocusedField(ElementIdentifier id);
@@ -407,6 +411,11 @@
     return dark_mode_banner_;
   }
 
+  const absl::optional<DialogButton>& override_default_button(
+      base::PassKey<DialogModelHost>) const {
+    return override_default_button_;
+  }
+
   ElementIdentifier initially_focused_field(
       base::PassKey<DialogModelHost>) const {
     return initially_focused_field_;
@@ -468,6 +477,7 @@
   ImageModel banner_;
   ImageModel dark_mode_banner_;
 
+  absl::optional<DialogButton> override_default_button_;
   std::vector<std::unique_ptr<DialogModelField>> fields_;
   ElementIdentifier initially_focused_field_;
   bool is_alert_dialog_ = false;
diff --git a/ui/base/win/hwnd_subclass.cc b/ui/base/win/hwnd_subclass.cc
index 2dd8817b..956f874 100644
--- a/ui/base/win/hwnd_subclass.cc
+++ b/ui/base/win/hwnd_subclass.cc
@@ -4,12 +4,11 @@
 
 #include "ui/base/win/hwnd_subclass.h"
 
-#include <algorithm>
-
 #include "base/check.h"
 #include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/singleton.h"
+#include "base/ranges/algorithm.h"
 #include "ui/base/win/touch_input.h"
 #include "ui/gfx/win/hwnd_util.h"
 
@@ -102,7 +101,7 @@
 
 void HWNDSubclass::RemoveFilter(HWNDMessageFilter* filter) {
   std::vector<HWNDMessageFilter*>::iterator it =
-      std::find(filters_.begin(), filters_.end(), filter);
+      base::ranges::find(filters_, filter);
   if (it != filters_.end())
     filters_.erase(it);
 }
diff --git a/ui/base/x/selection_requestor.cc b/ui/base/x/selection_requestor.cc
index 820f833..b7f050f 100644
--- a/ui/base/x/selection_requestor.cc
+++ b/ui/base/x/selection_requestor.cc
@@ -4,9 +4,8 @@
 
 #include "ui/base/x/selection_requestor.h"
 
-#include <algorithm>
-
 #include "base/memory/ref_counted_memory.h"
+#include "base/ranges/algorithm.h"
 #include "ui/base/x/selection_owner.h"
 #include "ui/base/x/selection_utils.h"
 #include "ui/base/x/x11_clipboard_helper.h"
@@ -62,7 +61,7 @@
     ConvertSelectionForCurrentRequest();
   BlockTillSelectionNotifyForRequest(&request);
 
-  auto request_it = std::find(requests_.begin(), requests_.end(), &request);
+  auto request_it = base::ranges::find(requests_, &request);
   CHECK(request_it != requests_.end());
   if (static_cast<int>(current_request_index_) >
       request_it - requests_.begin()) {
diff --git a/ui/base/x/x11_gl_egl_utility.cc b/ui/base/x/x11_gl_egl_utility.cc
index 99f7c30..27fee028 100644
--- a/ui/base/x/x11_gl_egl_utility.cc
+++ b/ui/base/x/x11_gl_egl_utility.cc
@@ -4,6 +4,7 @@
 
 #include "ui/base/x/x11_gl_egl_utility.h"
 
+#include "base/containers/contains.h"
 #include "ui/base/x/x11_util.h"
 #include "ui/gl/gl_surface_egl.h"
 
@@ -42,9 +43,8 @@
   // 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())) {
+      !base::Contains(*attributes,
+                      EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE)) {
     x11::VisualId visual_id;
     XVisualManager::GetInstance()->ChooseVisualForWindow(
         true, &visual_id, nullptr, nullptr, nullptr);
diff --git a/ui/compositor/total_animation_throughput_reporter.cc b/ui/compositor/total_animation_throughput_reporter.cc
index 53f0608..ffd295b 100644
--- a/ui/compositor/total_animation_throughput_reporter.cc
+++ b/ui/compositor/total_animation_throughput_reporter.cc
@@ -10,6 +10,19 @@
 
 namespace ui {
 
+TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker::
+    ScopedThroughputReporterBlocker(
+        base::WeakPtr<TotalAnimationThroughputReporter> reporter)
+    : reporter_(std::move(reporter)) {
+  reporter_->scoped_blocker_count_++;
+}
+
+TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker::
+    ~ScopedThroughputReporterBlocker() {
+  if (reporter_)
+    reporter_->scoped_blocker_count_--;
+}
+
 TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
     ui::Compositor* compositor,
     ReportOnceCallback once_callback,
@@ -45,6 +58,9 @@
 
 void TotalAnimationThroughputReporter::OnFirstNonAnimatedFrameStarted(
     ui::Compositor* compositor) {
+  if (IsBlocked())
+    return;
+
   throughput_tracker_->Stop();
   throughput_tracker_.reset();
   // Stop observing if no need to report multiple times.
@@ -64,6 +80,19 @@
     delete this;
 }
 
+base::WeakPtr<ui::TotalAnimationThroughputReporter>
+TotalAnimationThroughputReporter::GetWeakPtr() {
+  return ptr_factory_.GetWeakPtr();
+}
+
+std::unique_ptr<
+    TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker>
+TotalAnimationThroughputReporter::NewScopedBlocker() {
+  return std::make_unique<
+      ui::TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker>(
+      ptr_factory_.GetWeakPtr());
+}
+
 TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
     ui::Compositor* compositor,
     ReportRepeatingCallback repeating_callback,
@@ -94,4 +123,8 @@
     report_repeating_callback_.Run(data);
 }
 
+bool TotalAnimationThroughputReporter::IsBlocked() const {
+  return scoped_blocker_count_;
+}
+
 }  // namespace ui
diff --git a/ui/compositor/total_animation_throughput_reporter.h b/ui/compositor/total_animation_throughput_reporter.h
index bddc5e4..866676e 100644
--- a/ui/compositor/total_animation_throughput_reporter.h
+++ b/ui/compositor/total_animation_throughput_reporter.h
@@ -14,6 +14,10 @@
 #include "ui/compositor/compositor_observer.h"
 #include "ui/compositor/throughput_tracker.h"
 
+namespace ash {
+class LoginUnlockThroughputRecorderTestBase;
+}
+
 namespace ui {
 
 // Reports cc::FrameSequenceMetrics::ThroughputData between the first animation
@@ -32,9 +36,31 @@
 // report callback is invoked on the next begin frame if there is enough data.
 // Since this observes multiple animations, aborting one of animations will
 // not cancel the tracking, and the data will be reported as normal.
+//
+// The reporter will not fire if ScopedThroughputReporterBlocker is active.
+// This allows to measure throughput from the very first animation (when
+// reporter was created) till the specific expected animation ends even if
+// there were delays between the animations.
 class COMPOSITOR_EXPORT TotalAnimationThroughputReporter
     : public CompositorObserver {
  public:
+  // This allows to temporarily ignore OnFirstNonAnimatedFrameStarted event
+  // until an interesting event happens.
+  class COMPOSITOR_EXPORT ScopedThroughputReporterBlocker {
+   public:
+    explicit ScopedThroughputReporterBlocker(
+        base::WeakPtr<TotalAnimationThroughputReporter> reporter);
+    ScopedThroughputReporterBlocker(const ScopedThroughputReporterBlocker&) =
+        delete;
+    ~ScopedThroughputReporterBlocker();
+
+    ScopedThroughputReporterBlocker& operator=(
+        const ScopedThroughputReporterBlocker&) = delete;
+
+   private:
+    base::WeakPtr<TotalAnimationThroughputReporter> reporter_;
+  };
+
   using ReportOnceCallback = base::OnceCallback<void(
       const cc::FrameSequenceMetrics::CustomReportData& data)>;
   using ReportRepeatingCallback = base::RepeatingCallback<void(
@@ -64,9 +90,18 @@
   void OnFirstNonAnimatedFrameStarted(Compositor* compositor) override;
   void OnCompositingShuttingDown(Compositor* compositor) override;
 
+  base::WeakPtr<ui::TotalAnimationThroughputReporter> GetWeakPtr();
+
   bool IsMeasuringForTesting() const { return bool{throughput_tracker_}; }
 
+  // The returned scope will delay the animation report until the next
+  // |OnFirstNonAnimatedFrameStarted| received after it is destructed. See
+  // |ScopedThroughputReporterBlocker| above.
+  std::unique_ptr<ScopedThroughputReporterBlocker> NewScopedBlocker();
+
  private:
+  friend class ash::LoginUnlockThroughputRecorderTestBase;
+
   TotalAnimationThroughputReporter(Compositor* compositor,
                                    ReportRepeatingCallback repeating_callback,
                                    ReportOnceCallback once_callback,
@@ -74,12 +109,18 @@
 
   void Report(const cc::FrameSequenceMetrics::CustomReportData& data);
 
+  // Returns true if there is an active ScopedThroughputReporterBlocker.
+  bool IsBlocked() const;
+
   raw_ptr<Compositor> compositor_;
   ReportRepeatingCallback report_repeating_callback_;
   ReportOnceCallback report_once_callback_;
   bool should_delete_ = false;
   absl::optional<ThroughputTracker> throughput_tracker_;
 
+  // Number of active ScopedThroughputReporterBlocker objects.
+  int scoped_blocker_count_ = 0;
+
   base::WeakPtrFactory<TotalAnimationThroughputReporter> ptr_factory_{this};
 };
 
diff --git a/ui/compositor/total_animation_throughput_reporter_unittest.cc b/ui/compositor/total_animation_throughput_reporter_unittest.cc
index 7f8d369..b4c02dc 100644
--- a/ui/compositor/total_animation_throughput_reporter_unittest.cc
+++ b/ui/compositor/total_animation_throughput_reporter_unittest.cc
@@ -48,6 +48,58 @@
   layer.SetOpacity(opacity);
 }
 
+class TestCompositorMonitor : public ui::CompositorObserver {
+ public:
+  explicit TestCompositorMonitor(ui::Compositor* compositor)
+      : compositor_(compositor) {
+    compositor->AddObserver(this);
+  }
+
+  ~TestCompositorMonitor() override { compositor_->RemoveObserver(this); }
+
+  // ui::CompositorObserver
+  void OnFirstAnimationStarted(Compositor* compositor) override {
+    animatins_running_ = true;
+  }
+
+  void OnFirstNonAnimatedFrameStarted(Compositor* compositor) override {
+    DCHECK_EQ(compositor_, compositor);
+    if (animatins_running_) {
+      waiting_for_did_present_compositor_frame_ = true;
+    }
+    animatins_running_ = false;
+  }
+
+  void OnDidPresentCompositorFrame(
+      uint32_t frame_token,
+      const gfx::PresentationFeedback& feedback) override {
+    if (waiting_for_did_present_compositor_frame_) {
+      waiting_for_did_present_compositor_frame_ = false;
+      if (animatins_running_)
+        return;
+
+      if (run_loop_)
+        run_loop_->Quit();
+    }
+  }
+
+  void WaitForAllAnimationsEnd() {
+    if (!animatins_running_ && !waiting_for_did_present_compositor_frame_)
+      return;
+
+    run_loop_ = std::make_unique<base::RunLoop>(
+        base::RunLoop::Type::kNestableTasksAllowed);
+    run_loop_->Run();
+    run_loop_.reset();
+  }
+
+ private:
+  const base::raw_ptr<ui::Compositor> compositor_;
+  bool animatins_running_ = false;
+  bool waiting_for_did_present_compositor_frame_ = false;
+  std::unique_ptr<base::RunLoop> run_loop_;
+};
+
 }  // namespace
 
 using TotalAnimationThroughputReporterTest =
@@ -61,7 +113,21 @@
   ThroughputReportChecker checker(this);
   TotalAnimationThroughputReporter reporter(compositor(),
                                             checker.repeating_callback());
+  auto scoped_blocker = reporter.NewScopedBlocker();
   SetLayerOpacity(layer, 1.0f, base::Milliseconds(48));
+  Advance(base::Milliseconds(200));
+
+  // No report should happen while scoped_blocker exists.
+  EXPECT_FALSE(checker.reported());
+
+  scoped_blocker.reset();
+  // No animation should be running yet, nothing to report.
+  EXPECT_FALSE(checker.reported());
+  Advance(base::Milliseconds(200));
+  EXPECT_FALSE(checker.reported());
+
+  // Animation of opacity goes to 0.5.
+  SetLayerOpacity(layer, 0.5f, base::Milliseconds(48));
   Advance(base::Milliseconds(32));
   EXPECT_FALSE(checker.reported());
   EXPECT_TRUE(checker.WaitUntilReported());
@@ -126,7 +192,6 @@
   ThroughputReportChecker checker(this);
   TotalAnimationThroughputReporter reporter(compositor(),
                                             checker.repeating_callback());
-
   SetLayerOpacity(layer, 1.0f, base::Milliseconds(48));
   {
     LayerAnimator* animator = layer.GetAnimator();
@@ -289,6 +354,7 @@
 
 // Make sure the once reporter is called only once.
 TEST_F(TotalAnimationThroughputReporterTest, OnceReporter) {
+  TestCompositorMonitor compositor_monitor(compositor());
   Layer layer;
   layer.SetOpacity(0.5f);
   root_layer()->Add(&layer);
@@ -300,6 +366,7 @@
   ThroughputReportChecker checker(this);
   TotalAnimationThroughputReporter reporter(
       compositor(), checker.once_callback(), /*should_delete=*/false);
+  auto scoped_blocker = reporter.NewScopedBlocker();
 
   // Make sure the TotalAnimationThroughputReporter removes itself
   // from compositor as observer.
@@ -307,6 +374,22 @@
 
   // Report data for animation of opacity goes to 1.
   SetLayerOpacity(layer, 1.0f, base::Milliseconds(48));
+  Advance(base::Milliseconds(100));
+
+  // No report should happen while scoped_blocker exists.
+  EXPECT_FALSE(checker.reported());
+
+  // Make sure there are no animations running.
+  compositor_monitor.WaitForAllAnimationsEnd();
+
+  scoped_blocker.reset();
+  // No animation should be running yet, nothing to report.
+  EXPECT_FALSE(checker.reported());
+  Advance(base::Milliseconds(100));
+  EXPECT_FALSE(checker.reported());
+
+  // Animation of opacity goes to 0.5.
+  SetLayerOpacity(layer, 0.7f, base::Milliseconds(48));
   EXPECT_TRUE(checker.WaitUntilReported());
 
   // Report data for animation of opacity goes to 0.5.
@@ -334,6 +417,7 @@
     raw_ptr<bool> deleted_;
   };
 
+  TestCompositorMonitor compositor_monitor(compositor());
   Layer layer;
   layer.SetOpacity(0.5f);
   root_layer()->Add(&layer);
@@ -346,21 +430,40 @@
   base::RunLoop run_loop;
 
   bool deleted = false;
-  new DeleteTestReporter(
+  TotalAnimationThroughputReporter* reporter = new DeleteTestReporter(
       compositor(),
       base::BindLambdaForTesting(
           [&](const cc::FrameSequenceMetrics::CustomReportData&) {
             run_loop.Quit();
           }),
       &deleted);
+  auto scoped_blocker = reporter->NewScopedBlocker();
 
   // Report data for animation of opacity goes to 1.
   SetLayerOpacity(layer, 1.0f, base::Milliseconds(48));
-  run_loop.Run();
+  Advance(base::Milliseconds(100));
+
+  // No report should happen while scoped_blocker exists.
+  EXPECT_FALSE(deleted);
+
+  // Make sure there are no animations running.
+  compositor_monitor.WaitForAllAnimationsEnd();
+
+  scoped_blocker.reset();
+  // No animation should be running yet, nothing to report.
+  EXPECT_FALSE(deleted);
+  Advance(base::Milliseconds(100));
+  EXPECT_FALSE(deleted);
+
+  // Animation of opacity goes to 0.5.
+  layer.SetOpacity(0.7f);
+  EXPECT_FALSE(deleted);
+  Advance(base::Milliseconds(100));
   EXPECT_TRUE(deleted);
 }
 
 TEST_F(TotalAnimationThroughputReporterTest, ThreadCheck) {
+  TestCompositorMonitor compositor_monitor(compositor());
   Layer layer;
   layer.SetOpacity(0.5f);
   root_layer()->Add(&layer);
@@ -383,9 +486,26 @@
 
   TotalAnimationThroughputReporter reporter(c, std::move(callback),
                                             /*should_delete=*/false);
+  auto scoped_blocker = reporter.NewScopedBlocker();
 
   // Report data for animation of opacity goes to 1.
   layer.SetOpacity(1.0f);
+  Advance(base::Milliseconds(100));
+
+  // No report should happen while scoped_blocker exists.
+  EXPECT_FALSE(checker.reported());
+
+  // Make sure there are no animations running.
+  compositor_monitor.WaitForAllAnimationsEnd();
+
+  scoped_blocker.reset();
+  // No animation should be running yet, nothing to report.
+  EXPECT_FALSE(checker.reported());
+  Advance(base::Milliseconds(100));
+  EXPECT_FALSE(checker.reported());
+
+  // Animation of opacity goes to 0.5.
+  layer.SetOpacity(0.7f);
   EXPECT_TRUE(checker.WaitUntilReported());
 }
 
diff --git a/ui/display/mac/test/virtual_display_mac_util.h b/ui/display/mac/test/virtual_display_mac_util.h
index 5df35c8..40d0692 100644
--- a/ui/display/mac/test/virtual_display_mac_util.h
+++ b/ui/display/mac/test/virtual_display_mac_util.h
@@ -20,7 +20,7 @@
 struct DisplayParams;
 
 // This interface creates system-level virtual displays to support the automated
-// integration testing of display information and window placement APIs in
+// integration testing of display information and window management APIs in
 // multi-screen device environments. It updates the displays that the normal mac
 // screen impl sees, but not `TestScreenMac`.
 class VirtualDisplayMacUtil : public display::DisplayObserver {
diff --git a/ui/display/manager/touch_transform_controller.cc b/ui/display/manager/touch_transform_controller.cc
index ada1b9c9..d140f430 100644
--- a/ui/display/manager/touch_transform_controller.cc
+++ b/ui/display/manager/touch_transform_controller.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "base/ranges/algorithm.h"
 #include "ui/display/display_layout.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/manager/managed_display_info.h"
@@ -344,10 +345,10 @@
   }
 
   if (display_manager_->IsInMirrorMode()) {
-    std::size_t primary_display_id_index =
-        std::distance(display_id_list.begin(),
-                      std::find(display_id_list.begin(), display_id_list.end(),
-                                Screen::GetScreen()->GetPrimaryDisplay().id()));
+    std::size_t primary_display_id_index = std::distance(
+        display_id_list.begin(),
+        base::ranges::find(display_id_list,
+                           Screen::GetScreen()->GetPrimaryDisplay().id()));
 
     for (std::size_t index = 0; index < display_id_list.size(); index++) {
       // In extended but software mirroring mode, there is a WindowTreeHost
diff --git a/ui/events/devices/x11/device_data_manager_x11.cc b/ui/events/devices/x11/device_data_manager_x11.cc
index 64d7a7e..9d03ccb72 100644
--- a/ui/events/devices/x11/device_data_manager_x11.cc
+++ b/ui/events/devices/x11/device_data_manager_x11.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <algorithm>
 #include <utility>
 
 #include "base/at_exit.h"
diff --git a/ui/events/event_dispatcher.cc b/ui/events/event_dispatcher.cc
index bf46914a..21bedb2 100644
--- a/ui/events/event_dispatcher.cc
+++ b/ui/events/event_dispatcher.cc
@@ -4,8 +4,7 @@
 
 #include "ui/events/event_dispatcher.h"
 
-#include <algorithm>
-
+#include "base/ranges/algorithm.h"
 #include "ui/events/event_target.h"
 #include "ui/events/event_targeter.h"
 
@@ -106,9 +105,7 @@
 }
 
 void EventDispatcher::OnHandlerDestroyed(EventHandler* handler) {
-  handler_list_.erase(std::find(handler_list_.begin(),
-                                handler_list_.end(),
-                                handler));
+  handler_list_.erase(base::ranges::find(handler_list_, handler));
 }
 
 void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
diff --git a/ui/events/event_target.cc b/ui/events/event_target.cc
index dd62b4c2..67990c1 100644
--- a/ui/events/event_target.cc
+++ b/ui/events/event_target.cc
@@ -4,10 +4,9 @@
 
 #include "ui/events/event_target.h"
 
-#include <algorithm>
-
 #include "base/check.h"
 #include "base/notreached.h"
+#include "base/ranges/algorithm.h"
 #include "ui/events/event.h"
 #include "ui/gfx/geometry/point_conversions.h"
 
@@ -64,8 +63,7 @@
 }
 
 void EventTarget::RemovePostTargetHandler(EventHandler* handler) {
-  auto find =
-      std::find(post_target_list_.begin(), post_target_list_.end(), handler);
+  auto find = base::ranges::find(post_target_list_, handler);
   if (find != post_target_list_.end())
     post_target_list_.erase(find);
 }
diff --git a/ui/events/gestures/gesture_recognizer_impl.cc b/ui/events/gestures/gesture_recognizer_impl.cc
index 2e3a1aef..a40968b 100644
--- a/ui/events/gestures/gesture_recognizer_impl.cc
+++ b/ui/events/gestures/gesture_recognizer_impl.cc
@@ -13,6 +13,7 @@
 #include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
+#include "base/ranges/algorithm.h"
 #include "base/time/time.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
@@ -380,7 +381,7 @@
 
 void GestureRecognizerImpl::RemoveGestureEventHelper(
     GestureEventHelper* helper) {
-  auto it = std::find(helpers_.begin(), helpers_.end(), helper);
+  auto it = base::ranges::find(helpers_, helper);
   if (it != helpers_.end())
     helpers_.erase(it);
 }
diff --git a/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc b/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc
index 60b8eaa..5c164c9 100644
--- a/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc
+++ b/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc
@@ -12,6 +12,7 @@
 #include "base/check_op.h"
 #include "base/containers/flat_map.h"
 #include "base/logging.h"
+#include "base/ranges/algorithm.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/dom_key.h"
 #include "ui/events/keycodes/dom/dom_keyboard_layout_map_base.h"
@@ -67,8 +68,8 @@
   // the order of the layouts in the control panel so we use GetKeyboardLayout
   // to retrieve the current layout and swap (if needed) to ensure it is always
   // evaluated first.
-  auto iter = std::find(keyboard_layout_handles_.begin(),
-                        keyboard_layout_handles_.end(), GetKeyboardLayout(0));
+  auto iter =
+      base::ranges::find(keyboard_layout_handles_, GetKeyboardLayout(0));
   if (iter != keyboard_layout_handles_.begin() &&
       iter != keyboard_layout_handles_.end())
     std::iter_swap(keyboard_layout_handles_.begin(), iter);
diff --git a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc
index 936ef72..24f99336 100644
--- a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc
+++ b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc
@@ -105,8 +105,8 @@
 
 TEST_F(PalmDetectionFilterFactoryTest, HeuristicEnabledForEve) {
   scoped_feature_list_->InitWithFeaturesAndParameters(
-      {base::test::ScopedFeatureList::FeatureAndParams(
-          ui::kEnableHeuristicPalmDetectionFilter, {})},
+      {base::test::FeatureRefAndParams(ui::kEnableHeuristicPalmDetectionFilter,
+                                       {})},
       {ui::kEnableNeuralPalmDetectionFilter});
   std::unique_ptr<PalmDetectionFilter> palm_filter =
       CreatePalmDetectionFilter(eve_touchscreen_info_, &shared_palm_state_);
@@ -131,7 +131,7 @@
 
 TEST_F(PalmDetectionFilterFactoryTest, HeuristicTimesSet) {
   scoped_feature_list_->InitWithFeaturesAndParameters(
-      {base::test::ScopedFeatureList::FeatureAndParams(
+      {base::test::FeatureRefAndParams(
           ui::kEnableHeuristicPalmDetectionFilter,
           {{"heuristic_palm_cancel_threshold_seconds", "0.8"},
            {"heuristic_palm_hold_threshold_seconds", "15.327"}})},
@@ -178,10 +178,10 @@
 
 TEST_F(PalmDetectionFilterFactoryTest, NeuralBeatsHeuristic) {
   scoped_feature_list_->InitWithFeaturesAndParameters(
-      {base::test::ScopedFeatureList::FeatureAndParams(
-           ui::kEnableHeuristicPalmDetectionFilter, {}),
-       base::test::ScopedFeatureList::FeatureAndParams(
-           ui::kEnableNeuralPalmDetectionFilter, {})},
+      {base::test::FeatureRefAndParams(ui::kEnableHeuristicPalmDetectionFilter,
+                                       {}),
+       base::test::FeatureRefAndParams(ui::kEnableNeuralPalmDetectionFilter,
+                                       {})},
       {});
   std::unique_ptr<PalmDetectionFilter> palm_filter = CreatePalmDetectionFilter(
       nocturne_touchscreen_info_, &shared_palm_state_);
@@ -205,7 +205,7 @@
 
 TEST_F(PalmDetectionFilterFactoryDeathTest, BadNeuralParamParse) {
   scoped_feature_list_->InitWithFeaturesAndParameters(
-      {base::test::ScopedFeatureList::FeatureAndParams(
+      {base::test::FeatureRefAndParams(
           ui::kEnableNeuralPalmDetectionFilter,
           {
               {"neural_palm_radius_polynomial", "1.0,chicken"},
diff --git a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
index bd803891..ad27927 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -194,9 +194,9 @@
     ":menu_button",
     ":menu_item",
     ":position_util",
+    "//ash/webui/common/resources:event_tracker",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:cr.m",
-    "//ui/webui/resources/js:event_tracker",
     "//ui/webui/resources/js/cr:event_target",
     "//ui/webui/resources/js/cr:ui",
   ]
@@ -687,9 +687,9 @@
     ":menu",
     ":menu_item",
     ":position_util",
+    "//ash/webui/common/resources:event_tracker",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:cr.m",
-    "//ui/webui/resources/js:event_tracker",
     "//ui/webui/resources/js/cr:ui",
   ]
 }
@@ -717,8 +717,8 @@
   deps = [
     ":menu",
     ":menu_item",
+    "//ash/webui/common/resources:event_tracker",
     "//ui/webui/resources/js:assert",
-    "//ui/webui/resources/js:event_tracker",
     "//ui/webui/resources/js/cr:ui",
   ]
 }
@@ -730,9 +730,9 @@
     ":menu_item",
     ":multi_menu",
     ":position_util",
+    "//ash/webui/common/resources:event_tracker",
     "//ui/file_manager/file_manager/common/js:util",
     "//ui/webui/resources/js:assert",
-    "//ui/webui/resources/js:event_tracker",
     "//ui/webui/resources/js/cr:ui",
   ]
 }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/context_menu_handler.js b/ui/file_manager/file_manager/foreground/js/ui/context_menu_handler.js
index 3ab4b3c..9e5a6702 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/context_menu_handler.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/context_menu_handler.js
@@ -5,7 +5,7 @@
 // clang-format off
 import {assertInstanceof} from 'chrome://resources/js/assert.js';
 import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.js';
+import {EventTracker} from 'chrome://resources/ash/common/event_tracker.js';
 import {isWindows, isLinux, isMac, isLacros, dispatchPropertyChange} from 'chrome://resources/js/cr.m.js';
 import {decorate} from 'chrome://resources/js/cr/ui.js';
 import {Menu} from './menu.js';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/menu_button.js b/ui/file_manager/file_manager/foreground/js/ui/menu_button.js
index e41cdfc..3e0b336 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/menu_button.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/menu_button.js
@@ -4,7 +4,7 @@
 
 import {assert} from 'chrome://resources/js/assert.js';
 import {isWindows} from 'chrome://resources/js/cr.m.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.js';
+import {EventTracker} from 'chrome://resources/ash/common/event_tracker.js';
 import {define as crUiDefine, decorate} from 'chrome://resources/js/cr/ui.js';
 import {positionPopupAroundElement, AnchorType} from './position_util.js';
 import {Menu} from './menu.js';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js b/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js
index 6986868e..157344a4f 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js
@@ -6,7 +6,7 @@
 import {decorate} from 'chrome://resources/js/cr/ui.js';
 import {Menu} from './menu.js';
 import {MenuItem} from './menu_item.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.js';
+import {EventTracker} from 'chrome://resources/ash/common/event_tracker.js';
 
 /**
  * Creates a menu that supports sub-menus.
diff --git a/ui/file_manager/file_manager/foreground/js/ui/multi_menu_button.js b/ui/file_manager/file_manager/foreground/js/ui/multi_menu_button.js
index 25a9595..dd17dad 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/multi_menu_button.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/multi_menu_button.js
@@ -8,7 +8,7 @@
 import {HideType} from './menu_button.js';
 import {MenuItem} from './menu_item.js';
 import {AnchorType, positionPopupAroundElement} from './position_util.js';
-import {EventTracker} from 'chrome://resources/js/event_tracker.js';
+import {EventTracker} from 'chrome://resources/ash/common/event_tracker.js';
 
 import {util} from '../../../common/js/util.js';
 
diff --git a/ui/gfx/font_fallback_unittest.cc b/ui/gfx/font_fallback_unittest.cc
index 35e07f14..62558cc5 100644
--- a/ui/gfx/font_fallback_unittest.cc
+++ b/ui/gfx/font_fallback_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <tuple>
 
+#include "base/containers/contains.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -204,11 +205,8 @@
 
   // Ensure the fallback font is a part of the validation fallback fonts list.
   if (!test_option_.skip_fallback_fonts_validation) {
-    bool valid = std::find(test_case_.fallback_fonts.begin(),
-                           test_case_.fallback_fonts.end(),
-                           fallback_font.GetFontName()) !=
-                 test_case_.fallback_fonts.end();
-    if (!valid) {
+    if (!base::Contains(test_case_.fallback_fonts,
+                        fallback_font.GetFontName())) {
       ADD_FAILURE() << "GetFallbackFont failed for '" << script_name_
                     << "' invalid fallback font: "
                     << fallback_font.GetFontName()
diff --git a/ui/gfx/x/window_cache.cc b/ui/gfx/x/window_cache.cc
index 66fea67..74fd398 100644
--- a/ui/gfx/x/window_cache.cc
+++ b/ui/gfx/x/window_cache.cc
@@ -187,8 +187,8 @@
       if (auto* siblings = GetChildren(info->parent)) {
         Window window = configure->window;
         Window above = configure->above_sibling;
-        auto src = std::find(siblings->begin(), siblings->end(), window);
-        auto dst = std::find(siblings->begin(), siblings->end(), above);
+        auto src = base::ranges::find(*siblings, window);
+        auto dst = base::ranges::find(*siblings, above);
         auto end = siblings->end();
         if (src != end && (dst != end || above == Window::None)) {
           dst = above == Window::None ? siblings->begin() : ++dst;
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index 827a28c..573e4a6 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -8,9 +8,9 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/ranges/algorithm.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-
 #include "third_party/khronos/EGL/egl.h"
 #include "third_party/khronos/EGL/eglext.h"
 #include "ui/gl/egl_util.h"
@@ -103,8 +103,7 @@
 bool ChangeContextAttributes(std::vector<EGLint>& context_attributes,
                              EGLint attribute,
                              EGLint value) {
-  auto iter = std::find(context_attributes.begin(), context_attributes.end(),
-                        attribute);
+  auto iter = base::ranges::find(context_attributes, attribute);
   if (iter != context_attributes.end()) {
     ++iter;
     if (iter != context_attributes.end()) {
diff --git a/ui/gl/gl_image.cc b/ui/gl/gl_image.cc
index 18834f4..956d037d 100644
--- a/ui/gl/gl_image.cc
+++ b/ui/gl/gl_image.cc
@@ -87,10 +87,6 @@
   color_space_ = color_space;
 }
 
-void GLImage::Flush() {
-  NOTREACHED();
-}
-
 void GLImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                            uint64_t process_tracing_id,
                            const std::string& dump_name) {
diff --git a/ui/gl/gl_image.h b/ui/gl/gl_image.h
index c7b3d98..df67822 100644
--- a/ui/gl/gl_image.h
+++ b/ui/gl/gl_image.h
@@ -96,9 +96,6 @@
   virtual void SetColorSpace(const gfx::ColorSpace& color_space);
   const gfx::ColorSpace& color_space() const { return color_space_; }
 
-  // Flush any preceding rendering for the image.
-  virtual void Flush();
-
   // Dumps information about the memory backing the GLImage to a dump named
   // |dump_name|.
   virtual void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
diff --git a/ui/gl/gl_image_ahardwarebuffer.cc b/ui/gl/gl_image_ahardwarebuffer.cc
index d12e5da..64e7fb83 100644
--- a/ui/gl/gl_image_ahardwarebuffer.cc
+++ b/ui/gl/gl_image_ahardwarebuffer.cc
@@ -125,8 +125,6 @@
   return false;
 }
 
-void GLImageAHardwareBuffer::Flush() {}
-
 void GLImageAHardwareBuffer::OnMemoryDump(
     base::trace_event::ProcessMemoryDump* pmd,
     uint64_t process_tracing_id,
diff --git a/ui/gl/gl_image_ahardwarebuffer.h b/ui/gl/gl_image_ahardwarebuffer.h
index 4f07ea9..404811e 100644
--- a/ui/gl/gl_image_ahardwarebuffer.h
+++ b/ui/gl/gl_image_ahardwarebuffer.h
@@ -38,7 +38,6 @@
   bool CopyTexSubImage(unsigned target,
                        const gfx::Point& offset,
                        const gfx::Rect& rect) override;
-  void Flush() override;
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
diff --git a/ui/gl/gl_image_d3d.h b/ui/gl/gl_image_d3d.h
index a688cbc..7077eec 100644
--- a/ui/gl/gl_image_d3d.h
+++ b/ui/gl/gl_image_d3d.h
@@ -58,7 +58,6 @@
   bool CopyTexSubImage(unsigned target,
                        const gfx::Point& offset,
                        const gfx::Rect& rect) override;
-  void Flush() override {}
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
diff --git a/ui/gl/gl_image_dxgi.cc b/ui/gl/gl_image_dxgi.cc
index cfd84920..fc246617 100644
--- a/ui/gl/gl_image_dxgi.cc
+++ b/ui/gl/gl_image_dxgi.cc
@@ -187,8 +187,6 @@
   return false;
 }
 
-void GLImageDXGI::Flush() {}
-
 unsigned GLImageDXGI::GetInternalFormat() {
   if (!handle_.Get())
     return GL_BGRA_EXT;
diff --git a/ui/gl/gl_image_dxgi.h b/ui/gl/gl_image_dxgi.h
index 9d7e327..61118ca 100644
--- a/ui/gl/gl_image_dxgi.h
+++ b/ui/gl/gl_image_dxgi.h
@@ -33,7 +33,6 @@
   bool CopyTexSubImage(unsigned target,
                        const gfx::Point& offset,
                        const gfx::Rect& rect) override;
-  void Flush() override;
   unsigned GetInternalFormat() override;
   unsigned GetDataType() override;
   gfx::Size GetSize() override;
diff --git a/ui/gl/gl_image_egl_pixmap.h b/ui/gl/gl_image_egl_pixmap.h
index 9265fd80..8cf74be 100644
--- a/ui/gl/gl_image_egl_pixmap.h
+++ b/ui/gl/gl_image_egl_pixmap.h
@@ -33,7 +33,6 @@
   BindOrCopy ShouldBindOrCopy() override;
   bool BindTexImage(unsigned target) override;
   void ReleaseTexImage(unsigned target) override;
-  void Flush() override {}
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
diff --git a/ui/gl/gl_image_glx.h b/ui/gl/gl_image_glx.h
index ce43dcbd..12b1d45 100644
--- a/ui/gl/gl_image_glx.h
+++ b/ui/gl/gl_image_glx.h
@@ -34,7 +34,6 @@
   bool CopyTexSubImage(unsigned target,
                        const gfx::Point& offset,
                        const gfx::Rect& rect) override;
-  void Flush() override {}
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
diff --git a/ui/gl/gl_image_io_surface.h b/ui/gl/gl_image_io_surface.h
index 05af4022..c0d5715a 100644
--- a/ui/gl/gl_image_io_surface.h
+++ b/ui/gl/gl_image_io_surface.h
@@ -65,7 +65,6 @@
   bool BindTexImage(unsigned target) override;
   void ReleaseTexImage(unsigned target) override;
   void SetColorSpace(const gfx::ColorSpace& color_space) override;
-  void Flush() override {}
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
diff --git a/ui/gl/gl_image_memory.h b/ui/gl/gl_image_memory.h
index 086f534..88d9da2 100644
--- a/ui/gl/gl_image_memory.h
+++ b/ui/gl/gl_image_memory.h
@@ -45,7 +45,6 @@
   bool CopyTexSubImage(unsigned target,
                        const gfx::Point& offset,
                        const gfx::Rect& rect) override;
-  void Flush() override {}
   Type GetType() const override;
 
   const unsigned char* memory() { return memory_; }
diff --git a/ui/gl/gl_image_native_pixmap.cc b/ui/gl/gl_image_native_pixmap.cc
index e48a7d5..3205565 100644
--- a/ui/gl/gl_image_native_pixmap.cc
+++ b/ui/gl/gl_image_native_pixmap.cc
@@ -131,8 +131,6 @@
     : GLImageEGL(size),
       format_(format),
       plane_(plane),
-      has_image_flush_external_(gl::GLSurfaceEGL::GetGLDisplayEGL()
-                                    ->ext->b_EGL_EXT_image_flush_external),
       has_image_dma_buf_export_(gl::GLSurfaceEGL::GetGLDisplayEGL()
                                     ->ext->b_EGL_MESA_image_dma_buf_export) {}
 
@@ -392,22 +390,6 @@
   return false;
 }
 
-void GLImageNativePixmap::Flush() {
-  if (!has_image_flush_external_)
-    return;
-
-  EGLDisplay display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
-  const EGLAttrib attribs[] = {
-      EGL_NONE,
-  };
-  if (!eglImageFlushExternalEXT(display, egl_image_, attribs)) {
-    // TODO(reveman): Investigate why we're hitting the following log
-    // statement on ARM devices. b/63364517
-    DLOG(WARNING) << "Failed to flush rendering";
-    return;
-  }
-}
-
 void GLImageNativePixmap::OnMemoryDump(
     base::trace_event::ProcessMemoryDump* pmd,
     uint64_t process_tracing_id,
diff --git a/ui/gl/gl_image_native_pixmap.h b/ui/gl/gl_image_native_pixmap.h
index ea5c8832..c4f9b3cd 100644
--- a/ui/gl/gl_image_native_pixmap.h
+++ b/ui/gl/gl_image_native_pixmap.h
@@ -37,7 +37,6 @@
   bool CopyTexSubImage(unsigned target,
                        const gfx::Point& offset,
                        const gfx::Rect& rect) override;
-  void Flush() override;
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
@@ -50,7 +49,6 @@
   gfx::BufferFormat format_;
   scoped_refptr<gfx::NativePixmap> pixmap_;
   gfx::BufferPlane plane_;
-  bool has_image_flush_external_;
   bool has_image_dma_buf_export_;
   bool did_initialize_;
 };
diff --git a/ui/gl/gl_image_stub.h b/ui/gl/gl_image_stub.h
index 31e9bcf9..3037b94 100644
--- a/ui/gl/gl_image_stub.h
+++ b/ui/gl/gl_image_stub.h
@@ -28,7 +28,6 @@
   bool CopyTexSubImage(unsigned target,
                        const gfx::Point& offset,
                        const gfx::Rect& rect) override;
-  void Flush() override {}
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override {}
diff --git a/ui/gl/gl_surface_overlay.cc b/ui/gl/gl_surface_overlay.cc
index 1c8beff2..2917cea 100644
--- a/ui/gl/gl_surface_overlay.cc
+++ b/ui/gl/gl_surface_overlay.cc
@@ -33,8 +33,4 @@
                                       std::move(acquire_fences), {});
 }
 
-void GLSurfaceOverlay::Flush() const {
-  return image_->Flush();
-}
-
 }  // namespace gl
diff --git a/ui/gl/gl_surface_overlay.h b/ui/gl/gl_surface_overlay.h
index 8c7bd5e0..73306908 100644
--- a/ui/gl/gl_surface_overlay.h
+++ b/ui/gl/gl_surface_overlay.h
@@ -33,8 +33,6 @@
   // This should be called at most once.
   bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget);
 
-  void Flush() const;
-
   gfx::GpuFence* gpu_fence() const { return gpu_fence_.get(); }
   int z_order() const { return overlay_plane_data_.z_order; }
 
diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc
index e138cca..7e6381a5 100644
--- a/ui/gl/gl_switches.cc
+++ b/ui/gl/gl_switches.cc
@@ -233,7 +233,7 @@
 // that DWM power optimization can be turned on.
 BASE_FEATURE(kDirectCompositionLetterboxVideoOptimization,
              "DirectCompositionLetterboxVideoOptimization",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Allow dual GPU rendering through EGL where supported, i.e., allow a WebGL
 // or WebGPU context to be on the high performance GPU if preferred and Chrome
diff --git a/ui/gl/init/gl_factory.cc b/ui/gl/init/gl_factory.cc
index 50f908af..e5c997b 100644
--- a/ui/gl/init/gl_factory.cc
+++ b/ui/gl/init/gl_factory.cc
@@ -4,13 +4,13 @@
 
 #include "ui/gl/init/gl_factory.h"
 
-#include <algorithm>
 #include <string>
 #include <vector>
 
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_util.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -66,9 +66,9 @@
       GetAllowedGLImplementations();
 
   if (cmd->HasSwitch(switches::kDisableES3GLContext)) {
-    auto iter =
-        std::find(allowed_impls.begin(), allowed_impls.end(),
-                  GLImplementationParts(kGLImplementationDesktopGLCoreProfile));
+    auto iter = base::ranges::find(
+        allowed_impls,
+        GLImplementationParts(kGLImplementationDesktopGLCoreProfile));
     if (iter != allowed_impls.end())
       allowed_impls.erase(iter);
   }
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 6a4c212a..9e37b2d6 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -46,8 +46,7 @@
       window_(std::move(window)),
       widget_(widget),
       has_implicit_external_sync_(
-          display->ext->b_EGL_ARM_implicit_external_sync),
-      has_image_flush_external_(display->ext->b_EGL_EXT_image_flush_external) {
+          display->ext->b_EGL_ARM_implicit_external_sync) {
   surface_factory_->RegisterSurface(window_->widget(), this);
   supports_plane_gpu_fences_ = window_->SupportsGpuFences();
   unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
@@ -130,8 +129,7 @@
     return;
   }
 
-  if ((!has_image_flush_external_ && !supports_plane_gpu_fences_) ||
-      requires_gl_flush_on_swap_buffers_) {
+  if (!supports_plane_gpu_fences_ || requires_gl_flush_on_swap_buffers_) {
     glFlush();
   }
 
@@ -139,8 +137,6 @@
   gl::TerminateFrame();  // Notify end of frame at buffer swap request.
 #endif
 
-  unsubmitted_frames_.back()->Flush();
-
   PendingFrame* frame = unsubmitted_frames_.back().get();
   frame->completion_callback = std::move(completion_callback);
   frame->presentation_callback = std::move(presentation_callback);
@@ -243,11 +239,6 @@
   return true;
 }
 
-void GbmSurfaceless::PendingFrame::Flush() {
-  for (const auto& overlay : overlays)
-    overlay.Flush();
-}
-
 void GbmSurfaceless::SubmitFrame() {
   DCHECK(!unsubmitted_frames_.empty());
 
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
index 70bdb11..74102c0 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -91,7 +91,6 @@
     ~PendingFrame();
 
     bool ScheduleOverlayPlanes(gfx::AcceleratedWidget widget);
-    void Flush();
 
     bool ready = false;
     gfx::SwapResult swap_result = gfx::SwapResult::SWAP_FAILED;
@@ -119,7 +118,6 @@
   std::unique_ptr<PendingFrame> submitted_frame_;
   std::unique_ptr<gfx::GpuFence> submitted_frame_gpu_fence_;
   const bool has_implicit_external_sync_;
-  const bool has_image_flush_external_;
   bool last_swap_buffers_result_ = true;
   bool supports_plane_gpu_fences_ = false;
   bool use_egl_fence_sync_ = true;
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
index e0eec15..6c710b0f 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -38,12 +38,6 @@
 #include "ui/ozone/platform/drm/gpu/page_flip_request.h"
 #include "ui/ozone/platform/drm/gpu/page_flip_watchdog.h"
 
-// Vendor ID for downstream, interim ChromeOS specific modifiers.
-#define DRM_FORMAT_MOD_VENDOR_CHROMEOS 0xf0
-// TODO(b/231167263) Remove once DRM_FORMAT_MOD_ARM_AFBC is used by all kernels
-// and allocators.
-#define DRM_FORMAT_MOD_CHROMEOS_ROCKCHIP_AFBC fourcc_mod_code(CHROMEOS, 1)
-
 namespace ui {
 
 namespace {
@@ -82,12 +76,6 @@
 }
 
 bool IsRockchipAfbc(uint64_t modifier) {
-  // TODO(b/231167263): Drop when kernel 4.4 is gone for RK3399.
-  if (modifier == DRM_FORMAT_MOD_CHROMEOS_ROCKCHIP_AFBC) {
-    return true;
-  }
-
-  // Newer (and upstream) kernels use DRM_FORMAT_MOD_ARM_AFBC.
   return modifier ==
          DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
                                  AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR);
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
index 4d8116b..61114668 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
@@ -6,10 +6,12 @@
 
 #include <drm_fourcc.h>
 #include <drm_mode.h>
+
 #include <string>
 
 #include "base/logging.h"
 #include "base/notreached.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_util.h"
 #include "base/trace_event/traced_value.h"
 #include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
@@ -151,8 +153,7 @@
     uint32_t format) const {
   std::vector<uint64_t> modifiers;
 
-  auto it =
-      std::find(supported_formats_.begin(), supported_formats_.end(), format);
+  auto it = base::ranges::find(supported_formats_, format);
   if (it == supported_formats_.end())
     return modifiers;
 
diff --git a/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc b/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc
index 71cdc758..fd93096 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc
@@ -4,7 +4,7 @@
 
 #include "ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h"
 
-#include <algorithm>
+#include "base/containers/contains.h"
 
 // From ANGLE's egl/eglext.h. Follows the same approach as in
 // ui/gl/gl_surface_egl.cc
@@ -31,9 +31,8 @@
 void WaylandGLEGLUtility::GetAdditionalEGLAttributes(
     EGLenum platform_type,
     std::vector<EGLAttrib>* display_attributes) {
-  if (std::find(display_attributes->begin(), display_attributes->end(),
-                EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE) !=
-      display_attributes->end()) {
+  if (base::Contains(*display_attributes,
+                     EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE)) {
     display_attributes->push_back(
         EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE);
     display_attributes->push_back(
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
index 795042f..fef154d 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -77,7 +77,6 @@
   bool displayed() const { return displayed_; }
 
   // Overridden from GLImage:
-  void Flush() override {}
   scoped_refptr<gfx::NativePixmap> GetNativePixmap() override {
     return pixmap_;
   }
diff --git a/ui/ozone/platform/wayland/test/mock_zwp_linux_dmabuf.cc b/ui/ozone/platform/wayland/test/mock_zwp_linux_dmabuf.cc
index ae21b38..c69c711 100644
--- a/ui/ozone/platform/wayland/test/mock_zwp_linux_dmabuf.cc
+++ b/ui/ozone/platform/wayland/test/mock_zwp_linux_dmabuf.cc
@@ -7,6 +7,7 @@
 #include <linux-dmabuf-unstable-v1-server-protocol.h>
 #include <wayland-server-core.h>
 
+#include "base/ranges/algorithm.h"
 #include "ui/ozone/platform/wayland/test/mock_buffer.h"
 #include "ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h"
 
@@ -56,7 +57,7 @@
 
 void MockZwpLinuxDmabufV1::OnBufferParamsDestroyed(
     TestZwpLinuxBufferParamsV1* params) {
-  auto it = std::find(buffer_params_.begin(), buffer_params_.end(), params);
+  auto it = base::ranges::find(buffer_params_, params);
   DCHECK(it != buffer_params_.end());
   buffer_params_.erase(it);
 }
diff --git a/ui/ozone/platform/x11/x11_window.cc b/ui/ozone/platform/x11/x11_window.cc
index 45e0a75a6..199941a3 100644
--- a/ui/ozone/platform/x11/x11_window.cc
+++ b/ui/ozone/platform/x11/x11_window.cc
@@ -7,6 +7,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/no_destructor.h"
 #include "base/notreached.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
@@ -1812,9 +1813,8 @@
   // Unregister from the global security surface list if necessary.
   if (is_security_surface_) {
     auto& security_surfaces = GetSecuritySurfaces();
-    security_surfaces.erase(
-        std::find(security_surfaces.begin(), security_surfaces.end(), xwindow_),
-        security_surfaces.end());
+    security_surfaces.erase(base::ranges::find(security_surfaces, xwindow_),
+                            security_surfaces.end());
   }
 
   connection_->DestroyWindow({xwindow_});
diff --git a/ui/platform_window/BUILD.gn b/ui/platform_window/BUILD.gn
index 39f4cb9..f31f747c 100644
--- a/ui/platform_window/BUILD.gn
+++ b/ui/platform_window/BUILD.gn
@@ -36,7 +36,6 @@
 
     public_deps += [
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.element",
-      "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.policy",
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.views",
       "//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp",
       "//third_party/fuchsia-sdk/sdk/pkg/sys_cpp",
diff --git a/ui/platform_window/fuchsia/initialize_presenter_api_view.cc b/ui/platform_window/fuchsia/initialize_presenter_api_view.cc
index 4f3662e..fe11f9d 100644
--- a/ui/platform_window/fuchsia/initialize_presenter_api_view.cc
+++ b/ui/platform_window/fuchsia/initialize_presenter_api_view.cc
@@ -4,10 +4,10 @@
 //
 #include "ui/platform_window/fuchsia/initialize_presenter_api_view.h"
 
-#include <fuchsia/ui/policy/cpp/fidl.h>
 #include <lib/sys/cpp/component_context.h>
 #include <lib/ui/scenic/cpp/view_ref_pair.h>
 #include <lib/ui/scenic/cpp/view_token_pair.h>
+#include <zircon/rights.h>
 
 #include <utility>
 
@@ -29,6 +29,15 @@
   return *view_presenter;
 }
 
+::fuchsia::ui::views::ViewRef CloneViewRef(
+    const ::fuchsia::ui::views::ViewRef& view_ref) {
+  ::fuchsia::ui::views::ViewRef dup;
+  zx_status_t status =
+      view_ref.reference.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup.reference);
+  ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
+  return dup;
+}
+
 }  // namespace
 
 void InitializeViewTokenAndPresentView(
@@ -45,10 +54,15 @@
   // Request Presenter to show the view full-screen.
   auto presenter = base::ComponentContextForProcess()
                        ->svc()
-                       ->Connect<::fuchsia::ui::policy::Presenter>();
+                       ->Connect<::fuchsia::element::GraphicalPresenter>();
 
-  presenter->PresentOrReplaceView(std::move(view_tokens.view_holder_token),
-                                  nullptr);
+  ::fuchsia::element::ViewSpec view_spec;
+  view_spec.set_view_holder_token(std::move(view_tokens.view_holder_token));
+  view_spec.set_view_ref(
+      CloneViewRef(window_properties_out->view_ref_pair.view_ref));
+  presenter->PresentView(std::move(view_spec), nullptr,
+                         window_properties_out->view_controller.NewRequest(),
+                         [](auto) {});
 }
 
 void SetScenicViewPresenter(ScenicPresentViewCallback view_presenter) {
diff --git a/ui/views/accessibility/ax_aura_obj_cache.cc b/ui/views/accessibility/ax_aura_obj_cache.cc
index 71a4bf59..5ad26b1 100644
--- a/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/string_util.h"
 #include "ui/accessibility/ax_enums.mojom.h"
@@ -291,8 +292,7 @@
     GetFocusClient(window)->AddObserver(this);
 
   // Do not allow duplicate entries.
-  if (std::find(root_windows_.begin(), root_windows_.end(), window) ==
-      root_windows_.end()) {
+  if (!base::Contains(root_windows_, window)) {
     root_windows_.push_back(window);
   }
 }
diff --git a/ui/views/accessibility/ax_window_obj_wrapper.cc b/ui/views/accessibility/ax_window_obj_wrapper.cc
index 6dc426a..191848b 100644
--- a/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -274,19 +274,15 @@
 }
 
 void AXWindowObjWrapper::OnWindowDestroyed(aura::Window* window) {
+  if (is_root_window_)
+    aura_obj_cache_->OnRootWindowObjDestroyed(window_);
+
   aura_obj_cache_->Remove(window, nullptr);
 }
 
 void AXWindowObjWrapper::OnWindowDestroying(aura::Window* window) {
-  if (window == window_)
-    window_destroying_ = true;
-
-  Widget* widget = GetWidgetForWindow(window);
-  if (widget)
-    aura_obj_cache_->Remove(widget);
-
-  if (is_root_window_)
-    aura_obj_cache_->OnRootWindowObjDestroyed(window_);
+  DCHECK_EQ(window, window_);
+  window_destroying_ = true;
 }
 
 void AXWindowObjWrapper::OnWindowHierarchyChanged(
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
index 1dee584c0..ffbd844d 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
@@ -4,13 +4,13 @@
 
 #include "ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h"
 
-#include <algorithm>
 #include <memory>
 #include <vector>
 
 #include "base/containers/contains.h"
 #include "base/memory/raw_ptr.h"
 #include "base/no_destructor.h"
+#include "base/ranges/algorithm.h"
 #include "base/scoped_multi_source_observation.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_enums.mojom.h"
@@ -111,7 +111,7 @@
     if (window && window_observations_.IsObservingSource(window))
       window_observations_.RemoveObservation(window);
 
-    auto iter = std::find(widgets_.begin(), widgets_.end(), widget);
+    auto iter = base::ranges::find(widgets_, widget);
     if (iter != widgets_.end())
       widgets_.erase(iter);
   }
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc
index 94f387d..a5ce0c7a 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
@@ -241,7 +242,7 @@
  private:
   void AddToAnchorVector() {
     auto& vector = GetAnchorVector(anchor_view_);
-    DCHECK(vector.cend() == std::find(vector.cbegin(), vector.cend(), parent_));
+    DCHECK(!base::Contains(vector, parent_));
     vector.push_back(parent_);
   }
 
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc
index 50af229..907ad7640 100644
--- a/ui/views/bubble/bubble_dialog_model_host.cc
+++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -417,6 +417,9 @@
 
   SetButtons(button_mask);
 
+  if (model_->override_default_button(GetPassKey()))
+    SetDefaultButton(model_->override_default_button(GetPassKey()).value());
+
   SetTitle(model_->title(GetPassKey()));
 
   SetSubtitle(model_->subtitle(GetPassKey()));
diff --git a/ui/views/bubble/bubble_dialog_model_host_unittest.cc b/ui/views/bubble/bubble_dialog_model_host_unittest.cc
index 9c0eb60..4b526b9 100644
--- a/ui/views/bubble/bubble_dialog_model_host_unittest.cc
+++ b/ui/views/bubble/bubble_dialog_model_host_unittest.cc
@@ -8,11 +8,14 @@
 #include <utility>
 
 #include "base/callback_helpers.h"
+#include "base/test/gtest_util.h"
 #include "ui/base/interaction/element_identifier.h"
 #include "ui/base/interaction/element_tracker.h"
+#include "ui/views/controls/button/label_button.h"
 #include "ui/views/interaction/element_tracker_views.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/test/widget_test.h"
+#include "ui/views/view_class_properties.h"
 
 namespace views {
 
@@ -115,4 +118,44 @@
   bubble_widget->CloseNow();
 }
 
+TEST_F(BubbleDialogModelHostTest, OverrideDefaultButton) {
+  auto host = std::make_unique<BubbleDialogModelHost>(
+      ui::DialogModel::Builder()
+          .AddCancelButton(base::OnceClosure())
+          .OverrideDefaultButton(ui::DialogButton::DIALOG_BUTTON_CANCEL)
+          .Build(),
+      /*anchor_view=*/nullptr, BubbleBorder::Arrow::TOP_RIGHT);
+  EXPECT_EQ(host->GetDefaultDialogButton(),
+            ui::DialogButton::DIALOG_BUTTON_CANCEL);
+}
+
+TEST_F(BubbleDialogModelHostTest, OverrideDefaultButtonDeathTest) {
+  EXPECT_DCHECK_DEATH(std::make_unique<BubbleDialogModelHost>(
+      ui::DialogModel::Builder()
+          .AddCancelButton(base::OnceClosure())
+          .OverrideDefaultButton(ui::DialogButton::DIALOG_BUTTON_OK)
+          .Build(),
+      /*anchor_view=*/nullptr, BubbleBorder::Arrow::TOP_RIGHT))
+      << "Cannot override the default button with a button which does not "
+         "exist.";
+}
+
+TEST_F(BubbleDialogModelHostTest,
+       SetInitiallyFocusedViewOverridesDefaultButtonFocus) {
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kFocusedField);
+
+  auto host = std::make_unique<BubbleDialogModelHost>(
+      ui::DialogModel::Builder()
+          .AddCancelButton(base::OnceClosure())
+          .OverrideDefaultButton(ui::DialogButton::DIALOG_BUTTON_CANCEL)
+          .AddTextfield(kFocusedField, u"label", u"text")
+          .SetInitiallyFocusedField(kFocusedField)
+          .Build(),
+      /*anchor_view=*/nullptr, BubbleBorder::Arrow::TOP_RIGHT);
+  EXPECT_EQ(host->GetDefaultDialogButton(),
+            ui::DialogButton::DIALOG_BUTTON_CANCEL);
+  EXPECT_EQ(host->GetInitiallyFocusedView()->GetProperty(kElementIdentifierKey),
+            kFocusedField);
+}
+
 }  // namespace views
diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.mm b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
index bde63eb..020c952e 100644
--- a/ui/views/cocoa/native_widget_mac_ns_window_host.mm
+++ b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
@@ -12,6 +12,7 @@
 #include "base/mac/foundation_util.h"
 #include "base/no_destructor.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/time/time.h"
 #include "components/remote_cocoa/app_shim/immersive_mode_controller.h"
@@ -701,8 +702,7 @@
     return;
 
   if (parent_) {
-    auto found =
-        std::find(parent_->children_.begin(), parent_->children_.end(), this);
+    auto found = base::ranges::find(parent_->children_, this);
     DCHECK(found != parent_->children_.end());
     parent_->children_.erase(found);
     parent_ = nullptr;
@@ -806,8 +806,7 @@
                           NativeWidgetMacEventMonitor* monitor) {
     if (!weak_this)
       return;
-    auto found = std::find(weak_this->event_monitors_.begin(),
-                           weak_this->event_monitors_.end(), monitor);
+    auto found = base::ranges::find(weak_this->event_monitors_, monitor);
     CHECK(found != weak_this->event_monitors_.end());
     weak_this->event_monitors_.erase(found);
 
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 59b96ef7..d678b4f4 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -14,6 +14,7 @@
 #include "base/i18n/case_conversion.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/raw_ptr.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -3333,7 +3334,7 @@
   const size_t num_menu_items = menu_items.size();
   if (num_menu_items <= 1)
     return;
-  const auto i = std::find(menu_items.cbegin(), menu_items.cend(), item);
+  const auto i = base::ranges::find(menu_items, item);
   DCHECK(i != menu_items.cend());
   auto index = static_cast<size_t>(std::distance(menu_items.cbegin(), i));
 
diff --git a/ui/views/corewm/tooltip_controller_unittest.cc b/ui/views/corewm/tooltip_controller_unittest.cc
index df01450bf..76a24404 100644
--- a/ui/views/corewm/tooltip_controller_unittest.cc
+++ b/ui/views/corewm/tooltip_controller_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/at_exit.h"
 #include "base/memory/raw_ptr.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "ui/accessibility/ax_enums.mojom.h"
@@ -722,8 +723,7 @@
 
 // Returns the index of |window| in its parent's children.
 int IndexInParent(const aura::Window* window) {
-  auto i = std::find(window->parent()->children().begin(),
-                     window->parent()->children().end(), window);
+  auto i = base::ranges::find(window->parent()->children(), window);
   return i == window->parent()->children().end()
              ? -1
              : static_cast<int>(i - window->parent()->children().begin());
diff --git a/ui/views/examples/examples_window.cc b/ui/views/examples/examples_window.cc
index b391c91..7f9323c 100644
--- a/ui/views/examples/examples_window.cc
+++ b/ui/views/examples/examples_window.cc
@@ -12,6 +12,7 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/containers/cxx20_erase.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
@@ -86,8 +87,7 @@
     // from the list.
     if (!valid_examples.empty()) {
       base::EraseIf(examples, [valid_examples](auto& example) {
-        return std::find(valid_examples.begin(), valid_examples.end(),
-                         example->example_title()) == valid_examples.end();
+        return !base::Contains(valid_examples, example->example_title());
       });
     }
   } else if (command_line->HasSwitch(kEnableExamples)) {
diff --git a/ui/views/focus/focus_manager_unittest.cc b/ui/views/focus/focus_manager_unittest.cc
index c099e3f..7560bb4 100644
--- a/ui/views/focus/focus_manager_unittest.cc
+++ b/ui/views/focus/focus_manager_unittest.cc
@@ -18,7 +18,7 @@
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/accelerators/test_accelerator_target.h"
 #include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/views/accessibility/accessibility_paint_checks.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/accessible_pane_view.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/buildflags.h"
@@ -1146,12 +1146,18 @@
   child->SetFocusBehavior(View::FocusBehavior::ALWAYS);
   bubble_widget->GetRootView()->AddChildView(child);
 
-  // TODO(crbug.com/1218186): Remove this, this is in place temporarily to be
-  // able to submit accessibility checks, but this focusable View needs to
-  // add a name so that the screen reader knows what to announce.
-  parent1->SetProperty(views::kSkipAccessibilityPaintChecks, true);
-  parent2->SetProperty(views::kSkipAccessibilityPaintChecks, true);
-  child->SetProperty(views::kSkipAccessibilityPaintChecks, true);
+  // In order to pass the accessibility paint checks, focusable views must have
+  // a valid role.
+  parent1->GetViewAccessibility().OverrideRole(ax::mojom::Role::kGroup);
+  parent2->GetViewAccessibility().OverrideRole(ax::mojom::Role::kGroup);
+  child->GetViewAccessibility().OverrideRole(ax::mojom::Role::kButton);
+
+  // In order to pass the accessibility paint checks, focusable views must have
+  // a non-empty accessible name, or have their name set to explicitly empty.
+  parent1->GetViewAccessibility().OverrideName(u"Parent 1");
+  parent2->GetViewAccessibility().OverrideName(
+      u"", ax::mojom::NameFrom::kAttributeExplicitlyEmpty);
+  child->GetViewAccessibility().OverrideName("uChild");
 
   widget->Activate();
   parent1->RequestFocus();
diff --git a/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/ui/views/touchui/touch_selection_controller_impl_unittest.cc
index e2dddd49..7774d75 100644
--- a/ui/views/touchui/touch_selection_controller_impl_unittest.cc
+++ b/ui/views/touchui/touch_selection_controller_impl_unittest.cc
@@ -25,7 +25,6 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/render_text.h"
-#include "ui/views/accessibility/accessibility_paint_checks.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_test_api.h"
 #include "ui/views/test/views_test_base.h"
@@ -96,10 +95,12 @@
 
   void CreateTextfield() {
     textfield_ = new Textfield();
-    // TODO(crbug.com/1218186): Remove this, this is in place temporarily to be
-    // able to submit accessibility checks, but this focusable View needs to
-    // add a name so that the screen reader knows what to announce.
-    textfield_->SetProperty(views::kSkipAccessibilityPaintChecks, true);
+
+    // Focusable views must have an accessible name in order to pass the
+    // accessibility paint checks. The name can be literal text, placeholder
+    // text or an associated label.
+    textfield_->SetPlaceholderText(u"Foo");
+
     textfield_widget_ = new Widget;
     Widget::InitParams params =
         CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
diff --git a/ui/views/view.h b/ui/views/view.h
index 32ee6dda..aacd085 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -7,7 +7,6 @@
 
 #include <stddef.h>
 
-#include <algorithm>
 #include <memory>
 #include <set>
 #include <string>
@@ -16,6 +15,7 @@
 
 #include "base/callback.h"
 #include "base/callback_list.h"
+#include "base/containers/contains.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
@@ -449,8 +449,7 @@
     DCHECK(!view->owned_by_client())
         << "This should only be called if the client doesn't already have "
            "ownership of |view|.";
-    DCHECK(std::find(children_.cbegin(), children_.cend(), view) !=
-           children_.cend());
+    DCHECK(base::Contains(children_, view));
     RemoveChildView(view);
     return base::WrapUnique(view);
   }
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
index 83718b3..7dd5897 100644
--- a/ui/views/view_unittest.cc
+++ b/ui/views/view_unittest.cc
@@ -12,11 +12,11 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/raw_ptr.h"
-
-#include "base/containers/contains.h"
 #include "base/rand_util.h"
+#include "base/ranges/algorithm.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -109,7 +109,7 @@
   if (!parent)
     return nullptr;
   const std::vector<ui::Layer*> children = parent->children();
-  const auto i = std::find(children.cbegin(), children.cend(), layer) + 1;
+  const auto i = base::ranges::find(children, layer) + 1;
   return (i == children.cend()) ? parent : FirstLayer(*i);
 }
 
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 8e2d497..f2442cb 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -14,6 +14,7 @@
 #include "base/i18n/rtl.h"
 #include "base/notreached.h"
 #include "base/observer_list.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -1745,8 +1746,8 @@
 
   // Don't descend into |child| if there is a view with a Layer that contains
   // the point and is stacked above |child_layer|.
-  auto child_layer_iter = std::find(root_layer->children().begin(),
-                                    root_layer->children().end(), child_layer);
+  auto child_layer_iter =
+      base::ranges::find(root_layer->children(), child_layer);
   if (child_layer_iter == root_layer->children().end())
     return true;
 
@@ -1757,8 +1758,7 @@
     ui::Layer* layer = view->layer();
     DCHECK(layer);
     if (layer->visible() && layer->bounds().Contains(location)) {
-      auto root_layer_iter = std::find(root_layer->children().begin(),
-                                       root_layer->children().end(), layer);
+      auto root_layer_iter = base::ranges::find(root_layer->children(), layer);
       if (child_layer_iter > root_layer_iter) {
         // |child| is on top of the remaining layers, no need to continue.
         return true;
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc
index ffa5760d..bfc941b 100644
--- a/ui/views/widget/widget_interactive_uitest.cc
+++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -32,7 +32,6 @@
 #include "ui/events/event_utils.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/views/accessibility/accessibility_paint_checks.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_test_api.h"
@@ -315,11 +314,10 @@
 
 std::unique_ptr<Textfield> CreateTextfield() {
   auto textfield = std::make_unique<Textfield>();
-  // TODO(crbug.com/1218186): Remove this, this is in place temporarily to be
-  // able to submit accessibility checks, but this focusable View needs to
-  // add a name so that the screen reader knows what to announce. Consider
-  // adding bogus placeholder text here.
-  textfield->SetProperty(views::kSkipAccessibilityPaintChecks, true);
+  // Focusable views must have an accessible name in order to pass the
+  // accessibility paint checks. The name can be literal text, placeholder
+  // text or an associated label.
+  textfield->SetAccessibleName(u"Foo");
   return textfield;
 }
 
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn
index 727253b..eeb848b 100644
--- a/ui/webui/resources/BUILD.gn
+++ b/ui/webui/resources/BUILD.gn
@@ -144,7 +144,6 @@
 checked_in_dts_files = [
   "js/parse_html_subset.d.ts",
   "js/promise_resolver.d.ts",
-  "js/static_types.d.ts",
 ]
 
 # Copies checked-in .d.ts files to the preprocess folder so that they are
@@ -160,7 +159,6 @@
   "js/cr/event_target.js",
   "js/cr.m.js",
   "js/cr/ui.js",
-  "js/event_tracker.js",
   "js/load_time_data.m.js",
   "js/icon.js",
   "js/util.js",
@@ -183,11 +181,13 @@
                "js/color_utils.ts",
                "js/custom_element.ts",
                "js/drag_wrapper.ts",
+               "js/event_tracker.ts",
                "js/focus_grid.ts",
                "js/focus_row.ts",
                "js/focus_outline_manager.ts",
                "js/keyboard_shortcut_list.ts",
                "js/plural_string_proxy.ts",
+               "js/static_types.ts",
                "js/store_ts.ts",
                "js/test_loader.ts",
                "js/test_loader_util.ts",
diff --git a/ui/webui/resources/cr_components/history_clusters/cluster.html b/ui/webui/resources/cr_components/history_clusters/cluster.html
index b700f9b..a999f8d 100644
--- a/ui/webui/resources/cr_components/history_clusters/cluster.html
+++ b/ui/webui/resources/cr_components/history_clusters/cluster.html
@@ -51,6 +51,7 @@
   }
 
   :host([in-side-panel_]) .label-row {
+    min-height: 44px;
     padding-inline-start: 16px;
   }
 
@@ -60,14 +61,18 @@
     font-weight: 500;
   }
 
-  .debug-info {
-    color: var(--cr-secondary-text-color);
+  :host([in-side-panel_]) .label {
+    font-size: .875rem;  /* 14px */
+    line-height: calc(10/7); /* 20px */
   }
 
-  #label-and-timestamp {
-    display: flex;
-    flex-direction: column;
-    row-gap: 2px;
+  :host([in-side-panel_]) .timestamp {
+    font-size: .75rem;  /* 12px */
+    line-height: calc(5/3); /* 20px */
+  }
+
+  .debug-info {
+    color: var(--cr-secondary-text-color);
   }
 
   #related-searches {
@@ -78,6 +83,11 @@
     padding: 8px var(--cluster-padding-horizontal) var(--cluster-padding-vertical);
   }
 
+  :host([in-side-panel_]) #related-searches {
+    margin-top: -8px;
+    padding: 0 16px var(--cluster-padding-vertical);
+  }
+
   search-query {
     margin-top: var(--search-query-margin);
   }
@@ -129,15 +139,7 @@
   <!-- In the side panel the label and timestamp should be stacked on the
        left, while outside the side panel the timestamp and the menu should
        be side by side on the right. -->
-  <div class="label-row" hidden="[[!inSidePanel_]]">
-    <div id="label-and-timestamp">
-      <div id="labelSidePanel" class="label"></div>
-      <div class="debug-info">[[cluster.debugInfo]]</div>
-      <div class="timestamp">[[cluster.visits.0.relativeDate]]</div>
-    </div>
-    <cluster-menu></cluster-menu>
-  </div>
-  <div class="label-row" hidden="[[inSidePanel_]]">
+  <div class="label-row">
     <div id="label" class="label"></div>
     <div class="debug-info">[[cluster.debugInfo]]</div>
     <div class="timestamp-and-menu">
@@ -158,7 +160,7 @@
   <div id="related-searches" hidden="[[!cluster.relatedSearches.length]]"
       role="list" aria-label$="[[i18n('relatedSearchesHeader')]]"
       on-related-search-clicked="onRelatedSearchClicked_">
-    <template is="dom-repeat" items="[[cluster.relatedSearches]]">
+    <template is="dom-repeat" items="[[relatedSearches_]]">
       <search-query search-query="[[item]]" index="[[index]]" role="listitem">
       </search-query>
     </template>
diff --git a/ui/webui/resources/cr_components/history_clusters/cluster.ts b/ui/webui/resources/cr_components/history_clusters/cluster.ts
index d4b462e..0693c6c0 100644
--- a/ui/webui/resources/cr_components/history_clusters/cluster.ts
+++ b/ui/webui/resources/cr_components/history_clusters/cluster.ts
@@ -18,7 +18,7 @@
 
 import {BrowserProxyImpl} from './browser_proxy.js';
 import {getTemplate} from './cluster.html.js';
-import {Cluster, ClusterAction, PageCallbackRouter, URLVisit, VisitAction} from './history_clusters.mojom-webui.js';
+import {Cluster, ClusterAction, PageCallbackRouter, SearchQuery, URLVisit, VisitAction} from './history_clusters.mojom-webui.js';
 import {MetricsProxyImpl} from './metrics_proxy.js';
 import {insertHighlightedTextWithMatchesIntoElement} from './utils.js';
 
@@ -37,7 +37,6 @@
 interface HistoryClusterElement {
   $: {
     label: HTMLElement,
-    labelSidePanel: HTMLElement,
     container: HTMLElement,
   };
 }
@@ -98,6 +97,14 @@
       },
 
       /**
+       * The visible related searches.
+       */
+      relatedSearches_: {
+        type: Object,
+        computed: `computeRelatedSearches_(cluster.relatedSearches.*)`,
+      },
+
+      /**
        * The label for the cluster. This property is actually unused. The side
        * effect of the compute function is used to insert the HTML elements for
        * highlighting into this.$.label element.
@@ -311,12 +318,18 @@
       return 'no_label';
     }
 
-    const label = this.inSidePanel_ ? this.$.labelSidePanel : this.$.label;
     insertHighlightedTextWithMatchesIntoElement(
-        label, this.cluster.label!, this.cluster.labelMatchPositions);
+        this.$.label, this.cluster.label!, this.cluster.labelMatchPositions);
     return this.cluster.label!;
   }
 
+  private computeRelatedSearches_(): SearchQuery[] {
+    return this.cluster.relatedSearches.filter(
+        (query: SearchQuery, index: number) => {
+          return query && !(this.inSidePanel_ && index > 2);
+        });
+  }
+
   private computeVisibleVisits_(): URLVisit[] {
     return this.cluster.visits.filter((visit: URLVisit) => {
       return !visit.hidden;
diff --git a/ui/webui/resources/cr_components/history_clusters/url_visit.html b/ui/webui/resources/cr_components/history_clusters/url_visit.html
index b9382cac..16ce275 100644
--- a/ui/webui/resources/cr_components/history_clusters/url_visit.html
+++ b/ui/webui/resources/cr_components/history_clusters/url_visit.html
@@ -91,7 +91,8 @@
   }
 
   :host([in-side-panel_]) #title {
-      font-size: 13px;
+    font-size: .8125rem;  /* 13px */
+    line-height: calc(20/13);  /* 20px */
   }
 
   #url {
@@ -101,7 +102,8 @@
 
   :host([in-side-panel_]) #url {
     color: var(--side-panel-url-color);
-    font-size: 12px;
+    font-size: .75rem;  /* 12px */
+    line-height: calc(5/3);  /* 20px */
   }
 
   #debug-info {
diff --git a/ui/webui/resources/cr_components/history_clusters/url_visit.ts b/ui/webui/resources/cr_components/history_clusters/url_visit.ts
index c5ea1e1..7533838 100644
--- a/ui/webui/resources/cr_components/history_clusters/url_visit.ts
+++ b/ui/webui/resources/cr_components/history_clusters/url_visit.ts
@@ -213,6 +213,11 @@
   //============================================================================
 
   private computeAnnotations_(): string[] {
+    // Disabling annotations until more appropriate design for annotations in
+    // the side panel is complete.
+    if (this.inSidePanel_) {
+      return [];
+    }
     return this.visit.annotations
         .map((annotation: number) => annotationToStringId.get(annotation))
         .filter(
diff --git a/ui/webui/resources/css/BUILD.gn b/ui/webui/resources/css/BUILD.gn
index b440145..e620e3f1 100644
--- a/ui/webui/resources/css/BUILD.gn
+++ b/ui/webui/resources/css/BUILD.gn
@@ -26,7 +26,6 @@
     "action_link.css",
     "butter_bar.css",
     "chrome_shared.css",
-    "i18n_process.css",
     "list.css",
     "menu_button.css",
     "menu.css",
diff --git a/ui/webui/resources/css/chrome_shared.css b/ui/webui/resources/css/chrome_shared.css
index 323bf89e..788e3ec 100644
--- a/ui/webui/resources/css/chrome_shared.css
+++ b/ui/webui/resources/css/chrome_shared.css
@@ -6,7 +6,6 @@
  * chrome:// pages. */
 
 @import url(chrome://resources/css/text_defaults.css);
-@import url(i18n_process.css);
 @import url(widgets.css);
 
 /* Prevent CSS from overriding the hidden property. */
diff --git a/ui/webui/resources/css/i18n_process.css b/ui/webui/resources/css/i18n_process.css
deleted file mode 100644
index 34ac111b..0000000
--- a/ui/webui/resources/css/i18n_process.css
+++ /dev/null
@@ -1,17 +0,0 @@
-/* Copyright 2015 The Chromium Authors
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-[i18n-content]::before,
-[i18n-values*='.innerHTML:']::before {
-  /* Insert a non-breaking space into nodes that have i18n content. */
-  content: '\00a0';
-}
-
-[i18n-processed][i18n-content]::before,
-[i18n-processed] [i18n-content]::before,
-[i18n-processed][i18n-values*='.innerHTML:']::before,
-[i18n-processed] [i18n-values*='.innerHTML:']::before {
-  /* Undo the non-breaking space hack after i18n processing has run. */
-  content: normal;
-}
diff --git a/ui/webui/resources/js/BUILD.gn b/ui/webui/resources/js/BUILD.gn
index 48d1fc8..6b1c13d5 100644
--- a/ui/webui/resources/js/BUILD.gn
+++ b/ui/webui/resources/js/BUILD.gn
@@ -44,12 +44,14 @@
     "color_utils.ts",
     "custom_element.ts",
     "drag_wrapper.ts",
+    "event_tracker.ts",
     "focus_grid.ts",
     "focus_outline_manager.ts",
     "focus_row.ts",
     "keyboard_shortcut_list.ts",
     "plural_string_proxy.ts",
     "search_highlight_utils.ts",
+    "static_types.ts",
     "store_ts.ts",
     "test_loader.ts",
     "test_loader_util.ts",
@@ -76,13 +78,11 @@
     "cr.m.js",
     "cr/event_target.js",
     "cr/ui.js",
-    "event_tracker.js",
     "icon.js",
     "load_time_data.m.js",
     "load_time_data_deprecated.js",
     "parse_html_subset.js",
     "promise_resolver.js",
-    "static_types.js",
     "util.js",
     "webui_resource_test.js",
   ]
@@ -146,12 +146,10 @@
   deps = [
     ":assert",
     ":cr.m",
-    ":event_tracker",
     ":icon",
     ":load_time_data.m",
     ":parse_html_subset",
     ":promise_resolver",
-    ":static_types",
     ":util",
   ]
 }
@@ -167,9 +165,6 @@
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
-js_library("event_tracker") {
-}
-
 js_library("icon") {
   deps = [ ":cr.m" ]
 }
@@ -184,10 +179,6 @@
   deps = [ ":assert" ]
 }
 
-js_library("static_types") {
-  deps = [ ":assert" ]
-}
-
 js_library("util") {
   deps = [
     ":assert",
diff --git a/ui/webui/resources/js/event_tracker.js b/ui/webui/resources/js/event_tracker.js
deleted file mode 100644
index d418945a..0000000
--- a/ui/webui/resources/js/event_tracker.js
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2011 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview EventTracker is a simple class that manages the addition and
- * removal of DOM event listeners. In particular, it keeps track of all
- * listeners that have been added and makes it easy to remove some or all of
- * them without requiring all the information again. This is particularly handy
- * when the listener is a generated function such as a lambda or the result of
- * calling Function.bind.
- */
-
-  export class EventTracker {
-    /**
-     * Create an EventTracker to track a set of events.
-     * EventTracker instances are typically tied 1:1 with other objects or
-     * DOM elements whose listeners should be removed when the object is
-     * disposed or the corresponding elements are removed from the DOM.
-     */
-    constructor() {
-      /**
-       * @type {Array<EventTrackerEntry>}
-       * @private
-       */
-      this.listeners_ = [];
-    }
-
-    /**
-     * Add an event listener - replacement for EventTarget.addEventListener.
-     * @param {!EventTarget} target The DOM target to add a listener to.
-     * @param {string} eventType The type of event to subscribe to.
-     * @param {EventListener|Function} listener The listener to add.
-     * @param {boolean=} capture Whether to invoke during the capture phase.
-     */
-    add(target, eventType, listener, capture = false) {
-      const h = {
-        target: target,
-        eventType: eventType,
-        listener: listener,
-        capture: capture,
-      };
-      this.listeners_.push(h);
-      target.addEventListener(eventType, listener, capture);
-    }
-
-    /**
-     * Remove any specified event listeners added with this EventTracker.
-     * @param {!EventTarget} target The DOM target to remove a listener from.
-     * @param {?string} eventType The type of event to remove.
-     */
-    remove(target, eventType) {
-      this.listeners_ = this.listeners_.filter(listener => {
-        if (listener.target === target &&
-            (!eventType || (listener.eventType === eventType))) {
-          EventTracker.removeEventListener(listener);
-          return false;
-        }
-        return true;
-      });
-    }
-
-    /** Remove all event listeners added with this EventTracker. */
-    removeAll() {
-      this.listeners_.forEach(
-          listener => EventTracker.removeEventListener(listener));
-      this.listeners_ = [];
-    }
-
-    /**
-     * Remove a single event listener given it's tracking entry. It's up to the
-     * caller to ensure the entry is removed from listeners_.
-     * @param {EventTrackerEntry} entry The entry describing the listener to
-     * remove.
-     */
-    static removeEventListener(entry) {
-      entry.target.removeEventListener(
-          entry.eventType, entry.listener, entry.capture);
-    }
-  }
-
-  /**
-   * The type of the internal tracking entry.
-   * @typedef {{target: !EventTarget,
-   *            eventType: string,
-   *            listener: (EventListener|Function),
-   *            capture: boolean}}
-   */
-  let EventTrackerEntry;
-
diff --git a/ui/webui/resources/js/event_tracker.ts b/ui/webui/resources/js/event_tracker.ts
new file mode 100644
index 0000000..eb56704
--- /dev/null
+++ b/ui/webui/resources/js/event_tracker.ts
@@ -0,0 +1,78 @@
+// Copyright 2011 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview EventTracker is a simple class that manages the addition and
+ * removal of DOM event listeners. In particular, it keeps track of all
+ * listeners that have been added and makes it easy to remove some or all of
+ * them without requiring all the information again. This is particularly handy
+ * when the listener is a generated function such as a lambda or the result of
+ * calling Function.bind.
+ */
+
+export class EventTracker {
+  private listeners_: EventTrackerEntry[] = [];
+
+  /**
+   * Add an event listener - replacement for EventTarget.addEventListener.
+   * @param target The DOM target to add a listener to.
+   * @param eventType The type of event to subscribe to.
+   * @param listener The listener to add.
+   * @param capture Whether to invoke during the capture phase. Defaults to
+   *     false.
+   */
+  add(target: EventTarget, eventType: string,
+      listener: EventListener|((p: any) => void), capture: boolean = false) {
+    const h = {
+      target: target,
+      eventType: eventType,
+      listener: listener,
+      capture: capture,
+    };
+    this.listeners_.push(h);
+    target.addEventListener(eventType, listener, capture);
+  }
+
+  /**
+   * Remove any specified event listeners added with this EventTracker.
+   * @param target The DOM target to remove a listener from.
+   * @param eventType The type of event to remove.
+   */
+  remove(target: EventTarget, eventType?: string) {
+    this.listeners_ = this.listeners_.filter(listener => {
+      if (listener.target === target &&
+          (!eventType || (listener.eventType === eventType))) {
+        EventTracker.removeEventListener(listener);
+        return false;
+      }
+      return true;
+    });
+  }
+
+  /** Remove all event listeners added with this EventTracker. */
+  removeAll() {
+    this.listeners_.forEach(
+        listener => EventTracker.removeEventListener(listener));
+    this.listeners_ = [];
+  }
+
+  /**
+   * Remove a single event listener given it's tracking entry. It's up to the
+   * caller to ensure the entry is removed from listeners_.
+   * @param entry The entry describing the listener to
+   * remove.
+   */
+  static removeEventListener(entry: EventTrackerEntry) {
+    entry.target.removeEventListener(
+        entry.eventType, entry.listener, entry.capture);
+  }
+}
+
+// The type of the internal tracking entry.
+interface EventTrackerEntry {
+  target: EventTarget;
+  eventType: string;
+  listener: EventListener|(() => void);
+  capture: boolean;
+}
diff --git a/ui/webui/resources/js/static_types.d.ts b/ui/webui/resources/js/static_types.d.ts
deleted file mode 100644
index 152e9c2..0000000
--- a/ui/webui/resources/js/static_types.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-export function getTrustedHTML(literal: string[]|
-                               TemplateStringsArray): TrustedHTML|string;
-export function getTrustedScript(literal: string[]|
-                                 TemplateStringsArray): TrustedScript|string;
-export function getTrustedScriptURL(literal: string[]|TemplateStringsArray):
-    TrustedScriptURL|string;
diff --git a/ui/webui/resources/js/static_types.js b/ui/webui/resources/js/static_types.js
deleted file mode 100644
index 63205c6..0000000
--- a/ui/webui/resources/js/static_types.js
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {assertNotReached} from './assert.js';
-
-/** @typedef {!Array<string>} */
-let TaggedLiterals;
-
-/**
- * @param {!TaggedLiterals} arr
- * @return {boolean} Whether the passed tagged template literal is a valid
- *     array.
- */
-function isValidArray(arr) {
-  if (arr instanceof Array && Object.isFrozen(arr)) {
-    return true;
-  }
-
-  return false;
-}
-
-/**
- * Checks if the passed tagged template literal only contains static string.
- * And return the string in the literal if so.
- * @param {!TaggedLiterals} literal
- * @return {string}
- * @throws {Error} If the passed argument is not supported literals.
- */
-function getStaticString(literal) {
-  if (isValidArray(literal) && !!literal.raw && isValidArray(literal.raw) &&
-      literal.length === literal.raw.length && literal.length === 1) {
-    return literal.join('');
-  }
-
-  assertNotReached('Static Types only allows static Template literals');
-}
-
-/**
- * @param {string} ignore
- * @param {!TaggedLiterals} literal
- * @return {string}
- */
-function createTypes(ignore, literal) {
-  return getStaticString(literal);
-}
-
-/**
- * Rules used to enforce static literal checks.
- * @type {!TrustedTypePolicyOptions}
- * @suppress {checkTypes}
- */
-const rules = {
-  createHTML: createTypes,
-  createScript: createTypes,
-  createScriptURL: createTypes,
-};
-
-/**
- * This policy returns Trusted Types if the passed literal is static.
- * @type {!TrustedTypePolicy|!TrustedTypePolicyOptions}
- */
-let staticPolicy;
-if (window.trustedTypes) {
-  staticPolicy = trustedTypes.createPolicy('static-types', rules);
-} else {
-  staticPolicy = rules;
-}
-
-/**
- * @param {!TaggedLiterals} literal
- * @return {!TrustedHTML|string} Returns TrustedHTML if the passed literal is
- *     static.
- * @suppress {checkTypes}
- */
-export function getTrustedHTML(literal) {
-  return staticPolicy.createHTML('', literal);
-}
-
-/**
- * @param {!TaggedLiterals} literal
- * @return {!TrustedScript|string} Returns TrustedScript if the passed literal
- *     is static.
- * @suppress {checkTypes}
- */
-export function getTrustedScript(literal) {
-  return staticPolicy.createScript('', literal);
-}
-
-/**
- * @param {!TaggedLiterals} literal
- * @return {!TrustedScriptURL|string} Returns TrustedScriptURL if the passed
- *     literal is static.
- * @suppress {checkTypes}
- */
-export function getTrustedScriptURL(literal) {
-  return staticPolicy.createScriptURL('', literal);
-}
diff --git a/ui/webui/resources/js/static_types.ts b/ui/webui/resources/js/static_types.ts
new file mode 100644
index 0000000..4ff882f
--- /dev/null
+++ b/ui/webui/resources/js/static_types.ts
@@ -0,0 +1,77 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {assert} from './assert_ts.js';
+
+/**
+ * @return Whether the passed tagged template literal is a valid array.
+ */
+function isValidArray(arr: TemplateStringsArray|readonly string[]): boolean {
+  if (arr instanceof Array && Object.isFrozen(arr)) {
+    return true;
+  }
+
+  return false;
+}
+
+/**
+ * Checks if the passed tagged template literal only contains static string.
+ * And return the string in the literal if so.
+ * Throws an Error if the passed argument is not supported literals.
+ */
+function getStaticString(literal: TemplateStringsArray): string {
+  const isStaticString = isValidArray(literal) && !!literal.raw &&
+      isValidArray(literal.raw) && literal.length === literal.raw.length &&
+      literal.length === 1;
+  assert(isStaticString, 'static_types.js only allows static strings');
+
+  return literal.join('');
+}
+
+function createTypes(_ignore: string, literal: TemplateStringsArray): string {
+  return getStaticString(literal);
+}
+
+/**
+ * Rules used to enforce static literal checks.
+ */
+const rules: TrustedTypePolicyOptions = {
+  createHTML: createTypes,
+  createScript: createTypes,
+  createScriptURL: createTypes,
+};
+
+/**
+ * This policy returns Trusted Types if the passed literal is static.
+ */
+let staticPolicy: TrustedTypePolicy|TrustedTypePolicyOptions;
+if (window.trustedTypes) {
+  staticPolicy = window.trustedTypes.createPolicy('static-types', rules);
+} else {
+  staticPolicy = rules;
+}
+
+/**
+ * Returns TrustedHTML if the passed literal is static.
+ */
+export function getTrustedHTML(literal: TemplateStringsArray): (TrustedHTML|
+                                                                string) {
+  return staticPolicy.createHTML!('', literal);
+}
+
+/**
+ * Returns TrustedScript if the passed literal is static.
+ */
+export function getTrustedScript(literal: TemplateStringsArray): (TrustedScript|
+                                                                  string) {
+  return staticPolicy.createScript!('', literal);
+}
+
+/**
+ * Returns TrustedScriptURL if the passed literal is static.
+ */
+export function getTrustedScriptURL(literal: TemplateStringsArray):
+    (TrustedScriptURL|string) {
+  return staticPolicy.createScriptURL!('', literal);
+}
diff --git a/ui/wm/core/transient_window_manager.cc b/ui/wm/core/transient_window_manager.cc
index 313c129..90895ac 100644
--- a/ui/wm/core/transient_window_manager.cc
+++ b/ui/wm/core/transient_window_manager.cc
@@ -4,13 +4,13 @@
 
 #include "ui/wm/core/transient_window_manager.h"
 
-#include <algorithm>
 #include <functional>
 
 #include "base/auto_reset.h"
 #include "base/containers/adapters.h"
 #include "base/containers/contains.h"
 #include "base/observer_list.h"
+#include "base/ranges/algorithm.h"
 #include "ui/aura/client/transient_window_client.h"
 #include "ui/aura/client/transient_window_client_observer.h"
 #include "ui/aura/window.h"
@@ -91,8 +91,7 @@
 }
 
 void TransientWindowManager::RemoveTransientChild(Window* child) {
-  auto i =
-      std::find(transient_children_.begin(), transient_children_.end(), child);
+  auto i = base::ranges::find(transient_children_, child);
   DCHECK(i != transient_children_.end());
   transient_children_.erase(i);
   TransientWindowManager* child_manager = GetOrCreate(child);
@@ -238,8 +237,7 @@
   // Do nothing if we initiated the stacking change.
   const TransientWindowManager* transient_manager = GetIfExists(window);
   if (transient_manager && transient_manager->stacking_target_) {
-    auto window_i = std::find(window->parent()->children().begin(),
-                              window->parent()->children().end(), window);
+    auto window_i = base::ranges::find(window->parent()->children(), window);
     DCHECK(window_i != window->parent()->children().end());
     if (window_i != window->parent()->children().begin() &&
         (*(window_i - 1) == transient_manager->stacking_target_))
diff --git a/ui/wm/core/transient_window_stacking_client.cc b/ui/wm/core/transient_window_stacking_client.cc
index 6aa7336c..8970396 100644
--- a/ui/wm/core/transient_window_stacking_client.cc
+++ b/ui/wm/core/transient_window_stacking_client.cc
@@ -6,8 +6,7 @@
 
 #include <stddef.h>
 
-#include <algorithm>
-
+#include "base/ranges/algorithm.h"
 #include "ui/aura/client/transient_window_client.h"
 #include "ui/wm/core/transient_window_manager.h"
 #include "ui/wm/core/window_util.h"
@@ -88,8 +87,7 @@
   if (*direction == Window::STACK_ABOVE &&
       !HasTransientAncestor(*child, *target)) {
     const Window::Windows& siblings((*child)->parent()->children());
-    size_t target_i =
-        std::find(siblings.begin(), siblings.end(), *target) - siblings.begin();
+    size_t target_i = base::ranges::find(siblings, *target) - siblings.begin();
     while (target_i + 1 < siblings.size() &&
            HasTransientAncestor(siblings[target_i + 1], *target)) {
       ++target_i;
diff --git a/ui/wm/core/window_animations.cc b/ui/wm/core/window_animations.cc
index 7a4fcde..84f1083 100644
--- a/ui/wm/core/window_animations.cc
+++ b/ui/wm/core/window_animations.cc
@@ -6,7 +6,6 @@
 
 #include <math.h>
 
-#include <algorithm>
 #include <memory>
 
 #include "base/bind.h"
@@ -17,6 +16,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/notreached.h"
+#include "base/ranges/algorithm.h"
 #include "base/time/time.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -101,8 +101,7 @@
     if (window_->parent()) {
       const aura::Window::Windows& transient_children =
           GetTransientChildren(window_);
-      auto iter = std::find(window_->parent()->children().begin(),
-                            window_->parent()->children().end(), window_);
+      auto iter = base::ranges::find(window_->parent()->children(), window_);
       DCHECK(iter != window_->parent()->children().end());
       aura::Window* topmost_transient_child = nullptr;
       for (++iter; iter != window_->parent()->children().end(); ++iter) {
diff --git a/ui/wm/core/window_animations_unittest.cc b/ui/wm/core/window_animations_unittest.cc
index 43937cc..63c45c3e 100644
--- a/ui/wm/core/window_animations_unittest.cc
+++ b/ui/wm/core/window_animations_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/containers/contains.h"
+#include "base/ranges/algorithm.h"
 #include "base/time/time.h"
 #include "ui/aura/test/aura_test_base.h"
 #include "ui/aura/test/test_windows.h"
@@ -30,7 +31,7 @@
 template<typename T>int GetZPosition(const T* child) {
   const T* parent = child->parent();
   const std::vector<T*> children = parent->children();
-  auto iter = std::find(children.begin(), children.end(), child);
+  auto iter = base::ranges::find(children, child);
   DCHECK(iter != children.end());
   return iter - children.begin();
 }
diff --git a/ui/wm/core/window_modality_controller.cc b/ui/wm/core/window_modality_controller.cc
index 3139530..4dee15a 100644
--- a/ui/wm/core/window_modality_controller.cc
+++ b/ui/wm/core/window_modality_controller.cc
@@ -6,9 +6,9 @@
 
 #include <stddef.h>
 
-#include <algorithm>
 #include <queue>
 
+#include "base/ranges/algorithm.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/env.h"
@@ -187,7 +187,7 @@
 }
 
 void WindowModalityController::OnWindowDestroyed(aura::Window* window) {
-  windows_.erase(std::find(windows_.begin(), windows_.end(), window));
+  windows_.erase(base::ranges::find(windows_, window));
   window->RemoveObserver(this);
 }
 
diff --git a/weblayer/browser/autofill_client_impl.cc b/weblayer/browser/autofill_client_impl.cc
index 26d69d47..3f1fe99 100644
--- a/weblayer/browser/autofill_client_impl.cc
+++ b/weblayer/browser/autofill_client_impl.cc
@@ -375,6 +375,13 @@
   NOTREACHED();
 }
 
+autofill::FormInteractionsFlowId
+AutofillClientImpl::GetCurrentFormInteractionsFlowId() {
+  // Currently not in use here. See `ChromeAutofillClient` for a proper
+  // implementation.
+  return {};
+}
+
 void AutofillClientImpl::LoadRiskData(
     base::OnceCallback<void(const std::string&)> callback) {
   NOTREACHED();
diff --git a/weblayer/browser/autofill_client_impl.h b/weblayer/browser/autofill_client_impl.h
index 52f072d..dfc7c86 100644
--- a/weblayer/browser/autofill_client_impl.h
+++ b/weblayer/browser/autofill_client_impl.h
@@ -147,6 +147,7 @@
   bool AreServerCardsSupported() const override;
   void ExecuteCommand(int id) override;
   void OpenPromoCodeOfferDetailsURL(const GURL& url) override;
+  autofill::FormInteractionsFlowId GetCurrentFormInteractionsFlowId() override;
 
   // RiskDataLoader:
   void LoadRiskData(
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
index 4c07421..1e34143 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
@@ -755,23 +755,6 @@
     @Override
     public void executeScript(String script, boolean useSeparateIsolate, IObjectWrapper callback) {
         StrictModeWorkaround.apply();
-        Callback<String> nativeCallback = new Callback<String>() {
-            @Override
-            public void onResult(String result) {
-                ValueCallback<String> unwrappedCallback =
-                        (ValueCallback<String>) ObjectWrapper.unwrap(callback, ValueCallback.class);
-                if (unwrappedCallback != null) {
-                    unwrappedCallback.onReceiveValue(result);
-                }
-            }
-        };
-        TabImplJni.get().executeScript(mNativeTab, script, useSeparateIsolate, nativeCallback);
-    }
-
-    @Override
-    public void executeScriptIfAllowed(
-            String script, boolean useSeparateIsolate, IObjectWrapper callback) {
-        StrictModeWorkaround.apply();
 
         WebLayerOriginVerificationScheduler originVerifier =
                 WebLayerOriginVerificationScheduler.getInstance();
@@ -781,11 +764,24 @@
             if (!url.equals(mWebContents.getVisibleUrl().getSpec())) {
                 return;
             }
-            if (verified) {
-                executeScript(script, useSeparateIsolate, callback);
-            } else {
+
+            ValueCallback<String> unwrappedCallback =
+                    (ValueCallback<String>) ObjectWrapper.unwrap(callback, ValueCallback.class);
+            assert unwrappedCallback != null;
+
+            if (!verified) {
                 // TODO(swestphal): Propagate exception to calling api.
+                unwrappedCallback.onReceiveValue(null);
+                return;
             }
+
+            Callback<String> nativeCallback = new Callback<String>() {
+                @Override
+                public void onResult(String result) {
+                    unwrappedCallback.onReceiveValue(result);
+                }
+            };
+            TabImplJni.get().executeScript(mNativeTab, script, useSeparateIsolate, nativeCallback);
         });
     }
 
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl
index e0d8b51..95ad424e 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl
+++ b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl
@@ -85,7 +85,4 @@
 
   // Added in 93
   void setExternalIntentInIncognitoCallbackClient(IExternalIntentInIncognitoCallbackClient client) = 33;
-
-  // Added in 107
-  void executeScriptIfAllowed(in String script, boolean useSeparateIsolate, in IObjectWrapper callback) = 34;
 }
diff --git a/weblayer/public/java/org/chromium/browserfragment/Tab.java b/weblayer/public/java/org/chromium/browserfragment/Tab.java
index 860d7b4ce..2935b5e 100644
--- a/weblayer/public/java/org/chromium/browserfragment/Tab.java
+++ b/weblayer/public/java/org/chromium/browserfragment/Tab.java
@@ -85,7 +85,13 @@
                 mTabProxy.executeScript(script, useSeparateIsolate, new IStringCallback.Stub() {
                     @Override
                     public void onResult(String result) {
-                        completer.set(result);
+                        if (result != null) {
+                            completer.set(result);
+                        } else {
+                            // TODO(rayankans): Improve exception reporting.
+                            completer.setException(
+                                    new IllegalStateException("Failed to execute script"));
+                        }
                     }
                 });
             } catch (RemoteException e) {
diff --git a/weblayer/public/java/org/chromium/weblayer/Tab.java b/weblayer/public/java/org/chromium/weblayer/Tab.java
index 4f01c535..4f28fea 100644
--- a/weblayer/public/java/org/chromium/weblayer/Tab.java
+++ b/weblayer/public/java/org/chromium/weblayer/Tab.java
@@ -261,29 +261,6 @@
     }
 
     /**
-     * Executes the script if the target origin can verify itself via DAL as 1P website, and
-     * returns the result to the callback if provided.
-     *
-     * @param script The javascript to execute.
-     * @param useSeparateIsolate If true, runs the script in a separate v8 Isolate. This uses more
-     * memory, but separates the injected scrips from scripts in the page. This prevents any
-     * potentially malicious interaction between first-party scripts in the page, and injected
-     * scripts. Use with caution, only pass false for this argument if you know this isn't an issue
-     * or you need to interact with first-party scripts.
-     * @param callback Callback function that is called with the result of the executed script.
-     */
-    public void executeScriptIfAllowed(@NonNull String script, boolean useSeparateIsolate,
-            @Nullable ValueCallback<String> callback) {
-        ThreadCheck.ensureOnUiThread();
-        throwIfDestroyed();
-        try {
-            mImpl.executeScriptIfAllowed(script, useSeparateIsolate, ObjectWrapper.wrap(callback));
-        } catch (RemoteException e) {
-            throw new APICallException(e);
-        }
-    }
-
-    /**
      * Runs the beforeunload handler for the main frame or any sub frame, if necessary; otherwise,
      * asynchronously closes the tab.
      *
diff --git a/weblayer/public/java/org/chromium/weblayer/TabProxy.java b/weblayer/public/java/org/chromium/weblayer/TabProxy.java
index 3147cbf..2080de5 100644
--- a/weblayer/public/java/org/chromium/weblayer/TabProxy.java
+++ b/weblayer/public/java/org/chromium/weblayer/TabProxy.java
@@ -76,7 +76,7 @@
     @Override
     public void executeScript(String script, boolean useSeparateIsolate, IStringCallback callback) {
         mHandler.post(() -> {
-            getTab().executeScriptIfAllowed(script, useSeparateIsolate, (String result) -> {
+            getTab().executeScript(script, useSeparateIsolate, (String result) -> {
                 try {
                     callback.onResult(result);
                 } catch (RemoteException e) {
diff --git a/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java b/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java
index e2e9bab..d413ef0 100644
--- a/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java
+++ b/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java
@@ -149,7 +149,19 @@
                                 "Navigation: url:" + navigation.getUri()
                                         + ", HTTP-StatusCode: " + navigation.getStatusCode()
                                         + ", samePage: " + navigation.isSameDocument());
-                        tab.executeScript("console.log('injected JS after 1P validation')", true);
+                        ListenableFuture<String> scriptResultFuture =
+                                tab.executeScript("1+1", true);
+                        Futures.addCallback(scriptResultFuture, new FutureCallback<String>() {
+                            @Override
+                            public void onSuccess(String result) {
+                                Log.w(TAG, "executeScript result: " + result);
+                            }
+
+                            @Override
+                            public void onFailure(Throwable thrown) {
+                                Log.w(TAG, "executeScript failed: " + thrown);
+                            }
+                        }, mContext.getMainExecutor());
                     }
 
                     @Override