diff --git a/DEPS b/DEPS
index a1419f9..bcd511ea 100644
--- a/DEPS
+++ b/DEPS
@@ -220,7 +220,7 @@
   #
   # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-amd64-generic-chrome-skylab
   # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-arm-generic-chrome-skylab
-  'lacros_sdk_version': '15419.0.0',
+  'lacros_sdk_version': '15428.0.0',
 
   # Generate location tag metadata to include in tests result data uploaded
   # to ResultDB. This isn't needed on some configs and the tool that generates
@@ -285,19 +285,19 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '01b6fa2e627143fc4ce8efbd52ad2163c0d57440',
+  'skia_revision': '9b1b2a5dd89911258de74dc62d584ab633ceabac',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '8a767c9c45cd7093d85056290c9b422394e7ad5b',
+  'v8_revision': '8a8a1e7086dacc426965d3875914efa66663c431',
   # 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': 'd6d7e551cb185c310a2a200ed9b3bcfd27653051',
+  'angle_revision': 'f8b182b5b85adc7b2ccc3a4fe754a3efd6943b78',
   # 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': 'dd55e592406dc0bae219df11adec6363840aff4a',
+  'swiftshader_revision': 'c0e5813a9b7754690dbae7cd71ce35f21ca9d98c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -312,7 +312,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:12.20230424.1.1',
+  'fuchsia_version': 'version:12.20230424.2.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.
@@ -332,7 +332,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'd2f043255597fe84888bbece2909f342f39b36c6',
+  'nacl_revision': '417e89893751ee0fea04c86edf386f1eff0e2c96',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -356,7 +356,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': '1aa5adbafbaf89278ef54e8f9fff97aee3e013ba',
+  'catapult_revision': 'cae7ec667dee9f5c012b54ee9ffee94eb7beda14',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -372,7 +372,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': '51b89d107ab2f0a056aedabeca71430323d64f69',
+  'devtools_frontend_revision': '49cec5c2602d764fba68f0be0d09d879438b65fd',
   # 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.
@@ -412,7 +412,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': 'd14a9fbb6e3d398cbca9d7404eb6ffaa0fbe5646',
+  'dawn_revision': 'c1b3c7431680e8e67bfde55ae6dd9ff3b13a235c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -436,7 +436,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nearby
   # and whatever else without interference from each other.
-  'nearby_revision': 'e4c1f9aa240fb016c08964af11f7232d9cbce62d',
+  'nearby_revision': 'db308775d2dfb6e1bf49d666acbf92b516effe52',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling securemessage
   # and whatever else without interference from each other.
@@ -782,7 +782,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '19356589399a6f3c1161e789b8d09027dc0c1020',
+    '8dc675ea2f869a1318a6ca7597fcb3cc30ba7f6c',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -791,7 +791,7 @@
   },
 
   'src/ios/third_party/earl_grey2/src': {
-      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '7c4f01d07d2cb8b4c7cb1c010a65a848452c54d9',
+      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '726e019b3e9e9ecf3ec92e40172f3489e40d8dd0',
       'condition': 'checkout_ios',
   },
 
@@ -971,7 +971,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'OUM7PZTmuDvW-TtOpyI-h84a743D9Ete1SlaY1PPWNEC',
+          'version': 'vf4nNaoNXCQUtS2Ye70vMzrPTUUdLtAn9U9U3hYqkAQC',
       },
     ],
     'condition': 'checkout_android',
@@ -1174,7 +1174,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' + '@' + 'fd23c5d19cc38a3238f64b26639fd6fb2c5b993e',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'de7a53c99abce88396be62e12fd910bd4b50cc4a',
       'condition': 'checkout_chromeos',
   },
 
@@ -1206,13 +1206,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b5cec8c8674bbf180cb47a6705cd5f4545fb11a0',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6e714e6dfe62110c95fafed4bdeb365a69c6a77e',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'e2fa30142a86b0ed035fccb496af4095ecd33210',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '99ba110fdfac4085939e1cccc5a2e025cfc63243',
     'condition': 'checkout_src_internal',
   },
 
@@ -1687,7 +1687,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'aa34142ee605c81ba5cad2b8a36bdcfd1c3c2fbf',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '20b114cd063623e63ef1b0a31167d60081567e51',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1774,7 +1774,7 @@
     Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f',
 
   'src/third_party/snappy/src':
-    Var('chromium_git') + '/external/github.com/google/snappy.git' + '@' + '65dc7b383985eb4f63cd3e752136db8d9b4be8c0',
+    Var('chromium_git') + '/external/github.com/google/snappy.git' + '@' + 'c9f9edf6d75bb065fa47468bf035e051a57bec7c',
 
   'src/third_party/sqlite/src':
     Var('chromium_git') + '/chromium/deps/sqlite.git' + '@' + 'f6752b7ed1fe3cc1491c0c47ec5804ee2bd0e59b',
@@ -1832,7 +1832,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@4b61bdad813f41ad4b3d77a048af31fb782dc19d',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@79949f0f114626c85e1199c70aba085963254d40',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1869,7 +1869,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'bc8d8ae5463bffc5a106bcaaeb68b1ea12a130dc',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '7d2d22292ce5af280c8c5849ed7f0679d7ab70e9',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '39e859901b6c071a75c164b41e6caf1601a9fae9',
@@ -1962,7 +1962,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': Var('chrome_git') + '/chrome/src-internal.git@2d151942439e738fd87439117acbe0597e757d7d',
+    'url': Var('chrome_git') + '/chrome/src-internal.git@26bb6e2ca3378c12e7913079c61d3b441b28e62d',
     'condition': 'checkout_src_internal',
   },
 
@@ -1981,7 +1981,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/eche_app/app',
-        'version': 'tgXRrSKiiTDgWKMFmNkWFsV7OWvZS649zxB4JpuRzGMC',
+        'version': 'nY9Vmlr6KyuNa0J3Q_0CtPu2MakDSfSXKvIZp2iqDrsC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2003,7 +2003,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'rpwMygCtafjs8ZuQDRKvzZNO-kiYslzP1ed45_ZRXxEC',
+        'version': 'P9vjS0K8ys3NJYtAG5mCxYzHAYCepSu-MXyhtngxO-UC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/nonembedded/java/AndroidManifest.xml b/android_webview/nonembedded/java/AndroidManifest.xml
index ef918ea..6f4d201 100644
--- a/android_webview/nonembedded/java/AndroidManifest.xml
+++ b/android_webview/nonembedded/java/AndroidManifest.xml
@@ -15,9 +15,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     package="{{manifest_package|default('com.android.webview')}}"
-    {% if use_isolated_splits is defined and use_isolated_splits == 'true' %}
     android:isolatedSplits="true"
-    {% endif %}
     tools:ignore="MissingLeanbackLauncher">
 
     <uses-feature android:name="android.hardware.touchscreen"
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/services/MetricsBridgeService.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/services/MetricsBridgeService.java
index e824d9f..fb0a6253 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/services/MetricsBridgeService.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/services/MetricsBridgeService.java
@@ -137,7 +137,7 @@
                     mRecordsList.add(proto.toByteArray());
                 }
                 logParsingLogResult(ParsingLogResult.SUCCESS);
-            } catch (InvalidProtocolBufferException e) {
+            } catch (InvalidProtocolBufferException | IllegalStateException e) {
                 Log.e(TAG, "Malformed metrics log proto", e);
                 logParsingLogResult(ParsingLogResult.MALFORMED_PROTOBUF);
                 deleteMetricsLogFile();
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 5f10697..2a7d405 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -58,11 +58,11 @@
     output = _android_manifest
     _force_32_bit = _include_32_bit_webview && _include_64_bit_webview &&
                     (!_is_trichrome || !_is_64_bit_browser)
-    variables = webview_jinja_variables + [
-                  "android_sdk_release=$_android_sdk_release",
-                  "force_32_bit=$_force_32_bit",
-                  "manifest_package=$_manifest_package",
-                ]
+    variables = [
+      "android_sdk_release=$_android_sdk_release",
+      "force_32_bit=$_force_32_bit",
+      "manifest_package=$_manifest_package",
+    ]
     if (_is_trichrome) {
       variables +=
           trichrome_jinja_variables + [ "trichrome_version=$_version_code" ]
@@ -104,7 +104,6 @@
                                  "include_64_bit_webview",
                                  "manifest_package",
                                  "weblayer_product_config_java_package",
-                                 "weblayer_in_split",
                                  "webview_framework_dep",
                                  "webview_product_config_java_package",
                                  "webview_devui_show_icon",
@@ -135,8 +134,7 @@
     if (_exclude_weblayer_java) {
       deps += [ "//android_webview:android_webview_no_weblayer_java" ]
     } else {
-      if (_is_bundle_module && invoker.weblayer_in_split &&
-          webview_includes_weblayer) {
+      if (_is_bundle_module && webview_includes_weblayer) {
         deps += [
           # TODO(crbug.com/1105096): WebLayer resources are added to the base
           # module for now because of bugs with shared resources in splits.
diff --git a/android_webview/system_webview_bundle.gni b/android_webview/system_webview_bundle.gni
index e056095..3a07ee9 100644
--- a/android_webview/system_webview_bundle.gni
+++ b/android_webview/system_webview_bundle.gni
@@ -22,7 +22,7 @@
 
   assert(_is_trichrome == defined(invoker.static_library_provider))
 
-  if (webview_includes_weblayer && weblayer_in_split) {
+  if (webview_includes_weblayer) {
     # TODO(crbug.com/1105096): If WebView starts using
     # //components/module_installer, it will probably make sense to refactor
     # chrome_feature_module() to be used here.
@@ -95,7 +95,7 @@
     } else {
       compress_shared_libraries = true
     }
-    if (webview_includes_weblayer && weblayer_in_split) {
+    if (webview_includes_weblayer) {
       extra_modules = [ _weblayer_module_desc ]
     }
     system_image_locale_allowlist = platform_pak_locales
diff --git a/android_webview/variables.gni b/android_webview/variables.gni
index 6a320ea..4d72e8b 100644
--- a/android_webview/variables.gni
+++ b/android_webview/variables.gni
@@ -23,6 +23,4 @@
   upstream_only_webview_deps += [ "//weblayer/browser/java:upstream_java" ]
 }
 
-webview_jinja_variables = [ "use_isolated_splits=$weblayer_in_split" ]
-
 webview_product_config_java_package = "org.chromium.android_webview"
diff --git a/ash/accelerators/accelerator_alias_converter.cc b/ash/accelerators/accelerator_alias_converter.cc
index db765b98..f996a91 100644
--- a/ash/accelerators/accelerator_alias_converter.cc
+++ b/ash/accelerators/accelerator_alias_converter.cc
@@ -6,7 +6,9 @@
 
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/shell.h"
+#include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/events/ash/keyboard_capability.h"
@@ -118,8 +120,15 @@
     return {};
   }
 
-  const bool top_row_are_fkeys =
-      Shell::Get()->keyboard_capability()->TopRowKeysAreFKeys();
+  const bool top_row_are_fkeys = [&]() -> bool {
+    if (features::IsInputDeviceSettingsSplitEnabled()) {
+      const auto* settings =
+          Shell::Get()->input_device_settings_controller()->GetKeyboardSettings(
+              priority_keyboard->id);
+      return settings && settings->top_row_are_fkeys;
+    }
+    return Shell::Get()->keyboard_capability()->TopRowKeysAreFKeys();
+  }();
   absl::optional<ui::KeyboardCode> function_key =
       Shell::Get()->keyboard_capability()->GetCorrespondingFunctionKey(
           *priority_keyboard, *action_key);
diff --git a/ash/accelerators/accelerator_commands.cc b/ash/accelerators/accelerator_commands.cc
index a7746c4..cd212be7 100644
--- a/ash/accelerators/accelerator_commands.cc
+++ b/ash/accelerators/accelerator_commands.cc
@@ -1633,17 +1633,14 @@
           WindowSnapAcceleratorAction::kCycleRightSnapInClamshellNoOverview);
     }
   }
-
-  const WMEvent event(action == WINDOW_CYCLE_SNAP_LEFT
-                          ? WM_EVENT_CYCLE_SNAP_PRIMARY
-                          : WM_EVENT_CYCLE_SNAP_SECONDARY);
+  const WindowSnapWMEvent event(
+      action == WINDOW_CYCLE_SNAP_LEFT ? WM_EVENT_CYCLE_SNAP_PRIMARY
+                                       : WM_EVENT_CYCLE_SNAP_SECONDARY,
+      WindowSnapActionSource::kKeyboardShortcutToSnap);
   aura::Window* window = GetTargetWindow();
   DCHECK(window);
 
-  auto* window_state = WindowState::Get(window);
-  window_state->set_snap_action_source(
-      WindowSnapActionSource::kKeyboardShortcutToSnap);
-  window_state->OnWMEvent(&event);
+  WindowState::Get(window)->OnWMEvent(&event);
 }
 
 bool ZoomDisplay(bool up) {
diff --git a/ash/ambient/ambient_controller.cc b/ash/ambient/ambient_controller.cc
index cb63d80..2fbc85d 100644
--- a/ash/ambient/ambient_controller.cc
+++ b/ash/ambient/ambient_controller.cc
@@ -718,10 +718,10 @@
                     base::Value(minutes));
 }
 
-int AmbientController::GetScreenSaverDuration() {
+absl::optional<int> AmbientController::GetScreenSaverDuration() {
   auto* pref_service = GetPrimaryUserPrefService();
-  if (!ash::features::IsScreenSaverDurationEnabled() || !pref_service) {
-    return -1;
+  if (!pref_service) {
+    return absl::nullopt;
   }
   return pref_service->GetInteger(
       ambient::prefs::kAmbientModeRunningDurationMinutes);
diff --git a/ash/ambient/ambient_controller.h b/ash/ambient/ambient_controller.h
index 2ef4afa..8402b4d 100644
--- a/ash/ambient/ambient_controller.h
+++ b/ash/ambient/ambient_controller.h
@@ -147,8 +147,8 @@
   void SetScreenSaverDuration(int minutes);
 
   // Get the number of minutes to run screen saver before sleep from
-  // pref_service.
-  int GetScreenSaverDuration();
+  // pref_service. A nullopt means failed to fetch duration pref value.
+  absl::optional<int> GetScreenSaverDuration();
 
   void StartTimerToReleaseWakeLock();
 
diff --git a/ash/ambient/test/ambient_ash_test_base.cc b/ash/ambient/test/ambient_ash_test_base.cc
index 5f414e36..e7fbb80 100644
--- a/ash/ambient/test/ambient_ash_test_base.cc
+++ b/ash/ambient/test/ambient_ash_test_base.cc
@@ -717,7 +717,7 @@
   ambient_controller()->SetScreenSaverDuration(minutes);
 }
 
-int AmbientAshTestBase::GetScreenSaverDuration() {
+absl::optional<int> AmbientAshTestBase::GetScreenSaverDuration() {
   return ambient_controller()->GetScreenSaverDuration();
 }
 
diff --git a/ash/ambient/test/ambient_ash_test_base.h b/ash/ambient/test/ambient_ash_test_base.h
index 72c671eb..0a548c7f 100644
--- a/ash/ambient/test/ambient_ash_test_base.h
+++ b/ash/ambient/test/ambient_ash_test_base.h
@@ -232,7 +232,7 @@
 
   void SetScreenSaverDuration(int minutes);
 
-  int GetScreenSaverDuration();
+  absl::optional<int> GetScreenSaverDuration();
 
  private:
   void SpinWaitForAmbientViewAvailable(
diff --git a/ash/app_list/views/top_icon_animation_view.cc b/ash/app_list/views/top_icon_animation_view.cc
index 2d37259..ff8f4f30 100644
--- a/ash/app_list/views/top_icon_animation_view.cc
+++ b/ash/app_list/views/top_icon_animation_view.cc
@@ -11,7 +11,9 @@
 #include "ash/app_list/views/apps_grid_view.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/style/ash_color_id.h"
+#include "ash/style/typography.h"
 #include "base/task/single_thread_task_runner.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/gfx/image/image_skia_operations.h"
@@ -44,11 +46,21 @@
   title_label->SetBackgroundColor(SK_ColorTRANSPARENT);
   title_label->SetAutoColorReadabilityEnabled(false);
   title_label->SetHandlesTooltips(false);
-  title_label->SetFontList(grid_->app_list_config()->app_title_font());
-  title_label->SetLineHeight(
-      grid_->app_list_config()->app_title_max_line_height());
   title_label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
-  title_label->SetEnabledColorId(cros_tokens::kTextColorPrimary);
+
+  const AppListConfig* const app_list_config = grid_->app_list_config();
+  if (chromeos::features::IsJellyEnabled()) {
+    TypographyProvider::Get()->StyleLabel(
+        app_list_config->type() == AppListConfigType::kDense
+            ? TypographyToken::kCrosAnnotation1
+            : TypographyToken::kCrosButton2,
+        *title_label);
+    title_label->SetEnabledColorId(cros_tokens::kCrosSysOnSurface);
+  } else {
+    title_label->SetFontList(app_list_config->app_title_font());
+    title_label->SetEnabledColorId(cros_tokens::kTextColorPrimary);
+  }
+  title_label->SetLineHeight(app_list_config->app_title_max_line_height());
   title_label->SetText(title);
   if (item_in_folder_icon_) {
     // The title's opacity of the item should be changed separately if it is in
diff --git a/ash/components/arc/session/arc_session_impl.cc b/ash/components/arc/session/arc_session_impl.cc
index 91c8acb87..7d85e7b3 100644
--- a/ash/components/arc/session/arc_session_impl.cc
+++ b/ash/components/arc/session/arc_session_impl.cc
@@ -701,7 +701,7 @@
   state_ = State::RUNNING_FULL_INSTANCE;
 
   // Some memory parameters may be changed when ARC is launched.
-  ash::UpdateMemoryParameters();
+  ash::UpdateMemoryParameters(arc::IsArcAvailable());
 }
 
 void ArcSessionImpl::Stop() {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 466e2a9..4f24c241 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -2122,12 +2122,12 @@
 
 // Enables time of day screen saver.
 BASE_FEATURE(kTimeOfDayScreenSaver,
-             "FeatureManagementTimeOfDayScreenSaver",
+             "TimeOfDayScreenSaver",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Enables time of day wallpaper.
 BASE_FEATURE(kTimeOfDayWallpaper,
-             "FeatureManagementTimeOfDayWallpaper",
+             "TimeOfDayWallpaper",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Enables the TrafficCountersHandler class to auto-reset traffic counters
diff --git a/ash/display/display_move_window_util_unittest.cc b/ash/display/display_move_window_util_unittest.cc
index acc8a04..1217f6f 100644
--- a/ash/display/display_move_window_util_unittest.cc
+++ b/ash/display/display_move_window_util_unittest.cc
@@ -131,7 +131,7 @@
 
   // Set window to left snapped state.
   PerformMoveWindowAccel();
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
   EXPECT_EQ(display_manager()->GetDisplayAt(0).id(),
             screen->GetDisplayNearestWindow(window).id());
diff --git a/ash/drag_drop/tab_drag_drop_delegate.cc b/ash/drag_drop/tab_drag_drop_delegate.cc
index 3a14530af..9a91bc4 100644
--- a/ash/drag_drop/tab_drag_drop_delegate.cc
+++ b/ash/drag_drop/tab_drag_drop_delegate.cc
@@ -261,9 +261,8 @@
           snap_position) {
     overview_session->MergeWindowIntoOverviewForWebUITabStrip(new_window);
   } else {
-    WindowState::Get(new_window)
-        ->set_snap_action_source(WindowSnapActionSource::kDragTabToSnap);
     split_view_controller->SnapWindow(new_window, snap_position,
+                                      WindowSnapActionSource::kDragTabToSnap,
                                       /*activate_window=*/true);
   }
 
@@ -282,9 +281,8 @@
   // |source_window_| is itself a child window of the browser since it
   // hosts web content (specifically, the tab strip WebUI). Snap its
   // toplevel window which is the browser window.
-  WindowState::Get(new_window)
-      ->set_snap_action_source(WindowSnapActionSource::kDragTabToSnap);
-  split_view_controller->SnapWindow(source_window_, opposite_position);
+  split_view_controller->SnapWindow(source_window_, opposite_position,
+                                    WindowSnapActionSource::kDragTabToSnap);
 }
 
 bool TabDragDropDelegate::ShouldPreventSnapToTheEdge(
diff --git a/ash/events/keyboard_capability_delegate_impl.h b/ash/events/keyboard_capability_delegate_impl.h
index 9e17769..73392c2 100644
--- a/ash/events/keyboard_capability_delegate_impl.h
+++ b/ash/events/keyboard_capability_delegate_impl.h
@@ -5,6 +5,7 @@
 #ifndef ASH_EVENTS_KEYBOARD_CAPABILITY_DELEGATE_IMPL_H_
 #define ASH_EVENTS_KEYBOARD_CAPABILITY_DELEGATE_IMPL_H_
 
+#include "ash/ash_export.h"
 #include "ash/public/cpp/session/session_observer.h"
 #include "base/observer_list.h"
 #include "components/prefs/pref_member.h"
@@ -17,8 +18,9 @@
 // KeyboardCapabilityDelegateImpl implements KeyboardCapability Delegate. It
 // provides various keyboard capability information such as if top row keys are
 // treated as function keys.
-class KeyboardCapabilityDelegateImpl : public ui::KeyboardCapability::Delegate,
-                                       public SessionObserver {
+class ASH_EXPORT KeyboardCapabilityDelegateImpl
+    : public ui::KeyboardCapability::Delegate,
+      public SessionObserver {
  public:
   KeyboardCapabilityDelegateImpl();
   KeyboardCapabilityDelegateImpl(const KeyboardCapabilityDelegateImpl&) =
diff --git a/ash/events/keyboard_capability_unittest.cc b/ash/events/keyboard_capability_unittest.cc
index df6810c..98bc512 100644
--- a/ash/events/keyboard_capability_unittest.cc
+++ b/ash/events/keyboard_capability_unittest.cc
@@ -4,15 +4,17 @@
 
 #include "ui/events/ash/keyboard_capability.h"
 
+#include <linux/input-event-codes.h>
 #include <memory>
 
 #include "ash/constants/ash_pref_names.h"
 #include "ash/display/privacy_screen_controller.h"
+#include "ash/events/keyboard_capability_delegate_impl.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "base/files/file_path.h"
-#include "base/memory/raw_ptr.h"
+#include "base/files/scoped_file.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -50,6 +52,7 @@
 // A tag that should fail parsing for the top row custom scan code string.
 constexpr char kKbdInvalidCustomTopRowLayout[] = "X X X";
 
+// This set of scan code mappings come from x86 internal vivaldi keyboards.
 enum CustomTopRowScanCode : uint32_t {
   kPreviousTrack = 0x90,
   kFullscreen = 0x91,
@@ -109,6 +112,52 @@
       device_info.vendor_id(), device_info.product_id(), device_info.version());
 }
 
+absl::optional<uint32_t> GetEvdevKeyCodeForScanCode(const base::ScopedFD& fd,
+                                                    uint32_t scancode) {
+  switch (scancode) {
+    case CustomTopRowScanCode::kPreviousTrack:
+      return KEY_PREVIOUSSONG;
+    case CustomTopRowScanCode::kFullscreen:
+      return KEY_ZOOM;
+    case CustomTopRowScanCode::kOverview:
+      return KEY_SCALE;
+    case CustomTopRowScanCode::kScreenshot:
+      return KEY_SYSRQ;
+    case CustomTopRowScanCode::kScreenBrightnessDown:
+      return KEY_BRIGHTNESSDOWN;
+    case CustomTopRowScanCode::kScreenBrightnessUp:
+      return KEY_BRIGHTNESSUP;
+    case CustomTopRowScanCode::kPrivacyScreenToggle:
+      return KEY_PRIVACY_SCREEN_TOGGLE;
+    case CustomTopRowScanCode::kKeyboardBacklightDown:
+      return KEY_KBDILLUMDOWN;
+    case CustomTopRowScanCode::kKeyboardBacklightUp:
+      return KEY_KBDILLUMUP;
+    case CustomTopRowScanCode::kNextTrack:
+      return KEY_NEXTSONG;
+    case CustomTopRowScanCode::kPlayPause:
+      return KEY_PLAYPAUSE;
+    case CustomTopRowScanCode::kMicrophoneMute:
+      return KEY_MICMUTE;
+    case CustomTopRowScanCode::kKeyboardBacklightToggle:
+      return KEY_KBDILLUMTOGGLE;
+    case CustomTopRowScanCode::kVolumeMute:
+      return KEY_MUTE;
+    case CustomTopRowScanCode::kVolumeDown:
+      return KEY_VOLUMEDOWN;
+    case CustomTopRowScanCode::kVolumeUp:
+      return KEY_VOLUMEUP;
+    case CustomTopRowScanCode::kForward:
+      return KEY_FORWARD;
+    case CustomTopRowScanCode::kBack:
+      return KEY_BACK;
+    case CustomTopRowScanCode::kRefresh:
+      return KEY_REFRESH;
+  }
+
+  return absl::nullopt;
+}
+
 class FakeDeviceManager {
  public:
   FakeDeviceManager() = default;
@@ -173,14 +222,17 @@
 
 }  // namespace
 
-class KeyboardCapabilityTest : public AshTestBase {
+class KeyboardCapabilityTest : public NoSessionAshTestBase {
  public:
   KeyboardCapabilityTest() = default;
   ~KeyboardCapabilityTest() override = default;
 
   void SetUp() override {
     AshTestBase::SetUp();
-    keyboard_capability_ = Shell::Get()->keyboard_capability();
+    keyboard_capability_ = std::make_unique<ui::KeyboardCapability>(
+        base::BindRepeating(&GetEvdevKeyCodeForScanCode),
+        std::make_unique<KeyboardCapabilityDelegateImpl>());
+    SimulateUserLogin(/*user_email=*/"email@google.com");
     test_observer_ = std::make_unique<TestObserver>();
     fake_keyboard_manager_ = std::make_unique<FakeDeviceManager>();
     keyboard_capability_->AddObserver(test_observer_.get());
@@ -188,6 +240,7 @@
 
   void TearDown() override {
     keyboard_capability_->RemoveObserver(test_observer_.get());
+    keyboard_capability_.reset();
     AshTestBase::TearDown();
   }
 
@@ -211,7 +264,7 @@
   }
 
  protected:
-  raw_ptr<ui::KeyboardCapability, ExperimentalAsh> keyboard_capability_;
+  std::unique_ptr<ui::KeyboardCapability> keyboard_capability_;
   std::unique_ptr<TestObserver> test_observer_;
   std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
 };
@@ -967,7 +1020,9 @@
         return CustomTopRowScanCode::kPreviousTrack;
       case ui::TopRowActionKey::kPlayPause:
         return CustomTopRowScanCode::kPlayPause;
-      case ui::TopRowActionKey::kLauncher:
+      case ui::TopRowActionKey::kAllApplications:
+      case ui::TopRowActionKey::kEmojiPicker:
+      case ui::TopRowActionKey::kDictation:
       case ui::TopRowActionKey::kUnknown:
       case ui::TopRowActionKey::kNone:
         return 0;
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
index 45474e5..cb2762f 100644
--- a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
+++ b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
@@ -330,7 +330,7 @@
   EXPECT_TRUE(window_state->IsNormalStateType());
 
   // Snap the window.
-  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   // Check the window is now snapped.
   EXPECT_TRUE(window_state->IsSnapped());
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc
index ce7f94ed..8594d4f 100644
--- a/ash/frame/caption_buttons/frame_size_button_unittest.cc
+++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -696,8 +696,10 @@
   EXPECT_TRUE(window_state()->IsNormalStateType());
   ui::test::EventGenerator* generator = GetEventGenerator();
   ShowMultitaskMenu();
-  generator->MoveMouseTo(CenterPointInScreen(
-      GetMultitaskMenu()->multitask_menu_view()->float_button_for_testing()));
+  generator->MoveMouseTo(
+      CenterPointInScreen(GetMultitaskMenu()
+                              ->multitask_menu_view_for_testing()
+                              ->float_button_for_testing()));
   generator->ClickLeftButton();
   EXPECT_TRUE(window_state()->IsFloated());
   histogram_tester.ExpectBucketCount(
@@ -712,7 +714,7 @@
   ui::test::EventGenerator* generator = GetEventGenerator();
   ShowMultitaskMenu();
   generator->MoveMouseTo(GetMultitaskMenu()
-                             ->multitask_menu_view()
+                             ->multitask_menu_view_for_testing()
                              ->half_button_for_testing()
                              ->GetBoundsInScreen()
                              .left_center());
@@ -732,7 +734,7 @@
 
   ShowMultitaskMenu();
   GetEventGenerator()->MoveMouseTo(GetMultitaskMenu()
-                                       ->multitask_menu_view()
+                                       ->multitask_menu_view_for_testing()
                                        ->half_button_for_testing()
                                        ->GetBoundsInScreen()
                                        .left_center());
@@ -760,7 +762,7 @@
   // snapped state, because in this orientation secondary snapped is actually
   // physically on the left side.
   GetEventGenerator()->MoveMouseToInHost(GetMultitaskMenu()
-                                             ->multitask_menu_view()
+                                             ->multitask_menu_view_for_testing()
                                              ->half_button_for_testing()
                                              ->GetBoundsInScreen()
                                              .left_center());
@@ -788,7 +790,7 @@
   // Snap to primary with 0.67f screen ratio.
   ShowMultitaskMenu();
   generator->MoveMouseTo(GetMultitaskMenu()
-                             ->multitask_menu_view()
+                             ->multitask_menu_view_for_testing()
                              ->partial_button()
                              ->GetBoundsInScreen()
                              .left_center());
@@ -807,7 +809,7 @@
   // Snap to secondary with 0.33f screen ratio.
   ShowMultitaskMenu();
   generator->MoveMouseTo(GetMultitaskMenu()
-                             ->multitask_menu_view()
+                             ->multitask_menu_view_for_testing()
                              ->partial_button()
                              ->GetRightBottomButton()
                              ->GetBoundsInScreen()
@@ -831,8 +833,10 @@
   ASSERT_TRUE(window_state()->IsNormalStateType());
   ui::test::EventGenerator* generator = GetEventGenerator();
   ShowMultitaskMenu();
-  generator->MoveMouseTo(CenterPointInScreen(
-      GetMultitaskMenu()->multitask_menu_view()->full_button_for_testing()));
+  generator->MoveMouseTo(
+      CenterPointInScreen(GetMultitaskMenu()
+                              ->multitask_menu_view_for_testing()
+                              ->full_button_for_testing()));
   generator->ClickLeftButton();
   EXPECT_TRUE(window_state()->IsFullscreen());
   histogram_tester.ExpectBucketCount(
@@ -920,7 +924,7 @@
   // Snap the window to half so we can click outside the window bounds.
   ShowMultitaskMenu();
   GetEventGenerator()->MoveMouseTo(GetMultitaskMenu()
-                                       ->multitask_menu_view()
+                                       ->multitask_menu_view_for_testing()
                                        ->half_button_for_testing()
                                        ->GetBoundsInScreen()
                                        .left_center());
@@ -932,7 +936,7 @@
   ASSERT_TRUE(multitask_menu);
 
   // Click on a point outside the menu on the screen below.
-  gfx::Point offset_point(multitask_menu->multitask_menu_view()
+  gfx::Point offset_point(multitask_menu->multitask_menu_view_for_testing()
                               ->GetBoundsInScreen()
                               .bottom_right());
   offset_point.Offset(10, 10);
diff --git a/ash/frame/non_client_frame_view_ash.cc b/ash/frame/non_client_frame_view_ash.cc
index e95f800a..f12537b 100644
--- a/ash/frame/non_client_frame_view_ash.cc
+++ b/ash/frame/non_client_frame_view_ash.cc
@@ -11,7 +11,6 @@
 #include "ash/public/cpp/tablet_mode_observer.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
@@ -22,13 +21,11 @@
 #include "base/memory/raw_ptr.h"
 #include "chromeos/ui/base/window_properties.h"
 #include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h"
-#include "chromeos/ui/frame/caption_buttons/frame_size_button.h"
 #include "chromeos/ui/frame/default_frame_header.h"
 #include "chromeos/ui/frame/frame_utils.h"
 #include "chromeos/ui/frame/header_view.h"
 #include "chromeos/ui/frame/immersive/immersive_fullscreen_controller.h"
 #include "chromeos/ui/frame/non_client_frame_view_base.h"
-#include "chromeos/ui/wm/features.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
@@ -180,13 +177,6 @@
 
   header_view_->set_context_menu_controller(
       frame_context_menu_controller_.get());
-
-  auto* size_button = header_view_->caption_button_container()->size_button();
-  if (chromeos::wm::features::IsWindowLayoutMenuEnabled() && size_button) {
-    size_button->SetFeedbackButtonCallback(
-        base::BindRepeating(&NonClientFrameViewAsh::ShowFeedbackPageForMenu,
-                            weak_factory_.GetWeakPtr()));
-  }
 }
 
 NonClientFrameViewAsh::~NonClientFrameViewAsh() = default;
@@ -325,12 +315,6 @@
   frame_window->SetProperty(kFrameInactiveColorKey, dialog_title_bar_color);
 }
 
-void NonClientFrameViewAsh::ShowFeedbackPageForMenu() {
-  Shell::Get()->shell_delegate()->OpenFeedbackDialog(
-      ShellDelegate::FeedbackSource::kWindowLayoutMenu,
-      /*description_template=*/"#WindowLayoutMenu");
-}
-
 BEGIN_METADATA(NonClientFrameViewAsh, views::NonClientFrameView)
 END_METADATA
 
diff --git a/ash/frame/non_client_frame_view_ash.h b/ash/frame/non_client_frame_view_ash.h
index db6152a7..9b2adbe 100644
--- a/ash/frame/non_client_frame_view_ash.h
+++ b/ash/frame/non_client_frame_view_ash.h
@@ -123,9 +123,6 @@
   // Updates the windows default frame colors if necessary.
   void UpdateDefaultFrameColors() override;
 
-  // Shows a dogfood feedback page for the multitask menu.
-  void ShowFeedbackPageForMenu();
-
   // Generates a nine patch layer painted with a highlight border.
   std::unique_ptr<HighlightBorderOverlay> highlight_border_overlay_;
 
diff --git a/ash/frame/snap_controller_impl.cc b/ash/frame/snap_controller_impl.cc
index 07758c5e..c53e61d0 100644
--- a/ash/frame/snap_controller_impl.cc
+++ b/ash/frame/snap_controller_impl.cc
@@ -8,6 +8,7 @@
 #include "ash/wm/window_positioning_utils.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
+#include "ash/wm/wm_metrics.h"
 #include "ash/wm/workspace/phantom_window_controller.h"
 #include "ui/aura/window.h"
 #include "ui/events/devices/haptic_touchpad_effects.h"
@@ -59,19 +60,33 @@
 
 void SnapControllerImpl::CommitSnap(aura::Window* window,
                                     chromeos::SnapDirection snap,
-                                    float snap_ratio) {
+                                    float snap_ratio,
+                                    SnapRequestSource snap_request_source) {
   phantom_window_controller_.reset();
-  if (snap == chromeos::SnapDirection::kNone)
+  if (snap == chromeos::SnapDirection::kNone) {
     return;
+  }
 
-  WindowState* window_state = WindowState::Get(window);
-  window_state->set_snap_action_source(
-      WindowSnapActionSource::kUseCaptionButtonToSnap);
-  const WMEvent snap_event(snap == chromeos::SnapDirection::kPrimary
-                               ? WM_EVENT_SNAP_PRIMARY
-                               : WM_EVENT_SNAP_SECONDARY,
-                           snap_ratio);
-  window_state->OnWMEvent(&snap_event);
+  WindowSnapActionSource snap_action_source =
+      WindowSnapActionSource::kNotSpecified;
+  switch (snap_request_source) {
+    case SnapRequestSource::kSnapButton:
+      snap_action_source =
+          WindowSnapActionSource::kLongPressCaptionButtonToSnap;
+      break;
+    case SnapRequestSource::kWindowLayoutMenu:
+      snap_action_source = WindowSnapActionSource::kSnapByWindowLayoutMenu;
+      break;
+    case SnapRequestSource::kFromLacrosSnapButtonOrWindowLayoutMenu:
+      // TODO: handle the lacros snap request.
+      break;
+  }
+
+  const WindowSnapWMEvent snap_event(snap == chromeos::SnapDirection::kPrimary
+                                         ? WM_EVENT_SNAP_PRIMARY
+                                         : WM_EVENT_SNAP_SECONDARY,
+                                     snap_ratio, snap_action_source);
+  WindowState::Get(window)->OnWMEvent(&snap_event);
 }
 
 }  // namespace ash
diff --git a/ash/frame/snap_controller_impl.h b/ash/frame/snap_controller_impl.h
index 84098666..d3a7892 100644
--- a/ash/frame/snap_controller_impl.h
+++ b/ash/frame/snap_controller_impl.h
@@ -30,7 +30,8 @@
                        bool allow_haptic_feedback) override;
   void CommitSnap(aura::Window* window,
                   chromeos::SnapDirection snap,
-                  float snap_ratio) override;
+                  float snap_ratio,
+                  SnapRequestSource snap_request_source) override;
 
  private:
   std::unique_ptr<PhantomWindowController> phantom_window_controller_;
diff --git a/ash/public/cpp/shell_window_ids.h b/ash/public/cpp/shell_window_ids.h
index fd2774a..5292f0b5 100644
--- a/ash/public/cpp/shell_window_ids.h
+++ b/ash/public/cpp/shell_window_ids.h
@@ -149,8 +149,8 @@
   // The container for menus.
   kShellWindowId_MenuContainer,
 
-  // The container for drag/drop images, tooltips, and widgets that are tagged
-  // with ui::ZOrderLevel::kSecuritySurface.
+  // The container for drag/drop images, tooltips, toasts and widgets that are
+  // tagged with ui::ZOrderLevel::kSecuritySurface.
   kShellWindowId_DragImageAndTooltipContainer,
 
   // The container for the fullscreen power button menu.
diff --git a/ash/shelf/drag_window_from_shelf_controller.cc b/ash/shelf/drag_window_from_shelf_controller.cc
index 1c6fac1..752990115 100644
--- a/ash/shelf/drag_window_from_shelf_controller.cc
+++ b/ash/shelf/drag_window_from_shelf_controller.cc
@@ -528,10 +528,9 @@
       SplitViewController::Get(Shell::GetPrimaryRootWindow());
   if (split_view_controller->InSplitViewMode() ||
       snap_position != SplitViewController::SnapPosition::kNone) {
-    WindowState::Get(window_)->set_snap_action_source(
-        WindowSnapActionSource::kDragUpFromShelfToSnap);
     split_view_controller->OnWindowDragEnded(
-        window_, snap_position, gfx::ToRoundedPoint(location_in_screen));
+        window_, snap_position, gfx::ToRoundedPoint(location_in_screen),
+        WindowSnapActionSource::kDragUpFromShelfToSnap);
   }
 
   // Scale-in-to-show home screen if home screen should be shown after drag
diff --git a/ash/shelf/shelf.h b/ash/shelf/shelf.h
index 80ce0de..a18c92f7 100644
--- a/ash/shelf/shelf.h
+++ b/ash/shelf/shelf.h
@@ -92,6 +92,10 @@
     explicit ScopedAutoHideLock(Shelf* shelf) : shelf_(shelf) {
       ++shelf_->auto_hide_lock_;
     }
+
+    ScopedAutoHideLock(const ScopedAutoHideLock&) = delete;
+    ScopedAutoHideLock& operator=(const ScopedAutoHideLock&) = delete;
+
     ~ScopedAutoHideLock() {
       --shelf_->auto_hide_lock_;
       DCHECK_GE(shelf_->auto_hide_lock_, 0);
@@ -114,6 +118,9 @@
       }
     }
 
+    ScopedDisableAutoHide(const ScopedDisableAutoHide&) = delete;
+    ScopedDisableAutoHide& operator=(const ScopedDisableAutoHide&) = delete;
+
     ~ScopedDisableAutoHide() {
       --shelf_->disable_auto_hide_;
       CHECK_GE(shelf_->disable_auto_hide_, 0);
@@ -122,6 +129,8 @@
       }
     }
 
+    Shelf* shelf() { return shelf_; }
+
    private:
     const raw_ptr<Shelf, ExperimentalAsh> shelf_;
   };
diff --git a/ash/style/system_toast_style.cc b/ash/style/system_toast_style.cc
index 3677de7..f2676a5 100644
--- a/ash/style/system_toast_style.cc
+++ b/ash/style/system_toast_style.cc
@@ -135,10 +135,11 @@
 
   if (!leading_icon_->is_empty()) {
     leading_icon_view_ = AddChildView(std::make_unique<views::ImageView>());
-    leading_icon_view_->SetPreferredSize(gfx::Size(
-        kLeadingIconSize + kLeadingIconRightPadding, kLeadingIconSize));
-    leading_icon_view_->SetBorder(views::CreateEmptyBorder(
-        gfx::Insets::TLBR(0, 0, 0, kLeadingIconRightPadding)));
+    leading_icon_view_->SetPreferredSize(
+        gfx::Size(kLeadingIconSize, kLeadingIconSize));
+    auto* icon_padding = AddChildView(std::make_unique<views::View>());
+    icon_padding->SetPreferredSize(
+        gfx::Size(kLeadingIconRightPadding, kLeadingIconSize));
   }
 
   label_ = AddChildView(std::make_unique<SystemToastInnerLabel>(text));
diff --git a/ash/system/camera/autozoom_toast_controller.cc b/ash/system/camera/autozoom_toast_controller.cc
index cb621c3..a29b81a0 100644
--- a/ash/system/camera/autozoom_toast_controller.cc
+++ b/ash/system/camera/autozoom_toast_controller.cc
@@ -88,8 +88,7 @@
   StartAutoCloseTimer();
   UpdateToastView();
 
-  tray_->SetTrayBubbleHeight(
-      bubble_widget_->GetWindowBoundsInScreen().height());
+  tray_->NotifySecondaryBubbleHeight(toast_view_->height());
 }
 
 void AutozoomToastController::HideToast() {
@@ -97,7 +96,7 @@
   if (!bubble_widget_ || bubble_widget_->IsClosed())
     return;
   bubble_widget_->Close();
-  tray_->SetTrayBubbleHeight(0);
+  tray_->NotifySecondaryBubbleHeight(0);
 }
 
 void AutozoomToastController::BubbleViewDestroyed() {
diff --git a/ash/system/cast/cast_zero_state_view.cc b/ash/system/cast/cast_zero_state_view.cc
index 47c23ea9..40f8810f 100644
--- a/ash/system/cast/cast_zero_state_view.cc
+++ b/ash/system/cast/cast_zero_state_view.cc
@@ -33,7 +33,7 @@
 
   // The zero-state view are inside a rounded container.
   auto* container = AddChildView(std::make_unique<RoundedContainer>());
-  container->SetBorderInsets(gfx::Insets::VH(0, 32));
+  container->SetBorderInsets(gfx::Insets::VH(0, 16));
 
   // The views are centered vertically.
   std::unique_ptr<BoxLayout> layout =
@@ -53,6 +53,7 @@
 
   Label* title = container->AddChildView(std::make_unique<Label>(
       l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_ZERO_STATE_TITLE)));
+  title->SetMultiLine(true);
   bubble_utils::ApplyStyle(title, TypographyToken::kCrosTitle1);
   title->SetEnabledColorId(cros_tokens::kCrosSysOnSurface);
   title->SetProperty(views::kMarginsKey, gfx::Insets::TLBR(32, 0, 0, 0));
diff --git a/ash/system/message_center/ash_message_popup_collection.cc b/ash/system/message_center/ash_message_popup_collection.cc
index f85b34b..57f67796c 100644
--- a/ash/system/message_center/ash_message_popup_collection.cc
+++ b/ash/system/message_center/ash_message_popup_collection.cc
@@ -48,7 +48,7 @@
     "ash/message_center/MessagePopup";
 
 AshMessagePopupCollection::AshMessagePopupCollection(Shelf* shelf)
-    : screen_(nullptr), shelf_(shelf), tray_bubble_height_(0) {
+    : screen_(nullptr), shelf_(shelf) {
   shelf_->AddObserver(this);
   Shell::Get()->tablet_mode_controller()->AddObserver(this);
 }
@@ -67,41 +67,43 @@
   screen_ = screen;
   work_area_ = display.work_area();
   display_observer_.emplace(this);
-  if (tray_bubble_height_ > 0)
+  if (baseline_offset_ > 0) {
     UpdateWorkArea();
+  }
 }
 
-void AshMessagePopupCollection::SetTrayBubbleHeight(int height) {
-  const int old_tray_bubble_height = tray_bubble_height_;
+void AshMessagePopupCollection::SetBaselineOffset(int baseline_offset) {
+  const int old_baseline_offset = baseline_offset_;
 
-  tray_bubble_height_ = height;
+  baseline_offset_ = baseline_offset;
 
   // If the shelf is shown during auto-hide state, the distance from the edge
   // should be reduced by the height of shelf's shown height.
   if (shelf_->GetVisibilityState() == SHELF_AUTO_HIDE &&
       shelf_->GetAutoHideState() == SHELF_AUTO_HIDE_SHOWN) {
-    tray_bubble_height_ -= ShelfConfig::Get()->shelf_size();
+    baseline_offset_ -= ShelfConfig::Get()->shelf_size();
   }
 
-  if (tray_bubble_height_ > 0)
-    tray_bubble_height_ += message_center::kMarginBetweenPopups;
-  else
-    tray_bubble_height_ = 0;
+  if (baseline_offset_ > 0) {
+    baseline_offset_ += message_center::kMarginBetweenPopups;
+  } else {
+    baseline_offset_ = 0;
+  }
 
-  if (old_tray_bubble_height != tray_bubble_height_)
+  if (old_baseline_offset != baseline_offset_) {
     ResetBounds();
+  }
 }
 
 int AshMessagePopupCollection::GetPopupOriginX(
     const gfx::Rect& popup_bounds) const {
-  // In Ash, RTL UI language mirrors the whole ash layout, so the popup
-  // widgets should be at the bottom-left instead of bottom right.
-  if (base::i18n::IsRTL())
-    return work_area_.x() + kPopupMarginX;
-
-  if (IsFromLeft())
-    return work_area_.x() + kPopupMarginX;
-  return work_area_.right() - kPopupMarginX - popup_bounds.width();
+  // Popups should always follow the status area and will usually show on the
+  // bottom-right of the screen. They will show at the bottom-left whenever the
+  // shelf is left-aligned or for RTL when the shelf is not right aligned.
+  return ((base::i18n::IsRTL() && GetAlignment() != ShelfAlignment::kRight) ||
+          IsFromLeft())
+             ? work_area_.x() + kPopupMarginX
+             : work_area_.right() - kPopupMarginX - popup_bounds.width();
 }
 
 int AshMessagePopupCollection::GetBaseline() const {
@@ -113,14 +115,14 @@
 
   // Decrease baseline by `kShelfDisplayOffset` to compensate for the adjustment
   // of edges in `Shelf::GetSystemTrayAnchorRect()`.
-  return work_area_.bottom() - tray_bubble_insets.bottom() -
-         tray_bubble_height_ - hotseat_height - kShelfDisplayOffset;
+  return work_area_.bottom() - tray_bubble_insets.bottom() - baseline_offset_ -
+         hotseat_height - kShelfDisplayOffset;
 }
 
 gfx::Rect AshMessagePopupCollection::GetWorkArea() const {
   gfx::Rect work_area_without_tray_bubble = work_area_;
   work_area_without_tray_bubble.set_height(
-      work_area_without_tray_bubble.height() - tray_bubble_height_);
+      work_area_without_tray_bubble.height() - baseline_offset_);
   return work_area_without_tray_bubble;
 }
 
diff --git a/ash/system/message_center/ash_message_popup_collection.h b/ash/system/message_center/ash_message_popup_collection.h
index 837d65fd..f78730e 100644
--- a/ash/system/message_center/ash_message_popup_collection.h
+++ b/ash/system/message_center/ash_message_popup_collection.h
@@ -56,9 +56,9 @@
   // Start observing the system.
   void StartObserving(display::Screen* screen, const display::Display& display);
 
-  // Sets the current height of the system tray bubble (or legacy notification
-  // bubble) so that notification toasts can avoid it.
-  void SetTrayBubbleHeight(int height);
+  // Sets an offset from the baseline so that notification popups can shift up
+  // without overlapping with slider bubbles.
+  void SetBaselineOffset(int baseline_offset);
 
   // message_center::MessagePopupCollection:
   int GetPopupOriginX(const gfx::Rect& popup_bounds) const override;
@@ -87,8 +87,8 @@
   // Sets `animation_idle_closure_`.
   void SetAnimationIdleClosureForTest(base::OnceClosure closure);
 
-  // Returns the current tray bubble height or 0 if there is no bubble.
-  int tray_bubble_height_for_test() const { return tray_bubble_height_; }
+  // Returns the current baseline offset.
+  int baseline_offset_for_test() const { return baseline_offset_; }
 
   int popups_animating_for_test() const { return popups_animating_; }
 
@@ -129,7 +129,7 @@
   raw_ptr<display::Screen, ExperimentalAsh> screen_;
   gfx::Rect work_area_;
   raw_ptr<Shelf, ExperimentalAsh> shelf_;
-  int tray_bubble_height_;
+  int baseline_offset_ = 0;
 
   std::set<views::Widget*> tracked_widgets_;
 
diff --git a/ash/system/message_center/ash_message_popup_collection_unittest.cc b/ash/system/message_center/ash_message_popup_collection_unittest.cc
index 1fd883a1..9f23f73 100644
--- a/ash/system/message_center/ash_message_popup_collection_unittest.cc
+++ b/ash/system/message_center/ash_message_popup_collection_unittest.cc
@@ -262,19 +262,20 @@
   EXPECT_LT(baseline, popup_collection()->GetBaseline());
 }
 
-TEST_P(AshMessagePopupCollectionTest, TrayHeight) {
+TEST_P(AshMessagePopupCollectionTest, BaselineOffset) {
   const gfx::Rect popup_size(0, 0, 10, 10);
   UpdateDisplay("601x600");
   int origin_x = popup_collection()->GetPopupOriginX(popup_size);
   int baseline = popup_collection()->GetBaseline();
 
-  // Simulate the system tray bubble being open.
-  const int kTrayHeight = 100;
-  popup_collection()->SetTrayBubbleHeight(kTrayHeight);
+  // Simulate a secondary bubble (e.g. QS slider) being shown on screen.
+  const int kSecondaryBubbleHeight = 100;
+  popup_collection()->SetBaselineOffset(kSecondaryBubbleHeight);
 
   EXPECT_EQ(origin_x, popup_collection()->GetPopupOriginX(popup_size));
-  EXPECT_EQ(baseline - kTrayHeight - message_center::kMarginBetweenPopups,
-            popup_collection()->GetBaseline());
+  EXPECT_EQ(
+      baseline - kSecondaryBubbleHeight - message_center::kMarginBetweenPopups,
+      popup_collection()->GetBaseline());
 }
 
 TEST_P(AshMessagePopupCollectionTest, Extended) {
diff --git a/ash/system/message_center/ash_notification_input_container.cc b/ash/system/message_center/ash_notification_input_container.cc
index d805061..1dd2849 100644
--- a/ash/system/message_center/ash_notification_input_container.cc
+++ b/ash/system/message_center/ash_notification_input_container.cc
@@ -8,7 +8,9 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/style/typography.h"
 #include "ash/system/message_center/message_center_constants.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/color/color_id.h"
 #include "ui/gfx/font_list.h"
@@ -72,15 +74,17 @@
 }
 
 void AshNotificationInputContainer::StyleTextfield() {
-  textfield()->SetFontList(gfx::FontList({kGoogleSansFont}, gfx::Font::NORMAL,
-                                         kNotificationBodyFontWeight,
-                                         gfx::Font::Weight::MEDIUM));
-  auto* color_provider = ash::AshColorProvider::Get();
-  textfield()->SetBackground(views::CreateRoundedRectBackground(
-      color_provider->GetControlsLayerColor(
-          ash::AshColorProvider::ControlsLayerType::
-              kControlBackgroundColorInactive),
-      kTextfieldBackgroundCornerRadius));
+  if (!chromeos::features::IsJellyEnabled()) {
+    textfield()->SetFontList(gfx::FontList({kGoogleSansFont}, gfx::Font::NORMAL,
+                                           kNotificationBodyFontWeight,
+                                           gfx::Font::Weight::MEDIUM));
+    auto* color_provider = ash::AshColorProvider::Get();
+    textfield()->SetBackground(views::CreateRoundedRectBackground(
+        color_provider->GetControlsLayerColor(
+            ash::AshColorProvider::ControlsLayerType::
+                kControlBackgroundColorInactive),
+        kTextfieldBackgroundCornerRadius));
+  }
 
   views::FocusRing::Install(textfield());
   views::InstallRoundRectHighlightPathGenerator(
@@ -126,6 +130,23 @@
   UpdateButtonImage();
   SetSendButtonHighlightPath();
   StyleTextfield();
+
+  if (chromeos::features::IsJellyEnabled()) {
+    textfield()->SetTextColor(
+        GetColorProvider()->GetColor(cros_tokens::kCrosSysOnSurface));
+    textfield()->SetFontList(
+        ash::TypographyProvider::Get()->ResolveTypographyToken(
+            ash::TypographyToken::kCrosBody2));
+    textfield()->set_placeholder_text_color(
+        GetColorProvider()->GetColor(cros_tokens::kCrosSysOnSurfaceVariant));
+    textfield()->set_placeholder_font_list(
+        ash::TypographyProvider::Get()->ResolveTypographyToken(
+            ash::TypographyToken::kCrosBody2));
+
+    textfield()->SetBackground(views::CreateRoundedRectBackground(
+        GetColorProvider()->GetColor(cros_tokens::kCrosSysSurface),
+        kTextfieldBackgroundCornerRadius));
+  }
 }
 
 }  // namespace ash
diff --git a/ash/system/message_center/ash_notification_view.cc b/ash/system/message_center/ash_notification_view.cc
index e93ce2b..e7e74264 100644
--- a/ash/system/message_center/ash_notification_view.cc
+++ b/ash/system/message_center/ash_notification_view.cc
@@ -1228,10 +1228,12 @@
     }
   }
   if (inline_reply()) {
-    SkColor text_color = ash::AshColorProvider::Get()->GetContentLayerColor(
-        ash::AshColorProvider::ContentLayerType::kTextColorSecondary);
-    inline_reply()->textfield()->SetTextColor(text_color);
-    inline_reply()->textfield()->set_placeholder_text_color(text_color);
+    if (!chromeos::features::IsJellyEnabled()) {
+      SkColor text_color = ash::AshColorProvider::Get()->GetContentLayerColor(
+          ash::AshColorProvider::ContentLayerType::kTextColorSecondary);
+      inline_reply()->textfield()->SetTextColor(text_color);
+      inline_reply()->textfield()->set_placeholder_text_color(text_color);
+    }
   }
 }
 
@@ -1347,10 +1349,20 @@
   // bar. This is the opposite of what is required of the chrome notification.
   CreateOrUpdateProgressStatusView(notification);
   CreateOrUpdateProgressBarView(notification);
+  if (progress_bar_view() && chromeos::features::IsJellyEnabled()) {
+    progress_bar_view()->SetForegroundColorId(cros_tokens::kCrosSysPrimary);
+    progress_bar_view()->SetBackgroundColorId(
+        cros_tokens::kCrosSysHighlightShape);
+  }
 
   if (status_view()) {
     status_view()->SetMultiLine(true);
     status_view()->SetMaxLines(message_center::kMaxLinesForStatusView);
+    if (chromeos::features::IsJellyEnabled()) {
+      status_view()->SetEnabledColorId(cros_tokens::kCrosSysOnSurfaceVariant);
+      TypographyProvider::Get()->StyleLabel(TypographyToken::kCrosAnnotation1,
+                                            *status_view());
+    }
   }
 }
 
@@ -1429,10 +1441,17 @@
           notification_id()));
 
   if (inline_reply()) {
-    SkColor text_color = ash::AshColorProvider::Get()->GetContentLayerColor(
-        ash::AshColorProvider::ContentLayerType::kTextColorSecondary);
-    inline_reply()->textfield()->SetTextColor(text_color);
-    inline_reply()->textfield()->set_placeholder_text_color(text_color);
+    if (chromeos::features::IsJellyEnabled()) {
+      inline_reply()->textfield()->SetTextColor(
+          GetColorProvider()->GetColor(cros_tokens::kCrosSysOnSurface));
+      inline_reply()->textfield()->set_placeholder_text_color(
+          GetColorProvider()->GetColor(cros_tokens::kCrosSysOnSurfaceVariant));
+    } else {
+      SkColor text_color = ash::AshColorProvider::Get()->GetContentLayerColor(
+          ash::AshColorProvider::ContentLayerType::kTextColorSecondary);
+      inline_reply()->textfield()->SetTextColor(text_color);
+      inline_reply()->textfield()->set_placeholder_text_color(text_color);
+    }
   }
 
   if (icon_view() &&
diff --git a/ash/system/message_center/ash_notification_view_pixeltest.cc b/ash/system/message_center/ash_notification_view_pixeltest.cc
index b3f748b..77f2bf7 100644
--- a/ash/system/message_center/ash_notification_view_pixeltest.cc
+++ b/ash/system/message_center/ash_notification_view_pixeltest.cc
@@ -159,7 +159,7 @@
   // Compare pixels.
   const std::string screenshot = GetParam().second;
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
-      screenshot, /*revision_number=*/1, notification_view));
+      screenshot, /*revision_number=*/2, notification_view));
 }
 
 class ScreenCaptureNotificationPixelTest
@@ -224,7 +224,7 @@
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       base::StrCat({"screen_capture_popup_notification_",
                     GetDisplayTypeName(GetParam())}),
-      /*revision_number=*/0,
+      /*revision_number=*/1,
       test_api()->GetPopupViewForId(kScreenCaptureNotificationId)));
 }
 
diff --git a/ash/system/phonehub/app_stream_connection_error_dialog.cc b/ash/system/phonehub/app_stream_connection_error_dialog.cc
index 603a198..55db34e7 100644
--- a/ash/system/phonehub/app_stream_connection_error_dialog.cc
+++ b/ash/system/phonehub/app_stream_connection_error_dialog.cc
@@ -44,7 +44,9 @@
 
 namespace {
 
-constexpr int kDialogVerticalMargin = 50;
+// Offset to place dialog in the vertical center of bubble due to
+// PhoneStatusView.
+constexpr int kDialogVerticalOffset = 25;
 
 constexpr int kDialogWidth = 330;
 
@@ -304,20 +306,16 @@
     return;
   }
 
-  gfx::Point anchor_point_in_screen(host_view_->width() / 2, 0);
+  gfx::Point anchor_point_in_screen(host_view_->width() / 2,
+                                    host_view_->height() / 2);
   views::View::ConvertPointToScreen(host_view_, &anchor_point_in_screen);
 
-  const int offset_for_frame_insets =
-      widget_->non_client_view() && widget_->non_client_view()->frame_view()
-          ? widget_->non_client_view()->frame_view()->GetInsets().top()
-          : 0;
-  const int vertical_offset = kDialogVerticalMargin - offset_for_frame_insets;
-
   gfx::Size dialog_size = widget_->GetContentsView()->GetPreferredSize();
-  widget_->SetBounds(
-      gfx::Rect(gfx::Point(anchor_point_in_screen.x() - dialog_size.width() / 2,
-                           anchor_point_in_screen.y() + vertical_offset),
-                dialog_size));
+  widget_->SetBounds(gfx::Rect(
+      gfx::Point(anchor_point_in_screen.x() - dialog_size.width() / 2,
+                 anchor_point_in_screen.y() - dialog_size.height() / 2 -
+                     kDialogVerticalOffset),
+      dialog_size));
 }
 
 void AppStreamConnectionErrorDialog::OnWidgetDestroying(views::Widget* widget) {
diff --git a/ash/system/phonehub/phone_hub_recent_apps_view.cc b/ash/system/phonehub/phone_hub_recent_apps_view.cc
index c0bd89b..9a0635d 100644
--- a/ash/system/phonehub/phone_hub_recent_apps_view.cc
+++ b/ash/system/phonehub/phone_hub_recent_apps_view.cc
@@ -411,9 +411,11 @@
     case RecentAppsUiState::PLACEHOLDER_VIEW:
       recent_app_buttons_view_->SetVisible(false);
       placeholder_view_->SetVisible(true);
-      header_view_->SetErrorButtonVisible(false);
-      if (loading_view_) {
-        loading_view_->SetVisible(false);
+      if (features::IsEcheNetworkConnectionStateEnabled()) {
+        header_view_->SetErrorButtonVisible(false);
+        if (loading_view_) {
+          loading_view_->SetVisible(false);
+        }
       }
       SetVisible(true);
       break;
diff --git a/ash/system/privacy_screen/privacy_screen_toast_controller.cc b/ash/system/privacy_screen/privacy_screen_toast_controller.cc
index 6be66c3a..7397f8c 100644
--- a/ash/system/privacy_screen/privacy_screen_toast_controller.cc
+++ b/ash/system/privacy_screen/privacy_screen_toast_controller.cc
@@ -70,8 +70,7 @@
   StartAutoCloseTimer();
   UpdateToastView();
 
-  tray_->SetTrayBubbleHeight(
-      bubble_widget_->GetWindowBoundsInScreen().height());
+  tray_->NotifySecondaryBubbleHeight(toast_view_->height());
 
   // Activate the bubble so ChromeVox can announce the toast.
   if (Shell::Get()->accessibility_controller()->spoken_feedback().enabled()) {
@@ -85,7 +84,7 @@
   if (!bubble_widget_ || bubble_widget_->IsClosed())
     return;
   bubble_widget_->Close();
-  tray_->SetTrayBubbleHeight(0);
+  tray_->NotifySecondaryBubbleHeight(0);
 }
 
 void PrivacyScreenToastController::BubbleViewDestroyed() {
diff --git a/ash/system/toast/toast_manager_impl.cc b/ash/system/toast/toast_manager_impl.cc
index 210bc03..e15aefb 100644
--- a/ash/system/toast/toast_manager_impl.cc
+++ b/ash/system/toast/toast_manager_impl.cc
@@ -278,7 +278,6 @@
   new_overlay = std::make_unique<ToastOverlay>(
       this, current_toast_data_->text, current_toast_data_->dismiss_text,
       *current_toast_data_->leading_icon, current_toast_data_->duration,
-      current_toast_data_->visible_on_lock_screen && locked_,
       current_toast_data_->persist_on_hover, root_window,
       current_toast_data_->dismiss_callback);
   new_overlay->Show(true);
diff --git a/ash/system/toast/toast_manager_unittest.cc b/ash/system/toast/toast_manager_unittest.cc
index 7a6f38e..5249a8d 100644
--- a/ash/system/toast/toast_manager_unittest.cc
+++ b/ash/system/toast/toast_manager_unittest.cc
@@ -30,6 +30,7 @@
 #include "base/task/single_thread_task_runner.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 "components/session_manager/session_manager_types.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -86,7 +87,8 @@
 
 namespace ash {
 
-class ToastManagerImplTest : public AshTestBase {
+class ToastManagerImplTest : public AshTestBase,
+                             public testing::WithParamInterface<bool> {
  public:
   ToastManagerImplTest()
       : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
@@ -96,8 +98,10 @@
 
   ~ToastManagerImplTest() override = default;
 
- private:
   void SetUp() override {
+    scoped_feature_list_.InitWithFeatureState(features::kSideAlignedToasts,
+                                              AreSideAlignedToastsEnabled());
+
     AshTestBase::SetUp();
 
     manager_ = Shell::Get()->toast_manager();
@@ -109,6 +113,8 @@
     ChangeLockState(false);
   }
 
+  bool AreSideAlignedToastsEnabled() const { return GetParam(); }
+
  protected:
   ToastManagerImpl* manager() { return manager_; }
 
@@ -121,6 +127,10 @@
     return manager_->GetCurrentOverlayForTesting(root_window);
   }
 
+  gfx::Rect GetToastBounds() {
+    return GetCurrentWidget()->GetWindowBoundsInScreen();
+  }
+
   views::Widget* GetCurrentWidget(
       aura::Window* root_window = Shell::GetRootWindowForNewWindows()) {
     ToastOverlay* overlay = GetCurrentOverlay(root_window);
@@ -216,9 +226,14 @@
  private:
   raw_ptr<ToastManagerImpl, ExperimentalAsh> manager_ = nullptr;
   unsigned int serial_ = 0;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-TEST_F(ToastManagerImplTest, ShowAndCloseAutomatically) {
+INSTANTIATE_TEST_SUITE_P(All,
+                         ToastManagerImplTest,
+                         testing::Bool() /* AreSideAlignedToastsEnabled() */);
+
+TEST_P(ToastManagerImplTest, ShowAndCloseAutomatically) {
   ShowToast("DUMMY", base::Milliseconds(10));
 
   EXPECT_EQ(1, GetToastSerial());
@@ -227,7 +242,7 @@
   EXPECT_FALSE(GetCurrentOverlay());
 }
 
-TEST_F(ToastManagerImplTest, ShowAndCloseManually) {
+TEST_P(ToastManagerImplTest, ShowAndCloseManually) {
   ShowToastWithDismiss("DUMMY", ToastData::kInfiniteDuration, u"Dismiss");
 
   EXPECT_EQ(1, GetToastSerial());
@@ -239,7 +254,7 @@
   EXPECT_EQ(nullptr, GetCurrentOverlay());
 }
 
-TEST_F(ToastManagerImplTest, ShowAndCloseManuallyDuringAnimation) {
+TEST_P(ToastManagerImplTest, ShowAndCloseManuallyDuringAnimation) {
   ui::ScopedAnimationDurationScaleMode slow_animation_duration(
       ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
 
@@ -259,7 +274,7 @@
   base::RunLoop().RunUntilIdle();
 }
 
-TEST_F(ToastManagerImplTest, QueueMessage) {
+TEST_P(ToastManagerImplTest, QueueMessage) {
   const base::TimeDelta kDelay = ToastData::kMinimumDuration;
 
   ShowToast("DUMMY1", kDelay);
@@ -282,7 +297,7 @@
   EXPECT_EQ(u"DUMMY3", GetCurrentText());
 }
 
-TEST_F(ToastManagerImplTest, PositionWithVisibleBottomShelf) {
+TEST_P(ToastManagerImplTest, PositionWithVisibleBottomShelf) {
   Shelf* shelf = GetPrimaryShelf();
   EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
@@ -290,13 +305,19 @@
   ShowToast("DUMMY", ToastData::kInfiniteDuration);
   EXPECT_EQ(1, GetToastSerial());
 
-  gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
+  gfx::Rect toast_bounds = GetToastBounds();
   gfx::Rect root_bounds =
       screen_util::GetDisplayBoundsWithShelf(shelf->GetWindow());
 
   EXPECT_TRUE(toast_bounds.Intersects(
       GetPrimaryWorkAreaInsets()->user_work_area_bounds()));
-  EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(), 1);
+  if (AreSideAlignedToastsEnabled()) {
+    EXPECT_EQ(root_bounds.right(),
+              toast_bounds.right() + ToastOverlay::kOffset);
+  } else {
+    EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(),
+                1);
+  }
 
   gfx::Rect shelf_bounds = shelf->GetIdealBounds();
   EXPECT_FALSE(toast_bounds.Intersects(shelf_bounds));
@@ -306,7 +327,7 @@
       toast_bounds.bottom());
 }
 
-TEST_F(ToastManagerImplTest, PositionWithHotseatShown) {
+TEST_P(ToastManagerImplTest, PositionWithHotseatShown) {
   Shelf* shelf = GetPrimaryShelf();
   TabletModeController* tablet_mode_controller =
       Shell::Get()->tablet_mode_controller();
@@ -318,7 +339,7 @@
   tablet_mode_controller->SetEnabledForTest(true);
   ShowToast("DUMMY", ToastData::kInfiniteDuration);
 
-  gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
+  gfx::Rect toast_bounds = GetToastBounds();
   gfx::Rect hotseat_bounds = hotseat->GetWindowBoundsInScreen();
 
   EXPECT_EQ(hotseat->state(), HotseatState::kShownHomeLauncher);
@@ -329,7 +350,7 @@
             toast_bounds.bottom());
 }
 
-TEST_F(ToastManagerImplTest, PositionWithHotseatExtended) {
+TEST_P(ToastManagerImplTest, PositionWithHotseatExtended) {
   Shelf* shelf = GetPrimaryShelf();
   TabletModeController* tablet_mode_controller =
       Shell::Get()->tablet_mode_controller();
@@ -342,7 +363,7 @@
   hotseat->SetState(HotseatState::kExtended);
   ShowToast("DUMMY", ToastData::kInfiniteDuration);
 
-  gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
+  gfx::Rect toast_bounds = GetToastBounds();
   gfx::Rect hotseat_bounds = hotseat->GetWindowBoundsInScreen();
 
   EXPECT_FALSE(toast_bounds.Intersects(hotseat_bounds));
@@ -352,7 +373,7 @@
             toast_bounds.bottom());
 }
 
-TEST_F(ToastManagerImplTest, PositionWithHotseatShownForMultipleMonitors) {
+TEST_P(ToastManagerImplTest, PositionWithHotseatShownForMultipleMonitors) {
   UpdateDisplay("600x400,600x400");
   Shelf* shelf = GetPrimaryShelf();
   TabletModeController* tablet_mode_controller =
@@ -367,7 +388,7 @@
 
   ShowToast("DUMMY", ToastData::kInfiniteDuration);
 
-  gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
+  gfx::Rect toast_bounds = GetToastBounds();
   gfx::Rect hotseat_bounds = hotseat->GetWindowBoundsInScreen();
 
   EXPECT_EQ(hotseat->state(), HotseatState::kShownHomeLauncher);
@@ -378,7 +399,62 @@
             toast_bounds.bottom());
 }
 
-TEST_F(ToastManagerImplTest, PositionWithHotseatExtendedOnSecondMonitor) {
+// Tests that `ToastOverlay`'s are cleaned up properly on shutdown with hotseat
+// extended on multi-monitor
+TEST_P(ToastManagerImplTest, ShutdownWithExtendedHotseat) {
+  UpdateDisplay("600x400,600x400");
+  Shelf* const shelf =
+      Shell::GetRootWindowControllerWithDisplayId(GetSecondaryDisplay().id())
+          ->shelf();
+  EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
+  EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
+
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  display_manager()->SetMirrorMode(display::MirrorMode::kOff, absl::nullopt);
+
+  std::unique_ptr<aura::Window> window(
+      CreateTestWindow(gfx::Rect(700, 100, 200, 200)));
+
+  GetPrimaryShelf()->hotseat_widget()->SetState(HotseatState::kExtended);
+
+  ShowToast("DUMMY", ToastData::kInfiniteDuration);
+
+  // Shutdown, there should be no crash.
+}
+
+// Tests that toasts that observe UnifiedSystemTray and are shown in
+// multiple displays are properly destroyed after disconnecting a monitor.
+TEST_P(ToastManagerImplTest, ToastsOnMultipleMonitors) {
+  UpdateDisplay("800x700,800x700");
+  auto* toast_manager = manager();
+
+  std::string toast_id = "TOAST_ID_" + base::NumberToString(GetToastSerial());
+
+  // Create a basic toast with `ToastData::kDefaultToastDuration` as duration.
+  ToastData toast_data(toast_id, ToastCatalogName::kToastManagerUnittest,
+                       /*text=*/u"");
+
+  // Indicate that the toast will show on all root windows.
+  toast_data.show_on_all_root_windows = true;
+
+  toast_manager->Show(std::move(toast_data));
+  ASSERT_TRUE(toast_manager->IsRunning(toast_id));
+  for (auto* root_window : Shell::GetAllRootWindows()) {
+    ASSERT_TRUE(GetCurrentOverlay(root_window));
+  }
+
+  // Wait for half of the toast duration to elapse.
+  WaitForTimeDelta(ToastData::kDefaultToastDuration / 2);
+
+  // Remove a display to trigger the destruction of a toast overlay.
+  UpdateDisplay("800x700");
+  ASSERT_EQ(1u, Shell::GetAllRootWindows().size());
+  ASSERT_TRUE(toast_manager->IsRunning(toast_id));
+
+  // No crash should happen.
+}
+
+TEST_P(ToastManagerImplTest, PositionWithHotseatExtendedOnSecondMonitor) {
   UpdateDisplay("600x400,700x400");
   RootWindowController* const secondary_root_window_controller =
       Shell::GetRootWindowControllerWithDisplayId(GetSecondaryDisplay().id());
@@ -403,7 +479,7 @@
 
   ShowToast("DUMMY", ToastData::kInfiniteDuration);
 
-  gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
+  gfx::Rect toast_bounds = GetToastBounds();
   gfx::Rect hotseat_bounds = hotseat->GetWindowBoundsInScreen();
 
   EXPECT_EQ(hotseat->state(), HotseatState::kExtended);
@@ -416,7 +492,7 @@
             toast_bounds.bottom());
 }
 
-TEST_F(ToastManagerImplTest, PositionWithHotseatExtendedOnAnotherMonitor) {
+TEST_P(ToastManagerImplTest, PositionWithHotseatExtendedOnAnotherMonitor) {
   UpdateDisplay("600x400,700x400");
   RootWindowController* const secondary_root_window_controller =
       Shell::GetRootWindowControllerWithDisplayId(GetSecondaryDisplay().id());
@@ -457,7 +533,7 @@
             toast_bounds.bottom());
 }
 
-TEST_F(ToastManagerImplTest, PositionWithAutoHiddenBottomShelf) {
+TEST_P(ToastManagerImplTest, PositionWithAutoHiddenBottomShelf) {
   std::unique_ptr<aura::Window> window(
       CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
 
@@ -469,20 +545,26 @@
   ShowToast("DUMMY", ToastData::kInfiniteDuration);
   EXPECT_EQ(1, GetToastSerial());
 
-  gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
+  gfx::Rect toast_bounds = GetToastBounds();
   gfx::Rect root_bounds =
       screen_util::GetDisplayBoundsWithShelf(shelf->GetWindow());
 
   EXPECT_TRUE(toast_bounds.Intersects(
       GetPrimaryWorkAreaInsets()->user_work_area_bounds()));
-  EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(), 1);
+  if (AreSideAlignedToastsEnabled()) {
+    EXPECT_EQ(root_bounds.right(),
+              toast_bounds.right() + ToastOverlay::kOffset);
+  } else {
+    EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(),
+                1);
+  }
   EXPECT_EQ(root_bounds.bottom() -
                 ShelfConfig::Get()->hidden_shelf_in_screen_portion() -
                 ToastOverlay::kOffset,
             toast_bounds.bottom());
 }
 
-TEST_F(ToastManagerImplTest, PositionWithHiddenBottomShelf) {
+TEST_P(ToastManagerImplTest, PositionWithHiddenBottomShelf) {
   Shelf* shelf = GetPrimaryShelf();
   EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
   shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlwaysHidden);
@@ -491,43 +573,62 @@
   ShowToast("DUMMY", ToastData::kInfiniteDuration);
   EXPECT_EQ(1, GetToastSerial());
 
-  gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
+  gfx::Rect toast_bounds = GetToastBounds();
   gfx::Rect root_bounds =
       screen_util::GetDisplayBoundsWithShelf(shelf->GetWindow());
 
   EXPECT_TRUE(toast_bounds.Intersects(
       GetPrimaryWorkAreaInsets()->user_work_area_bounds()));
-  EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(), 1);
+  if (AreSideAlignedToastsEnabled()) {
+    EXPECT_EQ(root_bounds.right(),
+              toast_bounds.right() + ToastOverlay::kOffset);
+  } else {
+    EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(),
+                1);
+  }
   EXPECT_EQ(root_bounds.bottom() - ToastOverlay::kOffset,
             toast_bounds.bottom());
 }
 
-TEST_F(ToastManagerImplTest, PositionWithVisibleLeftShelf) {
+// Tests that toasts follow the shelf when aligning it to the side.
+// Toasts should stay at center of the work area if side aligned toasts are not
+// enabled.
+TEST_P(ToastManagerImplTest, PositionWithVisibleSideShelf) {
   Shelf* shelf = GetPrimaryShelf();
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
-  shelf->SetAlignment(ShelfAlignment::kLeft);
 
   ShowToast("DUMMY", ToastData::kInfiniteDuration);
   EXPECT_EQ(1, GetToastSerial());
 
-  gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
-  gfx::RectF precise_toast_bounds(toast_bounds);
-  gfx::Rect root_bounds =
-      screen_util::GetDisplayBoundsWithShelf(shelf->GetWindow());
+  gfx::Rect work_area_bounds;
+  gfx::Rect shelf_bounds;
 
-  EXPECT_TRUE(toast_bounds.Intersects(
-      GetPrimaryWorkAreaInsets()->user_work_area_bounds()));
-  EXPECT_EQ(root_bounds.bottom() - ToastOverlay::kOffset,
-            toast_bounds.bottom());
+  shelf->SetAlignment(ShelfAlignment::kLeft);
+  work_area_bounds = GetPrimaryWorkAreaInsets()->user_work_area_bounds();
+  shelf_bounds = shelf->GetIdealBounds();
+  EXPECT_FALSE(GetToastBounds().Intersects(shelf_bounds));
+  if (AreSideAlignedToastsEnabled()) {
+    EXPECT_EQ(work_area_bounds.x(),
+              GetToastBounds().x() - ToastOverlay::kOffset);
+  } else {
+    EXPECT_NEAR(work_area_bounds.CenterPoint().x(),
+                GetToastBounds().CenterPoint().x(), 1);
+  }
 
-  gfx::Rect shelf_bounds = shelf->GetIdealBounds();
-  EXPECT_FALSE(toast_bounds.Intersects(shelf_bounds));
-  EXPECT_NEAR(
-      shelf_bounds.right() + (root_bounds.width() - shelf_bounds.width()) / 2.0,
-      precise_toast_bounds.CenterPoint().x(), 1.f /* accepted error */);
+  shelf->SetAlignment(ShelfAlignment::kRight);
+  work_area_bounds = GetPrimaryWorkAreaInsets()->user_work_area_bounds();
+  shelf_bounds = shelf->GetIdealBounds();
+  EXPECT_FALSE(GetToastBounds().Intersects(shelf_bounds));
+  if (AreSideAlignedToastsEnabled()) {
+    EXPECT_EQ(work_area_bounds.right(),
+              GetToastBounds().right() + ToastOverlay::kOffset);
+  } else {
+    EXPECT_NEAR(work_area_bounds.CenterPoint().x(),
+                GetToastBounds().CenterPoint().x(), 1);
+  }
 }
 
-TEST_F(ToastManagerImplTest, PositionWithUnifiedDesktop) {
+TEST_P(ToastManagerImplTest, PositionWithUnifiedDesktop) {
   display_manager()->SetUnifiedDesktopEnabled(true);
   UpdateDisplay("1000x500,0+600-100x500");
 
@@ -538,14 +639,20 @@
   ShowToast("DUMMY", ToastData::kInfiniteDuration);
   EXPECT_EQ(1, GetToastSerial());
 
-  gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
+  gfx::Rect toast_bounds = GetToastBounds();
   gfx::Rect root_bounds =
       screen_util::GetDisplayBoundsWithShelf(shelf->GetWindow());
 
   EXPECT_TRUE(toast_bounds.Intersects(
       GetPrimaryWorkAreaInsets()->user_work_area_bounds()));
   EXPECT_TRUE(root_bounds.Contains(toast_bounds));
-  EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(), 1);
+  if (AreSideAlignedToastsEnabled()) {
+    EXPECT_EQ(root_bounds.right(),
+              toast_bounds.right() + ToastOverlay::kOffset);
+  } else {
+    EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(),
+                1);
+  }
 
   gfx::Rect shelf_bounds = shelf->GetIdealBounds();
   EXPECT_FALSE(toast_bounds.Intersects(shelf_bounds));
@@ -555,7 +662,7 @@
       toast_bounds.bottom());
 }
 
-TEST_F(ToastManagerImplTest, CancelToast) {
+TEST_P(ToastManagerImplTest, CancelToast) {
   std::string id1 = ShowToast("TEXT1", ToastData::kInfiniteDuration);
   std::string id2 = ShowToast("TEXT2", ToastData::kInfiniteDuration);
   std::string id3 = ShowToast("TEXT3", ToastData::kInfiniteDuration);
@@ -578,7 +685,7 @@
   EXPECT_EQ(2, GetToastSerial());
 }
 
-TEST_F(ToastManagerImplTest, ReplaceContentsOfQueuedToast) {
+TEST_P(ToastManagerImplTest, ReplaceContentsOfQueuedToast) {
   std::string id1 = ShowToast(/*text=*/"TEXT1", ToastData::kInfiniteDuration);
   std::string id2 = ShowToast(/*text=*/"TEXT2", ToastData::kInfiniteDuration);
 
@@ -601,7 +708,7 @@
   EXPECT_EQ(2, GetToastSerial());
 }
 
-TEST_F(ToastManagerImplTest, ReplaceContentsOfCurrentToast) {
+TEST_P(ToastManagerImplTest, ReplaceContentsOfCurrentToast) {
   std::string id1 = ShowToast(/*text=*/"TEXT1", ToastData::kInfiniteDuration);
   std::string id2 = ShowToast(/*text=*/"TEXT2", ToastData::kInfiniteDuration);
 
@@ -626,7 +733,7 @@
   EXPECT_EQ(3, GetToastSerial());
 }
 
-TEST_F(ToastManagerImplTest,
+TEST_P(ToastManagerImplTest,
        ReplaceContentsOfCurrentToastBeforePriorReplacementFinishes) {
   // By default, the animation duration is zero in tests. Set the animation
   // duration to non-zero so that toasts don't immediately close.
@@ -668,7 +775,7 @@
   EXPECT_EQ(3, GetToastSerial());
 }
 
-TEST_F(ToastManagerImplTest, ShowToastOnLockScreen) {
+TEST_P(ToastManagerImplTest, ShowToastOnLockScreen) {
   // Simulate device lock.
   ChangeLockState(true);
 
@@ -683,7 +790,7 @@
   EXPECT_EQ(u"TEXT1", GetCurrentText());
 }
 
-TEST_F(ToastManagerImplTest, ShowSupportedToastOnLockScreen) {
+TEST_P(ToastManagerImplTest, ShowSupportedToastOnLockScreen) {
   // Simulate device lock.
   ChangeLockState(true);
 
@@ -701,7 +808,7 @@
   EXPECT_EQ(u"TEXT1", GetCurrentText());
 }
 
-TEST_F(ToastManagerImplTest, DeferToastByLockScreen) {
+TEST_P(ToastManagerImplTest, DeferToastByLockScreen) {
   // Show a toast.
   std::string id1 = ShowToast("TEXT1", ToastData::kInfiniteDuration,
                               /*visible_on_lock_screen=*/true);
@@ -721,7 +828,7 @@
   EXPECT_EQ(u"TEXT1", GetCurrentText());
 }
 
-TEST_F(ToastManagerImplTest, NotDeferToastForLockScreen) {
+TEST_P(ToastManagerImplTest, NotDeferToastForLockScreen) {
   // Show a toast.
   std::string id1 = ShowToast("TEXT1", ToastData::kInfiniteDuration,
                               /*visible_on_lock_screen=*/false);
@@ -740,7 +847,7 @@
   EXPECT_EQ(u"TEXT1", GetCurrentText());
 }
 
-TEST_F(ToastManagerImplTest, DismissButton) {
+TEST_P(ToastManagerImplTest, DismissButton) {
   // Show a toast without dismiss button.
   std::string id1 = ShowToast("TEXT1", ToastData::kInfiniteDuration);
 
@@ -777,7 +884,7 @@
             GetCurrentDismissText());
 }
 
-TEST_F(ToastManagerImplTest, ShownCountMetric) {
+TEST_P(ToastManagerImplTest, ShownCountMetric) {
   base::HistogramTester histogram_tester;
 
   const ToastCatalogName catalog_name_1 = static_cast<ToastCatalogName>(1);
@@ -808,7 +915,7 @@
                                      catalog_name_2, 1);
 }
 
-TEST_F(ToastManagerImplTest, TimeInQueueMetric) {
+TEST_P(ToastManagerImplTest, TimeInQueueMetric) {
   base::HistogramTester histogram_tester;
 
   const ToastCatalogName catalog_name_1 = static_cast<ToastCatalogName>(1);
@@ -846,7 +953,7 @@
                                          duration, 1);
 }
 
-TEST_F(ToastManagerImplTest, UserJourneyTimeMetric) {
+TEST_P(ToastManagerImplTest, UserJourneyTimeMetric) {
   base::HistogramTester histogram_tester;
 
   const ToastCatalogName catalog_name = ToastCatalogName::kToastManagerUnittest;
@@ -879,7 +986,7 @@
 // Table-driven test that checks whether a toast's expired callback is run when
 // a toast is closed when the toast manager cancels the toast, when the toast
 // duration cancels the toast, and when the dismiss button is pressed.
-TEST_F(ToastManagerImplTest, ExpiredCallbackRunsWhenToastOverlayClosed) {
+TEST_P(ToastManagerImplTest, ExpiredCallbackRunsWhenToastOverlayClosed) {
   // Covers possible ways that a toast can be cancelled.
   enum class CancellationSource {
     kToastManager,
@@ -947,7 +1054,7 @@
 
 // Tests that a toast that is created with `ToastData::persist_on_hover` set to
 // true will not expire while the mouse is hovering over it.
-TEST_F(ToastManagerImplTest, ToastsCanPersistOnHover) {
+TEST_P(ToastManagerImplTest, ToastsCanPersistOnHover) {
   std::string toast_id = "TOAST_ID_" + base::NumberToString(GetToastSerial());
 
   ToastData toast_data(toast_id, ToastCatalogName::kToastManagerUnittest,
@@ -986,7 +1093,7 @@
 
 // Table-driven test that checks that toasts designated to show on all windows
 // correctly show and close on all root windows.
-TEST_F(ToastManagerImplTest, ShowAndCloseToastsOnAllRootWindows) {
+TEST_P(ToastManagerImplTest, ShowAndCloseToastsOnAllRootWindows) {
   UpdateDisplay("800x700,800x700");
 
   // Covers possible ways that a toast can be cancelled.
@@ -1062,7 +1169,7 @@
 
 // This tests that toasts that are designated to persist on hover and appear on
 // all root windows will not close when one of the toast instances is hovered.
-TEST_F(ToastManagerImplTest, ToastsThatPersistOnHoverOnAllRootWindows) {
+TEST_P(ToastManagerImplTest, ToastsThatPersistOnHoverOnAllRootWindows) {
   UpdateDisplay("800x700,800x700");
   auto* toast_manager = manager();
   const aura::Window::Windows root_windows = Shell::GetAllRootWindows();
@@ -1118,7 +1225,7 @@
 
 // This tests that multi-monitor toast instances do not call the
 // `expired_callback_` when the root window is removed.
-TEST_F(ToastManagerImplTest, ExpiredCallbackNotCalledOnRootWindowRemoved) {
+TEST_P(ToastManagerImplTest, ExpiredCallbackNotCalledOnRootWindowRemoved) {
   UpdateDisplay("800x700,800x700");
   auto* toast_manager = manager();
 
@@ -1160,7 +1267,7 @@
 
 // This tests that new instances of a multi-monitor toast are spawned with the
 // correct duration and correct persisting state.
-TEST_F(ToastManagerImplTest,
+TEST_P(ToastManagerImplTest,
        AllRootWindowToastsCreatedWithCorrectDurationAndPersistState) {
   // Start with display at 800x700 to maintain cursor position when adding root
   // windows.
@@ -1217,11 +1324,35 @@
 }
 
 // Tests that toasts add a leading icon when one is provided.
-TEST_F(ToastManagerImplTest, ToastWithLeadingIcon) {
+TEST_P(ToastManagerImplTest, ToastWithLeadingIcon) {
   ShowToastWithLeadingIcon(gfx::kNoneIcon);
   EXPECT_FALSE(CurrentToastHasLeadingIcon());
   ShowToastWithLeadingIcon(kSystemMenuBusinessIcon);
   EXPECT_TRUE(CurrentToastHasLeadingIcon());
 }
 
+// Tests that an offset is added to shift the overlay baseline up when
+// toasts are side aligned and a slider bubble is shown.
+// Overlay baseline is unchanged when toasts are not side aligned.
+TEST_P(ToastManagerImplTest, BaselineUpdatesAfterSliderBubbleShown) {
+  ShowToast("DUMMY", ToastData::kInfiniteDuration);
+  const int previous_baseline = GetToastBounds().bottom();
+
+  // The difference between baselines for side aligned toasts after showing a
+  // slider bubble should be the slider bubble height + a default spacing
+  // offset. Baseline remains unchanged with center aligned toasts.
+  GetPrimaryUnifiedSystemTray()->ShowVolumeSliderBubble();
+  if (AreSideAlignedToastsEnabled()) {
+    EXPECT_EQ(GetPrimaryUnifiedSystemTray()->GetSliderBubbleHeight() +
+                  ToastOverlay::kOffset,
+              previous_baseline - GetToastBounds().bottom());
+  } else {
+    EXPECT_EQ(GetToastBounds().bottom(), previous_baseline);
+  }
+
+  // Baseline returns to previous value when the slider bubble is closed.
+  GetPrimaryUnifiedSystemTray()->CloseSecondaryBubbles();
+  EXPECT_EQ(GetToastBounds().bottom(), previous_baseline);
+}
+
 }  // namespace ash
diff --git a/ash/system/toast/toast_overlay.cc b/ash/system/toast/toast_overlay.cc
index 6f086f1..fb34c066 100644
--- a/ash/system/toast/toast_overlay.cc
+++ b/ash/system/toast/toast_overlay.cc
@@ -4,8 +4,10 @@
 
 #include "ash/system/toast/toast_overlay.h"
 
+#include "ash/constants/ash_features.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/public/cpp/ash_typography.h"
+#include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/system/toast_data.h"
 #include "ash/resources/vector_icons/vector_icons.h"
@@ -148,7 +150,6 @@
                            const std::u16string& dismiss_text,
                            const gfx::VectorIcon& leading_icon,
                            base::TimeDelta duration,
-                           bool show_on_lock_screen,
                            bool persist_on_hover,
                            aura::Window* root_window,
                            base::RepeatingClosure dismiss_callback)
@@ -174,10 +175,8 @@
   params.accept_events = true;
   params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.bounds = CalculateOverlayBounds();
-  // Show toasts above the app list and below the lock screen.
-  params.parent = root_window_->GetChildById(
-      show_on_lock_screen ? kShellWindowId_LockSystemModalContainer
-                          : kShellWindowId_SystemModalContainer);
+  params.parent =
+      root_window_->GetChildById(kShellWindowId_DragImageAndTooltipContainer);
   overlay_widget_->Init(std::move(params));
   overlay_widget_->SetVisibilityChangedAnimationsEnabled(true);
   overlay_widget_->SetContentsView(overlay_view_.get());
@@ -199,6 +198,19 @@
   }
 
   keyboard::KeyboardUIController::Get()->AddObserver(this);
+
+  if (features::AreSideAlignedToastsEnabled()) {
+    auto* window_controller = RootWindowController::ForWindow(root_window_);
+    if (window_controller->GetStatusAreaWidget()) {
+      // `UnifiedSystemTray` is observed when side aligned toasts are enabled so
+      // we can shift the toast baseline up when slider bubbles are visible.
+      // The observation is safe on external monitor disconnect because
+      // ToastManagerImpl deletes the ToastOverlay before the root window is
+      // destroyed.
+      scoped_unified_system_tray_observer_.Observe(
+          window_controller->GetStatusAreaWidget()->unified_system_tray());
+    }
+  }
 }
 
 ToastOverlay::~ToastOverlay() {
@@ -251,9 +263,16 @@
   return true;
 }
 
+void ToastOverlay::OnSliderBubbleHeightChanged() {
+  // We only update toast baseline if they are aligned to the side.
+  if (features::AreSideAlignedToastsEnabled()) {
+    UpdateOverlayBounds();
+  }
+}
+
 gfx::Rect ToastOverlay::CalculateOverlayBounds() {
   // If the native window has not been initialized, as in the first call, get
-  // the default root window. Otherwise get the window for this overlay_widget
+  // the default root window. Otherwise get the window for this `overlay_widget`
   // to handle multiple monitors properly.
   auto* window = overlay_widget_->IsNativeWidgetInitialized()
                      ? overlay_widget_->GetNativeWindow()
@@ -263,16 +282,54 @@
 
   gfx::Rect bounds = GetUserWorkAreaBounds(window);
 
-  if (hotseat_widget)
+  if (hotseat_widget) {
     AdjustWorkAreaBoundsForHotseatState(bounds, hotseat_widget);
+  }
 
-  int target_y =
+  if (features::AreSideAlignedToastsEnabled()) {
+    // Toasts should always follow the status area and will usually show on the
+    // bottom-right of the screen. They will show at the bottom-left whenever
+    // the shelf is left-aligned or for RTL when the shelf is not right aligned.
+    auto alignment = window_controller->shelf()->alignment();
+    const int target_x =
+        ((base::i18n::IsRTL() && alignment != ShelfAlignment::kRight) ||
+         alignment == ShelfAlignment::kLeft)
+            ? bounds.x() + ToastOverlay::kOffset
+            : bounds.right() - widget_size_.width() - ToastOverlay::kOffset;
+
+    const int target_y = bounds.bottom() - widget_size_.height() -
+                         ToastOverlay::kOffset - CalculateSliderBubbleOffset();
+
+    return gfx::Rect(gfx::Point(target_x, target_y), widget_size_);
+  }
+
+  const int target_y =
       bounds.bottom() - widget_size_.height() - ToastOverlay::kOffset;
   bounds.ClampToCenteredSize(widget_size_);
   bounds.set_y(target_y);
   return bounds;
 }
 
+// Calculates the y offset used to shift side aligned toasts up whenever case a
+// slider bubble is visible.
+int ToastOverlay::CalculateSliderBubbleOffset() {
+  // Slider bubble offset is only used for side aligned toasts.
+  if (!features::AreSideAlignedToastsEnabled()) {
+    return 0;
+  }
+
+  auto* unified_system_tray = RootWindowController::ForWindow(root_window_)
+                                  ->GetStatusAreaWidget()
+                                  ->unified_system_tray();
+
+  // If a slider bubble is visible, the toast baseline will be shifted
+  // up by the slider bubble's height + a default spacing offset.
+  return unified_system_tray->IsSliderBubbleShown()
+             ? unified_system_tray->GetSliderBubbleHeight() +
+                   ToastOverlay::kOffset
+             : 0;
+}
+
 void ToastOverlay::OnButtonClicked() {
   if (dismiss_callback_) {
     dismiss_callback_.Run();
diff --git a/ash/system/toast/toast_overlay.h b/ash/system/toast/toast_overlay.h
index 49dd6e9..ad86101 100644
--- a/ash/system/toast/toast_overlay.h
+++ b/ash/system/toast/toast_overlay.h
@@ -10,6 +10,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
+#include "ash/system/unified/unified_system_tray.h"
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/time/time.h"
@@ -37,7 +38,8 @@
 class SystemToastStyle;
 
 class ASH_EXPORT ToastOverlay : public ui::ImplicitAnimationObserver,
-                                public KeyboardControllerObserver {
+                                public KeyboardControllerObserver,
+                                public UnifiedSystemTray::Observer {
  public:
   class ASH_EXPORT Delegate {
    public:
@@ -64,7 +66,6 @@
                const std::u16string& dismiss_text,
                const gfx::VectorIcon& leading_icon,
                base::TimeDelta duration,
-               bool show_on_lock_screen,
                bool persist_on_hover,
                aura::Window* root_window,
                base::RepeatingClosure dismiss_callback);
@@ -90,6 +91,9 @@
   // Returns false if `is_dismiss_button_highlighted_` is false.
   bool MaybeActivateHighlightedDismissButton();
 
+  // UnifiedSystemTray::Observer:
+  void OnSliderBubbleHeightChanged() override;
+
  private:
   friend class ToastManagerImplTest;
   friend class ClipboardHistoryControllerRefreshTest;
@@ -101,6 +105,10 @@
   // Returns the current bounds of the overlay, which is based on visibility.
   gfx::Rect CalculateOverlayBounds();
 
+  // Calculates the y offset used to shift side aligned toasts up whenever a
+  // slider bubble is visible.
+  int CalculateSliderBubbleOffset();
+
   // Executed the callback and closes the toast.
   void OnButtonClicked();
 
@@ -133,6 +141,9 @@
   // `current_toast_expiration_timer_` if we are allowing for the toast to
   // persist on hover.
   std::unique_ptr<ToastHoverObserver> hover_observer_;
+
+  base::ScopedObservation<UnifiedSystemTray, UnifiedSystemTray::Observer>
+      scoped_unified_system_tray_observer_{this};
 };
 
 }  // namespace ash
diff --git a/ash/system/unified/unified_slider_bubble_controller.cc b/ash/system/unified/unified_slider_bubble_controller.cc
index 2240f542..8d0dd64 100644
--- a/ash/system/unified/unified_slider_bubble_controller.cc
+++ b/ash/system/unified/unified_slider_bubble_controller.cc
@@ -110,11 +110,15 @@
     return;
   }
   bubble_widget_->Close();
-  tray_->SetTrayBubbleHeight(0);
+  tray_->NotifySecondaryBubbleHeight(0);
 }
 
 bool UnifiedSliderBubbleController::IsBubbleShown() const {
-  return !!bubble_widget_;
+  return !!bubble_widget_ && !bubble_widget_->IsClosed();
+}
+
+int UnifiedSliderBubbleController::GetBubbleHeight() const {
+  return !!slider_view_ ? slider_view_->height() : 0;
 }
 
 void UnifiedSliderBubbleController::BubbleViewDestroyed() {
@@ -302,9 +306,9 @@
 
   bubble_view_ = new TrayBubbleView(init_params);
   bubble_view_->SetCanActivate(false);
-  UnifiedSliderView* slider_view = static_cast<UnifiedSliderView*>(
+  slider_view_ = static_cast<UnifiedSliderView*>(
       bubble_view_->AddChildView(slider_controller_->CreateView()));
-  ConfigureSliderViewStyle(slider_view);
+  ConfigureSliderViewStyle(slider_view_);
 
   bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_);
 
@@ -313,13 +317,12 @@
 
   // Notify value change accessibility event because the popup is triggered by
   // changing value using an accessor key like VolUp.
-  slider_view->slider()->NotifyAccessibilityEvent(
+  slider_view_->slider()->NotifyAccessibilityEvent(
       ax::mojom::Event::kValueChanged, true);
 
   StartAutoCloseTimer();
 
-  tray_->SetTrayBubbleHeight(
-      bubble_widget_->GetWindowBoundsInScreen().height());
+  tray_->NotifySecondaryBubbleHeight(slider_view_->height());
 }
 
 void UnifiedSliderBubbleController::CreateSliderController() {
diff --git a/ash/system/unified/unified_slider_bubble_controller.h b/ash/system/unified/unified_slider_bubble_controller.h
index b2132c9..1745baf7 100644
--- a/ash/system/unified/unified_slider_bubble_controller.h
+++ b/ash/system/unified/unified_slider_bubble_controller.h
@@ -53,6 +53,10 @@
   // True if a slider bubble is shown.
   bool IsBubbleShown() const;
 
+  // Returns the height of the bubble. Used to calculate baseline offset for
+  // notification popups or side aligned toasts.
+  int GetBubbleHeight() const;
+
   // TrayBubbleView::Delegate:
   void BubbleViewDestroyed() override;
   void OnMouseEnteredView() override;
@@ -96,6 +100,7 @@
 
   raw_ptr<TrayBubbleView, ExperimentalAsh> bubble_view_ = nullptr;
   raw_ptr<views::Widget, ExperimentalAsh> bubble_widget_ = nullptr;
+  UnifiedSliderView* slider_view_ = nullptr;
 
   // Type of the currently shown slider.
   SliderType slider_type_ = SLIDER_TYPE_VOLUME;
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc
index 53f76c6..a640bebb 100644
--- a/ash/system/unified/unified_system_tray.cc
+++ b/ash/system/unified/unified_system_tray.cc
@@ -94,8 +94,8 @@
 
   MessageCenterUiController* ui_controller() { return ui_controller_.get(); }
 
-  void SetTrayBubbleHeight(int height) {
-    message_popup_collection_->SetTrayBubbleHeight(height);
+  void NotifySecondaryBubbleHeight(int height) {
+    message_popup_collection_->SetBaselineOffset(height);
   }
 
   message_center::MessagePopupView* GetPopupViewForNotificationID(
@@ -161,7 +161,7 @@
 }
 
 void UnifiedSystemTray::UiDelegate::HidePopups() {
-  message_popup_collection_->SetTrayBubbleHeight(0);
+  message_popup_collection_->SetBaselineOffset(0);
 }
 
 bool UnifiedSystemTray::UiDelegate::ShowMessageCenter() {
@@ -328,6 +328,10 @@
   return slider_bubble_controller_->IsBubbleShown();
 }
 
+int UnifiedSystemTray::GetSliderBubbleHeight() const {
+  return slider_bubble_controller_->GetBubbleHeight();
+}
+
 bool UnifiedSystemTray::IsMessageCenterBubbleShown() const {
   if (message_center_bubble_) {
     return message_center_bubble_->IsMessageCenterVisible();
@@ -404,8 +408,11 @@
   bubble_->ShowNetworkDetailedView(true /* force */);
 }
 
-void UnifiedSystemTray::SetTrayBubbleHeight(int height) {
-  ui_delegate_->SetTrayBubbleHeight(height);
+void UnifiedSystemTray::NotifySecondaryBubbleHeight(int height) {
+  ui_delegate_->NotifySecondaryBubbleHeight(height);
+  for (auto& observer : observers_) {
+    observer.OnSliderBubbleHeightChanged();
+  }
 }
 
 bool UnifiedSystemTray::FocusMessageCenter(bool reverse,
diff --git a/ash/system/unified/unified_system_tray.h b/ash/system/unified/unified_system_tray.h
index 5df905f..33161e4 100644
--- a/ash/system/unified/unified_system_tray.h
+++ b/ash/system/unified/unified_system_tray.h
@@ -82,6 +82,9 @@
 
     // Gets called when leaving from the calendar view.
     virtual void OnLeavingCalendarView() {}
+
+    // Gets called when a slider bubble is shown or closed.
+    virtual void OnSliderBubbleHeightChanged() {}
   };
 
   explicit UnifiedSystemTray(Shelf* shelf);
@@ -105,14 +108,20 @@
   // accelerator is shown.
   bool IsSliderBubbleShown() const;
 
+  // Gets the height of the slider bubble used to calculate the baseline of
+  // notification popups and side aligned toasts so they don't overlap.
+  int GetSliderBubbleHeight() const;
+
   // True if the bubble containing notifications is visible..
   bool IsMessageCenterBubbleShown() const;
 
   // True if the bubble is active.
   bool IsBubbleActive() const;
 
-  // Closes all non-system tray bubbles (e.g. volume/brightness, and toasts) if
-  // any are shown.
+  // Closes all secondary bubbles (e.g. volume/brightness sliders, autozoom,
+  // privacy screen toast) if any are shown.
+  // TODO(b/279044049): Consider making autozoom and privacy screen slider
+  // bubbles, or have them extend a common class with sliders.
   void CloseSecondaryBubbles();
 
   // Activates the system tray bubble.
@@ -154,10 +163,10 @@
   // message center opens.
   void SetTargetNotification(const std::string& notification_id);
 
-  // Sets the height of the system tray bubble from the edge of the work area
-  // so that the notification popups don't overlap with the tray. Pass 0 if no
-  // bubble is shown.
-  void SetTrayBubbleHeight(int height);
+  // Notifies the height of the secondary bubble (e.g. Volume/Brightness
+  // sliders, Privacy screen/Autozoom toast) if one is showing so notification
+  // popups or toasts won't overlap with it. Pass 0 if no bubble is shown.
+  void NotifySecondaryBubbleHeight(int height);
 
   // Transfer focus to the message center bubble. Will focus only on the message
   // center if vox is enabled. Otherwise, will focus on the first element in the
diff --git a/ash/test/pixel/OWNERS b/ash/test/pixel/OWNERS
index 7a24acfc..424f03e 100644
--- a/ash/test/pixel/OWNERS
+++ b/ash/test/pixel/OWNERS
@@ -1 +1,2 @@
 andrewxu@chromium.org
+svenzheng@chromium.org
diff --git a/ash/test/pixel/ash_pixel_differ.cc b/ash/test/pixel/ash_pixel_differ.cc
index 782bced..1525a4f6 100644
--- a/ash/test/pixel/ash_pixel_differ.cc
+++ b/ash/test/pixel/ash_pixel_differ.cc
@@ -15,8 +15,10 @@
 
 // The names of the pixel tests that use the "positive if only" algorithm.
 // This list should be removed when all existing tests are migrated.
-const std::array<std::string, 3> kMigratedTests = {
-    {"DemoAshPixelDiffTest", "LoginShelf", "AmbientInfoViewTest"}};
+// NOTE: maintain the array in the alphabetical order.
+const std::array<std::string, 5> kMigratedTests = {
+    {"AmbientInfoViewTest", "AshNotificationView", "DemoAshPixelDiffTest",
+     "LoginShelf", "ScreenCaptureNotification"}};
 
 // Returns true if the test specified by `screenshot_prefix` should use the
 // "positive if only" algorithm.
diff --git a/ash/user_education/holding_space_tour/holding_space_tour_controller.cc b/ash/user_education/holding_space_tour/holding_space_tour_controller.cc
index 028dde0..f20ceef4 100644
--- a/ash/user_education/holding_space_tour/holding_space_tour_controller.cc
+++ b/ash/user_education/holding_space_tour/holding_space_tour_controller.cc
@@ -4,9 +4,29 @@
 
 #include "ash/user_education/holding_space_tour/holding_space_tour_controller.h"
 
+#include <memory>
+#include <string>
+
+#include "ash/display/window_tree_host_manager.h"
+#include "ash/drag_drop/scoped_drag_drop_observer.h"
+#include "ash/public/cpp/holding_space/holding_space_controller.h"
+#include "ash/public/cpp/wallpaper/wallpaper_controller.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shell.h"
 #include "ash/user_education/user_education_types.h"
+#include "ash/wallpaper/wallpaper_drag_drop_delegate.h"
 #include "base/check_op.h"
+#include "base/pickle.h"
 #include "components/user_education/common/tutorial_description.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/clipboard/custom_data_helper.h"
+#include "ui/base/dragdrop/drop_target_event.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/wm/core/coordinate_conversion.h"
 
 namespace ash {
 namespace {
@@ -14,6 +34,155 @@
 // The singleton instance owned by the `UserEducationController`.
 HoldingSpaceTourController* g_instance = nullptr;
 
+// Helpers ---------------------------------------------------------------------
+
+const ui::ClipboardFormatType& FilesAppFormatType() {
+  // NOTE: The Files app stores file system sources as custom web data.
+  return ui::ClipboardFormatType::WebCustomDataType();
+}
+
+aura::Window* GetRootWindowForDisplayId(int64_t display_id) {
+  return Shell::Get()->window_tree_host_manager()->GetRootWindowForDisplayId(
+      display_id);
+}
+
+display::Display GetDisplayNearestPoint(const gfx::Point& location_in_screen) {
+  return display::Screen::GetScreen()->GetDisplayNearestPoint(
+      location_in_screen);
+}
+
+aura::client::DragDropClient* GetDragDropClientNearestPoint(
+    const gfx::Point& location_in_screen) {
+  return aura::client::GetDragDropClient(GetRootWindowForDisplayId(
+      GetDisplayNearestPoint(location_in_screen).id()));
+}
+
+Shelf* GetShelfNearestPoint(const gfx::Point& location_in_screen) {
+  return Shelf::ForWindow(GetRootWindowForDisplayId(
+      GetDisplayNearestPoint(location_in_screen).id()));
+}
+
+// DragDropDelegate ------------------------------------------------------------
+
+// An implementation of the singleton drag-and-drop delegate, owned by the
+// `WallpaperControllerImpl`, which observes a drag-and-drop sequence once the
+// user has dragged a file from the Files app over the wallpaper. It then
+// ensures that:
+//
+// (a) the shelf is visible on the active display, and that
+// (b) holding space is visible in the shelf on all displays
+//
+// While the observed drag-and-drop sequence is in progress.
+class DragDropDelegate : public WallpaperDragDropDelegate {
+ private:
+  // WallpaperDragDropDelegate:
+  void GetDropFormats(int* formats,
+                      std::set<ui::ClipboardFormatType>* types) override {
+    types->insert(FilesAppFormatType());
+  }
+
+  bool CanDrop(const ui::OSExchangeData& data) override {
+    // TODO(http://b/279031685): Ask Files app team to own a util API for this.
+    base::Pickle pickled_data;
+    if (data.GetPickledData(FilesAppFormatType(), &pickled_data)) {
+      std::u16string file_system_sources;
+      ui::ReadCustomDataForType(pickled_data.data(), pickled_data.size(),
+                                u"fs/sources", &file_system_sources);
+      return !file_system_sources.empty();
+    }
+    return true;
+  }
+
+  void OnDragEntered(const ui::OSExchangeData& data,
+                     const gfx::Point& location_in_screen) override {
+    // If the `drag_drop_observer_` already exists, we are already observing the
+    // current drag-and-drop sequence and can no-op here.
+    if (drag_drop_observer_) {
+      return;
+    }
+
+    // Once the user has dragged a file from the Files app over the wallpaper,
+    // observe the drag-and-drop sequence to ensure that (a) the shelf is
+    // visible on the active display and that (b) holding space is visible in
+    // the shelf on all displays while the observed drag-and-drop sequence is in
+    // progress.
+    drag_drop_observer_ = std::make_unique<ScopedDragDropObserver>(
+        GetDragDropClientNearestPoint(location_in_screen),
+        base::BindRepeating(&DragDropDelegate::OnDropTargetEvent,
+                            base::Unretained(this)));
+
+    // Explicitly update state as `OnDropTargetEvent()` will not be invoked
+    // until the next drag event.
+    OnDragOrDropEvent(location_in_screen);
+  }
+
+  void OnDropTargetEvent(const ui::DropTargetEvent* event) {
+    // This code should only be reached if we are observing a drag-and-drop
+    // sequence due to the user dragging a file from the Files app over the
+    // wallpaper.
+    CHECK(drag_drop_observer_);
+
+    absl::optional<gfx::Point> location_in_screen;
+
+    if (event) {
+      location_in_screen = event->root_location();
+      wm::ConvertPointToScreen(
+          static_cast<aura::Window*>(event->target())->GetRootWindow(),
+          &location_in_screen.value());
+    }
+
+    OnDragOrDropEvent(std::move(location_in_screen));
+  }
+
+  void OnDragOrDropEvent(absl::optional<gfx::Point> location_in_screen) {
+    // This code should only be reached if we are observing a drag-and-drop
+    // sequence due to the user dragging a file from the Files app over the
+    // wallpaper.
+    CHECK(drag_drop_observer_);
+
+    // If `location_in_screen` is absent, the observed drag-and-drop sequence
+    // has been completed or cancelled. We can stop observing drag-and-drop
+    // sequences and reset the shelf to its natural state.
+    if (!location_in_screen) {
+      drag_drop_observer_.reset();
+      disable_shelf_auto_hide_.reset();
+      force_holding_space_show_in_shelf_.reset();
+      return;
+    }
+
+    Shelf* shelf = GetShelfNearestPoint(location_in_screen.value());
+    CHECK(shelf);
+
+    // Ensure the shelf is visible on the active display while the observed
+    // drag-and-drop sequence is in progress.
+    if (!disable_shelf_auto_hide_ ||
+        disable_shelf_auto_hide_->shelf() != shelf) {
+      disable_shelf_auto_hide_ =
+          std::make_unique<Shelf::ScopedDisableAutoHide>(shelf);
+    }
+
+    // Ensure that holding space is visible in the shelf on all displays while
+    // the observed drag-and-drop sequence is in progress.
+    if (!force_holding_space_show_in_shelf_) {
+      force_holding_space_show_in_shelf_ =
+          std::make_unique<HoldingSpaceController::ScopedForceShowInShelf>();
+    }
+  }
+
+  // Used to observe a single drag-and-drop sequence once the user has dragged
+  // a file from the Files app over the wallpaper.
+  std::unique_ptr<ScopedDragDropObserver> drag_drop_observer_;
+
+  // Used to ensure the shelf is visible on the active display while an
+  // observed drag-and-drop sequence is in progress.
+  std::unique_ptr<Shelf::ScopedDisableAutoHide> disable_shelf_auto_hide_;
+
+  // Used to ensure that holding space is visible in the shelf on all displays
+  // while an observed drag-and-drop sequence is in progress.
+  std::unique_ptr<HoldingSpaceController::ScopedForceShowInShelf>
+      force_holding_space_show_in_shelf_;
+};
+
 }  // namespace
 
 // HoldingSpaceTourController --------------------------------------------------
@@ -21,6 +190,11 @@
 HoldingSpaceTourController::HoldingSpaceTourController() {
   CHECK_EQ(g_instance, nullptr);
   g_instance = this;
+
+  // Register our implementation as the singleton delegate for drag-and-drop
+  // events over the wallpaper.
+  WallpaperController::Get()->SetDragDropDelegate(
+      std::make_unique<DragDropDelegate>());
 }
 
 HoldingSpaceTourController::~HoldingSpaceTourController() {
diff --git a/ash/user_education/holding_space_tour/holding_space_tour_controller_unittest.cc b/ash/user_education/holding_space_tour/holding_space_tour_controller_unittest.cc
index 7b129d6..fbd3377f 100644
--- a/ash/user_education/holding_space_tour/holding_space_tour_controller_unittest.cc
+++ b/ash/user_education/holding_space_tour/holding_space_tour_controller_unittest.cc
@@ -5,16 +5,41 @@
 #include "ash/user_education/holding_space_tour/holding_space_tour_controller.h"
 
 #include <map>
+#include <memory>
+#include <string>
+#include <unordered_map>
 
 #include "ash/constants/ash_features.h"
-#include "ash/test/ash_test_base.h"
+#include "ash/display/window_tree_host_manager.h"
+#include "ash/drag_drop/drag_drop_controller.h"
+#include "ash/public/cpp/holding_space/holding_space_controller.h"
+#include "ash/public/cpp/holding_space/holding_space_model.h"
+#include "ash/public/cpp/holding_space/mock_holding_space_client.h"
+#include "ash/public/cpp/shelf_types.h"
+#include "ash/public/cpp/test/shell_test_api.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shell.h"
+#include "ash/system/holding_space/holding_space_tray.h"
+#include "ash/system/status_area_widget.h"
+#include "ash/test/test_widget_builder.h"
 #include "ash/user_education/tutorial_controller.h"
+#include "ash/user_education/user_education_ash_test_base.h"
 #include "ash/user_education/user_education_types.h"
+#include "base/pickle.h"
+#include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/account_id/account_id.h"
 #include "components/user_education/common/tutorial_description.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/clipboard/custom_data_helper.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/dragdrop/os_exchange_data_provider.h"
+#include "ui/display/display.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
 
 namespace ash {
 namespace {
@@ -26,12 +51,70 @@
 using testing::Pair;
 using user_education::TutorialDescription;
 
+// Helpers ---------------------------------------------------------------------
+
+HoldingSpaceTray* GetHoldingSpaceTrayForShelf(Shelf* shelf) {
+  return shelf->GetStatusAreaWidget()->holding_space_tray();
+}
+
+aura::Window* GetRootWindowForDisplayId(int64_t display_id) {
+  return Shell::Get()->window_tree_host_manager()->GetRootWindowForDisplayId(
+      display_id);
+}
+
+Shelf* GetShelfForDisplayId(int64_t display_id) {
+  return Shelf::ForWindow(GetRootWindowForDisplayId(display_id));
+}
+
+std::unique_ptr<views::Widget> CreateTestWidgetForDisplayId(
+    int64_t display_id) {
+  return TestWidgetBuilder()
+      .SetWidgetType(views::Widget::InitParams::TYPE_WINDOW_FRAMELESS)
+      .SetContext(GetRootWindowForDisplayId(display_id))
+      .BuildOwnsNativeWidget();
+}
+
+void SetFilesAppData(ui::OSExchangeData* data) {
+  base::Pickle pickled_data;
+  ui::WriteCustomDataToPickle(
+      std::unordered_map<std::u16string, std::u16string>(
+          {{u"fs/sources", u"filesystem:filepath"}}),
+      &pickled_data);
+
+  // NOTE: The Files app stores file system sources as custom web data.
+  data->SetPickledData(ui::ClipboardFormatType::WebCustomDataType(),
+                       pickled_data);
+}
+
+// DraggableView ---------------------------------------------------------------
+
+// TODO(http://b/279211692): Modify and reuse `DraggableTestView`.
+// A view supporting drag operations that relies on a `delegate_` to write data.
+class DraggableView : public views::View {
+ public:
+  using Delegate = base::RepeatingCallback<void(ui::OSExchangeData*)>;
+  explicit DraggableView(Delegate delegate) : delegate_(std::move(delegate)) {}
+
+ private:
+  // views::View:
+  int GetDragOperations(const gfx::Point&) override {
+    return ui::DragDropTypes::DragOperation::DRAG_COPY;
+  }
+
+  void WriteDragData(const gfx::Point&, ui::OSExchangeData* data) override {
+    delegate_.Run(data);
+  }
+
+  // The delegate for writing drag data.
+  Delegate delegate_;
+};
+
 }  // namespace
 
 // HoldingSpaceTourControllerTest ----------------------------------------------
 
 // Base class for tests of the `HoldingSpaceTourController`.
-class HoldingSpaceTourControllerTest : public NoSessionAshTestBase {
+class HoldingSpaceTourControllerTest : public UserEducationAshTestBase {
  public:
   HoldingSpaceTourControllerTest() {
     // NOTE: The `HoldingSpaceTourController` exists only when the Holding Space
@@ -62,4 +145,163 @@
                   Pair(Eq(TutorialId::kHoldingSpaceTourPrototype2), _)));
 }
 
+// HoldingSpaceTourControllerDragAndDropTest -----------------------------------
+
+// Base class for drag-and-drop tests of the `HoldingSpaceTourController`,
+// parameterized by (a) whether to drag Files app data and (b) whether to
+// complete the drop (as opposed to cancelling it).
+class HoldingSpaceTourControllerDragAndDropTest
+    : public HoldingSpaceTourControllerTest,
+      public testing::WithParamInterface<
+          std::tuple</*drag_files_app_data=*/bool, /*complete_drop=*/bool>> {
+ public:
+  // Whether to drag Files app data given test parameterization.
+  bool drag_files_app_data() const { return std::get<0>(GetParam()); }
+
+  // Whether to complete the drop (as opposed to cancelling it) given test
+  // parameterization.
+  bool complete_drop() const { return std::get<1>(GetParam()); }
+
+  // Moves the mouse to the center of the specified `widget`.
+  void MoveMouseTo(views::Widget* widget) {
+    GetEventGenerator()->MoveMouseTo(
+        widget->GetWindowBoundsInScreen().CenterPoint(), /*count=*/10);
+  }
+
+  // Moves the mouse by the specified `x` and `y` offsets.
+  void MoveMouseBy(int x, int y) {
+    auto* event_generator = GetEventGenerator();
+    event_generator->MoveMouseTo(
+        event_generator->current_screen_location() + gfx::Vector2d(x, y),
+        /*count=*/10);
+  }
+
+  // Presses and releases the key associated with the specified `key_code`.
+  void PressAndReleaseKey(ui::KeyboardCode key_code) {
+    GetEventGenerator()->PressAndReleaseKey(key_code);
+  }
+
+  // Presses/releases the left mouse button.
+  void PressLeftButton() { GetEventGenerator()->PressLeftButton(); }
+  void ReleaseLeftButton() { GetEventGenerator()->ReleaseLeftButton(); }
+
+ private:
+  // HoldingSpaceTourControllerTest:
+  void SetUp() override {
+    HoldingSpaceTourControllerTest::SetUp();
+
+    // Prevent blocking during drag-and-drop sequences.
+    ShellTestApi().drag_drop_controller()->set_should_block_during_drag_drop(
+        false);
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    HoldingSpaceTourControllerDragAndDropTest,
+    testing::Combine(/*drag_files_app_data=*/testing::Bool(),
+                     /*complete_drop=*/testing::Bool()));
+
+// Tests -----------------------------------------------------------------------
+
+// Verifies that the `HoldingSpaceTourController` handles drag-and-drop events
+// as expected.
+TEST_P(HoldingSpaceTourControllerDragAndDropTest, DragAndDrop) {
+  // The holding space tray is always visible in the shelf when the
+  // predictability feature is enabled. Force disable it so that we verify that
+  // holding space visibility is updated by the `HoldingSpaceTourController`.
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(
+      features::kHoldingSpacePredictability);
+
+  // Set up a primary and secondary display and cache IDs.
+  UpdateDisplay("1024x768,1024x768");
+  const int64_t primary_display_id = GetPrimaryDisplay().id();
+  const int64_t secondary_display_id = GetSecondaryDisplay().id();
+
+  // Log in a regular user.
+  const AccountId& account_id = AccountId::FromUserEmail("user@test");
+  SimulateUserLogin(account_id);
+
+  // Register a model and client for holding space.
+  HoldingSpaceModel holding_space_model;
+  MockHoldingSpaceClient holding_space_client;
+  HoldingSpaceController::Get()->RegisterClientAndModelForUser(
+      account_id, &holding_space_client, &holding_space_model);
+
+  // Create and show a widget on the primary display from which data can be
+  // drag-and-dropped.
+  auto primary_widget = CreateTestWidgetForDisplayId(primary_display_id);
+  primary_widget->SetContentsView(std::make_unique<DraggableView>(
+      base::BindLambdaForTesting([&](ui::OSExchangeData* data) {
+        data->SetString(u"Payload");
+        if (drag_files_app_data()) {
+          SetFilesAppData(data);
+        }
+      })));
+  primary_widget->CenterWindow(gfx::Size(100, 100));
+  primary_widget->Show();
+
+  // Create and show a widget on the secondary display.
+  auto secondary_widget = CreateTestWidgetForDisplayId(secondary_display_id);
+  secondary_widget->CenterWindow(gfx::Size(100, 100));
+  secondary_widget->Show();
+
+  // Cache both shelves and holding space trays.
+  auto* const primary_shelf = GetShelfForDisplayId(primary_display_id);
+  auto* const secondary_shelf = GetShelfForDisplayId(secondary_display_id);
+  auto* const primary_tray = GetHoldingSpaceTrayForShelf(primary_shelf);
+  auto* const secondary_tray = GetHoldingSpaceTrayForShelf(secondary_shelf);
+
+  // Set auto-hide behavior and verify that neither shelf is visible.
+  primary_shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
+  secondary_shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
+  EXPECT_FALSE(primary_shelf->IsVisible());
+  EXPECT_FALSE(secondary_shelf->IsVisible());
+
+  // Verify that neither holding space tray is visible.
+  EXPECT_FALSE(primary_tray->GetVisible());
+  EXPECT_FALSE(secondary_tray->GetVisible());
+
+  // Drag data from the `primary_widget` to the wallpaper.
+  MoveMouseTo(primary_widget.get());
+  PressLeftButton();
+  MoveMouseBy(/*x=*/primary_widget->GetWindowBoundsInScreen().width(), /*y=*/0);
+
+  // Expect the primary shelf and both holding space trays to be visible if
+  // and only if Files app data was dragged.
+  EXPECT_EQ(primary_shelf->IsVisible(), drag_files_app_data());
+  EXPECT_EQ(primary_tray->GetVisible(), drag_files_app_data());
+  EXPECT_EQ(secondary_tray->GetVisible(), drag_files_app_data());
+  EXPECT_FALSE(secondary_shelf->IsVisible());
+
+  // Drag the data to the `secondary_widget`.
+  MoveMouseTo(secondary_widget.get());
+
+  // Expect the secondary shelf and both holding space trays to be visible if
+  // and only if Files app data was dragged.
+  EXPECT_EQ(secondary_shelf->IsVisible(), drag_files_app_data());
+  EXPECT_EQ(primary_tray->GetVisible(), drag_files_app_data());
+  EXPECT_EQ(secondary_tray->GetVisible(), drag_files_app_data());
+  EXPECT_FALSE(primary_shelf->IsVisible());
+
+  // Conditionally complete or cancel the drop depending on test
+  // parameterization.
+  if (complete_drop()) {
+    ReleaseLeftButton();
+  } else {
+    PressAndReleaseKey(ui::VKEY_ESCAPE);
+  }
+
+  // Expect both shelves and holding space trays to no longer be visible.
+  EXPECT_FALSE(primary_shelf->IsVisible());
+  EXPECT_FALSE(secondary_shelf->IsVisible());
+  EXPECT_FALSE(primary_tray->GetVisible());
+  EXPECT_FALSE(secondary_tray->GetVisible());
+
+  // Clean up holding space controller.
+  HoldingSpaceController::Get()->RegisterClientAndModelForUser(
+      account_id, /*client=*/nullptr, /*model=*/nullptr);
+}
+
 }  // namespace ash
diff --git a/ash/user_education/user_education_ash_test_base.h b/ash/user_education/user_education_ash_test_base.h
index 9a8e42e..2c482c5 100644
--- a/ash/user_education/user_education_ash_test_base.h
+++ b/ash/user_education/user_education_ash_test_base.h
@@ -19,6 +19,9 @@
 // * Does NOT add user sessions during `SetUp()`.
 class UserEducationAshTestBase : public NoSessionAshTestBase {
  protected:
+  // NoSessionAshTestBase:
+  void SetUp() override;
+
   // Returns the mocked delegate which facilitates communication between Ash and
   // user education services in the browser.
   testing::NiceMock<MockUserEducationDelegate>* user_education_delegate() {
@@ -26,9 +29,6 @@
   }
 
  private:
-  // NoSessionAshTestBase:
-  void SetUp() override;
-
   // The mocked delegate which facilitates communication between Ash and user
   // education services in the browser. Created during `SetUp()`.
   raw_ptr<testing::NiceMock<MockUserEducationDelegate>, ExperimentalAsh>
diff --git a/ash/webui/camera_app_ui/resources/css/colors_default.css b/ash/webui/camera_app_ui/resources/css/colors_default.css
index 033120b..7498d36f5 100644
--- a/ash/webui/camera_app_ui/resources/css/colors_default.css
+++ b/ash/webui/camera_app_ui/resources/css/colors_default.css
@@ -10,8 +10,12 @@
 :root {
   --cros-sys-app_base: var(--grey-900);
   --cros-sys-base_elevated: var(--grey-200);
+  --cros-sys-error_container: rgba(var(--red-300-rgb), 0.3);
   --cros-sys-focus_ring: var(--blue-300);
+  --cros-sys-hover_on_subtle: rgba(255, 255, 255, 0.06);
   --cros-sys-inverse_on_surface: black;
+  --cros-sys-primary: var(--blue-300);
+  --cros-sys-on_error_container: var(--red-300);
   --cros-sys-on_surface: var(--grey-200);
 }
 
@@ -34,7 +38,8 @@
 #open-mirror-panel,
 #open-grid-panel,
 #open-timer-panel,
-#open-ptz-panel {
+#open-ptz-panel,
+#toggle-mic {
   border-radius: 50%;
 }
 
@@ -62,3 +67,11 @@
     color: var(--blue-300);
   }
 }
+
+body:not(.mic) #toggle-mic {
+  /* Before jelly, the background size is slightly smaller at 36px */
+  background: radial-gradient(
+    var(--cros-sys-error_container) 18px,
+    transparent 19px
+  );
+}
diff --git a/ash/webui/camera_app_ui/resources/css/main.css b/ash/webui/camera_app_ui/resources/css/main.css
index 0afd853..84e1b3ec 100644
--- a/ash/webui/camera_app_ui/resources/css/main.css
+++ b/ash/webui/camera_app_ui/resources/css/main.css
@@ -8,6 +8,8 @@
   --blue-300: rgb(var(--blue-300-rgb));
   --blue-500: rgb(66, 133, 244);
   --blue-600: rgb(26, 115, 232);
+  --red-300-rgb: 242, 139, 130;
+  --red-300: rgb(var(--red-300-rgb));
   --grey-100: rgb(241, 243, 244);
   --grey-200-rgb: 233, 234, 237;
   --grey-200: rgb(var(--grey-200-rgb));
@@ -621,17 +623,26 @@
 #open-mirror-panel,
 #open-grid-panel,
 #open-timer-panel,
-#open-ptz-panel {
+#open-ptz-panel,
+#toggle-mic {
   border-radius: 12px;
 }
 
 #open-mirror-panel,
-#open-grid-panel {
+#open-grid-panel,
+#toggle-mic {
   .on-icon {
     display: none;
   }
 }
 
+body:not(.mic) #toggle-mic {
+  background: var(--cros-sys-error_container);
+  .off-icon {
+    color: var(--cros-sys-on_error_container);
+  }
+}
+
 body.mirror #open-mirror-panel,
 body.grid #open-grid-panel,
 body:is(.timer-3s, .timer-10s) #open-timer-panel,
@@ -640,7 +651,8 @@
 }
 
 body.mirror #open-mirror-panel,
-body.grid #open-grid-panel {
+body.grid #open-grid-panel,
+body.mic #toggle-mic {
   .off-icon {
     display: none;
   }
@@ -684,14 +696,6 @@
   display: none;
 }
 
-#toggle-mic:checked {
-  background-image: url(/images/camera_button_mic_on.svg);
-}
-
-#toggle-mic {
-  background-image: url(/images/camera_button_mic_off.svg);
-}
-
 body.should-handle-intent-result #open-settings {
   display: none;
 }
@@ -1145,9 +1149,6 @@
 
 .menu-header,
 .menu-item {
-  --hover-color: rgba(255, 255, 255, 0.06);
-  --toggled-color: rgb(140, 180, 245);
-
   align-items: center;
   color: var(--grey-100);
   display: flex;
@@ -1159,7 +1160,7 @@
 
 button.menu-item:hover,
 label.menu-item:hover {
-  background-color: var(--hover-color);
+  background-color: var(--cros-sys-hover_on_subtle);
 }
 
 .settings .menu-item {
@@ -1199,7 +1200,7 @@
 
 .menu-item input::before {
   bottom: 13px;
-  box-shadow: 0 0 0 2px var(--grey-100);
+  box-shadow: 0 0 0 2px var(--cros-sys-on_surface);
   content: '';
   left: 13px;
   position: absolute;
@@ -1213,10 +1214,10 @@
 
 .menu-item input:checked::before {
   background-clip: padding-box;
-  background-color: var(--toggled-color);
+  background-color: var(--cros-sys-primary);
   border: 4px solid transparent;
   bottom: 12px;
-  box-shadow: 0 0 0 1px var(--toggled-color);
+  box-shadow: 0 0 0 1px var(--cros-sys-primary);
   left: 12px;
   right: 12px;
   top: 12px;
@@ -1238,7 +1239,7 @@
 }
 
 .menu-header .icon:hover {
-  background-color: var(--hover-color);
+  background-color: var(--cros-sys-hover_on_subtle);
 }
 
 #settings-gridtype .icon {
@@ -1425,7 +1426,7 @@
 }
 
 #options-container .menu-item span {
-  color: var(--grey-100);
+  color: var(--cros-sys-on_surface);
   margin-inline-start: 4px;
 }
 
diff --git a/ash/webui/camera_app_ui/resources/images/camera_button_mic_off.svg b/ash/webui/camera_app_ui/resources/images/camera_button_mic_off.svg
index 8df91d1..fdae118 100644
--- a/ash/webui/camera_app_ui/resources/images/camera_button_mic_off.svg
+++ b/ash/webui/camera_app_ui/resources/images/camera_button_mic_off.svg
@@ -1,6 +1,5 @@
-<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
-<circle cx="18" cy="18" r="18" fill="#F28B82" fill-opacity="0.3"/>
-<path d="M20.5715 12.5L20.5629 17.5C20.5629 17.9551 20.4395 18.3813 20.2233 18.7484L19.0073 17.5324C19.0076 17.5243 19.0077 17.5161 19.0078 17.5079L19.0469 12.5078C19.0513 11.9525 18.6023 11.5 18.047 11.5C17.4978 11.5 17.0514 11.9429 17.0471 12.4921L17.0231 15.5483L15.4286 13.9537V12.5C15.4286 11.1167 16.5772 10 18 10C19.4229 10 20.5715 11.1167 20.5715 12.5Z" fill="#F28B82"/>
-<path d="M10.2374 11.2374L9 12.4749L18.3834 21.8582C18.2564 21.8685 18.1285 21.8737 18 21.8737C15.6343 21.8737 13.4572 20.1053 13.4572 17.579H12C12 20.459 14.3314 22.8253 17.1429 23.2379V26H18.8572V23.2379C19.1112 23.2014 19.3614 23.1488 19.6063 23.0811L23.5251 27L24.7626 25.7626L10.2374 11.2374Z" fill="#F28B82"/>
-<path d="M21.6393 20.1645L22.6382 21.1633C23.4813 20.1835 24 18.9374 24 17.579H22.5429C22.5429 18.5811 22.2003 19.4639 21.6393 20.1645Z" fill="#F28B82"/>
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.5715 4.5L12.5629 9.5C12.5629 9.95509 12.4395 10.3813 12.2233 10.7484L11.0073 9.53245C11.0076 9.52428 11.0077 9.51608 11.0078 9.50786L11.0469 4.5078C11.0513 3.95249 10.6023 3.5 10.047 3.5C9.49779 3.5 9.05136 3.94294 9.04706 4.49214L9.02314 7.54828L7.4286 5.95375V4.5C7.4286 3.11667 8.57717 2 10 2C11.4229 2 12.5715 3.11667 12.5715 4.5Z"/>
+<path d="M2.23742 3.23744L1 4.47486L10.3834 13.8582C10.2564 13.8685 10.1285 13.8737 10 13.8737C7.6343 13.8737 5.45715 12.1053 5.45715 9.57898H4.00001C4.00001 12.459 6.33144 14.8253 9.14287 15.2379V18H10.8572V15.2379C11.1112 15.2014 11.3614 15.1488 11.6063 15.0811L15.5251 19L16.7626 17.7626L2.23742 3.23744Z"/>
+<path d="M13.6393 12.1645L14.6382 13.1633C15.4813 12.1835 16 10.9374 16 9.57898H14.5429C14.5429 10.5811 14.2003 11.4639 13.6393 12.1645Z"/>
 </svg>
diff --git a/ash/webui/camera_app_ui/resources/images/camera_button_mic_on.svg b/ash/webui/camera_app_ui/resources/images/camera_button_mic_on.svg
index f9632e9..e3bd49f1 100644
--- a/ash/webui/camera_app_ui/resources/images/camera_button_mic_on.svg
+++ b/ash/webui/camera_app_ui/resources/images/camera_button_mic_on.svg
@@ -1,22 +1,3 @@
-<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <defs>
-        <filter x="-54.2%" y="-40.6%" width="208.3%" height="181.2%" filterUnits="objectBoundingBox" id="filter-1">
-            <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
-            <feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
-            <feColorMatrix values="0 0 0 0 0.125490196   0 0 0 0 0.129411765   0 0 0 0 0.141176471  0 0 0 0.3 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
-            <feMerge>
-                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
-                <feMergeNode in="SourceGraphic"></feMergeNode>
-            </feMerge>
-        </filter>
-        <path d="M5.83333333,10 C7.21666667,10 8.33333333,8.88333333 8.33333333,7.5 L8.33333333,2.5 C8.33333333,1.11666667 7.21666667,0 5.83333333,0 C4.45,0 3.33333333,1.11666667 3.33333333,2.5 L3.33333333,7.5 C3.33333333,8.88333333 4.45,10 5.83333333,10 Z M10,7.5 C10,9.8 8.13333333,11.6666667 5.83333333,11.6666667 C3.53333333,11.6666667 1.66666667,9.8 1.66666667,7.5 L0,7.5 C0,10.4416667 2.175,12.8583333 5,13.2666667 L5,15.8333333 L6.66666667,15.8333333 L6.66666667,13.2666667 C9.49166667,12.8583333 11.6666667,10.4416667 11.6666667,7.5 L10,7.5 Z" id="path-2"></path>
-    </defs>
-    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="Group" filter="url(#filter-1)" transform="translate(6.166667, 4.500000)">
-            <mask id="mask-3" fill="white">
-                <use xlink:href="#path-2"></use>
-            </mask>
-            <use id="ic_mic_24px" fill="#FFFFFF" fill-rule="nonzero" xlink:href="#path-2"></use>
-        </g>
-    </g>
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M10 12.1053C11.4229 12.1053 12.5629 10.9768 12.5629 9.57895L12.5714 4.52632C12.5714 3.12842 11.4229 2 10 2C8.57716 2 7.42859 3.12842 7.42859 4.52632V9.57895C7.42859 10.9768 8.57716 12.1053 10 12.1053ZM14.5429 9.57898C14.5429 12.1053 12.3657 13.8737 10 13.8737C7.63429 13.8737 5.45714 12.1053 5.45714 9.57898H4C4 12.459 6.33143 14.8253 9.14286 15.2379V18H10.8571V15.2379C13.6686 14.8337 16 12.459 16 9.57898H14.5429Z"/>
 </svg>
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
index c3e6916b..059d3223 100644
--- a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
@@ -643,11 +643,17 @@
         assert(param !== null);
         timeLapseSaver = await this.captureTimeLapse(param);
       } finally {
-        // TODO(b/236800499): Handle video too short.
         state.set(state.State.RECORDING, false);
         this.recordTime.stop({pause: false});
       }
 
+      if (this.recordTime.inMilliseconds() <
+          (MINIMUM_VIDEO_DURATION_IN_MILLISECONDS * TIME_LAPSE_INITIAL_SPEED)) {
+        toast.show(I18nString.ERROR_MSG_VIDEO_TOO_SHORT);
+        timeLapseSaver.cancel();
+        return [Promise.resolve()];
+      }
+
       return [this.handler.onTimeLapseCaptureDone({
         autoStopped: this.autoStopped,
         duration: this.recordTime.inMilliseconds(),
diff --git a/ash/webui/camera_app_ui/resources/js/type.ts b/ash/webui/camera_app_ui/resources/js/type.ts
index 5a99a5139..8c50c7a 100644
--- a/ash/webui/camera_app_ui/resources/js/type.ts
+++ b/ash/webui/camera_app_ui/resources/js/type.ts
@@ -440,10 +440,10 @@
 }
 
 /**
- * Throws when the GIF recording is ended with no frame captured.
+ * Throws when the GIF or time lapse recording is ended with no frame captured.
  */
 export class NoFrameError extends Error {
-  constructor(message = 'No frames captured during GIF recording') {
+  constructor(message = 'No frames captured during the recording') {
     super(message);
     this.name = this.constructor.name;
   }
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera/options.ts b/ash/webui/camera_app_ui/resources/js/views/camera/options.ts
index 219c95fb..f7edfbb 100644
--- a/ash/webui/camera_app_ui/resources/js/views/camera/options.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/camera/options.ts
@@ -23,7 +23,7 @@
  * Creates a controller for the options of Camera view.
  */
 export class Options implements CameraUI {
-  private readonly toggleMic = dom.get('#toggle-mic', HTMLInputElement);
+  private readonly toggleMic = dom.get('#toggle-mic', HTMLButtonElement);
 
   private readonly openMirrorPanel =
       dom.get('#open-mirror-panel', HTMLButtonElement);
@@ -71,23 +71,15 @@
     dom.get('#open-settings', HTMLButtonElement)
         .addEventListener('click', () => nav.open(ViewName.SETTINGS));
 
-    this.toggleMic.addEventListener('click', () => this.updateAudioByMic());
-
     this.initOpenMirrorPanel();
     this.initOpenGridPanel();
     this.initOpenTimerPanel();
     this.initOpenPTZPanel();
+    this.initToggleMic();
 
     // Restore saved mirroring states per video device.
     this.mirroringToggles =
         localStorage.getObject(LocalStorageKey.MIRRORING_TOGGLES);
-
-    util.bindElementAriaLabelWithState({
-      element: this.toggleMic,
-      state: state.State.MIC,
-      onLabel: I18nString.ARIA_MUTE_OFF,
-      offLabel: I18nString.ARIA_MUTE_ON,
-    });
   }
 
   private setAriaLabelForOptionButton(
@@ -230,6 +222,30 @@
     });
   }
 
+  private initToggleMic() {
+    const updateMicState = (newMicState: boolean) => {
+      state.set(state.State.MIC, newMicState);
+      // The checked state is whether the mic is muted or not, which is the
+      // inverse of whether the mic is enabled.
+      this.toggleMic.ariaChecked = newMicState ? 'false' : 'true';
+      this.updateAudioByMic();
+    };
+    updateMicState(localStorage.getBool(LocalStorageKey.TOGGLE_MIC, true));
+    this.toggleMic.addEventListener('click', () => {
+      const newMicState = !state.get(state.State.MIC);
+      updateMicState(newMicState);
+      localStorage.set(LocalStorageKey.TOGGLE_MIC, newMicState);
+    });
+    // The label on/off state is whether the mic is muted or not, which is also
+    // the inverse of whether the mic is enabled.
+    util.bindElementAriaLabelWithState({
+      element: this.toggleMic,
+      state: state.State.MIC,
+      onLabel: I18nString.ARIA_MUTE_OFF,
+      offLabel: I18nString.ARIA_MUTE_ON,
+    });
+  }
+
   onUpdateCapability(cameraInfo: CameraInfo): void {
     state.set(state.State.MULTI_CAMERA, cameraInfo.devicesInfo.length >= 2);
   }
@@ -294,7 +310,7 @@
    */
   private updateAudioByMic() {
     if (this.audioTrack) {
-      this.audioTrack.enabled = this.toggleMic.checked;
+      this.audioTrack.enabled = state.get(state.State.MIC);
     }
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/views/main.html b/ash/webui/camera_app_ui/resources/views/main.html
index 6a9bc3c..9fb8033 100644
--- a/ash/webui/camera_app_ui/resources/views/main.html
+++ b/ash/webui/camera_app_ui/resources/views/main.html
@@ -21,7 +21,7 @@
     <link rel="stylesheet" href="/css/views/settings.css">
     <script type="module" src="/js/init.js"></script>
   </head>
-  <body class="sound mirror mic view-splash">
+  <body class="sound mirror view-splash">
     <div id="spoken_msg" class="centered-overlay" tabindex="-1"
          aria-live="polite"></div>
     <div id="view-camera">
@@ -129,9 +129,13 @@
                 i18n-label="back_button"></button>
       </div>
       <div class="top-stripe right-stripe circle buttons">
-        <input id="toggle-mic" type="checkbox" tabindex="0"
-               i18n-label="toggle_mic_button" data-state="mic"
-               i18n-aria="aria_mute_off" data-key="toggleMic" checked>
+        <button id="toggle-mic" role="checkbox" tabindex="0"
+               i18n-label="toggle_mic_button" i18n-aria="aria_mute_off">
+          <svg-wrapper name="camera_button_mic_off.svg"
+                       class="off-icon"></svg-wrapper>
+          <svg-wrapper name="camera_button_mic_on.svg"
+                       class="on-icon"></svg-wrapper>
+        </button>
       </div>
       <div id="options-group" class="left-stripe buttons circle">
         <!--
diff --git a/ash/webui/personalization_app/mojom/personalization_app.mojom b/ash/webui/personalization_app/mojom/personalization_app.mojom
index 4d95a6b..812f661 100644
--- a/ash/webui/personalization_app/mojom/personalization_app.mojom
+++ b/ash/webui/personalization_app/mojom/personalization_app.mojom
@@ -618,6 +618,11 @@
   // Notifies the JS side about the current state of TopicSource.
   OnTopicSourceChanged(TopicSource topic_source);
 
+  // Notifies the JS side about the current state of ScreenSaverDuration.
+  //
+  // SPECIAL NOTE: 0 means forever.
+  OnScreenSaverDurationChanged(uint32 minutes);
+
   // Notifies the JS side about the current state of TemperatureUnit.
   OnTemperatureUnitChanged(TemperatureUnit temperature_unit);
 
diff --git a/ash/webui/personalization_app/personalization_app_ui.cc b/ash/webui/personalization_app/personalization_app_ui.cc
index 59270f0..7febc6d 100644
--- a/ash/webui/personalization_app/personalization_app_ui.cc
+++ b/ash/webui/personalization_app/personalization_app_ui.cc
@@ -293,6 +293,7 @@
       {"wallpaperColorDescription",
        IDS_PERSONALIZATION_APP_KEYBOARD_BACKLIGHT_WALLPAPER_COLOR_DESCRIPTION},
       {"zoneTitle", IDS_PERSONALIZATION_APP_KEYBOARD_BACKLIGHT_ZONE_TITLE},
+      {"keyboardZonesTitle", IDS_PERSONALIZATION_APP_KEYBOARD_ZONES_TITLE},
 
       // Google Photos strings
       // TODO(b/229149314): Finalize error and retry strings.
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
index 5ed9b66..51ea6631 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
@@ -11,7 +11,7 @@
 import {PersonalizationStore} from '../personalization_store.js';
 import {isNonEmptyArray, isRecentHighlightsAlbum} from '../utils.js';
 
-import {setAlbumsAction, setAmbientModeEnabledAction, setAmbientUiVisibilityAction, setAnimationThemeAction, setPreviewsAction, setTemperatureUnitAction, setTopicSourceAction} from './ambient_actions.js';
+import {setAlbumsAction, setAmbientModeEnabledAction, setAmbientUiVisibilityAction, setAnimationThemeAction, setPreviewsAction, setScreenSaverDurationAction, setTemperatureUnitAction, setTopicSourceAction} from './ambient_actions.js';
 import {getAmbientProvider} from './ambient_interface_provider.js';
 
 /** @fileoverview listens for updates on ambient mode changes. */
@@ -70,6 +70,11 @@
     store.dispatch(setAnimationThemeAction(animationTheme));
   }
 
+  onScreenSaverDurationChanged(minutes: number): void {
+    const store = PersonalizationStore.getInstance();
+    store.dispatch(setScreenSaverDurationAction(minutes));
+  }
+
   onTopicSourceChanged(topicSource: TopicSource) {
     const store = PersonalizationStore.getInstance();
     // If the first time receiving `topicSource`, allow logging load
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html
index c069801f..c027ba1 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html
@@ -180,7 +180,8 @@
                 selected-temperature-unit="[[temperatureUnitToString_(temperatureUnit_)]]">
             </ambient-weather-unit>
             <template is="dom-if" if="[[isScreenSaverDurationEnabled_]]">
-              <duration-list></duration-list>
+              <duration-list duration="[[duration_]]">
+              </duration-list>
             </template>
           </template>
         </template>
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
index ebfd324..980e75c8 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
@@ -56,6 +56,10 @@
         value: null,
         observer: 'onAmbientModeEnabledChanged_',
       },
+      duration_: {
+        type: Number,
+        value: null,
+      },
       temperatureUnit_: {
         type: Number,
         value: null,
@@ -91,8 +95,10 @@
   private albums_: AmbientModeAlbum[]|null;
   private ambientModeEnabled_: boolean|null;
   private animationTheme_: AnimationTheme|null;
+  private duration_: number|null;
   private temperatureUnit_: TemperatureUnit|null;
   private topicSource_: TopicSource|null;
+  private isScreenSaverDurationEnabled_: boolean;
   private isPersonalizationJellyEnabled_: boolean;
 
   // Refetch albums if the user is currently viewing ambient subpage, focuses
@@ -130,6 +136,8 @@
         'temperatureUnit_', state => state.ambient.temperatureUnit);
     this.watch<AmbientSubpage['topicSource_']>(
         'topicSource_', state => state.ambient.topicSource);
+    this.watch<AmbientSubpage['duration_']>(
+        'duration_', state => state.ambient.duration);
     this.updateFromStore();
 
     getAmbientProvider().setPageViewed();
@@ -226,7 +234,8 @@
 
   private computeLoading_(): boolean {
     return this.ambientModeEnabled_ === null || this.albums_ === null ||
-        this.topicSource_ === null || this.temperatureUnit_ === null;
+        this.topicSource_ === null || this.temperatureUnit_ === null ||
+        (this.isScreenSaverDurationEnabled_ && this.duration_ === null);
   }
 
   private getPlaceholders_(x: number): number[] {
diff --git a/ash/webui/personalization_app/resources/js/ambient/duration_list_element.ts b/ash/webui/personalization_app/resources/js/ambient/duration_list_element.ts
index bc5d19c..8d660a22 100644
--- a/ash/webui/personalization_app/resources/js/ambient/duration_list_element.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/duration_list_element.ts
@@ -37,6 +37,11 @@
       /**
        * Used to refer to the enum values in HTML file.
        */
+      duration: {
+        type: Number,
+        observer: 'onDurationChanged_',
+      },
+
       options_: {
         type: Array,
         value: [
@@ -70,9 +75,16 @@
     };
   }
 
+  private duration: number|null;
   private options_: DurationOption[];
   private selectedDuration_: string;
 
+  private onDurationChanged_(value: number|null) {
+    if (value) {
+      this.selectedDuration_ = value.toString();
+    }
+  }
+
   private setScreenSaverDuration_(minutes: number) {
     setScreenSaverDuration(minutes, getAmbientProvider(), this.getStore());
   }
diff --git a/ash/webui/personalization_app/resources/js/keyboard_backlight/zone_customization_element.html b/ash/webui/personalization_app/resources/js/keyboard_backlight/zone_customization_element.html
index 09d2f11..6ed9f2e6f 100644
--- a/ash/webui/personalization_app/resources/js/keyboard_backlight/zone_customization_element.html
+++ b/ash/webui/personalization_app/resources/js/keyboard_backlight/zone_customization_element.html
@@ -17,10 +17,12 @@
   #zoneSelector {
     background-color: var(--cros-tab-slider-track-color);
     border-radius: 24px;
+    column-gap: 2px;
     display: grid;
     grid-template-columns: repeat(auto-fit, minmax(0,1fr));
     grid-template-rows: minmax(0,1fr);
     margin-block-end: 28px;
+    margin-block-start: 2px;
     width: 100%;
   }
 
@@ -69,15 +71,25 @@
     word-break: break-all;
     word-wrap: break-word;
   }
+
+  #zoneSelector:focus-visible,
+  color-selector:focus-visible {
+    outline: none;
+  }
+
+  .zone-tab:focus-visible {
+    outline: 2px solid var(--cros-focus-ring-color);
+  }
 </style>
 <cr-dialog id="dialog" show-on-attach>
-  <div slot="body">
+  <div slot="body" aria-label=" ">
     <iron-a11y-keys id="zoneKeys" keys="left right enter" on-keys-pressed="onZoneKeysPress_">
     </iron-a11y-keys>
     <iron-selector
         id="zoneSelector"
         selected="0"
         selected-item="{{ironSelectedZone_}}"
+        aria-label$="[[getZoneTabListAriaLabel_()]]"
         role="tablist">
       <template is="dom-repeat" items="[[zoneIdxs_]]" as="zoneIdx">
         <div
@@ -86,6 +98,7 @@
             tabindex$="[[getZoneTabIndex_(zoneIdx, zoneSelected_)]]"
             data-zone-idx$="[[zoneIdx]]"
             on-click="onClickZoneTab_"
+            aria-description$="[[getZoneColorDescription_(zoneIdx, zoneColors_)]]"
             aria-selected$="[[getZoneAriaSelected_(zoneIdx, zoneSelected_)]]"
             role="tab">
           <paper-ripple fit></paper-ripple>
@@ -100,7 +113,8 @@
         is-customized-dialog
         selected-color="[[getSelectedColor_(zoneSelected_, zoneColors_)]]"
         on-wallpaper-color-selected="onWallpaperColorSelected_"
-        on-preset-color-selected="onPresetColorSelected_">
+        on-preset-color-selected="onPresetColorSelected_"
+        role="tabpanel">
       <div slot="button-container" class="customization-button-container">
         <cr-button class="primary action-button" id="dialogCloseButton"
             on-click="onClickCloseDialog_">
diff --git a/ash/webui/personalization_app/resources/js/keyboard_backlight/zone_customization_element.ts b/ash/webui/personalization_app/resources/js/keyboard_backlight/zone_customization_element.ts
index 822cfec..301565d2 100644
--- a/ash/webui/personalization_app/resources/js/keyboard_backlight/zone_customization_element.ts
+++ b/ash/webui/personalization_app/resources/js/keyboard_backlight/zone_customization_element.ts
@@ -17,6 +17,7 @@
 import {assert} from 'chrome://resources/js/assert_ts.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';
+import {afterNextRender} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {BacklightColor, CurrentBacklightState} from '../../personalization_app.mojom-webui.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
@@ -99,6 +100,16 @@
         'currentBacklightState_',
         state => state.keyboardBacklight.currentBacklightState);
     this.updateFromStore();
+    // Set focus on the currently selected zone to overwrite the default focus
+    // on the dialog title.
+    afterNextRender(this, () => {
+      const selectedZoneElem =
+          this.shadowRoot!.querySelector('.zone-tab[aria-selected=true]') as
+          HTMLElement;
+      if (selectedZoneElem) {
+        selectedZoneElem.focus();
+      }
+    });
   }
 
   private computeZoneIdxs_(): number[] {
@@ -203,6 +214,16 @@
     return zoneIdx === zoneSelected ? '0' : '-1';
   }
 
+  private getZoneTabListAriaLabel_() {
+    return this.i18n('keyboardZonesTitle');
+  }
+
+  private getZoneColorDescription_(
+      zoneSelected: number, zoneColors: BacklightColor[]): string {
+    const zoneColorId = this.getColorId_(zoneSelected, zoneColors);
+    return zoneColorId ? this.i18n(zoneColorId) : '';
+  }
+
   private getZoneAriaSelected_(zoneIdx: number, zoneSelected: number) {
     return (zoneIdx === zoneSelected).toString();
   }
diff --git a/ash/webui/scanning/resources/loading_page.html b/ash/webui/scanning/resources/loading_page.html
index 3c1a683..26b6eeb 100644
--- a/ash/webui/scanning/resources/loading_page.html
+++ b/ash/webui/scanning/resources/loading_page.html
@@ -69,8 +69,18 @@
     <paper-progress indeterminate></paper-progress>
   </div>
   <div id="noScannersDiv" hidden="[[!noScannersAvailable_]]">
-    <img src$="[[getNoScannersSvgSrc_(isDarkModeEnabled_)]]"
-        alt="[[i18n('noScannersText')]]">
+    <!-- TODO(b/276493795): After the Jelly experiment is launched, remove
+                            used image elements and SVGs. -->
+    <template is="dom-if" if="[[!isJellyEnabled_]]">
+      <img src$="[[getNoScannersSvgSrc_(isDarkModeEnabled_)]]"
+          alt="[[i18n('noScannersText')]]">
+    </template>
+    <template is="dom-if" if="[[isJellyEnabled_]]">
+      <svg preserveAspectRatio="xMidYMid meet" role="img" viewBox="0 0 257 256">
+        <title>[[i18n('noScannersSubtext')]]</title>
+        <use href="svg/illo_no_scanner.svg#illo_no_scanner"></use>
+      </svg>
+    </template>
     <h1>[[i18n('noScannersText')]]</h1>
     <span id="noScannersSubtext">[[i18n('noScannersSubtext')]]</span>
     <div id="buttonDiv">
diff --git a/ash/webui/scanning/resources/scan_preview.html b/ash/webui/scanning/resources/scan_preview.html
index 10c98392..24cf65ce 100644
--- a/ash/webui/scanning/resources/scan_preview.html
+++ b/ash/webui/scanning/resources/scan_preview.html
@@ -90,12 +90,17 @@
   }
 
   .scanned-image {
-    box-shadow: var(--scanned-image-shadowed)
+    box-shadow: var(--scanned-image-shadow);
     margin-bottom: var(--scanned-image-margin-bottom);
     margin-inline-start: 12px;
     width: calc(100% - 24px);
   }
 
+  .svg-wrapper {
+    margin: var(--ready-to-scan-image-margin-top) auto 32px;
+    width: 50%;
+  }
+
   :host([show-single-image-focus_]) .preview:hover .focused-scanned-image {
     box-shadow: var(--image-focus-shadow);
   }
@@ -152,10 +157,21 @@
   <div id="helpOrProgress" class="preview-item" aria-hidden="true"
       hidden$="[[!showHelpOrProgress_]]">
     <div id="helpDiv" hidden$="[[!showHelperText_]]">
-      <img id="readyToScanImg"
-          src$="[[getReadyToScanSvgSrc_(isDarkModeEnabled_)]]"
-          alt="[[i18n('scanPreviewHelperText')]]">
-      </img>
+      <template is="dom-if" if="[[!isJellyEnabled_]]">
+        <img id="readyToScanImg"
+            src$="[[getReadyToScanSvgSrc_(isDarkModeEnabled_)]]"
+            alt="[[i18n('scanPreviewHelperText')]]">
+        </img>
+      </template>
+      <template is="dom-if" if="[[isJellyEnabled_]]">
+        <span class="svg-wrapper">
+          <svg id="readyToScanSvg" preserveAspectRatio="xMidYMid meet"
+              role="img" viewBox="0 0 257 256">
+            <title>[[i18n('scanPreviewHelperText')]]</title>
+            <use href="svg/illo_ready_to_scan.svg#illo_ready_to_scan"></use>
+          </svg>
+        </span>
+      </template>
       <span id="helperText">
         [[i18n('scanPreviewHelperText')]]
       </span>
diff --git a/ash/webui/scanning/resources/scan_preview.js b/ash/webui/scanning/resources/scan_preview.js
index 23020376..04c76526 100644
--- a/ash/webui/scanning/resources/scan_preview.js
+++ b/ash/webui/scanning/resources/scan_preview.js
@@ -84,6 +84,14 @@
       type: Boolean,
     },
 
+    /** @protected {boolean} */
+    isJellyEnabled_: {
+      type: Boolean,
+      value: () => {
+        return loadTimeData.getBoolean('isJellyEnabledForScanningApp');
+      },
+    },
+
     /**
      * The object URLs of the scanned images.
      * @type {!Array<string>}
@@ -583,6 +591,11 @@
     this.style.setProperty('--action-toolbar-left', leftPosition + 'px');
   },
 
+  /** @param {boolean} enabled */
+  setIsJellyEnabledForTesting(enabled) {
+    this.isJellyEnabled_ = enabled;
+  },
+
   /**
    * Called when the "show-remove-page-dialog" event fires from the action
    * toolbar button click.
diff --git a/ash/webui/scanning/resources/scanning_app_resources.grd b/ash/webui/scanning/resources/scanning_app_resources.grd
index a49337f..ec0e5dd 100644
--- a/ash/webui/scanning/resources/scanning_app_resources.grd
+++ b/ash/webui/scanning/resources/scanning_app_resources.grd
@@ -57,8 +57,10 @@
       <include name="IDR_SCANNING_APP_SCANNERS_LOADING_ILLO_SVG" file="svg/illo_loading_scanner.svg" type="BINDATA" />
       <include name="IDR_SCANNING_APP_SCANNERS_LOADING_SVG" file="svg/scanners_loading.svg" type="BINDATA" />
       <include name="IDR_SCANNING_APP_SCANNERS_LOADING_DARK_SVG" file="svg/scanners_loading_dark.svg" type="BINDATA" />
+      <include name="IDR_SCANNING_APP_NO_SCANNERS_ILLO_SVG" file="svg/illo_no_scanner.svg" type="BINDATA" />
       <include name="IDR_SCANNING_APP_NO_SCANNERS_SVG" file="svg/no_scanners.svg" type="BINDATA" />
       <include name="IDR_SCANNING_APP_NO_SCANNERS_DARK_SVG" file="svg/no_scanners_dark.svg" type="BINDATA" />
+      <include name="IDR_SCANNING_APP_READY_TO_SCAN_ILLO_SVG" file="svg/illo_ready_to_scan.svg" type="BINDATA" />
       <include name="IDR_SCANNING_APP_READY_TO_SCAN_SVG" file="svg/ready_to_scan.svg" type="BINDATA" />
       <include name="IDR_SCANNING_APP_READY_TO_SCAN_DARK_SVG" file="svg/ready_to_scan_dark.svg" type="BINDATA" />
       <include name="IDR_SCANNING_APP_REMOVE_PAGE_SVG" file="svg/remove_page.svg" type="BINDATA" />
diff --git a/ash/webui/scanning/resources/svg/illo_no_scanner.svg b/ash/webui/scanning/resources/svg/illo_no_scanner.svg
new file mode 100644
index 0000000..265145a
--- /dev/null
+++ b/ash/webui/scanning/resources/svg/illo_no_scanner.svg
@@ -0,0 +1,37 @@
+<svg id="illo_no_scanner" xmlns="http://www.w3.org/2000/svg" width="257" height="256" viewBox="0 0 257 256" fill="none">
+<g clip-path="url(#clip0_2_30972)">
+<path d="M101.744 174.4C102.444 175 106.744 178.8 112.044 177.8C117.344 176.8 120.344 171.7 120.644 171.1C122.444 167.9 122.044 165.3 124.244 164.3C124.905 163.944 125.657 163.792 126.405 163.864C127.152 163.935 127.862 164.226 128.444 164.7C130.644 166.4 129.544 170.8 129.144 172.8C128.693 174.992 127.734 177.047 126.344 178.8C124.519 180.925 122.177 182.544 119.544 183.5C116.767 184.297 113.821 184.297 111.044 183.5" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M97.1439 201C103.744 201 110.344 200.9 116.844 199.6C123.344 198.3 129.544 196.7 132.644 191.2C134.244 188.2 134.444 184.6 134.544 181.1C134.585 180.195 134.518 179.289 134.344 178.4C134.22 177.95 133.993 177.534 133.681 177.187C133.368 176.84 132.979 176.57 132.544 176.4" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M115.344 189.4L120.344 188.7C122.348 188.554 124.282 187.899 125.962 186.796C127.642 185.694 129.013 184.181 129.944 182.4C131.033 180.361 131.808 178.17 132.244 175.9C132.644 174.1 132.744 173 132.144 171.7C131.685 170.547 130.835 169.591 129.744 169" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M101.744 174.4C102.122 173.28 102.625 172.207 103.244 171.2L103.644 170.4L104.544 169.1C105.744 167.2 106.944 165.2 107.044 162.9C107.111 162.589 107.111 162.267 107.042 161.956C106.973 161.645 106.837 161.353 106.644 161.1C106.336 160.729 105.915 160.469 105.445 160.361C104.976 160.252 104.483 160.301 104.044 160.5C103.137 160.805 102.315 161.319 101.644 162C100.144 163.8 95.8439 169.1 90.1439 176.4" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M111.344 133L105.544 120.3L93.3439 119.8L90.0439 130.2" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M103.344 124C110.137 124 115.644 118.493 115.644 111.7C115.644 104.907 110.137 99.4 103.344 99.4C96.5508 99.4 91.0439 104.907 91.0439 111.7C91.0439 118.493 96.5508 124 103.344 124Z" fill="var(--cros-sys-illo-base)" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M106.044 114.7C108.218 114.91 110.392 114.304 112.144 113" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M109.744 101.9C108.588 100.88 107.198 100.163 105.696 99.8143C104.195 99.4652 102.631 99.4947 101.144 99.9C98.2439 100.6 95.4439 101 93.4439 103.3C91.4439 105.6 91.2439 107.8 90.6439 109.6C90.3244 110.534 90.1556 111.513 90.1439 112.5C90.1439 114 90.6439 113.7 91.7439 113.3C96.015 111.65 100.076 109.502 103.844 106.9C105.92 105.367 107.891 103.697 109.744 101.9Z" fill="var(--cros-sys-illo-color1)" />
+<path d="M97.8439 102.8C96.6439 103.3 95.9439 105.8 94.5439 106.5C94.7439 106.4 92.1439 104.7 93.1439 103.4C94.2101 102.061 95.4948 100.911 96.9439 100L101.744 96.5L106.344 92.9L108.444 91.6C109.255 91.0947 110.188 90.8183 111.144 90.8C111.643 90.7675 112.142 90.8602 112.596 91.0698C113.05 91.2793 113.445 91.5991 113.744 92C113.98 92.5773 114.084 93.1999 114.05 93.8226C114.015 94.4453 113.842 95.0524 113.544 95.6C114.636 95.0087 115.819 94.6032 117.044 94.4C117.416 94.2831 117.81 94.2584 118.193 94.3281C118.577 94.3978 118.937 94.5598 119.244 94.8C119.756 95.3092 120.074 95.9812 120.144 96.7C120.444 99.7 118.544 102.4 116.644 104.7L115.344 105.8C114.944 105.9 113.344 103.5 112.544 103C108.544 100.6 106.844 98.9 97.8439 102.8Z" fill="var(--cros-sys-illo-color1)" />
+<path d="M117.144 193.7L122.244 193.1C124.644 192.632 126.924 191.679 128.944 190.3C130.094 189.325 131.045 188.136 131.744 186.8C132.922 184.792 133.734 182.591 134.144 180.3C134.562 178.925 134.527 177.453 134.044 176.1C133.753 175.299 133.231 174.603 132.544 174.1" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M101.044 214.2C86.4439 226.1 66.5439 227.7 51.8439 218.6C33.9439 207.6 31.5439 185.5 34.2439 172.1C38.1439 152.8 55.1439 136.8 77.8439 131.6C81.8451 130.636 85.9314 130.066 90.0439 129.9C91.206 131.728 92.7429 133.288 94.553 134.478C96.363 135.667 98.405 136.459 100.544 136.8C102.621 136.986 104.714 136.705 106.669 135.979C108.624 135.252 110.392 134.098 111.844 132.6C113.818 132.914 115.762 133.381 117.661 133.996M125.744 198C129.635 202.086 134.43 205.202 139.744 207.1C156.144 212.6 176.544 204.6 191.844 187.2L173.844 158.6L151.644 167.7C150.704 165.555 148.98 160.904 146.947 157.464" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M101.044 214.2C97.4439 201.3 93.7439 188.5 90.0439 175.6L71.1439 183.2L70.3439 167.2" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M99.3439 206.7H116.244L118.644 199.3" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M130.244 52.6C129.63 52.7016 129.051 52.9564 128.562 53.341C128.072 53.7256 127.688 54.2274 127.444 54.8L123.244 64.7C122.998 65.2731 122.915 65.9028 123.003 66.5201C123.091 67.1374 123.348 67.7185 123.744 68.2L128.244 74.3L132.044 52.4L130.244 52.6Z" fill="var(--cros-sys-illo-color3)" />
+<path fill-rule="evenodd" clip-rule="evenodd" d="M132.544 49.7C155.644 17.6 200.744 14 225.844 37.3C248.444 58.2 251.144 97.3 228.144 124L140.717 158.817C144.369 155.986 146.721 151.556 146.721 146.577C146.721 138.029 139.791 131.1 131.244 131.1C124.061 131.1 118.022 135.992 116.276 142.627L116.244 142.6L128.244 74.3L130.244 76.8C130.601 77.301 131.087 77.6958 131.65 77.9423C132.214 78.1889 132.834 78.2779 133.444 78.2L144.144 76.9C144.77 76.7968 145.361 76.5425 145.866 76.1591C146.372 75.7757 146.776 75.2749 147.044 74.7L151.244 64.8C151.49 64.2269 151.573 63.5972 151.485 62.9799C151.396 62.3626 151.14 61.7815 150.744 61.3L144.244 52.7C143.887 52.1735 143.386 51.7612 142.801 51.5129C142.215 51.2645 141.57 51.1906 140.944 51.3L132.044 52.4L132.544 49.7Z" fill="var(--cros-sys-illo-color1-2)" />
+<path d="M131.244 161.2C139.362 161.2 145.944 154.619 145.944 146.5C145.944 138.381 139.362 131.8 131.244 131.8C123.125 131.8 116.544 138.381 116.544 146.5C116.544 154.619 123.125 161.2 131.244 161.2Z" fill="var(--cros-sys-illo-color1-2)" />
+<path fill-rule="evenodd" clip-rule="evenodd" d="M131.244 132.8C123.678 132.8 117.544 138.934 117.544 146.5C117.544 154.066 123.678 160.2 131.244 160.2C138.81 160.2 144.944 154.066 144.944 146.5C144.944 138.934 138.81 132.8 131.244 132.8ZM115.544 146.5C115.544 137.829 122.573 130.8 131.244 130.8C139.915 130.8 146.944 137.829 146.944 146.5C146.944 155.171 139.915 162.2 131.244 162.2C122.573 162.2 115.544 155.171 115.544 146.5Z" fill="var(--cros-sys-illo-color1)" />
+<path d="M114.011 156.753C113.786 157.612 113.741 158.507 113.878 159.384C114.014 160.26 114.331 161.102 114.808 161.858C115.284 162.613 115.912 163.269 116.654 163.784C117.396 164.3 118.236 164.666 119.126 164.86C120.753 165.235 122.463 165.039 123.956 164.308" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M106.844 70C101.944 65.3 98.1439 64.3 95.3439 64.4C89.8439 64.6 88.1439 69.5 82.2439 70.1C76.3439 70.7 73.1439 68.2 69.7439 65.7" stroke="var(--cros-sys-illo-secondary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M132.844 134.8C130.253 134.612 127.673 135.285 125.503 136.713C123.333 138.142 121.696 140.246 120.844 142.7C118.944 148.3 121.844 154.8 127.744 157.4" stroke="var(--cros-sys-illo-base)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M187.444 151.3L187.244 151.5C189.844 150.3 191.844 148.1 194.144 146.4L196.344 144.9C199.114 143.133 202.024 141.594 205.044 140.3C206.644 139.7 209.144 138.6 210.444 140.2C210.689 140.644 210.818 141.143 210.818 141.65C210.818 142.157 210.689 142.656 210.444 143.1C209.603 144.173 208.547 145.058 207.344 145.7L203.544 148.3C201.044 150.1 198.444 151.8 195.844 153.4L207.644 145.8C208.844 145.1 210.944 143.8 212.344 143.7C213.744 143.6 215.244 144.5 214.644 146.2C214.25 147.108 213.63 147.899 212.844 148.5C210.844 149.9 208.744 151.3 206.544 152.6C204.344 153.9 201.144 155.9 198.444 157.7C201.044 155.9 203.744 154.2 206.544 152.6L210.644 150.3C211.744 149.7 213.744 148.1 214.844 148.8C217.444 150.4 214.744 153 213.744 153.7L200.644 162L208.844 156.8C210.193 155.732 211.765 154.98 213.444 154.6C213.667 154.521 213.904 154.486 214.14 154.499C214.377 154.511 214.609 154.57 214.822 154.673C215.036 154.775 215.227 154.918 215.385 155.094C215.544 155.271 215.665 155.477 215.744 155.7C215.933 156.115 216.014 156.571 215.979 157.026C215.944 157.48 215.794 157.919 215.544 158.3C214.653 159.323 213.607 160.2 212.444 160.9C208.744 163.4 207.044 164.6 203.444 167.4C199.844 170.2 199.244 172.6 196.444 175.1C194.08 177.149 191.273 178.621 188.244 179.4" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M187.744 163.8C188.523 161.796 188.846 159.643 188.69 157.499C188.535 155.354 187.904 153.271 186.844 151.4C186.544 151 187.944 148.9 188.244 148.4C188.544 147.9 189.744 145.1 189.544 143.5C189.547 143.055 189.385 142.625 189.089 142.293C188.794 141.961 188.386 141.749 187.944 141.7C186.844 141.5 186.044 142.4 185.244 143.2C180.89 147.671 177.428 152.932 175.044 158.7" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M209.544 106C210.351 105.48 211.253 105.125 212.198 104.954C213.143 104.783 214.112 104.8 215.05 105.004C215.989 105.209 216.877 105.596 217.665 106.145C218.454 106.693 219.126 107.391 219.644 108.2V108.4L228.844 123.3C229.877 124.998 230.194 127.036 229.725 128.967C229.256 130.898 228.04 132.565 226.344 133.6V133.6C225.517 134.113 224.597 134.459 223.636 134.616C222.676 134.773 221.693 134.739 220.746 134.516C219.798 134.293 218.904 133.886 218.114 133.317C217.325 132.748 216.655 132.028 216.144 131.2H216.044L206.944 116.3C205.929 114.65 205.602 112.669 206.032 110.78C206.462 108.892 207.615 107.248 209.244 106.2L209.544 106Z" stroke="var(--cros-sys-illo-color4)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M184.944 105.9C201.568 105.9 215.044 92.4238 215.044 75.8C215.044 59.1762 201.568 45.7 184.944 45.7C168.32 45.7 154.844 59.1762 154.844 75.8C154.844 92.4238 168.32 105.9 184.944 105.9Z" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="6 6" />
+<path d="M181.244 79.1C181.774 77.7724 182.635 76.6021 183.744 75.7C185.191 74.6841 186.773 73.8763 188.444 73.3C189.754 72.8362 191.025 72.2677 192.244 71.6C193.144 70.9834 193.84 70.1132 194.244 69.1C194.542 68.4401 194.696 67.7242 194.696 67C194.696 66.2758 194.542 65.5599 194.244 64.9C193.903 64.2004 193.427 63.5752 192.844 63.0603C192.26 62.5455 191.58 62.1511 190.844 61.9C189.526 61.2797 188.015 61.2078 186.644 61.7C185.342 62.2298 184.179 63.0508 183.244 64.1L180.244 61.1C181.689 59.5295 183.514 58.3584 185.544 57.7C187.82 57.0263 190.261 57.1677 192.444 58.1C194.144 58.8028 195.652 59.8996 196.844 61.3C197.911 62.591 198.605 64.1487 198.852 65.8052C199.098 67.4617 198.888 69.1541 198.244 70.7C197.652 72.2707 196.564 73.605 195.144 74.5C193.643 75.4333 192.03 76.1725 190.344 76.7C189.168 77.1046 188.056 77.6772 187.044 78.4C186.236 79.1637 185.59 80.0818 185.144 81.1L184.344 83L180.344 81.3L181.244 79.1ZM176.544 90.2C176.336 89.8047 176.213 89.3704 176.183 88.9248C176.154 88.4792 176.217 88.0324 176.37 87.6129C176.524 87.1935 176.763 86.8107 177.073 86.4893C177.383 86.1679 177.757 85.9149 178.17 85.7466C178.584 85.5784 179.028 85.4985 179.475 85.5123C179.921 85.526 180.36 85.6331 180.762 85.8265C181.165 86.0199 181.522 86.2954 181.812 86.6353C182.102 86.9752 182.317 87.3719 182.444 87.8C182.645 88.1679 182.751 88.5806 182.751 89C182.751 89.4194 182.645 89.8321 182.444 90.2C182.299 90.5884 182.072 90.9412 181.778 91.2345C181.485 91.5277 181.132 91.7547 180.744 91.9C180.376 92.1013 179.963 92.2068 179.544 92.2068C179.125 92.2068 178.712 92.1013 178.344 91.9C177.94 91.761 177.571 91.5375 177.26 91.2443C176.95 90.9512 176.706 90.5951 176.544 90.2Z" fill="var(--cros-sys-illo-color1)" />
+<path d="M238.344 154.7C240.553 154.7 242.344 152.909 242.344 150.7C242.344 148.491 240.553 146.7 238.344 146.7C236.135 146.7 234.344 148.491 234.344 150.7C234.344 152.909 236.135 154.7 238.344 154.7Z" fill="var(--cros-sys-illo-color5)" />
+<path d="M84.1439 131.1C88.4439 139.7 97.0439 144.4 104.944 143C107.366 142.62 109.673 141.704 111.697 140.32C113.721 138.936 115.411 137.119 116.644 135" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M114.199 156.264L114.987 156.88L115.129 156.697L115.177 156.471L114.199 156.264ZM105.871 166.915L105.083 166.299L105.006 166.397L104.956 166.511L105.871 166.915ZM107.712 175.644L107.113 176.444H107.113L107.712 175.644ZM116.361 174.522L117.065 175.233L117.115 175.184L117.158 175.128L116.361 174.522ZM124.16 164.261L123.845 163.312C123.654 163.375 123.486 163.495 123.364 163.656L124.16 164.261ZM117.845 143.87C117.959 143.329 117.614 142.799 117.074 142.684C116.533 142.57 116.003 142.915 115.888 143.456L117.845 143.87ZM136.797 161.122C137.322 160.948 137.606 160.382 137.432 159.858C137.258 159.334 136.692 159.05 136.168 159.224L136.797 161.122ZM113.411 155.648L105.083 166.299L106.658 167.531L114.987 156.88L113.411 155.648ZM105.871 166.915C104.956 166.511 104.956 166.511 104.955 166.512C104.955 166.512 104.955 166.512 104.955 166.513C104.955 166.513 104.954 166.514 104.954 166.515C104.953 166.517 104.952 166.519 104.951 166.521C104.949 166.526 104.946 166.532 104.943 166.54C104.937 166.554 104.928 166.575 104.918 166.6C104.898 166.651 104.87 166.721 104.836 166.811C104.77 166.989 104.684 167.242 104.595 167.554C104.418 168.175 104.229 169.045 104.188 170.035C104.104 172.025 104.625 174.58 107.113 176.444L108.312 174.843C106.52 173.501 106.12 171.692 106.186 170.119C106.219 169.327 106.372 168.617 106.518 168.101C106.591 167.846 106.661 167.642 106.712 167.506C106.737 167.438 106.757 167.387 106.77 167.355C106.777 167.339 106.781 167.328 106.784 167.322C106.785 167.319 106.786 167.317 106.786 167.316C106.787 167.316 106.786 167.316 106.786 167.316C106.786 167.316 106.786 167.317 106.786 167.317C106.786 167.317 106.786 167.318 106.786 167.318C106.786 167.318 106.785 167.318 105.871 166.915ZM107.113 176.444C109.626 178.327 112.193 177.976 114.028 177.208C114.938 176.827 115.689 176.339 116.21 175.95C116.472 175.754 116.68 175.581 116.824 175.454C116.897 175.391 116.954 175.338 116.994 175.301C117.015 175.282 117.031 175.266 117.042 175.255C117.048 175.249 117.053 175.245 117.057 175.241C117.059 175.239 117.06 175.237 117.062 175.236C117.062 175.236 117.063 175.235 117.064 175.234C117.064 175.234 117.064 175.234 117.064 175.234C117.065 175.233 117.065 175.233 116.361 174.522C115.658 173.812 115.658 173.812 115.658 173.811C115.658 173.811 115.659 173.811 115.659 173.811C115.659 173.811 115.659 173.81 115.659 173.81C115.66 173.81 115.66 173.81 115.659 173.81C115.659 173.811 115.657 173.812 115.655 173.815C115.65 173.819 115.641 173.828 115.628 173.84C115.602 173.864 115.561 173.902 115.506 173.95C115.395 174.047 115.228 174.187 115.014 174.347C114.582 174.669 113.973 175.062 113.256 175.363C111.836 175.957 110.078 176.166 108.312 174.843L107.113 176.444ZM117.158 175.128L124.957 164.866L123.364 163.656L115.565 173.917L117.158 175.128ZM115.888 143.456L113.221 156.057L115.177 156.471L117.845 143.87L115.888 143.456ZM124.475 165.21L136.797 161.122L136.168 159.224L123.845 163.312L124.475 165.21Z" fill="var(--cros-sys-illo-color1)" />
+</g>
+<defs>
+<clipPath id="clip0_2_30972">
+<rect width="256" height="256" fill="var(--cros-sys-illo-base)" transform="translate(0.743896)" />
+</clipPath>
+</defs>
+</svg>
\ No newline at end of file
diff --git a/ash/webui/scanning/resources/svg/illo_ready_to_scan.svg b/ash/webui/scanning/resources/svg/illo_ready_to_scan.svg
new file mode 100644
index 0000000..148d534
--- /dev/null
+++ b/ash/webui/scanning/resources/svg/illo_ready_to_scan.svg
@@ -0,0 +1,26 @@
+<svg id="illo_ready_to_scan" xmlns="http://www.w3.org/2000/svg" width="257" height="256" viewBox="0 0 257 256" fill="none">
+<path d="M31.4861 225.122H226.017" stroke="var(--cros-sys-illo-color1-2)" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" />
+<path d="M96.5642 155.433C98.0258 153.113 100.317 151.436 102.97 150.745C109.845 149.027 116.252 156.527 127.502 164.886C128.674 165.824 138.986 173.558 148.752 177.933C166.642 186.214 193.986 188.714 205.158 175.355C207.091 172.984 208.526 170.247 209.377 167.308" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M115.47 165.745C114.748 165.102 113.879 164.644 112.94 164.413C112 164.181 111.019 164.183 110.08 164.417C109.767 164.452 109.466 164.554 109.196 164.716C108.927 164.877 108.695 165.095 108.517 165.355C108.017 165.939 107.693 166.652 107.583 167.413C107.472 168.173 107.579 168.95 107.892 169.652" stroke="var(--cros-sys-illo-color1-2)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M128.205 136.214C128.082 136.78 128.081 137.365 128.202 137.931C128.323 138.497 128.564 139.03 128.908 139.496C129.174 139.973 129.558 140.374 130.023 140.661C130.488 140.949 131.018 141.112 131.564 141.136C132.191 141.101 132.803 140.929 133.357 140.632C133.91 140.335 134.392 139.921 134.767 139.417" stroke="var(--cros-sys-illo-color1-2)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M30.4705 154.73C39.4548 157.308 48.9079 159.886 58.6736 162.308C65.8611 164.105 72.8142 165.746 79.6111 167.152C79.6111 167.152 82.1892 167.699 97.1111 169.652C108.361 171.058 113.517 171.449 115.314 168.636C115.742 167.935 115.982 167.134 116.009 166.313C116.036 165.492 115.851 164.677 115.47 163.949C114.767 162.308 113.049 161.058 104.064 159.105C95.0798 157.152 92.8923 157.23 92.1892 155.355C91.4861 153.48 93.0486 151.683 94.2986 150.433" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M93.5173 122.542C91.0173 120.042 86.9548 120.824 84.0642 121.683C81.1735 122.542 76.8767 124.495 73.3611 126.058L64.6892 130.042C60.1579 132.152 52.5798 132.855 38.9861 126.996" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M94.2986 150.433C95.5486 149.496 104.142 143.714 109.845 141.214C111.143 140.588 112.549 140.217 113.986 140.12C116.048 140.124 118.089 140.522 120.002 141.292C123.439 142.542 125.47 144.027 129.142 144.886C132.814 145.746 134.142 145.511 135.705 143.558C137.267 141.605 135.08 139.027 132.658 138.011L130.939 137.23L126.877 134.808C124.064 132.933 122.58 131.527 119.299 130.511C117.895 130.062 116.458 129.722 115.002 129.496C111.902 129.269 108.787 129.56 105.783 130.355C102.409 131.119 99.1512 132.327 96.0954 133.949" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M90.3923 129.886C94.3023 128.015 98.3507 126.447 102.502 125.199C105.555 124.471 108.733 124.444 111.799 125.121C114.845 125.746 118.908 128.089 120.549 130.824" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M102.502 125.199C100.52 123.465 97.9435 122.569 95.3142 122.699C92.3679 123.063 89.4955 123.88 86.7986 125.12L83.9861 126.449" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M113.205 140.199C115.002 140.589 116.408 141.917 117.814 143.011C119.117 144.193 120.664 145.074 122.345 145.589C123.177 145.892 124.072 145.98 124.946 145.843C125.821 145.706 126.646 145.35 127.345 144.808" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M56.0955 132.542C53.9861 141.449 51.7986 150.355 49.6892 159.183L41.2517 157.621L47.8923 130.824L56.0955 132.542Z" fill="var(--cros-sys-illo-color1)" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M51.4861 148.089C55.4988 148.089 58.7517 144.836 58.7517 140.824C58.7517 136.811 55.4988 133.558 51.4861 133.558C47.4734 133.558 44.2205 136.811 44.2205 140.824C44.2205 144.836 47.4734 148.089 51.4861 148.089Z" fill="var(--cros-sys-illo-base)" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M53.5173 139.027L50.783 140.98L54.4548 141.839" stroke="var(--cros-sys-illo-color1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M187.04 57.7437L183.593 58.7584C182.848 58.9776 182.39 59.6533 182.571 60.2675L218.621 182.754C218.801 183.368 219.552 183.688 220.297 183.469L223.745 182.455C224.49 182.235 224.947 181.56 224.766 180.945L188.717 58.4587C188.536 57.8445 187.785 57.5244 187.04 57.7437Z" fill="var(--cros-sys-illo-color1-2)" />
+<path d="M206.794 207.552C208.52 207.552 209.919 206.153 209.919 204.427C209.919 202.701 208.52 201.302 206.794 201.302C205.068 201.302 203.669 202.701 203.669 204.427C203.669 206.153 205.068 207.552 206.794 207.552Z" fill="var(--cros-sys-illo-color2)" />
+<path d="M94.1423 79.183C94.3329 80.2376 94.9324 81.1743 95.8104 81.7889C96.6884 82.4034 97.7737 82.6462 98.8298 82.4642H98.9861L108.517 80.5892C109.582 80.3466 110.508 79.6933 111.093 78.7715C111.678 77.8497 111.876 76.7341 111.642 75.6674V75.6674C111.435 74.6109 110.816 73.6802 109.922 73.0796C109.029 72.479 107.933 72.2577 106.877 72.4642H106.799L97.3454 74.4955C96.321 74.7041 95.4164 75.2995 94.8198 76.158C94.2232 77.0166 93.9806 78.072 94.1423 79.1049V79.183Z" fill="var(--cros-sys-illo-color4)" />
+<path d="M187.987 154.239L187.918 154.276C184.292 156.187 182.897 160.667 184.803 164.282C186.709 167.896 191.193 169.277 194.819 167.365L194.888 167.328C198.514 165.417 199.908 160.937 198.003 157.322C196.097 153.708 191.613 152.328 187.987 154.239Z" fill="var(--cros-sys-illo-color1-2)" />
+<path d="M72.1892 80.1205L74.0642 75.5111C74.0996 75.3736 74.1809 75.2523 74.2945 75.1671C74.4081 75.0819 74.5473 75.0379 74.6892 75.0424L79.6111 74.3393C79.7555 74.3372 79.8989 74.3637 80.033 74.4174C80.1671 74.471 80.2892 74.5507 80.3924 74.6518L83.3611 78.558C83.4503 78.6657 83.5054 78.7975 83.5194 78.9367C83.5333 79.0759 83.5054 79.216 83.4392 79.3393L81.6423 83.9486C81.5905 84.0617 81.5148 84.1621 81.4204 84.2431C81.326 84.324 81.2151 84.3835 81.0955 84.4174L76.1736 85.1205C76.0286 85.1273 75.8838 85.1029 75.7491 85.049C75.6143 84.9951 75.4927 84.9129 75.3923 84.808L72.3454 80.9018C72.2583 80.7938 72.1986 80.6664 72.1714 80.5303C72.1441 80.3943 72.1503 80.2537 72.1892 80.1205V80.1205Z" fill="var(--cros-sys-illo-color3)" />
+<path d="M136.017 70.7455H136.095C139.022 69.2187 142.432 68.9036 145.589 69.8682C148.746 70.8328 151.397 72.9998 152.97 75.9017V75.9017C154.512 78.834 154.827 82.2584 153.846 85.4225C152.864 88.5867 150.667 91.2318 147.736 92.7768H147.658C144.726 94.3186 141.301 94.6333 138.137 93.6518C134.973 92.6704 132.328 90.473 130.783 87.5424V87.5424C130.021 86.0963 129.552 84.5141 129.403 82.8866C129.254 81.259 129.428 79.6179 129.914 78.0576C130.4 76.4972 131.19 75.0481 132.237 73.7933C133.284 72.5386 134.569 71.5029 136.017 70.7455V70.7455Z" stroke="var(--cros-sys-illo-color5)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+<path d="M189.455 128.792C188.887 127.278 187.978 125.915 186.799 124.808V124.808C186.188 124.13 185.477 123.55 184.689 123.089L182.58 121.449C181.766 120.831 181.084 120.056 180.574 119.171C180.064 118.285 179.737 117.306 179.611 116.292C179.41 115.574 179.253 114.843 179.142 114.105C179.042 112.4 178.618 110.729 177.892 109.183L177.189 110.042L176.408 110.745C176.85 111.928 177.139 113.162 177.267 114.417L177.58 116.683C178.059 119.145 179.352 121.374 181.252 123.011L183.439 124.73H183.595C184.247 125.158 184.849 125.656 185.392 126.214C186.815 127.69 187.761 129.558 188.11 131.578C188.458 133.598 188.192 135.676 187.345 137.542C186.785 138.795 185.966 139.916 184.943 140.832C183.92 141.747 182.715 142.436 181.408 142.855C179.135 143.58 176.679 143.476 174.476 142.56C172.273 141.645 170.466 139.977 169.377 137.855C168.583 136.368 168.206 134.695 168.283 133.011C168.266 132.244 168.371 131.479 168.595 130.745V130.745L168.986 128.011C169.362 125.338 168.69 122.623 167.111 120.433L166.408 119.495L164.767 117.23L164.611 116.839L162.502 117.152C162.62 117.545 162.805 117.915 163.049 118.245C163.576 119.109 164.15 119.944 164.767 120.746L165.47 121.605C166.13 122.461 166.602 123.445 166.858 124.495C167.114 125.544 167.147 126.636 166.955 127.699L166.642 130.355C166.392 131.218 166.261 132.112 166.252 133.011C166.145 136.164 167.281 139.232 169.414 141.555C171.547 143.878 174.508 145.271 177.658 145.433H178.283C179.532 145.422 180.772 145.211 181.955 144.808C183.53 144.341 184.987 143.541 186.227 142.463C187.467 141.385 188.461 140.053 189.142 138.558C189.87 137.041 190.273 135.389 190.327 133.708C190.381 132.027 190.084 130.353 189.455 128.792Z" fill="var(--cros-sys-illo-color1)" />
+<path d="M162.267 110.745C162.647 109.562 163.286 108.478 164.137 107.573C164.989 106.667 166.031 105.963 167.189 105.511L167.658 105.355C169.096 104.857 170.641 104.746 172.136 105.034C173.63 105.322 175.023 105.999 176.174 106.995C176.877 107.612 177.459 108.354 177.892 109.183C181.327 105.135 183.167 99.9734 183.067 94.6656C182.966 89.3578 180.932 84.2692 177.345 80.3549C177.097 80.0233 176.727 79.8042 176.316 79.7456C175.906 79.687 175.49 79.7937 175.158 80.0424C175.019 80.105 174.908 80.2161 174.845 80.3549L147.267 109.73C147.102 109.914 146.976 110.129 146.894 110.363C146.813 110.596 146.778 110.844 146.793 111.091C146.807 111.337 146.87 111.579 146.979 111.801C147.087 112.024 147.238 112.222 147.424 112.386H147.502C151.79 115.667 157.111 117.302 162.502 116.995C161.641 115.016 161.558 112.784 162.267 110.745Z" fill="var(--cros-sys-illo-color2)" />
+<path d="M170.47 106.917C169.729 106.906 168.991 107.011 168.283 107.23H167.97C167.081 107.597 166.28 108.15 165.62 108.85C164.96 109.55 164.456 110.383 164.142 111.292C163.829 112.159 163.709 113.083 163.79 114C163.871 114.918 164.151 115.807 164.611 116.605C169.08 115.897 173.21 113.791 176.408 110.589C176.08 109.74 175.543 108.987 174.845 108.402C173.63 107.366 172.065 106.835 170.47 106.917V106.917Z" fill="var(--cros-sys-illo-color2)" />
+<rect x="57.4294" y="185.287" width="161.519" height="37.7483" rx="10" stroke="var(--cros-sys-illo-color1)" stroke-width="2" />
+<line x1="57.321" y1="213.272" x2="218.948" y2="213.272" stroke="var(--cros-sys-illo-color1)" stroke-width="2" />
+</svg>
\ No newline at end of file
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 ff01820a..cdc3a08d 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
@@ -12,6 +12,7 @@
 #include "ash/accelerators/accelerator_alias_converter.h"
 #include "ash/accelerators/accelerator_controller_impl.h"
 #include "ash/accelerators/ash_accelerator_configuration.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/accelerators_util.h"
 #include "ash/public/mojom/accelerator_configuration.mojom-shared.h"
 #include "ash/public/mojom/accelerator_configuration.mojom.h"
@@ -19,6 +20,7 @@
 #include "ash/public/mojom/accelerator_info.mojom-shared.h"
 #include "ash/public/mojom/accelerator_keys.mojom.h"
 #include "ash/shell.h"
+#include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
 #include "ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h"
 #include "ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom.h"
 #include "base/check.h"
@@ -297,6 +299,10 @@
   // Observe top row keys are f-keys preference changes.
   Shell::Get()->keyboard_capability()->AddObserver(this);
 
+  if (features::IsInputDeviceSettingsSplitEnabled()) {
+    Shell::Get()->input_device_settings_controller()->AddObserver(this);
+  }
+
   ash_accelerator_configuration_->AddAcceleratorsUpdatedCallback(
       base::BindRepeating(
           &AcceleratorConfigurationProvider::OnAcceleratorsUpdated,
@@ -327,6 +333,9 @@
     Shell::Get()->keyboard_capability()->RemoveObserver(this);
     Shell::Get()->accelerator_controller()->SetPreventProcessingAccelerators(
         /*prevent_processing_accelerators=*/false);
+    if (features::IsInputDeviceSettingsSplitEnabled()) {
+      Shell::Get()->input_device_settings_controller()->RemoveObserver(this);
+    }
   }
 }
 
@@ -392,6 +401,21 @@
   NotifyAcceleratorsUpdated();
 }
 
+void AcceleratorConfigurationProvider::OnKeyboardConnected(
+    const mojom::Keyboard& keyboard) {
+  NotifyAcceleratorsUpdated();
+}
+
+void AcceleratorConfigurationProvider::OnKeyboardDisconnected(
+    const mojom::Keyboard& keyboard) {
+  NotifyAcceleratorsUpdated();
+}
+
+void AcceleratorConfigurationProvider::OnKeyboardSettingsUpdated(
+    const mojom::Keyboard& keyboard) {
+  NotifyAcceleratorsUpdated();
+}
+
 AcceleratorConfigurationProvider::AcceleratorConfigurationMap
 AcceleratorConfigurationProvider::GetAcceleratorConfig() {
   return CreateConfigurationMap();
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 2d4fb196..df8c033 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h
@@ -11,6 +11,7 @@
 #include "ash/accelerators/accelerator_alias_converter.h"
 #include "ash/accelerators/ash_accelerator_configuration.h"
 #include "ash/public/cpp/accelerator_configuration.h"
+#include "ash/public/cpp/input_device_settings_controller.h"
 #include "ash/public/mojom/accelerator_configuration.mojom-forward.h"
 #include "ash/public/mojom/accelerator_info.mojom-forward.h"
 #include "ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h"
@@ -36,7 +37,8 @@
     : public shortcut_customization::mojom::AcceleratorConfigurationProvider,
       public ui::InputDeviceEventObserver,
       public input_method::InputMethodManager::Observer,
-      public ui::KeyboardCapability::Observer {
+      public ui::KeyboardCapability::Observer,
+      public InputDeviceSettingsController::Observer {
  public:
   using ActionIdToAcceleratorsInfoMap =
       base::flat_map<AcceleratorActionId,
@@ -107,6 +109,11 @@
   // ui::KeyboardCapability::Observer:
   void OnTopRowKeysAreFKeysChanged() override;
 
+  // InputDeviceSettingsController::Observer:
+  void OnKeyboardConnected(const mojom::Keyboard& keyboard) override;
+  void OnKeyboardDisconnected(const mojom::Keyboard& keyboard) override;
+  void OnKeyboardSettingsUpdated(const mojom::Keyboard& keyboard) override;
+
   AcceleratorConfigurationMap GetAcceleratorConfig();
   std::vector<mojom::AcceleratorLayoutInfoPtr> GetAcceleratorLayoutInfos()
       const;
diff --git a/ash/webui/shortcut_customization_ui/resources/js/input_key.html b/ash/webui/shortcut_customization_ui/resources/js/input_key.html
index 82dabd7..e8e30dc 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/input_key.html
+++ b/ash/webui/shortcut_customization_ui/resources/js/input_key.html
@@ -17,7 +17,7 @@
     align-items: center;
     border-radius: 12px;
     box-sizing: border-box;
-    display: flex;
+    display: inline-flex;
     font-weight: 500;
     height: 32px;
     justify-content: center;
diff --git a/ash/webui/shortcut_customization_ui/resources/js/search/search_box.ts b/ash/webui/shortcut_customization_ui/resources/js/search/search_box.ts
index b5b353d5..31824c5 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/search/search_box.ts
+++ b/ash/webui/shortcut_customization_ui/resources/js/search/search_box.ts
@@ -17,8 +17,9 @@
 import {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js';
 import {afterNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+import {SearchResultsAvailabilityObserverInterface, SearchResultsAvailabilityObserverReceiver} from '../../mojom-webui/ash/webui/shortcut_customization_ui/backend/search/search.mojom-webui.js';
 import {stringToMojoString16} from '../mojo_utils.js';
-import {MojoSearchResult, ShortcutSearchHandlerInterface} from '../shortcut_types.js';
+import {AcceleratorState, MojoSearchResult, ShortcutSearchHandlerInterface} from '../shortcut_types.js';
 
 import {getTemplate} from './search_box.html.js';
 import {SearchResultRowElement} from './search_result_row.js';
@@ -36,7 +37,8 @@
 
 const SearchBoxElementBase = I18nMixin(PolymerElement);
 
-export class SearchBoxElement extends SearchBoxElementBase {
+export class SearchBoxElement extends SearchBoxElementBase implements
+    SearchResultsAvailabilityObserverInterface {
   static get is(): string {
     return 'search-box';
   }
@@ -115,6 +117,13 @@
   constructor() {
     super();
     this.shortcutSearchHandler = getShortcutSearchHandler();
+    const receiver = new SearchResultsAvailabilityObserverReceiver(this);
+    this.shortcutSearchHandler.addSearchResultsAvailabilityObserver(
+        receiver.$.bindNewPipeAndPassRemote());
+  }
+
+  onSearchResultsAvailabilityChanged(): void {
+    this.onSearchChanged();
   }
 
   override ready(): void {
@@ -375,12 +384,35 @@
     }
 
     this.spinnerActive = false;
-    this.searchResults = results;
+    this.searchResults = this.filterSearchResults(results);
 
     // This invalidates whatever SearchResultRow element was previously focused,
     // since it's likely that the element has been removed after the search.
     this.lastFocused = null;
   }
+
+  /**
+   * Filter the given search results to hide accelerators and results that are
+   * disabled because their keys are unavailable. This filtering matches the
+   * behavior of the Shortcut app's main list of shortcuts.
+   * @param searchResults the search results to filter.
+   * @returns the given search results with disabled keys and results with no
+   *     keys filtered out.
+   */
+  private filterSearchResults(searchResults: MojoSearchResult[]):
+      MojoSearchResult[] {
+    return searchResults
+        // Hide accelerators that are disabled because the keys are
+        // unavailable.
+        .map(
+            result => ({
+              ...result,
+              acceleratorInfos: result.acceleratorInfos.filter(
+                  a => a.state !== AcceleratorState.kDisabledByUnavailableKeys),
+            }))
+        // Hide results that don't contain any accelerators.
+        .filter(result => result.acceleratorInfos.length > 0);
+  }
 }
 
 declare global {
diff --git a/ash/webui/shortcut_customization_ui/resources/js/text_accelerator.html b/ash/webui/shortcut_customization_ui/resources/js/text_accelerator.html
index 95327776..9ccd9eb 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/text_accelerator.html
+++ b/ash/webui/shortcut_customization_ui/resources/js/text_accelerator.html
@@ -15,13 +15,6 @@
     justify-content: space-between;
   }
 
-  .parts-container {
-    align-items: center;
-    display: flex;
-    flex-wrap: wrap;
-    row-gap: 8px;
-  }
-
   :host([narrow]) .parts-container {
     flex-wrap: nowrap;
     white-space: nowrap;
diff --git a/ash/wm/README.md b/ash/wm/README.md
index 4feef80..9bf15424 100644
--- a/ash/wm/README.md
+++ b/ash/wm/README.md
@@ -45,7 +45,7 @@
 #include "ash/wm/window_state.h"
 
 WindowState* window_state = WindowState::Get(window);
-WMEvent wm_event(WM_EVENT_SNAP_PRIMARY);
+WindowSnapWMEvent wm_event(WM_EVENT_SNAP_PRIMARY);
 window_state->OnWMEvent(&wm_event);
 // WindowState will compute the animation and target bounds and animate the
 // window to the left half.
diff --git a/ash/wm/base_state.cc b/ash/wm/base_state.cc
index ee264218..b82f052 100644
--- a/ash/wm/base_state.cc
+++ b/ash/wm/base_state.cc
@@ -155,13 +155,16 @@
       // restrictive than |WindowState::CanSnap|.
       DCHECK(SplitViewController::Get(window)->IsWindowInSplitView(window));
       SplitViewController::Get(window)->SnapWindow(
-          window, is_desired_primary_snapped
-                      ? SplitViewController::SnapPosition::kPrimary
-                      : SplitViewController::SnapPosition::kSecondary);
+          window,
+          is_desired_primary_snapped
+              ? SplitViewController::SnapPosition::kPrimary
+              : SplitViewController::SnapPosition::kSecondary,
+          WindowSnapActionSource::kKeyboardShortcutToSnap);
     } else {
-      const WMEvent wm_event(is_desired_primary_snapped
-                                 ? WM_EVENT_SNAP_PRIMARY
-                                 : WM_EVENT_SNAP_SECONDARY);
+      const WindowSnapWMEvent wm_event(
+          is_desired_primary_snapped ? WM_EVENT_SNAP_PRIMARY
+                                     : WM_EVENT_SNAP_SECONDARY,
+          WindowSnapActionSource::kKeyboardShortcutToSnap);
       window_state->OnWMEvent(&wm_event);
     }
     window_state->ReadOutWindowCycleSnapAction(
diff --git a/ash/wm/client_controlled_state.cc b/ash/wm/client_controlled_state.cc
index 0ee09394..06b25025 100644
--- a/ash/wm/client_controlled_state.cc
+++ b/ash/wm/client_controlled_state.cc
@@ -347,17 +347,19 @@
                                ? WM_EVENT_SNAP_PRIMARY
                                : WM_EVENT_SNAP_SECONDARY);
 
-      if (event_type == WM_EVENT_RESTORE) {
-        window_state->set_snap_action_source(
-            WindowSnapActionSource::kSnapByWindowStateRestore);
-      }
-      window_state->RecordAndResetWindowSnapActionSource(
-          window_state->GetStateType(), next_state_type);
-
-      // Get the desired window bounds for the snap state.
       const bool is_restoring =
           window_state->window()->GetProperty(aura::client::kIsRestoringKey) ||
           event_type == WM_EVENT_RESTORE;
+      if (is_restoring) {
+        window_state->RecordWindowSnapActionSource(
+            WindowSnapActionSource::kSnapByWindowStateRestore);
+      } else {
+        CHECK(event->IsSnapEvent());
+        window_state->RecordWindowSnapActionSource(
+            static_cast<const WindowSnapWMEvent*>(event)->snap_action_source());
+      }
+
+      // Get the desired window bounds for the snap state.
       // TODO(b/246683799): Investigate why window_state->snap_ratio() can be
       // empty.
       // Use the saved `window_state->snap_ratio()` if restoring, otherwise use
@@ -367,8 +369,9 @@
         next_snap_ratio =
             window_state->snap_ratio().value_or(chromeos::kDefaultSnapRatio);
       } else {
-        DCHECK(event->IsSnapEvent());
-        next_snap_ratio = event->snap_ratio();
+        CHECK(event->IsSnapEvent());
+        CHECK(event->AsSnapEvent());
+        next_snap_ratio = event->AsSnapEvent()->snap_ratio();
       }
       gfx::Rect bounds = GetSnappedWindowBoundsInParent(window, next_state_type,
                                                         next_snap_ratio);
diff --git a/ash/wm/client_controlled_state_unittest.cc b/ash/wm/client_controlled_state_unittest.cc
index d2e7e83..25596bb 100644
--- a/ash/wm/client_controlled_state_unittest.cc
+++ b/ash/wm/client_controlled_state_unittest.cc
@@ -453,12 +453,12 @@
   ASSERT_FALSE(window_state()->CanSnap());
 
   // The event should be ignored.
-  const WMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_PRIMARY);
   window_state()->OnWMEvent(&snap_left_event);
   EXPECT_FALSE(window_state()->IsSnapped());
   EXPECT_TRUE(delegate()->requested_bounds().IsEmpty());
 
-  const WMEvent snap_right_event(WM_EVENT_CYCLE_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_right_event(WM_EVENT_CYCLE_SNAP_SECONDARY);
   window_state()->OnWMEvent(&snap_right_event);
   EXPECT_FALSE(window_state()->IsSnapped());
   EXPECT_TRUE(delegate()->requested_bounds().IsEmpty());
@@ -496,7 +496,7 @@
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
 
   // Test that snap from half to partial works.
-  const WMEvent snap_left_half(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left_half(WM_EVENT_SNAP_PRIMARY);
   window_state()->OnWMEvent(&snap_left_half);
   gfx::Rect expected_bounds(work_area.x(), work_area.y(),
                             work_area.width() * chromeos::kDefaultSnapRatio,
@@ -504,23 +504,23 @@
   EXPECT_EQ(WindowStateType::kPrimarySnapped, delegate()->new_state());
   EXPECT_EQ(expected_bounds, delegate()->requested_bounds());
 
-  const WMEvent snap_left_partial(WM_EVENT_SNAP_PRIMARY,
-                                  chromeos::kTwoThirdSnapRatio);
+  const WindowSnapWMEvent snap_left_partial(WM_EVENT_SNAP_PRIMARY,
+                                            chromeos::kTwoThirdSnapRatio);
   window_state()->OnWMEvent(&snap_left_partial);
   expected_bounds.set_width(work_area.width() * chromeos::kTwoThirdSnapRatio);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, delegate()->new_state());
   EXPECT_EQ(expected_bounds, delegate()->requested_bounds());
 
   // Test that snap from primary to secondary works.
-  const WMEvent snap_right_half(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_right_half(WM_EVENT_SNAP_SECONDARY);
   window_state()->OnWMEvent(&snap_right_half);
   EXPECT_EQ(WindowStateType::kSecondarySnapped, delegate()->new_state());
   expected_bounds.set_x(work_area.width() * chromeos::kDefaultSnapRatio);
   expected_bounds.set_width(work_area.width() * chromeos::kDefaultSnapRatio);
   EXPECT_EQ(expected_bounds, delegate()->requested_bounds());
 
-  const WMEvent snap_right_partial(WM_EVENT_SNAP_SECONDARY,
-                                   chromeos::kOneThirdSnapRatio);
+  const WindowSnapWMEvent snap_right_partial(WM_EVENT_SNAP_SECONDARY,
+                                             chromeos::kOneThirdSnapRatio);
   window_state()->OnWMEvent(&snap_right_partial);
   EXPECT_EQ(WindowStateType::kSecondarySnapped, delegate()->new_state());
   expected_bounds.set_x(
@@ -542,7 +542,7 @@
   widget_delegate()->EnableSnap();
 
   // Make sure the requested bounds for snapped window is local to display.
-  const WMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_PRIMARY);
   window_state()->OnWMEvent(&snap_left_event);
 
   EXPECT_EQ(second_display_id, delegate()->display_id());
@@ -565,7 +565,7 @@
   UpdateDisplay("800x600");
   widget_delegate()->EnableSnap();
 
-  const WMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left_event(WM_EVENT_CYCLE_SNAP_PRIMARY);
   window_state()->OnWMEvent(&snap_left_event);
   state()->EnterNextState(window_state(), delegate()->new_state());
   EXPECT_EQ(gfx::Rect(0, 0, 400, 600 - ShelfConfig::Get()->shelf_size()),
@@ -1240,7 +1240,7 @@
   requested_bounds_queue.push(delegate()->requested_bounds());
 
   // Send a snap request.
-  const WMEvent snap(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap(WM_EVENT_SNAP_PRIMARY);
   window_state()->OnWMEvent(&snap);
   new_state_queue.push(delegate()->new_state());
   requested_bounds_queue.push(delegate()->requested_bounds());
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc
index 44fe7b3c..d7b7f40 100644
--- a/ash/wm/default_state.cc
+++ b/ash/wm/default_state.cc
@@ -431,12 +431,17 @@
   }
 
   if (IsSnappedWindowStateType(next_state_type)) {
-    if (type == WM_EVENT_RESTORE) {
-      window_state->set_snap_action_source(
+    const bool is_restoring =
+        window_state->window()->GetProperty(aura::client::kIsRestoringKey) ||
+        type == WM_EVENT_RESTORE;
+    if (is_restoring) {
+      window_state->RecordWindowSnapActionSource(
           WindowSnapActionSource::kSnapByWindowStateRestore);
+    } else {
+      CHECK(event->IsSnapEvent());
+      window_state->RecordWindowSnapActionSource(
+          static_cast<const WindowSnapWMEvent*>(event)->snap_action_source());
     }
-    window_state->RecordAndResetWindowSnapActionSource(current_state_type,
-                                                       next_state_type);
     EnterToNextState(window_state, next_state_type);
     return;
   }
diff --git a/ash/wm/desks/desk_bar_view_base.cc b/ash/wm/desks/desk_bar_view_base.cc
index 0c74021..fc7f2d0 100644
--- a/ash/wm/desks/desk_bar_view_base.cc
+++ b/ash/wm/desks/desk_bar_view_base.cc
@@ -6,23 +6,190 @@
 
 #include <memory>
 
+#include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.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_id.h"
+#include "ash/wm/desks/cros_next_default_desk_button.h"
+#include "ash/wm/desks/cros_next_desk_icon_button.h"
+#include "ash/wm/desks/desk_action_view.h"
+#include "ash/wm/desks/desk_mini_view_animations.h"
+#include "ash/wm/desks/desk_name_view.h"
 #include "ash/wm/desks/desk_preview_view.h"
 #include "ash/wm/desks/desks_constants.h"
 #include "ash/wm/desks/desks_controller.h"
+#include "ash/wm/desks/expanded_desks_bar_button.h"
+#include "ash/wm/desks/templates/saved_desk_metrics_util.h"
+#include "ash/wm/desks/templates/saved_desk_presenter.h"
+#include "ash/wm/desks/templates/saved_desk_util.h"
+#include "ash/wm/desks/zero_state_button.h"
 #include "ash/wm/overview/overview_controller.h"
+#include "ash/wm/overview/overview_highlight_controller.h"
+#include "ash/wm/overview/overview_metrics.h"
 #include "ash/wm/overview/overview_session.h"
+#include "ash/wm/overview/overview_utils.h"
 #include "base/check.h"
 #include "base/notreached.h"
+#include "chromeos/constants/chromeos_features.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/events/devices/device_data_manager.h"
+#include "ui/views/background.h"
+#include "ui/views/highlight_border.h"
 #include "ui/wm/core/window_animations.h"
 
 namespace ash {
 
+namespace {
+
+OverviewHighlightController* GetHighlightController() {
+  auto* overview_controller = Shell::Get()->overview_controller();
+  DCHECK(overview_controller->InOverviewSession());
+  return overview_controller->overview_session()->highlight_controller();
+}
+
+// Checks whether there are any external keyboards.
+bool HasExternalKeyboard() {
+  for (const ui::InputDevice& device :
+       ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
+    if (device.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Initialize a scoped layer animation settings for scroll view contents.
+void InitScrollContentsAnimationSettings(
+    ui::ScopedLayerAnimationSettings& settings) {
+  settings.SetTransitionDuration(kDeskBarScrollDuration);
+  settings.SetTweenType(gfx::Tween::ACCEL_20_DECEL_60);
+}
+
+}  // namespace
+
 DeskBarViewBase::DeskBarViewBase(aura::Window* root, Type type)
     : type_(type), state_(GetPerferredState(type)), root_(root) {
   CHECK(root && root->IsRootWindow());
+
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
+
+  SetBorder(std::make_unique<views::HighlightBorder>(
+      /*corner_radius=*/0,
+      chromeos::features::IsJellyrollEnabled()
+          ? views::HighlightBorder::Type::kHighlightBorderNoShadow
+          : views::HighlightBorder::Type::kHighlightBorder2));
+
+  SetBackground(views::CreateThemedSolidBackground(kColorAshShieldAndBase80));
+  // Use layer scrolling so that the contents will paint on top of the parent,
+  // which uses SetPaintToLayer()
+  scroll_view_ = AddChildView(std::make_unique<views::ScrollView>(
+      views::ScrollView::ScrollWithLayers::kEnabled));
+  scroll_view_->SetPaintToLayer();
+  scroll_view_->layer()->SetFillsBoundsOpaquely(false);
+  scroll_view_->SetBackgroundColor(absl::nullopt);
+  scroll_view_->SetDrawOverflowIndicator(false);
+  scroll_view_->SetHorizontalScrollBarMode(
+      views::ScrollView::ScrollBarMode::kHiddenButEnabled);
+  scroll_view_->SetTreatAllScrollEventsAsHorizontal(true);
+
+  left_scroll_button_ = AddChildView(std::make_unique<ScrollArrowButton>(
+      base::BindRepeating(&DeskBarViewBase::ScrollToPreviousPage,
+                          base::Unretained(this)),
+      /*is_left_arrow=*/true, this));
+  right_scroll_button_ = AddChildView(std::make_unique<ScrollArrowButton>(
+      base::BindRepeating(&DeskBarViewBase::ScrollToNextPage,
+                          base::Unretained(this)),
+      /*is_left_arrow=*/false, this));
+
+  // Make the scroll content view animatable by painting to a layer.
+  scroll_view_contents_ =
+      scroll_view_->SetContents(std::make_unique<views::View>());
+  scroll_view_contents_->SetPaintToLayer();
+
+  if (chromeos::features::IsJellyrollEnabled()) {
+    default_desk_button_ = scroll_view_contents_->AddChildView(
+        std::make_unique<CrOSNextDefaultDeskButton>(this));
+    new_desk_button_ = scroll_view_contents_->AddChildView(
+        std::make_unique<CrOSNextDeskIconButton>(
+            this, &kDesksNewDeskButtonIcon,
+            l10n_util::GetStringUTF16(IDS_ASH_DESKS_NEW_DESK_BUTTON),
+            cros_tokens::kCrosSysOnPrimary, cros_tokens::kCrosSysPrimary,
+            /*initially_enabled=*/DesksController::Get()->CanCreateDesks(),
+            base::BindRepeating(&DeskBarViewBase::OnNewDeskButtonPressed,
+                                base::Unretained(this),
+                                DesksCreationRemovalSource::kButton)));
+    new_desk_button_label_ =
+        scroll_view_contents_->AddChildView(std::make_unique<views::Label>());
+    new_desk_button_label_->SetPaintToLayer();
+    new_desk_button_label_->layer()->SetFillsBoundsOpaquely(false);
+  } else {
+    expanded_state_new_desk_button_ = scroll_view_contents_->AddChildView(
+        std::make_unique<ExpandedDesksBarButton>(
+            this, &kDesksNewDeskButtonIcon,
+            l10n_util::GetStringUTF16(IDS_ASH_DESKS_NEW_DESK_BUTTON),
+            /*initially_enabled=*/DesksController::Get()->CanCreateDesks(),
+            base::BindRepeating(&DeskBarViewBase::OnNewDeskButtonPressed,
+                                base::Unretained(this),
+                                DesksCreationRemovalSource::kButton)));
+
+    zero_state_default_desk_button_ = scroll_view_contents_->AddChildView(
+        std::make_unique<ZeroStateDefaultDeskButton>(this));
+    zero_state_new_desk_button_ = scroll_view_contents_->AddChildView(
+        std::make_unique<ZeroStateIconButton>(
+            this, &kDesksNewDeskButtonIcon,
+            l10n_util::GetStringUTF16(IDS_ASH_DESKS_NEW_DESK_BUTTON),
+            base::BindRepeating(&DeskBarViewBase::OnNewDeskButtonPressed,
+                                base::Unretained(this),
+                                DesksCreationRemovalSource::kButton)));
+  }
+
+  if (saved_desk_util::IsSavedDesksEnabled()) {
+    int button_text_id = IDS_ASH_DESKS_TEMPLATES_DESKS_BAR_BUTTON_LIBRARY;
+    if (!saved_desk_util::AreDesksTemplatesEnabled()) {
+      button_text_id = IDS_ASH_DESKS_TEMPLATES_DESKS_BAR_BUTTON_SAVED_FOR_LATER;
+    }
+
+    if (chromeos::features::IsJellyrollEnabled()) {
+      library_button_ = scroll_view_contents_->AddChildView(
+          std::make_unique<CrOSNextDeskIconButton>(
+              this, &kDesksTemplatesIcon,
+              l10n_util::GetStringUTF16(button_text_id),
+              cros_tokens::kCrosSysOnSecondaryContainer,
+              cros_tokens::kCrosSysInversePrimary,
+              /*initially_enabled=*/true,
+              base::BindRepeating(&DeskBarViewBase::OnLibraryButtonPressed,
+                                  base::Unretained(this))));
+      library_button_label_ =
+          scroll_view_contents_->AddChildView(std::make_unique<views::Label>());
+      library_button_label_->SetPaintToLayer();
+      library_button_label_->layer()->SetFillsBoundsOpaquely(false);
+    } else {
+      expanded_state_library_button_ = scroll_view_contents_->AddChildView(
+          std::make_unique<ExpandedDesksBarButton>(
+              this, &kDesksTemplatesIcon,
+              l10n_util::GetStringUTF16(button_text_id),
+              /*initially_enabled=*/true,
+              base::BindRepeating(&DeskBarViewBase::OnLibraryButtonPressed,
+                                  base::Unretained(this))));
+      zero_state_library_button_ = scroll_view_contents_->AddChildView(
+          std::make_unique<ZeroStateIconButton>(
+              this, &kDesksTemplatesIcon,
+              l10n_util::GetStringUTF16(button_text_id),
+              base::BindRepeating(&DeskBarViewBase::OnLibraryButtonPressed,
+                                  base::Unretained(this))));
+    }
+  }
+
+  on_contents_scrolled_subscription_ =
+      scroll_view_->AddContentsScrolledCallback(base::BindRepeating(
+          &DeskBarViewBase::OnContentsScrolled, base::Unretained(this)));
+  on_contents_scroll_ended_subscription_ =
+      scroll_view_->AddContentsScrollEndedCallback(base::BindRepeating(
+          &DeskBarViewBase::OnContentsScrollEnded, base::Unretained(this)));
 }
 
 DeskBarViewBase::~DeskBarViewBase() = default;
@@ -128,34 +295,79 @@
   return widget;
 }
 
-void DeskBarViewBase::UpdateNewMiniViews(bool initializing_bar_view,
-                                         bool expanding_bar_view) {
-  NOTREACHED();
+const char* DeskBarViewBase::GetClassName() const {
+  return "DeskBarViewBase";
 }
-void DeskBarViewBase::UpdateDeskButtonsVisibility() {
-  NOTREACHED();
+
+void DeskBarViewBase::Layout() {
+  if (is_bounds_animation_on_going_) {
+    return;
+  }
+
+  if (!overview_grid_) {
+    return;
+  }
+
+  // Scroll buttons are kept `kDeskBarScrollViewMinimumHorizontalPadding` away
+  // from the edge of the scroll view. So the horizontal padding of the scroll
+  // view is set to guarantee enough space for the scroll buttons.
+  const gfx::Insets insets = overview_grid_->GetGridInsets();
+  DCHECK(insets.left() == insets.right());
+  const int horizontal_padding =
+      std::max(kDeskBarScrollViewMinimumHorizontalPadding, insets.left());
+  left_scroll_button_->SetBounds(
+      horizontal_padding - kDeskBarScrollViewMinimumHorizontalPadding,
+      bounds().y(), kDeskBarScrollButtonWidth, bounds().height());
+  right_scroll_button_->SetBounds(
+      bounds().right() - horizontal_padding -
+          (kDeskBarScrollButtonWidth -
+           kDeskBarScrollViewMinimumHorizontalPadding),
+      bounds().y(), kDeskBarScrollButtonWidth, bounds().height());
+
+  gfx::Rect scroll_bounds = bounds();
+  // Align with the overview grid in horizontal, so only horizontal insets are
+  // needed here.
+  scroll_bounds.Inset(gfx::Insets::VH(0, horizontal_padding));
+  scroll_view_->SetBoundsRect(scroll_bounds);
+
+  // Clip the contents that are outside of the |scroll_view_|'s bounds.
+  scroll_view_->layer()->SetMasksToBounds(true);
+  scroll_view_->Layout();
+
+  UpdateScrollButtonsVisibility();
+  UpdateGradientMask();
 }
-void DeskBarViewBase::SwitchToExpandedState() {
-  NOTREACHED();
+
+bool DeskBarViewBase::OnMousePressed(const ui::MouseEvent& event) {
+  DeskNameView::CommitChanges(GetWidget());
+  return false;
 }
-void DeskBarViewBase::NudgeDeskName(int desk_index) {
-  NOTREACHED();
+
+void DeskBarViewBase::OnGestureEvent(ui::GestureEvent* event) {
+  switch (event->type()) {
+    case ui::ET_GESTURE_LONG_PRESS:
+    case ui::ET_GESTURE_LONG_TAP:
+    case ui::ET_GESTURE_TAP:
+    case ui::ET_GESTURE_TAP_DOWN:
+      DeskNameView::CommitChanges(GetWidget());
+      break;
+
+    default:
+      break;
+  }
 }
-void DeskBarViewBase::HandlePressEvent(DeskMiniView* mini_view,
-                                       const ui::LocatedEvent& event) {
-  NOTREACHED();
-}
-void DeskBarViewBase::HandleLongPressEvent(DeskMiniView* mini_view,
-                                           const ui::LocatedEvent& event) {
-  NOTREACHED();
-}
-void DeskBarViewBase::HandleDragEvent(DeskMiniView* mini_view,
-                                      const ui::LocatedEvent& event) {
-  NOTREACHED();
-}
-bool DeskBarViewBase::HandleReleaseEvent(DeskMiniView* mini_view,
-                                         const ui::LocatedEvent& event) {
-  NOTREACHED_NORETURN();
+
+void DeskBarViewBase::Init() {
+  UpdateNewMiniViews(/*initializing_bar_view=*/true,
+                     /*expanding_bar_view=*/false);
+
+  // When the bar is initialized, scroll to make active desk mini view visible.
+  auto it = base::ranges::find_if(mini_views_, [](DeskMiniView* mini_view) {
+    return mini_view->desk()->is_active();
+  });
+  if (it != mini_views_.end()) {
+    ScrollToShowViewIfNecessary(*it);
+  }
 }
 
 bool DeskBarViewBase::IsZeroState() const {
@@ -166,6 +378,19 @@
   return drag_view_ != nullptr;
 }
 
+bool DeskBarViewBase::IsDeskNameBeingModified() const {
+  if (!GetWidget()->IsActive()) {
+    return false;
+  }
+
+  for (auto* mini_view : mini_views_) {
+    if (mini_view->IsDeskNameBeingModified()) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void DeskBarViewBase::ScrollToShowViewIfNecessary(const views::View* view) {
   CHECK(base::Contains(scroll_view_contents_->children(), view));
   const gfx::Rect visible_bounds = scroll_view_->GetVisibleRect();
@@ -198,13 +423,233 @@
              : std::distance(mini_views_.cbegin(), iter);
 }
 
-void DeskBarViewBase::UpdateScrollButtonsVisibility() {
+void DeskBarViewBase::OnNewDeskButtonPressed(
+    DesksCreationRemovalSource desks_creation_removal_source) {
+  auto* controller = DesksController::Get();
+  if (!controller->CanCreateDesks()) {
+    return;
+  }
+  controller->NewDesk(desks_creation_removal_source);
+  NudgeDeskName(mini_views_.size() - 1);
+
+  // TODO(b/277081702): When desk order is adjusted for RTL, remove the check
+  // below to always make new desk button visible.
+  if (!base::i18n::IsRTL()) {
+    if (new_desk_button_) {
+      ScrollToShowViewIfNecessary(new_desk_button_);
+    } else if (expanded_state_new_desk_button_) {
+      ScrollToShowViewIfNecessary(expanded_state_new_desk_button_);
+    }
+  }
+}
+
+void DeskBarViewBase::OnSavedDeskLibraryHidden() {
+  if (!chromeos::features::IsJellyrollEnabled() && mini_views_.size() == 1u) {
+    SwitchToZeroState();
+  }
+}
+
+void DeskBarViewBase::NudgeDeskName(int desk_index) {
+  DCHECK_LT(desk_index, static_cast<int>(mini_views_.size()));
+
+  auto* name_view = mini_views_[desk_index]->desk_name_view();
+  name_view->RequestFocus();
+
+  // Set `name_view`'s accessible name to the default desk name since its text
+  // is cleared.
+  if (name_view->GetAccessibleName().empty()) {
+    name_view->SetAccessibleName(
+        DesksController::GetDeskDefaultName(desk_index));
+  }
+
+  if (type_ == Type::kOverview) {
+    UpdateOverviewHighlightForFocus(name_view);
+
+    // If we're in tablet mode and there are no external keyboards, open up the
+    // virtual keyboard.
+    if (Shell::Get()->tablet_mode_controller()->InTabletMode() &&
+        !HasExternalKeyboard()) {
+      keyboard::KeyboardUIController::Get()->ShowKeyboard(/*lock=*/false);
+    }
+  }
+}
+
+void DeskBarViewBase::UpdateButtonsForSavedDeskGrid() {
+  if (IsZeroState() || !saved_desk_util::IsSavedDesksEnabled()) {
+    return;
+  }
+
+  FindMiniViewForDesk(Shell::Get()->desks_controller()->active_desk())
+      ->UpdateFocusColor();
+
+  if (type_ == Type::kOverview) {
+    if (chromeos::features::IsJellyrollEnabled()) {
+      library_button_->set_paint_as_active(
+          overview_grid_->IsShowingSavedDeskLibrary());
+      library_button_->UpdateFocusState();
+    } else {
+      expanded_state_library_button_->set_active(
+          overview_grid_->IsShowingSavedDeskLibrary());
+      expanded_state_library_button_->UpdateFocusColor();
+    }
+  }
+}
+
+void DeskBarViewBase::UpdateDeskButtonsVisibility() {
+  if (chromeos::features::IsJellyrollEnabled()) {
+    UpdateDeskButtonsVisibilityCrOSNext();
+    return;
+  }
+  const bool is_zero_state = IsZeroState();
+  zero_state_default_desk_button_->SetVisible(is_zero_state);
+  zero_state_new_desk_button_->SetVisible(is_zero_state);
+  expanded_state_new_desk_button_->SetVisible(!is_zero_state);
+
+  UpdateLibraryButtonVisibility();
+}
+
+void DeskBarViewBase::UpdateDeskButtonsVisibilityCrOSNext() {
+  const bool is_zero_state = IsZeroState();
+  default_desk_button_->SetVisible(is_zero_state);
+  new_desk_button_label_->SetVisible(new_desk_button_->state() ==
+                                     CrOSNextDeskIconButton::State::kActive);
+
+  UpdateLibraryButtonVisibilityCrOSNext();
+}
+
+void DeskBarViewBase::UpdateLibraryButtonVisibility() {
+  if (chromeos::features::IsJellyrollEnabled()) {
+    UpdateLibraryButtonVisibilityCrOSNext();
+    return;
+  }
+  if (!saved_desk_util::IsSavedDesksEnabled()) {
+    return;
+  }
+  if (type_ != Type::kOverview) {
+    return;
+  }
+
+  const bool should_show_ui = overview_grid_->overview_session()
+                                  ->saved_desk_presenter()
+                                  ->should_show_saved_desk_library();
+  const bool is_zero_state = IsZeroState();
+
+  zero_state_library_button_->SetVisible(should_show_ui && is_zero_state);
+  expanded_state_library_button_->SetVisible(should_show_ui && !is_zero_state);
+
+  // Removes the button from the tabbing order if it becomes invisible.
+  auto* highlight_controller = GetHighlightController();
+  if (!zero_state_library_button_->GetVisible()) {
+    highlight_controller->OnViewDestroyingOrDisabling(
+        zero_state_library_button_);
+  }
+  if (!expanded_state_library_button_->GetVisible()) {
+    highlight_controller->OnViewDestroyingOrDisabling(
+        expanded_state_library_button_->GetInnerButton());
+  }
+
+  const int begin_x = GetFirstMiniViewXOffset();
+  Layout();
+
+  if (mini_views_.empty()) {
+    return;
+  }
+
+  // The mini views and new desk button are already laid out in the earlier
+  // `Layout()` call. This call shifts the transforms of the mini views and new
+  // desk button and then animates to the identity transform.
+  PerformLibraryButtonVisibilityAnimation(
+      mini_views_,
+      is_zero_state
+          ? static_cast<views::View*>(zero_state_new_desk_button_)
+          : static_cast<views::View*>(expanded_state_new_desk_button_),
+      begin_x - GetFirstMiniViewXOffset());
+}
+
+void DeskBarViewBase::UpdateLibraryButtonVisibilityCrOSNext() {
+  if (!saved_desk_util::IsSavedDesksEnabled()) {
+    return;
+  }
+  if (type_ != Type::kOverview) {
+    return;
+  }
+
+  const bool should_show_ui = overview_grid_->overview_session()
+                                  ->saved_desk_presenter()
+                                  ->should_show_saved_desk_library();
+
+  library_button_label_->SetVisible(
+      should_show_ui &&
+      (library_button_->state() == CrOSNextDeskIconButton::State::kActive));
+
+  // If the visibility of the library button doesn't change, return early.
+  if (library_button_->GetVisible() == should_show_ui) {
+    return;
+  }
+
+  library_button_->SetVisible(should_show_ui);
+  if (should_show_ui) {
+    if (overview_grid_->WillShowSavedDeskLibrary()) {
+      library_button_->UpdateState(CrOSNextDeskIconButton::State::kActive);
+    } else {
+      library_button_->UpdateState(CrOSNextDeskIconButton::State::kExpanded);
+    }
+  }
+
+  if (mini_views_.empty()) {
+    return;
+  }
+
+  const int begin_x = GetFirstMiniViewXOffset();
+  Layout();
+
+  // The mini views and new desk button are already laid out in the earlier
+  // `Layout()` call. This call shifts the transforms of the mini views and new
+  // desk button and then animates to the identity transform.
+  PerformLibraryButtonVisibilityAnimation(mini_views_, new_desk_button_,
+                                          begin_x - GetFirstMiniViewXOffset());
+}
+
+void DeskBarViewBase::UpdateDeskIconButtonState(
+    CrOSNextDeskIconButton* button,
+    CrOSNextDeskIconButton::State target_state) {
+  button->UpdateState(target_state);
+  Layout();
+}
+
+void DeskBarViewBase::UpdateNewMiniViews(bool initializing_bar_view,
+                                         bool expanding_bar_view) {
   NOTREACHED();
 }
-void DeskBarViewBase::UpdateGradientMask() {
+
+void DeskBarViewBase::SwitchToZeroState() {
   NOTREACHED();
 }
 
+void DeskBarViewBase::SwitchToExpandedState() {
+  NOTREACHED();
+}
+
+void DeskBarViewBase::HandlePressEvent(DeskMiniView* mini_view,
+                                       const ui::LocatedEvent& event) {
+  NOTREACHED();
+}
+
+void DeskBarViewBase::HandleLongPressEvent(DeskMiniView* mini_view,
+                                           const ui::LocatedEvent& event) {
+  NOTREACHED();
+}
+
+void DeskBarViewBase::HandleDragEvent(DeskMiniView* mini_view,
+                                      const ui::LocatedEvent& event) {
+  NOTREACHED();
+}
+
+bool DeskBarViewBase::HandleReleaseEvent(DeskMiniView* mini_view,
+                                         const ui::LocatedEvent& event) {
+  NOTREACHED_NORETURN();
+}
+
 int DeskBarViewBase::GetFirstMiniViewXOffset() const {
   // `GetMirroredX` is used here to make sure the removing and adding a desk
   // transform is correct while in RTL layout.
@@ -212,11 +657,196 @@
                              : mini_views_[0]->GetMirroredX();
 }
 
-void DeskBarViewBase::UpdateDeskButtonsVisibilityCrOSNext() {
-  NOTREACHED();
+int DeskBarViewBase::DetermineMoveIndex(int location_screen_x) const {
+  const int views_size = static_cast<int>(mini_views_.size());
+
+  // We find the target position according to the x-axis coordinate of the
+  // desks' center positions in screen in ascending order.
+  for (int new_index = 0; new_index != views_size - 1; ++new_index) {
+    auto* mini_view = mini_views_[new_index];
+
+    // Note that we cannot directly use `GetBoundsInScreen`. Because we may
+    // perform animation (transform) on mini views. The bounds gotten from
+    // `GetBoundsInScreen` may be the intermediate bounds during animation.
+    // Therefore, we transfer a mini view's origin from its parent level to
+    // avoid the influence of its own transform.
+    gfx::Point center_screen_pos = mini_view->GetMirroredBounds().CenterPoint();
+    views::View::ConvertPointToScreen(mini_view->parent(), &center_screen_pos);
+    if (location_screen_x < center_screen_pos.x()) {
+      return new_index;
+    }
+  }
+
+  return views_size - 1;
 }
-void DeskBarViewBase::UpdateLibraryButtonVisibilityCrOSNext() {
-  NOTREACHED();
+
+void DeskBarViewBase::UpdateScrollButtonsVisibility() {
+  const gfx::Rect visible_bounds = scroll_view_->GetVisibleRect();
+  left_scroll_button_->SetVisible(visible_bounds.x() > 0);
+  right_scroll_button_->SetVisible(visible_bounds.right() <
+                                   scroll_view_contents_->bounds().width());
+}
+
+void DeskBarViewBase::UpdateGradientMask() {
+  const bool is_rtl = base::i18n::IsRTL();
+  const bool is_left_scroll_button_visible = left_scroll_button_->GetVisible();
+  const bool is_right_scroll_button_visible =
+      right_scroll_button_->GetVisible();
+  const bool is_left_visible_only =
+      is_left_scroll_button_visible && !is_right_scroll_button_visible;
+
+  bool should_show_start_gradient = false;
+  bool should_show_end_gradient = false;
+  // Show the both sides gradients during scroll if the corresponding scroll
+  // button is visible. Otherwise, show the start/end gradient only in last page
+  // and show the end/start gradient if there are contents beyond the right/left
+  // side of the visible bounds with LTR/RTL layout.
+  if (scroll_view_->is_scrolling()) {
+    should_show_start_gradient =
+        is_rtl ? is_right_scroll_button_visible : is_left_scroll_button_visible;
+    should_show_end_gradient =
+        is_rtl ? is_left_scroll_button_visible : is_right_scroll_button_visible;
+  } else {
+    should_show_start_gradient =
+        is_rtl ? is_right_scroll_button_visible : is_left_visible_only;
+    should_show_end_gradient =
+        is_rtl ? is_left_visible_only : is_right_scroll_button_visible;
+  }
+
+  // The bounds of the start and end gradient will be the same regardless it is
+  // LTR or RTL layout. While the `left_scroll_button_` will be changed from
+  // left to right and `right_scroll_button_` will be changed from right to left
+  // if it is RTL layout.
+
+  // Horizontal linear gradient, from left to right.
+  gfx::LinearGradient gradient_mask(/*angle=*/0);
+
+  // Fraction of layer width that gradient will be applied to.
+  const float fade_position =
+      should_show_start_gradient || should_show_end_gradient
+          ? static_cast<float>(kDeskBarGradientZoneLength) /
+                scroll_view_->bounds().width()
+          : 0;
+
+  // Left fade in section.
+  if (should_show_start_gradient) {
+    gradient_mask.AddStep(/*fraction=*/0, /*alpha=*/0);
+    gradient_mask.AddStep(fade_position, 255);
+  }
+  // Right fade out section.
+  if (should_show_end_gradient) {
+    gradient_mask.AddStep((1 - fade_position), 255);
+    gradient_mask.AddStep(1, 0);
+  }
+
+  scroll_view_->layer()->SetGradientMask(gradient_mask);
+  scroll_view_->SchedulePaint();
+}
+
+void DeskBarViewBase::ScrollToPreviousPage() {
+  ui::ScopedLayerAnimationSettings settings(
+      scroll_view_contents_->layer()->GetAnimator());
+  InitScrollContentsAnimationSettings(settings);
+  scroll_view_->ScrollToPosition(
+      scroll_view_->horizontal_scroll_bar(),
+      GetAdjustedUncroppedScrollPosition(scroll_view_->GetVisibleRect().x() -
+                                         scroll_view_->width()));
+}
+
+void DeskBarViewBase::ScrollToNextPage() {
+  ui::ScopedLayerAnimationSettings settings(
+      scroll_view_contents_->layer()->GetAnimator());
+  InitScrollContentsAnimationSettings(settings);
+  scroll_view_->ScrollToPosition(
+      scroll_view_->horizontal_scroll_bar(),
+      GetAdjustedUncroppedScrollPosition(scroll_view_->GetVisibleRect().x() +
+                                         scroll_view_->width()));
+}
+
+int DeskBarViewBase::GetAdjustedUncroppedScrollPosition(int position) const {
+  // Let the ScrollView handle it if the given `position` is invalid or it can't
+  // be adjusted.
+  if (position <= 0 || position >= scroll_view_contents_->bounds().width() -
+                                       scroll_view_->width()) {
+    return position;
+  }
+
+  int adjusted_position = position;
+  int i = 0;
+  gfx::Rect mini_view_bounds;
+  const int mini_views_size = static_cast<int>(mini_views_.size());
+  for (; i < mini_views_size; i++) {
+    mini_view_bounds = mini_views_[i]->bounds();
+
+    // Return early if there is no desk preview cropped at the start position.
+    if (mini_view_bounds.x() >= position) {
+      return position - kDeskBarDeskPreviewViewFocusRingThicknessAndPadding;
+    }
+
+    if (mini_view_bounds.x() < position &&
+        mini_view_bounds.right() > position) {
+      break;
+    }
+  }
+
+  DCHECK_LT(i, mini_views_size);
+  if ((position - mini_view_bounds.x()) < mini_view_bounds.width() / 2) {
+    adjusted_position = mini_view_bounds.x();
+  } else {
+    adjusted_position = mini_view_bounds.right();
+    if (i + 1 < mini_views_size) {
+      adjusted_position = mini_views_[i + 1]->bounds().x();
+    }
+  }
+  return adjusted_position -
+         kDeskBarDeskPreviewViewFocusRingThicknessAndPadding;
+}
+
+void DeskBarViewBase::OnLibraryButtonPressed() {
+  RecordLoadSavedDeskLibraryHistogram();
+  if (IsDeskNameBeingModified()) {
+    DeskNameView::CommitChanges(GetWidget());
+  }
+
+  aura::Window* root = GetWidget()->GetNativeWindow()->GetRootWindow();
+  OverviewSession* overview_session;
+  if (overview_grid_) {
+    overview_session = overview_grid_->overview_session();
+  } else {
+    Shell::Get()->overview_controller()->StartOverview(
+        OverviewStartAction::kDeskButton);
+    overview_session = Shell::Get()->overview_controller()->overview_session();
+  }
+  overview_session->ShowSavedDeskLibrary(base::GUID(), /*saved_desk_name=*/u"",
+                                         root);
+}
+
+void DeskBarViewBase::MaybeUpdateCombineDesksTooltips() {
+  for (auto* mini_view : mini_views_) {
+    // If desk is being removed, do not update the tooltip.
+    if (mini_view->desk()->is_desk_being_removed()) {
+      continue;
+    }
+    mini_view->desk_action_view()->UpdateCombineDesksTooltip(
+        DesksController::Get()->GetCombineDesksTargetName(mini_view->desk()));
+  }
+}
+
+void DeskBarViewBase::OnContentsScrolled() {
+  UpdateScrollButtonsVisibility();
+  UpdateGradientMask();
+}
+
+void DeskBarViewBase::OnContentsScrollEnded() {
+  const gfx::Rect visible_bounds = scroll_view_->GetVisibleRect();
+  const int current_position = visible_bounds.x();
+  const int adjusted_position =
+      GetAdjustedUncroppedScrollPosition(current_position);
+  if (current_position != adjusted_position) {
+    scroll_view_->ScrollToPosition(scroll_view_->horizontal_scroll_bar(),
+                                   adjusted_position);
+  }
+  UpdateGradientMask();
 }
 
 }  // namespace ash
diff --git a/ash/wm/desks/desk_bar_view_base.h b/ash/wm/desks/desk_bar_view_base.h
index cba6f05..0c18ba1 100644
--- a/ash/wm/desks/desk_bar_view_base.h
+++ b/ash/wm/desks/desk_bar_view_base.h
@@ -8,8 +8,13 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "ash/wm/desks/cros_next_default_desk_button.h"
+#include "ash/wm/desks/cros_next_desk_icon_button.h"
 #include "ash/wm/desks/desk_mini_view.h"
 #include "ash/wm/desks/desks_controller.h"
+#include "ash/wm/desks/expanded_desks_bar_button.h"
+#include "ash/wm/desks/scroll_arrow_button.h"
+#include "ash/wm/desks/zero_state_button.h"
 #include "ash/wm/overview/overview_grid.h"
 #include "base/allocator/partition_allocator/pointers/raw_ptr.h"
 #include "ui/events/event.h"
@@ -76,20 +81,64 @@
     return scroll_view_contents_;
   }
 
-  // TODO(yongshun): Migrate the following virtual functions to base class.
-  virtual void UpdateNewMiniViews(bool initializing_bar_view,
-                                  bool expanding_bar_view);
-  virtual void UpdateDeskButtonsVisibility();
-  virtual void SwitchToExpandedState();
-  virtual void NudgeDeskName(int desk_index);
-  virtual void HandlePressEvent(DeskMiniView* mini_view,
-                                const ui::LocatedEvent& event);
-  virtual void HandleLongPressEvent(DeskMiniView* mini_view,
-                                    const ui::LocatedEvent& event);
-  virtual void HandleDragEvent(DeskMiniView* mini_view,
-                               const ui::LocatedEvent& event);
-  virtual bool HandleReleaseEvent(DeskMiniView* mini_view,
-                                  const ui::LocatedEvent& event);
+  ZeroStateDefaultDeskButton* zero_state_default_desk_button() const {
+    return zero_state_default_desk_button_;
+  }
+
+  ZeroStateIconButton* zero_state_new_desk_button() const {
+    return zero_state_new_desk_button_;
+  }
+
+  ExpandedDesksBarButton* expanded_state_new_desk_button() const {
+    return expanded_state_new_desk_button_;
+  }
+
+  ZeroStateIconButton* zero_state_library_button() const {
+    return zero_state_library_button_;
+  }
+
+  ExpandedDesksBarButton* expanded_state_library_button() const {
+    return expanded_state_library_button_;
+  }
+
+  CrOSNextDefaultDeskButton* default_desk_button() {
+    return default_desk_button_;
+  }
+  const CrOSNextDefaultDeskButton* default_desk_button() const {
+    return default_desk_button_;
+  }
+
+  CrOSNextDeskIconButton* new_desk_button() { return new_desk_button_; }
+  const CrOSNextDeskIconButton* new_desk_button() const {
+    return new_desk_button_;
+  }
+
+  CrOSNextDeskIconButton* library_button() { return library_button_; }
+  const CrOSNextDeskIconButton* library_button() const {
+    return library_button_;
+  }
+
+  views::Label* new_desk_button_label() { return new_desk_button_label_; }
+  const views::Label* new_desk_button_label() const {
+    return new_desk_button_label_;
+  }
+
+  views::Label* library_button_label() { return library_button_label_; }
+  const views::Label* library_button_label() const {
+    return library_button_label_;
+  }
+
+  // views::View:
+  const char* GetClassName() const override;
+  void Layout() override;
+  bool OnMousePressed(const ui::MouseEvent& event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
+
+  // Initializes and creates mini_views for any pre-existing desks, before the
+  // bar was created. This should only be called after this view has been added
+  // to a widget, as it needs to call `GetWidget()` when it's performing a
+  // layout.
+  virtual void Init();
 
   // Returns true if it is currently in zero state.
   bool IsZeroState() const;
@@ -97,6 +146,10 @@
   // If a desk is in a drag & drop cycle.
   bool IsDraggingDesk() const;
 
+  // Returns true if a desk name is being modified using its mini view's
+  // DeskNameView on this bar.
+  bool IsDeskNameBeingModified() const;
+
   // If the focused `view` is outside of the scroll view's visible bounds,
   // scrolls the bar to make sure it can always be seen. Please note, `view`
   // must be a child of `scroll_view_contents_`.
@@ -109,17 +162,115 @@
   // Get the index of a desk mini view in the `mini_views`.
   int GetMiniViewIndex(const DeskMiniView* mini_view) const;
 
- protected:
-  // TODO(yongshun): Migrate the following virtual functions to base class.
-  virtual void UpdateScrollButtonsVisibility();
-  virtual void UpdateGradientMask();
+  void OnNewDeskButtonPressed(
+      DesksCreationRemovalSource desks_creation_removal_source);
 
+  // Called when the saved desk library is hidden. Transitions the desk bar
+  // view to zero state if necessary.
+  void OnSavedDeskLibraryHidden();
+
+  // Bring focus to the name view of the desk with `desk_index`.
+  void NudgeDeskName(int desk_index);
+
+  // If in expanded state, updates the border color of the
+  // `expanded_state_library_button_` and the active desk's mini view
+  // after the saved desk library has been shown. If not in expanded state,
+  // updates the background color of the `zero_state_library_button_`
+  // and the `zero_state_default_desk_button_`.
+  void UpdateButtonsForSavedDeskGrid();
+
+  // Updates the visibility of the two buttons inside the zero state desk bar
+  // and the `ExpandedDesksBarButton` on the desk bar's state.
+  void UpdateDeskButtonsVisibility();
+
+  // Udates the visibility of the `default_desk_button_` on the desk bar's
+  // state.
+  // TODO(conniekxu): Remove `UpdateDeskButtonsVisibility`, replace it with this
+  // function, and rename this function by removing the prefix CrOSNext.
+  void UpdateDeskButtonsVisibilityCrOSNext();
+
+  // Updates the visibility of the saved desk library button based on whether
+  // the saved desk feature is enabled, the user has any saved desks and the
+  // state of the desk bar.
+  void UpdateLibraryButtonVisibility();
+
+  // Updates the visibility of the saved desk library button based on whether
+  // the saved desk feature is enabled and the user has any saved desks.
+  // TODO(conniekxu): Remove `UpdateLibraryButtonVisibility`, replace it with
+  // this function, and rename this function by removing the prefix CrOSNext.
+  void UpdateLibraryButtonVisibilityCrOSNext();
+
+  // Called to update state of `button` and apply the scale animation to the
+  // button. For the new desk button, this is called when the make the new desk
+  // button a drop target for the window being dragged or at the end of the
+  // drag. For the library button, this is called when the library is clicked at
+  // the expanded state. Please note this will only be used to switch the states
+  // of the `button` between the expanded and active.
+  virtual void UpdateDeskIconButtonState(
+      CrOSNextDeskIconButton* button,
+      CrOSNextDeskIconButton::State target_state);
+
+  virtual void UpdateNewMiniViews(bool initializing_bar_view,
+                                  bool expanding_bar_view);
+
+  virtual void SwitchToZeroState();
+
+  virtual void SwitchToExpandedState();
+
+  virtual void HandlePressEvent(DeskMiniView* mini_view,
+                                const ui::LocatedEvent& event);
+
+  virtual void HandleLongPressEvent(DeskMiniView* mini_view,
+                                    const ui::LocatedEvent& event);
+
+  virtual void HandleDragEvent(DeskMiniView* mini_view,
+                               const ui::LocatedEvent& event);
+
+  virtual bool HandleReleaseEvent(DeskMiniView* mini_view,
+                                  const ui::LocatedEvent& event);
+
+ protected:
   // Returns the X offset of the first mini_view on the left (if there's one),
   // or the X offset of this view's center point when there are no mini_views.
   // This offset is used to calculate the amount by which the mini_views should
   // be moved when performing the mini_view creation or deletion animations.
   int GetFirstMiniViewXOffset() const;
 
+  // Determine the new index of the dragged desk at the position of
+  // `location_in_screen`.
+  int DetermineMoveIndex(int location_in_screen) const;
+
+  // Updates the visibility of `left_scroll_button_` and `right_scroll_button_`.
+  // Show `left_scroll_button_` if there are contents outside of the left edge
+  // of the `scroll_view_`, the same for `right_scroll_button_` based on the
+  // right side of the `scroll_view_`.
+  void UpdateScrollButtonsVisibility();
+
+  // We will show a fade in gradient besides `left_scroll_button_` and a fade
+  // out gradient besides `right_scroll_button_`. Show the gradient only when
+  // the corresponding scroll button is visible.
+  void UpdateGradientMask();
+
+  // Scrolls the desk bar to the previous or next page. The page size is the
+  // width of the scroll view, the contents that are outside of the scroll view
+  // will be clipped and can not be seen.
+  void ScrollToPreviousPage();
+  void ScrollToNextPage();
+
+  // Gets the adjusted scroll position based on `position` to make sure no desk
+  // preview is cropped at the start position of the scrollable bar.
+  int GetAdjustedUncroppedScrollPosition(int position) const;
+
+  void OnLibraryButtonPressed();
+
+  // This function cycles through `mini_views_` and updates the tooltip for each
+  // mini view's combine desks button.
+  void MaybeUpdateCombineDesksTooltips();
+
+  // Scrollview callbacks.
+  void OnContentsScrolled();
+  void OnContentsScrollEnded();
+
   const Type type_ = Type::kOverview;
 
   State state_ = State::kZero;
@@ -149,7 +300,7 @@
   // The views representing desks mini_views. They're owned by views hierarchy.
   std::vector<DeskMiniView*> mini_views_;
 
-  // Puts the contents in a ScrollView to support scrollable desks.
+  // Puts the contents in a `ScrollView` to support scrollable desks.
   views::ScrollView* scroll_view_ = nullptr;
 
   // Contents of `scroll_view_`, which includes `mini_views_`,
@@ -157,10 +308,43 @@
   // `expanded_state_library_button_` currently.
   views::View* scroll_view_contents_ = nullptr;
 
- private:
-  // TODO(yongshun): Migrate the following virtual functions to base class.
-  virtual void UpdateDeskButtonsVisibilityCrOSNext();
-  virtual void UpdateLibraryButtonVisibilityCrOSNext();
+  // Default desk button and new desk buttons.
+  raw_ptr<ZeroStateDefaultDeskButton, ExperimentalAsh>
+      zero_state_default_desk_button_ = nullptr;
+  raw_ptr<ZeroStateIconButton, ExperimentalAsh> zero_state_new_desk_button_ =
+      nullptr;
+  raw_ptr<ExpandedDesksBarButton, ExperimentalAsh>
+      expanded_state_new_desk_button_ = nullptr;
+
+  // Buttons to show the saved desk grid.
+  raw_ptr<ZeroStateIconButton, ExperimentalAsh> zero_state_library_button_ =
+      nullptr;
+  raw_ptr<ExpandedDesksBarButton, ExperimentalAsh>
+      expanded_state_library_button_ = nullptr;
+
+  // Buttons for the CrOS Next updated UI. They're added behind the feature flag
+  // Jellyroll.
+  // TODO(conniekxu): After CrOS Next is launched, replace
+  // `zero_state_default_desk_button_`, `zero_state_default_desk_button_`,
+  // `expanded_state_new_desk_button_`, `zero_state_library_button_` and
+  // `expanded_state_library_button_` with the buttons below.
+  raw_ptr<CrOSNextDefaultDeskButton, ExperimentalAsh> default_desk_button_ =
+      nullptr;
+  raw_ptr<CrOSNextDeskIconButton, ExperimentalAsh> new_desk_button_ = nullptr;
+  raw_ptr<CrOSNextDeskIconButton, ExperimentalAsh> library_button_ = nullptr;
+
+  // Labels to be shown under the desk icon buttons when they're at the active
+  // state.
+  raw_ptr<views::Label, ExperimentalAsh> new_desk_button_label_ = nullptr;
+  raw_ptr<views::Label, ExperimentalAsh> library_button_label_ = nullptr;
+
+  // Scroll arrow buttons.
+  raw_ptr<ScrollArrowButton, ExperimentalAsh> left_scroll_button_ = nullptr;
+  raw_ptr<ScrollArrowButton, ExperimentalAsh> right_scroll_button_ = nullptr;
+
+  // ScrollView callback subscriptions.
+  base::CallbackListSubscription on_contents_scrolled_subscription_;
+  base::CallbackListSubscription on_contents_scroll_ended_subscription_;
 
   raw_ptr<aura::Window> root_;
 };
diff --git a/ash/wm/desks/desks_constants.h b/ash/wm/desks/desks_constants.h
index ec29b9b..f0fd971 100644
--- a/ash/wm/desks/desks_constants.h
+++ b/ash/wm/desks/desks_constants.h
@@ -34,6 +34,12 @@
 
 constexpr int kDeskBarDeskPreviewViewFocusRingThicknessAndPadding = 4;
 
+// The minimum horizontal padding of the scroll view. This is set to make sure
+// there is enough space for the scroll buttons.
+constexpr int kDeskBarScrollViewMinimumHorizontalPadding = 32;
+
+constexpr int kDeskBarScrollButtonWidth = 36;
+
 // The duration of scrolling one page.
 constexpr base::TimeDelta kDeskBarScrollDuration = base::Milliseconds(250);
 
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc
index 12c4bd6..941ab47 100644
--- a/ash/wm/desks/desks_controller.cc
+++ b/ash/wm/desks/desks_controller.cc
@@ -1352,13 +1352,12 @@
           case chromeos::WindowStateType::kPrimarySnapped:
           case chromeos::WindowStateType::kSecondarySnapped:
             if (window_state->CanSnap()) {
-              window_state->set_snap_action_source(
-                  WindowSnapActionSource::kOthers);
-
-              const WMEvent event(
+              const WindowSnapWMEvent event(
                   target_state == chromeos::WindowStateType::kPrimarySnapped
                       ? WM_EVENT_SNAP_PRIMARY
-                      : WM_EVENT_SNAP_SECONDARY);
+                      : WM_EVENT_SNAP_SECONDARY,
+                  WindowSnapActionSource::
+                      kSnapByFullRestoreOrDeskTemplateOrSavedDesk);
               window_state->OnWMEvent(&event);
             }
             break;
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index f0ccc91..c64d6bf0 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -3937,7 +3937,7 @@
   auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
   auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
   WindowState* win0_state = WindowState::Get(win0.get());
-  WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  WindowSnapWMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
   win0_state->OnWMEvent(&snap_to_left);
   EXPECT_EQ(chromeos::WindowStateType::kPrimarySnapped,
             win0_state->GetStateType());
diff --git a/ash/wm/desks/legacy_desk_bar_view.cc b/ash/wm/desks/legacy_desk_bar_view.cc
index 71f90aa..6b907413 100644
--- a/ash/wm/desks/legacy_desk_bar_view.cc
+++ b/ash/wm/desks/legacy_desk_bar_view.cc
@@ -23,6 +23,7 @@
 #include "ash/wm/desks/desk_mini_view_animations.h"
 #include "ash/wm/desks/desk_name_view.h"
 #include "ash/wm/desks/desk_preview_view.h"
+#include "ash/wm/desks/desks_constants.h"
 #include "ash/wm/desks/desks_util.h"
 #include "ash/wm/desks/expanded_desks_bar_button.h"
 #include "ash/wm/desks/scroll_arrow_button.h"
@@ -77,21 +78,8 @@
 // The local Y coordinate of the zero state desk buttons.
 constexpr int kZeroStateY = 6;
 
-// The minimum horizontal padding of the scroll view. This is set to make sure
-// there is enough space for the scroll buttons.
-constexpr int kScrollViewMinimumHorizontalPadding = 32;
-
-constexpr int kScrollButtonWidth = 36;
-
-constexpr int kGradientZoneLength = 40;
-
-constexpr int kDeskPreviewViewFocusRingThicknessAndPadding = 4;
-
 constexpr int kDeskIconButtonAndLabelSpacing = 8;
 
-// The duration of scrolling one page.
-constexpr base::TimeDelta kBarScrollDuration = base::Milliseconds(250);
-
 gfx::Rect GetGestureEventScreenRect(const ui::Event& event) {
   DCHECK(event.IsGestureEvent());
   return event.AsGestureEvent()->details().bounding_box();
@@ -103,24 +91,6 @@
   return overview_controller->overview_session()->highlight_controller();
 }
 
-// Initialize a scoped layer animation settings for scroll view contents.
-void InitScrollContentsAnimationSettings(
-    ui::ScopedLayerAnimationSettings& settings) {
-  settings.SetTransitionDuration(kBarScrollDuration);
-  settings.SetTweenType(gfx::Tween::ACCEL_20_DECEL_60);
-}
-
-// Checks whether there are any external keyboards.
-bool HasExternalKeyboard() {
-  for (const ui::InputDevice& device :
-       ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
-    if (device.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL) {
-      return true;
-    }
-  }
-  return false;
-}
-
 }  // namespace
 
 // -----------------------------------------------------------------------------
@@ -288,7 +258,8 @@
     // between the views, the focus ring's thickness and padding on each sides.
     const int content_width =
         num_items * (mini_view_size.width() + kMiniViewsSpacing) -
-        kMiniViewsSpacing + kDeskPreviewViewFocusRingThicknessAndPadding * 2;
+        kMiniViewsSpacing +
+        kDeskBarDeskPreviewViewFocusRingThicknessAndPadding * 2;
     width_ = std::max(scroll_bounds.width(), content_width);
 
     // Update the size of the |host|, which is |scroll_view_contents_| here.
@@ -301,7 +272,7 @@
     // padding into consideration, otherwise the focus ring won't be drawn on
     // the left side of the first mini view.
     int x = (width_ - content_width) / 2 +
-            kDeskPreviewViewFocusRingThicknessAndPadding;
+            kDeskBarDeskPreviewViewFocusRingThicknessAndPadding;
     const int y = kMiniViewsY - mini_views[0]->GetPreviewBorderInsets().top();
     for (auto* mini_view : mini_views) {
       mini_view->SetBoundsRect(gfx::Rect(gfx::Point(x, y), mini_view_size));
@@ -436,7 +407,8 @@
         (new_desk_button_size.width() + kMiniViewsSpacing) +
         (library_button_visible ? 1 : 0) *
             (library_button_size.width() + kMiniViewsSpacing) -
-        kMiniViewsSpacing + kDeskPreviewViewFocusRingThicknessAndPadding * 2;
+        kMiniViewsSpacing +
+        kDeskBarDeskPreviewViewFocusRingThicknessAndPadding * 2;
     width_ = std::max(scroll_bounds.width(), content_width);
 
     // Update the size of the `host`, which is `scroll_view_contents_` here.
@@ -449,7 +421,7 @@
     // padding into consideration, otherwise the focus ring won't be drawn on
     // the left side of the first mini view.
     int x = (width_ - content_width) / 2 +
-            kDeskPreviewViewFocusRingThicknessAndPadding;
+            kDeskBarDeskPreviewViewFocusRingThicknessAndPadding;
     const int y = kMiniViewsY - mini_views[0]->GetPreviewBorderInsets().top();
     for (auto* mini_view : mini_views) {
       mini_view->SetBoundsRect(gfx::Rect(gfx::Point(x, y), mini_view_size));
@@ -512,125 +484,11 @@
     : DeskBarViewBase(overview_grid->root_window(),
                       DeskBarViewBase::Type::kOverview) {
   overview_grid_ = overview_grid;
-  SetPaintToLayer();
-  layer()->SetFillsBoundsOpaquely(false);
 
-  SetBorder(std::make_unique<views::HighlightBorder>(
-      /*corner_radius=*/0,
-      chromeos::features::IsJellyrollEnabled()
-          ? views::HighlightBorder::Type::kHighlightBorderNoShadow
-          : views::HighlightBorder::Type::kHighlightBorder2));
-
-  SetBackground(views::CreateThemedSolidBackground(kColorAshShieldAndBase80));
-  // Use layer scrolling so that the contents will paint on top of the parent,
-  // which uses SetPaintToLayer()
-  scroll_view_ = AddChildView(std::make_unique<views::ScrollView>(
-      views::ScrollView::ScrollWithLayers::kEnabled));
-  scroll_view_->SetPaintToLayer();
-  scroll_view_->layer()->SetFillsBoundsOpaquely(false);
-  scroll_view_->SetBackgroundColor(absl::nullopt);
-  scroll_view_->SetDrawOverflowIndicator(false);
-  scroll_view_->SetHorizontalScrollBarMode(
-      views::ScrollView::ScrollBarMode::kHiddenButEnabled);
-  scroll_view_->SetTreatAllScrollEventsAsHorizontal(true);
-
-  left_scroll_button_ = AddChildView(std::make_unique<ScrollArrowButton>(
-      base::BindRepeating(&LegacyDeskBarView::ScrollToPreviousPage,
-                          base::Unretained(this)),
-      /*is_left_arrow=*/true, this));
-  right_scroll_button_ = AddChildView(std::make_unique<ScrollArrowButton>(
-      base::BindRepeating(&LegacyDeskBarView::ScrollToNextPage,
-                          base::Unretained(this)),
-      /*is_left_arrow=*/false, this));
-
-  // Make the scroll content view animatable by painting to a layer.
-  scroll_view_contents_ =
-      scroll_view_->SetContents(std::make_unique<views::View>());
-  scroll_view_contents_->SetPaintToLayer();
-
-  if (chromeos::features::IsJellyrollEnabled()) {
-    default_desk_button_ = scroll_view_contents_->AddChildView(
-        std::make_unique<CrOSNextDefaultDeskButton>(this));
-    new_desk_button_ = scroll_view_contents_->AddChildView(
-        std::make_unique<CrOSNextDeskIconButton>(
-            this, &kDesksNewDeskButtonIcon,
-            l10n_util::GetStringUTF16(IDS_ASH_DESKS_NEW_DESK_BUTTON),
-            cros_tokens::kCrosSysOnPrimary, cros_tokens::kCrosSysPrimary,
-            /*initially_enabled=*/DesksController::Get()->CanCreateDesks(),
-            base::BindRepeating(&LegacyDeskBarView::OnNewDeskButtonPressed,
-                                base::Unretained(this),
-                                DesksCreationRemovalSource::kButton)));
-    new_desk_button_label_ =
-        scroll_view_contents_->AddChildView(std::make_unique<views::Label>());
-    new_desk_button_label_->SetPaintToLayer();
-    new_desk_button_label_->layer()->SetFillsBoundsOpaquely(false);
-  } else {
-    expanded_state_new_desk_button_ = scroll_view_contents_->AddChildView(
-        std::make_unique<ExpandedDesksBarButton>(
-            this, &kDesksNewDeskButtonIcon,
-            l10n_util::GetStringUTF16(IDS_ASH_DESKS_NEW_DESK_BUTTON),
-            /*initially_enabled=*/DesksController::Get()->CanCreateDesks(),
-            base::BindRepeating(&LegacyDeskBarView::OnNewDeskButtonPressed,
-                                base::Unretained(this),
-                                DesksCreationRemovalSource::kButton)));
-
-    zero_state_default_desk_button_ = scroll_view_contents_->AddChildView(
-        std::make_unique<ZeroStateDefaultDeskButton>(this));
-    zero_state_new_desk_button_ = scroll_view_contents_->AddChildView(
-        std::make_unique<ZeroStateIconButton>(
-            this, &kDesksNewDeskButtonIcon,
-            l10n_util::GetStringUTF16(IDS_ASH_DESKS_NEW_DESK_BUTTON),
-            base::BindRepeating(&LegacyDeskBarView::OnNewDeskButtonPressed,
-                                base::Unretained(this),
-                                DesksCreationRemovalSource::kButton)));
-  }
-
-  if (saved_desk_util::IsSavedDesksEnabled()) {
-    int button_text_id = IDS_ASH_DESKS_TEMPLATES_DESKS_BAR_BUTTON_LIBRARY;
-    if (!saved_desk_util::AreDesksTemplatesEnabled()) {
-      button_text_id = IDS_ASH_DESKS_TEMPLATES_DESKS_BAR_BUTTON_SAVED_FOR_LATER;
-    }
-
-    if (chromeos::features::IsJellyrollEnabled()) {
-      library_button_ = scroll_view_contents_->AddChildView(
-          std::make_unique<CrOSNextDeskIconButton>(
-              this, &kDesksTemplatesIcon,
-              l10n_util::GetStringUTF16(button_text_id),
-              cros_tokens::kCrosSysOnSecondaryContainer,
-              cros_tokens::kCrosSysInversePrimary,
-              /*initially_enabled=*/true,
-              base::BindRepeating(&LegacyDeskBarView::OnLibraryButtonPressed,
-                                  base::Unretained(this))));
-      library_button_label_ =
-          scroll_view_contents_->AddChildView(std::make_unique<views::Label>());
-      library_button_label_->SetPaintToLayer();
-      library_button_label_->layer()->SetFillsBoundsOpaquely(false);
-    } else {
-      expanded_state_library_button_ = scroll_view_contents_->AddChildView(
-          std::make_unique<ExpandedDesksBarButton>(
-              this, &kDesksTemplatesIcon,
-              l10n_util::GetStringUTF16(button_text_id),
-              /*initially_enabled=*/true,
-              base::BindRepeating(&LegacyDeskBarView::OnLibraryButtonPressed,
-                                  base::Unretained(this))));
-      zero_state_library_button_ = scroll_view_contents_->AddChildView(
-          std::make_unique<ZeroStateIconButton>(
-              this, &kDesksTemplatesIcon,
-              l10n_util::GetStringUTF16(button_text_id),
-              base::BindRepeating(&LegacyDeskBarView::OnLibraryButtonPressed,
-                                  base::Unretained(this))));
-    }
-  }
+  // TODO(b/278946142): Migrate `DesksBarScrollViewLayout` to use base class.
   scroll_view_contents_->SetLayoutManager(
       std::make_unique<DesksBarScrollViewLayout>(this));
 
-  on_contents_scrolled_subscription_ =
-      scroll_view_->AddContentsScrolledCallback(base::BindRepeating(
-          &LegacyDeskBarView::OnContentsScrolled, base::Unretained(this)));
-  on_contents_scroll_ended_subscription_ =
-      scroll_view_->AddContentsScrollEndedCallback(base::BindRepeating(
-          &LegacyDeskBarView::OnContentsScrollEnded, base::Unretained(this)));
-
   DesksController::Get()->AddObserver(this);
 }
 
@@ -642,34 +500,13 @@
 }
 
 void LegacyDeskBarView::Init() {
-  UpdateNewMiniViews(/*initializing_bar_view=*/true,
-                     /*expanding_bar_view=*/false);
+  DeskBarViewBase::Init();
 
-  // When the bar is initialized, scroll to make active desk mini view visible.
-  auto it = base::ranges::find_if(mini_views_, [](DeskMiniView* mini_view) {
-    return mini_view->desk()->is_active();
-  });
-  if (it != mini_views_.end()) {
-    ScrollToShowViewIfNecessary(*it);
-  }
-
+  // TODO(b/278946144): Migrate `DeskBarHoverObserver` to use base class.
   hover_observer_ = std::make_unique<DeskBarHoverObserver>(
       this, GetWidget()->GetNativeWindow());
 }
 
-bool LegacyDeskBarView::IsDeskNameBeingModified() const {
-  if (!GetWidget()->IsActive()) {
-    return false;
-  }
-
-  for (auto* mini_view : mini_views_) {
-    if (mini_view->IsDeskNameBeingModified()) {
-      return true;
-    }
-  }
-  return false;
-}
-
 void LegacyDeskBarView::OnHoverStateMayHaveChanged() {
   for (auto* mini_view : mini_views_) {
     mini_view->UpdateDeskButtonVisibility();
@@ -901,73 +738,10 @@
   drag_proxy_.reset();
 }
 
-void LegacyDeskBarView::OnSavedDeskLibraryHidden() {
-  if (!chromeos::features::IsJellyrollEnabled() && mini_views_.size() == 1u) {
-    SwitchToZeroState();
-  }
-}
-
 const char* LegacyDeskBarView::GetClassName() const {
   return "LegacyDeskBarView";
 }
 
-void LegacyDeskBarView::Layout() {
-  if (is_bounds_animation_on_going_) {
-    return;
-  }
-
-  if (!overview_grid_) {
-    return;
-  }
-
-  // Scroll buttons are kept |kScrollViewMinimumHorizontalPadding| away from
-  // the edge of the scroll view. So the horizontal padding of the scroll view
-  // is set to guarantee enough space for the scroll buttons.
-  const gfx::Insets insets = overview_grid_->GetGridInsets();
-  DCHECK(insets.left() == insets.right());
-  const int horizontal_padding =
-      std::max(kScrollViewMinimumHorizontalPadding, insets.left());
-  left_scroll_button_->SetBounds(
-      horizontal_padding - kScrollViewMinimumHorizontalPadding, bounds().y(),
-      kScrollButtonWidth, bounds().height());
-  right_scroll_button_->SetBounds(
-      bounds().right() - horizontal_padding -
-          (kScrollButtonWidth - kScrollViewMinimumHorizontalPadding),
-      bounds().y(), kScrollButtonWidth, bounds().height());
-
-  gfx::Rect scroll_bounds = bounds();
-  // Align with the overview grid in horizontal, so only horizontal insets are
-  // needed here.
-  scroll_bounds.Inset(gfx::Insets::VH(0, horizontal_padding));
-  scroll_view_->SetBoundsRect(scroll_bounds);
-
-  // Clip the contents that are outside of the |scroll_view_|'s bounds.
-  scroll_view_->layer()->SetMasksToBounds(true);
-  scroll_view_->Layout();
-
-  UpdateScrollButtonsVisibility();
-  UpdateGradientMask();
-}
-
-bool LegacyDeskBarView::OnMousePressed(const ui::MouseEvent& event) {
-  DeskNameView::CommitChanges(GetWidget());
-  return false;
-}
-
-void LegacyDeskBarView::OnGestureEvent(ui::GestureEvent* event) {
-  switch (event->type()) {
-    case ui::ET_GESTURE_LONG_PRESS:
-    case ui::ET_GESTURE_LONG_TAP:
-    case ui::ET_GESTURE_TAP:
-    case ui::ET_GESTURE_TAP_DOWN:
-      DeskNameView::CommitChanges(GetWidget());
-      break;
-
-    default:
-      break;
-  }
-}
-
 void LegacyDeskBarView::OnDeskAdded(const Desk* desk) {
   DeskNameView::CommitChanges(GetWidget());
 
@@ -1158,154 +932,6 @@
       begin_x - GetFirstMiniViewXOffset());
 }
 
-void LegacyDeskBarView::OnNewDeskButtonPressed(
-    DesksCreationRemovalSource desks_creation_removal_source) {
-  auto* controller = DesksController::Get();
-  if (!controller->CanCreateDesks()) {
-    return;
-  }
-  controller->NewDesk(desks_creation_removal_source);
-  NudgeDeskName(mini_views_.size() - 1);
-
-  // TODO(b/277081702): When desk order is adjusted for RTL, remove the check
-  // below to always make new desk button visible.
-  if (!base::i18n::IsRTL()) {
-    if (new_desk_button_) {
-      ScrollToShowViewIfNecessary(new_desk_button_);
-    } else if (expanded_state_new_desk_button_) {
-      ScrollToShowViewIfNecessary(expanded_state_new_desk_button_);
-    }
-  }
-}
-
-void LegacyDeskBarView::UpdateButtonsForSavedDeskGrid() {
-  if (IsZeroState() || !saved_desk_util::IsSavedDesksEnabled()) {
-    return;
-  }
-
-  FindMiniViewForDesk(Shell::Get()->desks_controller()->active_desk())
-      ->UpdateFocusColor();
-
-  if (chromeos::features::IsJellyrollEnabled()) {
-    library_button_->set_paint_as_active(
-        overview_grid_->IsShowingSavedDeskLibrary());
-    library_button_->UpdateFocusState();
-  } else {
-    expanded_state_library_button_->set_active(
-        overview_grid_->IsShowingSavedDeskLibrary());
-    expanded_state_library_button_->UpdateFocusColor();
-  }
-}
-
-void LegacyDeskBarView::UpdateDeskButtonsVisibility() {
-  if (chromeos::features::IsJellyrollEnabled()) {
-    UpdateDeskButtonsVisibilityCrOSNext();
-    return;
-  }
-  const bool is_zero_state = IsZeroState();
-  zero_state_default_desk_button_->SetVisible(is_zero_state);
-  zero_state_new_desk_button_->SetVisible(is_zero_state);
-  expanded_state_new_desk_button_->SetVisible(!is_zero_state);
-
-  UpdateLibraryButtonVisibility();
-}
-
-void LegacyDeskBarView::UpdateDeskButtonsVisibilityCrOSNext() {
-  const bool is_zero_state = IsZeroState();
-  default_desk_button_->SetVisible(is_zero_state);
-  new_desk_button_label_->SetVisible(new_desk_button_->state() ==
-                                     CrOSNextDeskIconButton::State::kActive);
-
-  UpdateLibraryButtonVisibilityCrOSNext();
-}
-
-void LegacyDeskBarView::UpdateLibraryButtonVisibility() {
-  if (chromeos::features::IsJellyrollEnabled()) {
-    UpdateLibraryButtonVisibilityCrOSNext();
-    return;
-  }
-  if (!saved_desk_util::IsSavedDesksEnabled()) {
-    return;
-  }
-
-  const bool should_show_ui = overview_grid_->overview_session()
-                                  ->saved_desk_presenter()
-                                  ->should_show_saved_desk_library();
-  const bool is_zero_state = IsZeroState();
-
-  zero_state_library_button_->SetVisible(should_show_ui && is_zero_state);
-  expanded_state_library_button_->SetVisible(should_show_ui && !is_zero_state);
-
-  // Removes the button from the tabbing order if it becomes invisible.
-  auto* highlight_controller = GetHighlightController();
-  if (!zero_state_library_button_->GetVisible()) {
-    highlight_controller->OnViewDestroyingOrDisabling(
-        zero_state_library_button_);
-  }
-  if (!expanded_state_library_button_->GetVisible()) {
-    highlight_controller->OnViewDestroyingOrDisabling(
-        expanded_state_library_button_->GetInnerButton());
-  }
-
-  const int begin_x = GetFirstMiniViewXOffset();
-  Layout();
-
-  if (mini_views_.empty()) {
-    return;
-  }
-
-  // The mini views and new desk button are already laid out in the earlier
-  // `Layout()` call. This call shifts the transforms of the mini views and new
-  // desk button and then animates to the identity transform.
-  PerformLibraryButtonVisibilityAnimation(
-      mini_views_,
-      is_zero_state
-          ? static_cast<views::View*>(zero_state_new_desk_button_)
-          : static_cast<views::View*>(expanded_state_new_desk_button_),
-      begin_x - GetFirstMiniViewXOffset());
-}
-
-void LegacyDeskBarView::UpdateLibraryButtonVisibilityCrOSNext() {
-  if (!saved_desk_util::IsSavedDesksEnabled()) {
-    return;
-  }
-
-  const bool should_show_ui = overview_grid_->overview_session()
-                                  ->saved_desk_presenter()
-                                  ->should_show_saved_desk_library();
-
-  library_button_label_->SetVisible(
-      should_show_ui &&
-      (library_button_->state() == CrOSNextDeskIconButton::State::kActive));
-
-  // If the visibility of the library button doesn't change, return early.
-  if (library_button_->GetVisible() == should_show_ui) {
-    return;
-  }
-
-  library_button_->SetVisible(should_show_ui);
-  if (should_show_ui) {
-    if (overview_grid_->WillShowSavedDeskLibrary()) {
-      library_button_->UpdateState(CrOSNextDeskIconButton::State::kActive);
-    } else {
-      library_button_->UpdateState(CrOSNextDeskIconButton::State::kExpanded);
-    }
-  }
-
-  if (mini_views_.empty()) {
-    return;
-  }
-
-  const int begin_x = GetFirstMiniViewXOffset();
-  Layout();
-
-  // The mini views and new desk button are already laid out in the earlier
-  // `Layout()` call. This call shifts the transforms of the mini views and new
-  // desk button and then animates to the identity transform.
-  PerformLibraryButtonVisibilityAnimation(mini_views_, new_desk_button_,
-                                          begin_x - GetFirstMiniViewXOffset());
-}
-
 void LegacyDeskBarView::SwitchToZeroState() {
   DCHECK(!chromeos::features::IsJellyrollEnabled());
 
@@ -1346,29 +972,6 @@
   }
 }
 
-int LegacyDeskBarView::DetermineMoveIndex(int location_screen_x) const {
-  const int views_size = static_cast<int>(mini_views_.size());
-
-  // We find the target position according to the x-axis coordinate of the
-  // desks' center positions in screen in ascending order.
-  for (int new_index = 0; new_index != views_size - 1; ++new_index) {
-    auto* mini_view = mini_views_[new_index];
-
-    // Note that we cannot directly use |GetBoundsInScreen|. Because we may
-    // perform animation (transform) on mini views. The bounds gotten from
-    // |GetBoundsInScreen| may be the intermediate bounds during animation.
-    // Therefore, we transfer a mini view's origin from its parent level to
-    // avoid the influence of its own transform.
-    gfx::Point center_screen_pos = mini_view->GetMirroredBounds().CenterPoint();
-    views::View::ConvertPointToScreen(mini_view->parent(), &center_screen_pos);
-    if (location_screen_x < center_screen_pos.x()) {
-      return new_index;
-    }
-  }
-
-  return views_size - 1;
-}
-
 bool LegacyDeskBarView::MaybeScrollByDraggedDesk() {
   DCHECK(drag_proxy_);
 
@@ -1391,148 +994,6 @@
   return false;
 }
 
-void LegacyDeskBarView::UpdateScrollButtonsVisibility() {
-  const gfx::Rect visible_bounds = scroll_view_->GetVisibleRect();
-  left_scroll_button_->SetVisible(visible_bounds.x() > 0);
-  right_scroll_button_->SetVisible(visible_bounds.right() <
-                                   scroll_view_contents_->bounds().width());
-}
-
-void LegacyDeskBarView::UpdateGradientMask() {
-  const bool is_rtl = base::i18n::IsRTL();
-  const bool is_left_scroll_button_visible = left_scroll_button_->GetVisible();
-  const bool is_right_scroll_button_visible =
-      right_scroll_button_->GetVisible();
-  const bool is_left_visible_only =
-      is_left_scroll_button_visible && !is_right_scroll_button_visible;
-
-  bool should_show_start_gradient = false;
-  bool should_show_end_gradient = false;
-  // Show the both sides gradients during scroll if the corresponding scroll
-  // button is visible. Otherwise, show the start/end gradient only in last page
-  // and show the end/start gradient if there are contents beyond the right/left
-  // side of the visible bounds with LTR/RTL layout.
-  if (scroll_view_->is_scrolling()) {
-    should_show_start_gradient =
-        is_rtl ? is_right_scroll_button_visible : is_left_scroll_button_visible;
-    should_show_end_gradient =
-        is_rtl ? is_left_scroll_button_visible : is_right_scroll_button_visible;
-  } else {
-    should_show_start_gradient =
-        is_rtl ? is_right_scroll_button_visible : is_left_visible_only;
-    should_show_end_gradient =
-        is_rtl ? is_left_visible_only : is_right_scroll_button_visible;
-  }
-
-  // The bounds of the start and end gradient will be the same regardless it is
-  // LTR or RTL layout. While the |left_scroll_button_| will be changed from
-  // left to right and |right_scroll_button_| will be changed from right to left
-  // if it is RTL layout.
-
-  // Horizontal linear gradient, from left to right.
-  gfx::LinearGradient gradient_mask(/*angle=*/0);
-
-  // Fraction of layer width that gradient will be applied to.
-  const float fade_position =
-      should_show_start_gradient || should_show_end_gradient
-          ? static_cast<float>(kGradientZoneLength) /
-                scroll_view_->bounds().width()
-          : 0;
-
-  // Left fade in section.
-  if (should_show_start_gradient) {
-    gradient_mask.AddStep(/*fraction=*/0, /*alpha=*/0);
-    gradient_mask.AddStep(fade_position, 255);
-  }
-  // Right fade out section.
-  if (should_show_end_gradient) {
-    gradient_mask.AddStep((1 - fade_position), 255);
-    gradient_mask.AddStep(1, 0);
-  }
-
-  scroll_view_->layer()->SetGradientMask(gradient_mask);
-  scroll_view_->SchedulePaint();
-}
-
-void LegacyDeskBarView::ScrollToPreviousPage() {
-  ui::ScopedLayerAnimationSettings settings(
-      scroll_view_contents_->layer()->GetAnimator());
-  InitScrollContentsAnimationSettings(settings);
-  scroll_view_->ScrollToPosition(
-      scroll_view_->horizontal_scroll_bar(),
-      GetAdjustedUncroppedScrollPosition(scroll_view_->GetVisibleRect().x() -
-                                         scroll_view_->width()));
-}
-
-void LegacyDeskBarView::ScrollToNextPage() {
-  ui::ScopedLayerAnimationSettings settings(
-      scroll_view_contents_->layer()->GetAnimator());
-  InitScrollContentsAnimationSettings(settings);
-  scroll_view_->ScrollToPosition(
-      scroll_view_->horizontal_scroll_bar(),
-      GetAdjustedUncroppedScrollPosition(scroll_view_->GetVisibleRect().x() +
-                                         scroll_view_->width()));
-}
-
-int LegacyDeskBarView::GetAdjustedUncroppedScrollPosition(int position) const {
-  // Let the ScrollView handle it if the given |position| is invalid or it can't
-  // be adjusted.
-  if (position <= 0 || position >= scroll_view_contents_->bounds().width() -
-                                       scroll_view_->width()) {
-    return position;
-  }
-
-  int adjusted_position = position;
-  int i = 0;
-  gfx::Rect mini_view_bounds;
-  const int mini_views_size = static_cast<int>(mini_views_.size());
-  for (; i < mini_views_size; i++) {
-    mini_view_bounds = mini_views_[i]->bounds();
-
-    // Return early if there is no desk preview cropped at the start position.
-    if (mini_view_bounds.x() >= position) {
-      return position - kDeskPreviewViewFocusRingThicknessAndPadding;
-    }
-
-    if (mini_view_bounds.x() < position &&
-        mini_view_bounds.right() > position) {
-      break;
-    }
-  }
-
-  DCHECK_LT(i, mini_views_size);
-  if ((position - mini_view_bounds.x()) < mini_view_bounds.width() / 2) {
-    adjusted_position = mini_view_bounds.x();
-  } else {
-    adjusted_position = mini_view_bounds.right();
-    if (i + 1 < mini_views_size) {
-      adjusted_position = mini_views_[i + 1]->bounds().x();
-    }
-  }
-  return adjusted_position - kDeskPreviewViewFocusRingThicknessAndPadding;
-}
-
-void LegacyDeskBarView::OnLibraryButtonPressed() {
-  RecordLoadSavedDeskLibraryHistogram();
-  if (IsDeskNameBeingModified()) {
-    DeskNameView::CommitChanges(GetWidget());
-  }
-  overview_grid_->overview_session()->ShowSavedDeskLibrary(
-      base::Uuid(), /*saved_desk_name=*/u"",
-      GetWidget()->GetNativeWindow()->GetRootWindow());
-}
-
-void LegacyDeskBarView::MaybeUpdateCombineDesksTooltips() {
-  for (auto* mini_view : mini_views_) {
-    // If desk is being removed, do not update the tooltip.
-    if (mini_view->desk()->is_desk_being_removed()) {
-      continue;
-    }
-    mini_view->desk_action_view()->UpdateCombineDesksTooltip(
-        DesksController::Get()->GetCombineDesksTargetName(mini_view->desk()));
-  }
-}
-
 void LegacyDeskBarView::UpdateDeskIconButtonState(
     CrOSNextDeskIconButton* button,
     CrOSNextDeskIconButton::State target_state) {
@@ -1546,8 +1007,7 @@
   const int begin_x = GetFirstMiniViewXOffset();
   gfx::Rect current_bounds = button->GetBoundsInScreen();
 
-  button->UpdateState(target_state);
-  Layout();
+  DeskBarViewBase::UpdateDeskIconButtonState(button, target_state);
 
   gfx::RectF target_bounds = gfx::RectF(new_desk_button_->GetBoundsInScreen());
   gfx::Transform scale_transform;
@@ -1556,48 +1016,9 @@
   scale_transform.Scale(current_bounds.width() / target_bounds.width(),
                         current_bounds.height() / target_bounds.height());
 
+  // TODO(b/278946302): Migrate desk mini view animations to use base class.
   PerformDeskIconButtonScaleAnimationCrOSNext(button, this, scale_transform,
                                               shift_x);
 }
 
-void LegacyDeskBarView::OnContentsScrolled() {
-  UpdateScrollButtonsVisibility();
-  UpdateGradientMask();
-}
-
-void LegacyDeskBarView::OnContentsScrollEnded() {
-  const gfx::Rect visible_bounds = scroll_view_->GetVisibleRect();
-  const int current_position = visible_bounds.x();
-  const int adjusted_position =
-      GetAdjustedUncroppedScrollPosition(current_position);
-  if (current_position != adjusted_position) {
-    scroll_view_->ScrollToPosition(scroll_view_->horizontal_scroll_bar(),
-                                   adjusted_position);
-  }
-  UpdateGradientMask();
-}
-
-void LegacyDeskBarView::NudgeDeskName(int desk_index) {
-  DCHECK_LT(desk_index, static_cast<int>(mini_views_.size()));
-
-  auto* name_view = mini_views_[desk_index]->desk_name_view();
-  name_view->RequestFocus();
-
-  // Set `name_view`'s accessible name to the default desk name since its text
-  // is cleared.
-  if (name_view->GetAccessibleName().empty()) {
-    name_view->SetAccessibleName(
-        DesksController::GetDeskDefaultName(desk_index));
-  }
-
-  UpdateOverviewHighlightForFocus(name_view);
-
-  // If we're in tablet mode and there are no external keyboards, open up the
-  // virtual keyboard.
-  if (Shell::Get()->tablet_mode_controller()->InTabletMode() &&
-      !HasExternalKeyboard()) {
-    keyboard::KeyboardUIController::Get()->ShowKeyboard(/*lock=*/false);
-  }
-}
-
 }  // namespace ash
diff --git a/ash/wm/desks/legacy_desk_bar_view.h b/ash/wm/desks/legacy_desk_bar_view.h
index 69d4ea3..36926611 100644
--- a/ash/wm/desks/legacy_desk_bar_view.h
+++ b/ash/wm/desks/legacy_desk_bar_view.h
@@ -21,17 +21,11 @@
 
 namespace ash {
 
-class CrOSNextDefaultDeskButton;
-class CrOSNextDeskIconButton;
 class DesksBarScrollViewLayout;
 class DeskBarHoverObserver;
 class DeskDragProxy;
 class DeskMiniView;
-class ExpandedDesksBarButton;
 class OverviewGrid;
-class ScrollArrowButton;
-class ZeroStateDefaultDeskButton;
-class ZeroStateIconButton;
 
 // A bar that resides at the top portion of the overview, which contains desk
 // mini views, the new desk button, the library button, and the scroll arrow
@@ -45,62 +39,7 @@
 
   ~LegacyDeskBarView() override;
 
-  ZeroStateDefaultDeskButton* zero_state_default_desk_button() const {
-    return zero_state_default_desk_button_;
-  }
-
-  ZeroStateIconButton* zero_state_new_desk_button() const {
-    return zero_state_new_desk_button_;
-  }
-
-  ExpandedDesksBarButton* expanded_state_new_desk_button() const {
-    return expanded_state_new_desk_button_;
-  }
-
-  ZeroStateIconButton* zero_state_library_button() const {
-    return zero_state_library_button_;
-  }
-
-  ExpandedDesksBarButton* expanded_state_library_button() const {
-    return expanded_state_library_button_;
-  }
-
-  CrOSNextDefaultDeskButton* default_desk_button() {
-    return default_desk_button_;
-  }
-  const CrOSNextDefaultDeskButton* default_desk_button() const {
-    return default_desk_button_;
-  }
-
-  CrOSNextDeskIconButton* new_desk_button() { return new_desk_button_; }
-  const CrOSNextDeskIconButton* new_desk_button() const {
-    return new_desk_button_;
-  }
-
-  CrOSNextDeskIconButton* library_button() { return library_button_; }
-  const CrOSNextDeskIconButton* library_button() const {
-    return library_button_;
-  }
-
-  views::Label* new_desk_button_label() { return new_desk_button_label_; }
-  const views::Label* new_desk_button_label() const {
-    return new_desk_button_label_;
-  }
-
-  views::Label* library_button_label() { return library_button_label_; }
-  const views::Label* library_button_label() const {
-    return library_button_label_;
-  }
-
-  // Initializes and creates mini_views for any pre-existing desks, before the
-  // bar was created. This should only be called after this view has been added
-  // to a widget, as it needs to call `GetWidget()` when it's performing a
-  // layout.
-  void Init();
-
-  // Returns true if a desk name is being modified using its mini view's
-  // DeskNameView on this bar.
-  bool IsDeskNameBeingModified() const;
+  void Init() override;
 
   // Updates the visibility state of the close buttons on all the mini_views as
   // a result of mouse and gesture events.
@@ -110,6 +49,7 @@
   // Called when an item is being dragged in overview mode to update whether it
   // is currently intersecting with this view, and the |screen_location| of the
   // current drag position.
+  // TODO(b/278946648): Migrate drag related stuff to base class.
   void SetDragDetails(const gfx::Point& screen_location,
                       bool dragged_item_over_bar);
 
@@ -147,17 +87,11 @@
   // Reset the drag view and the drag proxy.
   void FinalizeDragDesk();
 
-  // Called when the saved desk library is hidden. Transitions the desk bar
-  // view to zero state if necessary.
-  void OnSavedDeskLibraryHidden();
-
   // views::View:
   const char* GetClassName() const override;
-  void Layout() override;
-  bool OnMousePressed(const ui::MouseEvent& event) override;
-  void OnGestureEvent(ui::GestureEvent* event) override;
 
   // DesksController::Observer:
+  // TODO(b/278945929): Migrate the following functions to base class.
   void OnDeskAdded(const Desk* desk) override;
   void OnDeskRemoved(const Desk* desk) override;
   void OnDeskReordered(int old_index, int new_index) override;
@@ -189,143 +123,34 @@
   void UpdateNewMiniViews(bool initializing_bar_view,
                           bool expanding_bar_view) override;
 
-  void OnNewDeskButtonPressed(
-      DesksCreationRemovalSource desks_creation_removal_source);
-
-  // If in expanded state, updates the border color of the
-  // `expanded_state_library_button_` and the active desk's mini view
-  // after the saved desk library has been shown. If not in expanded state,
-  // updates the background color of the `zero_state_library_button_`
-  // and the `zero_state_default_desk_button_`.
-  void UpdateButtonsForSavedDeskGrid();
-
-  // Updates the visibility of the two buttons inside the zero state desk bar
-  // and the `ExpandedDesksBarButton` on the desk bar's state.
-  void UpdateDeskButtonsVisibility() override;
-
-  // Udates the visibility of the `default_desk_button_` on the desk bar's
-  // state.
-  // TODO(conniekxu): Remove `UpdateDeskButtonsVisibility`, replace it with this
-  // function, and rename this function by removing the prefix CrOSNext.
-  void UpdateDeskButtonsVisibilityCrOSNext() override;
-
-  // Updates the visibility of the saved desk library button based on whether
-  // the saved desk feature is enabled, the user has any saved desks and the
-  // state of the desk bar.
-  void UpdateLibraryButtonVisibility();
-
-  // Updates the visibility of the saved desk library button based on whether
-  // the saved desk feature is enabled and the user has any saved desks.
-  // TODO(conniekxu): Remove `UpdateLibraryButtonVisibility`, replace it with
-  // this function, and rename this function by removing the prefix CrOSNext.
-  void UpdateLibraryButtonVisibilityCrOSNext() override;
-
   // Animates the bar from the expanded state to the zero state. It refreshes
   // the bounds of the desk bar widget, and also updates child UI components,
   // including desk mini views, the new desk button, and the library button.
-  void SwitchToZeroState();
+  void SwitchToZeroState() override;
 
   // Animates the bar from the zero state to the expanded state.
   void SwitchToExpandedState() override;
 
-  // Bring focus to the name view of the desk with `desk_index`.
-  void NudgeDeskName(int desk_index) override;
-
-  // Called to update state of `button` and apply the scale animation to the
-  // button. For the new desk button, this is called when the make the new desk
-  // button a drop target for the window being dragged or at the end of the
-  // drag. For the library button, this is called when the library is clicked at
-  // the expanded state. Please note this will only be used to switch the states
-  // of the `button` between the expanded and active.
-  void UpdateDeskIconButtonState(CrOSNextDeskIconButton* button,
-                                 CrOSNextDeskIconButton::State target_state);
+  void UpdateDeskIconButtonState(
+      CrOSNextDeskIconButton* button,
+      CrOSNextDeskIconButton::State target_state) override;
 
  private:
   friend class DesksBarScrollViewLayout;
   friend class DesksTestApi;
 
-  // Determine the new index of the dragged desk at the position of
-  // |location_in_screen|.
-  int DetermineMoveIndex(int location_in_screen) const;
-
   // If drag a desk over a scroll button (i.e., the desk intersects the button),
   // scroll the desk bar. If the desk is dropped or leaves the button, end
   // scroll. Return true if the scroll is triggered. Return false if the scroll
   // is ended.
   bool MaybeScrollByDraggedDesk();
 
-  // Updates the visibility of |left_scroll_button_| and |right_scroll_button_|.
-  // Show |left_scroll_button_| if there are contents outside of the left edge
-  // of the |scroll_view_|, the same for |right_scroll_button_| based on the
-  // right side of the |scroll_view_|.
-  void UpdateScrollButtonsVisibility() override;
-
-  // We will show a fade in gradient besides |left_scroll_button_| and a fade
-  // out gradient besides |right_scroll_button_|. Show the gradient only when
-  // the corresponding scroll button is visible.
-  void UpdateGradientMask() override;
-
-  // Scrolls the desk bar to the previous or next page. The page size is the
-  // width of the scroll view, the contents that are outside of the scroll view
-  // will be clipped and can not be seen.
-  void ScrollToPreviousPage();
-  void ScrollToNextPage();
-
-  // Gets the adjusted scroll position based on |position| to make sure no desk
-  // preview is cropped at the start position of the scrollable bar.
-  int GetAdjustedUncroppedScrollPosition(int position) const;
-
-  void OnLibraryButtonPressed();
-
-  // This function cycles through `mini_views_` and updates the tooltip for each
-  // mini view's combine desks button.
-  void MaybeUpdateCombineDesksTooltips();
-
-  // Scrollview callbacks.
-  void OnContentsScrolled();
-  void OnContentsScrollEnded();
-
   // Observes mouse events on the desk bar widget and updates the states of the
   // mini_views accordingly.
   std::unique_ptr<DeskBarHoverObserver> hover_observer_;
 
-  raw_ptr<ZeroStateDefaultDeskButton, ExperimentalAsh>
-      zero_state_default_desk_button_ = nullptr;
-  raw_ptr<ZeroStateIconButton, ExperimentalAsh> zero_state_new_desk_button_ =
-      nullptr;
-  raw_ptr<ExpandedDesksBarButton, ExperimentalAsh>
-      expanded_state_new_desk_button_ = nullptr;
-
-  // Buttons to show the saved desk grid.
-  raw_ptr<ZeroStateIconButton, ExperimentalAsh> zero_state_library_button_ =
-      nullptr;
-  raw_ptr<ExpandedDesksBarButton, ExperimentalAsh>
-      expanded_state_library_button_ = nullptr;
-
-  // Buttons for the CrOS Next updated UI. They're added behind the feature flag
-  // Jellyroll.
-  // TODO(conniekxu): After CrOS Next is launched, replace
-  // `zero_state_default_desk_button_`, `zero_state_default_desk_button_`,
-  // `expanded_state_new_desk_button_`, `zero_state_library_button_` and
-  // `expanded_state_library_button_` with the buttons below.
-  raw_ptr<CrOSNextDefaultDeskButton, ExperimentalAsh> default_desk_button_ =
-      nullptr;
-  raw_ptr<CrOSNextDeskIconButton, ExperimentalAsh> new_desk_button_ = nullptr;
-  raw_ptr<CrOSNextDeskIconButton, ExperimentalAsh> library_button_ = nullptr;
-
-  // Labels to be shown under the desk icon buttons when they're at the active
-  // state.
-  raw_ptr<views::Label, ExperimentalAsh> new_desk_button_label_ = nullptr;
-  raw_ptr<views::Label, ExperimentalAsh> library_button_label_ = nullptr;
-
-  raw_ptr<ScrollArrowButton, ExperimentalAsh> left_scroll_button_ = nullptr;
-  raw_ptr<ScrollArrowButton, ExperimentalAsh> right_scroll_button_ = nullptr;
   // Drag proxy for the dragged desk.
   std::unique_ptr<DeskDragProxy> drag_proxy_;
-
-  // ScrollView callback subscriptions.
-  base::CallbackListSubscription on_contents_scrolled_subscription_;
-  base::CallbackListSubscription on_contents_scroll_ended_subscription_;
 };
 
 }  // namespace ash
diff --git a/ash/wm/desks/templates/saved_desk_unittest.cc b/ash/wm/desks/templates/saved_desk_unittest.cc
index 04065b1..607c3bca 100644
--- a/ash/wm/desks/templates/saved_desk_unittest.cc
+++ b/ash/wm/desks/templates/saved_desk_unittest.cc
@@ -3486,7 +3486,7 @@
   auto test_window = CreateAppWindow();
 
   WindowState* window_state = WindowState::Get(test_window.get());
-  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   EXPECT_EQ(chromeos::WindowStateType::kPrimarySnapped,
             window_state->GetStateType());
diff --git a/ash/wm/float/float_controller.cc b/ash/wm/float/float_controller.cc
index fbf9f46..6a01874 100644
--- a/ash/wm/float/float_controller.cc
+++ b/ash/wm/float/float_controller.cc
@@ -14,6 +14,7 @@
 #include "ash/public/cpp/window_properties.h"
 #include "ash/rotator/screen_rotation_animator.h"
 #include "ash/scoped_animation_disabler.h"
+#include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/wm/desks/desk.h"
 #include "ash/wm/desks/desks_util.h"
@@ -27,7 +28,6 @@
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_default_layout_manager.h"
 #include "ash/wm/wm_event.h"
-#include "ash/wm/work_area_insets.h"
 #include "ash/wm/workspace/workspace_event_handler.h"
 #include "ash/wm/workspace/workspace_layout_manager.h"
 #include "base/check.h"
@@ -404,9 +404,8 @@
     return window->bounds();
   }
 
-  gfx::Rect work_area = WorkAreaInsets::ForWindow(window->GetRootWindow())
-                            ->user_work_area_bounds();
-  wm::ConvertRectFromScreen(window->GetRootWindow(), &work_area);
+  const gfx::Rect work_area =
+      screen_util::GetDisplayWorkAreaBoundsInParent(window);
 
   const int padding_dp = chromeos::wm::kFloatedWindowPaddingDp;
 
@@ -468,9 +467,8 @@
   }
 #endif
 
-  gfx::Rect work_area = WorkAreaInsets::ForWindow(window->GetRootWindow())
-                            ->user_work_area_bounds();
-  wm::ConvertRectFromScreen(window->GetRootWindow(), &work_area);
+  const gfx::Rect work_area =
+      screen_util::GetDisplayWorkAreaBoundsInParent(window);
 
   // Update the origin of the floated window based on whichever corner it is
   // magnetized to.
diff --git a/ash/wm/float/float_controller_unittest.cc b/ash/wm/float/float_controller_unittest.cc
index e6055b2d..51a6e3c 100644
--- a/ash/wm/float/float_controller_unittest.cc
+++ b/ash/wm/float/float_controller_unittest.cc
@@ -2045,11 +2045,11 @@
 
   // Create two windows and snap one on each side.
   auto left_window = CreateAppWindow();
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(left_window.get())->OnWMEvent(&snap_left);
 
   auto right_window = CreateAppWindow();
-  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   WindowState::Get(right_window.get())->OnWMEvent(&snap_right);
 
   auto* split_view_controller =
@@ -2076,7 +2076,7 @@
 
   // If there are no other windows, expect to enter overview. The hotseat will
   // extended and users can pick a second app from there.
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window.get())->OnWMEvent(&snap_left);
   ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   ASSERT_TRUE(split_view_controller->InSplitViewMode());
@@ -2121,9 +2121,9 @@
   auto* split_view_controller =
       SplitViewController::Get(Shell::GetPrimaryRootWindow());
 
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window_1.get())->OnWMEvent(&snap_left);
-  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   WindowState::Get(window_2.get())->OnWMEvent(&snap_right);
   EXPECT_TRUE(split_view_controller->BothSnapped());
   EXPECT_EQ(split_view_controller->primary_window(), window_1.get());
diff --git a/ash/wm/multi_display/persistent_window_controller_unittest.cc b/ash/wm/multi_display/persistent_window_controller_unittest.cc
index 1c9570a1..b0037f8 100644
--- a/ash/wm/multi_display/persistent_window_controller_unittest.cc
+++ b/ash/wm/multi_display/persistent_window_controller_unittest.cc
@@ -827,7 +827,7 @@
       SplitViewController::Get(Shell::GetPrimaryRootWindow());
 
   // Snap the unique window in clamshell mode will not enter split view mode.
-  WMEvent wm_left_snap_event(WM_EVENT_SNAP_PRIMARY);
+  WindowSnapWMEvent wm_left_snap_event(WM_EVENT_SNAP_PRIMARY);
   auto* window_state = WindowState::Get(w1);
   window_state->OnWMEvent(&wm_left_snap_event);
   EXPECT_FALSE(split_view_controller->InSplitViewMode());
diff --git a/ash/wm/multitask_menu_nudge_controller_unittest.cc b/ash/wm/multitask_menu_nudge_controller_unittest.cc
index 2294fc8..47a598b9 100644
--- a/ash/wm/multitask_menu_nudge_controller_unittest.cc
+++ b/ash/wm/multitask_menu_nudge_controller_unittest.cc
@@ -44,8 +44,8 @@
     return TabletModeControllerTestApi()
         .tablet_mode_window_manager()
         ->tablet_mode_multitask_menu_event_handler()
-        ->multitask_cue_for_testing()
-        ->nudge_controller_for_testing();
+        ->multitask_cue()
+        ->nudge_controller();
   }
 
   if (auto* frame = NonClientFrameViewAsh::Get(window)) {
@@ -165,11 +165,11 @@
   views::NamedWidgetShownWaiter waiter(
       views::test::AnyWidgetTestPasskey{},
       std::string("MultitaskMenuBubbleWidget"));
-  chromeos::FrameSizeButton* size_button =
+  auto* size_button = static_cast<chromeos::FrameSizeButton*>(
       NonClientFrameViewAsh::Get(window.get())
           ->GetHeaderView()
           ->caption_button_container()
-          ->size_button();
+          ->size_button());
   size_button->ShowMultitaskMenu(
       chromeos::MultitaskMenuEntryType::kFrameSizeButtonHover);
   views::WidgetDelegate* delegate =
@@ -178,10 +178,11 @@
       static_cast<chromeos::MultitaskMenu*>(delegate->AsDialogDelegate());
 
   // After floating the window from the multitask menu, there is no crash.
-  GetEventGenerator()->MoveMouseTo(multitask_menu->multitask_menu_view()
-                                       ->float_button_for_testing()
-                                       ->GetBoundsInScreen()
-                                       .CenterPoint());
+  GetEventGenerator()->MoveMouseTo(
+      multitask_menu->multitask_menu_view_for_testing()
+          ->float_button_for_testing()
+          ->GetBoundsInScreen()
+          .CenterPoint());
   GetEventGenerator()->ClickLeftButton();
   EXPECT_TRUE(WindowState::Get(window.get())->IsFloated());
 }
@@ -299,11 +300,11 @@
   views::NamedWidgetShownWaiter waiter(
       views::test::AnyWidgetTestPasskey{},
       std::string("MultitaskMenuBubbleWidget"));
-  chromeos::FrameSizeButton* size_button =
+  auto* size_button = static_cast<chromeos::FrameSizeButton*>(
       NonClientFrameViewAsh::Get(window.get())
           ->GetHeaderView()
           ->caption_button_container()
-          ->size_button();
+          ->size_button());
   size_button->ShowMultitaskMenu(
       chromeos::MultitaskMenuEntryType::kFrameSizeButtonHover);
   waiter.WaitIfNeededAndGet();
diff --git a/ash/wm/overview/overview_metrics.h b/ash/wm/overview/overview_metrics.h
index 014c1f7e..b51b0dc 100644
--- a/ash/wm/overview/overview_metrics.h
+++ b/ash/wm/overview/overview_metrics.h
@@ -21,7 +21,8 @@
   kDevTools,
   kTests,
   kOverviewDeskSwitch,
-  kMaxValue = kOverviewDeskSwitch,
+  kDeskButton,
+  kMaxValue = kDeskButton,
 };
 void RecordOverviewStartAction(OverviewStartAction type);
 
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 64c2ad77..c197d8c 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -5109,7 +5109,7 @@
   EXPECT_EQ(SplitViewController::State::kNoSnap,
             split_view_controller()->state());
   EXPECT_FALSE(InOverviewSession());
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   snapped_window_state->OnWMEvent(&alt_left_square_bracket);
   EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
   EXPECT_EQ(WindowStateType::kPrimarySnapped,
@@ -5130,7 +5130,8 @@
   EXPECT_EQ(SplitViewController::State::kNoSnap,
             split_view_controller()->state());
   EXPECT_FALSE(InOverviewSession());
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
+  const WindowSnapWMEvent alt_right_square_bracket(
+      WM_EVENT_CYCLE_SNAP_SECONDARY);
   snapped_window_state->OnWMEvent(&alt_right_square_bracket);
   EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
   EXPECT_EQ(WindowStateType::kSecondarySnapped,
@@ -5157,10 +5158,11 @@
         EXPECT_FALSE(InOverviewSession());
       };
   expect_unsnappable_window_is_active_and_maximized();
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   unsnappable_window_state->OnWMEvent(&alt_left_square_bracket);
   expect_unsnappable_window_is_active_and_maximized();
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
+  const WindowSnapWMEvent alt_right_square_bracket(
+      WM_EVENT_CYCLE_SNAP_SECONDARY);
   unsnappable_window_state->OnWMEvent(&alt_right_square_bracket);
   expect_unsnappable_window_is_active_and_maximized();
 }
@@ -5174,7 +5176,7 @@
                                         &window1](WMEventType event_type) {
     wm::ActivateWindow(window1.get());
     WindowState* window1_state = WindowState::Get(window1.get());
-    const WMEvent event(event_type);
+    const WindowSnapWMEvent event(event_type);
     window1_state->OnWMEvent(&event);
     EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
     EXPECT_EQ(WindowStateType::kMaximized, window1_state->GetStateType());
@@ -5230,7 +5232,8 @@
   const auto test_left_snapping_window1 = [this, &window1, &window2]() {
     wm::ActivateWindow(window1.get());
     WindowState* window1_state = WindowState::Get(window1.get());
-    const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
+    const WindowSnapWMEvent alt_left_square_bracket(
+        WM_EVENT_CYCLE_SNAP_PRIMARY);
     window1_state->OnWMEvent(&alt_left_square_bracket);
     EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
     EXPECT_EQ(WindowStateType::kPrimarySnapped, window1_state->GetStateType());
@@ -5243,7 +5246,8 @@
   const auto test_right_snapping_window1 = [this, &window1, &window2]() {
     wm::ActivateWindow(window1.get());
     WindowState* window1_state = WindowState::Get(window1.get());
-    const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
+    const WindowSnapWMEvent alt_right_square_bracket(
+        WM_EVENT_CYCLE_SNAP_SECONDARY);
     window1_state->OnWMEvent(&alt_right_square_bracket);
     EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
     EXPECT_EQ(WindowStateType::kSecondarySnapped,
@@ -7319,14 +7323,15 @@
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
   EXPECT_FALSE(InOverviewSession());
   // Alt+[
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   WindowState* window1_state = WindowState::Get(window1.get());
   window1_state->OnWMEvent(&alt_left_square_bracket);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, window1_state->GetStateType());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
   EXPECT_FALSE(InOverviewSession());
   // Alt+]
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
+  const WindowSnapWMEvent alt_right_square_bracket(
+      WM_EVENT_CYCLE_SNAP_SECONDARY);
   window1_state->OnWMEvent(&alt_right_square_bracket);
   EXPECT_EQ(WindowStateType::kSecondarySnapped, window1_state->GetStateType());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
@@ -7346,7 +7351,7 @@
             snapped_window_state->GetStateType());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(InOverviewSession());
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   snapped_window_state->OnWMEvent(&alt_left_square_bracket);
   EXPECT_EQ(WindowStateType::kNormal, snapped_window_state->GetStateType());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
@@ -7366,7 +7371,8 @@
             snapped_window_state->GetStateType());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(InOverviewSession());
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
+  const WindowSnapWMEvent alt_right_square_bracket(
+      WM_EVENT_CYCLE_SNAP_SECONDARY);
   snapped_window_state->OnWMEvent(&alt_right_square_bracket);
   EXPECT_EQ(WindowStateType::kNormal, snapped_window_state->GetStateType());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
@@ -7392,7 +7398,7 @@
   EXPECT_EQ(snapped_window.get(), split_view_controller()->secondary_window());
   EXPECT_TRUE(InOverviewSession());
   // Test using Alt+[ to put |snapped_window| on the left.
-  const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_PRIMARY);
   snapped_window_state->OnWMEvent(&alt_left_square_bracket);
   EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
   EXPECT_EQ(WindowStateType::kPrimarySnapped,
@@ -7402,7 +7408,8 @@
   EXPECT_EQ(snapped_window.get(), split_view_controller()->primary_window());
   EXPECT_TRUE(InOverviewSession());
   // Test using Alt+] to put |snapped_window| on the right.
-  const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_SECONDARY);
+  const WindowSnapWMEvent alt_right_square_bracket(
+      WM_EVENT_CYCLE_SNAP_SECONDARY);
   snapped_window_state->OnWMEvent(&alt_right_square_bracket);
   EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
   EXPECT_EQ(WindowStateType::kSecondarySnapped,
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index 7f87375..c34f2b4 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -738,10 +738,10 @@
     // passed parameters |snap_position_| and |location_in_screen| won't be used
     // in this function for this case, but they are passed in as placeholders.
     aura::Window* window = item_->GetWindow();
-    WindowState::Get(window)->set_snap_action_source(
-        WindowSnapActionSource::kDragOrSelectOverviewWindowToSnap);
     SplitViewController::Get(Shell::GetPrimaryRootWindow())
-        ->OnWindowDragEnded(window, snap_position_, rounded_screen_point);
+        ->OnWindowDragEnded(
+            window, snap_position_, rounded_screen_point,
+            WindowSnapActionSource::kDragOrSelectOverviewWindowToSnap);
 
     // Update window grid bounds and |snap_position_| in case the screen
     // orientation was changed.
@@ -926,8 +926,6 @@
   DCHECK(!SplitViewController::Get(Shell::GetPrimaryRootWindow())
               ->IsDividerAnimating());
   aura::Window* window = item_->GetWindow();
-  WindowState::Get(window)->set_snap_action_source(
-      WindowSnapActionSource::kDragOrSelectOverviewWindowToSnap);
 
   // If `window` is currently fullscreen, snapping it will trigger a work area
   // change, which triggers `OverviewSession::OnDisplayMetricsChanged`. Display
@@ -936,8 +934,10 @@
   // See crbug.com/1330042 for more details. `item_` will be deleted after
   // SplitViewController::SnapWindow().
   item_ = nullptr;
-  split_view_controller->SnapWindow(window, snap_position,
-                                    /*activate_window=*/true);
+  split_view_controller->SnapWindow(
+      window, snap_position,
+      WindowSnapActionSource::kDragOrSelectOverviewWindowToSnap,
+      /*activate_window=*/true);
 }
 
 OverviewGrid* OverviewWindowDragController::GetCurrentGrid() const {
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc
index 03ff145..3844b7f1 100644
--- a/ash/wm/snap_group/snap_group_unittest.cc
+++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -156,10 +156,10 @@
                          chromeos::WindowStateType state_type) {
     UpdateDisplay("800x600");
     WindowState* window_state = WindowState::Get(window);
-    const WMEvent snap_type(state_type ==
-                                    chromeos::WindowStateType::kPrimarySnapped
-                                ? WM_EVENT_SNAP_PRIMARY
-                                : WM_EVENT_SNAP_SECONDARY);
+    const WindowSnapWMEvent snap_type(
+        state_type == chromeos::WindowStateType::kPrimarySnapped
+            ? WM_EVENT_SNAP_PRIMARY
+            : WM_EVENT_SNAP_SECONDARY);
     window_state->OnWMEvent(&snap_type);
     EXPECT_EQ(state_type, window_state->GetStateType());
   }
@@ -921,13 +921,13 @@
     UpdateDisplay("800x700");
 
     WindowState* primary_window_state = WindowState::Get(primary_window);
-    const WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+    const WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
     primary_window_state->OnWMEvent(&snap_primary);
     EXPECT_EQ(chromeos::WindowStateType::kPrimarySnapped,
               primary_window_state->GetStateType());
 
     WindowState* secondary_window_state = WindowState::Get(secondary_window);
-    const WMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+    const WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
     secondary_window_state->OnWMEvent(&snap_secondary);
     EXPECT_EQ(chromeos::WindowStateType::kSecondarySnapped,
               secondary_window_state->GetStateType());
@@ -1009,4 +1009,4 @@
   EXPECT_TRUE(IsStackedBelow(w3.get(), w2.get()));
 }
 
-}  // namespace ash
\ No newline at end of file
+}  // namespace ash
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index c7fa46d..7ead481 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -275,8 +275,9 @@
   CHECK(event_type == WM_EVENT_SNAP_PRIMARY ||
         event_type == WM_EVENT_SNAP_SECONDARY);
 
-  const WMEvent window_event(event_type, window_state->snap_ratio().value_or(
-                                             chromeos::kDefaultSnapRatio));
+  const WindowSnapWMEvent window_event(
+      event_type,
+      window_state->snap_ratio().value_or(chromeos::kDefaultSnapRatio));
   window_state->OnWMEvent(&window_event);
 }
 
@@ -554,13 +555,13 @@
 
     // Snap the window on the non-default side of the screen if split view mode
     // is active.
-    WindowState::Get(window)->set_snap_action_source(
-        WindowSnapActionSource::kAutoSnapBySplitview);
     split_view_controller_->SnapWindow(
-        window, (split_view_controller_->default_snap_position() ==
-                 SnapPosition::kPrimary)
-                    ? SnapPosition::kSecondary
-                    : SnapPosition::kPrimary);
+        window,
+        (split_view_controller_->default_snap_position() ==
+         SnapPosition::kPrimary)
+            ? SnapPosition::kSecondary
+            : SnapPosition::kPrimary,
+        WindowSnapActionSource::kAutoSnapInSplitView);
   }
 
   void AddWindow(aura::Window* window) {
@@ -843,6 +844,7 @@
 
 void SplitViewController::SnapWindow(aura::Window* window,
                                      SnapPosition snap_position,
+                                     WindowSnapActionSource snap_action_source,
                                      bool activate_window,
                                      float snap_ratio) {
   DCHECK(window && CanSnapWindow(window));
@@ -866,10 +868,10 @@
                                          ->GetDisplayNearestWindow(root_window_)
                                          .id());
   }
-  const WMEvent event(snap_position == SnapPosition::kPrimary
-                          ? WM_EVENT_SNAP_PRIMARY
-                          : WM_EVENT_SNAP_SECONDARY,
-                      snap_ratio);
+  const WindowSnapWMEvent event(snap_position == SnapPosition::kPrimary
+                                    ? WM_EVENT_SNAP_PRIMARY
+                                    : WM_EVENT_SNAP_SECONDARY,
+                                snap_ratio, snap_action_source);
   WindowState::Get(window)->OnWMEvent(&event);
 
   base::RecordAction(base::UserMetricsAction("SplitView_SnapWindow"));
@@ -877,8 +879,8 @@
 
 void SplitViewController::OnWMEvent(aura::Window* window,
                                     WMEventType event_type) {
-  DCHECK(event_type == WM_EVENT_SNAP_PRIMARY ||
-         event_type == WM_EVENT_SNAP_SECONDARY);
+  CHECK(event_type == WM_EVENT_SNAP_PRIMARY ||
+        event_type == WM_EVENT_SNAP_SECONDARY);
 
   // If split view can't be enabled at the moment, do nothing.
   if (!ShouldAllowSplitView())
@@ -1605,10 +1607,8 @@
       OverviewStartAction::kOverviewButtonLongPress,
       OverviewEnterExitType::kImmediateEnter);
 
-  WindowState::Get(target_window)
-      ->set_snap_action_source(
-          WindowSnapActionSource::kLongPressOverviewButtonToSnap);
   SnapWindow(target_window, SnapPosition::kPrimary,
+             WindowSnapActionSource::kLongPressOverviewButtonToSnap,
              /*activate_window=*/true);
   base::RecordAction(
       base::UserMetricsAction("Tablet_LongPressOverviewButtonEnterSplitView"));
@@ -1631,10 +1631,12 @@
 void SplitViewController::OnWindowDragEnded(
     aura::Window* dragged_window,
     SnapPosition desired_snap_position,
-    const gfx::Point& last_location_in_screen) {
+    const gfx::Point& last_location_in_screen,
+    WindowSnapActionSource snap_action_source) {
   DCHECK(!window_util::IsDraggingTabs(dragged_window));
   EndWindowDragImpl(dragged_window, dragged_window->is_destroying(),
-                    desired_snap_position, last_location_in_screen);
+                    desired_snap_position, last_location_in_screen,
+                    snap_action_source);
 }
 
 void SplitViewController::OnWindowDragCanceled() {
@@ -1972,11 +1974,11 @@
       overview_item->RestoreWindow(/*reset_transform=*/false);
       overview_session->RemoveItem(overview_item.get());
 
-      WindowState::Get(window)->set_snap_action_source(
-          WindowSnapActionSource::kAutoSnapBySplitview);
-      SnapWindow(window, (default_snap_position_ == SnapPosition::kPrimary)
-                             ? SnapPosition::kSecondary
-                             : SnapPosition::kPrimary);
+      SnapWindow(window,
+                 (default_snap_position_ == SnapPosition::kPrimary)
+                     ? SnapPosition::kSecondary
+                     : SnapPosition::kPrimary,
+                 WindowSnapActionSource::kAutoSnapInSplitView);
       // If ending overview causes a window to snap, also do not do exiting
       // overview animation.
       overview_session->SetWindowListNotAnimatedWhenExiting(root_window_);
@@ -2677,9 +2679,10 @@
             GetPositionOfSnappedWindow(window) == SnapPosition::kPrimary
                 ? SnapPosition::kSecondary
                 : SnapPosition::kPrimary;
-        WMEvent event(snap_position == SnapPosition::kPrimary
-                          ? WM_EVENT_SNAP_PRIMARY
-                          : WM_EVENT_SNAP_SECONDARY);
+        WindowSnapWMEvent event(snap_position == SnapPosition::kPrimary
+                                    ? WM_EVENT_SNAP_PRIMARY
+                                    : WM_EVENT_SNAP_SECONDARY,
+                                WindowSnapActionSource::kAutoSnapInSplitView);
         WindowState::Get(mru_window)->OnWMEvent(&event);
         return;
       }
@@ -3051,7 +3054,8 @@
     aura::Window* window,
     bool is_being_destroyed,
     SnapPosition desired_snap_position,
-    const gfx::Point& last_location_in_screen) {
+    const gfx::Point& last_location_in_screen,
+    WindowSnapActionSource snap_action_source) {
   if (split_view_divider_)
     split_view_divider_->OnWindowDragEnded();
 
@@ -3081,6 +3085,7 @@
       // location. Note if there is already a window at |desired_snap_postion|,
       // SnapWindow() will put the previous snapped window in overview.
       SnapWindow(window, ComputeSnapPosition(last_location_in_screen),
+                 snap_action_source,
                  /*activate_window=*/true);
     } else {
       // Restore the dragged window's transform first if it's not identity. It
@@ -3114,7 +3119,8 @@
   } else {
     // Note SnapWindow() might put the previous window that was snapped at the
     // |desired_snap_position| in overview.
-    SnapWindow(window, desired_snap_position, /*activate_window=*/true);
+    SnapWindow(window, desired_snap_position, snap_action_source,
+               /*activate_window=*/true);
   }
 }
 
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index bb00bbce..a43da49 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -19,6 +19,7 @@
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state_observer.h"
 #include "ash/wm/wm_event.h"
+#include "ash/wm/wm_metrics.h"
 #include "base/containers/flat_map.h"
 #include "base/memory/raw_ptr.h"
 #include "base/observer_list.h"
@@ -237,6 +238,8 @@
   // transition.
   void SnapWindow(aura::Window* window,
                   SnapPosition snap_position,
+                  WindowSnapActionSource snap_action_source =
+                      WindowSnapActionSource::kNotSpecified,
                   bool activate_window = false,
                   float snap_ratio = chromeos::kDefaultSnapRatio);
 
@@ -356,7 +359,8 @@
   void OnWindowDragStarted(aura::Window* dragged_window);
   void OnWindowDragEnded(aura::Window* dragged_window,
                          SnapPosition desired_snap_position,
-                         const gfx::Point& last_location_in_screen);
+                         const gfx::Point& last_location_in_screen,
+                         WindowSnapActionSource snap_action_source);
   void OnWindowDragCanceled();
 
   // Computes the snap position for a dragged window, based on the last
@@ -612,7 +616,8 @@
   void EndWindowDragImpl(aura::Window* window,
                          bool is_being_destroyed,
                          SnapPosition desired_snap_position,
-                         const gfx::Point& last_location_in_screen);
+                         const gfx::Point& last_location_in_screen,
+                         WindowSnapActionSource snap_action_source);
 
   // Do the split divider spawn animation. It will add a finishing touch to the
   // |window| animation that generally accommodates snapping by dragging.
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index 6bca4f5..5d79b6f 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -3140,7 +3140,7 @@
 
   // Test the functionalities in tablet mode.
   // Sending WM_EVENT_SNAP_SECONDARY to |window1| will snap to left.
-  WMEvent wm_left_snap_event(WM_EVENT_SNAP_PRIMARY);
+  WindowSnapWMEvent wm_left_snap_event(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window1.get())->OnWMEvent(&wm_left_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_EQ(split_view_controller()->primary_window(), window1.get());
@@ -3151,7 +3151,7 @@
   EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get()));
 
   // Sending WM_EVENT_SNAP_SECONDARY to |window1| will snap to right.
-  WMEvent wm_right_snap_event(WM_EVENT_SNAP_SECONDARY);
+  WindowSnapWMEvent wm_right_snap_event(WM_EVENT_SNAP_SECONDARY);
   WindowState::Get(window1.get())->OnWMEvent(&wm_right_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_EQ(split_view_controller()->secondary_window(), window1.get());
@@ -3254,9 +3254,9 @@
 
   // Snap `window1` to primary position and `window2` to secondary position,
   // both with default snap ratios.
-  WMEvent snap_primary_default(WM_EVENT_SNAP_PRIMARY);
+  WindowSnapWMEvent snap_primary_default(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window1.get())->OnWMEvent(&snap_primary_default);
-  WMEvent snap_secondary_default(WM_EVENT_SNAP_SECONDARY);
+  WindowSnapWMEvent snap_secondary_default(WM_EVENT_SNAP_SECONDARY);
   WindowState::Get(window2.get())->OnWMEvent(&snap_secondary_default);
 
   // Test that both window bounds are at half the work area width and that the
@@ -3278,8 +3278,8 @@
             window2->bounds().width() + divider_delta);
 
   // Snap `window1`, still in primary position, but with two thirds snap ratio.
-  WMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
-                                 chromeos::kTwoThirdSnapRatio);
+  WindowSnapWMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
+                                           chromeos::kTwoThirdSnapRatio);
   WindowState::Get(window1.get())->OnWMEvent(&snap_primary_two_third);
 
   // Test that the window bounds have updated to two thirds and one third of the
@@ -3305,11 +3305,11 @@
 
   // Snap `window1` to primary with 2/3 width and `window2` to secondary with
   // 1/3 width. Verify the divider is at 2/3 of the work area.
-  WMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
-                                 chromeos::kTwoThirdSnapRatio);
+  WindowSnapWMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
+                                           chromeos::kTwoThirdSnapRatio);
   WindowState::Get(window1.get())->OnWMEvent(&snap_primary_two_third);
-  WMEvent snap_secondary_one_third(WM_EVENT_SNAP_SECONDARY,
-                                   chromeos::kOneThirdSnapRatio);
+  WindowSnapWMEvent snap_secondary_one_third(WM_EVENT_SNAP_SECONDARY,
+                                             chromeos::kOneThirdSnapRatio);
   WindowState::Get(window2.get())->OnWMEvent(&snap_secondary_one_third);
   const gfx::Rect work_area_bounds =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
@@ -3366,7 +3366,8 @@
   window->SetProperty(aura::client::kAppType,
                       static_cast<int>(AppType::BROWSER));
 
-  WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY, chromeos::kTwoThirdSnapRatio);
+  WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY,
+                                 chromeos::kTwoThirdSnapRatio);
   WindowState::Get(window.get())->OnWMEvent(&snap_primary);
   EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped());
 }
@@ -3394,8 +3395,8 @@
 
   // Snap `window1` to 2/3. Since `window2` can't fit in 1/3, test that we open
   // Overview instead.
-  WMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
-                                 chromeos::kTwoThirdSnapRatio);
+  WindowSnapWMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
+                                           chromeos::kTwoThirdSnapRatio);
   WindowState::Get(window1.get())->OnWMEvent(&snap_primary_two_third);
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::State::kPrimarySnapped);
@@ -3420,8 +3421,8 @@
   std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
 
   // 1. Test without min size. Snap `window1` to 2/3.
-  WMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
-                                 chromeos::kTwoThirdSnapRatio);
+  WindowSnapWMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
+                                           chromeos::kTwoThirdSnapRatio);
   WindowState::Get(window1.get())->OnWMEvent(&snap_primary_two_third);
   // Activate `window2`. Test that `window2` gets auto-snapped to 1/3.
   wm::ActivateWindow(window2.get());
@@ -3567,7 +3568,7 @@
 
   // 1. Test landscape orientation.
   // Snap |window1| to the left to enter split view overview in tablet mode.
-  WMEvent wm_left_snap_event(WM_EVENT_SNAP_PRIMARY);
+  WindowSnapWMEvent wm_left_snap_event(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window1.get())->OnWMEvent(&wm_left_snap_event);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   OverviewController* overview_controller = Shell::Get()->overview_controller();
@@ -3610,8 +3611,8 @@
   wm::ActivateWindow(window1.get());
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
 
-  const WMEvent wm_left_snap_event(WM_EVENT_SNAP_PRIMARY);
-  const WMEvent wm_right_snap_event(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent wm_left_snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent wm_right_snap_event(WM_EVENT_SNAP_SECONDARY);
   const WMEvent fullscreen_event(WM_EVENT_TOGGLE_FULLSCREEN);
 
   // 1. Test portrait orientation.
diff --git a/ash/wm/splitview/split_view_divider_handler_view.cc b/ash/wm/splitview/split_view_divider_handler_view.cc
index 2c1c68b..69898d5c 100644
--- a/ash/wm/splitview/split_view_divider_handler_view.cc
+++ b/ash/wm/splitview/split_view_divider_handler_view.cc
@@ -6,11 +6,14 @@
 
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/shell.h"
-#include "ash/style/ash_color_provider.h"
+#include "ash/style/ash_color_id.h"
 #include "ash/wm/splitview/split_view_constants.h"
 #include "ash/wm/splitview/split_view_utils.h"
 #include "base/memory/raw_ptr.h"
 #include "base/timer/timer.h"
+#include "chromeos/constants/chromeos_features.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/color/color_id.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/animation/slide_animation.h"
@@ -18,15 +21,6 @@
 
 namespace ash {
 
-namespace {
-
-SkColor GetBackgroundColor() {
-  return AshColorProvider::Get()->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kIconColorPrimary);
-}
-
-}  // namespace
-
 class SplitViewDividerHandlerView::SelectionAnimation
     : public gfx::SlideAnimation,
       public gfx::AnimationDelegate {
@@ -123,8 +117,11 @@
 SplitViewDividerHandlerView::SplitViewDividerHandlerView()
     : selection_animation_(std::make_unique<SelectionAnimation>(this)) {
   SetPaintToLayer();
-  SetBackground(views::CreateRoundedRectBackground(
-      GetBackgroundColor(), kSplitviewWhiteBarCornerRadius));
+  SetBackground(views::CreateThemedRoundedRectBackground(
+      chromeos::features::IsJellyrollEnabled()
+          ? static_cast<ui::ColorId>(cros_tokens::kCrosSysOnSurface)
+          : kColorAshIconColorPrimary,
+      kSplitviewWhiteBarCornerRadius));
 }
 
 SplitViewDividerHandlerView::~SplitViewDividerHandlerView() = default;
@@ -170,10 +167,4 @@
   views::View::OnPaint(canvas);
 }
 
-void SplitViewDividerHandlerView::OnThemeChanged() {
-  views::View::OnThemeChanged();
-  background()->SetNativeControlColor(GetBackgroundColor());
-  SchedulePaint();
-}
-
 }  // namespace ash
diff --git a/ash/wm/splitview/split_view_divider_handler_view.h b/ash/wm/splitview/split_view_divider_handler_view.h
index 89c37ee..eeff56e 100644
--- a/ash/wm/splitview/split_view_divider_handler_view.h
+++ b/ash/wm/splitview/split_view_divider_handler_view.h
@@ -49,7 +49,6 @@
 
   // views::View:
   void OnPaint(gfx::Canvas* canvas) override;
-  void OnThemeChanged() override;
 
   // Handles the animations for starting and ending dragging.
   std::unique_ptr<SelectionAnimation> selection_animation_;
diff --git a/ash/wm/splitview/split_view_divider_view.cc b/ash/wm/splitview/split_view_divider_view.cc
index 95a7b076..02a203f 100644
--- a/ash/wm/splitview/split_view_divider_view.cc
+++ b/ash/wm/splitview/split_view_divider_view.cc
@@ -10,7 +10,7 @@
 #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/ash_color_id.h"
 #include "ash/system/screen_layout_observer.h"
 #include "ash/wm/snap_group/snap_group.h"
 #include "ash/wm/snap_group/snap_group_controller.h"
@@ -20,7 +20,9 @@
 #include "ash/wm/splitview/split_view_divider.h"
 #include "ash/wm/splitview/split_view_divider_handler_view.h"
 #include "ash/wm/splitview/split_view_utils.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/gfx/geometry/rect.h"
@@ -56,9 +58,18 @@
 
   SetPaintToLayer(ui::LAYER_TEXTURED);
   layer()->SetFillsBoundsOpaquely(false);
-  SetBackground(
-      views::CreateSolidBackground(AshColorProvider::Get()->GetBaseLayerColor(
-          AshColorProvider::BaseLayerType::kOpaque)));
+
+  const bool is_jellyroll_enabled = chromeos::features::IsJellyrollEnabled();
+
+  SetBackground(views::CreateThemedSolidBackground(
+      is_jellyroll_enabled
+          ? static_cast<ui::ColorId>(cros_tokens::kCrosSysSystemBaseElevated)
+          : kColorAshShieldAndBaseOpaque));
+  SetBorder(std::make_unique<views::HighlightBorder>(
+      /*corner_radius=*/0,
+      is_jellyroll_enabled
+          ? views::HighlightBorder::Type::kHighlightBorderNoShadow
+          : views::HighlightBorder::Type::kHighlightBorder1));
 
   if (IsSnapGroupEnabledInClamshellMode()) {
     kebab_button_ = AddChildView(std::make_unique<IconButton>(
@@ -131,17 +142,6 @@
   }
 }
 
-void SplitViewDividerView::OnThemeChanged() {
-  views::View::OnThemeChanged();
-
-  background()->SetNativeControlColor(
-      AshColorProvider::Get()->GetBaseLayerColor(
-          AshColorProvider::BaseLayerType::kOpaque));
-
-  SetBorder(std::make_unique<views::HighlightBorder>(
-      /*corner_radius=*/0, views::HighlightBorder::Type::kHighlightBorder1));
-}
-
 bool SplitViewDividerView::OnMousePressed(const ui::MouseEvent& event) {
   gfx::Point location(event.location());
   views::View::ConvertPointToScreen(this, &location);
diff --git a/ash/wm/splitview/split_view_divider_view.h b/ash/wm/splitview/split_view_divider_view.h
index 76f4477..2496441 100644
--- a/ash/wm/splitview/split_view_divider_view.h
+++ b/ash/wm/splitview/split_view_divider_view.h
@@ -35,7 +35,6 @@
 
   // views::View:
   void Layout() override;
-  void OnThemeChanged() override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   bool OnMouseDragged(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc
index dfd85e7..ac55c67 100644
--- a/ash/wm/splitview/split_view_utils.cc
+++ b/ash/wm/splitview/split_view_utils.cc
@@ -347,14 +347,16 @@
         case WindowStateType::kPrimarySnapped:
           if (!split_view_controller->primary_window()) {
             split_view_controller->SnapWindow(
-                window, SplitViewController::SnapPosition::kPrimary);
+                window, SplitViewController::SnapPosition::kPrimary,
+                WindowSnapActionSource::kSnapByDeskOrSessionChange);
           }
           break;
 
         case WindowStateType::kSecondarySnapped:
           if (!split_view_controller->secondary_window()) {
             split_view_controller->SnapWindow(
-                window, SplitViewController::SnapPosition::kSecondary);
+                window, SplitViewController::SnapPosition::kSecondary,
+                WindowSnapActionSource::kSnapByDeskOrSessionChange);
           }
           break;
 
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index 2236b269..66804d3 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -209,7 +209,7 @@
   std::unique_ptr<aura::Window> CreateDesktopWindowSnappedLeft(
       const gfx::Rect& bounds = gfx::Rect()) {
     std::unique_ptr<aura::Window> window = CreateTestWindow(bounds);
-    WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
+    WindowSnapWMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
     WindowState::Get(window.get())->OnWMEvent(&snap_to_left);
     return window;
   }
@@ -218,7 +218,7 @@
   std::unique_ptr<aura::Window> CreateDesktopWindowSnappedRight(
       const gfx::Rect& bounds = gfx::Rect()) {
     std::unique_ptr<aura::Window> window = CreateTestWindow(bounds);
-    WMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_SECONDARY);
+    WindowSnapWMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_SECONDARY);
     WindowState::Get(window.get())->OnWMEvent(&snap_to_right);
     return window;
   }
@@ -1363,7 +1363,7 @@
   WindowState* left_window_state = WindowState::Get(left_window.get());
   ASSERT_TRUE(left_window_state->CanSnap());
   ASSERT_FALSE(split_view_controller()->CanSnapWindow(left_window.get()));
-  WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  WindowSnapWMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
   left_window_state->OnWMEvent(&snap_to_left);
   std::unique_ptr<aura::Window> right_window =
       CreateDesktopWindowSnappedRight();
@@ -1393,7 +1393,7 @@
   WindowState* right_window_state = WindowState::Get(right_window.get());
   ASSERT_TRUE(right_window_state->CanSnap());
   ASSERT_FALSE(split_view_controller()->CanSnapWindow(right_window.get()));
-  WMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_SECONDARY);
+  WindowSnapWMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_SECONDARY);
   right_window_state->OnWMEvent(&snap_to_right);
   wm::ActivateWindow(right_window.get());
   tablet_mode_controller()->SetEnabledForTest(true);
@@ -1422,7 +1422,7 @@
   WindowState* right_window_state = WindowState::Get(right_window.get());
   ASSERT_TRUE(right_window_state->CanSnap());
   ASSERT_FALSE(split_view_controller()->CanSnapWindow(right_window.get()));
-  WMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_SECONDARY);
+  WindowSnapWMEvent snap_to_right(WM_EVENT_CYCLE_SNAP_SECONDARY);
   right_window_state->OnWMEvent(&snap_to_right);
   ASSERT_EQ(left_window.get(), window_util::GetActiveWindow());
   tablet_mode_controller()->SetEnabledForTest(true);
@@ -1450,7 +1450,7 @@
   WindowState* left_window_state = WindowState::Get(left_window.get());
   ASSERT_TRUE(left_window_state->CanSnap());
   ASSERT_FALSE(split_view_controller()->CanSnapWindow(left_window.get()));
-  WMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  WindowSnapWMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
   left_window_state->OnWMEvent(&snap_to_left);
   std::unique_ptr<aura::Window> right_window =
       CreateDesktopWindowSnappedRight();
@@ -1743,7 +1743,7 @@
   EXPECT_TRUE(window_state->CanSnap());
 
   // Snap the window and check that `ShouldAutoHideTitlebars()` is true.
-  WMEvent snap_to_left(WM_EVENT_SNAP_PRIMARY);
+  WindowSnapWMEvent snap_to_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_to_left);
   EXPECT_TRUE(window_state->IsSnapped());
   EXPECT_TRUE(Shell::Get()->tablet_mode_controller()->ShouldAutoHideTitlebars(
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_cue.cc b/ash/wm/tablet_mode/tablet_mode_multitask_cue.cc
index f46044aa..985d16f 100644
--- a/ash/wm/tablet_mode/tablet_mode_multitask_cue.cc
+++ b/ash/wm/tablet_mode/tablet_mode_multitask_cue.cc
@@ -28,6 +28,7 @@
 // Cue timing values.
 constexpr base::TimeDelta kCueDismissTimeout = base::Seconds(6);
 constexpr base::TimeDelta kFadeDuration = base::Milliseconds(100);
+constexpr base::TimeDelta kCueResetDuration = base::Milliseconds(250);
 
 constexpr SkColor kCueColor = SK_ColorGRAY;
 
@@ -52,9 +53,7 @@
 void TabletModeMultitaskCue::MaybeShowCue(aura::Window* active_window) {
   DCHECK(active_window);
 
-  // Only show or dismiss the cue when activating app windows.
-  if (static_cast<AppType>(active_window->GetProperty(
-          aura::client::kAppType)) == AppType::NON_APP) {
+  if (!CanShowCue(active_window)) {
     return;
   }
 
@@ -102,7 +101,22 @@
   nudge_controller_.MaybeShowNudge(window_);
 }
 
-void TabletModeMultitaskCue::DismissCue(bool menu_opened) {
+bool TabletModeMultitaskCue::CanShowCue(aura::Window* window) const {
+  // Only show or dismiss the cue when activating app windows.
+  if (static_cast<AppType>(window->GetProperty(aura::client::kAppType)) ==
+      AppType::NON_APP) {
+    return false;
+  }
+
+  // Should not refresh cue if `window_` is reactivated.
+  if (window == window_) {
+    return false;
+  }
+
+  return true;
+}
+
+void TabletModeMultitaskCue::DismissCue() {
   cue_dismiss_timer_.Stop();
   window_observation_.Reset();
 
@@ -112,14 +126,19 @@
   }
 
   cue_layer_.reset();
+  nudge_controller_.DismissNudge();
+}
 
-  // If we want to dismiss the cue because the menu was opened, let the nudge
-  // know, so we don't show it anymore. Otherwise, just dismiss it.
-  if (menu_opened) {
-    nudge_controller_.OnMenuOpened(/*tablet_mode=*/true);
-  } else {
-    nudge_controller_.DismissNudge();
+void TabletModeMultitaskCue::ResetPosition() {
+  if (!cue_layer_) {
+    return;
   }
+
+  views::AnimationBuilder()
+      .Once()
+      .SetDuration(kCueResetDuration)
+      .SetTransform(cue_layer_.get(), gfx::Transform(),
+                    gfx::Tween::ACCEL_20_DECEL_100);
 }
 
 void TabletModeMultitaskCue::OnWindowDestroying(aura::Window* window) {
@@ -152,8 +171,12 @@
   // TODO(b/263519133): Stop the cue from reappearing after using non-app
   // windows like popups.
 
-  // The cue should not reappear when tapping off of the menu or selecting a
-  // new layout.
+  // The cue should not reappear when tapping off of the menu onto `window_`
+  // or selecting a new layout. In the case where the menu is open, the cue is
+  // active, and we tap onto another window (e.g., split view), we still want to
+  // show the cue on the new window.
+  // TODO(hewer): Fix this so the cue does not appear when the menu is dismissed
+  // by swiping up or not dragging far enough.
   if (event_handler->multitask_menu() &&
       event_handler->multitask_menu()->widget()->GetNativeWindow() ==
           lost_active) {
@@ -194,7 +217,7 @@
       .SetPreemptionStrategy(
           ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
       .OnEnded(base::BindOnce(&TabletModeMultitaskCue::DismissCue,
-                              base::Unretained(this), /*menu_opened=*/false))
+                              base::Unretained(this)))
       .Once()
       .SetDuration(kFadeDuration)
       .SetOpacity(cue_layer_.get(), 0.0f, gfx::Tween::LINEAR);
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_cue.h b/ash/wm/tablet_mode/tablet_mode_multitask_cue.h
index 1b0ac4b..e69df5e 100644
--- a/ash/wm/tablet_mode/tablet_mode_multitask_cue.h
+++ b/ash/wm/tablet_mode/tablet_mode_multitask_cue.h
@@ -21,6 +21,8 @@
 
 // Creates a cue (draggable bar) at the top center of an app window when it is
 // activated in tablet mode. Only one cue exists at a time.
+// TODO(b/279220838): Rename to TabletModeMultitaskCueController for better
+// clarity.
 class ASH_EXPORT TabletModeMultitaskCue : aura::WindowObserver,
                                           wm::ActivationChangeObserver,
                                           WindowStateObserver {
@@ -36,16 +38,26 @@
   ~TabletModeMultitaskCue() override;
 
   ui::Layer* cue_layer() { return cue_layer_.get(); }
+  chromeos::MultitaskMenuNudgeController* nudge_controller() {
+    return &nudge_controller_;
+  }
 
   // Shows the cue if `active_window` is an maximizable app window that is not
   // floated. Also sets a `OneShotTimer` to dismiss the cue after a short
   // duration.
   void MaybeShowCue(aura::Window* active_window);
 
+  // Returns false if the cue cannot be shown on `window` (e.g., non-app
+  // windows), and true otherwise.
+  bool CanShowCue(aura::Window* window) const;
+
   // Dismisses the cue from the screen and cleans up the pointers and
-  // observers related to its parent window. `menu_opened` is true if we want to
-  // dismiss the cue because the tablet multitask menu has been opened.
-  void DismissCue(bool menu_opened = false);
+  // observers related to its parent window.
+  void DismissCue();
+
+  // Resets the position of the cue back to the top of `window_` if the cue is
+  // still visible.
+  void ResetPosition();
 
   // aura::WindowObserver:
   void OnWindowDestroying(aura::Window* window) override;
@@ -63,9 +75,6 @@
   void OnPostWindowStateTypeChange(WindowState* window_state,
                                    chromeos::WindowStateType old_type) override;
 
-  chromeos::MultitaskMenuNudgeController* nudge_controller_for_testing() {
-    return &nudge_controller_;
-  }
   void FireCueDismissTimerForTesting() { cue_dismiss_timer_.FireNow(); }
 
  private:
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_cue_unittest.cc b/ash/wm/tablet_mode/tablet_mode_multitask_cue_unittest.cc
index a9dc39f1..e2faad7 100644
--- a/ash/wm/tablet_mode/tablet_mode_multitask_cue_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_multitask_cue_unittest.cc
@@ -37,7 +37,7 @@
     return TabletModeControllerTestApi()
         .tablet_mode_window_manager()
         ->tablet_mode_multitask_menu_event_handler()
-        ->multitask_cue_for_testing();
+        ->multitask_cue();
   }
 
   // AshTestBase:
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc b/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc
index 250de65..a97d2343 100644
--- a/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc
+++ b/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc
@@ -10,14 +10,12 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/screen_util.h"
-#include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ash/style/ash_color_id.h"
 #include "ash/style/system_shadow.h"
 #include "ash/wm/splitview/split_view_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_multitask_cue.h"
 #include "ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.h"
 #include "ash/wm/window_state.h"
-#include "base/functional/bind.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/frame/multitask_menu/multitask_menu_metrics.h"
 #include "chromeos/ui/frame/multitask_menu/multitask_menu_view.h"
@@ -30,7 +28,7 @@
 #include "ui/views/animation/animation_builder.h"
 #include "ui/views/background.h"
 #include "ui/views/highlight_border.h"
-#include "ui/views/layout/table_layout.h"
+#include "ui/views/layout/box_layout.h"
 
 namespace ash {
 
@@ -44,15 +42,13 @@
 constexpr int kShadowOutset = 12;
 
 // Menu layout values.
+constexpr int kBetweenButtonSpacing = 12;
 constexpr int kCornerRadius = 8;
-// Padding between the edges of the menu and the elements.
-constexpr int kPaddingWide = 12;
-// Padding between each column of elements.
-constexpr int kPaddingNarrow = 6;
+constexpr gfx::Insets kInsideBorderInsets(16);
 
-// Dogfood feedback button layout values.
-constexpr int kButtonWidth = 120;
-constexpr int kButtonHeight = 28;
+// The distance from the bottom of the multitask menu to the cue.
+// TODO(b/277972192): Update this value to match spec.
+constexpr int kCueOffset = 4;
 
 // Menu animation values.
 constexpr base::TimeDelta kPositionAnimationDurationMs =
@@ -109,12 +105,6 @@
         AddChildView(std::make_unique<chromeos::MultitaskMenuView>(
             window, std::move(callback), buttons, /*anchor_view=*/nullptr));
 
-    // base::Unretained() is safe since `this` also destroys `menu_view_base_`
-    // and its child `feedback_button_`.
-    menu_view_base_->feedback_button()->SetCallback(base::BindRepeating(
-        &TabletModeMultitaskMenuView::ShowFeedbackPageForMenu,
-        base::Unretained(this)));
-
     if (menu_view_base_->partial_button() &&
         !split_view_controller->CanSnapWindow(window,
                                               chromeos::kOneThirdSnapRatio)) {
@@ -126,45 +116,14 @@
           false);
     }
 
-    auto* layout = menu_view_base_->SetLayoutManager(
-        std::make_unique<views::TableLayout>());
-    layout->AddPaddingColumn(views::TableLayout::kFixedSize, kPaddingWide)
-        .AddColumn(views::LayoutAlignment::kCenter,
-                   views::LayoutAlignment::kCenter,
-                   views::TableLayout::kFixedSize,
-                   views::TableLayout::ColumnSize::kUsePreferred, 0, 0)
-        .AddPaddingColumn(views::TableLayout::kFixedSize, kPaddingNarrow)
-        .AddColumn(views::LayoutAlignment::kCenter,
-                   views::LayoutAlignment::kCenter,
-                   views::TableLayout::kFixedSize,
-                   views::TableLayout::ColumnSize::kUsePreferred, 0, 0)
-        .AddPaddingColumn(views::TableLayout::kFixedSize, kPaddingNarrow)
-        .AddColumn(views::LayoutAlignment::kCenter,
-                   views::LayoutAlignment::kCenter,
-                   views::TableLayout::kFixedSize,
-                   views::TableLayout::ColumnSize::kUsePreferred, 0, 0)
-        .AddPaddingColumn(views::TableLayout::kFixedSize, kPaddingNarrow)
-        .AddColumn(views::LayoutAlignment::kCenter,
-                   views::LayoutAlignment::kCenter,
-                   views::TableLayout::kFixedSize,
-                   views::TableLayout::ColumnSize::kUsePreferred, 0, 0)
-        .AddPaddingColumn(views::TableLayout::kFixedSize, kPaddingWide)
-        .AddPaddingRow(views::TableLayout::kFixedSize, kPaddingWide)
-        .AddRows(1, views::TableLayout::kFixedSize, 0)
-        .AddPaddingRow(views::TableLayout::kFixedSize, kPaddingWide)
-        .AddRows(1, views::TableLayout::kFixedSize, kButtonHeight)
-        .AddPaddingRow(views::TableLayout::kFixedSize, kPaddingWide);
-
-    // Feedback button should be ignored by the layout, as otherwise it will be
-    // counted as an element in the table and forced to the second row,
-    // first column.
-    layout->SetChildViewIgnoredByLayout(menu_view_base_->feedback_button(),
-                                        true);
-    auto pref_size = menu_view_base_->GetPreferredSize();
-    menu_view_base_->feedback_button()->SetBounds(
-        (pref_size.width() - kButtonWidth) / 2,
-        pref_size.height() - kButtonHeight - kPaddingWide, kButtonWidth,
-        kButtonHeight);
+    auto* layout =
+        menu_view_base_->SetLayoutManager(std::make_unique<views::BoxLayout>(
+            views::BoxLayout::Orientation::kHorizontal, kInsideBorderInsets,
+            kBetweenButtonSpacing));
+    layout->set_main_axis_alignment(
+        views::BoxLayout::MainAxisAlignment::kCenter);
+    layout->set_cross_axis_alignment(
+        views::BoxLayout::CrossAxisAlignment::kCenter);
 
     SetPaintToLayer();
     layer()->SetFillsBoundsOpaquely(false);
@@ -185,13 +144,6 @@
   SystemShadow* shadow() { return shadow_.get(); }
 
  private:
-  // Shows a dogfood feedback page for the multitask menu.
-  void ShowFeedbackPageForMenu() {
-    Shell::Get()->shell_delegate()->OpenFeedbackDialog(
-        ShellDelegate::FeedbackSource::kWindowLayoutMenu,
-        /*description_template=*/"#WindowLayoutMenu");
-  }
-
   raw_ptr<chromeos::MultitaskMenuView> menu_view_base_ = nullptr;
 
   std::unique_ptr<SystemShadow> shadow_;
@@ -282,7 +234,8 @@
         chromeos::MultitaskMenuEntryType::kGestureScroll);
   }
 
-  views::AnimationBuilder()
+  views::AnimationBuilder animation_builder;
+  animation_builder
       .OnEnded(show ? base::DoNothing()
                     : base::BindRepeating(&TabletModeMultitaskMenu::Reset,
                                           weak_factory_.GetWeakPtr()))
@@ -296,6 +249,16 @@
                                0, -menu_view_->GetPreferredSize().height() -
                                       kVerticalPosition),
                     gfx::Tween::ACCEL_20_DECEL_100);
+  ui::Layer* cue_layer = event_handler_->multitask_cue()->cue_layer();
+  if (cue_layer && !cue_layer->GetAnimator()->is_animating()) {
+    animation_builder.GetCurrentSequence().SetTransform(
+        cue_layer,
+        show ? gfx::Transform::MakeTranslation(
+                   0, menu_view_->GetPreferredSize().height() +
+                          kVerticalPosition + kCueOffset)
+             : gfx::Transform(),
+        gfx::Tween::ACCEL_20_DECEL_100);
+  }
 }
 
 void TabletModeMultitaskMenu::AnimateFadeOut() {
@@ -326,6 +289,11 @@
     initial_y_ = menu_view_->bounds().bottom();
     menu_view_->layer()->SetTransform(
         gfx::Transform::MakeTranslation(0, translation_y));
+
+    if (ui::Layer* cue_layer = event_handler_->multitask_cue()->cue_layer()) {
+      cue_layer->SetTransform(
+          gfx::Transform::MakeTranslation(0, initial_y + kCueOffset));
+    }
   } else {
     // Drag up can start from anywhere in the menu; simply save `initial_y` to
     // update drag relative to it.
@@ -341,6 +309,12 @@
   }
   menu_view_->layer()->SetTransform(
       gfx::Transform::MakeTranslation(0, translation_y));
+
+  if (ui::Layer* cue_layer = event_handler_->multitask_cue()->cue_layer()) {
+    cue_layer->SetTransform(gfx::Transform::MakeTranslation(
+        0, menu_view_->GetPreferredSize().height() + kVerticalPosition +
+               kCueOffset + translation_y));
+  }
 }
 
 void TabletModeMultitaskMenu::EndDrag() {
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_menu.h b/ash/wm/tablet_mode/tablet_mode_multitask_menu.h
index 9ab29b27..6e132fe 100644
--- a/ash/wm/tablet_mode/tablet_mode_multitask_menu.h
+++ b/ash/wm/tablet_mode/tablet_mode_multitask_menu.h
@@ -38,8 +38,8 @@
 
   views::Widget* widget() { return widget_.get(); }
 
-  // Performs a slide down animation on the menu if `show` is true, otherwise
-  // slide up animation.
+  // Performs a slide down animation on the menu (and cue if visible) if `show`
+  // is true, otherwise slide up animation.
   void Animate(bool show);
 
   // Performs a fade out animation and closes the menu. Called when tap outside
@@ -48,7 +48,8 @@
 
   // Actions called by the event handler, where `initial_y` and `current_y` are
   // in `window_`'s coordinates. If `down` is true, we are dragging down to show
-  // the menu, else we are dragging up to hide the menu.
+  // the menu, else we are dragging up to hide the menu. Also makes the cue
+  // follow the menu's movement if it is showing.
   void BeginDrag(float initial_y, bool down);
   void UpdateDrag(float current_y, bool down);
   void EndDrag();
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.cc b/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.cc
index 41ff094..8c1628c 100644
--- a/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.cc
+++ b/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.cc
@@ -67,6 +67,7 @@
 }
 
 void TabletModeMultitaskMenuEventHandler::ResetMultitaskMenu() {
+  multitask_cue_->ResetPosition();
   multitask_menu_.reset();
 }
 
@@ -98,7 +99,7 @@
         // We may need to recreate `multitask_menu_` on the new active window.
         multitask_menu_ =
             std::make_unique<TabletModeMultitaskMenu>(this, active_window);
-        multitask_cue_->DismissCue(/*menu_opened=*/true);
+        multitask_cue_->nudge_controller()->OnMenuOpened(/*tablet_mode=*/true);
         multitask_menu_->BeginDrag(window_location.y(), /*down=*/true);
         event->SetHandled();
         is_drag_active_ = true;
@@ -108,6 +109,8 @@
                      .Contains(screen_location)) {
         // If the menu is open and scroll up begins, only handle events inside
         // the menu to avoid consuming scroll events outside the menu.
+        // TODO(hewer): Fix the cue reappearing when the menu is dismissed
+        // by swiping up or not dragging far enough.
         multitask_menu_->BeginDrag(window_location.y(), /*down=*/false);
         event->SetHandled();
         is_drag_active_ = true;
@@ -155,7 +158,7 @@
   if (!multitask_menu_) {
     multitask_menu_ =
         std::make_unique<TabletModeMultitaskMenu>(this, active_window);
-    multitask_cue_->DismissCue(/*menu_opened=*/true);
+    multitask_cue_->nudge_controller()->OnMenuOpened(/*tablet_mode=*/true);
   }
 }
 
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.h b/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.h
index 0b84dca..f0c3be6 100644
--- a/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.h
+++ b/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler.h
@@ -29,20 +29,18 @@
   static bool CanShowMenu(aura::Window* window);
 
   TabletModeMultitaskMenu* multitask_menu() { return multitask_menu_.get(); }
+  TabletModeMultitaskCue* multitask_cue() { return multitask_cue_.get(); }
 
   // Creates and shows the menu.
   void ShowMultitaskMenu(aura::Window* window);
 
-  // Destroys the multitask menu.
+  // Destroys the multitask menu and resets the position of the cue if it is
+  // visible.
   void ResetMultitaskMenu();
 
   // ui::EventHandler:
   void OnGestureEvent(ui::GestureEvent* event) override;
 
-  TabletModeMultitaskCue* multitask_cue_for_testing() {
-    return multitask_cue_.get();
-  }
-
  private:
   void MaybeCreateMultitaskMenu(aura::Window* active_window);
 
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler_unittest.cc b/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler_unittest.cc
index 387539f..c866656 100644
--- a/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_multitask_menu_event_handler_unittest.cc
@@ -29,6 +29,7 @@
 #include "ui/aura/test/test_window_delegate.h"
 #include "ui/compositor/layer_animator.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/display/display_switches.h"
 #include "ui/wm/core/window_util.h"
@@ -38,9 +39,7 @@
 namespace {
 
 // The vertical distance used to end drag to show and start drag to hide.
-// TODO(b/267184500): Revert this value back to 100 when the feedback button is
-// removed.
-constexpr int kMenuDragPoint = 110;
+constexpr int kMenuDragPoint = 100;
 
 }  // namespace
 
@@ -251,17 +250,22 @@
   ui::ScopedAnimationDurationScaleMode test_duration_mode(
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
 
+  // Create a larger display so the menu is within the window bounds when split.
+  UpdateDisplay("1600x1000");
+
   auto window1 = CreateTestWindow(gfx::Rect(800, 600));
   PressHalfButton(window1.get(), /*left=*/true);
   auto window2 = CreateTestWindow(gfx::Rect(800, 600));
   PressHalfButton(window2.get(), /*left=*/false);
 
-  // Start swipe down on the left window, then swap to the right window. Note
-  // that `end_y` must be less than the menu height, to start an animation.
+  // Start swipe down on the left window, then swap to the right window. Swipe
+  // distance must be less than the menu height to start an animation.
   gfx::Rect left_bounds(window1->bounds());
-  GenerateScroll(left_bounds.CenterPoint().x(), 0, /*end_y=*/150);
+  GenerateScroll(left_bounds.CenterPoint().x(), 0,
+                 /*end_y=*/kMenuDragPoint);
   gfx::Rect right_bounds(window2->bounds());
-  GenerateScroll(right_bounds.CenterPoint().x(), 0, /*end_y=*/150);
+  GenerateScroll(right_bounds.CenterPoint().x(), 0,
+                 /*end_y=*/kMenuDragPoint);
   EXPECT_TRUE(window2->GetBoundsInScreen().Contains(
       GetMultitaskMenu()->widget()->GetWindowBoundsInScreen()));
 
@@ -269,8 +273,8 @@
   ui::test::EventGenerator* generator = GetEventGenerator();
   generator->PressTouchId(0, gfx::Point(left_bounds.CenterPoint().x(), 0));
   generator->PressTouchId(1, gfx::Point(right_bounds.CenterPoint().x(), 0));
-  generator->MoveTouchId(gfx::Point(0, 150), 0);
-  generator->MoveTouchId(gfx::Point(0, 150), 1);
+  generator->MoveTouchId(gfx::Point(0, kMenuDragPoint), 0);
+  generator->MoveTouchId(gfx::Point(0, kMenuDragPoint), 1);
 }
 
 // Tests that the multitask menu cannot be shown while in pinned state.
@@ -588,17 +592,29 @@
 }
 
 // Tests that showing the menu will dismiss the visual cue (drag bar).
-TEST_F(TabletModeMultitaskMenuEventHandlerTest, DismissCueOnShowMenu) {
+TEST_F(TabletModeMultitaskMenuEventHandlerTest, CueVisibleOnShowMenu) {
+  ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+
   auto window = CreateAppWindow();
 
-  auto* multitask_cue =
-      GetMultitaskMenuEventHandler()->multitask_cue_for_testing();
+  auto* multitask_cue = GetMultitaskMenuEventHandler()->multitask_cue();
   ASSERT_TRUE(multitask_cue);
   EXPECT_TRUE(multitask_cue->cue_layer());
 
-  ShowMultitaskMenu(*window);
+  // Wait for fade in to finish.
+  ui::LayerAnimationStoppedWaiter animation_waiter;
+  animation_waiter.Wait(multitask_cue->cue_layer());
 
-  multitask_cue = GetMultitaskMenuEventHandler()->multitask_cue_for_testing();
+  // Cue should still be showing when the menu is activated.
+  ShowMultitaskMenu(*window);
+  ASSERT_TRUE(multitask_cue);
+  EXPECT_TRUE(multitask_cue->cue_layer());
+
+  multitask_cue->FireCueDismissTimerForTesting();
+
+  // Wait for fade out to finish.
+  animation_waiter.Wait(multitask_cue->cue_layer());
   ASSERT_TRUE(multitask_cue);
   EXPECT_FALSE(multitask_cue->cue_layer());
 }
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
index 113710e..418a31ce 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -65,7 +65,8 @@
 // Snap the carry over windows into splitview mode at |divider_position|.
 void DoSplitViewTransition(
     std::vector<std::pair<aura::Window*, WindowStateType>> windows,
-    int divider_position) {
+    int divider_position,
+    WindowSnapActionSource snap_action_source) {
   if (windows.empty())
     return;
 
@@ -86,6 +87,7 @@
         /*snap_position=*/iter.second == WindowStateType::kPrimarySnapped
             ? SplitViewController::SnapPosition::kPrimary
             : SplitViewController::SnapPosition::kSecondary,
+        snap_action_source,
         /*activate_window=*/false,
         /*snap_ratio=*/snap_ratio ? *snap_ratio : chromeos::kDefaultSnapRatio);
   }
@@ -489,7 +491,8 @@
         GetCarryOverWindowsInSplitView(/*clamshell_to_tablet=*/true);
     const int divider_position = CalculateCarryOverDividerPosition(
         windows_in_splitview, /*clamshell_to_tablet=*/true);
-    DoSplitViewTransition(windows_in_splitview, divider_position);
+    DoSplitViewTransition(windows_in_splitview, divider_position,
+                          WindowSnapActionSource::kSnapByDeskOrSessionChange);
     accounts_since_entering_tablet_.insert(account_id);
   } else {
     refresh_snapped_windows = true;
@@ -669,7 +672,9 @@
   }
 
   // Do split view mode transition.
-  DoSplitViewTransition(windows_in_splitview, divider_position);
+  DoSplitViewTransition(
+      windows_in_splitview, divider_position,
+      WindowSnapActionSource::kSnapByClamshellTabletTransition);
 }
 
 void TabletModeWindowManager::ArrangeWindowsForClamshellMode(
@@ -687,7 +692,9 @@
   // Since we need to keep the windows that were in splitview still be snapped
   // in clamshell mode, change its window state to the corresponding snapped
   // window state.
-  DoSplitViewTransition(windows_in_splitview, divider_position);
+  DoSplitViewTransition(
+      windows_in_splitview, divider_position,
+      WindowSnapActionSource::kSnapByClamshellTabletTransition);
 }
 
 void TabletModeWindowManager::TrackWindow(aura::Window* window,
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
index d6fa21d..c9b592e 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -946,7 +946,7 @@
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   std::unique_ptr<aura::Window> window = CreateAppWindow();
   auto* window_state = WindowState::Get(window.get());
-  WMEvent event(WM_EVENT_SNAP_PRIMARY);
+  WindowSnapWMEvent event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&event);
   ASSERT_TRUE(window_state->IsSnapped());
 
@@ -1653,7 +1653,7 @@
 
   // 5. Clamshell -> Tablet. If the window is snapped, it will be carried over
   // to splitview in tablet mode.
-  const WMEvent event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent event(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window.get())->OnWMEvent(&event);
   EXPECT_TRUE(WindowState::Get(window.get())->IsSnapped());
   // After transition, we should be in single split screen.
@@ -1726,7 +1726,7 @@
   OverviewController* overview_controller = Shell::Get()->overview_controller();
 
   // First test 1 window case.
-  const WMEvent left_snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent left_snap_event(WM_EVENT_SNAP_PRIMARY);
   WindowState::Get(window.get())->OnWMEvent(&left_snap_event);
   const gfx::Rect left_snapped_bounds =
       gfx::Rect(1200 / 2, 800 - ShelfConfig::Get()->shelf_size());
@@ -1751,7 +1751,7 @@
   std::unique_ptr<aura::Window> window2(
       CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
   WindowState::Get(window.get())->OnWMEvent(&left_snap_event);
-  const WMEvent right_snap_event(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent right_snap_event(WM_EVENT_SNAP_SECONDARY);
   WindowState::Get(window2.get())->OnWMEvent(&right_snap_event);
   // Change their bounds horizontally and then enter tablet mode.
   window->SetBounds(gfx::Rect(400, left_snapped_bounds.height()));
@@ -1781,8 +1781,8 @@
   // 1. Create a window and snap to primary 2/3.
   auto window1 = CreateTestWindow();
   OverviewController* overview_controller = Shell::Get()->overview_controller();
-  const WMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
-                                       chromeos::kTwoThirdSnapRatio);
+  const WindowSnapWMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
+                                                 chromeos::kTwoThirdSnapRatio);
   WindowState::Get(window1.get())->OnWMEvent(&snap_primary_two_third);
   // Enter tablet mode and verify that overview opens and the window and
   // divider are at 2/3.
@@ -1808,8 +1808,8 @@
 
   // 2. Create another window and snap to secondary at 1/3.
   auto window2 = CreateTestWindow();
-  const WMEvent snap_secondary_one_third(WM_EVENT_SNAP_SECONDARY,
-                                         chromeos::kOneThirdSnapRatio);
+  const WindowSnapWMEvent snap_secondary_one_third(
+      WM_EVENT_SNAP_SECONDARY, chromeos::kOneThirdSnapRatio);
   WindowState::Get(window2.get())->OnWMEvent(&snap_secondary_one_third);
   EXPECT_EQ(std::round(work_area_bounds.width() * chromeos::kOneThirdSnapRatio),
             window2->bounds().width());
@@ -1901,7 +1901,7 @@
   EXPECT_TRUE(window_state->IsMaximized());
 
   // Transition to kPrimarySnapped window state.
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
   // Restoring a snapped window in tablet mode will change the window back to
   // maximized window state.
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.cc b/ash/wm/tablet_mode/tablet_mode_window_state.cc
index 15fae3a..d438281 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_state.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_state.cc
@@ -350,7 +350,10 @@
       break;
     case WM_EVENT_SNAP_PRIMARY:
     case WM_EVENT_SNAP_SECONDARY:
-      DoTabletSnap(window_state, event->type(), event->snap_ratio());
+      CHECK(event->AsSnapEvent());
+      DoTabletSnap(window_state, event->type(),
+                   event->AsSnapEvent()->snap_ratio(),
+                   event->AsSnapEvent()->snap_action_source());
       return;
     case WM_EVENT_CYCLE_SNAP_PRIMARY:
       CycleTabletSnap(window_state,
@@ -604,7 +607,8 @@
   }
   // If |window| can snap in split view, then snap |window| in |snap_position|.
   if (split_view_controller->CanSnapWindow(window)) {
-    split_view_controller->SnapWindow(window, snap_position);
+    split_view_controller->SnapWindow(
+        window, snap_position, WindowSnapActionSource::kKeyboardShortcutToSnap);
     window_state->ReadOutWindowCycleSnapAction(
         snap_position == SplitViewController::SnapPosition::kPrimary
             ? IDS_WM_SNAP_WINDOW_TO_LEFT_ON_SHORTCUT
@@ -615,9 +619,11 @@
   ShowAppCannotSnapToast();
 }
 
-void TabletModeWindowState::DoTabletSnap(WindowState* window_state,
-                                         WMEventType snap_event_type,
-                                         float snap_ratio) {
+void TabletModeWindowState::DoTabletSnap(
+    WindowState* window_state,
+    WMEventType snap_event_type,
+    float snap_ratio,
+    WindowSnapActionSource snap_action_source) {
   DCHECK(snap_event_type == WM_EVENT_SNAP_PRIMARY ||
          snap_event_type == WM_EVENT_SNAP_SECONDARY);
 
@@ -633,8 +639,7 @@
       snap_event_type == WM_EVENT_SNAP_PRIMARY
           ? WindowStateType::kPrimarySnapped
           : WindowStateType::kSecondarySnapped;
-  window_state->RecordAndResetWindowSnapActionSource(
-      window_state->GetStateType(), new_state_type);
+  window_state->RecordWindowSnapActionSource(snap_action_source);
 
   // A snap WMEvent will put the window in tablet split view.
   split_view_controller->OnWMEvent(window, snap_event_type);
@@ -646,13 +651,12 @@
 void TabletModeWindowState::DoRestore(WindowState* window_state) {
   WindowStateType restore_state = window_state->GetRestoreWindowState();
   if (chromeos::IsSnappedWindowStateType(restore_state)) {
-    window_state->set_snap_action_source(
-        WindowSnapActionSource::kSnapByWindowStateRestore);
     DoTabletSnap(window_state,
                  restore_state == WindowStateType::kPrimarySnapped
                      ? WM_EVENT_SNAP_PRIMARY
                      : WM_EVENT_SNAP_SECONDARY,
-                 chromeos::kDefaultSnapRatio);
+                 chromeos::kDefaultSnapRatio,
+                 WindowSnapActionSource::kSnapByWindowStateRestore);
     return;
   }
 
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.h b/ash/wm/tablet_mode/tablet_mode_window_state.h
index 1fb5fad5..832f5fbe 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_state.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_state.h
@@ -102,7 +102,8 @@
   // it cannot be snapped.
   void DoTabletSnap(WindowState* window_state,
                     WMEventType snap_event_type,
-                    float snap_ratio);
+                    float snap_ratio,
+                    WindowSnapActionSource snap_action_source);
 
   // Called by `WM_EVENT_RESTORE`, or a `WM_EVENT_NORMAL` that is restoring.
   // Restores to the state in `window_states`'s restore history.
diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc
index ee5f1ef1..e537abc2 100644
--- a/ash/wm/toplevel_window_event_handler_unittest.cc
+++ b/ash/wm/toplevel_window_event_handler_unittest.cc
@@ -1095,7 +1095,7 @@
   // Snap the window to the right.
   WindowState* window_state = WindowState::Get(w1.get());
   ASSERT_TRUE(window_state->CanSnap());
-  const WMEvent event(WM_EVENT_CYCLE_SNAP_SECONDARY);
+  const WindowSnapWMEvent event(WM_EVENT_CYCLE_SNAP_SECONDARY);
   window_state->OnWMEvent(&event);
   ASSERT_TRUE(window_state->IsSnapped());
 
diff --git a/ash/wm/window_restore/window_restore_controller.cc b/ash/wm/window_restore/window_restore_controller.cc
index 91375c9..aa6f4bc 100644
--- a/ash/wm/window_restore/window_restore_controller.cc
+++ b/ash/wm/window_restore/window_restore_controller.cc
@@ -543,10 +543,12 @@
           *state_type == chromeos::WindowStateType::kSecondarySnapped) {
         base::AutoReset<aura::Window*> auto_reset_to_be_snapped(
             &to_be_snapped_window_, window);
-        const WMEvent snap_event(
+        const WindowSnapWMEvent snap_event(
             *state_type == chromeos::WindowStateType::kPrimarySnapped
                 ? WM_EVENT_SNAP_PRIMARY
-                : WM_EVENT_SNAP_SECONDARY);
+                : WM_EVENT_SNAP_SECONDARY,
+            WindowSnapActionSource::
+                kSnapByFullRestoreOrDeskTemplateOrSavedDesk);
         window_state->OnWMEvent(&snap_event);
       }
       if (*state_type == chromeos::WindowStateType::kFloated) {
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index da7e501..ab3fd8a 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -537,7 +537,8 @@
 
   if (event->IsSnapEvent()) {
     // Save `event` requested snap ratio.
-    const float target_snap_ratio = event->snap_ratio();
+    CHECK(event->AsSnapEvent());
+    const float target_snap_ratio = event->AsSnapEvent()->snap_ratio();
     snap_ratio_ = absl::make_optional(target_snap_ratio);
     if (IsPartial(target_snap_ratio)) {
       partial_start_time_ = base::TimeTicks::Now();
@@ -1503,16 +1504,10 @@
   return true;
 }
 
-void WindowState::RecordAndResetWindowSnapActionSource(
-    chromeos::WindowStateType current_type,
-    chromeos::WindowStateType new_type) {
-  // Do not record the metrics if the window state snap type does not change.
-  if (current_type == new_type)
-    return;
-
+void WindowState::RecordWindowSnapActionSource(
+    WindowSnapActionSource snap_action_source) {
   base::UmaHistogramEnumeration(kWindowSnapActionSourceHistogram,
-                                snap_action_source_);
-  snap_action_source_ = WindowSnapActionSource::kOthers;
+                                snap_action_source);
 }
 
 void WindowState::CheckAndRecordDragMaximizedBehavior() {
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index 06452f1..6cb632f 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -450,10 +450,6 @@
   const DragDetails* drag_details() const { return drag_details_.get(); }
   DragDetails* drag_details() { return drag_details_.get(); }
 
-  void set_snap_action_source(WindowSnapActionSource type) {
-    snap_action_source_ = type;
-  }
-
   const std::vector<RestoreState>& window_state_restore_history_for_testing()
       const {
     return window_state_restore_history_;
@@ -600,9 +596,7 @@
 
   bool CanUnresizableSnapOnDisplay(display::Display display) const;
 
-  void RecordAndResetWindowSnapActionSource(
-      chromeos::WindowStateType current_type,
-      chromeos::WindowStateType new_type);
+  void RecordWindowSnapActionSource(WindowSnapActionSource snap_action_source);
 
   // Gets called by the `drag_to_maximize_mis_trigger_timer_` to check the drag
   // to maximize behavior's validity and record the number of mis-triggers.
@@ -707,10 +701,6 @@
   // a higher precedent than whatever is at the tip of
   // window_state_restore_history_.
   absl::optional<gfx::Rect> restore_bounds_override_;
-
-  // This is used to record where the current snap window state change request
-  // comes from.
-  WindowSnapActionSource snap_action_source_ = WindowSnapActionSource::kOthers;
 };
 
 ASH_EXPORT
diff --git a/ash/wm/window_state_unittest.cc b/ash/wm/window_state_unittest.cc
index f488022aa..56c1069 100644
--- a/ash/wm/window_state_unittest.cc
+++ b/ash/wm/window_state_unittest.cc
@@ -95,7 +95,7 @@
   std::unique_ptr<aura::Window> window(
       CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
   WindowState* window_state = WindowState::Get(window.get());
-  const WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_primary);
   gfx::Rect expected = gfx::Rect(kPrimaryDisplayWorkAreaBounds.x(),
                                  kPrimaryDisplayWorkAreaBounds.y(),
@@ -103,7 +103,7 @@
                                  kPrimaryDisplayWorkAreaBounds.height());
   EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
 
-  const WMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_secondary);
   expected.set_x(kPrimaryDisplayWorkAreaBounds.right() - expected.width());
   EXPECT_EQ(expected.ToString(), window->GetBoundsInScreen().ToString());
@@ -139,8 +139,8 @@
       CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
   std::unique_ptr<aura::Window> right_window(
       CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
-  const WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
-  const WMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
   WindowState::Get(left_window.get())->OnWMEvent(&snap_primary);
   WindowState::Get(right_window.get())->OnWMEvent(&snap_secondary);
   EXPECT_EQ(gfx::Rect(0, work_area.y(), 758, work_area.bottom()),
@@ -165,7 +165,7 @@
   delegate.set_minimum_size(gfx::Size(kMinimumWidth, 0));
   WindowState* window_state = WindowState::Get(window.get());
   EXPECT_TRUE(window_state->CanSnap());
-  const WMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_secondary);
   // Expect right snap with the minimum width.
   const gfx::Rect expected_right_snap(kWorkAreaBounds.width() - kMinimumWidth,
@@ -501,7 +501,7 @@
       &delegate, -1, gfx::Rect(100, 100, 100, 100)));
   delegate.set_window_component(HTRIGHT);
   WindowState* window_state = WindowState::Get(window.get());
-  const WMEvent cycle_snap_primary(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent cycle_snap_primary(WM_EVENT_CYCLE_SNAP_PRIMARY);
   window_state->OnWMEvent(&cycle_snap_primary);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   gfx::Rect expected =
@@ -553,7 +553,7 @@
           .Build();
   delegate.set_window_component(HTCAPTION);
   WindowState* window_state = WindowState::Get(window.get());
-  const WMEvent cycle_snap_primary(WM_EVENT_CYCLE_SNAP_PRIMARY);
+  const WindowSnapWMEvent cycle_snap_primary(WM_EVENT_CYCLE_SNAP_PRIMARY);
   window_state->OnWMEvent(&cycle_snap_primary);
 
   // Snap window to primary position (left).
@@ -598,9 +598,9 @@
   gfx::Rect restore_bounds = window->GetBoundsInScreen();
   restore_bounds.set_width(restore_bounds.width() + 1);
   window_state->SetRestoreBoundsInScreen(restore_bounds);
-  const WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_primary);
-  const WMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_secondary);
   EXPECT_NE(restore_bounds.ToString(), window->GetBoundsInScreen().ToString());
   EXPECT_EQ(restore_bounds.ToString(),
@@ -637,7 +637,7 @@
   window->Show();
 
   window_state->Maximize();
-  const WMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_secondary);
 
   const gfx::Rect kWorkAreaBounds =
@@ -928,7 +928,7 @@
   WindowState* window_state = WindowState::Get(window.get());
   EXPECT_FALSE(window_state->IsFullscreen());
 
-  const WMEvent snap_right_event(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_right_event(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_right_event);
   EXPECT_TRUE(window_state->IsSnapped());
   EXPECT_EQ(screen->GetDisplayNearestWindow(window.get()).id(),
@@ -1249,14 +1249,14 @@
   EXPECT_TRUE(window_state->IsNormalStateType());
   EXPECT_TRUE(window->GetTransparent());
 
-  const WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_primary);
   EXPECT_FALSE(window->GetTransparent());
 
   window_state->Restore();
   EXPECT_TRUE(window->GetTransparent());
 
-  const WMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_primary);
   EXPECT_FALSE(window->GetTransparent());
 
@@ -1286,7 +1286,7 @@
   EXPECT_EQ(window_state->GetRestoreBoundsInScreen(), gfx::Rect());
 
   // Transition to kPrimarySnapped window state.
-  const WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_primary);
   EXPECT_EQ(window->GetBoundsInScreen(), gfx::Rect(snap_window_size));
   ASSERT_EQ(restore_stack.size(), 1u);
@@ -1415,7 +1415,7 @@
   EXPECT_EQ(window_state->GetRestoreBoundsInScreen(), gfx::Rect());
 
   // Transition to kPrimarySnapped window state.
-  const WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_primary);
 
   // Then transition to kMaximized window state.
@@ -1471,7 +1471,7 @@
 
   // Test kPrimarySnapped & kSecondarySnapped.
   // Transition to kPrimarySnapped window state.
-  const WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_primary);
   ASSERT_EQ(restore_stack.size(), 1u);
   EXPECT_EQ(restore_stack[0].window_state_type, WindowStateType::kNormal);
@@ -1481,7 +1481,7 @@
   // Transition to kSecondarySnapped window state. Since it's on the same layer
   // as kPrimarySnapped, kPrimarySnapped won't be pushed into the restore
   // history stack.
-  const WMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_secondary);
   ASSERT_EQ(restore_stack.size(), 1u);
   EXPECT_EQ(restore_stack[0].window_state_type, WindowStateType::kNormal);
@@ -1533,7 +1533,7 @@
   EXPECT_EQ(window_state->GetRestoreBoundsInScreen(), gfx::Rect());
 
   // Transition to kPrimarySnapped window state.
-  const WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_primary);
 
   // Then transition to kMaximized window state.
@@ -1774,7 +1774,7 @@
   window->SetBounds(moved_bounds);
   window_state->SetRestoreBoundsInScreen(default_bounds);
 
-  const WMEvent snap_left_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left_event(WM_EVENT_SNAP_PRIMARY);
   const gfx::Rect snapped_left_bounds(0, 0, work_area_bounds.width() / 2,
                                       work_area_bounds.height());
   window_state->OnWMEvent(&snap_left_event);
@@ -1824,10 +1824,10 @@
   WindowState* window_state = WindowState::Get(window.get());
 
   // Use WMEvent to directly snap the window.
-  WMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_primary);
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kOthers, 1);
+                               WindowSnapActionSource::kNotSpecified, 1);
   window_state->Maximize();
 
   // Drag the window to the screen edge to snap.
@@ -1840,7 +1840,7 @@
                                WindowSnapActionSource::kDragWindowToEdgeToSnap,
                                1);
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kOthers, 1);
+                               WindowSnapActionSource::kNotSpecified, 1);
   window_state->Maximize();
 
   // Use keyboard to snap a window.
@@ -1850,7 +1850,7 @@
                                WindowSnapActionSource::kKeyboardShortcutToSnap,
                                1);
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kOthers, 1);
+                               WindowSnapActionSource::kNotSpecified, 1);
   window_state->Maximize();
 
   // Restore the maximized window to snap window state.
@@ -1859,7 +1859,7 @@
       kWindowSnapActionSourceHistogram,
       WindowSnapActionSource::kSnapByWindowStateRestore, 1);
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kOthers, 1);
+                               WindowSnapActionSource::kNotSpecified, 1);
   window_state->Maximize();
 
   // Drag or select overview window to snap window.
@@ -1877,7 +1877,7 @@
       kWindowSnapActionSourceHistogram,
       WindowSnapActionSource::kDragOrSelectOverviewWindowToSnap, 1);
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kOthers, 1);
+                               WindowSnapActionSource::kNotSpecified, 1);
   window_state->Maximize();
 
   Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
@@ -1890,14 +1890,14 @@
                                WindowSnapActionSource::kKeyboardShortcutToSnap,
                                2);
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kOthers, 1);
+                               WindowSnapActionSource::kNotSpecified, 1);
 
   // Auto-snap in splitview.
   std::unique_ptr<aura::Window> window2(CreateAppWindow());
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kAutoSnapBySplitview, 1);
+                               WindowSnapActionSource::kAutoSnapInSplitView, 1);
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kOthers, 1);
+                               WindowSnapActionSource::kNotSpecified, 1);
 
   // Resize in splitview.
   auto* split_view_controller =
@@ -1913,10 +1913,10 @@
   split_view_controller->ResizeWithDivider(resize_point);
   // This should not cause any metrics change.
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kOthers, 1);
+                               WindowSnapActionSource::kNotSpecified, 1);
   split_view_controller->EndResizeWithDivider(resize_point);
   histograms.ExpectBucketCount(kWindowSnapActionSourceHistogram,
-                               WindowSnapActionSource::kOthers, 1);
+                               WindowSnapActionSource::kNotSpecified, 1);
 }
 
 // Test how the minimum height specified by the aura::WindowDelegate affects
@@ -1938,7 +1938,7 @@
   delegate.set_minimum_size(kMinimumSize);
   WindowState* window_state = WindowState::Get(window.get());
   EXPECT_TRUE(window_state->CanSnap());
-  const WMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
   window_state->OnWMEvent(&snap_secondary);
   // Expect right snap for horizontal snap layout with the minimum width and
   // bottom snap for vertical snap layout with the minimum height.
@@ -1972,7 +1972,8 @@
 
   // Partial split for 30 seconds, then maximize. Test that it records 0 since
   // it has been less than 1 minute.
-  WMEvent partial_event(WM_EVENT_SNAP_PRIMARY, chromeos::kTwoThirdSnapRatio);
+  WindowSnapWMEvent partial_event(WM_EVENT_SNAP_PRIMARY,
+                                  chromeos::kTwoThirdSnapRatio);
   window_state->OnWMEvent(&partial_event);
   AdvanceClock(base::Seconds(30));
   window_state->Maximize();
@@ -1988,7 +1989,7 @@
   // in the 180 minute bucket.
   window_state->OnWMEvent(&partial_event);
   AdvanceClock(base::Hours(3));
-  WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
+  WindowSnapWMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   histogram_tester.ExpectBucketCount(kHistogramName, 180, 1);
 
@@ -2029,8 +2030,8 @@
   ActivateDesk(desks_controller->desks()[1].get());
   AdvanceClock(base::Minutes(1));
   std::unique_ptr<aura::Window> window2(CreateAppWindow());
-  WMEvent partial_secondary(WM_EVENT_SNAP_SECONDARY,
-                            chromeos::kOneThirdSnapRatio);
+  WindowSnapWMEvent partial_secondary(WM_EVENT_SNAP_SECONDARY,
+                                      chromeos::kOneThirdSnapRatio);
   WindowState::Get(window2.get())->OnWMEvent(&partial_secondary);
   AdvanceClock(base::Minutes(1));
   window.reset();
diff --git a/ash/wm/wm_event.cc b/ash/wm/wm_event.cc
index 69f6345..21120be7 100644
--- a/ash/wm/wm_event.cc
+++ b/ash/wm/wm_event.cc
@@ -9,13 +9,8 @@
 namespace ash {
 
 WMEvent::WMEvent(WMEventType type) : type_(type) {
-  DCHECK(IsWorkspaceEvent() || IsCompoundEvent() || IsBoundsEvent() ||
-         IsTransitionEvent());
-}
-
-WMEvent::WMEvent(WMEventType type, float snap_ratio)
-    : type_(type), snap_ratio_(snap_ratio) {
-  DCHECK(IsSnapEvent());
+  CHECK(IsWorkspaceEvent() || IsCompoundEvent() || IsBoundsEvent() ||
+        IsTransitionEvent());
 }
 
 WMEvent::~WMEvent() = default;
@@ -105,6 +100,10 @@
   return false;
 }
 
+const WindowSnapWMEvent* WMEvent::AsSnapEvent() const {
+  return nullptr;
+}
+
 const DisplayMetricsChangedWMEvent* WMEvent::AsDisplayMetricsChangedWMEvent()
     const {
   DCHECK_EQ(type(), WM_EVENT_DISPLAY_BOUNDS_CHANGED);
@@ -128,6 +127,36 @@
 
 SetBoundsWMEvent::~SetBoundsWMEvent() = default;
 
+WindowSnapWMEvent::WindowSnapWMEvent(WMEventType type) : WMEvent(type) {
+  CHECK(IsSnapEvent());
+}
+
+WindowSnapWMEvent::WindowSnapWMEvent(WMEventType type, float snap_ratio)
+    : WMEvent(type), snap_ratio_(snap_ratio) {
+  CHECK(IsSnapEvent());
+}
+
+WindowSnapWMEvent::WindowSnapWMEvent(WMEventType type,
+                                     WindowSnapActionSource snap_action_source)
+    : WMEvent(type), snap_action_source_(snap_action_source) {
+  CHECK(IsSnapEvent());
+}
+
+WindowSnapWMEvent::WindowSnapWMEvent(WMEventType type,
+                                     float snap_ratio,
+                                     WindowSnapActionSource snap_action_source)
+    : WMEvent(type),
+      snap_ratio_(snap_ratio),
+      snap_action_source_(snap_action_source) {
+  CHECK(IsSnapEvent());
+}
+
+WindowSnapWMEvent::~WindowSnapWMEvent() = default;
+
+const WindowSnapWMEvent* WindowSnapWMEvent::AsSnapEvent() const {
+  return this;
+}
+
 DisplayMetricsChangedWMEvent::DisplayMetricsChangedWMEvent(int changed_metrics)
     : WMEvent(WM_EVENT_DISPLAY_BOUNDS_CHANGED),
       changed_metrics_(changed_metrics) {}
diff --git a/ash/wm/wm_event.h b/ash/wm/wm_event.h
index 1c806d9..60c424f 100644
--- a/ash/wm/wm_event.h
+++ b/ash/wm/wm_event.h
@@ -7,6 +7,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/wm/window_state.h"
+#include "ash/wm/wm_metrics.h"
 #include "base/time/time.h"
 #include "chromeos/ui/frame/caption_buttons/snap_controller.h"
 #include "ui/display/display.h"
@@ -122,13 +123,11 @@
 
 class SetBoundsWMEvent;
 class DisplayMetricsChangedWMEvent;
+class WindowSnapWMEvent;
 
 class ASH_EXPORT WMEvent {
  public:
   explicit WMEvent(WMEventType type);
-  // Creates a window snap event with the requested `snap_ratio`. Used only by
-  // snap events.
-  WMEvent(WMEventType type, float snap_ratio);
 
   WMEvent(const WMEvent&) = delete;
   WMEvent& operator=(const WMEvent&) = delete;
@@ -137,8 +136,6 @@
 
   WMEventType type() const { return type_; }
 
-  float snap_ratio() const { return snap_ratio_; }
-
   // Predicates to test the type of event.
 
   // Event that notifies that workspace has changed. (its size, being
@@ -164,14 +161,14 @@
   // True if the event is a window snap event.
   bool IsSnapEvent() const;
 
+  // Returns `this` if it's a WindowSnapWMEvent, otherwise returns nullptr.
+  virtual const WindowSnapWMEvent* AsSnapEvent() const;
+
   // Utility methods to downcast to specific WMEvent types.
   const DisplayMetricsChangedWMEvent* AsDisplayMetricsChangedWMEvent() const;
 
  private:
   WMEventType type_;
-
-  // The snap ratio requested by snap events.
-  float snap_ratio_ = chromeos::kDefaultSnapRatio;
 };
 
 // An WMEvent to request new bounds for the window.
@@ -225,6 +222,37 @@
   const uint32_t changed_metrics_;
 };
 
+// An WMEvent to snap a window.
+class ASH_EXPORT WindowSnapWMEvent : public WMEvent {
+ public:
+  explicit WindowSnapWMEvent(WMEventType type);
+  WindowSnapWMEvent(WMEventType type, float snap_ratio);
+  WindowSnapWMEvent(WMEventType type,
+                    WindowSnapActionSource snap_action_source);
+  WindowSnapWMEvent(WMEventType type,
+                    float snap_ratio,
+                    WindowSnapActionSource snap_action_source);
+
+  WindowSnapWMEvent(const WindowSnapWMEvent&) = delete;
+  WindowSnapWMEvent& operator=(const WindowSnapWMEvent&) = delete;
+
+  ~WindowSnapWMEvent() override;
+
+  // WMEvent:
+  const WindowSnapWMEvent* AsSnapEvent() const override;
+
+  float snap_ratio() const { return snap_ratio_; }
+  WindowSnapActionSource snap_action_source() const {
+    return snap_action_source_;
+  }
+
+ private:
+  float snap_ratio_ = chromeos::kDefaultSnapRatio;
+
+  WindowSnapActionSource snap_action_source_ =
+      WindowSnapActionSource::kNotSpecified;
+};
+
 }  // namespace ash
 
 #endif  // ASH_WM_WM_EVENT_H_
diff --git a/ash/wm/wm_metrics.h b/ash/wm/wm_metrics.h
index f0f0d8e7..f3b64f9 100644
--- a/ash/wm/wm_metrics.h
+++ b/ash/wm/wm_metrics.h
@@ -10,25 +10,29 @@
 // Used to record different ways to snap a window. Note this should be kept in
 // sync with WindowSnapActionSource enum in tools/metrics/histograms/enums.xml.
 enum class WindowSnapActionSource {
+  kNotSpecified,  // Default value. This can include any actions that's not
+                  // covered below. Examples can be: swap action in split view,
+                  //
   kDragWindowToEdgeToSnap,
-  kUseCaptionButtonToSnap,
+  kLongPressCaptionButtonToSnap,
   kKeyboardShortcutToSnap,
   kDragOrSelectOverviewWindowToSnap,
   kLongPressOverviewButtonToSnap,
   kDragUpFromShelfToSnap,
   kDragDownFromTopToSnap,
   kDragTabToSnap,
-  kAutoSnapBySplitview,
+  kAutoSnapInSplitView,
   kSnapByWindowStateRestore,
-  kOthers,  // This can include any actions that's not covered above, e.g.,
-            // window snap by full restore, desk template, desk switch or user
-            // switch, etc
-  kMaxValue = kOthers,
+  kSnapByWindowLayoutMenu,
+  kSnapByFullRestoreOrDeskTemplateOrSavedDesk,
+  kSnapByClamshellTabletTransition,
+  kSnapByDeskOrSessionChange,
+  kMaxValue = kSnapByDeskOrSessionChange,
 };
 
 // Used to save histogram metrics about how the user initiates window snapping.
 constexpr char kWindowSnapActionSourceHistogram[] =
-    "Ash.Wm.WindowSnapActionSource";
+    "Ash.Wm.WindowSnapActionSource2";
 
 // Used to record the user action on initiating the multi-window resizer.
 constexpr char kMultiWindowResizerShow[] = "MultiWindowResizerShow";
diff --git a/ash/wm/workspace/multi_window_resize_controller.cc b/ash/wm/workspace/multi_window_resize_controller.cc
index afae5fc..8ce4c24 100644
--- a/ash/wm/workspace/multi_window_resize_controller.cc
+++ b/ash/wm/workspace/multi_window_resize_controller.cc
@@ -28,13 +28,18 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
 #include "base/time/time.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/base/hit_test.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/compositor/layer.h"
 #include "ui/display/screen.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/wm/core/compound_event_filter.h"
@@ -56,6 +61,10 @@
 
 constexpr int kLockButtonCornerRadius = 20;
 
+// The size of the resize widget when the feature flag `Jellyroll` is enabled.
+constexpr int kLongSideCrOSNext = 64;
+constexpr int kShortSideCrOSNext = 52;
+
 // Returns the widget init params needed to create the resize widget or snap
 // group lock widget.
 views::Widget::InitParams CreateWidgetParams(aura::Window* parent_window,
@@ -151,41 +160,92 @@
   // views::View:
   gfx::Size CalculatePreferredSize() const override {
     const bool vert = direction_ == Direction::kLeftRight;
+
+    if (chromeos::features::IsJellyrollEnabled()) {
+      return gfx::Size(vert ? kLongSideCrOSNext : kShortSideCrOSNext,
+                       vert ? kShortSideCrOSNext : kLongSideCrOSNext);
+    }
+
     return gfx::Size(vert ? kShortSide : kLongSide,
                      vert ? kLongSide : kShortSide);
   }
 
   void OnPaint(gfx::Canvas* canvas) override {
-    cc::PaintFlags flags;
-    flags.setColor(SkColorSetA(SK_ColorBLACK, 0x7F));
-    flags.setAntiAlias(true);
-    canvas->DrawRoundRect(gfx::RectF(GetLocalBounds()), 2, flags);
+    if (!chromeos::features::IsJellyrollEnabled()) {
+      cc::PaintFlags flags;
+      flags.setColor(SkColorSetA(SK_ColorBLACK, 0x7F));
+      flags.setAntiAlias(true);
+      canvas->DrawRoundRect(gfx::RectF(GetLocalBounds()), 2, flags);
 
-    // Craft the left arrow.
-    const SkRect kArrowBounds = SkRect::MakeXYWH(4, 28, 4, 8);
-    SkPath path;
-    path.moveTo(kArrowBounds.right(), kArrowBounds.y());
-    path.lineTo(kArrowBounds.x(), kArrowBounds.centerY());
-    path.lineTo(kArrowBounds.right(), kArrowBounds.bottom());
-    path.close();
+      // Craft the left arrow.
+      const SkRect kArrowBounds = SkRect::MakeXYWH(4, 28, 4, 8);
+      SkPath path;
+      path.moveTo(kArrowBounds.right(), kArrowBounds.y());
+      path.lineTo(kArrowBounds.x(), kArrowBounds.centerY());
+      path.lineTo(kArrowBounds.right(), kArrowBounds.bottom());
+      path.close();
 
-    // Do the same for the right arrow.
-    SkMatrix flip;
-    flip.setScale(-1, 1, kShortSide / 2, kLongSide / 2);
-    path.addPath(path, flip);
+      // Do the same for the right arrow.
+      SkMatrix flip;
+      flip.setScale(-1, 1, kShortSide / 2, kLongSide / 2);
+      path.addPath(path, flip);
 
-    // The arrows are drawn for the vertical orientation; rotate if need be.
-    if (direction_ == Direction::kTopBottom) {
-      SkMatrix transform;
-      constexpr int kHalfShort = kShortSide / 2;
-      constexpr int kHalfLong = kLongSide / 2;
-      transform.setRotate(90, kHalfShort, kHalfLong);
-      transform.postTranslate(kHalfLong - kHalfShort, kHalfShort - kHalfLong);
-      path.transform(transform);
+      // The arrows are drawn for the vertical orientation; rotate if need be.
+      if (direction_ == Direction::kTopBottom) {
+        SkMatrix transform;
+        constexpr int kHalfShort = kShortSide / 2;
+        constexpr int kHalfLong = kLongSide / 2;
+        transform.setRotate(90, kHalfShort, kHalfLong);
+        transform.postTranslate(kHalfLong - kHalfShort, kHalfShort - kHalfLong);
+        path.transform(transform);
+      }
+
+      flags.setColor(SK_ColorWHITE);
+      canvas->DrawPath(path, flags);
+      return;
     }
 
-    flags.setColor(SK_ColorWHITE);
-    canvas->DrawPath(path, flags);
+    cc::PaintFlags flags;
+
+    flags.setColor(
+        GetColorProvider()->GetColor(cros_tokens::kCrosSysSystemBaseElevated));
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    flags.setAntiAlias(true);
+
+    canvas->DrawPath(GeneratePath(GetLocalBounds()), flags);
+
+    // Paint the chevron icons.
+    constexpr int kIconSize = 20;
+    constexpr int kHalfLong = kLongSideCrOSNext / 2;
+
+    // Paint the left / up chevron icon.
+    canvas->Save();
+    int long_offset = (kHalfLong - kIconSize) / 2;
+    int short_offset = (kShortSideCrOSNext - kIconSize) / 2;
+    canvas->Translate(direction_ == Direction::kLeftRight
+                          ? gfx::Vector2d(long_offset, short_offset)
+                          : gfx::Vector2d(short_offset, long_offset));
+    gfx::PaintVectorIcon(
+        canvas,
+        direction_ == Direction::kLeftRight ? kOverflowShelfLeftIcon
+                                            : kChevronUpSmallIcon,
+        kIconSize,
+        GetColorProvider()->GetColor(cros_tokens::kCrosSysOnSurface));
+    canvas->Restore();
+
+    // Paint the right / down chevron icon.
+    canvas->Save();
+    long_offset = kHalfLong + (kHalfLong - kIconSize) / 2;
+    canvas->Translate(direction_ == Direction::kLeftRight
+                          ? gfx::Vector2d(long_offset, short_offset)
+                          : gfx::Vector2d(short_offset, long_offset));
+    gfx::PaintVectorIcon(
+        canvas,
+        direction_ == Direction::kLeftRight ? kOverflowShelfRightIcon
+                                            : kChevronDownSmallIcon,
+        kIconSize,
+        GetColorProvider()->GetColor(cros_tokens::kCrosSysOnSurface));
+    canvas->Restore();
   }
 
   bool OnMousePressed(const ui::MouseEvent& event) override {
@@ -219,6 +279,72 @@
 
   raw_ptr<MultiWindowResizeController, ExperimentalAsh> controller_;
   const Direction direction_;
+
+  SkPath GeneratePath(const gfx::Rect& bounds) {
+    //           /\
+    //      ----    ----
+    //    /              \
+    //    \              /
+    //      ----    ----
+    //           \/
+    //
+    // Generate the path for the shape above when `direction_` is
+    // `Direction::kLeftRight`. If the `direction_` is `Direction::kTopBottom`,
+    // generate the path for the shape above with 90 degree rotated.
+
+    static constexpr int kLargeCurveRadius = 16;
+    static constexpr int kSmallCurveRadius = 10;
+
+    // The resize shape is symmetric horizontally and vertically, hence only
+    // need to manually generate the path for the quarter and then flip twice;
+    const gfx::RectF quarter_bounds(bounds.x(), bounds.y(), bounds.width() / 2,
+                                    bounds.height() / 2);
+    SkPath path;
+    if (direction_ == Direction::kLeftRight) {
+      //           /|
+      //      ----  |
+      //    / ____  |
+
+      // Generate the path for the quarter of the resize shape which looks like
+      // the shape above, starting from left bottom to the right top and then
+      // back to the left bottom.
+      path.moveTo(quarter_bounds.x(), quarter_bounds.bottom());
+      path.arcTo(
+          quarter_bounds.x(), quarter_bounds.bottom() - kLargeCurveRadius,
+          quarter_bounds.x() + kLargeCurveRadius,
+          quarter_bounds.bottom() - kLargeCurveRadius, kLargeCurveRadius);
+      path.lineTo(quarter_bounds.right() - kSmallCurveRadius,
+                  quarter_bounds.bottom() - kLargeCurveRadius);
+      path.arcTo(quarter_bounds.right(),
+                 quarter_bounds.bottom() - kLargeCurveRadius,
+                 quarter_bounds.right(), quarter_bounds.y(), kSmallCurveRadius);
+      path.lineTo(quarter_bounds.right(), quarter_bounds.bottom());
+    } else {
+      // Similar to the way when `direction_` is `Direction::kLeftRight`,
+      // starting from the right top to the left bottom and then back to the
+      // right top.
+      path.moveTo(quarter_bounds.right(), quarter_bounds.y());
+      path.arcTo(quarter_bounds.right() - kLargeCurveRadius, quarter_bounds.y(),
+                 quarter_bounds.right() - kLargeCurveRadius,
+                 quarter_bounds.y() + kLargeCurveRadius, kLargeCurveRadius);
+      path.lineTo(quarter_bounds.right() - kLargeCurveRadius,
+                  quarter_bounds.bottom() - kSmallCurveRadius);
+      path.arcTo(quarter_bounds.right() - kLargeCurveRadius,
+                 quarter_bounds.bottom(), quarter_bounds.x(),
+                 quarter_bounds.bottom(), kSmallCurveRadius);
+      path.lineTo(quarter_bounds.right(), quarter_bounds.bottom());
+    }
+    path.close();
+
+    // Flip vertically and horizontally and vertically to get the full path.
+    SkMatrix flip;
+    flip.setScale(1, -1, quarter_bounds.width(), quarter_bounds.height());
+    path.addPath(path, flip);
+    flip.setScale(-1, 1, quarter_bounds.width(), quarter_bounds.height());
+    path.addPath(path, flip);
+
+    return path;
+  }
 };
 
 // -----------------------------------------------------------------------------
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
index 3f44f05..2cade14 100644
--- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc
+++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -622,7 +622,7 @@
       &delegate1, -1, gfx::Rect(100, 100, 100, 100)));
   delegate1.set_window_component(HTRIGHT);
   WindowState* w1_state = WindowState::Get(w1.get());
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   w1_state->OnWMEvent(&snap_left);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, w1_state->GetStateType());
   aura::test::TestWindowDelegate delegate2;
@@ -630,7 +630,7 @@
       &delegate2, -2, gfx::Rect(100, 100, 100, 100)));
   delegate2.set_window_component(HTRIGHT);
   WindowState* w2_state = WindowState::Get(w2.get());
-  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   w2_state->OnWMEvent(&snap_right);
   EXPECT_EQ(WindowStateType::kSecondarySnapped, w2_state->GetStateType());
   EXPECT_EQ(0.5f, *w1_state->snap_ratio());
@@ -767,11 +767,11 @@
   // over the edge and both `kMultiWindowResizerShow` and
   // `kMultiWindowResizerShowTwoWindowsSnapped` will be recorded.
   WindowState* w1_state = WindowState::Get(w1.get());
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   w1_state->OnWMEvent(&snap_left);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, w1_state->GetStateType());
   WindowState* w2_state = WindowState::Get(w2.get());
-  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   w2_state->OnWMEvent(&snap_right);
   EXPECT_EQ(WindowStateType::kSecondarySnapped, w2_state->GetStateType());
   EXPECT_EQ(0.5f, *w1_state->snap_ratio());
@@ -876,11 +876,11 @@
 
   // Snap two windows
   WindowState* w1_state = WindowState::Get(w1.get());
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   w1_state->OnWMEvent(&snap_left);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, w1_state->GetStateType());
   WindowState* w2_state = WindowState::Get(w2.get());
-  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   w2_state->OnWMEvent(&snap_right);
   EXPECT_EQ(WindowStateType::kSecondarySnapped, w2_state->GetStateType());
 
diff --git a/ash/wm/workspace/workspace_event_handler_unittest.cc b/ash/wm/workspace/workspace_event_handler_unittest.cc
index 85922493..f7a4d3d5 100644
--- a/ash/wm/workspace/workspace_event_handler_unittest.cc
+++ b/ash/wm/workspace/workspace_event_handler_unittest.cc
@@ -222,7 +222,7 @@
                                       .work_area();
 
   WindowState* window_state = WindowState::Get(window.get());
-  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
 
   gfx::Rect snapped_bounds_in_screen = window->GetBoundsInScreen();
@@ -371,7 +371,7 @@
   EXPECT_EQ(restore_bounds.ToString(), window->bounds().ToString());
 
   // 3) Double clicking a snapped window should maximize.
-  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   EXPECT_TRUE(window_state->IsSnapped());
   generator.MoveMouseTo(window->GetBoundsInRootWindow().CenterPoint());
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index cfa3b70..0442ef88 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -595,7 +595,7 @@
   auto insets = gfx::Insets::TLBR(0, 0, 56, 0);
   WorkAreaInsets::ForWindow(window.get())
       ->UpdateWorkAreaInsetsForTest(window.get(), gfx::Rect(), insets, insets);
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   const gfx::Rect kWorkAreaBounds = GetPrimaryDisplay().work_area();
@@ -630,7 +630,7 @@
   std::unique_ptr<aura::Window> window1(
       CreateTestWindow(gfx::Rect(10, 20, 100, 200)));
   WindowState* window1_state = WindowState::Get(window1.get());
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window1_state->OnWMEvent(&snap_left);
   const gfx::Rect work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
@@ -641,7 +641,7 @@
   std::unique_ptr<aura::Window> window2(
       CreateTestWindow(gfx::Rect(10, 20, 100, 200)));
   WindowState* window2_state = WindowState::Get(window2.get());
-  const WMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
+  const WindowSnapWMEvent snap_right(WM_EVENT_SNAP_SECONDARY);
   window2_state->OnWMEvent(&snap_right);
   const gfx::Rect expected_right_snapped_bounds =
       gfx::Rect(work_area.right() - work_area.width() / 2, work_area.y(),
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 2e110dc..c526d29 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -861,18 +861,18 @@
     WMEventType type;
     switch (snap_type_) {
       case SnapType::kPrimary: {
-        window_state()->set_snap_action_source(
-            WindowSnapActionSource::kDragWindowToEdgeToSnap);
         base::RecordAction(base::UserMetricsAction("WindowDrag_MaximizeLeft"));
-        const WMEvent snap_primary_event(WM_EVENT_SNAP_PRIMARY);
+        const WindowSnapWMEvent snap_primary_event(
+            WM_EVENT_SNAP_PRIMARY,
+            WindowSnapActionSource::kDragWindowToEdgeToSnap);
         window_state()->OnWMEvent(&snap_primary_event);
         return;
       }
       case SnapType::kSecondary: {
-        window_state()->set_snap_action_source(
-            WindowSnapActionSource::kDragWindowToEdgeToSnap);
         base::RecordAction(base::UserMetricsAction("WindowDrag_MaximizeRight"));
-        const WMEvent snap_secondary_event(WM_EVENT_SNAP_SECONDARY);
+        const WindowSnapWMEvent snap_secondary_event(
+            WM_EVENT_SNAP_SECONDARY,
+            WindowSnapActionSource::kDragWindowToEdgeToSnap);
         window_state()->OnWMEvent(&snap_secondary_event);
         return;
       }
@@ -1707,20 +1707,20 @@
     case WindowStateType::kPrimarySnapped:
       if (window_state->CanSnap()) {
         window_state->SetRestoreBoundsInParent(restore_bounds_for_gesture_);
-        window_state->set_snap_action_source(
-            WindowSnapActionSource::kDragWindowToEdgeToSnap);
 
-        const WMEvent event(WM_EVENT_SNAP_PRIMARY);
+        const WindowSnapWMEvent event(
+            WM_EVENT_SNAP_PRIMARY,
+            WindowSnapActionSource::kDragWindowToEdgeToSnap);
         window_state->OnWMEvent(&event);
       }
       break;
     case WindowStateType::kSecondarySnapped:
       if (window_state->CanSnap()) {
         window_state->SetRestoreBoundsInParent(restore_bounds_for_gesture_);
-        window_state->set_snap_action_source(
-            WindowSnapActionSource::kDragWindowToEdgeToSnap);
 
-        const WMEvent event(WM_EVENT_SNAP_SECONDARY);
+        const WindowSnapWMEvent event(
+            WM_EVENT_SNAP_SECONDARY,
+            WindowSnapActionSource::kDragWindowToEdgeToSnap);
         window_state->OnWMEvent(&event);
       }
       break;
diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc
index e9d24b26..659c25b 100644
--- a/ash/wm/workspace/workspace_window_resizer_unittest.cc
+++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc
@@ -657,7 +657,7 @@
   window_->Show();
   AllowSnap(window_.get());
 
-  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   gfx::Rect snapped_bounds = window_->bounds();
@@ -682,7 +682,7 @@
   window_->SetBounds(kInitialBounds);
   window_->Show();
 
-  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   gfx::Rect snapped_bounds = window_->bounds();
@@ -740,7 +740,7 @@
   window_->Show();
 
   // Snap the window to the left.
-  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   gfx::Rect snapped_bounds = window_->bounds();
 
@@ -2213,7 +2213,7 @@
   EXPECT_EQ(window_size, touch_resize_window_->bounds().size());
 
   // Snap a window and do the same test.
-  const WMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_event);
   ASSERT_TRUE(window_state->IsSnapped());
   const gfx::Rect snapped_bounds = window_state->window()->bounds();
@@ -2626,7 +2626,7 @@
   const gfx::Rect work_area =
       screen_util::GetDisplayWorkAreaBoundsInParent(window_.get());
 
-  const WMEvent snap_top(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_top(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_top);
   EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state->GetStateType());
   gfx::Rect expected_snap_bounds =
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index 60cdfb55..87e8d83 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -1283,7 +1283,7 @@
 
   // Left snap |window|.
   EXPECT_FALSE(window_state->bounds_changed_by_user());
-  const WMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent snap_left(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&snap_left);
   const gfx::Rect work_area =
       display::Screen::GetScreen()
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 1b938cb0..8f13e51 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -661,6 +661,7 @@
     "strings/stringprintf.cc",
     "strings/stringprintf.h",
     "strings/sys_string_conversions.h",
+    "strings/to_string.h",
     "strings/utf_offset_string_conversions.cc",
     "strings/utf_offset_string_conversions.h",
     "strings/utf_string_conversion_utils.cc",
@@ -934,6 +935,7 @@
     "types/optional_util.h",
     "types/pass_key.h",
     "types/strong_alias.h",
+    "types/supports_ostream_operator.h",
     "types/token_type.h",
     "types/variant_util.h",
     "unguessable_token.cc",
@@ -3266,6 +3268,7 @@
     "strings/stringize_macros_unittest.cc",
     "strings/stringprintf_unittest.cc",
     "strings/sys_string_conversions_unittest.cc",
+    "strings/to_string_test.cc",
     "strings/utf_offset_string_conversions_unittest.cc",
     "strings/utf_string_conversions_unittest.cc",
     "substring_set_matcher/string_pattern_unittest.cc",
@@ -3399,6 +3402,7 @@
     "types/optional_util_unittest.cc",
     "types/pass_key_unittest.cc",
     "types/strong_alias_unittest.cc",
+    "types/supports_ostream_operator_test.cc",
     "types/token_type_unittest.cc",
     "types/variant_util_unittest.cc",
     "unguessable_token_unittest.cc",
diff --git a/base/allocator/partition_alloc_support.cc b/base/allocator/partition_alloc_support.cc
index 85dec3de..d2d56a9a 100644
--- a/base/allocator/partition_alloc_support.cc
+++ b/base/allocator/partition_alloc_support.cc
@@ -39,6 +39,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
+#include "base/system/sys_info.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/thread_annotations.h"
 #include "base/threading/platform_thread.h"
@@ -1199,7 +1200,7 @@
 
 #if BUILDFLAG(IS_ANDROID)
   // Lower thread cache limits to avoid stranding too much memory in the caches.
-  if (base::SysInfo::IsLowEndDevice()) {
+  if (base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled()) {
     ::partition_alloc::ThreadCacheRegistry::Instance().SetThreadCacheMultiplier(
         ::partition_alloc::ThreadCache::kDefaultMultiplier / 2.);
   }
diff --git a/base/check_op.h b/base/check_op.h
index 07ad07d..d323229f 100644
--- a/base/check_op.h
+++ b/base/check_op.h
@@ -15,6 +15,7 @@
 #include "base/debug/debugging_buildflags.h"
 #include "base/memory/raw_ptr_exclusion.h"
 #include "base/template_util.h"
+#include "base/types/supports_ostream_operator.h"
 
 // This header defines the (DP)CHECK_EQ etc. macros.
 //
diff --git a/base/debug/dump_without_crashing.h b/base/debug/dump_without_crashing.h
index d5d014d5..d3fc807a 100644
--- a/base/debug/dump_without_crashing.h
+++ b/base/debug/dump_without_crashing.h
@@ -65,8 +65,11 @@
 // using base::FastHash to generate the hash.
 // `location` Location of the file from where the function is called.
 // `time_between_dumps` Time until the next dump should be captured.
-// Note: The unique identifier, as of now, is not comparable across different
-// runs or builds and is stable only for a process lifetime.
+// Note:
+// - The unique identifier, as of now, is not comparable across different
+//   runs or builds and is stable only for a process lifetime.
+// - The unique identifier is not recorded in the crash report. See
+//   crash_logging.h for such a purpose.
 NOT_TAIL_CALLED BASE_EXPORT bool DumpWithoutCrashingWithUniqueId(
     size_t unique_identifier,
     const base::Location& location = base::Location::Current(),
diff --git a/base/features.cc b/base/features.cc
index a94eadb8f..48f2401 100644
--- a/base/features.cc
+++ b/base/features.cc
@@ -22,4 +22,19 @@
              "SupportsUserDataFlatHashMap",
              FEATURE_DISABLED_BY_DEFAULT);
 
+#if BUILDFLAG(IS_ANDROID)
+// Force to enable LowEndDeviceMode partially on Android mid-range devices.
+// Such devices aren't considered low-end, but we'd like experiment with
+// a subset of low-end features to see if we get a good memory vs. performance
+// tradeoff.
+//
+// TODO(crbug.com/1434873): |#if| out 32-bit before launching or going to
+// high Stable %, because we will enable the feature only for <8GB 64-bit
+// devices, where we didn't ship yet. However, we first need a larger
+// population to collect data.
+BASE_FEATURE(kPartialLowEndModeOnMidRangeDevices,
+             "PartialLowEndModeOnMidRangeDevices",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#endif  // BUILDFLAG(IS_ANDROID)
+
 }  // namespace base::features
diff --git a/base/features.h b/base/features.h
index c61e07c..ccd15327 100644
--- a/base/features.h
+++ b/base/features.h
@@ -20,6 +20,10 @@
 
 BASE_EXPORT BASE_DECLARE_FEATURE(kSupportsUserDataFlatHashMap);
 
+#if BUILDFLAG(IS_ANDROID)
+BASE_EXPORT BASE_DECLARE_FEATURE(kPartialLowEndModeOnMidRangeDevices);
+#endif
+
 }  // namespace base::features
 
 #endif  // BASE_FEATURES_H_
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 120ffb2..0367af55 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -13,8 +13,6 @@
 #include <stdint.h>
 
 #include <initializer_list>
-#include <memory>
-#include <sstream>
 #include <string>
 #include <type_traits>
 #include <vector>
@@ -26,7 +24,6 @@
 #include "base/cxx20_to_address.h"
 #include "base/strings/string_piece.h"  // For implicit conversions.
 #include "base/strings/string_util_internal.h"
-#include "base/template_util.h"
 #include "build/build_config.h"
 
 namespace base {
@@ -116,93 +113,6 @@
   return MakeBasicStringPiece<wchar_t>(begin, end);
 }
 
-// Convert a type with defined `operator<<` or `.ToString()` method into a
-// string.
-
-// I/O manipulators are function pointers, but should be sent directly to the
-// `ostream` instead of being cast to `const void*` like other function
-// pointers.
-template <typename T, typename = void>
-constexpr bool IsIomanip = false;
-template <typename T>
-constexpr bool
-    IsIomanip<T&(T&), std::enable_if_t<std::is_base_of_v<std::ios_base, T>>> =
-        true;
-
-// Function pointers implicitly convert to `bool`, so use this to avoid printing
-// function pointers as 1 or 0.
-template <typename T, typename = void>
-constexpr bool WillBeIncorrectlyStreamedAsBool = false;
-template <typename T>
-constexpr bool WillBeIncorrectlyStreamedAsBool<
-    T,
-    std::enable_if_t<std::is_function_v<typename std::remove_pointer_t<T>> &&
-                     !IsIomanip<typename std::remove_pointer_t<T>>>> = true;
-
-// Fallback case when there is no better representation.
-template <typename T, typename = void>
-struct ToStringHelper {
-  static void Stringify(const T& v, std::ostringstream& ss) {
-    ss << "[" << sizeof(v) << "-byte object at 0x" << std::addressof(v) << "]";
-  }
-};
-
-// Most streamables.
-template <typename T>
-struct ToStringHelper<
-    T,
-    std::enable_if_t<base::internal::SupportsOstreamOperator<const T&>::value &&
-                     !WillBeIncorrectlyStreamedAsBool<T>>> {
-  static void Stringify(const T& v, std::ostringstream& ss) { ss << v; }
-};
-
-// Functions and function pointers.
-template <typename T>
-struct ToStringHelper<
-    T,
-    std::enable_if_t<base::internal::SupportsOstreamOperator<const T&>::value &&
-                     WillBeIncorrectlyStreamedAsBool<T>>> {
-  static void Stringify(const T& v, std::ostringstream& ss) {
-    ToStringHelper<const void*>::Stringify(reinterpret_cast<const void*>(v),
-                                           ss);
-  }
-};
-
-// Non-streamables that have a `ToString` member.
-template <typename T>
-struct ToStringHelper<
-    T,
-    std::enable_if_t<
-        !base::internal::SupportsOstreamOperator<const T&>::value &&
-        base::internal::SupportsToString<const T&>::value>> {
-  static void Stringify(const T& v, std::ostringstream& ss) {
-    // .ToString() may not return a std::string, e.g. blink::WTF::String.
-    ToStringHelper<decltype(v.ToString())>::Stringify(v.ToString(), ss);
-  }
-};
-
-// Non-streamable enums (i.e. scoped enums where no `operator<<` overload was
-// declared).
-template <typename T>
-struct ToStringHelper<T,
-                      std::enable_if_t<!base::internal::SupportsOstreamOperator<
-                                           const T&>::value &&
-                                       std::is_enum_v<T>>> {
-  static void Stringify(const T& v, std::ostringstream& ss) {
-    using UT = typename std::underlying_type_t<T>;
-    ToStringHelper<UT>::Stringify(static_cast<UT>(v), ss);
-  }
-};
-
-template <typename... Ts>
-std::string ToString(const Ts&... values) {
-  std::ostringstream ss;
-  (ToStringHelper<typename std::remove_cvref_t<decltype(values)>>::Stringify(
-       values, ss),
-   ...);
-  return ss.str();
-}
-
 // ASCII-specific tolower.  The standard library's tolower is locale sensitive,
 // so we don't want to use it here.
 template <typename CharT,
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index aba0e31..4bb22e5 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -1351,80 +1351,6 @@
   EXPECT_TRUE(MakeWStringPiece(baz.end(), baz.end()).empty());
 }
 
-enum class StreamableTestEnum { kGreeting, kLocation };
-enum class NonStreamableTestEnum { kGreeting = 0, kLocation };
-
-std::ostream& operator<<(std::ostream& os, const StreamableTestEnum& value) {
-  switch (value) {
-    case StreamableTestEnum::kGreeting:
-      return os << "hello";
-    case StreamableTestEnum::kLocation:
-      return os << "world";
-  }
-}
-
-class HasToString {
- public:
-  std::string ToString() const { return "yay!"; }
-};
-
-class UnusualToString {
- public:
-  HasToString ToString() const { return HasToString(); }
-};
-
-void Func() {}
-
-class NotStringifiable {};
-
-class OverloadsAddressOp {
- public:
-  OverloadsAddressOp* operator&() { return nullptr; }
-  const OverloadsAddressOp* operator&() const { return nullptr; }
-};
-
-TEST(StringUtilTest, ToString) {
-  // Types with built-in <<.
-  EXPECT_EQ(ToString("foo"), "foo");
-  EXPECT_EQ(ToString(123), "123");
-
-  // Type with user-defined <<.
-  EXPECT_EQ(ToString(StreamableTestEnum::kGreeting), "hello");
-  EXPECT_EQ(ToString(StreamableTestEnum::kGreeting, " ",
-                     StreamableTestEnum::kLocation),
-            "hello world");
-
-  // Type with user-defined ToString().
-  EXPECT_EQ(ToString(HasToString()), "yay!");
-
-  // Types with a ToString() that does not directly return a std::string should
-  // still work.
-  EXPECT_EQ(ToString(UnusualToString()), "yay!");
-
-  // Scoped enums without a defined << should print as their underlying type.
-  EXPECT_EQ(ToString(NonStreamableTestEnum::kLocation), "1");
-
-  // I/O manipulators should have their expected effect, not be printed as
-  // function pointers.
-  EXPECT_EQ(ToString("42 in hex is ", std::hex, 42), "42 in hex is 2a");
-
-  // We don't care about the actual address, but a function pointer should not
-  // be implicitly converted to bool.
-  EXPECT_NE(ToString(&Func), ToString(true));
-
-  // Functions should be treated like function pointers.
-  EXPECT_EQ(ToString(Func), ToString(&Func));
-
-  // Non-stringifiable types should be printed using a fallback.
-  EXPECT_NE(ToString(NotStringifiable()).find("-byte object at 0x"),
-            std::string::npos);
-
-  // Non-stringifiable types which overload operator& should print their real
-  // address.
-  EXPECT_NE(ToString(OverloadsAddressOp()),
-            ToString(static_cast<OverloadsAddressOp*>(nullptr)));
-}
-
 TEST(StringUtilTest, RemoveChars) {
   const char kRemoveChars[] = "-/+*";
   std::string input = "A-+bc/d!*";
diff --git a/base/strings/to_string.h b/base/strings/to_string.h
new file mode 100644
index 0000000..216963e
--- /dev/null
+++ b/base/strings/to_string.h
@@ -0,0 +1,110 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_TO_STRING_H_
+#define BASE_STRINGS_TO_STRING_H_
+
+#include <ios>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "base/template_util.h"
+#include "base/types/supports_ostream_operator.h"
+
+namespace base {
+
+namespace internal {
+
+// I/O manipulators are function pointers, but should be sent directly to the
+// `ostream` instead of being cast to `const void*` like other function
+// pointers.
+template <typename T, typename = void>
+constexpr bool IsIomanip = false;
+template <typename T>
+constexpr bool
+    IsIomanip<T&(T&), std::enable_if_t<std::is_base_of_v<std::ios_base, T>>> =
+        true;
+
+// Function pointers implicitly convert to `bool`, so use this to avoid printing
+// function pointers as 1 or 0.
+template <typename T, typename = void>
+constexpr bool WillBeIncorrectlyStreamedAsBool = false;
+template <typename T>
+constexpr bool WillBeIncorrectlyStreamedAsBool<
+    T,
+    std::enable_if_t<std::is_function_v<std::remove_pointer_t<T>> &&
+                     !IsIomanip<std::remove_pointer_t<T>>>> = true;
+
+// Fallback case when there is no better representation.
+template <typename T, typename = void>
+struct ToStringHelper {
+  static void Stringify(const T& v, std::ostringstream& ss) {
+    ss << "[" << sizeof(v) << "-byte object at 0x" << std::addressof(v) << "]";
+  }
+};
+
+// Most streamables.
+template <typename T>
+struct ToStringHelper<
+    T,
+    std::enable_if_t<SupportsOstreamOperator<const T&>::value &&
+                     !WillBeIncorrectlyStreamedAsBool<T>>> {
+  static void Stringify(const T& v, std::ostringstream& ss) { ss << v; }
+};
+
+// Functions and function pointers.
+template <typename T>
+struct ToStringHelper<
+    T,
+    std::enable_if_t<SupportsOstreamOperator<const T&>::value &&
+                     WillBeIncorrectlyStreamedAsBool<T>>> {
+  static void Stringify(const T& v, std::ostringstream& ss) {
+    ToStringHelper<const void*>::Stringify(reinterpret_cast<const void*>(v),
+                                           ss);
+  }
+};
+
+// Non-streamables that have a `ToString` member.
+template <typename T>
+struct ToStringHelper<
+    T,
+    std::enable_if_t<!SupportsOstreamOperator<const T&>::value &&
+                     SupportsToString<const T&>::value>> {
+  static void Stringify(const T& v, std::ostringstream& ss) {
+    // .ToString() may not return a std::string, e.g. blink::WTF::String.
+    ToStringHelper<decltype(v.ToString())>::Stringify(v.ToString(), ss);
+  }
+};
+
+// Non-streamable enums (i.e. scoped enums where no `operator<<` overload was
+// declared).
+template <typename T>
+struct ToStringHelper<
+    T,
+    std::enable_if_t<!SupportsOstreamOperator<const T&>::value &&
+                     std::is_enum_v<T>>> {
+  static void Stringify(const T& v, std::ostringstream& ss) {
+    using UT = typename std::underlying_type_t<T>;
+    ToStringHelper<UT>::Stringify(static_cast<UT>(v), ss);
+  }
+};
+
+}  // namespace internal
+
+// Converts any type to a string, preferring defined operator<<() or ToString()
+// methods if they exist.
+template <typename... Ts>
+std::string ToString(const Ts&... values) {
+  std::ostringstream ss;
+  (internal::ToStringHelper<remove_cvref_t<decltype(values)>>::Stringify(values,
+                                                                         ss),
+   ...);
+  return ss.str();
+}
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_TO_STRING_H_
diff --git a/base/strings/to_string_test.cc b/base/strings/to_string_test.cc
new file mode 100644
index 0000000..7938205
--- /dev/null
+++ b/base/strings/to_string_test.cc
@@ -0,0 +1,106 @@
+// Copyright 2023 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/strings/to_string.h"
+
+#include <ios>
+#include <ostream>
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(ToStringTest, Streamable) {
+  // Types with built-in <<.
+  EXPECT_EQ(ToString("foo"), "foo");
+  EXPECT_EQ(ToString(123), "123");
+}
+
+enum class StreamableTestEnum { kGreeting, kLocation };
+
+std::ostream& operator<<(std::ostream& os, const StreamableTestEnum& value) {
+  switch (value) {
+    case StreamableTestEnum::kGreeting:
+      return os << "hello";
+    case StreamableTestEnum::kLocation:
+      return os << "world";
+  }
+}
+
+TEST(ToStringTest, UserDefinedStreamable) {
+  // Type with user-defined <<.
+  EXPECT_EQ(ToString(StreamableTestEnum::kGreeting), "hello");
+  EXPECT_EQ(ToString(StreamableTestEnum::kGreeting, " ",
+                     StreamableTestEnum::kLocation),
+            "hello world");
+}
+
+class HasToString {
+ public:
+  std::string ToString() const { return "yay!"; }
+};
+
+TEST(ToStringTest, UserDefinedToString) {
+  // Type with user-defined ToString().
+  EXPECT_EQ(ToString(HasToString()), "yay!");
+}
+
+class UnusualToString {
+ public:
+  HasToString ToString() const { return HasToString(); }
+};
+
+TEST(ToStringTest, ToStringReturnsNonStdString) {
+  // Types with a ToString() that does not directly return a std::string should
+  // still work.
+  EXPECT_EQ(ToString(UnusualToString()), "yay!");
+}
+
+enum class NonStreamableTestEnum { kGreeting = 0, kLocation };
+
+TEST(ToStringTest, ScopedEnum) {
+  // Scoped enums without a defined << should print as their underlying type.
+  EXPECT_EQ(ToString(NonStreamableTestEnum::kLocation), "1");
+}
+
+TEST(ToStringTest, IoManip) {
+  // I/O manipulators should have their expected effect, not be printed as
+  // function pointers.
+  EXPECT_EQ(ToString("42 in hex is ", std::hex, 42), "42 in hex is 2a");
+}
+
+void Func() {}
+
+TEST(ToStringTest, FunctionPointer) {
+  // We don't care about the actual address, but a function pointer should not
+  // be implicitly converted to bool.
+  EXPECT_NE(ToString(&Func), ToString(true));
+
+  // Functions should be treated like function pointers.
+  EXPECT_EQ(ToString(Func), ToString(&Func));
+}
+
+class NotStringifiable {};
+
+class OverloadsAddressOp {
+ public:
+  OverloadsAddressOp* operator&() { return nullptr; }
+  const OverloadsAddressOp* operator&() const { return nullptr; }
+};
+
+TEST(ToStringTest, NonStringifiable) {
+  // Non-stringifiable types should be printed using a fallback.
+  EXPECT_NE(ToString(NotStringifiable()).find("-byte object at 0x"),
+            std::string::npos);
+
+  // Non-stringifiable types which overload operator& should print their real
+  // address.
+  EXPECT_NE(ToString(OverloadsAddressOp()),
+            ToString(static_cast<OverloadsAddressOp*>(nullptr)));
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/system/sys_info.cc b/base/system/sys_info.cc
index 2c5bfc9..9d52ed32 100644
--- a/base/system/sys_info.cc
+++ b/base/system/sys_info.cc
@@ -8,6 +8,7 @@
 
 #include "base/base_switches.h"
 #include "base/command_line.h"
+#include "base/features.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/location.h"
@@ -76,6 +77,47 @@
   return IsLowEndDeviceImpl();
 }
 
+#if BUILDFLAG(IS_ANDROID)
+
+namespace {
+
+bool IsAndroid4GbOr6GbDevice() {
+  // Because of Android carveouts, AmountOfPhysicalMemory() returns smaller
+  // than the actual memory size, So we will use a small lowerbound than 4GB
+  // to discriminate real 4GB devices from lower memory ones.
+  constexpr int kLowerBoundMB = 3.2 * 1024;
+  constexpr int kUpperBoundMB = 6 * 1024;
+  static bool is_4gb_or_6g_device =
+      kLowerBoundMB <= base::SysInfo::AmountOfPhysicalMemoryMB() &&
+      base::SysInfo::AmountOfPhysicalMemoryMB() <= kUpperBoundMB;
+  return is_4gb_or_6g_device;
+}
+
+bool IsPartialLowEndModeOnMidRangeDevicesEnabled() {
+  // TODO(crbug.com/1434873): make the feature not enable on 32-bit devices
+  // before launching or going to high Stable %.
+  return IsAndroid4GbOr6GbDevice() &&
+         base::FeatureList::IsEnabled(
+             features::kPartialLowEndModeOnMidRangeDevices);
+}
+
+}  // namespace
+
+#endif  // BUILDFLAG(IS_ANDROID)
+
+// TODO(crbug.com/1434873): This method is for chromium native code.
+// We need to update the java-side code, i.e.
+// base/android/java/src/org/chromium/base/SysUtils.java,
+// and to make the selected components in java to see this feature.
+bool SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled() {
+#if BUILDFLAG(IS_ANDROID)
+  return base::SysInfo::IsLowEndDevice() ||
+         IsPartialLowEndModeOnMidRangeDevicesEnabled();
+#else
+  return base::SysInfo::IsLowEndDevice();
+#endif
+}
+
 #if !BUILDFLAG(IS_ANDROID)
 // The Android equivalent of this lives in `detectLowEndDevice()` at:
 // base/android/java/src/org/chromium/base/SysUtils.java
diff --git a/base/system/sys_info.h b/base/system/sys_info.h
index 94389b0..02f3006 100644
--- a/base/system/sys_info.h
+++ b/base/system/sys_info.h
@@ -238,6 +238,14 @@
   // On Desktop this returns true when memory <= 2GB.
   static bool IsLowEndDevice();
 
+  // The same as IsLowEndDevice() except on Android.
+  //
+  // On Android this returns:
+  //   true when IsLowEndDevice() returns true.
+  //   true when the physical memory of the device is 4gb or 6gb and
+  //             the feature: kPartialLowEndModeOnMidEndDevices() is enabled.
+  static bool IsLowEndDeviceOrPartialLowEndModeEnabled();
+
 #if BUILDFLAG(IS_MAC)
   // Sets whether CPU security mitigations are enabled for the current process.
   // This is used to control the behavior of NumberOfProcessors(), see comment
diff --git a/base/template_util.h b/base/template_util.h
index 415b3ac..e192110 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -18,15 +18,6 @@
 
 namespace internal {
 
-// Uses expression SFINAE to detect whether using operator<< would work.
-template <typename T, typename = void>
-struct SupportsOstreamOperator : std::false_type {};
-template <typename T>
-struct SupportsOstreamOperator<T,
-                               decltype(void(std::declval<std::ostream&>()
-                                             << std::declval<T>()))>
-    : std::true_type {};
-
 template <typename T, typename = void>
 struct SupportsToString : std::false_type {};
 template <typename T>
diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc
index 2774b5cac..efcea3d 100644
--- a/base/template_util_unittest.cc
+++ b/base/template_util_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "base/template_util.h"
 
+#include <stdint.h>
+
 #include <string>
 #include <type_traits>
 
@@ -17,58 +19,11 @@
 enum SimpleEnum { SIMPLE_ENUM };
 enum EnumWithExplicitType : uint64_t { ENUM_WITH_EXPLICIT_TYPE };
 enum class ScopedEnum { SCOPED_ENUM };
-enum class ScopedEnumWithOperator { SCOPED_ENUM_WITH_OPERATOR };
-std::ostream& operator<<(std::ostream& os, ScopedEnumWithOperator v) {
-  return os;
-}
 struct SimpleStruct {};
-struct StructWithOperator {};
-std::ostream& operator<<(std::ostream& os, const StructWithOperator& v) {
-  return os;
-}
 struct StructWithToString {
   std::string ToString() const { return ""; }
 };
 
-// A few standard types that definitely support printing.
-static_assert(internal::SupportsOstreamOperator<int>::value,
-              "ints should be printable");
-static_assert(internal::SupportsOstreamOperator<const char*>::value,
-              "C strings should be printable");
-static_assert(internal::SupportsOstreamOperator<std::string>::value,
-              "std::string should be printable");
-
-// Various kinds of enums operator<< support.
-static_assert(internal::SupportsOstreamOperator<SimpleEnum>::value,
-              "simple enum should be printable by value");
-static_assert(internal::SupportsOstreamOperator<const SimpleEnum&>::value,
-              "simple enum should be printable by const ref");
-static_assert(internal::SupportsOstreamOperator<EnumWithExplicitType>::value,
-              "enum with explicit type should be printable by value");
-static_assert(
-    internal::SupportsOstreamOperator<const EnumWithExplicitType&>::value,
-    "enum with explicit type should be printable by const ref");
-static_assert(!internal::SupportsOstreamOperator<ScopedEnum>::value,
-              "scoped enum should not be printable by value");
-static_assert(!internal::SupportsOstreamOperator<const ScopedEnum&>::value,
-              "simple enum should not be printable by const ref");
-static_assert(internal::SupportsOstreamOperator<ScopedEnumWithOperator>::value,
-              "scoped enum with operator<< should be printable by value");
-static_assert(
-    internal::SupportsOstreamOperator<const ScopedEnumWithOperator&>::value,
-    "scoped enum with operator<< should be printable by const ref");
-
-// operator<< support on structs.
-static_assert(!internal::SupportsOstreamOperator<SimpleStruct>::value,
-              "simple struct should not be printable by value");
-static_assert(!internal::SupportsOstreamOperator<const SimpleStruct&>::value,
-              "simple struct should not be printable by const ref");
-static_assert(internal::SupportsOstreamOperator<StructWithOperator>::value,
-              "struct with operator<< should be printable by value");
-static_assert(
-    internal::SupportsOstreamOperator<const StructWithOperator&>::value,
-    "struct with operator<< should be printable by const ref");
-
 // .ToString() support on structs.
 static_assert(!internal::SupportsToString<SimpleStruct>::value,
               "simple struct value doesn't support .ToString()");
diff --git a/base/types/strong_alias.h b/base/types/strong_alias.h
index 8a757be..7a4872a4 100644
--- a/base/types/strong_alias.h
+++ b/base/types/strong_alias.h
@@ -9,8 +9,8 @@
 #include <type_traits>
 #include <utility>
 
-#include "base/template_util.h"
 #include "base/trace_event/base_tracing_forward.h"
+#include "base/types/supports_ostream_operator.h"
 
 namespace base {
 
@@ -154,7 +154,7 @@
 template <typename TagType,
           typename UnderlyingType,
           typename = std::enable_if_t<
-              base::internal::SupportsOstreamOperator<UnderlyingType>::value>>
+              internal::SupportsOstreamOperator<UnderlyingType>::value>>
 std::ostream& operator<<(std::ostream& stream,
                          const StrongAlias<TagType, UnderlyingType>& alias) {
   return stream << alias.value();
diff --git a/base/types/strong_alias_unittest.cc b/base/types/strong_alias_unittest.cc
index 6cc211a..7ab1444 100644
--- a/base/types/strong_alias_unittest.cc
+++ b/base/types/strong_alias_unittest.cc
@@ -14,7 +14,7 @@
 #include <utility>
 
 #include "base/strings/string_piece.h"
-#include "base/template_util.h"
+#include "base/types/supports_ostream_operator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(ENABLE_BASE_TRACING)
@@ -371,8 +371,7 @@
 void StreamOperatorExists() {
   // Aliases of ints should be streamable because ints are streamable.
   using StreamableAlias = StrongAlias<class IntTag, int>;
-  static_assert(base::internal::SupportsOstreamOperator<StreamableAlias>::value,
-                "");
+  static_assert(internal::SupportsOstreamOperator<StreamableAlias>::value);
 
   // Aliases of a class which does not expose a stream operator should
   // themselves not be streamable.
@@ -381,8 +380,7 @@
     Scope() = default;
   };
   using NonStreamableAlias = StrongAlias<class ScopeTag, Scope>;
-  static_assert(
-      !base::internal::SupportsOstreamOperator<NonStreamableAlias>::value, "");
+  static_assert(!internal::SupportsOstreamOperator<NonStreamableAlias>::value);
 }
 
 #if BUILDFLAG(ENABLE_BASE_TRACING)
diff --git a/base/types/supports_ostream_operator.h b/base/types/supports_ostream_operator.h
new file mode 100644
index 0000000..0803db4
--- /dev/null
+++ b/base/types/supports_ostream_operator.h
@@ -0,0 +1,28 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TYPES_SUPPORTS_OSTREAM_OPERATOR_H_
+#define BASE_TYPES_SUPPORTS_OSTREAM_OPERATOR_H_
+
+#include <ostream>
+#include <type_traits>
+#include <utility>
+
+namespace base::internal {
+
+// Uses expression SFINAE to detect whether using operator<< would work.
+//
+// Note that the above #include of <ostream> is necessary to guarantee
+// consistent results here for basic types.
+template <typename T, typename = void>
+struct SupportsOstreamOperator : std::false_type {};
+template <typename T>
+struct SupportsOstreamOperator<T,
+                               decltype(void(std::declval<std::ostream&>()
+                                             << std::declval<T>()))>
+    : std::true_type {};
+
+}  // namespace base::internal
+
+#endif  // BASE_TYPES_SUPPORTS_OSTREAM_OPERATOR_H_
diff --git a/base/types/supports_ostream_operator_test.cc b/base/types/supports_ostream_operator_test.cc
new file mode 100644
index 0000000..0f8c3a0
--- /dev/null
+++ b/base/types/supports_ostream_operator_test.cc
@@ -0,0 +1,68 @@
+// Copyright 2023 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/types/supports_ostream_operator.h"
+
+#include <stdint.h>
+
+#include <ostream>
+#include <string>
+
+namespace base {
+namespace {
+
+enum SimpleEnum { SIMPLE_ENUM };
+enum EnumWithExplicitType : uint64_t { ENUM_WITH_EXPLICIT_TYPE };
+enum class ScopedEnum { SCOPED_ENUM };
+enum class ScopedEnumWithOperator { SCOPED_ENUM_WITH_OPERATOR };
+std::ostream& operator<<(std::ostream& os, ScopedEnumWithOperator v) {
+  return os;
+}
+struct SimpleStruct {};
+struct StructWithOperator {};
+std::ostream& operator<<(std::ostream& os, const StructWithOperator& v) {
+  return os;
+}
+
+// A few standard types that definitely support printing.
+static_assert(internal::SupportsOstreamOperator<int>::value,
+              "ints should be printable");
+static_assert(internal::SupportsOstreamOperator<const char*>::value,
+              "C strings should be printable");
+static_assert(internal::SupportsOstreamOperator<std::string>::value,
+              "std::string should be printable");
+
+// Various kinds of enums operator<< support.
+static_assert(internal::SupportsOstreamOperator<SimpleEnum>::value,
+              "simple enum should be printable by value");
+static_assert(internal::SupportsOstreamOperator<const SimpleEnum&>::value,
+              "simple enum should be printable by const ref");
+static_assert(internal::SupportsOstreamOperator<EnumWithExplicitType>::value,
+              "enum with explicit type should be printable by value");
+static_assert(
+    internal::SupportsOstreamOperator<const EnumWithExplicitType&>::value,
+    "enum with explicit type should be printable by const ref");
+static_assert(!internal::SupportsOstreamOperator<ScopedEnum>::value,
+              "scoped enum should not be printable by value");
+static_assert(!internal::SupportsOstreamOperator<const ScopedEnum&>::value,
+              "simple enum should not be printable by const ref");
+static_assert(internal::SupportsOstreamOperator<ScopedEnumWithOperator>::value,
+              "scoped enum with operator<< should be printable by value");
+static_assert(
+    internal::SupportsOstreamOperator<const ScopedEnumWithOperator&>::value,
+    "scoped enum with operator<< should be printable by const ref");
+
+// operator<< support on structs.
+static_assert(!internal::SupportsOstreamOperator<SimpleStruct>::value,
+              "simple struct should not be printable by value");
+static_assert(!internal::SupportsOstreamOperator<const SimpleStruct&>::value,
+              "simple struct should not be printable by const ref");
+static_assert(internal::SupportsOstreamOperator<StructWithOperator>::value,
+              "struct with operator<< should be printable by value");
+static_assert(
+    internal::SupportsOstreamOperator<const StructWithOperator&>::value,
+    "struct with operator<< should be printable by const ref");
+
+}  // namespace
+}  // namespace base
diff --git a/build/android/gyp/create_app_bundle.py b/build/android/gyp/create_app_bundle.py
index b07a0df..f34f968 100755
--- a/build/android/gyp/create_app_bundle.py
+++ b/build/android/gyp/create_app_bundle.py
@@ -126,13 +126,30 @@
 
   options = parser.parse_args(args)
   options.module_zips = action_helpers.parse_gn_list(options.module_zips)
+
+  if len(options.module_zips) == 0:
+    parser.error('The module zip list cannot be empty.')
+  if len(options.module_zips) != len(options.module_names):
+    parser.error('# module zips != # names.')
+  if 'base' not in options.module_names:
+    parser.error('Missing base module.')
+
+  # Sort modules for more stable outputs.
+  per_module_values = list(
+      zip(options.module_names, options.module_zips,
+          options.uncompressed_assets, options.rtxt_in_paths,
+          options.pathmap_in_paths))
+  per_module_values.sort(key=lambda x: (x[0] != 'base', x[0]))
+  options.module_names = [x[0] for x in per_module_values]
+  options.module_zips = [x[1] for x in per_module_values]
+  options.uncompressed_assets = [x[2] for x in per_module_values]
+  options.rtxt_in_paths = [x[3] for x in per_module_values]
+  options.pathmap_in_paths = [x[4] for x in per_module_values]
+
   options.rtxt_in_paths = action_helpers.parse_gn_list(options.rtxt_in_paths)
   options.pathmap_in_paths = action_helpers.parse_gn_list(
       options.pathmap_in_paths)
 
-  if len(options.module_zips) == 0:
-    raise Exception('The module zip list cannot be empty.')
-
   # Merge all uncompressed assets into a set.
   uncompressed_list = []
   for entry in action_helpers.parse_gn_list(options.uncompressed_assets):
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 1c13bc8..53db095 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -685,6 +685,7 @@
         "/lldltocache:" +
             rebase_path("$root_out_dir/thinlto-cache", root_build_dir),
         "/lldltocachepolicy:$cache_policy",
+        "-mllvm:-disable-auto-upgrade-debug-info",
       ]
     } else {
       ldflags += [ "-flto=thin" ]
@@ -725,6 +726,14 @@
       }
 
       ldflags += [ "-Wl,-mllvm,-import-instr-limit=$import_instr_limit" ]
+
+      if (!is_chromeos) {
+        # TODO(https://crbug.com/972449): turn on for ChromeOS when that
+        # toolchain has this flag.
+        # We only use one version of LLVM within a build so there's no need to
+        # upgrade debug info, which can be expensive since it runs the verifier.
+        ldflags += [ "-Wl,-mllvm,-disable-auto-upgrade-debug-info" ]
+      }
     }
 
     # TODO(https://crbug.com/1211155): investigate why this isn't effective on
diff --git a/build/config/siso/linux.star b/build/config/siso/linux.star
index 2fa0f1a..d02318e 100644
--- a/build/config/siso/linux.star
+++ b/build/config/siso/linux.star
@@ -6,15 +6,18 @@
 
 load("@builtin//struct.star", "module")
 load("./clang_linux.star", "clang")
+load("./mojo.star", "mojo")
 load("./nacl_linux.star", "nacl")
 load("./remote_exec_wrapper.star", "remote_exec_wrapper")
 
 __filegroups = {}
 __filegroups.update(clang.filegroups)
+__filegroups.update(mojo.filegroups)
 __filegroups.update(nacl.filegroups)
 
 __handlers = {}
 __handlers.update(clang.handlers)
+__handlers.update(mojo.handlers)
 __handlers.update(nacl.handlers)
 
 def __step_config(ctx, step_config):
@@ -28,6 +31,7 @@
         step_config = remote_exec_wrapper.step_config(ctx, step_config)
     else:
         step_config = clang.step_config(ctx, step_config)
+        step_config = mojo.step_config(ctx, step_config)
         step_config = nacl.step_config(ctx, step_config)
     return step_config
 
diff --git a/build/config/siso/mojo.star b/build/config/siso/mojo.star
new file mode 100644
index 0000000..45502e7
--- /dev/null
+++ b/build/config/siso/mojo.star
@@ -0,0 +1,129 @@
+# -*- bazel-starlark -*-
+# Copyright 2023 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.
+"""Siso configuration for mojo."""
+
+load("@builtin//struct.star", "module")
+
+__filegroups = {}
+
+__handlers = {}
+
+def __step_config(ctx, step_config):
+    step_config["rules"].extend([
+        {
+            "name": "mojo/mojom_bindigns_generator",
+            "command_prefix": "python3 ../../mojo/public/tools/bindings/mojom_bindings_generator.py",
+            "inputs": [
+                "mojo/public/tools/bindings/mojom_bindings_generator.py",
+            ],
+            "indirect_inputs": {
+                "includes": [
+                    "*.js",
+                    "*.mojom",
+                    "*.mojom-module",
+                    "*.test-mojom",
+                    "*.test-mojom-module",
+                    "*.zip",
+                ],
+            },
+            "exclude_input_patterns": [
+                "*.stamp",
+            ],
+            # TODO(crbug.com/1437820): unspecified outputs of mojom_bindings_generator.py
+            "outputs_map": {
+                "./gen/components/aggregation_service/aggregation_service.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/components/aggregation_service/aggregation_service.mojom-webui.js",
+                    ],
+                },
+                "./gen/components/attribution_reporting/eligibility_error.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/components/attribution_reporting/eligibility_error.mojom-webui.js",
+                        "./gen/mojom-webui/components/attribution_reporting/registration_type.mojom-webui.js",
+                        "./gen/mojom-webui/components/attribution_reporting/source_registration_error.mojom-webui.js",
+                        "./gen/mojom-webui/components/attribution_reporting/trigger_registration_error.mojom-webui.js",
+                    ],
+                },
+                "./gen/components/attribution_reporting/registration.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/components/attribution_reporting/registration.mojom-webui.js",
+                    ],
+                },
+                "./gen/media/capture/mojom/image_capture.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/media/capture/mojom/image_capture.mojom-webui.js",
+                    ],
+                },
+                "./gen/services/device/public/mojom/usb_device.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/services/device/public/mojom/usb_device.mojom-webui.js",
+                        "./gen/mojom-webui/services/device/public/mojom/usb_enumeration_options.mojom-webui.js",
+                        "./gen/mojom-webui/services/device/public/mojom/usb_manager.mojom-webui.js",
+                        "./gen/mojom-webui/services/device/public/mojom/usb_manager_client.mojom-webui.js",
+                    ],
+                },
+                "./gen/services/media_session/public/mojom/audio_focus.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/services/media_session/public/mojom/audio_focus.mojom-webui.js",
+                        "./gen/mojom-webui/services/media_session/public/mojom/constants.mojom-webui.js",
+                        "./gen/mojom-webui/services/media_session/public/mojom/media_controller.mojom-webui.js",
+                        "./gen/mojom-webui/services/media_session/public/mojom/media_session.mojom-webui.js",
+                    ],
+                },
+                "./gen/services/network/public/mojom/attribution.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/services/network/public/mojom/attribution.mojom-webui.js",
+                    ],
+                },
+                "./gen/services/network/public/mojom/schemeful_site.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/services/network/public/mojom/schemeful_site.mojom-webui.js",
+                    ],
+                },
+                "./gen/third_party/blink/public/mojom/quota/quota_manager_host.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/third_party/blink/public/mojom/quota/quota_manager_host.mojom-webui.js",
+                        "./gen/mojom-webui/third_party/blink/public/mojom/quota/quota_types.mojom-webui.js",
+                    ],
+                },
+                "./gen/third_party/blink/public/mojom/storage_key/ancestor_chain_bit.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/third_party/blink/public/mojom/storage_key/ancestor_chain_bit.mojom-webui.js",
+                        "./gen/mojom-webui/third_party/blink/public/mojom/storage_key/storage_key.mojom-webui.js",
+                    ],
+                },
+                "./gen/ui/base/mojom/ui_base_types.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/ui/base/mojom/ui_base_types.mojom-webui.js",
+                        "./gen/mojom-webui/ui/base/mojom/window_open_disposition.mojom-webui.js",
+                    ],
+                },
+                "./gen/ui/gfx/image/mojom/image.mojom.js": {
+                    "outputs": [
+                        "./gen/mojom-webui/ui/gfx/image/mojom/image.mojom-webui.js",
+                    ],
+                },
+            },
+            "restat": True,
+            "remote": True,
+            "output_local": True,
+            "platform": {
+                # mojo_bindings_generators.py will run faster on n2-highmem-8
+                # than n2-custom-2-3840
+                # e.g.
+                #  n2-highmem-8: exec: 880.202978ms
+                #  n2-custom-2-3840: exec: 2.42808488s
+                "gceMachineType": "n2-highmem-8",
+            },
+        },
+    ])
+    return step_config
+
+mojo = module(
+    "mojo",
+    step_config = __step_config,
+    filegroups = __filegroups,
+    handlers = __handlers,
+)
diff --git a/build/config/siso/remote_exec_wrapper.star b/build/config/siso/remote_exec_wrapper.star
index 96f816ca..dcd5169 100644
--- a/build/config/siso/remote_exec_wrapper.star
+++ b/build/config/siso/remote_exec_wrapper.star
@@ -41,6 +41,11 @@
             "action": "(.*_)?objc",
             "use_remote_exec_wrapper": True,
         },
+        {
+            "name": "action_remote",
+            "command_prefix": "python3 ../../build/util/action_remote.py",
+            "use_remote_exec_wrapper": True,
+        },
     ])
     return step_config
 
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index c9e790a..bf92d5f 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-12.20230424.2.1
+12.20230424.3.1
diff --git a/build/fuchsia/test/run_test.py b/build/fuchsia/test/run_test.py
index 5a2952a..3fc3ac91 100755
--- a/build/fuchsia/test/run_test.py
+++ b/build/fuchsia/test/run_test.py
@@ -64,7 +64,7 @@
     register_device_args(parser)
     register_emulator_args(parser)
     register_executable_test_args(parser)
-    register_update_args(parser, default_os_check='ignore', default_pave=True)
+    register_update_args(parser, default_os_check='ignore', default_pave=False)
     register_log_args(parser)
     register_package_args(parser, allow_temp_repo=True)
     register_serve_args(parser)
diff --git a/build_overrides/tint.gni b/build_overrides/tint.gni
index 9b52393a..08806b0 100644
--- a/build_overrides/tint.gni
+++ b/build_overrides/tint.gni
@@ -2,12 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//skia/features.gni")
+
 tint_root_dir = "//third_party/dawn"
 tint_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src"
 tint_googletest_dir = "//third_party/googletest/src"
 tint_spirv_headers_dir = "//third_party/vulkan-deps/spirv-headers/src"
 
-tint_build_spv_reader = false
+tint_build_spv_reader = skia_use_dawn
 tint_build_spv_writer = true
 tint_build_wgsl_reader = true
 tint_build_wgsl_writer = true
diff --git a/cc/paint/paint_op_buffer_serializer.cc b/cc/paint/paint_op_buffer_serializer.cc
index 0b56c273..7c0de21 100644
--- a/cc/paint/paint_op_buffer_serializer.cc
+++ b/cc/paint/paint_op_buffer_serializer.cc
@@ -50,8 +50,11 @@
 
 PaintOpBufferSerializer::PaintOpBufferSerializer(
     SerializeCallback serialize_cb,
+    void* callback_data,
     const PaintOp::SerializeOptions& options)
-    : serialize_cb_(std::move(serialize_cb)), options_(options) {
+    : serialize_cb_(serialize_cb),
+      callback_data_(callback_data),
+      options_(options) {
   DCHECK(serialize_cb_);
 }
 
@@ -308,9 +311,8 @@
   // correctly for analysis of records in filters.
   PlaybackOnAnalysisCanvas(canvas, op, flags_to_serialize, params);
 
-  size_t bytes =
-      serialize_cb_.Run(op, options_, flags_to_serialize,
-                        canvas->getLocalToDevice(), params.original_ctm);
+  size_t bytes = serialize_cb_(callback_data_, op, options_, flags_to_serialize,
+                               canvas->getLocalToDevice(), params.original_ctm);
   if (!bytes) {
     valid_ = false;
     return false;
@@ -364,16 +366,15 @@
     void* memory,
     size_t size,
     const PaintOp::SerializeOptions& options)
-    : PaintOpBufferSerializer(
-          base::BindRepeating(&SimpleBufferSerializer::SerializeToMemory,
-                              base::Unretained(this)),
-          options),
+    : PaintOpBufferSerializer(&SimpleBufferSerializer::SerializeToMemory,
+                              this,
+                              options),
       memory_(memory),
       total_(size) {}
 
 SimpleBufferSerializer::~SimpleBufferSerializer() = default;
 
-size_t SimpleBufferSerializer::SerializeToMemory(
+size_t SimpleBufferSerializer::SerializeToMemoryImpl(
     const PaintOp& op,
     const PaintOp::SerializeOptions& options,
     const PaintFlags* flags_to_serialize,
diff --git a/cc/paint/paint_op_buffer_serializer.h b/cc/paint/paint_op_buffer_serializer.h
index 8e264ad..98301e1c 100644
--- a/cc/paint/paint_op_buffer_serializer.h
+++ b/cc/paint/paint_op_buffer_serializer.h
@@ -19,14 +19,16 @@
 
 class CC_PAINT_EXPORT PaintOpBufferSerializer {
  public:
-  using SerializeCallback =
-      base::RepeatingCallback<size_t(const PaintOp&,
-                                     const PaintOp::SerializeOptions&,
-                                     const PaintFlags*,
-                                     const SkM44&,
-                                     const SkM44&)>;
+  // As this code is performance sensitive, a raw function pointer is used.
+  using SerializeCallback = size_t (*)(void*,
+                                       const PaintOp&,
+                                       const PaintOp::SerializeOptions&,
+                                       const PaintFlags*,
+                                       const SkM44&,
+                                       const SkM44&);
 
   PaintOpBufferSerializer(SerializeCallback serialize_cb,
+                          void* callback_data,
                           const PaintOp::SerializeOptions& options);
   virtual ~PaintOpBufferSerializer();
 
@@ -108,6 +110,7 @@
                                 const PlaybackParams& params);
 
   SerializeCallback serialize_cb_;
+  raw_ptr<void> callback_data_;
   PaintOp::SerializeOptions options_;
 
   size_t serialized_op_count_ = 0;
@@ -125,11 +128,22 @@
   size_t written() const { return written_; }
 
  private:
-  size_t SerializeToMemory(const PaintOp& op,
-                           const PaintOp::SerializeOptions& options,
-                           const PaintFlags* flags_to_serialize,
-                           const SkM44& current_ctm,
-                           const SkM44& original_ctm);
+  size_t SerializeToMemoryImpl(const PaintOp& op,
+                               const PaintOp::SerializeOptions& options,
+                               const PaintFlags* flags_to_serialize,
+                               const SkM44& current_ctm,
+                               const SkM44& original_ctm);
+
+  static size_t SerializeToMemory(void* instance,
+                                  const PaintOp& op,
+                                  const PaintOp::SerializeOptions& options,
+                                  const PaintFlags* flags_to_serialize,
+                                  const SkM44& current_ctm,
+                                  const SkM44& original_ctm) {
+    return reinterpret_cast<SimpleBufferSerializer*>(instance)
+        ->SerializeToMemoryImpl(op, options, flags_to_serialize, current_ctm,
+                                original_ctm);
+  }
 
   raw_ptr<void> memory_;
   const size_t total_;
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index efb1b88e..b8cc77c 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -1802,22 +1802,23 @@
     int image_id = static_cast<int>(image_pair.first.hash());
 
     // If we have discardable decoded data, dump this here.
-    if (image_data->decode.HasData()) {
-      for (const auto aux_image : kAllAuxImages) {
-        const auto& info = image_data->GetImageInfo(aux_image);
-        std::string discardable_dump_name = base::StringPrintf(
-            "%s/discardable/image_%d%s", dump_name.c_str(), image_id,
-            aux_image == AuxImage::kDefault ? "" : AuxImageName(aux_image));
-        MemoryAllocatorDump* dump =
-            image_data->decode.data(aux_image)->CreateMemoryAllocatorDump(
-                discardable_dump_name.c_str(), pmd);
-        // Dump the "locked_size" as an additional column.
-        // This lets us see the amount of discardable which is contributing to
-        // memory pressure.
-        size_t locked_size = image_data->decode.is_locked() ? info.size : 0u;
-        dump->AddScalar("locked_size", MemoryAllocatorDump::kUnitsBytes,
-                        locked_size);
+    for (const auto aux_image : kAllAuxImages) {
+      const auto& info = image_data->GetImageInfo(aux_image);
+      const auto* data = image_data->decode.data(aux_image);
+      if (!data) {
+        continue;
       }
+      std::string discardable_dump_name = base::StringPrintf(
+          "%s/discardable/image_%d%s", dump_name.c_str(), image_id,
+          aux_image == AuxImage::kDefault ? "" : AuxImageName(aux_image));
+      MemoryAllocatorDump* dump =
+          data->CreateMemoryAllocatorDump(discardable_dump_name.c_str(), pmd);
+      // Dump the "locked_size" as an additional column.
+      // This lets us see the amount of discardable which is contributing to
+      // memory pressure.
+      size_t locked_size = image_data->decode.is_locked() ? info.size : 0u;
+      dump->AddScalar("locked_size", MemoryAllocatorDump::kUnitsBytes,
+                      locked_size);
     }
 
     // If we have an uploaded image (that is actually on the GPU, not just a
@@ -2452,9 +2453,6 @@
     return;
   }
 
-  aux_image_data[0].ValidateImagesMatchPixmaps();
-  aux_image_data[1].ValidateImagesMatchPixmaps();
-
   image_data->decode.SetLockedData(aux_image_data,
                                    task_type == TaskType::kOutOfRaster);
 }
diff --git a/chrome/VERSION b/chrome/VERSION
index 86193ec3..1a5a89e 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=114
 MINOR=0
-BUILD=5733
+BUILD=5734
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 4303452..8c460dc6 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2923,8 +2923,6 @@
 
   template("chrome_bundle_tmpl") {
     _is_monochrome = defined(invoker.is_monochrome) && invoker.is_monochrome
-    _is_trichrome = defined(invoker.is_trichrome) && invoker.is_trichrome
-    assert(_is_monochrome || _is_trichrome, "TODO: https://crbug.com/1426950")
 
     _base_module_target_name = "${invoker.target_name}__base_bundle_module"
     chrome_public_apk_or_module_tmpl(_base_module_target_name) {
@@ -2956,6 +2954,7 @@
                              [
                                "add_view_trace_events",
                                "baseline_profile_path",
+                               "bundle_name",
                                "enable_lint",
                                "include_32_bit_webview",
                                "include_64_bit_webview",
@@ -2972,20 +2971,12 @@
                              ])
       base_module_target = ":$_base_module_target_name"
       manifest_package = chrome_public_manifest_package
-      if (_is_trichrome) {
-        bundle_name = "TrichromeChrome${invoker.bundle_suffix}"
-        module_descs = chrome_module_descs
-      } else if (_is_monochrome) {
-        bundle_name = "MonochromePublic${invoker.bundle_suffix}"
+      if (_is_monochrome) {
         module_descs = monochrome_module_descs
+      } else {
+        module_descs = chrome_module_descs
       }
       chrome_deps = [ ":delegate_public_impl_java" ]
-      if (!_is_trichrome) {
-        chrome_deps += [ "//chrome/android:monochrome_java" ]
-      }
-      if (!is_java_debug) {
-        proguard_android_sdk_dep = webview_framework_dep
-      }
     }
   }
 
@@ -3013,6 +3004,7 @@
     # https://crbug.com/1000763
     chrome_bundle_tmpl("monochrome_public_bundle") {
       is_monochrome = true
+      bundle_name = "MonochromePublic"
 
       # Monochrome bundle is used as our unified lint target, so it needs to set the
       # lowest shipping minSdkVersion to catch all potential NewApi errors.
@@ -3022,7 +3014,6 @@
       lint_suppressions_file = "expectations/lint-suppressions.xml"
       add_view_trace_events = true
 
-      bundle_suffix = ""
       if (android_64bit_target_cpu) {
         is_64_bit_browser = false
         include_64_bit_webview = true
@@ -3054,8 +3045,8 @@
     }
 
     chrome_bundle_tmpl("trichrome_chrome_bundle") {
-      bundle_suffix = ""
       is_trichrome = true
+      bundle_name = "TrichromeChrome"
       static_library_provider = ":trichrome_library_apk"
       add_view_trace_events = true
       baseline_profile_path = "//chrome/android/baseline_profiles/profile.txt"
@@ -3169,14 +3160,14 @@
   if (android_64bit_target_cpu) {
     chrome_bundle_tmpl("monochrome_64_public_bundle") {
       is_monochrome = true
-      bundle_suffix = "64"
+      bundle_name = "MonochromePublic64"
       is_64_bit_browser = true
       include_32_bit_webview = false
     }
 
     chrome_bundle_tmpl("trichrome_chrome_64_bundle") {
       is_trichrome = true
-      bundle_suffix = "64"
+      bundle_name = "TrichromeChrome64"
       is_64_bit_browser = true
       include_32_bit_webview = false
       static_library_provider = ":trichrome_library_64_apk"
@@ -3189,21 +3180,21 @@
     if (!skip_secondary_abi_for_cq) {
       chrome_bundle_tmpl("monochrome_32_public_bundle") {
         is_monochrome = true
-        bundle_suffix = "32"
+        bundle_name = "MonochromePublic32"
         is_64_bit_browser = false
         include_64_bit_webview = false
       }
 
       chrome_bundle_tmpl("monochrome_64_32_public_bundle") {
         is_monochrome = true
-        bundle_suffix = "6432"
+        bundle_name = "MonochromePublic6432"
         is_64_bit_browser = true
         include_32_bit_webview = true
       }
 
       chrome_bundle_tmpl("trichrome_chrome_64_32_bundle") {
         is_trichrome = true
-        bundle_suffix = "6432"
+        bundle_name = "TrichromeChrome6432"
         is_64_bit_browser = true
         include_32_bit_webview = true
         static_library_provider = ":trichrome_library_64_32_apk"
@@ -3214,7 +3205,7 @@
       }
       chrome_bundle_tmpl("trichrome_chrome_32_bundle") {
         is_trichrome = true
-        bundle_suffix = "32"
+        bundle_name = "TrichromeChrome32"
         is_64_bit_browser = false
         include_64_bit_webview = false
         static_library_provider = ":trichrome_library_32_apk"
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 55a432a..d4a57d7 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -518,8 +518,8 @@
   "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarAnimationDelegate.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java",
-  "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/InterceptTouchLayout.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/NoOpkeyboardVisibilityDelegate.java",
+  "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/TitleAndUrlLayout.java",
   "java/src/org/chromium/chrome/browser/datareduction/DataSaverOSSetting.java",
   "java/src/org/chromium/chrome/browser/dependency_injection/ChromeActivityCommonsModule.java",
   "java/src/org/chromium/chrome/browser/dependency_injection/ChromeActivityComponent.java",
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
index cb1b86a..a5a0f297 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -47,6 +47,7 @@
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
+import org.chromium.chrome.browser.profiles.OriginalProfileSupplier;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileManager;
 import org.chromium.chrome.browser.query_tiles.QueryTileSection;
@@ -203,7 +204,7 @@
     private MostVisitedTilesCoordinator mMostVisitedCoordinator;
     private MostVisitedSuggestionsUiDelegate mSuggestionsUiDelegate;
     private TileGroupDelegateImpl mTileGroupDelegate;
-    private ObservableSupplier<Profile> mProfileSupplier;
+    private OneshotSupplier<Profile> mQueryTileProfileSupplier;
     private QueryTileSection mQueryTileSection;
     private boolean mIsMVTilesInitialized;
 
@@ -264,7 +265,6 @@
      * @param backPressManager {@link BackPressManager} to handle back press.
      * @param incognitoReauthControllerSupplier {@link OneshotSupplier<IncognitoReauthController>}
      *         to detect pending re-auth when tab switcher is shown.
-     * @param profileSupplier Supplies the {@Profile}.
      * @param tabSwitcherClickHandler The {@link OnClickListener} for the tab switcher button.
      */
     public StartSurfaceCoordinator(@NonNull Activity activity,
@@ -288,8 +288,7 @@
             @NonNull MultiWindowModeStateDispatcher multiWindowModeStateDispatcher,
             @NonNull Supplier<Toolbar> toolbarSupplier, BackPressManager backPressManager,
             @NonNull OneshotSupplier<IncognitoReauthController> incognitoReauthControllerSupplier,
-            @NonNull OnClickListener tabSwitcherClickHandler,
-            @NonNull ObservableSupplier<Profile> profileSupplier) {
+            @NonNull OnClickListener tabSwitcherClickHandler) {
         mConstructedTimeNs = SystemClock.elapsedRealtimeNanos();
         mActivity = activity;
         mScrimCoordinator = scrimCoordinator;
@@ -313,7 +312,6 @@
         mMultiWindowModeStateDispatcher = multiWindowModeStateDispatcher;
         mToolbarSupplier = toolbarSupplier;
         mIncognitoReauthControllerSupplier = incognitoReauthControllerSupplier;
-        mProfileSupplier = profileSupplier;
 
         mTabSwitcherCustomViewManagerSupplier = new ObservableSupplierImpl<>();
         boolean excludeQueryTiles = !mIsStartSurfaceEnabled
@@ -363,7 +361,7 @@
                 startSurfaceOneshotSupplier, hadWarmStart, initializeMVTilesRunnable,
                 mParentTabSupplier, logoContainerView,
                 mGridTabSwitcher == null ? backPressManager : null, feedPlaceholderParentView,
-                mActivityLifecycleDispatcher, tabSwitcherClickHandler, mProfileSupplier);
+                mActivityLifecycleDispatcher, tabSwitcherClickHandler);
 
         startSurfaceOneshotSupplier.set(this);
     }
@@ -391,7 +389,6 @@
             removeHeaderOffsetChangeListener(mOffsetChangedListenerToGenerateScrollEvents);
             mOffsetChangedListenerToGenerateScrollEvents = null;
         }
-        mProfileSupplier = null;
         if (mStartSurfaceMediator != null) {
             mStartSurfaceMediator.destroy();
         }
@@ -909,7 +906,8 @@
             if (ProfileManager.isInitialized()) {
                 initializeQueryTileSection(Profile.getLastUsedRegularProfile());
             } else {
-                mProfileSupplier.addObserver(this::initializeQueryTileSection);
+                mQueryTileProfileSupplier = new OriginalProfileSupplier();
+                mQueryTileProfileSupplier.onAvailable(this::initializeQueryTileSection);
             }
         } else {
             storeQueryTilesVisibility(false);
@@ -1099,8 +1097,6 @@
 
     private void initializeQueryTileSection(Profile profile) {
         assert profile != null;
-        if (profile.isOffTheRecord()) return;
-
         if (!QueryTileUtils.isQueryTilesEnabledOnStartSurface()) {
             storeQueryTilesVisibility(false);
             return;
@@ -1108,7 +1104,7 @@
         mQueryTileSection = new QueryTileSection(mView.findViewById(R.id.query_tiles_layout),
                 profile, query -> performSearchQuery(query.queryText, query.searchParams));
         storeQueryTilesVisibility(true);
-        mProfileSupplier.removeObserver(this::initializeQueryTileSection);
+        mQueryTileProfileSupplier = null;
     }
 
     /**
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
index 3019d14b..19c275b 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
@@ -11,7 +11,6 @@
 
 import androidx.annotation.NonNull;
 
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.supplier.Supplier;
@@ -26,7 +25,6 @@
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher;
 import org.chromium.chrome.browser.omnibox.OmniboxStub;
-import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.share.ShareDelegate;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -105,7 +103,6 @@
      * @param incognitoReauthControllerSupplier {@link OneshotSupplier<IncognitoReauthController>}
      *         to detect pending re-auth when tab switcher is shown.
      * @param tabSwitcherClickHandler The {@link OnClickListener} for the tab switcher button.
-     * @param profileSupplier Supplies the {@link Profile}.
      * @return the {@link StartSurface}
      */
     public static StartSurface createStartSurface(@NonNull Activity activity,
@@ -129,8 +126,7 @@
             @NonNull MultiWindowModeStateDispatcher multiWindowModeStateDispatcher,
             @NonNull Supplier<Toolbar> toolbarSupplier, BackPressManager backPressManager,
             @NonNull OneshotSupplier<IncognitoReauthController> incognitoReauthControllerSupplier,
-            @NonNull OnClickListener tabSwitcherClickHandler,
-            @NonNull ObservableSupplier<Profile> profileSupplier) {
+            @NonNull OnClickListener tabSwitcherClickHandler) {
         return new StartSurfaceCoordinator(activity, scrimCoordinator, sheetController,
                 startSurfaceOneshotSupplier, parentTabSupplier, hadWarmStart, windowAndroid,
                 containerView, dynamicResourceLoaderSupplier, tabModelSelector,
@@ -138,6 +134,6 @@
                 tabContentManager, modalDialogManager, chromeActivityNativeDelegate,
                 activityLifecycleDispatcher, tabCreatorManager, menuOrKeyboardActionController,
                 multiWindowModeStateDispatcher, toolbarSupplier, backPressManager,
-                incognitoReauthControllerSupplier, tabSwitcherClickHandler, profileSupplier);
+                incognitoReauthControllerSupplier, tabSwitcherClickHandler);
     }
 }
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index 8bf5029..f8f2820 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -75,8 +75,6 @@
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tab.TabSelectionType;
@@ -220,7 +218,6 @@
     private long mLastShownTimeMs = LAST_SHOW_TIME_NOT_SET;
     private boolean mIsStartSurfaceRefactorEnabled;
     private OnClickListener mTabSwitcherClickHandler;
-    private ObservableSupplier<Profile> mProfileSupplier;
 
     // TODO(crbug.com/1315676): Clean up TabSwitcher#Controller once the start surface refactoring
     // is done.
@@ -236,7 +233,7 @@
             View logoContainerView, @Nullable BackPressManager backPressManager,
             ViewGroup feedPlaceholderParentView,
             ActivityLifecycleDispatcher activityLifecycleDispatcher,
-            OnClickListener tabSwitcherClickHandler, ObservableSupplier<Profile> profileSupplier) {
+            OnClickListener tabSwitcherClickHandler) {
         mTabSwitcherContainer = tabSwitcherContainer;
         mTabSwitcherModule = tabSwitcherModule;
         mController = mTabSwitcherModule != null ? mTabSwitcherModule.getController() : controller;
@@ -265,8 +262,6 @@
                 ReturnToChromeUtil.shouldImproveStartWhenFeedIsDisabled(context);
         mIsStartSurfaceRefactorEnabled = ReturnToChromeUtil.isStartSurfaceRefactorEnabled(context);
         mTabSwitcherClickHandler = tabSwitcherClickHandler;
-        mProfileSupplier = profileSupplier;
-        mProfileSupplier.addObserver(this::onProfileAvailable);
 
         if (mPropertyModel != null) {
             assert mIsStartSurfaceEnabled;
@@ -476,7 +471,9 @@
             // Note that isVoiceSearchEnabled will return false in incognito mode.
             mPropertyModel.set(IS_VOICE_RECOGNITION_BUTTON_VISIBLE,
                     mOmniboxStub.getVoiceRecognitionHandler().isVoiceSearchEnabled());
-            updateLensVisibility();
+            boolean shouldShowLensButton = mOmniboxStub.isLensEnabled(LensEntryPoint.TASKS_SURFACE);
+            LensMetrics.recordShown(LensEntryPoint.TASKS_SURFACE, shouldShowLensButton);
+            mPropertyModel.set(IS_LENS_BUTTON_VISIBLE, shouldShowLensButton);
 
             // This is for Instant Start when overview is already visible while the omnibox, Feed
             // and MV tiles haven't been set.
@@ -538,19 +535,6 @@
         mFeedVisibilityPrefOnStartUp = prefService.getBoolean(Pref.ARTICLES_LIST_VISIBLE);
     }
 
-    void onProfileAvailable(Profile profile) {
-        if (profile.isOffTheRecord()) return;
-
-        TemplateUrlServiceFactory.getForProfile(profile).addObserver(this::updateLensVisibility);
-        mProfileSupplier.removeObserver(this::onProfileAvailable);
-    }
-
-    private void updateLensVisibility() {
-        boolean shouldShowLensButton = mOmniboxStub.isLensEnabled(LensEntryPoint.TASKS_SURFACE);
-        LensMetrics.recordShown(LensEntryPoint.TASKS_SURFACE, shouldShowLensButton);
-        mPropertyModel.set(IS_LENS_BUTTON_VISIBLE, shouldShowLensButton);
-    }
-
     void destroy() {
         if (mLogoCoordinator != null) {
             mLogoCoordinator.destroy();
@@ -559,11 +543,6 @@
         if (mCallbackController != null) {
             mCallbackController.destroy();
         }
-        if (mProfileSupplier.get() != null) {
-            TemplateUrlServiceFactory.getForProfile(mProfileSupplier.get())
-                    .removeObserver(this::updateLensVisibility);
-        }
-        mProfileSupplier.removeObserver(this::onProfileAvailable);
         mayRecordHomepageSessionEnd();
         mActivityLifecycleDispatcher.unregister(this);
     }
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java
index c12f463..7dc7245 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java
+++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java
@@ -19,6 +19,7 @@
 import static org.chromium.ui.test.util.ViewUtils.waitForView;
 
 import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.view.View;
 
 import androidx.test.InstrumentationRegistry;
@@ -39,6 +40,7 @@
 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.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.base.test.util.Feature;
@@ -57,7 +59,6 @@
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.R;
-import org.chromium.chrome.test.util.ChromeApplicationTestUtils;
 import org.chromium.chrome.test.util.MenuUtils;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
@@ -351,8 +352,8 @@
     @Feature({"StartSurface"})
     // clang-format off
     @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS})
-    @DisabledTest(message = "https://crbug.com/1246457")
     @DisableFeatures({ChromeFeatureList.BACK_GESTURE_REFACTOR})
+    @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.S_V2, message = "crbug/1436048")
     public void testSwipeBackOnStartSurfaceHomePage() throws ExecutionException {
         // clang-format on
         verifySwipeBackOnStartSurfaceHomePage();
@@ -362,8 +363,8 @@
     @MediumTest
     @Feature({"StartSurface"})
     @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS})
-    @DisabledTest(message = "https://crbug.com/1246457")
     @EnableFeatures({ChromeFeatureList.BACK_GESTURE_REFACTOR})
+    @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.S_V2, message = "crbug/1436048")
     public void testSwipeBackOnStartSurfaceHomePage_BackGestureRefactor()
             throws ExecutionException {
         verifySwipeBackOnStartSurfaceHomePage();
@@ -451,10 +452,7 @@
         StartSurfaceTestUtils.waitForStartSurfaceVisible(mLayoutChangedCallbackHelper,
                 mCurrentlyActiveLayout, mActivityTestRule.getActivity());
 
-        StartSurfaceTestUtils.gestureNavigateBack(mActivityTestRule);
-
-        // Back gesture on the start surface puts Chrome background.
-        ChromeApplicationTestUtils.waitUntilChromeInBackground();
+        StartSurfaceTestUtils.gestureNavigateBackToBringChromeBackground(mActivityTestRule);
     }
 
     /**
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java
index 4962654f..cb225a71 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java
+++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java
@@ -450,6 +450,21 @@
     }
 
     /**
+     * Perform gesture navigate back action on the start surface to put Chrome background.
+     * @param activityTestRule The ChromeTabbedActivityTestRule under test.
+     */
+    public static void gestureNavigateBackToBringChromeBackground(
+            ChromeTabbedActivityTestRule activityTestRule) {
+        AsyncInitializationActivity.interceptMoveTaskToBackForTesting();
+        GestureNavigationUtils navUtils = new GestureNavigationUtils(activityTestRule);
+        navUtils.swipeFromLeftEdge();
+
+        // Back gesture on the start surface puts Chrome background.
+        CriteriaHelper.pollUiThread(
+                () -> AsyncInitializationActivity.wasMoveTaskToBackInterceptedForTesting());
+    }
+
+    /**
      * Click the first MV tile (Explore tile) in mv_tiles_layout.
      * @param cta The ChromeTabbedActivity under test.
      * @param currentTabCount The correct number of normal tabs.
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java
index 89c7061..f696431 100644
--- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java
@@ -114,7 +114,6 @@
 
     private final OneshotSupplierImpl<IncognitoReauthController>
             mIncognitoReauthControllerSupplier = new OneshotSupplierImpl<>();
-    private ObservableSupplierImpl<Profile> mProfileSupplier = new ObservableSupplierImpl<>();
 
     private static class MockTabModelFilterProvider extends TabModelFilterProvider {
         public MockTabModelFilterProvider(Activity activity) {
@@ -273,7 +272,7 @@
                 new ActivityLifecycleDispatcherImpl(mActivity), new MockTabCreatorManager(),
                 Mockito.mock(MenuOrKeyboardActionController.class),
                 new MultiWindowModeStateDispatcherImpl(mActivity), new ObservableSupplierImpl<>(),
-                new BackPressManager(), mIncognitoReauthControllerSupplier, null, mProfileSupplier);
+                new BackPressManager(), mIncognitoReauthControllerSupplier, null);
 
         Assert.assertFalse(LibraryLoader.getInstance().isLoaded());
         when(mLibraryLoader.isInitialized()).thenReturn(true);
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
index 699bcb89..acd3b49 100644
--- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
@@ -74,7 +74,6 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.ContextUtils;
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.Supplier;
@@ -123,7 +122,6 @@
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.search_engines.TemplateUrlService;
-import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.url.JUnitTestGURLs;
@@ -200,8 +198,6 @@
     @Mock
     private Profile mProfile;
     @Mock
-    private ObservableSupplier<Profile> mProfileSupplier;
-    @Mock
     private TemplateUrlService mTemplateUrlService;
     @Mock
     private ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
@@ -228,8 +224,6 @@
     @Captor
     private ArgumentCaptor<PauseResumeWithNativeObserver>
             mPauseResumeWithNativeObserverArgumentCaptor;
-    @Captor
-    private ArgumentCaptor<TemplateUrlServiceObserver> mTemplateUrlServiceObserverCaptor;
 
     private ObservableSupplierImpl<Boolean>
             mCarouselTabSwitcherModuleControllerBackPressStateSupplier =
@@ -246,8 +240,6 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        doReturn(false).when(mProfile).isOffTheRecord();
-        doReturn(mProfile).when(mProfileSupplier).get();
         Profile.setLastUsedProfileForTesting(mProfile);
         TemplateUrlServiceFactory.setInstanceForTesting(mTemplateUrlService);
 
@@ -1296,6 +1288,9 @@
         when(mCarouselOrSingleTabSwitcherModuleController.overviewVisible()).thenReturn(true);
         mediator.initWithNative(
                 mOmniboxStub, mExploreSurfaceCoordinatorFactory, mPrefService, null);
+        when(mCarouselOrSingleTabSwitcherModuleController.overviewVisible()).thenReturn(true);
+        mediator.initWithNative(
+                mOmniboxStub, mExploreSurfaceCoordinatorFactory, mPrefService, null);
         assertThat(mPropertyModel.get(IS_EXPLORE_SURFACE_VISIBLE), equalTo(true));
     }
 
@@ -1834,28 +1829,6 @@
         verify(mTabListDelegate).postHiding();
     }
 
-    @Test
-    public void testDefaultSearchEngineChanged() {
-        doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler();
-
-        StartSurfaceMediator mediator = createStartSurfaceMediator(/*isStartSurfaceEnabled=*/true,
-                /* isRefactorEnabled */ false, /* hadWarmStart= */ false);
-        showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE);
-
-        mediator.onProfileAvailable(mProfile);
-        verify(mTemplateUrlService).addObserver(mTemplateUrlServiceObserverCaptor.capture());
-        doReturn(true).when(mOmniboxStub).isLensEnabled(LensEntryPoint.TASKS_SURFACE);
-        mTemplateUrlServiceObserverCaptor.getValue().onTemplateURLServiceChanged();
-        assertTrue(mPropertyModel.get(IS_LENS_BUTTON_VISIBLE));
-
-        doReturn(false).when(mOmniboxStub).isLensEnabled(LensEntryPoint.TASKS_SURFACE);
-        mTemplateUrlServiceObserverCaptor.getValue().onTemplateURLServiceChanged();
-        assertFalse(mPropertyModel.get(IS_LENS_BUTTON_VISIBLE));
-
-        mediator.destroy();
-        verify(mTemplateUrlService).removeObserver(mTemplateUrlServiceObserverCaptor.capture());
-    }
-
     private StartSurfaceMediator createStartSurfaceMediator(boolean isStartSurfaceEnabled) {
         return createStartSurfaceMediator(isStartSurfaceEnabled, /* isRefactorEnabled */ false,
                 /* hadWarmStart= */ false);
@@ -1874,6 +1847,9 @@
         mediator.initWithNative(mOmniboxStub,
                 isStartSurfaceEnabled ? mExploreSurfaceCoordinatorFactory : null, mPrefService,
                 null);
+        mediator.initWithNative(mOmniboxStub,
+                isStartSurfaceEnabled ? mExploreSurfaceCoordinatorFactory : null, mPrefService,
+                null);
         return mediator;
     }
 
@@ -1891,7 +1867,7 @@
                 hasTasksView || hasTabSwitcherModule ? mInitializeMVTilesRunnable : null,
                 mParentTabSupplier, mLogoContainerView, mBackPressManager,
                 null /* feedPlaceholderParentView */, mActivityLifecycleDispatcher,
-                mTabSwitcherClickHandler, mProfileSupplier);
+                mTabSwitcherClickHandler);
     }
 
     private void onControlsOffsetChanged(int topOffset, int topControlsMinHeightOffset) {
diff --git a/chrome/android/java/res/layout/custom_tabs_toolbar.xml b/chrome/android/java/res/layout/custom_tabs_toolbar.xml
index cd59b70..a649592 100644
--- a/chrome/android/java/res/layout/custom_tabs_toolbar.xml
+++ b/chrome/android/java/res/layout/custom_tabs_toolbar.xml
@@ -41,7 +41,7 @@
             android:visibility="invisible"
             app:tint="@color/default_icon_color_tint_list" />
         <view
-            class="org.chromium.chrome.browser.customtabs.features.toolbar.InterceptTouchLayout"
+            class="org.chromium.chrome.browser.customtabs.features.toolbar.TitleAndUrlLayout"
             android:id="@+id/title_url_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
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 eb8d976..13d99dbb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -737,7 +737,7 @@
                 getTabCreatorManagerSupplier().get(), getMenuOrKeyboardActionController(),
                 getMultiWindowModeStateDispatcher(), getToolbarManager()::getToolbar,
                 mBackPressManager, mRootUiCoordinator.getIncognitoReauthControllerSupplier(),
-                v -> onTabSwitcherClicked(), mTabModelProfileSupplier);
+                v -> onTabSwitcherClicked());
     }
 
     private void createGridTabSwitcher(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 37121266..501380a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -504,8 +504,9 @@
         int decorationType =
                 IntentUtils.safeGetIntExtra(intent, EXTRA_ACTIVITY_SIDE_SHEET_DECORATION_TYPE,
                         ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT);
-        return decorationType < 0 || decorationType > ACTIVITY_SIDE_SHEET_DECORATION_TYPE_MAX
-                ? ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT
+        return decorationType == ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT || decorationType < 0
+                        || decorationType > ACTIVITY_SIDE_SHEET_DECORATION_TYPE_MAX
+                ? ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW
                 : decorationType;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/CustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/CustomTabHeightStrategy.java
index e7a2bf0..caf4626 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/CustomTabHeightStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/CustomTabHeightStrategy.java
@@ -97,8 +97,9 @@
 
     /**
      * @see {@link BaseCustomTabRootUiCoordinator#handleCloseAnimation()}
+     * @return {@code true} if the animation will be performed.
      */
-    public void handleCloseAnimation(Runnable finishRunnable) {
+    public boolean handleCloseAnimation(Runnable finishRunnable) {
         throw new IllegalStateException(
                 "Custom close animation should be performed only on partial CCT.");
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBaseStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBaseStrategy.java
index b197697..4dcdf5f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBaseStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBaseStrategy.java
@@ -11,7 +11,6 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.Activity;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
@@ -465,14 +464,16 @@
     }
 
     @Override
-    public void handleCloseAnimation(Runnable finishRunnable) {
-        if (mFinishRunnable != null) return;
-
+    public boolean handleCloseAnimation(Runnable finishRunnable) {
+        // Can be entered twice - first from CustomTabToolbar (with a tap on close button)/
+        // HandleStrategy (swiping down), once again from RootUiCoordinator. Just run the passed
+        // runnable and return for the second invocation.
+        if (mFinishRunnable != null) {
+            if (finishRunnable != null) finishRunnable.run();
+            return false;
+        }
         mFinishRunnable = finishRunnable;
-        configureLayoutBeyondScreen(true);
-        AnimatorUpdateListener updater = animator -> setWindowY((int) animator.getAnimatedValue());
-        int start = mActivity.getWindow().getAttributes().y;
-        startAnimation(start, mHeight, updater, this::onCloseAnimationEnd);
+        return true;
     }
 
     protected void configureLayoutBeyondScreen(boolean enable) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBottomSheetStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBottomSheetStrategy.java
index 7000d4b6..0b10a7c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBottomSheetStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabBottomSheetStrategy.java
@@ -788,24 +788,18 @@
     }
 
     @Override
-    public void handleCloseAnimation(Runnable finishRunnable) {
-        // Swiping/tap on close button may have already started the animation and completed
-        // the closing task. Only the closing flow by back button/gesture can proceed.
-        if (mStatus == HeightStatus.CLOSE) {
-            if (finishRunnable != null) finishRunnable.run();
-            return;
-        }
-
-        mFinishRunnable = finishRunnable;
+    public boolean handleCloseAnimation(Runnable finishRunnable) {
+        if (!super.handleCloseAnimation(finishRunnable)) return false;
 
         mVersionCompat.setImeStateCallback(null);
 
         // Tapping the close button while in transition state should be ignored.
         // Delay it till the height settles in to either top/initial state, where the animation
         // begins when it detects the presence of |mFinishRunnable|.
-        if (mStatus == HeightStatus.TRANSITION) return;
+        if (mStatus == HeightStatus.TRANSITION) return false;
 
         animateTabTo(HeightStatus.CLOSE, /*autoResize=*/true);
+        return true;
     }
 
     // DragEventCallback implementation
@@ -930,6 +924,11 @@
     }
 
     @VisibleForTesting
+    CustomTabToolbar.HandleStrategy getHandleStrategyForTesting() {
+        return mHandleStrategy;
+    }
+
+    @VisibleForTesting
     CustomTabToolbar.HandleStrategy createHandleStrategyForTesting() {
         // Pass null for context because we don't depend on the GestureDetector inside as we invoke
         // MotionEvents directly in the tests.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabDisplayManager.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabDisplayManager.java
index f91b965..d22484fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabDisplayManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabDisplayManager.java
@@ -181,8 +181,8 @@
      * @see {@link BaseCustomTabRootUiCoordinator#handleCloseAnimation()}
      */
     @Override
-    public void handleCloseAnimation(Runnable finishRunnable) {
-        mStrategy.handleCloseAnimation(finishRunnable);
+    public boolean handleCloseAnimation(Runnable finishRunnable) {
+        return mStrategy.handleCloseAnimation(finishRunnable);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabFullSizeStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabFullSizeStrategy.java
index f3be90c..b99b9cf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabFullSizeStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabFullSizeStrategy.java
@@ -8,6 +8,7 @@
 
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_FULL_SCREEN;
 
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.Activity;
 import android.graphics.drawable.GradientDrawable;
 import android.view.Gravity;
@@ -77,6 +78,17 @@
     }
 
     @Override
+    public boolean handleCloseAnimation(Runnable finishRunnable) {
+        if (!super.handleCloseAnimation(finishRunnable)) return false;
+
+        configureLayoutBeyondScreen(true);
+        AnimatorUpdateListener updater = animator -> setWindowY((int) animator.getAnimatedValue());
+        int start = mActivity.getWindow().getAttributes().y;
+        startAnimation(start, mHeight, updater, this::onCloseAnimationEnd);
+        return true;
+    }
+
+    @Override
     protected int getHandleHeight() {
         return 0;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategy.java
index cf746abb..4995667 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategy.java
@@ -104,10 +104,9 @@
     }
 
     @Override
-    public void handleCloseAnimation(Runnable finishRunnable) {
-        if (mFinishRunnable != null) return;
+    public boolean handleCloseAnimation(Runnable finishRunnable) {
+        if (!super.handleCloseAnimation(finishRunnable)) return false;
 
-        mFinishRunnable = finishRunnable;
         configureLayoutBeyondScreen(true);
         Window window = mActivity.getWindow();
         AnimatorUpdateListener closeAnimation;
@@ -123,6 +122,7 @@
             closeAnimation = (animator) -> setWindowX((int) animator.getAnimatedValue());
         }
         startAnimation(start, end, closeAnimation, this::onCloseAnimationEnd, true);
+        return true;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/SimpleHandleStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/SimpleHandleStrategy.java
index 7c288f6..912c777d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/SimpleHandleStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/SimpleHandleStrategy.java
@@ -46,4 +46,8 @@
     public void close() {
         mOnClickCloseListener.onClick(null);
     }
+
+    public OnClickListener getClickCloseHandlerForTesting() {
+        return mOnClickCloseListener;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
index fd1d0aab..f014880d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -133,6 +133,8 @@
     // while the side sheet is running with the maximize button option on.
     private boolean mMaximizeButtonEnabled;
 
+    private OnClickListener mCloseClickListener;
+
     /**
      * Whether to use the toolbar as handle to resize the Window height.
      */
@@ -227,16 +229,22 @@
 
     @Override
     protected void setCustomTabCloseClickHandler(OnClickListener listener) {
+        mCloseClickListener = listener;
         if (mHandleStrategy == null) {
+            // Normal CCT does not have HandleStrategy.
             mCloseButton.setOnClickListener(listener);
         } else {
-            // Let the close button click initiate the closing animation first. The actual
-            // closing task will follow the animation.
-            mCloseButton.setOnClickListener(v -> mHandleStrategy.startCloseAnimation());
-            mHandleStrategy.setCloseClickHandler(listener);
+            setHandleStrategyCloseClickHandler(listener);
         }
     }
 
+    private void setHandleStrategyCloseClickHandler(OnClickListener listener) {
+        // Let the close button click initiate the closing animation first. The actual
+        // closing task will follow the animation.
+        mCloseButton.setOnClickListener(v -> mHandleStrategy.startCloseAnimation());
+        mHandleStrategy.setCloseClickHandler(listener);
+    }
+
     @Override
     protected void addCustomActionButton(
             Drawable drawable, String description, OnClickListener listener) {
@@ -432,18 +440,14 @@
         return false;
     }
 
-    public void setHandleStrategy(@Nullable HandleStrategy strategy) {
+    public void setHandleStrategy(HandleStrategy strategy) {
         if (!CustomTabsConnection.getInstance().isDynamicFeatureEnabled(
                     ChromeFeatureList.CCT_BRAND_TRANSPARENCY)) {
             mLocationBar.showBranding();
         }
 
-        // When the (P)CCT does not need to be resized the handle strategy can be null.
-        if (strategy == null) {
-            mHandleStrategy = null;
-            return;
-        }
         mHandleStrategy = strategy;
+        if (mCloseClickListener != null) setHandleStrategyCloseClickHandler(mCloseClickListener);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarAnimationDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarAnimationDelegate.java
index eeae118..9f15de5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarAnimationDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarAnimationDelegate.java
@@ -93,8 +93,6 @@
 
         float oldSizePx = mUrlBar.getTextSize();
         mUrlBar.setTextSize(TypedValue.COMPLEX_UNIT_PX, newSizeSp);
-        float newSizePx = mUrlBar.getTextSize();
-        final float scale = oldSizePx / newSizePx;
 
         // View#getY() cannot be used because the boundary of the parent will change after relayout.
         final int[] oldLoc = new int[2];
@@ -111,6 +109,11 @@
                 int[] newLoc = new int[2];
                 mUrlBar.getLocationInWindow(newLoc);
 
+                // The size may change during the measuring pass, so we should calculate the new
+                // size here, after the layout is done.
+                float newSizePx = mUrlBar.getTextSize();
+                final float scale = oldSizePx / newSizePx;
+
                 mUrlBar.setScaleX(scale);
                 mUrlBar.setScaleY(scale);
                 mUrlBar.setTranslationX(oldLoc[0] - newLoc[0]);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/InterceptTouchLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/InterceptTouchLayout.java
deleted file mode 100644
index 007f1b5..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/InterceptTouchLayout.java
+++ /dev/null
@@ -1,52 +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.
-
-package org.chromium.chrome.browser.customtabs.features.toolbar;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.widget.FrameLayout;
-
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.chrome.browser.omnibox.UrlBar;
-
-/**
- * A simple {@link FrameLayout} that prevents its children from getting touch events. This is
- * especially useful to prevent {@link UrlBar} from running custom touch logic since it is read-only
- * in custom tabs.
- */
-class InterceptTouchLayout extends FrameLayout {
-    private final GestureDetector mGestureDetector;
-
-    public InterceptTouchLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mGestureDetector =
-                new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
-                    @Override
-                    public boolean onSingleTapConfirmed(MotionEvent e) {
-                        if (LibraryLoader.getInstance().isInitialized()) {
-                            RecordUserAction.record("CustomTabs.TapUrlBar");
-                        }
-                        return super.onSingleTapConfirmed(e);
-                    }
-                }, ThreadUtils.getUiThreadHandler());
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        return true;
-    }
-
-    @Override
-    @SuppressLint("ClickableViewAccessibility")
-    public boolean onTouchEvent(MotionEvent event) {
-        mGestureDetector.onTouchEvent(event);
-        return super.onTouchEvent(event);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/TitleAndUrlLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/TitleAndUrlLayout.java
new file mode 100644
index 0000000..10415e19
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/TitleAndUrlLayout.java
@@ -0,0 +1,106 @@
+// 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.customtabs.features.toolbar;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import androidx.annotation.Px;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.omnibox.UrlBar;
+
+/**
+ * A specialized {@link FrameLayout} that wraps the title and URL bars. It currently has 2 purposes:
+ * - Prevents its children from getting touch events. This is especially useful to prevent
+ *   {@link UrlBar} from running custom touch logic since it is read-only in custom tabs.
+ * - Scales down the text within if they are overlapping. This can happen if the system font size
+ *   setting is set to a large value, e.g. 200%.
+ */
+class TitleAndUrlLayout extends FrameLayout {
+    private final GestureDetector mGestureDetector;
+    private TextView mTitleBar;
+    private UrlBar mUrlBar;
+    // Bit to make sure we scale and re-measure the text only once per activity launch.
+    private boolean mTextScaled;
+
+    public TitleAndUrlLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mGestureDetector =
+                new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
+                    @Override
+                    public boolean onSingleTapConfirmed(MotionEvent e) {
+                        if (LibraryLoader.getInstance().isInitialized()) {
+                            RecordUserAction.record("CustomTabs.TapUrlBar");
+                        }
+                        return super.onSingleTapConfirmed(e);
+                    }
+                }, ThreadUtils.getUiThreadHandler());
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mTitleBar = findViewById(R.id.title_bar);
+        mUrlBar = findViewById(R.id.url_bar);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        assert getChildCount() == 2;
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        int titleHeight = mTitleBar.getMeasuredHeight();
+        int urlHeight = mUrlBar.getMeasuredHeight();
+        if (!mTextScaled && titleHeight > 0 && urlHeight > 0
+                && (titleHeight + urlHeight > getMeasuredHeight())) {
+            float titleToTotalRatio =
+                    mTitleBar.getTextSize() / (mTitleBar.getTextSize() + mUrlBar.getTextSize());
+            int titleDesiredHeight = Math.round(getMeasuredHeight() * titleToTotalRatio);
+            int urlDesiredHeight = Math.round(getMeasuredHeight() * (1 - titleToTotalRatio));
+            scaleDownText(mTitleBar, titleDesiredHeight);
+            scaleDownText(mUrlBar, urlDesiredHeight);
+            ((FrameLayout.LayoutParams) mTitleBar.getLayoutParams()).bottomMargin =
+                    urlDesiredHeight;
+            mTextScaled = true;
+
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    private static void scaleDownText(TextView textView, int desiredHeight) {
+        float fontHeight = getMaxHeightOfFont(textView.getPaint().getFontMetrics());
+        float scaleRatio = desiredHeight / fontHeight;
+        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textView.getTextSize() * scaleRatio);
+    }
+
+    private static @Px float getMaxHeightOfFont(Paint.FontMetrics fontMetrics) {
+        return fontMetrics.bottom - fontMetrics.top;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        return true;
+    }
+
+    @Override
+    @SuppressLint("ClickableViewAccessibility")
+    public boolean onTouchEvent(MotionEvent event) {
+        mGestureDetector.onTouchEvent(event);
+        return super.onTouchEvent(event);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
index 7ef6d8e..8a9ca3c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
@@ -170,8 +170,6 @@
             BASE_PATH + "navigation_from_java_redirection.html";
     private static final String NAVIGATION_TO_CCT_FROM_INTENT_URI =
             BASE_PATH + "navigation_to_cct_via_intent_uri.html";
-    private static final String NAVIGATION_TO_FILE_SCHEME_FROM_INTENT_URI =
-            BASE_PATH + "navigation_to_file_scheme_via_intent_uri.html";
     private static final String FALLBACK_URL =
             "https://play.google.com/store/apps/details?id=com.android.chrome";
     private static final String SUBFRAME_REDIRECT_WITH_PLAY_FALLBACK =
@@ -201,6 +199,9 @@
     private static final String NAVIGATION_FROM_WINDOW_REDIRECT =
             BASE_PATH + "navigation_from_window_redirect.html";
 
+    private static final String EXTERNAL_APP_URL =
+            "intent://test/#Intent;scheme=externalappscheme;end;";
+
     private static final String OTHER_BROWSER_PACKAGE = "com.other.browser";
     // Needs to be a real package on the device so we can get an icon from it. It will not be
     // launched.
@@ -642,6 +643,14 @@
                 + (openInNewTab ? Base64.encodeToString(valBlank, Base64.URL_SAFE) : ""));
     }
 
+    private String getOpenWindowFromLinkUserGestureUrl(String targetUrl) {
+        byte[] param = ApiCompatibilityUtils.getBytesUtf8("PARAM_URL");
+        byte[] value = ApiCompatibilityUtils.getBytesUtf8(targetUrl);
+        return mTestServer.getURL(OPEN_WINDOW_FROM_LINK_USER_GESTURE_PAGE)
+                + "?replace_text=" + Base64.encodeToString(param, Base64.URL_SAFE) + ":"
+                + Base64.encodeToString(value, Base64.URL_SAFE);
+    }
+
     @Test
     @SmallTest
     public void testNavigationFromTimer() {
@@ -788,8 +797,8 @@
     @SmallTest
     public void testOpenWindowFromLinkUserGesture() {
         mActivityTestRule.startMainActivityOnBlankPage();
-        loadUrlAndWaitForIntentUrl(mTestServer.getURL(OPEN_WINDOW_FROM_LINK_USER_GESTURE_PAGE),
-                true, true, true, null, true);
+        loadUrlAndWaitForIntentUrl(getOpenWindowFromLinkUserGestureUrl(EXTERNAL_APP_URL), true,
+                true, true, null, true);
     }
 
     @Test
@@ -892,36 +901,40 @@
     @LargeTest
     public void testIntentURIWithFileSchemeDoesNothing() throws TimeoutException {
         mActivityTestRule.startMainActivityOnBlankPage();
-        String originalUrl = mTestServer.getURL(NAVIGATION_TO_FILE_SCHEME_FROM_INTENT_URI);
-        loadUrlAndWaitForIntentUrl(originalUrl, true, true, false, null, true, "scheme_file",
-                PageTransition.LINK, false);
+        String url = getOpenWindowFromLinkUserGestureUrl(
+                "intent:///x.mhtml#Intent;package=org.chromium.chrome.tests;"
+                + "action=android.intent.action.VIEW;scheme=file;end;");
+        loadUrlAndWaitForIntentUrl(url, true, true, false, null, true);
     }
 
     @Test
     @LargeTest
     public void testIntentURIWithMixedCaseFileSchemeDoesNothing() throws TimeoutException {
         mActivityTestRule.startMainActivityOnBlankPage();
-        String originalUrl = mTestServer.getURL(NAVIGATION_TO_FILE_SCHEME_FROM_INTENT_URI);
-        loadUrlAndWaitForIntentUrl(originalUrl, true, true, false, null, true,
-                "scheme_mixed_case_file", PageTransition.LINK, false);
+        String url = getOpenWindowFromLinkUserGestureUrl(
+                "intent:///x.mhtml#Intent;package=org.chromium.chrome.tests;"
+                + "action=android.intent.action.VIEW;scheme=FiLe;end;");
+        loadUrlAndWaitForIntentUrl(url, true, true, false, null, true);
     }
 
     @Test
     @LargeTest
     public void testIntentURIWithNoSchemeDoesNothing() throws TimeoutException {
         mActivityTestRule.startMainActivityOnBlankPage();
-        String originalUrl = mTestServer.getURL(NAVIGATION_TO_FILE_SCHEME_FROM_INTENT_URI);
-        loadUrlAndWaitForIntentUrl(originalUrl, true, true, false, null, true, "null_scheme",
-                PageTransition.LINK, false);
+        String url = getOpenWindowFromLinkUserGestureUrl(
+                "intent:///x.mhtml#Intent;package=org.chromium.chrome.tests;"
+                + "action=android.intent.action.VIEW;end;");
+        loadUrlAndWaitForIntentUrl(url, true, true, false, null, true);
     }
 
     @Test
     @LargeTest
     public void testIntentURIWithEmptySchemeDoesNothing() throws TimeoutException {
         mActivityTestRule.startMainActivityOnBlankPage();
-        String originalUrl = mTestServer.getURL(NAVIGATION_TO_FILE_SCHEME_FROM_INTENT_URI);
-        loadUrlAndWaitForIntentUrl(originalUrl, true, true, false, null, true, "empty_scheme",
-                PageTransition.LINK, false);
+        String url = getOpenWindowFromLinkUserGestureUrl(
+                "intent:///x.mhtml#Intent;package=org.chromium.chrome.tests;"
+                + "action=android.intent.action.VIEW;scheme=;end;");
+        loadUrlAndWaitForIntentUrl(url, true, true, false, null, true);
     }
 
     @Test
@@ -1132,7 +1145,7 @@
         });
 
         // Click link to go to second page.
-        DOMUtils.clickNode(mActivityTestRule.getWebContents(), "link");
+        TouchCommon.singleClickView(tab.getView());
         finishCallback.waitForCallback(0);
         syncHelper.notifyCalled();
 
@@ -1517,7 +1530,7 @@
         mActivityTestRule.startMainActivityOnBlankPage();
         ChromeActivity activity = mActivityTestRule.getActivity();
         TabModelImpl tabModel = (TabModelImpl) activity.getTabModelSelector().getModel(false);
-        GURL url = new GURL("intent://test/#Intent;scheme=externalappscheme;end;");
+        GURL url = new GURL(EXTERNAL_APP_URL);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             // Called when a popup window is allowed.
             tabModel.openNewTab(activity.getActivityTab(), url, createExampleOrigin(), null, null,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java
index 3a8238bf..9d8af50 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java
@@ -513,7 +513,7 @@
         // If the ContentSettingsType.NUM_TYPES value changes *and* a new value has been exposed on
         // Android, then please update this code block to include a test for your new type.
         // Otherwise, just update count in the assert.
-        Assert.assertEquals(86, ContentSettingsType.NUM_TYPES);
+        Assert.assertEquals(87, ContentSettingsType.NUM_TYPES);
         websitePreferenceBridge.addContentSettingException(
                 new ContentSettingException(ContentSettingsType.COOKIES, googleOrigin,
                         ContentSettingValues.DEFAULT, preferenceSource, /*isEmbargoed=*/false));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java
index 77132b4..b65f2b8 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java
@@ -708,7 +708,7 @@
         Intent intent = new CustomTabsIntent.Builder().build().intent;
         var dataProvider = new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT);
         assertEquals("Decoration types do not match",
-                CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT,
+                CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW,
                 dataProvider.getActivitySideSheetDecorationType());
 
         // Decoration set higher than max
@@ -716,7 +716,7 @@
                 CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_MAX + 1);
         var dataProvider2 = new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT);
         assertEquals("Decoration types do not match",
-                CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT,
+                CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW,
                 dataProvider2.getActivitySideSheetDecorationType());
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabDisplayManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabDisplayManagerTest.java
index a8c3232..23428137 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabDisplayManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabDisplayManagerTest.java
@@ -19,8 +19,8 @@
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_FULL_SCREEN;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_SIDE_SHEET;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_SIDE_SHEET_MAXIMIZED;
-import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DIVIDER;
+import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_NONE;
 import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_POSITION_END;
 import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_SLIDE_IN_FROM_SIDE;
@@ -73,7 +73,7 @@
     private PartialCustomTabDisplayManager createPcctDisplayManager(
             @Px int heightPx, @Px int widthPx) {
         return createPcctDisplayManager(
-                heightPx, widthPx, 1850, ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT);
+                heightPx, widthPx, 1850, ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW);
     }
 
     private PartialCustomTabDisplayManager createPcctDisplayManager(
@@ -125,7 +125,7 @@
     @Test
     public void create_SideSheet_WidthSetHeightNot_AboveBreakpoint() {
         PartialCustomTabDisplayManager displayManager =
-                createPcctDisplayManager(0, 2000, 840, ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT);
+                createPcctDisplayManager(0, 2000, 840, ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW);
         assertEquals(
                 "Breakpoint value is incorrect", 840, displayManager.getBreakPointDpForTesting());
         assertEquals("Side-Sheet PCCT should be created", PartialCustomTabType.SIDE_SHEET,
@@ -144,8 +144,8 @@
     @Test
     public void create_BottomSheet_HeightWidthSet_Compact() {
         mPCCTTestRule.configCompactDevice();
-        PartialCustomTabDisplayManager displayManager = createPcctDisplayManager(
-                350, 450, 400, ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT);
+        PartialCustomTabDisplayManager displayManager =
+                createPcctDisplayManager(350, 450, 400, ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW);
         assertEquals(
                 "Breakpoint value is incorrect", 600, displayManager.getBreakPointDpForTesting());
         assertEquals("Bottom-Sheet PCCT should be created", PartialCustomTabType.BOTTOM_SHEET,
@@ -236,6 +236,31 @@
     }
 
     @Test
+    public void closeAnimationNotInvokedTwice() {
+        mPCCTTestRule.configPortraitMode();
+        PartialCustomTabDisplayManager displayManager = createPcctDisplayManager();
+        assertEquals("Bottom-Sheet should be the active strategy",
+                PartialCustomTabType.BOTTOM_SHEET, displayManager.getActiveStrategyType());
+        Runnable finish = Mockito.mock(Runnable.class);
+        assertTrue("Close animation didn't run", displayManager.handleCloseAnimation(finish));
+        Runnable finish2 = Mockito.mock(Runnable.class);
+        assertFalse("Close animation shouldn't run", displayManager.handleCloseAnimation(finish2));
+
+        mPCCTTestRule.configLandscapeMode();
+        displayManager = createPcctDisplayManager();
+        assertEquals("Side-Sheet should be the active strategy", PartialCustomTabType.SIDE_SHEET,
+                displayManager.getActiveStrategyType());
+        assertTrue("Close animation didn't run", displayManager.handleCloseAnimation(finish));
+        assertFalse("Close animation shouldn't run", displayManager.handleCloseAnimation(finish2));
+
+        displayManager = createPcctDisplayManager(0, 0);
+        assertEquals("Full-Size PCCT should be created", PartialCustomTabType.FULL_SIZE,
+                displayManager.getActiveStrategyType());
+        assertTrue("Close animation didn't run", displayManager.handleCloseAnimation(finish));
+        assertFalse("Close animation shouldn't run", displayManager.handleCloseAnimation(finish2));
+    }
+
+    @Test
     public void
     transitionFromBottomSheetTo900dpBottomSheetWhenOrientationChangedToLandscape_andHeightSetWidthNot() {
         mPCCTTestRule.configPortraitMode();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategyTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategyTest.java
index a9eed626..31560f64 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategyTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabSideSheetStrategyTest.java
@@ -19,16 +19,15 @@
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_FULL_SCREEN;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_SIDE_SHEET;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_SIDE_SHEET_MAXIMIZED;
-import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DIVIDER;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_NONE;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_NONE;
 import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_TOP;
+import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_SIDE_SHEET_SLIDE_IN_FROM_SIDE;
 import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_POSITION_DEFAULT;
 import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_POSITION_END;
 import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_POSITION_START;
-import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.ACTIVITY_SIDE_SHEET_SLIDE_IN_DEFAULT;
 import static org.chromium.chrome.browser.customtabs.features.partialcustomtab.PartialCustomTabTestRule.DEVICE_HEIGHT;
 import static org.chromium.chrome.browser.customtabs.features.partialcustomtab.PartialCustomTabTestRule.DEVICE_HEIGHT_LANDSCAPE;
 import static org.chromium.chrome.browser.customtabs.features.partialcustomtab.PartialCustomTabTestRule.DEVICE_WIDTH;
@@ -81,21 +80,21 @@
     public final PartialCustomTabTestRule mPCCTTestRule = new PartialCustomTabTestRule();
 
     private PartialCustomTabSideSheetStrategy createPcctSideSheetStrategy(@Px int widthPx) {
-        return createPcctSideSheetStrategy(widthPx, ACTIVITY_SIDE_SHEET_POSITION_DEFAULT,
-                ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT,
+        return createPcctSideSheetStrategy(widthPx, ACTIVITY_SIDE_SHEET_POSITION_END,
+                ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW,
                 ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_NONE);
     }
 
     private PartialCustomTabSideSheetStrategy createLeftPcctSideSheetStrategy(
             @Px int widthPx, int roundedCornersPosition) {
         return createPcctSideSheetStrategy(widthPx, ACTIVITY_SIDE_SHEET_POSITION_START,
-                ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT, roundedCornersPosition);
+                ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW, roundedCornersPosition);
     }
 
     private PartialCustomTabSideSheetStrategy createPcctSideSheetStrategy(
             @Px int widthPx, int position) {
         return createPcctSideSheetStrategy(widthPx, position,
-                ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT,
+                ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW,
                 ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_NONE);
     }
 
@@ -105,7 +104,7 @@
                 mPCCTTestRule.mActivity, widthPx, mPCCTTestRule.mOnResizedCallback,
                 mPCCTTestRule.mOnActivityLayoutCallback, mPCCTTestRule.mFullscreenManager, false,
                 true, /*showMaximizedButton=*/true,
-                /*startMaximized=*/false, position, ACTIVITY_SIDE_SHEET_SLIDE_IN_DEFAULT,
+                /*startMaximized=*/false, position, ACTIVITY_SIDE_SHEET_SLIDE_IN_FROM_SIDE,
                 mPCCTTestRule.mHandleStrategyFactory, decorationType, roundedCornersPosition);
         pcct.setMockViewForTesting(mPCCTTestRule.mCoordinatorLayout, mPCCTTestRule.mToolbarView,
                 mPCCTTestRule.mToolbarCoordinator);
@@ -236,6 +235,7 @@
                 mPCCTTestRule.mLayoutParams.topMargin);
     }
 
+    @Config(sdk = Build.VERSION_CODES.Q)
     @Test
     public void leftShadowIsVisible() {
         doReturn(47)
@@ -255,6 +255,7 @@
                 mPCCTTestRule.mLayoutParams.rightMargin);
     }
 
+    @Config(sdk = Build.VERSION_CODES.Q)
     @Test
     public void rightShadowIsVisible() {
         doReturn(47)
@@ -281,7 +282,7 @@
                 .getDimensionPixelSize(eq(R.dimen.custom_tabs_handle_height));
         mPCCTTestRule.configLandscapeMode();
         var strategy = createPcctSideSheetStrategy(2000, ACTIVITY_SIDE_SHEET_POSITION_END,
-                ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT,
+                ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW,
                 ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_TOP);
         strategy.onToolbarInitialized(
                 mPCCTTestRule.mToolbarCoordinator, mPCCTTestRule.mToolbarView, 5);
@@ -353,7 +354,7 @@
                 .when(mPCCTTestRule.mResources)
                 .getDimensionPixelSize(eq(R.dimen.custom_tabs_shadow_offset));
         mPCCTTestRule.configLandscapeMode();
-        var strategy = createPcctSideSheetStrategy(2000, ACTIVITY_SIDE_SHEET_SLIDE_IN_DEFAULT,
+        var strategy = createPcctSideSheetStrategy(2000, ACTIVITY_SIDE_SHEET_SLIDE_IN_FROM_SIDE,
                 ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DIVIDER,
                 ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_NONE);
         strategy.onToolbarInitialized(
@@ -376,7 +377,7 @@
         mPCCTTestRule.configLandscapeMode();
         // Only override instead of shadow. If they set to no decoration, we don't override with
         // divider line
-        var strategy = createPcctSideSheetStrategy(2000, ACTIVITY_SIDE_SHEET_SLIDE_IN_DEFAULT,
+        var strategy = createPcctSideSheetStrategy(2000, ACTIVITY_SIDE_SHEET_SLIDE_IN_FROM_SIDE,
                 ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW,
                 ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_NONE);
         strategy.onToolbarInitialized(
@@ -396,7 +397,7 @@
                 .when(mPCCTTestRule.mResources)
                 .getDimensionPixelSize(eq(R.dimen.custom_tabs_shadow_offset));
         mPCCTTestRule.configLandscapeMode();
-        var strategy = createPcctSideSheetStrategy(2000, ACTIVITY_SIDE_SHEET_POSITION_DEFAULT,
+        var strategy = createPcctSideSheetStrategy(2000, ACTIVITY_SIDE_SHEET_POSITION_END,
                 ACTIVITY_SIDE_SHEET_DECORATION_TYPE_NONE, ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_NONE);
         strategy.onToolbarInitialized(
                 mPCCTTestRule.mToolbarCoordinator, mPCCTTestRule.mToolbarView, 5);
@@ -409,6 +410,7 @@
                 mPCCTTestRule.mLayoutParams.leftMargin);
     }
 
+    @Config(sdk = Build.VERSION_CODES.Q)
     @Test
     public void enterAndExitHtmlFullscreen() {
         doReturn(47)
@@ -454,7 +456,7 @@
 
     @Test
     public void enterAndExitHtmlFullscreen_useDivider() {
-        var strategy = createPcctSideSheetStrategy(800, ACTIVITY_SIDE_SHEET_SLIDE_IN_DEFAULT,
+        var strategy = createPcctSideSheetStrategy(800, ACTIVITY_SIDE_SHEET_SLIDE_IN_FROM_SIDE,
                 ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DIVIDER,
                 ACTIVITY_SIDE_SHEET_ROUNDED_CORNERS_NONE);
         strategy.onToolbarInitialized(
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarUnitTest.java
index d027fbf..3ff35b6 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarUnitTest.java
@@ -6,6 +6,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -56,6 +57,7 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate;
+import org.chromium.chrome.browser.customtabs.features.partialcustomtab.SimpleHandleStrategy;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar.CustomTabLocationBar;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
@@ -412,6 +414,23 @@
         assertFalse(mToolbar.isMaximizeButtonEnabledForTesting());
     }
 
+    @Test
+    @Features.EnableFeatures({ChromeFeatureList.CCT_RESIZABLE_SIDE_SHEET})
+    public void testHandleStrategy_ClickCloseListener() {
+        var strategy1 = new SimpleHandleStrategy(r -> {});
+        mToolbar.setHandleStrategy(strategy1);
+
+        View.OnClickListener listener = v -> {};
+        mToolbar.setCustomTabCloseClickHandler(listener);
+        assertNotNull(strategy1.getClickCloseHandlerForTesting());
+
+        var strategy2 = new SimpleHandleStrategy(r -> {});
+        // Another call to #setHandleStrategy which can come from device rotation.
+        // HandleStrategy should be initialized properly in response.
+        mToolbar.setHandleStrategy(strategy2);
+        assertNotNull(strategy2.getClickCloseHandlerForTesting());
+    }
+
     private void assertUrlAndTitleVisible(boolean titleVisible, boolean urlVisible) {
         int expectedTitleVisibility = titleVisible ? View.VISIBLE : View.GONE;
         int expectedUrlVisibility = urlVisible ? View.VISIBLE : View.GONE;
diff --git a/chrome/android/modules/chrome_bundle_tmpl.gni b/chrome/android/modules/chrome_bundle_tmpl.gni
index db74b6d..4c11a5f5 100644
--- a/chrome/android/modules/chrome_bundle_tmpl.gni
+++ b/chrome/android/modules/chrome_bundle_tmpl.gni
@@ -43,6 +43,9 @@
     android_manifest_dep =
         "${invoker.base_module_target}__android_manifest__split"
     java_deps = [ "//chrome/android:chrome_all_java" ]
+    if (_is_monochrome) {
+      java_deps += [ "//chrome/android:monochrome_java" ]
+    }
     if (defined(invoker.chrome_deps)) {
       java_deps += invoker.chrome_deps
     }
@@ -181,30 +184,6 @@
   }
 
   android_app_bundle(target_name) {
-    forward_variables_from(invoker,
-                           [
-                             "add_view_trace_events",
-                             "base_module_target",
-                             "baseline_profile_path",
-                             "bundle_name",
-                             "compress_shared_libraries",
-                             "enable_lint",
-                             "expected_libs_and_assets",
-                             "expected_libs_and_assets_base",
-                             "expected_proguard_config",
-                             "expected_proguard_config_base",
-                             "keystore_name",
-                             "keystore_password",
-                             "keystore_path",
-                             "lint_baseline_file",
-                             "lint_jar_path",
-                             "lint_min_sdk_version",
-                             "lint_suppressions_file",
-                             "lint_suppressions_dep",
-                             "proguard_android_sdk_dep",
-                             "rotation_config",
-                             "static_library_provider",
-                           ])
     min_sdk_version = _min_sdk_version
     command_line_flags_file = "chrome-command-line"
     proguard_enabled = !is_java_debug
@@ -224,6 +203,12 @@
     # testing easier. This removes the need to manually specify, e.g.,
     # "-m dev_ui" on every install or run.
     default_modules_for_testing = [ "dev_ui" ]
+
+    if (!is_java_debug && _is_monochrome) {
+      proguard_android_sdk_dep = webview_framework_dep
+    }
+
+    forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
   }
 
   if (defined(invoker.expected_android_manifest_template)) {
diff --git a/chrome/app/DEPS b/chrome/app/DEPS
index da589e0..2928e8b 100644
--- a/chrome/app/DEPS
+++ b/chrome/app/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+ash/components/arc/arc_util.h",
   "+ash/constants",
   "+ash/public",
   "+chrome/browser",
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 3bbd1f9..fb50937 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -148,6 +148,7 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/components/arc/arc_util.h"
 #include "ash/constants/ash_paths.h"
 #include "ash/constants/ash_switches.h"
 #include "base/system/sys_info.h"
@@ -926,7 +927,7 @@
 
   if (is_browser_process) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-    ash::ConfigureSwap();
+    ash::ConfigureSwap(arc::IsArcAvailable());
     ash::InitializeKstaled();
 #endif
   }
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 046cba0..662ac357 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -2950,12 +2950,18 @@
   <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_PRINTER" desc="In CUPS printing settings subpage, text for the link adding a new CUPS printer.">
     Add printer
   </message>
-    <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_DETECTED_OR_NEW_PRINTER" desc="In CUPS printing settings subpage, explanatory text for the nearby printers list.">
+  <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_DETECTED_OR_NEW_PRINTER" desc="In CUPS printing settings subpage, explanatory text for the nearby printers list.">
     Save detected printers to your profile, or add a new printer. <ph name="LINK_BEGIN">&lt;a&gt;</ph>Learn more<ph name="LINK_END">&lt;/a&gt;</ph>
   </message>
+  <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS_READY_SUBTEXT" desc="In CUPS printing settings subpage, explanatory text for the nearby printers list." translateable="false">
+    Connected printers will automatically appear here and ready to use or save to your profile.
+  </message>
   <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS" desc="In CUPS printing settings subpage, title for the nearby printers list.">
     Add printers to your profile
   </message>
+  <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS_READY" desc="In CUPS printing settings subpage, title for the nearby printers list." translateable="false">
+    Available printers ready to use
+  </message>
   <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS_COUNT_MANY" desc="In CUPS printing settings subpage, this message will be read aloud to the user to inform them on the number of printers showing on the screen that are available to save.">
     There are <ph name="PRINTER_COUNT">$1<ex>3</ex></ph> printers available to save.
   </message>
@@ -3004,6 +3010,9 @@
   <message name="IDS_SETTINGS_PRINTING_CUPS_SAVED_PRINTERS_TITLE" desc="Text for the title of the user's saved printers list.">
     Your saved printers
   </message>
+  <message name="IDS_SETTINGS_PRINTING_CUPS_SAVED_PRINTERS_SUBTEXT" desc="Subtext of the user's saved printers list." translateable="false">
+    Saved printers will appear here for easier managing and access.
+  </message>
   <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_MANY" desc="In CUPS printing settings subpage, this message will be read aloud to the user to inform them on the number of printers previously saved by the user.">
     You have <ph name="PRINTER_COUNT">$1<ex>3</ex></ph> saved printers.
   </message>
@@ -3777,15 +3786,6 @@
   <message name="IDS_SETTINGS_DEVICE_INFO_A11Y_LABEL_EID_AND_IMEI" desc="A11y label for the network device info popup dialog that's read out when both EID and IMEI is displayed.">
     Your device EID is <ph name="EID_NUMBER">$1<ex>123456789</ex></ph> and device IMEI is <ph name="IMEI_NUMBER">$1<ex>123456789</ex></ph>. These numbers can be used to help activate service.
   </message>
-  <message name="IDS_SETTINGS_INTERNET_PASSPOINT_DETAILS" desc="Name of the settings page which displays details about Passpoint.">
-    Passpoint provider details
-  </message>
-  <message name="IDS_SETTINGS_INTERNET_PASSPOINT_SECTION_LABEL" desc="Label of the section that contains the list of Passpoint subscriptions.">
-    Passpoint subscriptions
-  </message>
-  <message name="IDS_SETTINGS_INTERNET_PASSPOINT_PROVIDER" desc="Label of the link to the Passpoint provider details page.">
-    Passpoint provider
-  </message>
 
   <!-- Users Page (OS Settings) -->
   <message name="IDS_SETTINGS_USERS_MODIFIED_BY_OWNER_LABEL" desc="Label saying settings may only be modified by the device owner.">
@@ -4836,6 +4836,36 @@
   <message name="IDS_SETTINGS_KEYBOARD_NO_KEYBOARDS_HELP_MESSAGE" desc="In Keyboard remap keys subpage, the message that notifies users that no keyboards are connected.">
     No keyboard detected
   </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_ALT" desc="In keyboard remap keys subpage, the label and dropdown list item for the Alt key.">
+    alt
+  </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ASSISTANT" desc="In keyboard remap keys subpage, the label and dropdown list item for the Assistant key.">
+    assistant
+  </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_BACKSPACE" desc="In keyboard remap keys subpage, the dropdown list item for the Backspace key.">
+    backspace
+  </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_CAPS_LOCK" desc="In keyboard remap keys subpage, the label and dropdown list item for the Caps Lock key.">
+    caps lock
+  </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_CTRL" desc="In keyboard remap keys subpage, the label and dropdown list item for the Ctrl key.">
+    ctrl
+  </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ESCAPE" desc="In keyboard remap keys subpage, the dropdown list item for the Escape key.">
+    escape
+  </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_COMMAND" desc="In keyboard remap keys subpage, the dropdown list item for the external Command key on Apple keyboards when there's no internal keyboard on the device.">
+    command
+  </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_EXTERNAL_META" desc="In keyboard remap keys subpage, the dropdown list item for the external Meta key (Search key on ChromeOS keyboards, and Windows key on Windows keyboards).">
+    external meta
+  </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_SEARCH" desc="In keyboard remap keys subpage, the label and dropdown list item for the Search key.">
+    search
+  </message>
+  <message name="IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_DISABLED" desc="In keyboard remap keys subpage, the dropdown list item for a disabled key.">
+    disabled
+  </message>
 
   <!-- Device Keyboard page (OS settings) -->
   <message name="IDS_SETTINGS_KEYBOARD_TITLE" desc="In Device Settings, the title of the keyboard settings subpage.">
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_PASSPOINT_DETAILS.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_PASSPOINT_DETAILS.png.sha1
deleted file mode 100644
index aa0416c..0000000
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_PASSPOINT_DETAILS.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b4b8862a66e3a1c3bf9d9a71574e477b96b5a073
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_PASSPOINT_PROVIDER.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_PASSPOINT_PROVIDER.png.sha1
deleted file mode 100644
index 780c9ff81..0000000
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_PASSPOINT_PROVIDER.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-97fd1247867e556c9c47110e242413a363ec8e3e
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_PASSPOINT_SECTION_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_PASSPOINT_SECTION_LABEL.png.sha1
deleted file mode 100644
index c0f5c93..0000000
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_PASSPOINT_SECTION_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-9efa3c921bf5a986407ca2002268f2d5cf52f33e
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ASSISTANT.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ASSISTANT.png.sha1
new file mode 100644
index 0000000..b76e213
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ASSISTANT.png.sha1
@@ -0,0 +1 @@
+08266d4cdb272579774bf04d2e6f2f348531bec7
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_BACKSPACE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_BACKSPACE.png.sha1
new file mode 100644
index 0000000..d3a3107fd
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_BACKSPACE.png.sha1
@@ -0,0 +1 @@
+6e0bb45bf142c9138dfb2f8e6604b2f26fc29803
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_CAPS_LOCK.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_CAPS_LOCK.png.sha1
new file mode 100644
index 0000000..0f8ecada
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_CAPS_LOCK.png.sha1
@@ -0,0 +1 @@
+06e276f51206bc632b14607e23246f4469388275
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_COMMAND.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_COMMAND.png.sha1
new file mode 100644
index 0000000..104f63a
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_COMMAND.png.sha1
@@ -0,0 +1 @@
+bda4c00e5e934f1de022cabb82c29bbfe6022c29
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_DISABLED.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_DISABLED.png.sha1
new file mode 100644
index 0000000..d9931a6
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_DISABLED.png.sha1
@@ -0,0 +1 @@
+8dfff6bb92dba727d88119a739509022ef541401
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ESCAPE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ESCAPE.png.sha1
new file mode 100644
index 0000000..ab63d86
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ESCAPE.png.sha1
@@ -0,0 +1 @@
+a758f97fb43a2027d47163988ac5ab42dd79f876
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_EXTERNAL_META.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_EXTERNAL_META.png.sha1
new file mode 100644
index 0000000..a082dd9
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_EXTERNAL_META.png.sha1
@@ -0,0 +1 @@
+10e6cc2dd102fc248eea9d46dae9a7ad90f8c9ed
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_ALT.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_ALT.png.sha1
new file mode 100644
index 0000000..d0736ae5
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_ALT.png.sha1
@@ -0,0 +1 @@
+57e5b27281acd327d66aec9be8597e5e571c4da2
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_CTRL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_CTRL.png.sha1
new file mode 100644
index 0000000..101b209
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_CTRL.png.sha1
@@ -0,0 +1 @@
+6903fcf82ddf3cb05b7f777e5654ecc3f4b8921b
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_SEARCH.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_SEARCH.png.sha1
new file mode 100644
index 0000000..2cad3ce
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_SEARCH.png.sha1
@@ -0,0 +1 @@
+d46075593cdc18733985e8ec397e4beeb1706a42
\ No newline at end of file
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index f8a5b2d..7f079d8 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -52,6 +52,7 @@
     "cut_menu.icon",
     "default_touch_favicon.icon",
     "default_touch_favicon_mask.icon",
+    "desktop_windows.icon",
     "download_in_progress.icon",
     "download_in_progress_chrome_refresh.icon",
     "download_in_progress_touch.icon",
@@ -85,6 +86,7 @@
     "incognito_refresh_menu.icon",
     "ink_highlighter.icon",
     "input.icon",
+    "install_desktop_chrome_refresh.icon",
     "journeys.icon",
     "key.icon",
     "key_chrome_refresh.icon",
diff --git a/chrome/app/vector_icons/desktop_windows.icon b/chrome/app/vector_icons/desktop_windows.icon
new file mode 100644
index 0000000..f1899b5
--- /dev/null
+++ b/chrome/app/vector_icons/desktop_windows.icon
@@ -0,0 +1,34 @@
+// Copyright 2023 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, 16,
+MOVE_TO, 5.54f, 13.72f,
+R_V_LINE_TO, -1.38f,
+R_H_LINE_TO, 1.2f,
+R_V_LINE_TO, -1.2f,
+R_H_LINE_TO, -3.89f,
+R_CUBIC_TO, -0.38f, 0, -0.71f, -0.14f, -0.98f, -0.41f,
+R_ARC_TO, 1.33f, 1.33f, 0, 0, 1, -0.4f, -0.98f,
+V_LINE_TO, 3.64f,
+R_CUBIC_TO, 0, -0.38f, 0.13f, -0.71f, 0.4f, -0.98f,
+R_CUBIC_TO, 0.27f, -0.27f, 0.6f, -0.41f, 0.98f, -0.41f,
+R_H_LINE_TO, 10.31f,
+R_CUBIC_TO, 0.38f, 0, 0.71f, 0.14f, 0.98f, 0.41f,
+R_CUBIC_TO, 0.27f, 0.27f, 0.4f, 0.6f, 0.4f, 0.98f,
+R_V_LINE_TO, 6.12f,
+R_CUBIC_TO, 0, 0.38f, -0.13f, 0.71f, -0.4f, 0.98f,
+R_CUBIC_TO, -0.27f, 0.27f, -0.6f, 0.41f, -0.98f, 0.41f,
+H_LINE_TO, 9.26f,
+R_V_LINE_TO, 1.2f,
+R_H_LINE_TO, 1.2f,
+R_V_LINE_TO, 1.38f,
+CLOSE,
+MOVE_TO, 2.85f, 9.75f,
+R_H_LINE_TO, 10.3f,
+V_LINE_TO, 3.64f,
+H_LINE_TO, 2.85f,
+CLOSE,
+R_MOVE_TO, 0, 0,
+V_LINE_TO, 3.64f,
+CLOSE
diff --git a/chrome/app/vector_icons/install_desktop_chrome_refresh.icon b/chrome/app/vector_icons/install_desktop_chrome_refresh.icon
new file mode 100644
index 0000000..de83e21
--- /dev/null
+++ b/chrome/app/vector_icons/install_desktop_chrome_refresh.icon
@@ -0,0 +1,71 @@
+// Copyright 2023 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, 7, 17,
+R_V_LINE_TO, -2,
+H_LINE_TO, 3.5f,
+R_CUBIC_TO, -0.42f, 0, -0.77f, -0.15f, -1.06f, -0.44f,
+ARC_TO, 1.45f, 1.45f, 0, 0, 1, 2, 13.5f,
+R_V_LINE_TO, -9,
+R_CUBIC_TO, 0, -0.42f, 0.15f, -0.77f, 0.44f, -1.06f,
+ARC_TO, 1.45f, 1.45f, 0, 0, 1, 3.5f, 3,
+H_LINE_TO, 11,
+R_V_LINE_TO, 1.5f,
+H_LINE_TO, 3.5f,
+R_V_LINE_TO, 9,
+R_H_LINE_TO, 13,
+V_LINE_TO, 11,
+H_LINE_TO, 18,
+R_V_LINE_TO, 2.5f,
+R_CUBIC_TO, 0, 0.42f, -0.15f, 0.77f, -0.44f, 1.06f,
+ARC_TO, 1.45f, 1.45f, 0, 0, 1, 16.5f, 15,
+H_LINE_TO, 13,
+R_V_LINE_TO, 2,
+H_LINE_TO, 7,
+CLOSE,
+R_MOVE_TO, 7.48f, -6,
+LINE_TO, 11, 7.52f,
+R_LINE_TO, 1.06f, -1.06f,
+R_LINE_TO, 1.69f, 1.69f,
+V_LINE_TO, 3,
+R_H_LINE_TO, 1.5f,
+R_V_LINE_TO, 5.1f,
+R_LINE_TO, 1.69f, -1.69f,
+LINE_TO, 18, 7.48f,
+LINE_TO, 14.48f, 11,
+CLOSE
+
+CANVAS_DIMENSIONS, 16,
+MOVE_TO, 5.53f, 13.73f,
+R_V_LINE_TO, -1.66f,
+R_H_LINE_TO, -2.68f,
+R_CUBIC_TO, -0.38f, 0, -0.71f, -0.13f, -0.98f, -0.4f,
+R_ARC_TO, 1.34f, 1.34f, 0, 0, 1, -0.4f, -0.98f,
+V_LINE_TO, 3.64f,
+R_CUBIC_TO, 0, -0.38f, 0.13f, -0.71f, 0.4f, -0.98f,
+R_CUBIC_TO, 0.27f, -0.27f, 0.6f, -0.4f, 0.98f, -0.4f,
+R_H_LINE_TO, 5.95f,
+R_V_LINE_TO, 1.38f,
+H_LINE_TO, 2.85f,
+R_V_LINE_TO, 7.04f,
+R_H_LINE_TO, 10.3f,
+V_LINE_TO, 8.68f,
+R_H_LINE_TO, 1.38f,
+R_V_LINE_TO, 2.01f,
+R_CUBIC_TO, 0, 0.39f, -0.13f, 0.72f, -0.4f, 0.99f,
+R_CUBIC_TO, -0.27f, 0.27f, -0.6f, 0.4f, -0.98f, 0.4f,
+R_H_LINE_TO, -2.68f,
+R_V_LINE_TO, 1.66f,
+CLOSE,
+R_MOVE_TO, 6.06f, -5,
+LINE_TO, 8.76f, 5.91f,
+R_LINE_TO, 0.89f, -0.89f,
+R_LINE_TO, 1.32f, 1.32f,
+V_LINE_TO, 2.27f,
+R_H_LINE_TO, 1.26f,
+R_V_LINE_TO, 4.04f,
+R_LINE_TO, 1.32f, -1.32f,
+R_LINE_TO, 0.9f, 0.9f,
+CLOSE
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 49c2516..3c040d2 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -47,7 +47,6 @@
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/notifications/scheduler/public/features.h"
 #include "chrome/browser/page_info/page_info_features.h"
-#include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h"
 #include "chrome/browser/permissions/notifications_permission_revocation_config.h"
 #include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
 #include "chrome/browser/predictors/loading_predictor_config.h"
@@ -3302,42 +3301,6 @@
     {"Conservative", kHeuristicMemorySaverConservative,
      std::size(kHeuristicMemorySaverConservative), nullptr},
 };
-
-const FeatureEntry::Choice kHighEfficiencyModeTimeBeforeDiscardChoices[] = {
-    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
-    {"1 Minute Discard",
-     performance_manager::user_tuning::UserPerformanceTuningManager::
-         kTimeBeforeDiscardInMinutesSwitch,
-     "1"},
-    {"5 Minute Discard",
-     performance_manager::user_tuning::UserPerformanceTuningManager::
-         kTimeBeforeDiscardInMinutesSwitch,
-     "5"},
-    {"15 Minute Discard",
-     performance_manager::user_tuning::UserPerformanceTuningManager::
-         kTimeBeforeDiscardInMinutesSwitch,
-     "15"},
-    {"30 Minute Discard",
-     performance_manager::user_tuning::UserPerformanceTuningManager::
-         kTimeBeforeDiscardInMinutesSwitch,
-     "30"},
-    {"1 Hour Discard",
-     performance_manager::user_tuning::UserPerformanceTuningManager::
-         kTimeBeforeDiscardInMinutesSwitch,
-     "60"},
-    {"4 Hour Discard",
-     performance_manager::user_tuning::UserPerformanceTuningManager::
-         kTimeBeforeDiscardInMinutesSwitch,
-     "240"},
-    {"6 Hour Discard",
-     performance_manager::user_tuning::UserPerformanceTuningManager::
-         kTimeBeforeDiscardInMinutesSwitch,
-     "360"},
-    {"12 Hour Discard",
-     performance_manager::user_tuning::UserPerformanceTuningManager::
-         kTimeBeforeDiscardInMinutesSwitch,
-     "720"},
-};
 #endif  // !BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_ANDROID)
@@ -8522,7 +8485,7 @@
      FEATURE_VALUE_TYPE(features::kFedCmSelectiveDisclosure)},
 
     {"fedcm-rp-context", flag_descriptions::kFedCmRpContextName,
-     flag_descriptions::kFedCmRpContextDescription, kOsDesktop,
+     flag_descriptions::kFedCmRpContextDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kFedCmRpContext)},
 
     {"fedcm-user-info", flag_descriptions::kFedCmUserInfoName,
@@ -9652,10 +9615,6 @@
          performance_manager::features::kHeuristicMemorySaver,
          kHeuristicMemorySaverVariations,
          "HeuristicMemorySaver")},
-    {"high-efficiency-mode-time-before-discard",
-     flag_descriptions::kHighEfficiencyModeTimeBeforeDiscardName,
-     flag_descriptions::kHighEfficiencyModeTimeBeforeDiscardDescription,
-     kOsDesktop, MULTI_VALUE_TYPE(kHighEfficiencyModeTimeBeforeDiscardChoices)},
 #endif
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
index 35ec0fcf..b61d2b4b 100644
--- a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
+++ b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
@@ -640,7 +640,7 @@
      * @return An int representing the side sheet decoration type for the Activity.
      */
     public int getActivitySideSheetDecorationType() {
-        return ACTIVITY_SIDE_SHEET_DECORATION_TYPE_DEFAULT;
+        return ACTIVITY_SIDE_SHEET_DECORATION_TYPE_SHADOW;
     }
 
     /**
@@ -694,11 +694,11 @@
 
     /** Return the default behavior. */
     public int getSideSheetSlideInBehavior() {
-        return ACTIVITY_SIDE_SHEET_SLIDE_IN_DEFAULT;
+        return ACTIVITY_SIDE_SHEET_SLIDE_IN_FROM_SIDE;
     }
 
     /** Return the default position. */
     public int getSideSheetPosition() {
-        return ACTIVITY_SIDE_SHEET_POSITION_DEFAULT;
+        return ACTIVITY_SIDE_SHEET_POSITION_END;
     }
 }
diff --git a/chrome/browser/apps/platform_apps/api/browser/browser_api.cc b/chrome/browser/apps/platform_apps/api/browser/browser_api.cc
index e80b3ac..db46a9b6 100644
--- a/chrome/browser/apps/platform_apps/api/browser/browser_api.cc
+++ b/chrome/browser/apps/platform_apps/api/browser/browser_api.cc
@@ -23,12 +23,9 @@
   options.create_browser_if_needed = true;
   options.url = params->options.url;
 
-  auto result =
+  const auto result =
       extensions::ExtensionTabUtil::OpenTab(this, options, user_gesture());
-  if (!result.has_value())
-    return RespondNow(Error(result.error()));
-
-  return RespondNow(NoArguments());
+  return RespondNow(result.has_value() ? NoArguments() : Error(result.error()));
 }
 
 }  // namespace api
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
index e61cf9c..7b5733a 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/ash/app_restore/arc_ghost_window_delegate.h"
 
+#include "base/notreached.h"
 #include "chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.h"
 #include "chrome/browser/ash/app_restore/arc_window_utils.h"
 #include "chrome/browser/ash/arc/window_predictor/window_predictor_utils.h"
+#include "chromeos/ui/base/window_state_type.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 
@@ -114,18 +116,25 @@
     return;
   }
 
-  shell_surface_->SetBounds(display_id, bounds_in_screen);
-
-  if (requested_state != window_state->GetStateType()) {
-    DCHECK(requested_state == chromeos::WindowStateType::kPrimarySnapped ||
-           requested_state == chromeos::WindowStateType::kSecondarySnapped);
-
-    if (requested_state == chromeos::WindowStateType::kPrimarySnapped)
+  switch (requested_state) {
+    case chromeos::WindowStateType::kPrimarySnapped:
+      // TODO(b/279530665): Maybe sync to ARC.
       shell_surface_->SetSnapPrimary(chromeos::kDefaultSnapRatio);
-    else
+      break;
+    case chromeos::WindowStateType::kSecondarySnapped:
+      // TODO(b/279530665): Maybe sync to ARC.
       shell_surface_->SetSnapSecondary(chromeos::kDefaultSnapRatio);
-    // TODO(sstan): Currently the snap state will be ignored. Sync it to ARC.
+      break;
+    case chromeos::WindowStateType::kFloated:
+      // Ignore the unsupported request.
+      return;
+    default:
+      if (requested_state != window_state->GetStateType()) {
+        NOTREACHED();
+      }
   }
+
+  shell_surface_->SetBounds(display_id, bounds_in_screen);
   shell_surface_->OnSurfaceCommit();
   bounds_ = gfx::Rect(bounds_in_screen);
   UpdateWindowInfoToArc();
diff --git a/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc b/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
index 7f597ed..49f415f 100644
--- a/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
+++ b/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
@@ -3166,7 +3166,7 @@
   // Snap |window| to the left and store its window properties.
   // TODO(sammiequon): Store and check desk id and restore bounds.
   auto* window_state = WindowState::Get(window);
-  const WMEvent left_snap_event(WM_EVENT_SNAP_PRIMARY);
+  const WindowSnapWMEvent left_snap_event(WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&left_snap_event);
   const chromeos::WindowStateType pre_save_state_type =
       window_state->GetStateType();
diff --git a/chrome/browser/ash/crosapi/feedback_ash.cc b/chrome/browser/ash/crosapi/feedback_ash.cc
index 0b15c73..199cd6a 100644
--- a/chrome/browser/ash/crosapi/feedback_ash.cc
+++ b/chrome/browser/ash/crosapi/feedback_ash.cc
@@ -26,7 +26,7 @@
       return chrome::kFeedbackSourceChromeLabs;
     case mojom::LacrosFeedbackSource::kLacrosQuickAnswers:
       return chrome::kFeedbackSourceQuickAnswers;
-    case mojom::LacrosFeedbackSource::kLacrosWindowLayoutMenu:
+    case mojom::LacrosFeedbackSource::kDeprecatedLacrosWindowLayoutMenu:
       return chrome::kFeedbackSourceWindowLayoutMenu;
     case mojom::LacrosFeedbackSource::kUnknown:
       return chrome::kFeedbackSourceUnknownLacrosSource;
diff --git a/chrome/browser/ash/extensions/incoming_native_messaging_apitest.cc b/chrome/browser/ash/extensions/incoming_native_messaging_apitest.cc
index c55c75b5..117d088a 100644
--- a/chrome/browser/ash/extensions/incoming_native_messaging_apitest.cc
+++ b/chrome/browser/ash/extensions/incoming_native_messaging_apitest.cc
@@ -18,6 +18,7 @@
 #include "extensions/browser/api/messaging/channel_endpoint.h"
 #include "extensions/browser/api/messaging/message_service.h"
 #include "extensions/browser/api/messaging/native_message_host.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/api/messaging/messaging_endpoint.h"
 #include "extensions/common/api/messaging/port_id.h"
 #include "extensions/common/api/messaging/serialization_format.h"
@@ -84,7 +85,7 @@
         extensions::ChannelEndpoint(profile()), port_id,
         extensions::MessagingEndpoint::ForNativeApp(kFakeNativeAppName),
         std::move(native_message_port), extension_->id(), GURL(),
-        std::string() /* channel_name */);
+        extensions::ChannelType::kNative, std::string() /* channel_name */);
   }
 
  private:
diff --git a/chrome/browser/ash/fusebox/fusebox_read_writer.cc b/chrome/browser/ash/fusebox/fusebox_read_writer.cc
index 7e16eb2..d963cfca 100644
--- a/chrome/browser/ash/fusebox/fusebox_read_writer.cc
+++ b/chrome/browser/ash/fusebox/fusebox_read_writer.cc
@@ -366,18 +366,10 @@
     base::expected<base::ScopedFD, int> result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
-  if (!result.has_value()) {
-    Write2ResponseProto response_proto;
-    response_proto.set_posix_error_code(result.error());
-    content::GetUIThreadTaskRunner({})->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback), response_proto));
-    return;
-  }
-
   ReadWriter* self = weak_ptr.get();
-  if (!self) {
+  if (!result.has_value() || !self) {
     Write2ResponseProto response_proto;
-    response_proto.set_posix_error_code(EBUSY);
+    response_proto.set_posix_error_code(result.error_or(EBUSY));
     content::GetUIThreadTaskRunner({})->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), response_proto));
     return;
diff --git a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc
index e0aaf01..fdcaf362 100644
--- a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc
+++ b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc
@@ -23,6 +23,7 @@
 #include "extensions/browser/api/messaging/message_service.h"
 #include "extensions/browser/api/messaging/native_message_host.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/api/messaging/messaging_endpoint.h"
 #include "extensions/common/api/messaging/serialization_format.h"
 #include "extensions/common/extension.h"
@@ -137,7 +138,7 @@
       extensions::MessagingEndpoint::ForNativeApp(
           VmSKForwardingNativeMessageHost::kHostName),
       std::move(native_message_port), extension_id, GURL(),
-      std::string() /* channel_name */);
+      extensions::ChannelType::kNative, std::string() /* channel_name */);
 }
 
 void VmSKForwardingNativeMessageHost::DeliverMessageToSKForwardingExtension(
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_fetch_status_job.cc b/chrome/browser/ash/policy/remote_commands/device_command_fetch_status_job.cc
index 3119efe..4c08e682 100644
--- a/chrome/browser/ash/policy/remote_commands/device_command_fetch_status_job.cc
+++ b/chrome/browser/ash/policy/remote_commands/device_command_fetch_status_job.cc
@@ -43,7 +43,8 @@
   if (manager && manager->GetStatusUploader() &&
       manager->GetSystemLogUploader()) {
     manager->GetStatusUploader()->ScheduleNextStatusUploadImmediately();
-    manager->GetSystemLogUploader()->ScheduleNextSystemLogUploadImmediately();
+    manager->GetSystemLogUploader()->ScheduleNextSystemLogUploadImmediately(
+        unique_id());
     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
         FROM_HERE, base::BindOnce(std::move(result_callback),
                                   ResultType::kSuccess, absl::nullopt));
diff --git a/chrome/browser/ash/policy/uploading/system_log_uploader.cc b/chrome/browser/ash/policy/uploading/system_log_uploader.cc
index c4907db..5658722d 100644
--- a/chrome/browser/ash/policy/uploading/system_log_uploader.cc
+++ b/chrome/browser/ash/policy/uploading/system_log_uploader.cc
@@ -36,10 +36,12 @@
 #include "components/feedback/redaction_tool/redaction_tool.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/browser/policy_conversions.h"
+#include "components/policy/core/common/remote_commands/remote_command_job.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
 #include "net/http/http_request_headers.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/zlib/google/zip.h"
 
 namespace policy {
@@ -293,6 +295,11 @@
 const base::TimeDelta SystemLogUploader::kLogThrottleWindowDuration =
     base::Hours(24);
 
+// The request header to attach the command ID to upload request. The command Id
+// will be included in uploads that are triggered by
+// `DeviceCommandFetchStatusJob`.
+const char* const SystemLogUploader::kCommandIdHeaderName = "Command-ID";
+
 // String constant identifying the header field which stores the file type.
 const char* const SystemLogUploader::kFileTypeHeaderName = "File-Type";
 
@@ -337,7 +344,7 @@
   // Immediately schedule the next system log upload (last_upload_attempt_ is
   // set to the start of the epoch, so this will trigger an update upload in the
   // immediate future).
-  ScheduleNextSystemLogUpload(upload_frequency_);
+  ScheduleNextSystemLogUpload(upload_frequency_, absl::nullopt);
 }
 
 SystemLogUploader::~SystemLogUploader() {}
@@ -355,7 +362,7 @@
 
   // On successful log upload schedule the next log upload after
   // upload_frequency_ time from now.
-  ScheduleNextSystemLogUpload(upload_frequency_);
+  ScheduleNextSystemLogUpload(upload_frequency_, absl::nullopt);
 }
 
 void SystemLogUploader::OnFailure(UploadJob::ErrorCode error_code) {
@@ -372,13 +379,14 @@
   if (retry_count_++ < kMaxNumRetries) {
     SYSLOG(ERROR) << "Upload failed with error code " << error_code
                   << ", retrying later.";
-    ScheduleNextSystemLogUpload(base::Milliseconds(kErrorUploadDelayMs));
+    ScheduleNextSystemLogUpload(base::Milliseconds(kErrorUploadDelayMs),
+                                absl::nullopt);
   } else {
     // No more retries.
     SYSLOG(ERROR) << "Upload failed with error code " << error_code
                   << ", no more retries.";
     retry_count_ = 0;
-    ScheduleNextSystemLogUpload(upload_frequency_);
+    ScheduleNextSystemLogUpload(upload_frequency_, absl::nullopt);
   }
 }
 
@@ -389,8 +397,9 @@
   return redactor->Redact(data);
 }
 
-void SystemLogUploader::ScheduleNextSystemLogUploadImmediately() {
-  ScheduleNextSystemLogUpload(base::TimeDelta());
+void SystemLogUploader::ScheduleNextSystemLogUploadImmediately(
+    RemoteCommandJob::UniqueIDType command_id) {
+  ScheduleNextSystemLogUpload(base::TimeDelta(), command_id);
 }
 
 void SystemLogUploader::RefreshUploadSettings() {
@@ -410,7 +419,9 @@
   }
 }
 
-void SystemLogUploader::UploadZippedSystemLogs(std::string zipped_system_logs) {
+void SystemLogUploader::UploadZippedSystemLogs(
+    absl::optional<RemoteCommandJob::UniqueIDType> command_id,
+    std::string zipped_system_logs) {
   // Must be called on the main thread.
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!upload_job_);
@@ -434,30 +445,37 @@
       std::make_pair(kFileTypeHeaderName, kFileTypeZippedLogFile));
   header_fields.insert(std::make_pair(net::HttpRequestHeaders::kContentType,
                                       kContentTypeOctetStream));
+  if (command_id) {
+    header_fields.insert(std::make_pair(
+        kCommandIdHeaderName, base::NumberToString(command_id.value())));
+  }
   upload_job_->AddDataSegment(kZippedLogsName, kZippedLogsFileName,
                               header_fields, std::move(data));
   upload_job_->Start();
 }
 
-void SystemLogUploader::StartLogUpload() {
+void SystemLogUploader::StartLogUpload(
+    absl::optional<RemoteCommandJob::UniqueIDType> command_id) {
   // Must be called on the main thread.
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (upload_enabled_) {
     SYSLOG(INFO) << "Reading system logs for upload.";
     log_upload_in_progress_ = true;
-    syslog_delegate_->LoadSystemLogs(base::BindOnce(
-        &SystemLogUploader::OnSystemLogsLoaded, weak_factory_.GetWeakPtr()));
+    syslog_delegate_->LoadSystemLogs(
+        base::BindOnce(&SystemLogUploader::OnSystemLogsLoaded,
+                       weak_factory_.GetWeakPtr(), std::move(command_id)));
   } else {
     // If upload is disabled, schedule the next attempt after 12h.
     SYSLOG(INFO) << "System log upload is disabled, rescheduling.";
     retry_count_ = 0;
     last_upload_attempt_ = base::Time::NowFromSystemTime();
-    ScheduleNextSystemLogUpload(upload_frequency_);
+    ScheduleNextSystemLogUpload(upload_frequency_, absl::nullopt);
   }
 }
 
 void SystemLogUploader::OnSystemLogsLoaded(
+    absl::optional<RemoteCommandJob::UniqueIDType> command_id,
     std::unique_ptr<SystemLogs> system_logs) {
   // Must be called on the main thread.
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -468,7 +486,7 @@
   syslog_delegate_->ZipSystemLogs(
       std::move(system_logs),
       base::BindOnce(&SystemLogUploader::UploadZippedSystemLogs,
-                     weak_factory_.GetWeakPtr()));
+                     weak_factory_.GetWeakPtr(), std::move(command_id)));
 }
 
 // Update the list of logs within kLogThrottleWindowDuration window and add the
@@ -520,7 +538,9 @@
   return updated_log_uploads.empty() ? base::Time() : updated_log_uploads[0];
 }
 
-void SystemLogUploader::ScheduleNextSystemLogUpload(base::TimeDelta frequency) {
+void SystemLogUploader::ScheduleNextSystemLogUpload(
+    base::TimeDelta frequency,
+    absl::optional<RemoteCommandJob::UniqueIDType> command_id) {
   // Don't schedule a new system log upload if there's a log upload in progress
   // (it will be scheduled once the current one completes).
   if (log_upload_in_progress_) {
@@ -551,7 +571,7 @@
   task_runner_->PostDelayedTask(
       FROM_HERE,
       base::BindOnce(&SystemLogUploader::StartLogUpload,
-                     weak_factory_.GetWeakPtr()),
+                     weak_factory_.GetWeakPtr(), command_id),
       delay);
 }
 
diff --git a/chrome/browser/ash/policy/uploading/system_log_uploader.h b/chrome/browser/ash/policy/uploading/system_log_uploader.h
index b794c5f..e46464e 100644
--- a/chrome/browser/ash/policy/uploading/system_log_uploader.h
+++ b/chrome/browser/ash/policy/uploading/system_log_uploader.h
@@ -19,6 +19,8 @@
 #include "base/time/time.h"
 #include "chrome/browser/ash/policy/uploading/upload_job.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
+#include "components/policy/core/common/remote_commands/remote_command_job.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -51,6 +53,7 @@
   static const base::TimeDelta kLogThrottleWindowDuration;
 
   // Http header constants to upload zipped logs.
+  static const char* const kCommandIdHeaderName;
   static const char* const kFileTypeHeaderName;
   static const char* const kFileTypeZippedLogFile;
   static const char* const kZippedLogsName;
@@ -117,7 +120,10 @@
   // ever happened.
   base::Time last_upload_attempt() const { return last_upload_attempt_; }
 
-  void ScheduleNextSystemLogUploadImmediately();
+  // Schedules the next upload immediately. Is triggered in case of a remote
+  // command to upload logs. Attaches `command_id` to the file upload metadata.
+  void ScheduleNextSystemLogUploadImmediately(
+      RemoteCommandJob::UniqueIDType command_id);
 
   // Removes the log upload times before the particular time window ( which were
   // uploaded before kLogThrottleWindowDuration time from now), add the latest
@@ -138,18 +144,25 @@
   void RefreshUploadSettings();
 
   // Starts the system log loading process.
-  void StartLogUpload();
+  void StartLogUpload(
+      absl::optional<RemoteCommandJob::UniqueIDType> command_id);
 
   // The callback is invoked by the Delegate if system logs have been loaded
   // from disk, adds policy dump and calls UploadSystemLogs.
-  void OnSystemLogsLoaded(std::unique_ptr<SystemLogs> system_logs);
+  void OnSystemLogsLoaded(
+      absl::optional<RemoteCommandJob::UniqueIDType> command_id,
+      std::unique_ptr<SystemLogs> system_logs);
 
   // Uploads zipped system logs.
-  void UploadZippedSystemLogs(std::string zipped_system_logs);
+  void UploadZippedSystemLogs(
+      absl::optional<RemoteCommandJob::UniqueIDType> command_id,
+      std::string zipped_system_logs);
 
   // Helper method that figures out when the next system log upload should
   // be scheduled.
-  void ScheduleNextSystemLogUpload(base::TimeDelta frequency);
+  void ScheduleNextSystemLogUpload(
+      base::TimeDelta frequency,
+      absl::optional<RemoteCommandJob::UniqueIDType> command_id);
 
   // The number of consequent retries after the failed uploads.
   int retry_count_;
diff --git a/chrome/browser/ash/policy/uploading/system_log_uploader_unittest.cc b/chrome/browser/ash/policy/uploading/system_log_uploader_unittest.cc
index 25170da..dbff839 100644
--- a/chrome/browser/ash/policy/uploading/system_log_uploader_unittest.cc
+++ b/chrome/browser/ash/policy/uploading/system_log_uploader_unittest.cc
@@ -4,10 +4,12 @@
 
 #include "chrome/browser/ash/policy/uploading/system_log_uploader.h"
 
+#include <map>
 #include <utility>
 
 #include "base/containers/contains.h"
 #include "base/memory/raw_ptr.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
@@ -17,12 +19,16 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/testing_browser_process.h"
+#include "components/policy/core/common/remote_commands/remote_command_job.h"
 #include "components/prefs/testing_pref_service.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_utils.h"
 #include "net/http/http_request_headers.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+using ::testing::ContainerEq;
+
 namespace policy {
 
 namespace {
@@ -34,6 +40,8 @@
 
 constexpr char kZippedData[] = "zipped_data";
 
+constexpr RemoteCommandJob::UniqueIDType kCommandId = 12345;
+
 // Generate the fake system log files.
 SystemLogUploader::SystemLogs GenerateTestSystemLogFiles() {
   SystemLogUploader::SystemLogs system_logs;
@@ -47,7 +55,9 @@
  public:
   // If is_upload_error is false OnSuccess() will be invoked when the
   // Start() method is called, otherwise OnFailure() will be invoked.
-  MockUploadJob(UploadJob::Delegate* delegate, bool is_upload_error);
+  MockUploadJob(UploadJob::Delegate* delegate,
+                bool is_upload_error,
+                bool is_immediate_upload);
   ~MockUploadJob() override;
 
   // policy::UploadJob:
@@ -58,13 +68,33 @@
   void Start() override;
 
  protected:
+  const std::map<std::string, std::string> kExpectedUploadHeaders = {
+      {SystemLogUploader::kFileTypeHeaderName,
+       SystemLogUploader::kFileTypeZippedLogFile},
+      {net::HttpRequestHeaders::kContentType,
+       SystemLogUploader::kContentTypeOctetStream}};
+
+  // Immediate upload headers need to contain "Command-ID" field as they're
+  // triggered by a remote command.
+  const std::map<std::string, std::string> kExpectedHeadersImmediateUpload = {
+      {SystemLogUploader::kFileTypeHeaderName,
+       SystemLogUploader::kFileTypeZippedLogFile},
+      {net::HttpRequestHeaders::kContentType,
+       SystemLogUploader::kContentTypeOctetStream},
+      {SystemLogUploader::kCommandIdHeaderName,
+       base::NumberToString(kCommandId)}};
+
   raw_ptr<UploadJob::Delegate, ExperimentalAsh> delegate_;
   bool is_upload_error_;
+  bool is_immediate_upload_;
 };
 
 MockUploadJob::MockUploadJob(UploadJob::Delegate* delegate,
-                             bool is_upload_error)
-    : delegate_(delegate), is_upload_error_(is_upload_error) {}
+                             bool is_upload_error,
+                             bool is_immediate_upload)
+    : delegate_(delegate),
+      is_upload_error_(is_upload_error),
+      is_immediate_upload_(is_immediate_upload) {}
 
 MockUploadJob::~MockUploadJob() = default;
 
@@ -78,13 +108,9 @@
 
   EXPECT_EQ(SystemLogUploader::kZippedLogsFileName, filename);
 
-  EXPECT_EQ(2U, header_entries.size());
-  EXPECT_EQ(
-      SystemLogUploader::kFileTypeZippedLogFile,
-      header_entries.find(SystemLogUploader::kFileTypeHeaderName)->second);
-  EXPECT_EQ(SystemLogUploader::kContentTypeOctetStream,
-            header_entries.find(net::HttpRequestHeaders::kContentType)->second);
-
+  EXPECT_THAT(header_entries,
+              ContainerEq(is_immediate_upload_ ? kExpectedHeadersImmediateUpload
+                                               : kExpectedUploadHeaders));
   EXPECT_EQ(kZippedData, *data);
 }
 
@@ -104,8 +130,11 @@
 class MockSystemLogDelegate : public SystemLogUploader::Delegate {
  public:
   MockSystemLogDelegate(bool is_upload_error,
-                        const SystemLogUploader::SystemLogs& system_logs)
-      : is_upload_error_(is_upload_error), system_logs_(system_logs) {}
+                        const SystemLogUploader::SystemLogs& system_logs,
+                        bool is_immediate_upload)
+      : is_upload_error_(is_upload_error),
+        is_immediate_upload_(is_immediate_upload),
+        system_logs_(system_logs) {}
   ~MockSystemLogDelegate() override = default;
 
   std::string GetPolicyAsJSON() override { return kPolicyDump; }
@@ -119,7 +148,8 @@
   std::unique_ptr<UploadJob> CreateUploadJob(
       const GURL& url,
       UploadJob::Delegate* delegate) override {
-    return std::make_unique<MockUploadJob>(delegate, is_upload_error_);
+    return std::make_unique<MockUploadJob>(delegate, is_upload_error_,
+                                           is_immediate_upload_);
   }
 
   void ZipSystemLogs(std::unique_ptr<SystemLogUploader::SystemLogs> system_logs,
@@ -136,6 +166,7 @@
  private:
   bool is_upload_allowed_;
   bool is_upload_error_;
+  bool is_immediate_upload_;
   SystemLogUploader::SystemLogs system_logs_;
 };
 
@@ -210,7 +241,7 @@
        upload_num < SystemLogUploader::kLogThrottleCount + 3; upload_num++) {
     EXPECT_FALSE(task_runner_->HasPendingTask());
     auto syslog_delegate = std::make_unique<MockSystemLogDelegate>(
-        false, SystemLogUploader::SystemLogs());
+        false, SystemLogUploader::SystemLogs(), /*is_immediate_upload=*/false);
 
     syslog_delegate->set_upload_allowed(true);
     settings_helper_.SetBoolean(ash::kSystemLogUploadEnabled, true);
@@ -234,7 +265,7 @@
 TEST_P(SystemLogUploaderTest, ImmediateLogUpload) {
   EXPECT_FALSE(task_runner_->HasPendingTask());
   auto syslog_delegate = std::make_unique<MockSystemLogDelegate>(
-      false, SystemLogUploader::SystemLogs());
+      false, SystemLogUploader::SystemLogs(), /*is_immediate_upload=*/true);
 
   syslog_delegate->set_upload_allowed(true);
   settings_helper_.SetBoolean(ash::kSystemLogUploadEnabled, true);
@@ -242,7 +273,7 @@
   SystemLogUploader uploader(std::move(syslog_delegate), task_runner_);
   for (int upload_num = 0;
        upload_num < SystemLogUploader::kLogThrottleCount + 3; upload_num++) {
-    uploader.ScheduleNextSystemLogUploadImmediately();
+    uploader.ScheduleNextSystemLogUploadImmediately(kCommandId);
     EXPECT_EQ(task_runner_->NextPendingTaskDelay(), base::Milliseconds(0));
     task_runner_->RunPendingTasks();
     task_runner_->ClearPendingTasks();
@@ -255,7 +286,8 @@
 
   std::unique_ptr<MockSystemLogDelegate> syslog_delegate(
       new MockSystemLogDelegate(/*is_upload_error=*/false,
-                                SystemLogUploader::SystemLogs()));
+                                SystemLogUploader::SystemLogs(),
+                                /*is_immediate_upload=*/false));
   syslog_delegate->set_upload_allowed(false);
   SystemLogUploader uploader(std::move(syslog_delegate), task_runner_);
 
@@ -270,7 +302,8 @@
 
   std::unique_ptr<MockSystemLogDelegate> syslog_delegate(
       new MockSystemLogDelegate(/*is_upload_error=*/false,
-                                SystemLogUploader::SystemLogs()));
+                                SystemLogUploader::SystemLogs(),
+                                /*is_immediate_upload=*/false));
   syslog_delegate->set_upload_allowed(true);
   settings_helper_.SetBoolean(ash::kSystemLogUploadEnabled, true);
   SystemLogUploader uploader(std::move(syslog_delegate), task_runner_);
@@ -288,7 +321,8 @@
 
   std::unique_ptr<MockSystemLogDelegate> syslog_delegate(
       new MockSystemLogDelegate(/*is_upload_error=*/true,
-                                SystemLogUploader::SystemLogs()));
+                                SystemLogUploader::SystemLogs(),
+                                /*is_immediate_upload=*/false));
   syslog_delegate->set_upload_allowed(true);
   settings_helper_.SetBoolean(ash::kSystemLogUploadEnabled, true);
   SystemLogUploader uploader(std::move(syslog_delegate), task_runner_);
@@ -313,7 +347,8 @@
 
   SystemLogUploader::SystemLogs system_logs = GenerateTestSystemLogFiles();
   std::unique_ptr<MockSystemLogDelegate> syslog_delegate(
-      new MockSystemLogDelegate(/*is_upload_error=*/false, system_logs));
+      new MockSystemLogDelegate(/*is_upload_error=*/false, system_logs,
+                                /*is_immediate_upload=*/false));
   syslog_delegate->set_upload_allowed(true);
   settings_helper_.SetBoolean(ash::kSystemLogUploadEnabled, true);
   SystemLogUploader uploader(std::move(syslog_delegate), task_runner_);
@@ -331,7 +366,8 @@
 
   std::unique_ptr<MockSystemLogDelegate> syslog_delegate(
       new MockSystemLogDelegate(/*is_upload_error=*/true,
-                                SystemLogUploader::SystemLogs()));
+                                SystemLogUploader::SystemLogs(),
+                                /*is_immediate_upload=*/false));
   MockSystemLogDelegate* mock_delegate = syslog_delegate.get();
   settings_helper_.SetBoolean(ash::kSystemLogUploadEnabled, true);
   mock_delegate->set_upload_allowed(true);
diff --git a/chrome/browser/ash/printing/history/print_job_history_service_impl.cc b/chrome/browser/ash/printing/history/print_job_history_service_impl.cc
index 5493e51..29bd094 100644
--- a/chrome/browser/ash/printing/history/print_job_history_service_impl.cc
+++ b/chrome/browser/ash/printing/history/print_job_history_service_impl.cc
@@ -5,9 +5,9 @@
 #include "chrome/browser/ash/printing/history/print_job_history_service_impl.h"
 
 #include "base/functional/callback_helpers.h"
-#include "base/guid.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/uuid.h"
 #include "chrome/browser/ash/printing/cups_print_job.h"
 #include "chrome/browser/ash/printing/history/print_job_info_proto_conversions.h"
 #include "chrome/browser/printing/print_job.h"
@@ -80,8 +80,9 @@
     return;
   }
 
-  printing::proto::PrintJobInfo print_job_info =
-      CupsPrintJobToProto(*job, /*id=*/base::GenerateGUID(), base::Time::Now());
+  printing::proto::PrintJobInfo print_job_info = CupsPrintJobToProto(
+      *job, /*id=*/base::Uuid::GenerateRandomV4().AsLowercaseString(),
+      base::Time::Now());
   print_job_database_->SavePrintJob(
       print_job_info,
       base::BindOnce(&PrintJobHistoryServiceImpl::OnPrintJobSaved,
diff --git a/chrome/browser/ash/printing/oauth2/authorization_zone_impl.cc b/chrome/browser/ash/printing/oauth2/authorization_zone_impl.cc
index 725652a..3b61224 100644
--- a/chrome/browser/ash/printing/oauth2/authorization_zone_impl.cc
+++ b/chrome/browser/ash/printing/oauth2/authorization_zone_impl.cc
@@ -194,9 +194,8 @@
   base::expected<std::string, std::string> val_or_err =
       ExtractParameter(query, "state");
   if (!val_or_err.has_value()) {
-    std::move(callback).Run(
-        StatusCode::kInvalidResponse,
-        base::StrCat({"Authorization Request: ", val_or_err.error()}));
+    std::move(callback).Run(StatusCode::kInvalidResponse,
+                            "Authorization Request: " + val_or_err.error());
     return;
   }
   const std::string state = std::move(val_or_err.value());
@@ -215,9 +214,8 @@
   if (query.contains("error")) {
     val_or_err = ExtractParameter(query, "error");
     if (!val_or_err.has_value()) {
-      std::move(callback).Run(
-          StatusCode::kInvalidResponse,
-          base::StrCat({"Authorization Request: ", val_or_err.error()}));
+      std::move(callback).Run(StatusCode::kInvalidResponse,
+                              "Authorization Request: " + val_or_err.error());
       return;
     }
     const std::string error = std::move(val_or_err.value());
@@ -230,17 +228,15 @@
     } else {
       status = StatusCode::kAccessDenied;
     }
-    std::move(callback).Run(
-        status, base::StrCat({"Authorization Request: error=", error}));
+    std::move(callback).Run(status, "Authorization Request: error=" + error);
     return;
   }
 
   // Extract the parameter "code".
   val_or_err = ExtractParameter(query, "code");
   if (!val_or_err.has_value()) {
-    std::move(callback).Run(
-        StatusCode::kInvalidResponse,
-        base::StrCat({"Authorization Request: ", val_or_err.error()}));
+    std::move(callback).Run(StatusCode::kInvalidResponse,
+                            "Authorization Request: " + val_or_err.error());
     return;
   }
   const std::string code = std::move(val_or_err.value());
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc
index 9c88e99..8b4b339 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc
@@ -134,6 +134,11 @@
   // Call it once to get the current ambient ui settings.
   OnAmbientUiSettingsChanged();
 
+  // Call it once to get the current ambient duration settings.
+  if (ash::features::IsScreenSaverDurationEnabled()) {
+    OnScreenSaverDurationChanged();
+  }
+
   ResetLocalSettings();
 }
 
@@ -213,6 +218,7 @@
 void PersonalizationAppAmbientProviderImpl::SetScreenSaverDuration(
     int minutes) {
   Shell::Get()->ambient_controller()->SetScreenSaverDuration(minutes);
+  OnScreenSaverDurationChanged();
 }
 
 void PersonalizationAppAmbientProviderImpl::SetTemperatureUnit(
@@ -341,6 +347,19 @@
       GetCurrentUiSettings().theme());
 }
 
+void PersonalizationAppAmbientProviderImpl::OnScreenSaverDurationChanged() {
+  absl::optional<int> duration_pref_value =
+      Shell::Get()->ambient_controller()->GetScreenSaverDuration();
+
+  if (!ambient_observer_remote_.is_bound() ||
+      !duration_pref_value.has_value() || duration_pref_value.value() < 0) {
+    return;
+  }
+
+  ambient_observer_remote_->OnScreenSaverDurationChanged(
+      duration_pref_value.value());
+}
+
 void PersonalizationAppAmbientProviderImpl::OnTemperatureUnitChanged() {
   if (!ambient_observer_remote_.is_bound())
     return;
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.h b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.h
index 85c5dc5..1382c84 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.h
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.h
@@ -71,6 +71,7 @@
   // Notify WebUI the latest values.
   void OnAmbientModeEnabledChanged();
   void OnAmbientUiSettingsChanged();
+  void OnScreenSaverDurationChanged();
   void OnTemperatureUnitChanged();
   void OnTopicSourceChanged();
   void OnAlbumsChanged();
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl_unittest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl_unittest.cc
index 3f76a16..e67811b 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl_unittest.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl_unittest.cc
@@ -73,6 +73,10 @@
     albums_ = std::move(albums);
   }
 
+  void OnScreenSaverDurationChanged(uint32_t minutes) override {
+    duration_ = minutes;
+  }
+
   void OnTemperatureUnitChanged(
       ash::AmbientModeTemperatureUnit temperature_unit) override {
     temperature_unit_ = temperature_unit;
@@ -139,6 +143,7 @@
   bool ambient_mode_enabled_ = false;
 
   ash::AmbientTheme animation_theme_ = ash::AmbientTheme::kSlideshow;
+  uint32_t duration_ = 10;
   ash::AmbientModeTopicSource topic_source_ =
       ash::AmbientModeTopicSource::kArtGallery;
   ash::AmbientModeTemperatureUnit temperature_unit_ =
diff --git a/chrome/browser/ash/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc b/chrome/browser/ash/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc
index 2b6f17a..137f5ca 100644
--- a/chrome/browser/ash/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc
+++ b/chrome/browser/ash/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc
@@ -27,6 +27,7 @@
 #include "extensions/browser/api/messaging/message_service.h"
 #include "extensions/browser/api/messaging/native_message_host.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/api/messaging/messaging_endpoint.h"
 #include "extensions/common/api/messaging/serialization_format.h"
 #include "extensions/common/extension.h"
@@ -363,7 +364,7 @@
       extensions::MessagingEndpoint::ForNativeApp(
           kWilcoDtcSupportdUiMessageHost),
       std::move(native_message_port), extension_id, GURL(),
-      std::string() /* channel_name */);
+      extensions::ChannelType::kNative, std::string() /* channel_name */);
 }
 
 }  // namespace
diff --git a/chrome/browser/autofill/automated_tests/cache_replayer.cc b/chrome/browser/autofill/automated_tests/cache_replayer.cc
index 5761915..04fd89b 100644
--- a/chrome/browser/autofill/automated_tests/cache_replayer.cc
+++ b/chrome/browser/autofill/automated_tests/cache_replayer.cc
@@ -126,18 +126,16 @@
     // This situation will never happen if check for the query path is
     // done before calling this function.
     return base::unexpected(
-        base::StrCat({"could not get any value from query path in "
-                      "Query GET URL: ",
-                      url.spec()}));
+        "could not get any value from query path in Query GET URL: " +
+        url.spec());
   }
   size_t slash = value.find('/', strlen(kApiServerQueryPath));
   if (slash != std::string::npos) {
     return base::ok(value.substr(slash + 1));
   } else {
     return base::unexpected(
-        base::StrCat({"could not get any value from query path in "
-                      "Query GET URL: ",
-                      url.spec()}));
+        "could not get any value from query path in Query GET URL: " +
+        url.spec());
   }
 }
 
@@ -167,7 +165,7 @@
                              &decoded_query)) {
     return base::unexpected(base::StrCat(
         {"could not base64-decode value of path in Query GET URL: \"",
-         query_parameter->c_str(), "\""}));
+         *query_parameter, "\""}));
   }
   return ParseProtoContents<AutofillPageQueryRequest>(decoded_query);
 }
@@ -264,8 +262,7 @@
   if (!query.has_value()) {
     return base::unexpected(query.error());
   }
-  http_text = query.value();
-  return ParseProtoContents<AutofillPageQueryRequest>(http_text);
+  return ParseProtoContents<AutofillPageQueryRequest>(query.value());
 }
 
 // Gets AutofillQueryResponseContents from WPR recorded HTTP response body.
@@ -282,9 +279,8 @@
   auto http_pair = SplitHTTP(compressed_response_text);
   std::string decompressed_body;
   if (!compression::GzipUncompress(http_pair.second, &decompressed_body)) {
-    return base::unexpected(
-        base::StrCat({"Could not gzip decompress HTTP response: ",
-                      GetHexString(http_pair.second)}));
+    return base::unexpected("Could not gzip decompress HTTP response: " +
+                            GetHexString(http_pair.second));
   }
 
   // Eventual response needs header information, so lift that as well.
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java
index 05885ab5..8f51d4f 100644
--- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java
+++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java
@@ -182,11 +182,7 @@
     }
 
     private void backPressStateChanged() {
-        boolean intercept = shouldInterceptBackPress();
-        // If not using system back and MINIMIZE_APP_AND_CLOSE_TAB has registered, this must be
-        // true, since MINIMIZE_APP_AND_CLOSE_TAB unconditionally consumes last back press.
-        assert mUseSystemBack || !has(Type.MINIMIZE_APP_AND_CLOSE_TAB) || intercept;
-        mCallback.setEnabled(intercept || !mUseSystemBack);
+        mCallback.setEnabled(shouldInterceptBackPress());
     }
 
     private void handleBackPress() {
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java
index fec4d59..eacd6a30 100644
--- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java
+++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManagerUnitTest.java
@@ -269,23 +269,6 @@
                 manager.getCallback().isEnabled());
     }
 
-    // Test callback is always enabled to trigger fallbacks for groups without system back.
-    @Test
-    public void testAlwaysEnabledCallback() {
-        MinimizeAppAndCloseTabBackPressHandler.SYSTEM_BACK.setForTesting(false);
-        BackPressManager manager = new BackPressManager();
-        EmptyBackPressHandler h1 = new EmptyBackPressHandler();
-        EmptyBackPressHandler h2 = new EmptyBackPressHandler();
-        manager.addHandler(h1, 0);
-        manager.addHandler(h2, 1);
-        h1.getHandleBackPressChangedSupplier().set(true);
-        Assert.assertTrue("Callback should be enabled if any of handlers are enabled",
-                manager.getCallback().isEnabled());
-        h1.getHandleBackPressChangedSupplier().set(false);
-        Assert.assertFalse("No handler is enabled", manager.shouldInterceptBackPress());
-        Assert.assertTrue("Callback is always enabled", manager.getCallback().isEnabled());
-    }
-
     private int getHandlerCount(BackPressManager manager) {
         int count = 0;
         for (BackPressHandler handler : manager.getHandlersForTesting()) {
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc b/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc
index b4efa2c..266976b 100644
--- a/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc
+++ b/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc
@@ -36,6 +36,7 @@
   }
 
   void TearDown() override {
+    base::RunLoop().RunUntilIdle();
     profile_.reset();
     base::RunLoop().RunUntilIdle();
   }
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index 062314f..53de6fe 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -21,6 +21,7 @@
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/net/nss_service.h"
 #include "chrome/browser/net/nss_service_factory.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
 #include "chrome/common/net/x509_certificate_model_nss.h"
 #include "chrome/grit/generated_resources.h"
@@ -31,8 +32,10 @@
 #include "crypto/scoped_nss_types.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_database.h"
+#include "net/cert/nss_cert_database.h"
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util_nss.h"
+#include "net/net_buildflags.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -251,8 +254,19 @@
   void RefreshSlotsUnlocked() {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     DVLOG(1) << "refresh listing certs...";
-    cert_db_->ListCertsInfo(base::BindOnce(&CertsSourcePlatformNSS::DidGetCerts,
-                                           weak_ptr_factory_.GetWeakPtr()));
+    cert_db_->ListCertsInfo(
+        base::BindOnce(&CertsSourcePlatformNSS::DidGetCerts,
+                       weak_ptr_factory_.GetWeakPtr()),
+#if BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
+        SystemNetworkContextManager::IsUsingChromeRootStore()
+            ? net::NSSCertDatabase::NSSRootsHandling::kExclude
+            : net::NSSCertDatabase::NSSRootsHandling::kInclude
+#elif BUILDFLAG(CHROME_ROOT_STORE_ONLY)
+        net::NSSCertDatabase::NSSRootsHandling::kExclude
+#else
+        net::NSSCertDatabase::NSSRootsHandling::kInclude
+#endif
+    );
   }
 
   void DidGetCerts(net::NSSCertDatabase::CertInfoList cert_info_list) {
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 959d264c..e9be3ddd 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -990,7 +990,7 @@
       ash::ShortcutCustomizationAppUI,
       ash::printing::printing_manager::PrintManagementUI,
       ash::InternetConfigDialogUI, ash::InternetDetailDialogUI, ash::SetTimeUI,
-      ash::BluetoothPairingDialogUI,
+      ash::BluetoothPairingDialogUI, nearby_share::NearbyShareDialogUI,
 #endif
       NewTabPageUI, OmniboxPopupUI, BookmarksSidePanelUI, CustomizeChromeUI>(
       map);
diff --git a/chrome/browser/chromeos/drivefs/drivefs_native_message_host.cc b/chrome/browser/chromeos/drivefs/drivefs_native_message_host.cc
index e4949a6..bf18aa76 100644
--- a/chrome/browser/chromeos/drivefs/drivefs_native_message_host.cc
+++ b/chrome/browser/chromeos/drivefs/drivefs_native_message_host.cc
@@ -19,6 +19,7 @@
 #include "extensions/browser/api/messaging/native_message_host.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/api/messaging/messaging_endpoint.h"
 #include "extensions/common/api/messaging/port_id.h"
 #include "extensions/common/api/messaging/serialization_format.h"
@@ -180,7 +181,7 @@
       extensions::MessagingEndpoint::ForNativeApp(
           kDriveFsNativeMessageHostName),
       std::move(native_message_port), extension_id, GURL(),
-      /* channel name= */ std::string());
+      extensions::ChannelType::kNative, /* channel name= */ std::string());
   return drivefs::mojom::ExtensionConnectionStatus::kSuccess;
 }
 
diff --git a/chrome/browser/companion/core/BUILD.gn b/chrome/browser/companion/core/BUILD.gn
index 3dc3d7b..014cec7 100644
--- a/chrome/browser/companion/core/BUILD.gn
+++ b/chrome/browser/companion/core/BUILD.gn
@@ -4,6 +4,8 @@
 
 static_library("core") {
   sources = [
+    "companion_metrics_logger.cc",
+    "companion_metrics_logger.h",
     "companion_permission_utils.cc",
     "companion_permission_utils.h",
     "companion_url_builder.cc",
@@ -25,6 +27,8 @@
     "//components/unified_consent",
     "//content/public/browser",
     "//net",
+    "//services/metrics/public/cpp:metrics_cpp",
+    "//services/metrics/public/cpp:ukm_builders",
     "//url",
   ]
 }
@@ -32,6 +36,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "companion_metrics_logger_unittest.cc",
     "companion_url_builder_unittest.cc",
     "promo_handler_unittest.cc",
   ]
@@ -44,10 +49,12 @@
     "//base/test:test_support",
     "//chrome/test:test_support",
     "//components/prefs",
+    "//components/ukm:test_support",
     "//components/unified_consent",
     "//content/public/browser",
     "//content/test:test_support",
     "//net",
+    "//services/metrics/public/cpp:ukm_builders",
     "//testing/gmock",
     "//testing/gtest",
     "//url",
diff --git a/chrome/browser/companion/core/companion_metrics_logger.cc b/chrome/browser/companion/core/companion_metrics_logger.cc
new file mode 100644
index 0000000..ad991fa
--- /dev/null
+++ b/chrome/browser/companion/core/companion_metrics_logger.cc
@@ -0,0 +1,145 @@
+// Copyright 2023 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/companion/core/companion_metrics_logger.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/notreached.h"
+#include "base/strings/strcat.h"
+#include "chrome/browser/companion/core/constants.h"
+#include "chrome/browser/companion/core/features.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "url/gurl.h"
+
+namespace companion {
+namespace {
+
+std::string UiSurfaceToHistogramVariant(UiSurface ui_surface) {
+  switch (ui_surface) {
+    case UiSurface::kUnknown:
+      NOTREACHED();
+      return "Unknown";
+    case UiSurface::kCQ:
+      return "CQ";
+    case UiSurface::kPH:
+      return "PH";
+    case UiSurface::kRegionSearch:
+      return "RegionSearch";
+    default:
+      NOTREACHED();
+      return "Unknown";
+  }
+}
+
+PromoEvent ToPromoEventEnum(PromoType promo_type, PromoAction promo_action) {
+  if (promo_type == PromoType::kSignin) {
+    if (promo_action == PromoAction::kShown) {
+      return PromoEvent::kSignInShown;
+    }
+    if (promo_action == PromoAction::kAccepted) {
+      return PromoEvent::kSignInAccepted;
+    }
+    if (promo_action == PromoAction::kRejected) {
+      return PromoEvent::kSignInRejected;
+    }
+  }
+  if (promo_type == PromoType::kMsbb) {
+    if (promo_action == PromoAction::kShown) {
+      return PromoEvent::kMsbbShown;
+    }
+    if (promo_action == PromoAction::kAccepted) {
+      return PromoEvent::kMsbbAccepted;
+    }
+    if (promo_action == PromoAction::kRejected) {
+      return PromoEvent::kMsbbRejected;
+    }
+  }
+  if (promo_type == PromoType::kExps) {
+    if (promo_action == PromoAction::kShown) {
+      return PromoEvent::kExpsShown;
+    }
+    if (promo_action == PromoAction::kAccepted) {
+      return PromoEvent::kExpsAccepted;
+    }
+    if (promo_action == PromoAction::kRejected) {
+      return PromoEvent::kExpsRejected;
+    }
+  }
+  return PromoEvent::kUnknown;
+}
+
+}  // namespace
+
+CompanionMetricsLogger::CompanionMetricsLogger(ukm::SourceId ukm_source_id)
+    : ukm_source_id_(ukm_source_id) {}
+
+CompanionMetricsLogger::~CompanionMetricsLogger() {
+  FlushStats();
+}
+
+void CompanionMetricsLogger::RecordUiSurfaceShown(
+    UiSurface ui_surface,
+    uint32_t child_element_count) {
+  UiSurfaceMetrics& surface = ui_surface_metrics_[ui_surface];
+  surface.last_event = UiEvent::kShown;
+  // Clamped to record as having max 10 child elements.
+  surface.child_element_count = std::clamp(child_element_count, 0u, 10u);
+
+  base::UmaHistogramBoolean(
+      "Companion." + UiSurfaceToHistogramVariant(ui_surface) + ".Shown", true);
+}
+
+void CompanionMetricsLogger::RecordUiSurfaceClicked(UiSurface ui_surface) {
+  UiSurfaceMetrics& surface = ui_surface_metrics_[ui_surface];
+  surface.last_event = UiEvent::kClicked;
+  surface.click_count++;
+
+  base::UmaHistogramBoolean(
+      "Companion." + UiSurfaceToHistogramVariant(ui_surface) + ".Clicked",
+      true);
+}
+
+void CompanionMetricsLogger::OnPromoAction(PromoType promo_type,
+                                           PromoAction promo_action) {
+  last_promo_event_ = ToPromoEventEnum(promo_type, promo_action);
+  base::UmaHistogramEnumeration("Companion.PromoEvent",
+                                last_promo_event_.value());
+}
+
+void CompanionMetricsLogger::FlushStats() {
+  ukm::builders::Companion_PageView ukm_builder(ukm_source_id_);
+
+  // CQ surface.
+  auto iter = ui_surface_metrics_.find(UiSurface::kCQ);
+  if (iter != ui_surface_metrics_.end()) {
+    ukm_builder.SetCQ_LastEvent(static_cast<int64_t>(iter->second.last_event));
+    ukm_builder.SetCQ_ChildElementCount(iter->second.child_element_count);
+  }
+
+  // PH surface.
+  iter = ui_surface_metrics_.find(UiSurface::kPH);
+  if (iter != ui_surface_metrics_.end()) {
+    ukm_builder.SetPH_LastEvent(static_cast<int64_t>(iter->second.last_event));
+  }
+
+  // Region search.
+  iter = ui_surface_metrics_.find(UiSurface::kPH);
+  if (iter != ui_surface_metrics_.end()) {
+    ukm_builder.SetRegionSearch_ClickCount(iter->second.click_count);
+  }
+
+  // Promo state.
+  if (last_promo_event_.has_value()) {
+    ukm_builder.SetPromoEvent(static_cast<int>(last_promo_event_.value()));
+  }
+
+  ukm_builder.Record(ukm::UkmRecorder::Get());
+}
+
+}  // namespace companion
diff --git a/chrome/browser/companion/core/companion_metrics_logger.h b/chrome/browser/companion/core/companion_metrics_logger.h
new file mode 100644
index 0000000..8b607b4
--- /dev/null
+++ b/chrome/browser/companion/core/companion_metrics_logger.h
@@ -0,0 +1,100 @@
+// Copyright 2023 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_COMPANION_CORE_COMPANION_METRICS_LOGGER_H_
+#define CHROME_BROWSER_COMPANION_CORE_COMPANION_METRICS_LOGGER_H_
+
+#include "base/memory/raw_ptr.h"
+#include "chrome/browser/companion/core/mojom/companion.mojom.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "url/gurl.h"
+
+using side_panel::mojom::PromoAction;
+using side_panel::mojom::PromoType;
+using side_panel::mojom::UiSurface;
+
+namespace companion {
+
+// Types of events on the UI surfaces. Keep in sync with Companion.UiEvent in
+// enums.xml.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class UiEvent {
+  // The UI surface was not shown.
+  kNotAvailable = 1,
+
+  // The UI surface was shown.
+  kShown = 2,
+
+  // User clicked on the UI surface.
+  kClicked = 3,
+};
+
+// Tracks events happening on a single UI surface.
+struct UiSurfaceMetrics {
+  UiSurfaceMetrics() = default;
+  UiSurfaceMetrics(const UiSurfaceMetrics& other) = default;
+  UiSurfaceMetrics& operator=(const UiSurfaceMetrics& other) = default;
+  ~UiSurfaceMetrics() = default;
+
+  // Events on the surface. The last event wins and gets recorded.
+  UiEvent last_event = UiEvent::kNotAvailable;
+
+  // The number of child elements shown within the surface, e.g. number of
+  // related queries inside related queries component.
+  size_t child_element_count = 0;
+
+  // The number of times user clicked on the surface.
+  size_t click_count = 0;
+};
+
+// Various types of events happening on the promo surfaces on the companion
+// page. Keep in sync with Companion.PromoEvent in enums.xml. These values are
+// persisted to logs. Entries should not be renumbered and numeric values should
+// never be reused.
+enum class PromoEvent {
+  kUnknown = 0,
+  kSignInShown = 1,
+  kSignInAccepted = 2,
+  kSignInRejected = 3,
+  kMsbbShown = 4,
+  kMsbbAccepted = 5,
+  kMsbbRejected = 6,
+  kExpsShown = 7,
+  kExpsAccepted = 8,
+  kExpsRejected = 9,
+  kMaxValue = kExpsRejected,
+};
+
+// Utility to log UKM and UMA metrics for events happening on the companion
+// page. Should be associated with a single navigation. Flushes metrics on
+// destruction.
+class CompanionMetricsLogger {
+ public:
+  explicit CompanionMetricsLogger(ukm::SourceId ukm_source_id);
+  CompanionMetricsLogger(const CompanionMetricsLogger&) = delete;
+  CompanionMetricsLogger& operator=(const CompanionMetricsLogger&) = delete;
+  ~CompanionMetricsLogger();
+
+  void RecordUiSurfaceShown(UiSurface ui_surface, uint32_t child_element_count);
+  void RecordUiSurfaceClicked(UiSurface ui_surface);
+  void OnPromoAction(PromoType promo_type, PromoAction promo_action);
+
+ private:
+  // Meant to be called at destruction. Flushes the UKM metrics.
+  void FlushStats();
+
+  // The UKM source ID for the page being shown.
+  ukm::SourceId ukm_source_id_;
+
+  // In-memory accumulator of UI surface metrics.
+  std::map<UiSurface, UiSurfaceMetrics> ui_surface_metrics_;
+
+  // Last event on the promo surfaces.
+  absl::optional<PromoEvent> last_promo_event_;
+};
+
+}  // namespace companion
+
+#endif  // CHROME_BROWSER_COMPANION_CORE_COMPANION_METRICS_LOGGER_H_
diff --git a/chrome/browser/companion/core/companion_metrics_logger_unittest.cc b/chrome/browser/companion/core/companion_metrics_logger_unittest.cc
new file mode 100644
index 0000000..8c6157c
--- /dev/null
+++ b/chrome/browser/companion/core/companion_metrics_logger_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright 2023 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/companion/core/companion_metrics_logger.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "chrome/browser/companion/core/mojom/companion.mojom.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace companion {
+
+class CompanionMetricsLoggerTest : public testing::Test {
+ public:
+  CompanionMetricsLoggerTest() = default;
+  ~CompanionMetricsLoggerTest() override = default;
+
+  void SetUp() override {
+    ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
+    logger_ = std::make_unique<CompanionMetricsLogger>(/*ukm_source_id=*/2);
+  }
+
+  void TearDown() override { ukm_recorder_.reset(); }
+
+  ukm::TestUkmRecorder* ukm_recorder() { return ukm_recorder_.get(); }
+
+ protected:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  std::unique_ptr<ukm::TestUkmRecorder> ukm_recorder_;
+  std::unique_ptr<CompanionMetricsLogger> logger_;
+};
+
+TEST_F(CompanionMetricsLoggerTest, RecordUiSurfaceShown) {
+  base::HistogramTester histogram_tester;
+
+  // Show two surfaces, user clicks one.
+  logger_->RecordUiSurfaceShown(UiSurface::kPH, /*child_element_count=*/0);
+  logger_->RecordUiSurfaceShown(UiSurface::kCQ, /*child_element_count=*/3);
+  logger_->RecordUiSurfaceClicked(UiSurface::kCQ);
+
+  // Verify histograms for click and shown events.
+  histogram_tester.ExpectBucketCount("Companion.PH.Shown",
+                                     /*sample=*/true, /*expected_count=*/1);
+  histogram_tester.ExpectBucketCount("Companion.CQ.Shown",
+                                     /*sample=*/true, /*expected_count=*/1);
+  histogram_tester.ExpectBucketCount("Companion.CQ.Clicked",
+                                     /*sample=*/true, /*expected_count=*/1);
+
+  // Destroy the logger. Verify that UKM event is recorded.
+  logger_.reset();
+
+  const char* entry_name = ukm::builders::Companion_PageView::kEntryName;
+  EXPECT_EQ(ukm_recorder()->GetEntriesByName(entry_name).size(), 1ul);
+  auto* entry = ukm_recorder()->GetEntriesByName(entry_name)[0];
+  ukm_recorder()->EntryHasMetric(
+      entry, ukm::builders::Companion_PageView::kPH_LastEventName);
+  ukm_recorder()->ExpectEntryMetric(
+      entry, ukm::builders::Companion_PageView::kPH_LastEventName,
+      static_cast<int>(UiEvent::kShown));
+
+  ukm_recorder()->EntryHasMetric(
+      entry, ukm::builders::Companion_PageView::kCQ_LastEventName);
+  ukm_recorder()->ExpectEntryMetric(
+      entry, ukm::builders::Companion_PageView::kCQ_LastEventName,
+      static_cast<int>(UiEvent::kClicked));
+  ukm_recorder()->EntryHasMetric(
+      entry, ukm::builders::Companion_PageView::kCQ_ChildElementCountName);
+  ukm_recorder()->ExpectEntryMetric(
+      entry, ukm::builders::Companion_PageView::kCQ_ChildElementCountName, 3);
+}
+
+TEST_F(CompanionMetricsLoggerTest, RecordPromoEvent) {
+  base::HistogramTester histogram_tester;
+
+  // Show a promo, user accepts it.
+  logger_->OnPromoAction(PromoType::kSignin, PromoAction::kAccepted);
+
+  // Verify histograms for click and shown events.
+  histogram_tester.ExpectBucketCount("Companion.PromoEvent",
+                                     PromoEvent::kSignInAccepted,
+                                     /*expected_count=*/1);
+
+  // Destroy the logger. Verify that UKM event is recorded.
+  logger_.reset();
+
+  const char* entry_name = ukm::builders::Companion_PageView::kEntryName;
+  EXPECT_EQ(ukm_recorder()->GetEntriesByName(entry_name).size(), 1ul);
+  auto* entry = ukm_recorder()->GetEntriesByName(entry_name)[0];
+  ukm_recorder()->EntryHasMetric(
+      entry, ukm::builders::Companion_PageView::kPromoEventName);
+  ukm_recorder()->ExpectEntryMetric(
+      entry, ukm::builders::Companion_PageView::kPromoEventName,
+      static_cast<int>(PromoEvent::kSignInAccepted));
+}
+
+}  // namespace companion
diff --git a/chrome/browser/companion/core/companion_url_builder.cc b/chrome/browser/companion/core/companion_url_builder.cc
index 3d4ea840..af572fb1 100644
--- a/chrome/browser/companion/core/companion_url_builder.cc
+++ b/chrome/browser/companion/core/companion_url_builder.cc
@@ -70,8 +70,15 @@
 
 GURL CompanionUrlBuilder::BuildCompanionURL(GURL page_url,
                                             const std::string& text_query) {
-  GURL url_with_query_params = GetHomepageURLForCompanion();
+  return AppendCompanionParamsToURL(GetHomepageURLForCompanion(), page_url,
+                                    text_query);
+}
 
+GURL CompanionUrlBuilder::AppendCompanionParamsToURL(
+    GURL base_url,
+    GURL page_url,
+    const std::string& text_query) {
+  GURL url_with_query_params = base_url;
   // Fill the protobuf with the required query params.
   std::string base64_encoded_proto = BuildCompanionUrlParamProto(page_url);
   url_with_query_params = net::AppendOrReplaceQueryParameter(
@@ -95,7 +102,6 @@
     url_with_query_params = net::AppendOrReplaceQueryParameter(
         url_with_query_params, kTextQueryParameterKey, text_query);
   }
-
   return url_with_query_params;
 }
 
diff --git a/chrome/browser/companion/core/companion_url_builder.h b/chrome/browser/companion/core/companion_url_builder.h
index a9ea90f..2e6e11c4 100644
--- a/chrome/browser/companion/core/companion_url_builder.h
+++ b/chrome/browser/companion/core/companion_url_builder.h
@@ -31,6 +31,12 @@
   GURL BuildCompanionURL(GURL page_url);
   GURL BuildCompanionURL(GURL page_url, const std::string& text_query);
 
+  // Returns the `base_url` with the query parameters set to the protobuf
+  // representation of the `page_url` and associated state.
+  GURL AppendCompanionParamsToURL(GURL base_url,
+                                  GURL page_url,
+                                  const std::string& text_query);
+
   // Returns the protobuf representation of the `page_url` and
   // associated state. Used to notify the companion page both during initial
   // load and subsequent state updates.
diff --git a/chrome/browser/companion/core/features.cc b/chrome/browser/companion/core/features.cc
index e270a8d..eeb1489 100644
--- a/chrome/browser/companion/core/features.cc
+++ b/chrome/browser/companion/core/features.cc
@@ -26,6 +26,8 @@
     "https://www.example.com"};
 constexpr base::FeatureParam<bool> kEnableOpenCompanionForImageSearch{
     &kSidePanelCompanion, "open-companion-for-image-search", true};
+constexpr base::FeatureParam<bool> kEnableOpenCompanionForWebSearch{
+    &kSidePanelCompanion, "open-companion-for-web-search", true};
 
 }  // namespace features
 
diff --git a/chrome/browser/companion/core/features.h b/chrome/browser/companion/core/features.h
index 41af4039..9badb60 100644
--- a/chrome/browser/companion/core/features.h
+++ b/chrome/browser/companion/core/features.h
@@ -16,6 +16,7 @@
 extern const base::FeatureParam<std::string> kHomepageURLForCompanion;
 extern const base::FeatureParam<std::string> kImageUploadURLForCompanion;
 extern const base::FeatureParam<bool> kEnableOpenCompanionForImageSearch;
+extern const base::FeatureParam<bool> kEnableOpenCompanionForWebSearch;
 
 }  // namespace features
 
diff --git a/chrome/browser/companion/core/mojom/companion.mojom b/chrome/browser/companion/core/mojom/companion.mojom
index ec97cda..aa64c688 100644
--- a/chrome/browser/companion/core/mojom/companion.mojom
+++ b/chrome/browser/companion/core/mojom/companion.mojom
@@ -10,18 +10,24 @@
 // TODO(b/274618365): Link documentation for server side counterpart that must
 // be kept in sync.
 enum MethodType {
-  // Method called in response to a user action in a promo.
+  // Method corresponding to `CompanionPageHandler.OnPromoAction`.
   kOnPromoAction = 1,
 
-  // Method called in response to user clicking on the region search button.
+  // Method corresponding to `CompanionPageHandler.OnRegionSearchClicked`.
   kOnRegionSearchClicked = 2,
 
-  // Method called when user's experience opt-in status is available.
+  // Method corresponding to `CompanionPageHandler.OnExpsOptInStatusAvailable`.
   kOnExpsOptInStatusAvailable = 3,
 
-  // Method called when the url used for the 'open in new tab' button in the
-  // side panel header should be updated.
+  // Method corresponding to
+  // `CompanionPageHandler.OnOpenInNewTabButtonURLChanged`.
   kOnOpenInNewTabButtonURLChanged = 4,
+
+  // Method corresponding to `CompanionPageHandler.RecordUiSurfaceShown`.
+  kRecordUiSurfaceShown = 5,
+
+  // Method corresponding to `CompanionPageHandler.RecordUiSurfaceClicked`.
+  kRecordUiSurfaceClicked = 6,
 };
 
 // Types of promos shown in the companion UI.
@@ -72,6 +78,14 @@
   uint32 downscaled_width;
 };
 
+// Various UI surfaces on the companion page.
+enum UiSurface {
+  kUnknown = 0,
+  kPH = 1,
+  kCQ = 2,
+  kRegionSearch = 3,
+};
+
 // Factory method for creating a new WebUI page handler.
 interface CompanionPageHandlerFactory {
   // The WebUI calls this method when the page is first initialized.
@@ -99,6 +113,17 @@
   // button in the side panel header should be updated. If the url is empty
   // the button would be hidden.
   OnOpenInNewTabButtonURLChanged(url.mojom.Url url_to_open);
+
+  // For metrics only. Called to record that a certain UI surface was shown on
+  // the companion page. Additionally indicates the number of child elements
+  // shown within the surface, e.g. the number of related queries shown in
+  // the related queries component.
+  RecordUiSurfaceShown(UiSurface ui_surface, uint32 child_element_count);
+
+  // For metrics only. Called to record that the user clicked on the given UI
+  // surface on the companion page. These clicks are actual clicks on the
+  // surface which exclude clicks on the feedback elements.
+  RecordUiSurfaceClicked(UiSurface ui_surface);
 };
 
 // WebUI page handler for request from Browser side. (C++ -> TypeScript)
diff --git a/chrome/browser/component_updater/recovery_improved_component_installer.cc b/chrome/browser/component_updater/recovery_improved_component_installer.cc
index 02cc662..c2d298a 100644
--- a/chrome/browser/component_updater/recovery_improved_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_improved_component_installer.cc
@@ -105,8 +105,7 @@
     const base::CommandLine& cmdline) {
   PrepareFiles(unpack_path_);
   VLOG(1) << "run command: " << cmdline.GetCommandLineString();
-  base::expected<base::Process, int> process_or_error =
-      [&cmdline]() -> base::expected<base::Process, int> {
+  auto process_or_error = [&cmdline]() -> base::expected<base::Process, int> {
     base::LaunchOptions options;
 #if BUILDFLAG(IS_WIN)
     options.start_hidden = true;
@@ -121,7 +120,7 @@
       return base::unexpected(0);
 #endif
     }
-    return base::ok(std::move(process));
+    return std::move(process);
   }();
   base::ThreadPool::PostTask(
       FROM_HERE, kThreadPoolTaskTraitsRunCommand,
diff --git a/chrome/browser/dips/dips_features.cc b/chrome/browser/dips/dips_features.cc
index 271ec7a..872fc7c 100644
--- a/chrome/browser/dips/dips_features.cc
+++ b/chrome/browser/dips/dips_features.cc
@@ -16,7 +16,7 @@
 
 // Set whether DIPS persists its database to disk.
 const base::FeatureParam<bool> kPersistedDatabaseEnabled{
-    &kFeature, "persist_database", false};
+    &kFeature, "persist_database", true};
 
 // Set whether DIPS performs deletion.
 const base::FeatureParam<bool> kDeletionEnabled{&kFeature, "delete", false};
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
index 0859b06b..215c183 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
@@ -312,16 +312,9 @@
     delegate->RunCallback();
   }
 
-  // If all requests are already done, just let `delegate` go out of scope.
-  if (delegate->all_work_done_) {
-    return;
-  }
-
-  // ... otherwise, let the last response from the upload service callback
-  // delete the delegate when there is no more work.
-  if (work_being_done) {
+  // Upload service callback will delete the delegate.
+  if (work_being_done)
     delegate.release();
-  }
 }
 
 // static
@@ -728,15 +721,6 @@
 
   AckAllRequests();
 
-  if (run_callback_called_ && !dialog_ && *UIEnabledStorage()) {
-    // This code path implies that RunCallback has already been called,
-    // and that we are racing against a non-blocking scan. In such a
-    // case, we let the other caller handle deletion of `this`, and let
-    // them know no more work is needed.
-    all_work_done_ = true;
-    return;
-  }
-
   if (!UpdateDialog() && data_uploaded_) {
     // No UI was shown.  Delete |this| to cleanup, unless UploadData isn't done
     // yet.
@@ -745,10 +729,8 @@
 }
 
 void ContentAnalysisDelegate::RunCallback() {
-  if (callback_.is_null() || run_callback_called_) {
+  if (callback_.is_null())
     return;
-  }
-  run_callback_called_ = true;
 
   std::move(callback_).Run(data_, result_);
 
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
index 3236937..9382e196 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
@@ -432,16 +432,6 @@
   // Result updated in ImageRequestCallback().
   RequestHandlerResult image_request_result_;
 
-  // Indicates that RunCallback has already been called. This is used to
-  // prevent race conditions when a UI thread task blocked on a user interaction
-  // is racing against a scanning request.
-  bool run_callback_called_ = false;
-
-  // Indicates that `this` can be deleted right away. This is used with
-  // `run_callback_called_` to handle race conditions where non-blocking scans
-  // should wait before deleting `this`.
-  bool all_work_done_ = false;
-
   base::TimeTicks upload_start_time_;
 
   base::WeakPtrFactory<ContentAnalysisDelegate> weak_ptr_factory_{this};
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
index a6e7b8bc..1cb315d 100644
--- a/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor_unittest.cc
@@ -269,10 +269,10 @@
   const absl::optional<MockCrashEndpoint::Report>& actual_report =
       endpoint_->last_report();
   ASSERT_TRUE(actual_report);
-  // Escaped version of "<email: 1> says hi to <email: 2>"
+  // Escaped version of "(email: 1) says hi to (email: 2)"
   EXPECT_THAT(actual_report->query,
-              HasSubstr("error_message=%3Cemail%3A%201%3E%20says%20hi%20to%20"
-                        "%3Cemail%3A%202%3E"));
+              HasSubstr("error_message=(email%3A%201)%20says%20hi%20to%20"
+                        "(email%3A%202)"));
   // Redacted messages still need to be removed from stack trace.
   EXPECT_EQ(actual_report->content, "bad_func(1, 2)\nonclick()\n");
 }
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_api.cc b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
index f90f31f..0db0e1e 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_api.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
@@ -83,6 +83,11 @@
   absl::optional<Clear::Params> params = Clear::Params::Create(args());
   EXTENSION_FUNCTION_VALIDATE(params);
 
+  if (content_type == ContentSettingsType::DEPRECATED_PPAPI_BROKER) {
+    NOTREACHED();
+    return RespondNow(Error(kUnknownErrorDoNotUse));
+  }
+
   ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
   bool incognito = false;
   if (params->details.scope ==
@@ -116,6 +121,11 @@
   absl::optional<Get::Params> params = Get::Params::Create(args());
   EXTENSION_FUNCTION_VALIDATE(params);
 
+  if (content_type == ContentSettingsType::DEPRECATED_PPAPI_BROKER) {
+    NOTREACHED();
+    return RespondNow(Error(kUnknownErrorDoNotUse));
+  }
+
   GURL primary_url(params->details.primary_url);
   if (!primary_url.is_valid()) {
     return RespondNow(Error(kInvalidUrlError, params->details.primary_url));
@@ -182,6 +192,11 @@
   absl::optional<Set::Params> params = Set::Params::Create(args());
   EXTENSION_FUNCTION_VALIDATE(params);
 
+  if (content_type == ContentSettingsType::DEPRECATED_PPAPI_BROKER) {
+    NOTREACHED();
+    return RespondNow(Error(kUnknownErrorDoNotUse));
+  }
+
   std::string primary_error;
   ContentSettingsPattern primary_pattern =
       content_settings_helpers::ParseExtensionPattern(
diff --git a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
index 2094c324..80f169d 100644
--- a/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
+++ b/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
@@ -223,7 +223,7 @@
           {"app_locale=en-US&browser=Chrome&browser_process_uptime_ms=\\d+&"
            "browser_version=1.2."
            "3.4&channel=Stable&column=456&"
-           "error_message=%5BMAC%20OUI%3D06%3A00%3A00%20IFACE%3D1%5D&"
+           "error_message=\\(MAC%20OUI%3D06%3A00%3A00%20IFACE%3D1\\)&"
            "full_url=http%3A%2F%2Fwww.test.com%2Ffoo&line=123&num-experiments="
            "1&"
            "os=ChromeOS&prod=TestApp&renderer_process_uptime_ms=\\d+&"
diff --git a/chrome/browser/extensions/api/messaging/messaging_apitest.cc b/chrome/browser/extensions/api/messaging/messaging_apitest.cc
index e5a5f51..bfdf51c 100644
--- a/chrome/browser/extensions/api/messaging/messaging_apitest.cc
+++ b/chrome/browser/extensions/api/messaging/messaging_apitest.cc
@@ -1533,8 +1533,6 @@
 // Tests that the channel name used in runtime.connect() cannot redirect the
 // message to another event (like onMessage).
 // See https://crbug.com/1430999.
-// NOTE: This is currently an anti-test -- it tests undesirable behavior that we
-// hope to change.
 IN_PROC_BROWSER_TEST_F(MessagingApiTest, MessageChannelName) {
   static constexpr char kManifest[] =
       R"({
@@ -1549,13 +1547,8 @@
                  {name: 'chrome.runtime.sendMessage'});
              chrome.test.assertEq('chrome.runtime.sendMessage', port.name);
              port.onMessage.addListener((msg) => {
-               // TODO(https://crbug.com/1430999): This should be:
-               // chrome.test.assertEq('pong', msg);
-               // chrome.test.succeed();
-               // But currently the message goes to the wrong event. Verify
-               // the incorrect behavior for now by fail()ing if we get a
-               // response.
-               chrome.test.fail('Unexpected reply: ' + msg);
+               chrome.test.assertEq('pong', msg);
+               chrome.test.succeed();
              });
              port.postMessage('ping');
            }
@@ -1564,23 +1557,15 @@
       R"(chrome.runtime.onConnect.addListener((port) => {
            self.port = port;
            port.onMessage.addListener((msg) => {
-             // TODO(https://crbug.com/1430999): This should be:
-             // chrome.test.assertEq(port.name, 'chrome.runtime.sendMessage');
-             // chrome.test.assertEq(msg, 'ping');
-             // port.postMessage('pong');
-             // But we don't currently get a message here because it goes to
-             // the wrong event. Verify the incorrect behavior for now by
-             // fail()ing if we get a message.
-             chrome.test.fail('Unexpected reply: ' + msg);
+             chrome.test.assertEq(port.name, 'chrome.runtime.sendMessage');
+             chrome.test.assertEq(msg, 'ping');
+             port.postMessage('pong');
            });
          });
          chrome.runtime.onMessage.addListener((msg) => {
-           // TODO(https://crbug.com/1430999): This should be:
-           // chrome.test.fail(`Unexpected onMessage received: ${msg}`);
-           // But currently the message goes here instead of the port.
-           // Verify the incorrect behavior for now.
-           chrome.test.assertEq(msg, 'ping');
-           chrome.test.succeed();
+           // We don't expect anything to hit the `onMessage` listener.
+           // See https://crbug.com/1430999.
+           chrome.test.fail(`Unexpected onMessage received: ${msg}`);
          });)";
   TestExtensionDir test_dir;
   test_dir.WriteManifest(kManifest);
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc
index 735c334..2e3891b6 100644
--- a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc
+++ b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.cc
@@ -28,6 +28,7 @@
 #include "extensions/browser/api/messaging/native_message_host.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/api/messaging/messaging_endpoint.h"
 #include "extensions/common/api/messaging/serialization_format.h"
 #include "extensions/common/permissions/permission_set.h"
@@ -248,7 +249,7 @@
       extensions::ChannelEndpoint(profile), port_id,
       extensions::MessagingEndpoint::ForNativeApp(host_id),
       std::move(native_message_port), extension_id, GURL(),
-      std::string() /* channel_name */);
+      ChannelType::kNative, std::string() /* channel_name */);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/omnibox/suggestion_parser.cc b/chrome/browser/extensions/api/omnibox/suggestion_parser.cc
index 711b5ad..7e6ea88 100644
--- a/chrome/browser/extensions/api/omnibox/suggestion_parser.cc
+++ b/chrome/browser/extensions/api/omnibox/suggestion_parser.cc
@@ -144,21 +144,19 @@
     run_callback_with_error(std::move(value_or_error.error()));
     return;
   }
-
-  DCHECK(value_or_error.has_value());
+  const base::Value& root_node = *value_or_error;
 
   // From this point on, we hope that everything is valid (e.g., that we don't
   // get non-dictionary values or unexpected top-level types. But, if we did,
   // emit a generic error.
   constexpr char kGenericError[] = "Invalid XML";
 
-  if (!value_or_error->is_dict()) {
+  if (!root_node.is_dict()) {
     run_callback_with_error(kGenericError);
     return;
   }
 
   std::vector<const base::Value*> entries;
-  const base::Value& root_node = *value_or_error;
   if (has_multiple_entries) {
     if (!PopulateEntriesFromNode(root_node, &entries)) {
       run_callback_with_error(kGenericError);
diff --git a/chrome/browser/extensions/api/side_panel/side_panel_api.cc b/chrome/browser/extensions/api/side_panel/side_panel_api.cc
index 1718b4f..667288c 100644
--- a/chrome/browser/extensions/api/side_panel/side_panel_api.cc
+++ b/chrome/browser/extensions/api/side_panel/side_panel_api.cc
@@ -70,7 +70,7 @@
 SidePanelGetPanelBehaviorFunction::RunFunction() {
   api::side_panel::PanelBehavior behavior;
   behavior.open_panel_on_action_click =
-      GetService()->GetOpenSidePanelOnIconClick(extension()->id());
+      GetService()->OpenSidePanelOnIconClick(extension()->id());
 
   return RespondNow(WithArguments(behavior.ToValue()));
 }
diff --git a/chrome/browser/extensions/api/side_panel/side_panel_service.cc b/chrome/browser/extensions/api/side_panel/side_panel_service.cc
index a5fcffe0..934cac0 100644
--- a/chrome/browser/extensions/api/side_panel/side_panel_service.cc
+++ b/chrome/browser/extensions/api/side_panel/side_panel_service.cc
@@ -13,6 +13,7 @@
 #include "components/sessions/core/session_id.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/pref_types.h"
+#include "extensions/common/extension_features.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace extensions {
@@ -55,6 +56,19 @@
   extension_registry_observation_.Observe(extension_registry);
 }
 
+bool SidePanelService::HasSidePanelActionForTab(const Extension& extension,
+                                                TabId tab_id) {
+  if (!OpenSidePanelOnIconClick(extension.id()) ||
+      !base::FeatureList::IsEnabled(
+          extensions_features::kExtensionSidePanelIntegration)) {
+    return false;
+  }
+
+  api::side_panel::PanelOptions options = GetOptions(extension, tab_id);
+  return options.enabled.has_value() && *options.enabled &&
+         options.path.has_value();
+}
+
 api::side_panel::PanelOptions SidePanelService::GetOptions(
     const Extension& extension,
     absl::optional<TabId> id) {
@@ -171,7 +185,7 @@
   panels_.erase(id);
 }
 
-bool SidePanelService::GetOpenSidePanelOnIconClick(
+bool SidePanelService::OpenSidePanelOnIconClick(
     const ExtensionId& extension_id) {
   bool open_side_panel_on_icon_click = false;
   ExtensionPrefs::Get(browser_context_)
diff --git a/chrome/browser/extensions/api/side_panel/side_panel_service.h b/chrome/browser/extensions/api/side_panel/side_panel_service.h
index 096416b..c0c56d4e 100644
--- a/chrome/browser/extensions/api/side_panel/side_panel_service.h
+++ b/chrome/browser/extensions/api/side_panel/side_panel_service.h
@@ -45,9 +45,14 @@
   // BrowserContextKeyedAPI implementation.
   static BrowserContextKeyedAPIFactory<SidePanelService>* GetFactoryInstance();
 
+  using TabId = int;
+
+  // Returns if there is an action to toggle the side panel for the given
+  // `extension` and `tab_id`.
+  bool HasSidePanelActionForTab(const Extension& extension, TabId tab_id);
+
   // Get options for `tab_id`. Options are loaded in order first from service
   // storage, manifest, or an empty object will be returned, if they're unset.
-  using TabId = int;
   api::side_panel::PanelOptions GetOptions(const Extension& extension,
                                            absl::optional<TabId> tab_id);
 
@@ -66,7 +71,7 @@
 
   // Returns whether the extension will open its side panel entry when its icon
   // in the toolbar is clicked.
-  bool GetOpenSidePanelOnIconClick(const ExtensionId& extension_id);
+  bool OpenSidePanelOnIconClick(const ExtensionId& extension_id);
 
   // Updates whether the extension will open its side panel entry when its icon
   // in the toolbar is clicked.
diff --git a/chrome/browser/extensions/extension_action_runner.cc b/chrome/browser/extensions/extension_action_runner.cc
index e493b93..e3fe2e19 100644
--- a/chrome/browser/extensions/extension_action_runner.cc
+++ b/chrome/browser/extensions/extension_action_runner.cc
@@ -18,6 +18,7 @@
 #include "base/task/single_thread_task_runner.h"
 #include "chrome/browser/extensions/active_tab_permission_granter.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/extensions/api/side_panel/side_panel_service.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/permissions_updater.h"
 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
@@ -102,26 +103,48 @@
 ExtensionAction::ShowAction ExtensionActionRunner::RunAction(
     const Extension* extension,
     bool grant_tab_permissions) {
-  if (grant_tab_permissions) {
-    int blocked_actions = GetBlockedActions(extension->id());
-    GrantTabPermissions({extension});
+  int tab_id = sessions::SessionTabHelper::IdForTab(web_contents()).id();
 
+  if (grant_tab_permissions && GetBlockedActions(extension->id())) {
     // If the extension had blocked actions before granting tab permissions,
     // granting active tab will have run the extension. Don't execute further
     // since clicking should run blocked actions *or* the normal extension
     // action, not both.
-    if (blocked_actions)
-      return ExtensionAction::ACTION_NONE;
+    GrantTabPermissions({extension});
+    return ExtensionAction::ACTION_NONE;
   }
 
-  // Anything that gets here should have a page or browser action, and not
-  // blocked actions.
+  // Anything that gets here should have a page or browser action, or toggle the
+  // extension's side panel, and not blocked actions.
+  if (base::FeatureList::IsEnabled(
+          extensions_features::kExtensionSidePanelIntegration)) {
+    // This method is only called to execute an action by the user, so we can
+    // grant tab permissions unless `action` will toggle the side panel. Tab
+    // permissions are not granted in this case because:
+    //  - the extension's side panel entry can be opened through the side panel
+    //    itself which does not grant tab permissions
+    //  - extension side panels can persist through tab changes and so
+    //  permissions
+    //    granted for one tab shouldn't persist on that side panel across tab
+    //    changes.
+    // TODO(crbug.com/1435530): Evaluate if this is the best course of action.
+    SidePanelService* side_panel_service =
+        SidePanelService::Get(browser_context_);
+    if (side_panel_service &&
+        side_panel_service->HasSidePanelActionForTab(*extension, tab_id)) {
+      return ExtensionAction::ACTION_TOGGLE_SIDE_PANEL;
+    }
+  }
+
+  if (grant_tab_permissions) {
+    GrantTabPermissions({extension});
+  }
+
   ExtensionAction* extension_action =
       ExtensionActionManager::Get(browser_context_)
           ->GetExtensionAction(*extension);
   DCHECK(extension_action);
 
-  int tab_id = sessions::SessionTabHelper::IdForTab(web_contents()).id();
   if (!extension_action->GetIsVisible(tab_id))
     return ExtensionAction::ACTION_NONE;
 
diff --git a/chrome/browser/extensions/extension_action_runner.h b/chrome/browser/extensions/extension_action_runner.h
index c1e18a0..69f51e8 100644
--- a/chrome/browser/extensions/extension_action_runner.h
+++ b/chrome/browser/extensions/extension_action_runner.h
@@ -60,9 +60,15 @@
   static ExtensionActionRunner* GetForWebContents(
       content::WebContents* web_contents);
 
-  // Executes the action for the given |extension| and |grant_tab_permissions|
-  // if true. Returns any further action (like showing a popup) that should be
-  // taken.
+  // Runs the given extension action. This may trigger a number of different
+  // behaviors, depending on the extension and state, including:
+  // - Running blocked actions (if the extension had withheld permissions)
+  // - Firing the action.onClicked event for the extension
+  // - Determining that a UI action should be taken, indicated by the return
+  //   result.
+  // If `grant_tab_permissions` is true and the action is appropriate, this will
+  // grant tab permissions for the extension to the active tab. This may not
+  // happen in all cases (such as when showing a side panel).
   ExtensionAction::ShowAction RunAction(const Extension* extension,
                                         bool grant_tab_permissions);
 
diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc
index 1c53836b..af616bc 100644
--- a/chrome/browser/extensions/extension_context_menu_model.cc
+++ b/chrome/browser/extensions/extension_context_menu_model.cc
@@ -116,9 +116,8 @@
          policy->MustRemainInstalled(extension, nullptr);
 }
 
-std::u16string GetCurrentSite(content::WebContents* web_contents) {
-  return url_formatter::IDNToUnicode(
-      url_formatter::StripWWW(web_contents->GetLastCommittedURL().host()));
+std::u16string GetCurrentSite(const GURL& url) {
+  return url_formatter::IDNToUnicode(url_formatter::StripWWW(url.host()));
 }
 
 ExtensionContextMenuModel::ContextMenuAction CommandIdToContextMenuAction(
@@ -590,7 +589,11 @@
 void ExtensionContextMenuModel::CreatePageAccessItems(
     const Extension* extension,
     content::WebContents* web_contents) {
-  auto url = web_contents->GetLastCommittedURL();
+  const GURL& url = web_contents->GetLastCommittedURL();
+  // We store the origin to make sure it's the same when executing page access
+  // commands.
+  origin_ = url::Origin::Create(url);
+
   auto* permissions_manager = PermissionsManager::Get(profile_);
 
   if (base::FeatureList::IsEnabled(
@@ -609,15 +612,14 @@
     // only show the page access submenu with change extension settings options
     // if the site settings is set to "customize by extension". Otherwise, shows
     // a message that informs the user about the site setting.
-    auto site_setting =
-        permissions_manager->GetUserSiteSetting(url::Origin::Create(url));
+    auto site_setting = permissions_manager->GetUserSiteSetting(origin_);
     switch (site_setting) {
       case PermissionsManager::UserSiteSetting::kGrantAllExtensions:
         AddItem(
             PAGE_ACCESS_ALL_EXTENSIONS_GRANTED,
             l10n_util::GetStringFUTF16(
                 IDS_EXTENSIONS_CONTEXT_MENU_PAGE_ACCESS_ALL_EXTENSIONS_GRANTED,
-                GetCurrentSite(web_contents)));
+                GetCurrentSite(url)));
         add_page_access_secondary_buttons(this);
         return;
 
@@ -626,7 +628,7 @@
             PAGE_ACCESS_ALL_EXTENSIONS_BLOCKED,
             l10n_util::GetStringFUTF16(
                 IDS_EXTENSIONS_CONTEXT_MENU_PAGE_ACCESS_ALL_EXTENSIONS_BLOCKED,
-                GetCurrentSite(web_contents)));
+                GetCurrentSite(url)));
         add_page_access_secondary_buttons(this);
         return;
 
@@ -654,7 +656,7 @@
             PAGE_ACCESS_RUN_ON_SITE,
             l10n_util::GetStringFUTF16(
                 IDS_EXTENSIONS_CONTEXT_MENU_PAGE_ACCESS_RUN_ON_SITE_V2,
-                GetCurrentSite(web_contents)),
+                GetCurrentSite(url)),
             kRadioGroup);
         page_access_submenu_->AddRadioItemWithStringId(
             PAGE_ACCESS_RUN_ON_ALL_SITES,
@@ -689,7 +691,7 @@
         PAGE_ACCESS_RUN_ON_SITE,
         l10n_util::GetStringFUTF16(
             IDS_EXTENSIONS_CONTEXT_MENU_PAGE_ACCESS_RUN_ON_SITE,
-            GetCurrentSite(web_contents)),
+            GetCurrentSite(url)),
         kRadioGroup);
     page_access_submenu_->AddRadioItemWithStringId(
         PAGE_ACCESS_RUN_ON_ALL_SITES,
@@ -710,8 +712,9 @@
     int command_id,
     const Extension* extension) const {
   content::WebContents* web_contents = GetActiveWebContents();
-  if (!web_contents)
+  if (!web_contents) {
     return;
+  }
 
   LogPageAccessAction(command_id);
 
@@ -726,6 +729,11 @@
     return;
   }
 
+  // If the web contents have navigated to a different origin, do nothing.
+  if (!origin_.IsSameOriginWith(web_contents->GetLastCommittedURL())) {
+    return;
+  }
+
   SitePermissionsHelper permissions(profile_);
   permissions.UpdateSiteAccess(*extension, web_contents,
                                CommandIdToSiteAccess(command_id));
diff --git a/chrome/browser/extensions/extension_context_menu_model.h b/chrome/browser/extensions/extension_context_menu_model.h
index c813c050..99220a65 100644
--- a/chrome/browser/extensions/extension_context_menu_model.h
+++ b/chrome/browser/extensions/extension_context_menu_model.h
@@ -11,6 +11,7 @@
 #include "base/memory/raw_ptr.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/models/simple_menu_model.h"
+#include "url/origin.h"
 
 class Browser;
 class Profile;
@@ -188,6 +189,12 @@
   absl::optional<ContextMenuAction> action_taken_;
 
   ContextMenuSource source_;
+
+  // The origin used for populating the page access items.
+  // TODO(crbug.com/1435117): Web contents may change while the menu is open,
+  // which may affect the context menu contents. We should dynamically update
+  // the context menu, or close it when this happens.
+  url::Origin origin_;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_context_menu_model_unittest.cc b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
index feb9b8d..0ac3fb1 100644
--- a/chrome/browser/extensions/extension_context_menu_model_unittest.cc
+++ b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
@@ -1479,6 +1479,45 @@
             GetPageAccessCommandState(menu, kLearnMore));
 }
 
+// Test that we don't update site access when there is a page navigation with
+// the menu open.
+TEST_F(ExtensionContextMenuModelTest,
+       PageAccess_CustomizeByExtension_PageNavigation) {
+  InitializeEmptyExtensionService();
+  const GURL kOriginalUrl("http://www.example.com/");
+  const GURL kNewUrl("http://www.chromium.org/");
+
+  // Add an extension with all urls, and withhold permissions.
+  const Extension* extension =
+      AddExtensionWithHostPermission("extension", manifest_keys::kBrowserAction,
+                                     ManifestLocation::kInternal, "<all_urls>");
+
+  content::WebContents* web_contents = AddTab(kOriginalUrl);
+  ExtensionContextMenuModel menu(extension, GetBrowser(),
+                                 ExtensionContextMenuModel::PINNED, nullptr,
+                                 true, ContextMenuSource::kToolbarAction);
+
+  // By default, extension is granted access to all sites.
+  PermissionsManager* permissions_manager = PermissionsManager::Get(profile());
+  EXPECT_EQ(permissions_manager->GetUserSiteAccess(*extension, kOriginalUrl),
+            PermissionsManager::UserSiteAccess::kOnAllSites);
+  EXPECT_EQ(permissions_manager->GetUserSiteAccess(*extension, kNewUrl),
+            PermissionsManager::UserSiteAccess::kOnAllSites);
+
+  // Navigate to another page with the menu open, and execute "on site" command.
+  content::WebContentsTester* web_contents_tester =
+      content::WebContentsTester::For(web_contents);
+  web_contents_tester->NavigateAndCommit(kNewUrl);
+  menu.ExecuteCommand(kOnClick, 0);
+
+  // Since we navigated to a different page, we should not update the site of
+  // either page.
+  EXPECT_EQ(permissions_manager->GetUserSiteAccess(*extension, kOriginalUrl),
+            PermissionsManager::UserSiteAccess::kOnAllSites);
+  EXPECT_EQ(permissions_manager->GetUserSiteAccess(*extension, kNewUrl),
+            PermissionsManager::UserSiteAccess::kOnAllSites);
+}
+
 TEST_F(ExtensionContextMenuModelTest,
        TestTogglingAccessWithSpecificSitesWithUnrequestedUrl) {
   InitializeEmptyExtensionService();
diff --git a/chrome/browser/extensions/extension_security_exploit_browsertest.cc b/chrome/browser/extensions/extension_security_exploit_browsertest.cc
index c5a23945..d8b8d7d 100644
--- a/chrome/browser/extensions/extension_security_exploit_browsertest.cc
+++ b/chrome/browser/extensions/extension_security_exploit_browsertest.cc
@@ -415,7 +415,8 @@
         [matching_extension_id](
             int captured_render_process_id,
             const ExtensionHostMsg_OpenChannelToExtension::Param& param) {
-          auto [source_context, info, channel_name, port_id] = param;
+          auto [source_context, info, channel_type, channel_name, port_id] =
+              param;
 
           if (info.source_endpoint.extension_id != matching_extension_id)
             return false;
@@ -445,7 +446,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_EQ(MessagingEndpoint::Type::kContentScript, info.source_endpoint.type);
   EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
@@ -461,8 +462,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToExtension(source_context, info,
-                                              channel_name, port_id));
+      ExtensionHostMsg_OpenChannelToExtension(
+          source_context, info, channel_type, channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_INVALID_EXTENSION_ID_FOR_CONTENT_SCRIPT,
             kill_waiter.Wait());
 }
@@ -477,7 +478,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_EQ(MessagingEndpoint::Type::kContentScript, info.source_endpoint.type);
   EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
@@ -492,8 +493,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToExtension(source_context, info,
-                                              channel_name, port_id));
+      ExtensionHostMsg_OpenChannelToExtension(
+          source_context, info, channel_type, channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_INVALID_CHANNEL_SOURCE_TYPE, kill_waiter.Wait());
 }
 
@@ -507,7 +508,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_EQ(MessagingEndpoint::Type::kContentScript, info.source_endpoint.type);
   EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
@@ -523,8 +524,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToExtension(source_context, info,
-                                              channel_name, port_id));
+      ExtensionHostMsg_OpenChannelToExtension(
+          source_context, info, channel_type, channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_INVALID_EXTENSION_ID_FOR_EXTENSION_SOURCE,
             kill_waiter.Wait());
 }
@@ -539,7 +540,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_EQ(MessagingEndpoint::Type::kContentScript, info.source_endpoint.type);
   EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
@@ -556,8 +557,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToExtension(source_context, info,
-                                              channel_name, port_id));
+      ExtensionHostMsg_OpenChannelToExtension(
+          source_context, info, channel_type, channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_NO_EXTENSION_ID_FOR_EXTENSION_SOURCE,
             kill_waiter.Wait());
 }
@@ -572,7 +573,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_TRUE(source_context.is_for_render_frame());
   EXPECT_FALSE(source_context.is_for_service_worker());
@@ -591,8 +592,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToExtension(source_context, info,
-                                              channel_name, port_id));
+      ExtensionHostMsg_OpenChannelToExtension(
+          source_context, info, channel_type, channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_INVALID_EXTENSION_ID_FOR_WORKER_CONTEXT,
             kill_waiter.Wait());
 }
@@ -613,7 +614,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_EQ(MessagingEndpoint::Type::kContentScript, info.source_endpoint.type);
   EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
@@ -636,8 +637,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToExtension(source_context, info,
-                                              channel_name, port_id));
+      ExtensionHostMsg_OpenChannelToExtension(
+          source_context, info, channel_type, channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_INVALID_SOURCE_URL, kill_waiter.Wait());
 }
 
@@ -664,7 +665,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_EQ(MessagingEndpoint::Type::kExtension, info.source_endpoint.type);
   EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id);
@@ -683,8 +684,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(service_worker_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       service_worker_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToExtension(source_context, info,
-                                              channel_name, port_id));
+      ExtensionHostMsg_OpenChannelToExtension(
+          source_context, info, channel_type, channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_INVALID_SOURCE_URL, kill_waiter.Wait());
 }
 
@@ -704,7 +705,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_TRUE(source_context.is_for_render_frame());
 
@@ -722,8 +723,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToExtension(source_context, info,
-                                              channel_name, port_id));
+      ExtensionHostMsg_OpenChannelToExtension(
+          source_context, info, channel_type, channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_INVALID_OPEN_CHANNEL_TO_EXTENSION_FROM_NATIVE_HOST,
             kill_waiter.Wait());
 }
@@ -921,7 +922,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_TRUE(source_context.is_for_service_worker());
   EXPECT_EQ(active_extension_id(), source_context.worker->extension_id);
@@ -937,8 +938,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToTab(source_context, info, channel_name,
-                                        port_id));
+      ExtensionHostMsg_OpenChannelToTab(source_context, info, channel_type,
+                                        channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_INVALID_EXTENSION_ID_FOR_WORKER_CONTEXT,
             kill_waiter.Wait());
 }
@@ -957,7 +958,7 @@
 
   // Capture the IPC.
   int process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&process_id);
   EXPECT_TRUE(source_context.is_for_service_worker());
   EXPECT_EQ(active_extension_id(), source_context.worker->extension_id);
@@ -973,8 +974,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToTab(source_context, info, channel_name,
-                                        port_id));
+      ExtensionHostMsg_OpenChannelToTab(source_context, info, channel_type,
+                                        channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_NON_EXTENSION_SENDER_NATIVE_HOST,
             kill_waiter.Wait());
 }
@@ -995,7 +996,7 @@
 
   // Capture the IPC.
   int ignored_process_id = -1;
-  auto [source_context, info, channel_name, port_id] =
+  auto [source_context, info, channel_type, channel_name, port_id] =
       WaitForMessage(&ignored_process_id);
 
   // Navigate the test frame to a non-extension location.
@@ -1013,8 +1014,8 @@
   RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process);
   IPC::IpcSecurityTestUtil::PwnMessageReceived(
       main_frame_process->GetChannel(),
-      ExtensionHostMsg_OpenChannelToTab(source_context, info, channel_name,
-                                        port_id));
+      ExtensionHostMsg_OpenChannelToTab(source_context, info, channel_type,
+                                        channel_name, port_id));
   EXPECT_EQ(bad_message::EMF_NON_EXTENSION_SENDER_FRAME, kill_waiter.Wait());
 }
 
diff --git a/chrome/browser/extensions/site_permissions_helper.cc b/chrome/browser/extensions/site_permissions_helper.cc
index 59fad6b..40e3b46 100644
--- a/chrome/browser/extensions/site_permissions_helper.cc
+++ b/chrome/browser/extensions/site_permissions_helper.cc
@@ -84,16 +84,19 @@
     const Extension& extension,
     content::WebContents* web_contents,
     PermissionsManager::UserSiteAccess new_access) {
-  auto current_access = PermissionsManager::Get(profile_)->GetUserSiteAccess(
+  auto* permissions_manager = PermissionsManager::Get(profile_);
+  auto current_access = permissions_manager->GetUserSiteAccess(
       extension, web_contents->GetLastCommittedURL());
   if (new_access == current_access) {
     return;
   }
 
-  const GURL& current_url = web_contents->GetLastCommittedURL();
   ScriptingPermissionsModifier modifier(profile_, &extension);
-  PermissionsManager* permissions_manager = PermissionsManager::Get(profile_);
-  DCHECK(permissions_manager->CanAffectExtension(extension));
+  CHECK(permissions_manager->CanAffectExtension(extension));
+
+  auto current_url = web_contents->GetLastCommittedURL();
+  CHECK(permissions_manager->CanUserSelectSiteAccess(extension, current_url,
+                                                     new_access));
 
   switch (new_access) {
     case PermissionsManager::UserSiteAccess::kOnClick:
diff --git a/chrome/browser/extensions/webstore_data_fetcher.cc b/chrome/browser/extensions/webstore_data_fetcher.cc
index fba8a66..67c5af70 100644
--- a/chrome/browser/extensions/webstore_data_fetcher.cc
+++ b/chrome/browser/extensions/webstore_data_fetcher.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/webstore_data_fetcher.h"
 
+#include <string>
 #include <utility>
 
 #include "base/functional/bind.h"
diff --git a/chrome/browser/feedback/show_feedback_page_lacros.cc b/chrome/browser/feedback/show_feedback_page_lacros.cc
index 129a1de..eda736a 100644
--- a/chrome/browser/feedback/show_feedback_page_lacros.cc
+++ b/chrome/browser/feedback/show_feedback_page_lacros.cc
@@ -27,7 +27,8 @@
     case kFeedbackSourceQuickAnswers:
       return crosapi::mojom::LacrosFeedbackSource::kLacrosQuickAnswers;
     case kFeedbackSourceWindowLayoutMenu:
-      return crosapi::mojom::LacrosFeedbackSource::kLacrosWindowLayoutMenu;
+      return crosapi::mojom::LacrosFeedbackSource::
+          kDeprecatedLacrosWindowLayoutMenu;
     default:
       LOG(ERROR) << "ShowFeedbackPage is called by unknown Lacros source: "
                  << static_cast<int>(source);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index bbd059c..bab1007 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3668,8 +3668,8 @@
   },
   {
     "name": "enable-winrt-geolocation-implementation",
-    "owners": [ "pelavall@microsoft.com" ],
-    "expiry_milestone": 110
+    "owners": [ "pelavall@microsoft.com", "deviceapi-team@google.com" ],
+    "expiry_milestone": 125
   },
   {
     "name": "enable-zero-copy",
@@ -4380,11 +4380,6 @@
     "expiry_milestone": 115
   },
   {
-    "name": "high-efficiency-mode-time-before-discard",
-    "owners": [ "chrome-performance-ui-team@google.com" ],
-    "expiry_milestone": 120
-  },
-  {
     "name": "highlight-managed-pref-disclaimer-android",
     "owners": [ "ftirelo" ],
     "expiry_milestone": 115
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 1fdb017..564a793 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4505,11 +4505,6 @@
     "discarding a tab rather than doing it after a fixed amount of time in the "
     "background.";
 
-extern const char kHighEfficiencyModeTimeBeforeDiscardName[] =
-    "Configure discard time for Memory Saver";
-extern const char kHighEfficiencyModeTimeBeforeDiscardDescription[] =
-    "When set, this controls the time before memory saver discards a tab.";
-
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 extern const char kIOSPromoPasswordBubbleName[] =
     "Contextual Chrome for iOS promo in the password save/update bubble.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 66c7158..70fd1c7 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2577,9 +2577,6 @@
 extern const char kHeuristicMemorySaverName[];
 extern const char kHeuristicMemorySaverDescription[];
 
-extern const char kHighEfficiencyModeTimeBeforeDiscardName[];
-extern const char kHighEfficiencyModeTimeBeforeDiscardDescription[];
-
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 extern const char kIOSPromoPasswordBubbleName[];
 extern const char kIOSPromoPasswordBubbleDecription[];
diff --git a/chrome/browser/lacros/input_method_lacros_browsertest.cc b/chrome/browser/lacros/input_method_lacros_browsertest.cc
index 138cd39..6285636 100644
--- a/chrome/browser/lacros/input_method_lacros_browsertest.cc
+++ b/chrome/browser/lacros/input_method_lacros_browsertest.cc
@@ -40,6 +40,9 @@
       crosapi::mojom::InputMethodTestInterface::Uuid_);
 }
 
+// Used to parameterize these tests.
+struct TestParam {};
+
 // Binds an InputMethodTestInterface to Ash-Chrome, which allows these tests to
 // execute IME operations from Ash-Chrome.
 // `required_versions` are the `MethodMinVersion` values of all the test methods
@@ -49,6 +52,7 @@
 // InputMethodTestInterface does not support the required test methods or
 // capabilities.
 mojo::Remote<InputMethodTestInterface> BindInputMethodTestInterface(
+    const TestParam& test_param,
     std::initializer_list<InputMethodTestInterface::MethodMinVersions>
         required_versions,
     const std::vector<base::StringPiece>& required_test_capabilities = {}) {
@@ -486,14 +490,21 @@
   }
 }
 
-using InputMethodLacrosBrowserTest = InProcessBrowserTest;
+// Keep this fixture simple: only use this to enable / disable feature flags.
+class InputMethodLacrosBrowserTest
+    : public InProcessBrowserTest,
+      public ::testing::WithParamInterface<TestParam> {};
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+INSTANTIATE_TEST_SUITE_P(InputMethodLacrosBrowserTestAllParams,
+                         InputMethodLacrosBrowserTest,
+                         ::testing::Values(TestParam{}));
+
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        FocusingInputFieldSendsFocus) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
-          {InputMethodTestInterface::MethodMinVersions::
-               kWaitForFocusMinVersion});
+          GetParam(), {InputMethodTestInterface::MethodMinVersions::
+                           kWaitForFocusMinVersion});
   if (!input_method.is_bound()) {
     GTEST_SKIP() << "Unsupported ash version";
   }
@@ -504,10 +515,11 @@
   input_method_async_waiter.WaitForFocus();
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        CommitTextInsertsTextInInputField) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::kCommitTextMinVersion});
   if (!input_method.is_bound()) {
@@ -524,10 +536,11 @@
                                          "hello", gfx::Range(5)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        CommitTextUpdatesSurroundingText) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::kCommitTextMinVersion,
            InputMethodTestInterface::MethodMinVersions::
@@ -550,10 +563,11 @@
   EXPECT_EQ(selection_range, gfx::Range(3));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        CommitTextReplacesCompositionText) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kSetCompositionMinVersion,
@@ -577,10 +591,11 @@
                                          "hello abc", gfx::Range(9)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        CommitEmptyTextDeletesCompositionText) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kSetCompositionMinVersion,
@@ -602,10 +617,11 @@
                                          "", gfx::Range(0)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        CommitTextReplacesSelection) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::kCommitTextMinVersion});
   if (!input_method.is_bound()) {
@@ -624,10 +640,11 @@
                                          "habclo", gfx::Range(4)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        CommitTextTriggersWebEvents) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kKeyEventHandledMinVersion});
@@ -659,10 +676,11 @@
   EXPECT_FALSE(event_listener.HasMessages());
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        CommitTextWhileHandlingKeyEventTriggersWebEvents) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kSetCompositionMinVersion,
@@ -707,10 +725,11 @@
                                          "。", gfx::Range(1)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SetCompositionInsertsCompositionInEmptyInputField) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kSetCompositionMinVersion});
@@ -728,10 +747,11 @@
                                          "hello", gfx::Range(3)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SetCompositionInsertsCompositionAtStartOfInputField) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kSetCompositionMinVersion});
@@ -751,10 +771,11 @@
                                          "hello world", gfx::Range(5)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SetCompositionInsertsCompositionAtEndOfInputField) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kSetCompositionMinVersion});
@@ -774,10 +795,11 @@
                                          "hello world", gfx::Range(11)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SetCompositionInsertsCompositionInMiddleOfInputField) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kSetCompositionMinVersion});
@@ -797,10 +819,11 @@
                                          "hello world", gfx::Range(5)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SetCompositionReplacesCompositionInInputField) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kSetCompositionMinVersion});
@@ -819,10 +842,11 @@
                                          "abc", gfx::Range(2)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SetCompositionTriggersWebEvents) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kKeyEventHandledMinVersion});
@@ -859,10 +883,11 @@
   EXPECT_FALSE(event_listener.HasMessages());
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SetCompositionUpdatesSurroundingText) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::kCommitTextMinVersion,
            InputMethodTestInterface::MethodMinVersions::
@@ -885,10 +910,11 @@
   EXPECT_EQ(selection_range, gfx::Range(3));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendKeyEventNotHandledTypesInEmptyTextField) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kKeyEventHandledMinVersion});
@@ -915,10 +941,11 @@
                                          "abc", gfx::Range(3)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendBackspaceDeletesNonEmptyTextField) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kKeyEventHandledMinVersion});
@@ -957,10 +984,11 @@
                                          "lo", gfx::Range(0)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendLeftArrowKeyWithSelectionCollapsesSelectionLeft) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kKeyEventHandledMinVersion});
@@ -986,10 +1014,11 @@
                                          "abcde", gfx::Range(1)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendRightArrowKeyWithSelectionCollapsesSelectionRight) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kKeyEventHandledMinVersion});
@@ -1015,10 +1044,11 @@
                                          "abcde", gfx::Range(4)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendKeyEventShortcutsModifiesSelection) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kKeyEventHandledMinVersion},
@@ -1106,10 +1136,11 @@
                                          "abc abc abc", gfx::Range(11, 11)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SetCompositionWhileHandlingKeyEventTriggersWebEvents) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kSetCompositionMinVersion,
@@ -1153,10 +1184,11 @@
                                          "ㅎ", gfx::Range(1)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendKeyEventTriggersWebEvents) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kKeyEventHandledMinVersion});
@@ -1186,10 +1218,11 @@
   EXPECT_FALSE(event_listener.HasMessages());
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        SendKeyEventModifiersTriggersWebEvents) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kKeyEventHandledMinVersion},
@@ -1242,10 +1275,11 @@
   EXPECT_FALSE(event_listener.HasMessages());
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        ConfirmCompositionWithNoSelectionAndNoComposition) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kWaitForNextSurroundingTextChangeMinVersion},
@@ -1267,10 +1301,11 @@
                                          "hello", gfx::Range(3)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        ConfirmCompositionWithNoSelectionAndComposition) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kWaitForNextSurroundingTextChangeMinVersion},
@@ -1291,10 +1326,11 @@
                                          "hello", gfx::Range(3)));
 }
 
-IN_PROC_BROWSER_TEST_F(InputMethodLacrosBrowserTest,
+IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        ConfirmCompositionWithSelectionAndNoComposition) {
   mojo::Remote<InputMethodTestInterface> input_method =
       BindInputMethodTestInterface(
+          GetParam(),
           {InputMethodTestInterface::MethodMinVersions::kWaitForFocusMinVersion,
            InputMethodTestInterface::MethodMinVersions::
                kWaitForNextSurroundingTextChangeMinVersion},
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
index 57a5bbb..f2d4219 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
@@ -697,40 +697,39 @@
     const std::string& media_route_id,
     const std::string& message,
     data_decoder::DataDecoder::ValueOrError result) {
-  if (!result.has_value()) {
-    logger_->LogError(
-        mojom::LogCategory::kRoute, kLoggerComponent,
-        "Error parsing JSON data when sending route JSON message: " +
-            result.error(),
-        "", MediaRoute::GetMediaSourceIdFromMediaRouteId(media_route_id),
-        MediaRoute::GetPresentationIdFromMediaRouteId(media_route_id));
-    return;
-  }
+  const auto activity = [&]()
+      -> base::expected<std::pair<CastActivity*, std::string>, std::string> {
+    if (!result.has_value()) {
+      return base::unexpected(
+          "Error parsing JSON data when sending route JSON message: " +
+          result.error());
+    }
 
-  const std::string* client_id = result->FindStringKey("clientId");
-  if (!client_id) {
+    const std::string* const client_id =
+        result.value().FindStringKey("clientId");
+    if (!client_id) {
+      return base::unexpected(
+          "Cannot send route JSON message without client id.");
+    }
+
+    const auto it = activities_.find(media_route_id);
+    if (it == activities_.end()) {
+      return base::unexpected(
+          "No activity found with the given route_id to send route JSON "
+          "message.");
+    }
+    return std::make_pair(it->second.get(), *client_id);
+  }();
+  if (!activity.has_value()) {
     logger_->LogError(
-        mojom::LogCategory::kRoute, kLoggerComponent,
-        "Cannot send route JSON message without client id.", "",
+        mojom::LogCategory::kRoute, kLoggerComponent, activity.error(), "",
         MediaRoute::GetMediaSourceIdFromMediaRouteId(media_route_id),
         MediaRoute::GetPresentationIdFromMediaRouteId(media_route_id));
     return;
   }
-
-  const auto it = activities_.find(media_route_id);
-  if (it == activities_.end()) {
-    logger_->LogError(
-        mojom::LogCategory::kRoute, kLoggerComponent,
-        "No activity found with the given route_id to send route JSON message.",
-        "", MediaRoute::GetMediaSourceIdFromMediaRouteId(media_route_id),
-        MediaRoute::GetPresentationIdFromMediaRouteId(media_route_id));
-    return;
-  }
-  CastActivity& activity = *it->second;
-
-  auto message_ptr =
-      blink::mojom::PresentationConnectionMessage::NewMessage(message);
-  activity.SendMessageToClient(*client_id, std::move(message_ptr));
+  activity->first->SendMessageToClient(
+      std::move(activity->second),
+      blink::mojom::PresentationConnectionMessage::NewMessage(message));
 }
 
 void CastActivityManager::AddNonLocalActivity(const MediaSinkInternal& sink,
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
index d49d8e3..6dfb719 100644
--- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
+++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -36,6 +36,7 @@
 #include "chrome/browser/metrics/process_memory_metrics_emitter.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/shell_integration.h"
+#include "chrome/common/chrome_switches.h"
 #include "components/flags_ui/pref_service_flags_storage.h"
 #include "components/policy/core/common/management/management_service.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -117,11 +118,26 @@
 
 void RecordMemoryMetrics();
 
+// Gets the delay for logging memory related metrics for testing.
+absl::optional<base::TimeDelta> GetDelayForNextMemoryLogTest() {
+  int test_delay_in_minutes;
+  const base::CommandLine* command_line =
+      base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTestMemoryLogDelayInMinutes) &&
+      base::StringToInt(command_line->GetSwitchValueASCII(
+                            switches::kTestMemoryLogDelayInMinutes),
+                        &test_delay_in_minutes)) {
+    return base::Minutes(test_delay_in_minutes);
+  }
+  return absl::nullopt;
+}
+
 // Records memory metrics after a delay.
 void RecordMemoryMetricsAfterDelay() {
   content::GetUIThreadTaskRunner({})->PostDelayedTask(
       FROM_HERE, base::BindOnce(&RecordMemoryMetrics),
-      memory_instrumentation::GetDelayForNextMemoryLog());
+      GetDelayForNextMemoryLogTest().value_or(
+          memory_instrumentation::GetDelayForNextMemoryLog()));
 }
 
 // Records memory metrics, and then triggers memory colleciton after a delay.
diff --git a/chrome/browser/metrics/variations/field_trials_on_off_browsertest.cc b/chrome/browser/metrics/variations/field_trials_on_off_browsertest.cc
new file mode 100644
index 0000000..5c702c8f
--- /dev/null
+++ b/chrome/browser/metrics/variations/field_trials_on_off_browsertest.cc
@@ -0,0 +1,52 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/variations/variations_switches.h"
+#include "content/public/test/browser_test.h"
+
+class FieldTrialsOnOffBrowserTest : public InProcessBrowserTest,
+                                    public testing::WithParamInterface<bool> {
+ public:
+  FieldTrialsOnOffBrowserTest() = default;
+  FieldTrialsOnOffBrowserTest(const FieldTrialsOnOffBrowserTest&) = delete;
+  FieldTrialsOnOffBrowserTest& operator=(const FieldTrialsOnOffBrowserTest&) =
+      delete;
+  ~FieldTrialsOnOffBrowserTest() override = default;
+
+  void SetUp() override {
+    // Enable only one of --{enable,disable}-field-trial-config switches.
+    std::vector<std::string> switches = {
+        variations::switches::kDisableFieldTrialTestingConfig,
+        variations::switches::kEnableFieldTrialTestingConfig};
+    int append = GetParam();
+    int remove = !append;
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    if (!command_line->HasSwitch(switches[append])) {
+      command_line->AppendSwitch(switches[append]);
+    }
+    if (command_line->HasSwitch(switches[remove])) {
+      command_line->RemoveSwitch(switches[remove]);
+    }
+    InProcessBrowserTest::SetUp();
+  }
+};
+
+IN_PROC_BROWSER_TEST_P(FieldTrialsOnOffBrowserTest, Test) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL initial_url = embedded_test_server()->GetURL("/title1.html");
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), initial_url));
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         FieldTrialsOnOffBrowserTest,
+                         testing::Bool(),
+                         [](const ::testing::TestParamInfo<bool>& info) {
+                           return info.param ? "On" : "Off";
+                         });
diff --git a/chrome/browser/net/cert_verifier_service_browsertest.cc b/chrome/browser/net/cert_verifier_service_browsertest.cc
index 96f7b24..e4d4ce5 100644
--- a/chrome/browser/net/cert_verifier_service_browsertest.cc
+++ b/chrome/browser/net/cert_verifier_service_browsertest.cc
@@ -85,9 +85,8 @@
 IN_PROC_BROWSER_TEST_P(CertVerifierServiceChromeRootStoreFeaturePolicyTest,
                        Test) {
   // IsUsingChromeRootStore return value should match the expected state.
-  EXPECT_EQ(
-      expected_use_chrome_root_store(),
-      SystemNetworkContextManager::GetInstance()->IsUsingChromeRootStore());
+  EXPECT_EQ(expected_use_chrome_root_store(),
+            SystemNetworkContextManager::IsUsingChromeRootStore());
 
   net::EmbeddedTestServer https_test_server(
       net::EmbeddedTestServer::TYPE_HTTPS);
@@ -142,9 +141,8 @@
   SetPolicyValue(new_expected_use_chrome_root_store);
 
   // IsUsingChromeRootStore return value should match the new policy setting.
-  EXPECT_EQ(
-      new_expected_use_chrome_root_store,
-      SystemNetworkContextManager::GetInstance()->IsUsingChromeRootStore());
+  EXPECT_EQ(new_expected_use_chrome_root_store,
+            SystemNetworkContextManager::IsUsingChromeRootStore());
 
   // The SetUseChromeRootStore message should have been dispatched to the
   // CertVerifierServiceFactory but may not have actually been processed yet.
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index f67f0f7..35847a9 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -947,12 +947,26 @@
 }
 
 #if BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
+// static
 bool SystemNetworkContextManager::IsUsingChromeRootStore() {
+  // SystemNetworkContextManager::GetInstance() may be null in unit_tests. In
+  // that case just fall back to only using the feature flag.
+  return IsUsingChromeRootStoreImpl(
+      SystemNetworkContextManager::GetInstance()
+          ? SystemNetworkContextManager::GetInstance()->local_state_
+          : nullptr);
+}
+
+// static
+bool SystemNetworkContextManager::IsUsingChromeRootStoreImpl(
+    PrefService* local_state) {
 #if BUILDFLAG(CHROME_ROOT_STORE_POLICY_SUPPORTED)
-  const PrefService::Preference* chrome_root_store_enabled_pref =
-      local_state_->FindPreference(prefs::kChromeRootStoreEnabled);
-  if (chrome_root_store_enabled_pref->IsManaged()) {
-    return chrome_root_store_enabled_pref->GetValue()->GetBool();
+  if (local_state) {
+    const PrefService::Preference* chrome_root_store_enabled_pref =
+        local_state->FindPreference(prefs::kChromeRootStoreEnabled);
+    if (chrome_root_store_enabled_pref->IsManaged()) {
+      return chrome_root_store_enabled_pref->GetValue()->GetBool();
+    }
   }
 #endif  // BUILDFLAG(CHROME_ROOT_STORE_POLICY_SUPPORTED)
   return base::FeatureList::IsEnabled(net::features::kChromeRootStoreUsed);
@@ -985,7 +999,7 @@
 #if BUILDFLAG(CHROME_ROOT_STORE_POLICY_SUPPORTED)
 void SystemNetworkContextManager::UpdateChromeRootStoreEnabled() {
   content::GetCertVerifierServiceFactory()->SetUseChromeRootStore(
-      IsUsingChromeRootStore(), base::DoNothing());
+      IsUsingChromeRootStoreImpl(local_state_), base::DoNothing());
 }
 #endif  // BUILDFLAG(CHROME_ROOT_STORE_POLICY_SUPPORTED)
 
diff --git a/chrome/browser/net/system_network_context_manager.h b/chrome/browser/net/system_network_context_manager.h
index 15b5e77..2b1bffb 100644
--- a/chrome/browser/net/system_network_context_manager.h
+++ b/chrome/browser/net/system_network_context_manager.h
@@ -174,7 +174,7 @@
   }
 
 #if BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
-  bool IsUsingChromeRootStore();
+  static bool IsUsingChromeRootStore();
 #endif  // BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
 
  private:
@@ -198,6 +198,10 @@
   // the network process.
   void UpdateExplicitlyAllowedNetworkPorts();
 
+#if BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
+  static bool IsUsingChromeRootStoreImpl(PrefService* local_state);
+#endif  // BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
+
 #if BUILDFLAG(CHROME_ROOT_STORE_POLICY_SUPPORTED)
   void UpdateChromeRootStoreEnabled();
 #endif  // BUILDFLAG(CHROME_ROOT_STORE_POLICY_SUPPORTED)
diff --git a/chrome/browser/offline_pages/android/load_termination_listener_impl.cc b/chrome/browser/offline_pages/android/load_termination_listener_impl.cc
index 2bac4f2..5b986c2 100644
--- a/chrome/browser/offline_pages/android/load_termination_listener_impl.cc
+++ b/chrome/browser/offline_pages/android/load_termination_listener_impl.cc
@@ -12,11 +12,12 @@
 namespace offline_pages {
 
 LoadTerminationListenerImpl::LoadTerminationListenerImpl() {
-  if (base::SysInfo::IsLowEndDevice())
+  if (base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled()) {
     app_listener_ =
         base::android::ApplicationStatusListener::New(base::BindRepeating(
             &LoadTerminationListenerImpl::OnApplicationStateChange,
             weak_ptr_factory_.GetWeakPtr()));
+  }
 }
 
 LoadTerminationListenerImpl::~LoadTerminationListenerImpl() {
diff --git a/chrome/browser/performance_manager/metrics/metrics_provider_unittest.cc b/chrome/browser/performance_manager/metrics/metrics_provider_unittest.cc
index f5ca0a6..fc56232 100644
--- a/chrome/browser/performance_manager/metrics/metrics_provider_unittest.cc
+++ b/chrome/browser/performance_manager/metrics/metrics_provider_unittest.cc
@@ -17,12 +17,12 @@
 
 #include "base/logging.h"
 
-class FakeHighEfficiencyModeDelegate
+class FakeHighEfficiencyModeToggleDelegate
     : public performance_manager::user_tuning::UserPerformanceTuningManager::
-          HighEfficiencyModeDelegate {
+          HighEfficiencyModeToggleDelegate {
  public:
   void ToggleHighEfficiencyMode(bool enabled) override {}
-  ~FakeHighEfficiencyModeDelegate() override = default;
+  ~FakeHighEfficiencyModeToggleDelegate() override = default;
 };
 
 class PerformanceManagerMetricsProviderTest : public testing::Test {
diff --git a/chrome/browser/performance_manager/metrics/page_timeline_monitor_unittest.cc b/chrome/browser/performance_manager/metrics/page_timeline_monitor_unittest.cc
index 53465e9..7ce9b0b 100644
--- a/chrome/browser/performance_manager/metrics/page_timeline_monitor_unittest.cc
+++ b/chrome/browser/performance_manager/metrics/page_timeline_monitor_unittest.cc
@@ -268,10 +268,8 @@
   EXPECT_EQ(entries.size(), 2UL);
   test_ukm_recorder()->ExpectEntryMetric(entries[1], "HighEfficiencyMode", 0);
 
-  performance_manager::policies::HighEfficiencyModePolicy* policy =
-      performance_manager::policies::HighEfficiencyModePolicy::GetInstance();
-  policy->SetTimeBeforeDiscard(base::Hours(2));
-  policy->OnHighEfficiencyModeChanged(true);
+  performance_manager::policies::HighEfficiencyModePolicy::GetInstance()
+      ->OnHighEfficiencyModeChanged(true);
 
   TriggerCollectSlice();
   entries = test_ukm_recorder()->GetEntriesByName(
diff --git a/chrome/browser/performance_manager/policies/high_efficiency_mode_policy.cc b/chrome/browser/performance_manager/policies/high_efficiency_mode_policy.cc
index 49cf96f..9701f193 100644
--- a/chrome/browser/performance_manager/policies/high_efficiency_mode_policy.cc
+++ b/chrome/browser/performance_manager/policies/high_efficiency_mode_policy.cc
@@ -16,8 +16,11 @@
 
 }
 
+const base::TimeDelta HighEfficiencyModePolicy::kDefaultDiscardTimeInterval =
+    base::Hours(2);
+
 HighEfficiencyModePolicy::HighEfficiencyModePolicy()
-    : time_before_discard_(base::TimeDelta::Max()) {
+    : time_before_discard_(kDefaultDiscardTimeInterval) {
   DCHECK(!g_high_efficiency_mode_policy);
   g_high_efficiency_mode_policy = this;
 }
@@ -114,19 +117,6 @@
   }
 }
 
-base::TimeDelta HighEfficiencyModePolicy::GetTimeBeforeDiscardForTesting()
-    const {
-  return time_before_discard_;
-}
-
-void HighEfficiencyModePolicy::SetTimeBeforeDiscard(
-    base::TimeDelta time_before_discard) {
-  CHECK(active_discard_timers_.empty());
-  // TODO(charlesmeng): Update existing discard timers when time_before_discard_
-  // is changed.
-  time_before_discard_ = time_before_discard;
-}
-
 bool HighEfficiencyModePolicy::IsHighEfficiencyDiscardingEnabled() const {
   return high_efficiency_mode_enabled_;
 }
@@ -138,7 +128,6 @@
   if (IsHighEfficiencyDiscardingEnabled()) {
     // High Efficiency mode is enabled, so the tab should be discarded after the
     // amount of time specified by finch is elapsed.
-    CHECK_NE(time_before_discard_, base::TimeDelta::Max());
     active_discard_timers_[page_node].Start(
         FROM_HERE, time_before_discard,
         base::BindOnce(&HighEfficiencyModePolicy::DiscardPageTimerCallback,
diff --git a/chrome/browser/performance_manager/policies/high_efficiency_mode_policy.h b/chrome/browser/performance_manager/policies/high_efficiency_mode_policy.h
index b64edb32..1322a5d 100644
--- a/chrome/browser/performance_manager/policies/high_efficiency_mode_policy.h
+++ b/chrome/browser/performance_manager/policies/high_efficiency_mode_policy.h
@@ -20,6 +20,10 @@
 class HighEfficiencyModePolicy : public GraphOwned,
                                  public PageNode::ObserverDefaultImpl {
  public:
+  // The default amount of time a tab must spend in the background before it's
+  // discarded by Memory Saver.
+  static const base::TimeDelta kDefaultDiscardTimeInterval;
+
   HighEfficiencyModePolicy();
   ~HighEfficiencyModePolicy() override;
 
@@ -37,8 +41,6 @@
   void OnTakenFromGraph(Graph* graph) override;
 
   void OnHighEfficiencyModeChanged(bool enabled);
-  base::TimeDelta GetTimeBeforeDiscardForTesting() const;
-  void SetTimeBeforeDiscard(base::TimeDelta time_before_discard);
 
   // Returns true if High Efficiency mode is enabled, false otherwise. Useful to
   // get the state of the mode from the Performance Manager sequence.
@@ -53,7 +55,7 @@
   bool high_efficiency_mode_enabled_ = false;
 
   std::map<const PageNode*, base::OneShotTimer> active_discard_timers_;
-  base::TimeDelta time_before_discard_;
+  const base::TimeDelta time_before_discard_;
 
   raw_ptr<Graph> graph_ = nullptr;
 };
diff --git a/chrome/browser/performance_manager/policies/high_efficiency_mode_policy_unittest.cc b/chrome/browser/performance_manager/policies/high_efficiency_mode_policy_unittest.cc
index 9efc0de..2bfa99c 100644
--- a/chrome/browser/performance_manager/policies/high_efficiency_mode_policy_unittest.cc
+++ b/chrome/browser/performance_manager/policies/high_efficiency_mode_policy_unittest.cc
@@ -26,7 +26,6 @@
         static_cast<PageNode*>(page_node())->GetBrowserContextID(), {});
 
     auto policy = std::make_unique<HighEfficiencyModePolicy>();
-    policy->SetTimeBeforeDiscard(base::Hours(2));
     policy_ = policy.get();
     graph()->PassToGraph(std::move(policy));
   }
@@ -80,7 +79,8 @@
       .WillOnce(::testing::Return(true));
   page_node()->SetIsVisible(false);
 
-  task_env().FastForwardBy(policy()->GetTimeBeforeDiscardForTesting());
+  task_env().FastForwardBy(
+      HighEfficiencyModePolicy::kDefaultDiscardTimeInterval);
   ::testing::Mock::VerifyAndClearExpectations(discarder());
 }
 
@@ -109,27 +109,6 @@
   ::testing::Mock::VerifyAndClearExpectations(discarder());
 }
 
-TEST_F(HighEfficiencyModeTest, TimeBeforeDiscardChangedBeforeHighEfficiencyOn) {
-  base::TimeDelta original_time_before_discard =
-      policy()->GetTimeBeforeDiscardForTesting();
-  policy()->SetTimeBeforeDiscard(original_time_before_discard +
-                                 base::Seconds(10));
-
-  page_node()->SetType(PageType::kTab);
-  page_node()->SetIsVisible(true);
-  page_node()->SetIsVisible(false);
-  policy()->OnHighEfficiencyModeChanged(true);
-
-  task_env().FastForwardBy(original_time_before_discard);
-  ::testing::Mock::VerifyAndClearExpectations(discarder());
-
-  EXPECT_CALL(*discarder(), DiscardPageNodeImpl(page_node()))
-      .WillOnce(::testing::Return(true));
-
-  task_env().FastForwardBy(base::Seconds(10));
-  ::testing::Mock::VerifyAndClearExpectations(discarder());
-}
-
 TEST_F(HighEfficiencyModeTest, DiscardIfAlreadyNotVisibleWhenModeEnabled) {
   page_node()->SetType(PageType::kTab);
   page_node()->SetIsVisible(true);
@@ -141,8 +120,9 @@
 
   // Advance time by the usual discard interval, minus 10 seconds. This means
   // that the page will be discarded 10 seconds after the mode is changed.
-  task_env().FastForwardBy(policy()->GetTimeBeforeDiscardForTesting() -
-                           base::Seconds(10));
+  task_env().FastForwardBy(
+      HighEfficiencyModePolicy::kDefaultDiscardTimeInterval -
+      base::Seconds(10));
   ::testing::Mock::VerifyAndClearExpectations(discarder());
 
   policy()->OnHighEfficiencyModeChanged(true);
@@ -195,7 +175,8 @@
       .WillOnce(::testing::Return(true));
   page_node->SetIsVisible(false);
 
-  task_env().FastForwardBy(policy()->GetTimeBeforeDiscardForTesting());
+  task_env().FastForwardBy(
+      HighEfficiencyModePolicy::kDefaultDiscardTimeInterval);
   ::testing::Mock::VerifyAndClearExpectations(discarder());
 }
 
diff --git a/chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h b/chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h
index 95b12c86..1037f0a6 100644
--- a/chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h
+++ b/chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h
@@ -10,7 +10,6 @@
 #include "base/power_monitor/battery_state_sampler.h"
 #include "base/power_monitor/power_observer.h"
 #include "base/scoped_observation.h"
-#include "base/time/time.h"
 #include "chrome/browser/performance_manager/user_tuning/user_performance_tuning_notifier.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom-shared.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -41,9 +40,6 @@
   // would be `20` for 20%.
   static const uint64_t kLowBatteryThresholdPercent;
 
-  // Command line switch for setting the discard time.
-  static const char kTimeBeforeDiscardInMinutesSwitch[];
-
   class FrameThrottlingDelegate {
    public:
     virtual void StartThrottlingAllFrameSinks() = 0;
@@ -52,11 +48,10 @@
     virtual ~FrameThrottlingDelegate() = default;
   };
 
-  class HighEfficiencyModeDelegate {
+  class HighEfficiencyModeToggleDelegate {
    public:
     virtual void ToggleHighEfficiencyMode(bool enabled) = 0;
-    virtual void SetTimeBeforeDiscard(base::TimeDelta time_before_discard) = 0;
-    virtual ~HighEfficiencyModeDelegate() = default;
+    virtual ~HighEfficiencyModeToggleDelegate() = default;
   };
 
   class Observer : public base::CheckedObserver {
@@ -185,10 +180,6 @@
   // indicates that the battery state has not been sampled yet.
   int SampledBatteryPercentage() const;
 
-  // Sets the default value of the discard time pref using the command line
-  // switch, if the pref is in the default state.
-  static void SetDefaultTimeBeforeDiscardFromSwitch(PrefService* local_state);
-
   // Discards the given WebContents with the same mechanism as one that is
   // discarded through a natural timeout
   void DiscardPageForTesting(content::WebContents* web_contents);
@@ -217,13 +208,12 @@
       std::unique_ptr<UserPerformanceTuningNotifier> notifier = nullptr,
       std::unique_ptr<FrameThrottlingDelegate> frame_throttling_delegate =
           nullptr,
-      std::unique_ptr<HighEfficiencyModeDelegate>
-          high_efficiency_mode_delegate = nullptr);
+      std::unique_ptr<HighEfficiencyModeToggleDelegate>
+          high_efficiency_mode_toggle_delegate = nullptr);
 
   void Start();
 
   void OnHighEfficiencyModePrefChanged();
-  void OnHighEfficiencyModeTimeBeforeDiscardChanged();
   void OnBatterySaverModePrefChanged();
 
   void UpdateBatterySaverModeState();
@@ -244,7 +234,8 @@
   bool battery_saver_mode_enabled_ = false;
   bool battery_saver_mode_disabled_for_session_ = false;
   std::unique_ptr<FrameThrottlingDelegate> frame_throttling_delegate_;
-  std::unique_ptr<HighEfficiencyModeDelegate> high_efficiency_mode_delegate_;
+  std::unique_ptr<HighEfficiencyModeToggleDelegate>
+      high_efficiency_mode_toggle_delegate_;
 
   bool has_battery_ = false;
   bool force_has_battery_ = false;
@@ -259,7 +250,7 @@
   base::ObserverList<Observer> observers_;
 
   // Command line switch for overriding the device has battery flag.
-  static const char kForceDeviceHasBatterySwitch[];
+  static const char kForceDeviceHasBattery[];
 };
 
 }  // namespace performance_manager::user_tuning
diff --git a/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.cc b/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.cc
deleted file mode 100644
index c10b9377..0000000
--- a/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.cc
+++ /dev/null
@@ -1,21 +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 "chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.h"
-
-namespace performance_manager {
-
-void FakeHighEfficiencyModeDelegate::ToggleHighEfficiencyMode(bool enabled) {}
-
-void FakeHighEfficiencyModeDelegate::SetTimeBeforeDiscard(
-    base::TimeDelta time_before_discard) {
-  FakeHighEfficiencyModeDelegate::last_time_before_discard =
-      time_before_discard;
-}
-
-base::TimeDelta FakeHighEfficiencyModeDelegate::GetLastTimeBeforeDiscard() {
-  return last_time_before_discard;
-}
-
-}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.h b/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.h
deleted file mode 100644
index 7e47d7cc..0000000
--- a/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.h
+++ /dev/null
@@ -1,30 +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 CHROME_BROWSER_PERFORMANCE_MANAGER_TEST_SUPPORT_FAKE_HIGH_EFFICIENCY_MODE_DELEGATE_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_TEST_SUPPORT_FAKE_HIGH_EFFICIENCY_MODE_DELEGATE_H_
-
-#include "base/time/time.h"
-#include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h"
-
-namespace performance_manager {
-
-class FakeHighEfficiencyModeDelegate
-    : public performance_manager::user_tuning::UserPerformanceTuningManager::
-          HighEfficiencyModeDelegate {
- public:
-  // overrides of methods in HighEfficiencyModeDelegate
-  void ToggleHighEfficiencyMode(bool enabled) override;
-  void SetTimeBeforeDiscard(base::TimeDelta time_before_discard) override;
-  ~FakeHighEfficiencyModeDelegate() override = default;
-
-  base::TimeDelta GetLastTimeBeforeDiscard();
-
- private:
-  base::TimeDelta last_time_before_discard = base::TimeDelta::Max();
-};
-
-}  // namespace performance_manager
-
-#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_TEST_SUPPORT_FAKE_HIGH_EFFICIENCY_MODE_DELEGATE_H_
diff --git a/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.cc b/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.cc
new file mode 100644
index 0000000..90fc74d
--- /dev/null
+++ b/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.cc
@@ -0,0 +1,12 @@
+// 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/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.h"
+
+namespace performance_manager {
+
+void FakeHighEfficiencyModeToggleDelegate::ToggleHighEfficiencyMode(
+    bool enabled) {}
+
+}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.h b/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.h
new file mode 100644
index 0000000..73cfcae2
--- /dev/null
+++ b/chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.h
@@ -0,0 +1,22 @@
+// 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_PERFORMANCE_MANAGER_TEST_SUPPORT_FAKE_HIGH_EFFICIENCY_MODE_TOGGLE_DELEGATE_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_TEST_SUPPORT_FAKE_HIGH_EFFICIENCY_MODE_TOGGLE_DELEGATE_H_
+
+#include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h"
+
+namespace performance_manager {
+
+class FakeHighEfficiencyModeToggleDelegate
+    : public performance_manager::user_tuning::UserPerformanceTuningManager::
+          HighEfficiencyModeToggleDelegate {
+ public:
+  void ToggleHighEfficiencyMode(bool enabled) override;
+  ~FakeHighEfficiencyModeToggleDelegate() override = default;
+};
+
+}  // namespace performance_manager
+
+#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_TEST_SUPPORT_FAKE_HIGH_EFFICIENCY_MODE_TOGGLE_DELEGATE_H_
diff --git a/chrome/browser/performance_manager/test_support/test_user_performance_tuning_manager_environment.cc b/chrome/browser/performance_manager/test_support/test_user_performance_tuning_manager_environment.cc
index a3ced75..014375f0 100644
--- a/chrome/browser/performance_manager/test_support/test_user_performance_tuning_manager_environment.cc
+++ b/chrome/browser/performance_manager/test_support/test_user_performance_tuning_manager_environment.cc
@@ -6,7 +6,7 @@
 
 #include "base/test/power_monitor_test_utils.h"
 #include "chrome/browser/performance_manager/test_support/fake_frame_throttling_delegate.h"
-#include "chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.h"
+#include "chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.h"
 #include "chrome/browser/performance_manager/test_support/fake_power_monitor_source.h"
 #include "components/prefs/pref_service.h"
 
@@ -42,7 +42,7 @@
   manager_.reset(new user_tuning::UserPerformanceTuningManager(
       local_state, nullptr,
       std::make_unique<FakeFrameThrottlingDelegate>(&throttling_enabled_),
-      std::make_unique<FakeHighEfficiencyModeDelegate>()));
+      std::make_unique<FakeHighEfficiencyModeToggleDelegate>()));
   manager_->Start();
 }
 
diff --git a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
index 3e94ec7..c7b1500 100644
--- a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
+++ b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
@@ -8,6 +8,7 @@
 #include "base/feature_list.h"
 #include "base/power_monitor/power_monitor.h"
 #include "base/run_loop.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/performance_manager/metrics/page_timeline_monitor.h"
 #include "chrome/browser/performance_manager/policies/heuristic_memory_saver_policy.h"
@@ -63,9 +64,9 @@
   }
 };
 
-class HighEfficiencyModeDelegateImpl
+class HighEfficiencyModeToggleDelegateImpl
     : public performance_manager::user_tuning::UserPerformanceTuningManager::
-          HighEfficiencyModeDelegate {
+          HighEfficiencyModeToggleDelegate {
  public:
   void ToggleHighEfficiencyMode(bool enabled) override {
     performance_manager::PerformanceManager::CallOnGraph(
@@ -86,30 +87,14 @@
             enabled));
   }
 
-  void SetTimeBeforeDiscard(base::TimeDelta time_before_discard) override {
-    performance_manager::PerformanceManager::CallOnGraph(
-        FROM_HERE,
-        base::BindOnce(
-            [](base::TimeDelta time_before_discard,
-               performance_manager::Graph* graph) {
-              CHECK(policies::HighEfficiencyModePolicy::GetInstance());
-              policies::HighEfficiencyModePolicy::GetInstance()
-                  ->SetTimeBeforeDiscard(time_before_discard);
-            },
-            time_before_discard));
-  }
-
-  ~HighEfficiencyModeDelegateImpl() override = default;
+  ~HighEfficiencyModeToggleDelegateImpl() override = default;
 };
 
 }  // namespace
 
 const uint64_t UserPerformanceTuningManager::kLowBatteryThresholdPercent = 20;
 
-const char UserPerformanceTuningManager::kTimeBeforeDiscardInMinutesSwitch[] =
-    "time-before-discard-in-minutes";
-
-const char UserPerformanceTuningManager::kForceDeviceHasBatterySwitch[] =
+const char UserPerformanceTuningManager::kForceDeviceHasBattery[] =
     "force-device-has-battery";
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(
@@ -211,33 +196,6 @@
   return battery_percentage_;
 }
 
-// static
-void UserPerformanceTuningManager::SetDefaultTimeBeforeDiscardFromSwitch(
-    PrefService* local_state) {
-  // TODO(https://crbug.com/1424220): remove this function after multistate
-  // memory saver UI is available as the discard time pref will be configurable
-  // by the user
-  const PrefService::Preference* time_before_discard_pref =
-      local_state->FindPreference(
-          performance_manager::user_tuning::prefs::
-              kHighEfficiencyModeTimeBeforeDiscardInMinutes);
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (time_before_discard_pref->IsDefaultValue() &&
-      command_line->HasSwitch(kTimeBeforeDiscardInMinutesSwitch)) {
-    int time_before_discard_in_minutes;
-    std::string time_before_discard_in_minutes_string =
-        command_line->GetSwitchValueASCII(kTimeBeforeDiscardInMinutesSwitch);
-    if (base::StringToInt(time_before_discard_in_minutes_string,
-                          &time_before_discard_in_minutes) &&
-        time_before_discard_in_minutes > 0) {
-      local_state->SetDefaultPrefValue(
-          performance_manager::user_tuning::prefs::
-              kHighEfficiencyModeTimeBeforeDiscardInMinutes,
-          base::Value(time_before_discard_in_minutes));
-    }
-  }
-}
-
 UserPerformanceTuningManager::UserPerformanceTuningReceiverImpl::
     ~UserPerformanceTuningReceiverImpl() = default;
 
@@ -278,15 +236,16 @@
     PrefService* local_state,
     std::unique_ptr<UserPerformanceTuningNotifier> notifier,
     std::unique_ptr<FrameThrottlingDelegate> frame_throttling_delegate,
-    std::unique_ptr<HighEfficiencyModeDelegate> high_efficiency_mode_delegate)
+    std::unique_ptr<HighEfficiencyModeToggleDelegate>
+        high_efficiency_mode_toggle_delegate)
     : frame_throttling_delegate_(
           frame_throttling_delegate
               ? std::move(frame_throttling_delegate)
               : std::make_unique<FrameThrottlingDelegateImpl>()),
-      high_efficiency_mode_delegate_(
-          high_efficiency_mode_delegate
-              ? std::move(high_efficiency_mode_delegate)
-              : std::make_unique<HighEfficiencyModeDelegateImpl>()) {
+      high_efficiency_mode_toggle_delegate_(
+          high_efficiency_mode_toggle_delegate
+              ? std::move(high_efficiency_mode_toggle_delegate)
+              : std::make_unique<HighEfficiencyModeToggleDelegateImpl>()) {
   DCHECK(!g_user_performance_tuning_manager);
   g_user_performance_tuning_manager = this;
 
@@ -300,8 +259,6 @@
   // here in the same patch as the UI and enterprise policy are migrated to
   // the enum pref.
 
-  SetDefaultTimeBeforeDiscardFromSwitch(local_state);
-
   pref_change_registrar_.Init(local_state);
 }
 
@@ -309,18 +266,6 @@
   was_started_ = true;
 
   pref_change_registrar_.Add(
-      performance_manager::user_tuning::prefs::
-          kHighEfficiencyModeTimeBeforeDiscardInMinutes,
-      base::BindRepeating(&UserPerformanceTuningManager::
-                              OnHighEfficiencyModeTimeBeforeDiscardChanged,
-                          base::Unretained(this)));
-  // Make sure the initial state of the discard timer pref is passed on to the
-  // policy before it can be enabled, because the policy initially has a dummy
-  // value for time_before_discard_. This prevents tabs' discard timers from
-  // starting with a value different from the pref.
-  OnHighEfficiencyModeTimeBeforeDiscardChanged();
-
-  pref_change_registrar_.Add(
       performance_manager::user_tuning::prefs::kHighEfficiencyModeEnabled,
       base::BindRepeating(
           &UserPerformanceTuningManager::OnHighEfficiencyModePrefChanged,
@@ -329,7 +274,7 @@
   OnHighEfficiencyModePrefChanged();
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(kForceDeviceHasBatterySwitch)) {
+  if (command_line->HasSwitch(kForceDeviceHasBattery)) {
     force_has_battery_ = true;
     has_battery_ = true;
   }
@@ -357,21 +302,13 @@
 void UserPerformanceTuningManager::OnHighEfficiencyModePrefChanged() {
   bool enabled = pref_change_registrar_.prefs()->GetBoolean(
       performance_manager::user_tuning::prefs::kHighEfficiencyModeEnabled);
-  high_efficiency_mode_delegate_->ToggleHighEfficiencyMode(enabled);
+  high_efficiency_mode_toggle_delegate_->ToggleHighEfficiencyMode(enabled);
 
   for (auto& obs : observers_) {
     obs.OnHighEfficiencyModeChanged();
   }
 }
 
-void UserPerformanceTuningManager::
-    OnHighEfficiencyModeTimeBeforeDiscardChanged() {
-  base::TimeDelta time_before_discard = performance_manager::user_tuning::
-      prefs::GetCurrentHighEfficiencyModeTimeBeforeDiscard(
-          pref_change_registrar_.prefs());
-  high_efficiency_mode_delegate_->SetTimeBeforeDiscard(time_before_discard);
-}
-
 void UserPerformanceTuningManager::OnBatterySaverModePrefChanged() {
   battery_saver_mode_disabled_for_session_ = false;
   UpdateBatterySaverModeState();
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 08c862a..fdbe17d 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
@@ -12,7 +12,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/performance_manager/test_support/fake_frame_throttling_delegate.h"
-#include "chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.h"
+#include "chrome/browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.h"
 #include "chrome/browser/performance_manager/test_support/fake_power_monitor_source.h"
 #include "components/performance_manager/public/features.h"
 #include "components/performance_manager/public/user_tuning/prefs.h"
@@ -96,12 +96,9 @@
         std::make_unique<base::test::TestSamplingEventSource>();
     auto test_battery_level_provider =
         std::make_unique<base::test::TestBatteryLevelProvider>();
-    auto fake_high_efficiency_mode_delegate =
-        std::make_unique<FakeHighEfficiencyModeDelegate>();
 
     sampling_source_ = test_sampling_event_source.get();
     battery_level_provider_ = test_battery_level_provider.get();
-    high_efficiency_mode_delegate_ = fake_high_efficiency_mode_delegate.get();
 
     battery_sampler_ = std::make_unique<base::BatteryStateSampler>(
         std::move(test_sampling_event_source),
@@ -110,7 +107,7 @@
     manager_.reset(new UserPerformanceTuningManager(
         &local_state_, nullptr,
         std::make_unique<FakeFrameThrottlingDelegate>(&throttling_enabled_),
-        std::move(fake_high_efficiency_mode_delegate)));
+        std::make_unique<FakeHighEfficiencyModeToggleDelegate>()));
     manager()->Start();
   }
 
@@ -128,7 +125,6 @@
 
   raw_ptr<base::test::TestSamplingEventSource> sampling_source_;
   raw_ptr<base::test::TestBatteryLevelProvider> battery_level_provider_;
-  raw_ptr<FakeHighEfficiencyModeDelegate> high_efficiency_mode_delegate_;
   std::unique_ptr<base::BatteryStateSampler> battery_sampler_;
 
   raw_ptr<FakePowerMonitorSource> power_monitor_source_;
@@ -252,20 +248,6 @@
   EXPECT_FALSE(throttling_enabled());
 }
 
-TEST_F(UserPerformanceTuningManagerTest, SetDefaultTimeBeforeDiscardPref) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      performance_manager::user_tuning::UserPerformanceTuningManager::
-          kTimeBeforeDiscardInMinutesSwitch,
-      "5");
-  StartManager();
-
-  EXPECT_EQ(5, local_state_.GetInteger(
-                   performance_manager::user_tuning::prefs::
-                       kHighEfficiencyModeTimeBeforeDiscardInMinutes));
-  EXPECT_EQ(base::Minutes(5),
-            high_efficiency_mode_delegate_->GetLastTimeBeforeDiscard());
-}
-
 TEST_F(UserPerformanceTuningManagerTest, EnabledOnBatteryPower) {
   StartManager();
   EXPECT_FALSE(manager()->IsBatterySaverActive());
diff --git a/chrome/browser/preloading/chrome_preloading.h b/chrome/browser/preloading/chrome_preloading.h
index f840338..d7d4337 100644
--- a/chrome/browser/preloading/chrome_preloading.h
+++ b/chrome/browser/preloading/chrome_preloading.h
@@ -76,11 +76,17 @@
     "BackButtonHover");
 
 // When a pointerdown (e.g. mousedown or touchstart) event happens on an
-// bookmark bar link to an HTTP(S) origin, we may attempt to preload the link.
+// bookmark bar link to an HTTPS origin, we may attempt to preload the link.
 static constexpr content::PreloadingPredictor kPointerDownOnBookmarkBar(
     107,
     "PointerDownOnBookmarkBar");
 
+// When a mousehover event happens on a bookmark bar link to an HTTPS origin,
+// we may attempt to preload the link.
+static constexpr content::PreloadingPredictor kMouseHoverOnBookmarkBar(
+    108,
+    "MouseHoverOnBookmarkBar");
+
 // TODO(crbug.com/1309934): Integrate more Preloading predictors with
 // Preloading logging APIs.
 }  // namespace chrome_preloading_predictor
diff --git a/chrome/browser/preloading/prerender/prerender_manager.cc b/chrome/browser/preloading/prerender/prerender_manager.cc
index 5df9916..628937df 100644
--- a/chrome/browser/preloading/prerender/prerender_manager.cc
+++ b/chrome/browser/preloading/prerender/prerender_manager.cc
@@ -332,7 +332,9 @@
 }
 
 base::WeakPtr<content::PrerenderHandle>
-PrerenderManager::StartPrerenderBookmark(const GURL& prerendering_url) {
+PrerenderManager::StartPrerenderBookmark(
+    const GURL& prerendering_url,
+    content::PreloadingPredictor predictor) {
   // Helpers to create content::PreloadingAttempt.
   auto* preloading_data =
       content::PreloadingData::GetOrCreateForWebContents(web_contents());
@@ -342,9 +344,9 @@
   // Create new PreloadingAttempt and pass all the values corresponding to
   // this prerendering attempt for Prerender.
   content::PreloadingAttempt* preloading_attempt =
-      preloading_data->AddPreloadingAttempt(
-          chrome_preloading_predictor::kPointerDownOnBookmarkBar,
-          content::PreloadingType::kPrerender, std::move(same_url_matcher));
+      preloading_data->AddPreloadingAttempt(predictor,
+                                            content::PreloadingType::kPrerender,
+                                            std::move(same_url_matcher));
 
   if (bookmark_prerender_handle_) {
     if (bookmark_prerender_handle_->GetInitialPrerenderingUrl() ==
diff --git a/chrome/browser/preloading/prerender/prerender_manager.h b/chrome/browser/preloading/prerender/prerender_manager.h
index 51475e0d..3938422 100644
--- a/chrome/browser/preloading/prerender/prerender_manager.h
+++ b/chrome/browser/preloading/prerender/prerender_manager.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "content/public/browser/preloading.h"
 #include "content/public/browser/prerender_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -81,7 +82,8 @@
   // from the on-going one. If the url given is already on-going, this function
   // will return the weak pointer to the on-going prerender handle.
   base::WeakPtr<content::PrerenderHandle> StartPrerenderBookmark(
-      const GURL& prerendering_url);
+      const GURL& prerendering_url,
+      content::PreloadingPredictor predictor);
 
   // The entry of direct url input prerender.
   // Calling this method will return WeakPtr of the started prerender, and lead
diff --git a/chrome/browser/printing/print_backend_browsertest.cc b/chrome/browser/printing/print_backend_browsertest.cc
index d89d7c2c..35b46540 100644
--- a/chrome/browser/printing/print_backend_browsertest.cc
+++ b/chrome/browser/printing/print_backend_browsertest.cc
@@ -25,6 +25,7 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/printing/print_backend_service_test_impl.h"
+#include "chrome/browser/printing/print_test_utils.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -148,6 +149,9 @@
     // tests.
     auto default_caps = std::make_unique<PrinterSemanticCapsAndDefaults>();
     default_caps->copies_max = kCopiesMax;
+    default_caps->default_paper = kTestPaperLetter;
+    default_caps->papers.push_back(kTestPaperLetter);
+    default_caps->papers.push_back(kTestPaperLegal);
     test_print_backend_->AddValidPrinter(
         kDefaultPrinterName, std::move(default_caps),
         std::make_unique<PrinterBasicInfo>(kDefaultPrinterInfo));
@@ -337,6 +341,14 @@
     CheckForQuit();
   }
 
+#if BUILDFLAG(IS_WIN)
+  void OnDidGetPaperPrintableArea(gfx::Rect& capture_printable_area_um,
+                                  const gfx::Rect& printable_area_um) {
+    capture_printable_area_um = printable_area_um;
+    CheckForQuit();
+  }
+#endif
+
   void CapturePrintSettings(
       mojom::PrintSettingsResultPtr& capture_print_settings,
       mojom::PrintSettingsResultPtr print_settings) {
@@ -548,6 +560,63 @@
   EXPECT_EQ(caps_and_info->get_result_code(), mojom::ResultCode::kAccessDenied);
 }
 
+#if BUILDFLAG(IS_WIN)
+IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, GetPaperPrintableArea) {
+  AddDefaultPrinter();
+
+  mojom::PrinterCapsAndInfoResultPtr caps_and_info;
+
+  // Safe to use base::Unretained(this) since waiting locally on the callback
+  // forces a shorter lifetime than `this`.
+  GetPrintBackendService()->FetchCapabilities(
+      kDefaultPrinterName,
+      base::BindOnce(&PrintBackendBrowserTest::OnDidFetchCapabilities,
+                     base::Unretained(this), std::ref(caps_and_info)));
+  WaitUntilCallbackReceived();
+
+  // TODO(crbug.com/1432720):  Unlike in-browser behavior of fetching
+  // capabilities, out-of-process still provides the printable area for all
+  // paper sizes.  This is known to be slow, and so the behavior will need to
+  // be changed.
+  ASSERT_TRUE(caps_and_info->is_printer_caps_and_info());
+  absl::optional<PrinterSemanticCapsAndDefaults::Paper> non_default_paper;
+  const PrinterSemanticCapsAndDefaults::Paper& default_paper =
+      caps_and_info->get_printer_caps_and_info()->printer_caps.default_paper;
+  const PrinterSemanticCapsAndDefaults::Papers& papers =
+      caps_and_info->get_printer_caps_and_info()->printer_caps.papers;
+  for (const auto& paper : papers) {
+    if (paper != default_paper) {
+      non_default_paper = paper;
+      break;
+    }
+  }
+  ASSERT_TRUE(non_default_paper.has_value());
+  // TODO(crbug.com/1432720):  Update this to check that the printable area
+  // matches the paper size for non-default papers, once the workaround for
+  // the slow query is updated to match in-browser query behavior.
+  EXPECT_NE(non_default_paper->printable_area_um,
+            gfx::Rect(non_default_paper->size_um));
+
+  // Request the printable area for this paper size, which should not match
+  // match the physical size but have real printable area values.
+  gfx::Rect printable_area_um;
+  PrintSettings::RequestedMedia media(
+      /*.size_microns =*/non_default_paper->size_um,
+      /*.vendor_id = */ non_default_paper->vendor_id);
+  GetPrintBackendService()->GetPaperPrintableArea(
+      kDefaultPrinterName, media,
+      base::BindOnce(&PrintBackendBrowserTest::OnDidGetPaperPrintableArea,
+                     base::Unretained(this), std::ref(printable_area_um)));
+  WaitUntilCallbackReceived();
+  ASSERT_TRUE(!printable_area_um.IsEmpty());
+  // TODO(crbug.com/1432720):  Update this to check that the printable area
+  // does not match the paper size for non-default papers from
+  // FetchCapabilities(), once the workaround for the slow query is updated to
+  // match in-browser query behavior.
+  EXPECT_EQ(printable_area_um, non_default_paper->printable_area_um);
+}
+#endif  // BUILDFLAG(IS_WIN)
+
 IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, UseDefaultSettings) {
   AddDefaultPrinter();
   SetPrinterNameForSubsequentContexts(kDefaultPrinterName);
diff --git a/chrome/browser/printing/print_backend_service_manager.cc b/chrome/browser/printing/print_backend_service_manager.cc
index 6e30596..b5a4b52 100644
--- a/chrome/browser/printing/print_backend_service_manager.cc
+++ b/chrome/browser/printing/print_backend_service_manager.cc
@@ -282,6 +282,30 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+#if BUILDFLAG(IS_WIN)
+void PrintBackendServiceManager::GetPaperPrintableArea(
+    const std::string& printer_name,
+    const PrintSettings::RequestedMedia& media,
+    mojom::PrintBackendService::GetPaperPrintableAreaCallback callback) {
+  CallbackContext context;
+  auto& service = GetServiceAndCallbackContextForQuery(printer_name, context);
+
+  SaveCallback(
+      GetRemoteSavedGetPaperPrintableAreaCallbacks(context.is_sandboxed),
+      context.remote_id, context.saved_callback_id, std::move(callback));
+
+  SetCrashKeys(printer_name);
+
+  LogCallToRemote("GetPaperPrintableArea", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
+  service->GetPaperPrintableArea(
+      printer_name, media,
+      base::BindOnce(&PrintBackendServiceManager::OnDidGetPaperPrintableArea,
+                     base::Unretained(this), std::move(context)));
+}
+#endif
+
 PrintBackendServiceManager::ContextId
 PrintBackendServiceManager::EstablishPrintingContext(
     ClientId client_id,
@@ -1107,6 +1131,10 @@
       remote_id,
       mojom::PrinterSemanticCapsAndDefaultsResult::NewResultCode(
           mojom::ResultCode::kFailed));
+#if BUILDFLAG(IS_WIN)
+  RunSavedCallbacks(GetRemoteSavedGetPaperPrintableAreaCallbacks(sandboxed),
+                    remote_id, gfx::Rect());
+#endif
   RunSavedCallbacksStructResult(
       GetRemoteSavedUseDefaultSettingsCallbacks(sandboxed), remote_id,
       mojom::PrintSettingsResult::NewResultCode(mojom::ResultCode::kFailed));
@@ -1162,6 +1190,16 @@
              : unsandboxed_saved_get_printer_semantic_caps_and_defaults_callbacks_;
 }
 
+#if BUILDFLAG(IS_WIN)
+PrintBackendServiceManager::RemoteSavedGetPaperPrintableAreaCallbacks&
+PrintBackendServiceManager::GetRemoteSavedGetPaperPrintableAreaCallbacks(
+    bool sandboxed) {
+  return sandboxed ? sandboxed_saved_get_paper_printable_area_callbacks_
+                   : unsandboxed_saved_get_paper_printable_area_callbacks_;
+}
+
+#endif
+
 PrintBackendServiceManager::RemoteSavedUseDefaultSettingsCallbacks&
 PrintBackendServiceManager::GetRemoteSavedUseDefaultSettingsCallbacks(
     bool sandboxed) {
@@ -1281,7 +1319,7 @@
 
   auto callback_entry = callback_map.find(saved_callback_id);
   DCHECK(callback_entry != callback_map.end());
-  base::OnceCallback<void(X...)> callback = std::move(callback_entry->second);
+  auto callback = std::move(callback_entry->second);
   callback_map.erase(callback_entry);
 
   // Done disconnect wrapper management, propagate the callback.
@@ -1326,6 +1364,17 @@
                       std::move(printer_caps));
 }
 
+#if BUILDFLAG(IS_WIN)
+void PrintBackendServiceManager::OnDidGetPaperPrintableArea(
+    const CallbackContext& context,
+    const gfx::Rect& printable_area_um) {
+  LogCallbackFromRemote("GetPaperPrintableArea", context);
+  ServiceCallbackDone(
+      GetRemoteSavedGetPaperPrintableAreaCallbacks(context.is_sandboxed),
+      context.remote_id, context.saved_callback_id, printable_area_um);
+}
+#endif
+
 void PrintBackendServiceManager::OnDidUseDefaultSettings(
     const CallbackContext& context,
     mojom::PrintSettingsResultPtr settings) {
@@ -1428,7 +1477,7 @@
 void PrintBackendServiceManager::RunSavedCallbacks(
     RemoteSavedCallbacks<T...>& saved_callbacks,
     const RemoteId& remote_id,
-    T... result) {
+    std::remove_reference<T>::type... result) {
   auto found_callbacks_map = saved_callbacks.find(remote_id);
   if (found_callbacks_map == saved_callbacks.end())
     return;  // No callbacks to run.
diff --git a/chrome/browser/printing/print_backend_service_manager.h b/chrome/browser/printing/print_backend_service_manager.h
index c6139281..d812f3b 100644
--- a/chrome/browser/printing/print_backend_service_manager.h
+++ b/chrome/browser/printing/print_backend_service_manager.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <type_traits>
 
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
@@ -139,6 +140,12 @@
       mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback
           callback);
 #endif
+#if BUILDFLAG(IS_WIN)
+  void GetPaperPrintableArea(
+      const std::string& printer_name,
+      const PrintSettings::RequestedMedia& media,
+      mojom::PrintBackendService::GetPaperPrintableAreaCallback callback);
+#endif
   ContextId EstablishPrintingContext(ClientId client_id,
                                      const std::string& printer_name
 #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
@@ -293,6 +300,10 @@
       RemoteSavedStructCallbacks<mojom::DefaultPrinterNameResult>;
   using RemoteSavedGetPrinterSemanticCapsAndDefaultsCallbacks =
       RemoteSavedStructCallbacks<mojom::PrinterSemanticCapsAndDefaultsResult>;
+#if BUILDFLAG(IS_WIN)
+  using RemoteSavedGetPaperPrintableAreaCallbacks =
+      RemoteSavedCallbacks<const gfx::Rect&>;
+#endif
   using RemoteSavedUseDefaultSettingsCallbacks =
       RemoteSavedStructCallbacks<mojom::PrintSettingsResult>;
 #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
@@ -459,6 +470,10 @@
   GetRemoteSavedGetDefaultPrinterNameCallbacks(bool sandboxed);
   RemoteSavedGetPrinterSemanticCapsAndDefaultsCallbacks&
   GetRemoteSavedGetPrinterSemanticCapsAndDefaultsCallbacks(bool sandboxed);
+#if BUILDFLAG(IS_WIN)
+  RemoteSavedGetPaperPrintableAreaCallbacks&
+  GetRemoteSavedGetPaperPrintableAreaCallbacks(bool sandboxed);
+#endif
   RemoteSavedUseDefaultSettingsCallbacks&
   GetRemoteSavedUseDefaultSettingsCallbacks(bool sandboxed);
 #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
@@ -538,6 +553,10 @@
   void OnDidGetPrinterSemanticCapsAndDefaults(
       const CallbackContext& context,
       mojom::PrinterSemanticCapsAndDefaultsResultPtr printer_caps);
+#if BUILDFLAG(IS_WIN)
+  void OnDidGetPaperPrintableArea(const CallbackContext& context,
+                                  const gfx::Rect& printable_area_um);
+#endif
   void OnDidUseDefaultSettings(const CallbackContext& context,
                                mojom::PrintSettingsResultPtr settings);
 #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
@@ -568,7 +587,7 @@
   template <class... T>
   void RunSavedCallbacks(RemoteSavedCallbacks<T...>& saved_callbacks,
                          const RemoteId& remote_id,
-                         T... result);
+                         std::remove_reference<T>::type... result);
 
   // Test support for client ID management.
   static void SetClientsForTesting(
@@ -632,6 +651,12 @@
       sandboxed_saved_get_printer_semantic_caps_and_defaults_callbacks_;
   RemoteSavedGetPrinterSemanticCapsAndDefaultsCallbacks
       unsandboxed_saved_get_printer_semantic_caps_and_defaults_callbacks_;
+#if BUILDFLAG(IS_WIN)
+  RemoteSavedGetPaperPrintableAreaCallbacks
+      sandboxed_saved_get_paper_printable_area_callbacks_;
+  RemoteSavedGetPaperPrintableAreaCallbacks
+      unsandboxed_saved_get_paper_printable_area_callbacks_;
+#endif
   RemoteSavedUseDefaultSettingsCallbacks
       sandboxed_saved_use_default_settings_callbacks_;
   RemoteSavedUseDefaultSettingsCallbacks
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index 9006ac8..8971847 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -203,23 +203,20 @@
   return g_browser_process->print_preview_dialog_controller();
 }
 
-// static
 void PrintPreviewDialogController::PrintPreview(WebContents* initiator) {
 #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   ModuleDatabase::DisableThirdPartyBlocking();
 #endif
 
-  if (initiator->IsCrashed())
+  if (initiator->IsCrashed()) {
     return;
+  }
 
-  PrintPreviewDialogController* dialog_controller = GetInstance();
-  if (!dialog_controller)
-    return;
-  if (!dialog_controller->GetOrCreatePreviewDialog(initiator)) {
-    PrintViewManager* print_view_manager =
-        PrintViewManager::FromWebContents(initiator);
-    if (print_view_manager)
+  if (!GetOrCreatePreviewDialog(initiator)) {
+    auto* print_view_manager = PrintViewManager::FromWebContents(initiator);
+    if (print_view_manager) {
       print_view_manager->PrintPreviewDone();
+    }
   }
 }
 
diff --git a/chrome/browser/printing/print_preview_dialog_controller.h b/chrome/browser/printing/print_preview_dialog_controller.h
index df85b92..9166f72 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.h
+++ b/chrome/browser/printing/print_preview_dialog_controller.h
@@ -37,9 +37,6 @@
 
   static PrintPreviewDialogController* GetInstance();
 
-  // Initiates print preview for `initiator`.
-  static void PrintPreview(content::WebContents* initiator);
-
   // Returns true if `url` is a Print Preview dialog URL (has `chrome://print`
   // origin).
   static bool IsPrintPreviewURL(const GURL& url);
@@ -48,6 +45,9 @@
   // `chrome-untrusted://print` origin).
   static bool IsPrintPreviewContentURL(const GURL& url);
 
+  // Initiates print preview for `initiator`.
+  void PrintPreview(content::WebContents* initiator);
+
   // Returns the preview dialog for `contents`.
   // Returns `contents` if `contents` is a preview dialog.
   // Returns NULL if no preview dialog exists for `contents`.
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc
index 801fda0..4405b76a 100644
--- a/chrome/browser/printing/print_view_manager.cc
+++ b/chrome/browser/printing/print_view_manager.cc
@@ -10,7 +10,7 @@
 
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
-#include "base/lazy_instance.h"
+#include "base/no_destructor.h"
 #include "base/observer_list.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -44,17 +44,14 @@
 PrintManager* g_receiver_for_testing = nullptr;
 
 // Keeps track of pending scripted print preview closures.
-// No locking, only access on the UI thread.
-base::LazyInstance<std::map<content::RenderProcessHost*, base::OnceClosure>>::
-    Leaky g_scripted_print_preview_closure_map = LAZY_INSTANCE_INITIALIZER;
+using ScriptedPrintPreviewClosureMap =
+    std::map<content::RenderProcessHost*, base::OnceClosure>;
 
-content::WebContents* GetPrintPreviewDialog(
-    content::WebContents* web_contents) {
-  PrintPreviewDialogController* dialog_controller =
-      PrintPreviewDialogController::GetInstance();
-  if (!dialog_controller)
-    return nullptr;
-  return dialog_controller->GetPrintPreviewForContents(web_contents);
+ScriptedPrintPreviewClosureMap& GetScriptedPrintPreviewClosureMap() {
+  // No locking, only access on the UI thread.
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  static base::NoDestructor<ScriptedPrintPreviewClosureMap> closure_map;
+  return *closure_map;
 }
 
 }  // namespace
@@ -202,7 +199,7 @@
   is_switching_to_system_dialog_ = false;
 
   if (print_preview_state_ == SCRIPTED_PREVIEW) {
-    auto& map = g_scripted_print_preview_closure_map.Get();
+    auto& map = GetScriptedPrintPreviewClosureMap();
     auto it = map.find(scripted_print_preview_rph_);
     CHECK(it != map.end());
     std::move(it->second).Run();
@@ -354,7 +351,7 @@
     return;
   }
 
-  auto& map = g_scripted_print_preview_closure_map.Get();
+  auto& map = GetScriptedPrintPreviewClosureMap();
   if (base::Contains(map, rph)) {
     // Renderer already handling window.print(). Abort this attempt to prevent
     // the renderer from having multiple nested loops. If multiple nested loops
@@ -471,12 +468,18 @@
   if (!render_frame_host || !render_frame_host->IsRenderFrameLive())
     return;
 
+  auto* dialog_controller = PrintPreviewDialogController::GetInstance();
+  if (!dialog_controller) {
+    PrintPreviewDone();
+    return;
+  }
+
   if (params->webnode_only)
     PrintPreviewForWebNode(render_frame_host);
 
-  PrintPreviewDialogController::PrintPreview(web_contents());
-  PrintPreviewUI::SetInitialParams(GetPrintPreviewDialog(web_contents()),
-                                   *params);
+  dialog_controller->PrintPreview(web_contents());
+  PrintPreviewUI::SetInitialParams(
+      dialog_controller->GetPrintPreviewForContents(web_contents()), *params);
   PrintPreviewAllowedForTesting();
 }
 
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index fb09cc0..61696a3d 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -2973,7 +2973,11 @@
         ExecSearchWebInCompanionSidePanel(selection_navigation_url_);
         break;
       }
+      // Searching in this side panel is dependent on the companion feature
+      // being disabled.
       if (side_search::IsSearchWebInSidePanelSupported(
+              chrome::FindBrowserWithWebContents(embedder_web_contents_)) &&
+          !companion::IsSearchInCompanionSidePanelSupported(
               chrome::FindBrowserWithWebContents(embedder_web_contents_))) {
         ExecSearchWebInSidePanel(selection_navigation_url_);
         break;
diff --git a/chrome/browser/resources/discards/discards_tab.html b/chrome/browser/resources/discards/discards_tab.html
index 2506369..a5a18b2f 100644
--- a/chrome/browser/resources/discards/discards_tab.html
+++ b/chrome/browser/resources/discards/discards_tab.html
@@ -166,7 +166,7 @@
               <div class="header-cell-container">
                 <div>
                   <div>Utility</div>
-                  <div>Rank<div>
+                  <div>Rank</div>
                 </div>
               </div>
             </th>
@@ -214,7 +214,7 @@
                   <div>Count</div>
                 </div>
               </div>
-            </div></th>
+            </th>
             <th data-sort-key="isAutoDiscardable" on-click="onSortClick">
               <div class="header-cell-container">
                 <div>
diff --git a/chrome/browser/resources/nearby_share/BUILD.gn b/chrome/browser/resources/nearby_share/BUILD.gn
index 80b4b138..aadec04 100644
--- a/chrome/browser/resources/nearby_share/BUILD.gn
+++ b/chrome/browser/resources/nearby_share/BUILD.gn
@@ -23,6 +23,7 @@
   ts_deps = [
     "./shared:build_ts",
     "//third_party/polymer/v3_0:library",
+    "//ui/webui/resources/cr_components/color_change_listener:build_ts",
     "//ui/webui/resources/cr_elements:build_ts",
     "//ui/webui/resources/js:build_ts",
     "//ui/webui/resources/mojo:build_ts",
diff --git a/chrome/browser/resources/nearby_share/app.html b/chrome/browser/resources/nearby_share/app.html
index c66f26b..d5d5140 100644
--- a/chrome/browser/resources/nearby_share/app.html
+++ b/chrome/browser/resources/nearby_share/app.html
@@ -1,3 +1,6 @@
+<if expr="chromeos_ash">
+<style include="cros-color-overrides"></style>
+</if>
 <cr-view-manager id="viewManager">
   <nearby-confirmation-page id="[[Page.CONFIRMATION]]" slot="view"
       confirmation-manager="[[confirmationManager_]]"
diff --git a/chrome/browser/resources/nearby_share/app.ts b/chrome/browser/resources/nearby_share/app.ts
index 1aa0acd..34d50e5 100644
--- a/chrome/browser/resources/nearby_share/app.ts
+++ b/chrome/browser/resources/nearby_share/app.ts
@@ -12,6 +12,7 @@
 import {ConfirmationManagerInterface, PayloadPreview, ShareTarget, TransferUpdateListenerPendingReceiver} from '/shared/nearby_share.mojom-webui.js';
 import {NearbyShareSettingsMixin} from '/shared/nearby_share_settings_mixin.js';
 import {CloseReason} from '/shared/types.js';
+import {startColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js';
 import {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -92,6 +93,18 @@
         type: Object,
         value: null,
       },
+
+      /**
+       * Return true if the Jelly feature flag is enabled.
+       */
+      isJellyEnabled: {
+        type: Boolean,
+        readOnly: true,
+        value() {
+          return loadTimeData.valueExists('isJellyEnabled') &&
+              loadTimeData.getBoolean('isJellyEnabled');
+        },
+      },
     };
   }
 
@@ -99,6 +112,7 @@
   private transferUpdateListener_: TransferUpdateListenerPendingReceiver|null;
   private selectedShareTarget_: ShareTarget|null;
   private payloadPreview_: PayloadPreview|null;
+  isJellyEnabled: boolean;
 
   override ready() {
     super.ready();
@@ -108,6 +122,15 @@
     this.addEventListener(
         'close', e => this.onClose_(e as CustomEvent<{reason: CloseReason}>));
     this.addEventListener('onboarding-complete', this.onOnboardingComplete_);
+
+    if (this.isJellyEnabled) {
+      const link = document.createElement('link');
+      link.rel = 'stylesheet';
+      link.href = 'chrome://theme/colors.css?sets=legacy,sys';
+      document.head.appendChild(link);
+      document.body.classList.add('jelly-enabled');
+      startColorChangeUpdater();
+    }
   }
 
   /**
diff --git a/chrome/browser/resources/new_tab_page/modules/module_descriptors.ts b/chrome/browser/resources/new_tab_page/modules/module_descriptors.ts
index 43d4eed..d32d310 100644
--- a/chrome/browser/resources/new_tab_page/modules/module_descriptors.ts
+++ b/chrome/browser/resources/new_tab_page/modules/module_descriptors.ts
@@ -37,7 +37,6 @@
     modulesRedesignedEnabled ? driveV2Descriptor : driveDescriptor);
 descriptors.push(photosDescriptor);
 descriptors.push(modulesRedesignedEnabled ? feedV2Descriptor : feedDescriptor);
-descriptors.push(historyClustersDescriptor);
 descriptors.push(
     modulesRedesignedEnabled ? historyClustersV2Descriptor :
                                historyClustersDescriptor);
diff --git a/chrome/browser/resources/password_manager/BUILD.gn b/chrome/browser/resources/password_manager/BUILD.gn
index ecf6394..e88c3df 100644
--- a/chrome/browser/resources/password_manager/BUILD.gn
+++ b/chrome/browser/resources/password_manager/BUILD.gn
@@ -53,7 +53,6 @@
     "passwords_exporter.ts",
     "passwords_importer.ts",
     "passwords_section.ts",
-    "prefs/extension_controlled_icon.ts",
     "prefs/pref_toggle_button.ts",
     "settings_section.ts",
     "side_bar.ts",
@@ -68,7 +67,6 @@
     "password_manager.ts",
     "passkeys_browser_proxy.ts",
     "password_manager_proxy.ts",
-    "prefs/extension_control_browser_proxy.ts",
     "focus_config.ts",
     "router.ts",
     "searchable_label.ts",
@@ -99,15 +97,25 @@
   ]
 
   ts_deps = [
+    "//chrome/browser/resources/settings_shared:build_ts",
     "//third_party/polymer/v3_0:library",
     "//ui/webui/resources/cr_components/settings_prefs:build_ts",
     "//ui/webui/resources/cr_elements:build_ts",
     "//ui/webui/resources/js:build_ts",
   ]
 
+  ts_path_mappings =
+      [ "/shared/settings/*|" + rebase_path(
+            "$root_gen_dir/chrome/browser/resources/settings_shared/tsc/*",
+            target_gen_dir) ]
+
   optimize = optimize_webui
   if (optimize) {
     optimize_webui_host = "password-manager"
     optimize_webui_in_files = [ "password_manager.js" ]
+    optimize_webui_external_paths =
+        [ "/shared/settings|" + rebase_path(
+              "$root_gen_dir/chrome/browser/resources/settings_shared/tsc",
+              root_build_dir) ]
   }
 }
diff --git a/chrome/browser/resources/password_manager/password_manager.ts b/chrome/browser/resources/password_manager/password_manager.ts
index c89d04c..d0bf8ff 100644
--- a/chrome/browser/resources/password_manager/password_manager.ts
+++ b/chrome/browser/resources/password_manager/password_manager.ts
@@ -26,8 +26,6 @@
 export {PasswordsExporterElement} from './passwords_exporter.js';
 export {PasswordsImporterElement} from './passwords_importer.js';
 export {PasswordsSectionElement} from './passwords_section.js';
-export {ExtensionControlBrowserProxy, ExtensionControlBrowserProxyImpl} from './prefs/extension_control_browser_proxy.js';
-export {ExtensionControlledIconElement} from './prefs/extension_controlled_icon.js';
 export {PrefToggleButtonElement} from './prefs/pref_toggle_button.js';
 export {PromoCard, PromoCardsProxy, PromoCardsProxyImpl} from './promo_cards/promo_cards_browser_proxy.js';
 export {CheckupSubpage, Page, Route, RouteObserverMixin, RouteObserverMixinInterface, Router, UrlParam} from './router.js';
diff --git a/chrome/browser/resources/password_manager/passwords_importer.ts b/chrome/browser/resources/password_manager/passwords_importer.ts
index 4787b33..85178c5 100644
--- a/chrome/browser/resources/password_manager/passwords_importer.ts
+++ b/chrome/browser/resources/password_manager/passwords_importer.ts
@@ -255,6 +255,8 @@
               '#deleteFileOption');
       assert(deleteFileOption);
       deleteFile = deleteFileOption.checked;
+      chrome.metricsPrivate.recordBoolean(
+          'PasswordManager.Import.FileDeletionSelected', deleteFile);
     }
     await this.passwordManager_.resetImporter(deleteFile);
   }
diff --git a/chrome/browser/resources/password_manager/prefs/extension_control_browser_proxy.ts b/chrome/browser/resources/password_manager/prefs/extension_control_browser_proxy.ts
deleted file mode 100644
index 5d7908f..0000000
--- a/chrome/browser/resources/password_manager/prefs/extension_control_browser_proxy.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2023 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 class that enables substituting custom extension control
- * logic in test cases. Also see the equivalent
- * extension_control_browser_proxy.ts in settings.
- */
-
-export interface ExtensionControlBrowserProxy {
-  disableExtension(extensionId: string): void;
-}
-
-export class ExtensionControlBrowserProxyImpl implements
-    ExtensionControlBrowserProxy {
-  disableExtension(extensionId: string) {
-    chrome.send('disableExtension', [extensionId]);
-  }
-
-  static getInstance(): ExtensionControlBrowserProxy {
-    return instance || (instance = new ExtensionControlBrowserProxyImpl());
-  }
-
-  static setInstance(obj: ExtensionControlBrowserProxy) {
-    instance = obj;
-  }
-}
-
-let instance: ExtensionControlBrowserProxy|null = null;
diff --git a/chrome/browser/resources/password_manager/prefs/extension_controlled_icon.html b/chrome/browser/resources/password_manager/prefs/extension_controlled_icon.html
deleted file mode 100644
index 278fffa..0000000
--- a/chrome/browser/resources/password_manager/prefs/extension_controlled_icon.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<style include="cr-shared-style">
-  :host {
-    align-items: center;
-    display: flex;
-    padding-inline-start: 36px;
-  }
-
-  img {
-    /* Dimensions of the image are set in the URL. */
-    margin-inline-end: 16px;
-  }
-
-  iron-icon[icon='cr:open-in-new'] {
-    fill: var(--text-color);
-    flex-shrink: 0;  /* Prevent distortion of icons in cramped UI. */
-    height: var(--cr-icon-size);
-    margin-inline-end: -10px;
-    margin-inline-start: 6px;
-    width: var(--cr-icon-size);
-  }
-
-  #disable {
-    margin-inline-start: 8px;
-  }
-
-  span {
-    flex: 1;
-    margin-inline-end: 8px;
-  }
-</style>
-<img role="presentation" src="chrome://extension-icon/[[extensionId]]/20/1">
-<span>[[getLabel_(extensionName)]]</span>
-<cr-button id="manage" on-click="onManageClick_">
-  $i18n{manage}
-  <iron-icon icon="cr:open-in-new"></iron-icon>
-</cr-button>
-<template is="dom-if" if="[[extensionCanBeDisabled]]" restamp>
-  <cr-button id="disable" on-click="onDisableClick_">$i18n{disable}</cr-button>
-</template>
diff --git a/chrome/browser/resources/password_manager/prefs/extension_controlled_icon.ts b/chrome/browser/resources/password_manager/prefs/extension_controlled_icon.ts
deleted file mode 100644
index 7357b48..0000000
--- a/chrome/browser/resources/password_manager/prefs/extension_controlled_icon.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview
- * `extension-controlled-icon` is an icon that indicates that a given field is
- * managed by an extension and therefore disabled for the user. It mimics the
- * `extension_controlled_indicator` class that shows a similar indicator in the
- * settings code.
- */
-import '//resources/cr_elements/cr_button/cr_button.js';
-import '//resources/cr_elements/cr_icons.css.js';
-import '//resources/cr_elements/cr_shared_vars.css.js';
-
-import {assert} from '//resources/js/assert_ts.js';
-import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
-import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
-
-import {ExtensionControlBrowserProxyImpl} from './extension_control_browser_proxy.js';
-import {getTemplate} from './extension_controlled_icon.html.js';
-
-const ExtensionControlledIconElementBase = I18nMixin(PolymerElement);
-
-export class ExtensionControlledIconElement extends
-    ExtensionControlledIconElementBase {
-  static get is() {
-    return 'extension-controlled-icon';
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {
-      /**
-         Whether the extension can be disabled; false when, e.g., the extension
-         is set by policy
-       */
-      extensionCanBeDisabled: Boolean,
-      /** The ID of the extension controlling the associated field */
-      extensionId: String,
-      /** The name of the extension controlling the associated field */
-      extensionName: String,
-    };
-  }
-
-  extensionCanBeDisabled: boolean;
-  extensionId: string;
-  extensionName: string;
-
-  private getLabel_(): string {
-    return this.i18n('controlledByExtension', this.extensionName);
-  }
-
-  private onManageClick_(e: Event) {
-    e.stopPropagation();
-    const manageUrl = 'chrome://extensions/?id=' + this.extensionId;
-    OpenWindowProxyImpl.getInstance().openUrl(manageUrl);
-  }
-
-  private onDisableClick_(e: Event) {
-    e.stopPropagation();
-    assert(this.extensionCanBeDisabled);
-    ExtensionControlBrowserProxyImpl.getInstance().disableExtension(
-        this.extensionId);
-  }
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'extension-controlled-icon': ExtensionControlledIconElement;
-  }
-}
-
-customElements.define(
-    ExtensionControlledIconElement.is, ExtensionControlledIconElement);
diff --git a/chrome/browser/resources/password_manager/prefs/pref_toggle_button.html b/chrome/browser/resources/password_manager/prefs/pref_toggle_button.html
index 3706efb..5d2d4206 100644
--- a/chrome/browser/resources/password_manager/prefs/pref_toggle_button.html
+++ b/chrome/browser/resources/password_manager/prefs/pref_toggle_button.html
@@ -19,6 +19,10 @@
     margin-inline-end: var(--control-label-spacing);
     padding: var(--cr-section-vertical-padding) 0;
   }
+
+  cr-policy-pref-indicator {
+    margin-inline-end: var(--cr-controlled-by-spacing);
+  }
 </style>
 <div id="outerRow" noSubLabel$="[[!subLabel]]" role="switch">
   <div class="flex" id="labelWrapper">
@@ -29,16 +33,13 @@
       </span>
     </div>
   </div>
+  <template is="dom-if" if="[[hasPrefPolicyIndicator_(pref.*)]]">
+    <cr-policy-pref-indicator pref="[[pref]]" icon-aria-label="[[label]]">
+    </cr-policy-pref-indicator>
+  </template>
   <cr-toggle id="control" checked="{{checked}}"
-      disabled="[[disabled]]"
+      disabled="[[controlDisabled_(pref.*, disabled)]]"
       on-change="onToggleClick_"
       aria-label="[[getAriaLabel_(label, subLabel)]]">
   </cr-toggle>
-  <template is="dom-if" if="[[pref.extensionId]]">
-    <extension-controlled-icon id="extensionIcon"
-        extension-id="[[pref.extensionId]]"
-        extension-name="[[pref.controlledByName]]"
-        extension-can-be-disabled="[[pref.extensionCanBeDisabled]]">
-    </extension-controlled-icon>
-  </template>
 </div>
diff --git a/chrome/browser/resources/password_manager/prefs/pref_toggle_button.ts b/chrome/browser/resources/password_manager/prefs/pref_toggle_button.ts
index 17a2f6fa..c6b1bcc 100644
--- a/chrome/browser/resources/password_manager/prefs/pref_toggle_button.ts
+++ b/chrome/browser/resources/password_manager/prefs/pref_toggle_button.ts
@@ -10,7 +10,7 @@
 import '//resources/cr_elements/cr_shared_vars.css.js';
 import '//resources/cr_elements/cr_toggle/cr_toggle.js';
 import '//resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
-import './extension_controlled_icon.js';
+import '//resources/cr_elements/policy/cr_policy_pref_indicator.js';
 
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -66,6 +66,8 @@
         value: false,
       },
 
+      noExtensionIndicator: Boolean,
+
       pref: Object,
     };
   }
@@ -82,6 +84,7 @@
   checked: boolean;
   disabled: boolean;
   changeRequiresValidation: boolean;
+  noExtensionIndicator: boolean;
   pref: chrome.settingsPrivate.PrefObject;
 
   override ready() {
@@ -144,6 +147,30 @@
     }
     return [this.label, this.subLabel].join('. ');
   }
+
+  private isPrefEnforced_(): boolean {
+    return !!this.pref &&
+        this.pref.enforcement === chrome.settingsPrivate.Enforcement.ENFORCED;
+  }
+
+  private hasPrefPolicyIndicator_(): boolean {
+    if (!this.pref) {
+      return false;
+    }
+    if (this.noExtensionIndicator &&
+        this.pref.controlledBy ===
+            chrome.settingsPrivate.ControlledBy.EXTENSION) {
+      return false;
+    }
+    return this.isPrefEnforced_() ||
+        chrome.settingsPrivate.Enforcement.RECOMMENDED ===
+        this.pref.enforcement;
+  }
+
+  private controlDisabled_(): boolean {
+    return this.disabled || this.isPrefEnforced_() ||
+        !!(this.pref && this.pref.userControlDisabled);
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/password_manager/settings_section.html b/chrome/browser/resources/password_manager/settings_section.html
index 09ae1f1..7e59497 100644
--- a/chrome/browser/resources/password_manager/settings_section.html
+++ b/chrome/browser/resources/password_manager/settings_section.html
@@ -51,10 +51,23 @@
 </style>
 <h3 class="page-title">$i18n{settings}</h3>
 <div class="card">
-  <pref-toggle-button id="passwordToggle"
+  <pref-toggle-button id="passwordToggle" no-extension-indicator
       label="$i18n{savePasswordsLabel}"
       pref="{{prefs.credentials_enable_service}}">
   </pref-toggle-button>
+  <template is="dom-if"
+        if="[[prefs.credentials_enable_service.extensionId]]">
+    <div class="cr-row continuation">
+      <extension-controlled-indicator
+          id="passwordsExtensionIndicator"
+          extension-id="[[prefs.credentials_enable_service.extensionId]]"
+          extension-name="[[
+              prefs.credentials_enable_service.controlledByName]]"
+          extension-can-be-disabled="[[
+              prefs.credentials_enable_service.extensionCanBeDisabled]]">
+      </extension-controlled-indicator>
+    </div>
+  </template>
   <pref-toggle-button id="autosigninToggle" class="hr"
       label="$i18n{autosigninLabel}"
       sub-label="$i18n{autosigninDescription}"
diff --git a/chrome/browser/resources/password_manager/settings_section.ts b/chrome/browser/resources/password_manager/settings_section.ts
index 28b614e..c435f0d 100644
--- a/chrome/browser/resources/password_manager/settings_section.ts
+++ b/chrome/browser/resources/password_manager/settings_section.ts
@@ -6,6 +6,7 @@
 import './shared_style.css.js';
 import './prefs/pref_toggle_button.js';
 import './user_utils_mixin.js';
+import '/shared/settings/controls/extension_controlled_indicator.js';
 
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 import {CrLinkRowElement} from 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
diff --git a/chrome/browser/resources/settings/OWNERS b/chrome/browser/resources/settings/OWNERS
index b95e7884e4..2a6d22f 100644
--- a/chrome/browser/resources/settings/OWNERS
+++ b/chrome/browser/resources/settings/OWNERS
@@ -1,15 +1,4 @@
 dpapad@chromium.org
-khorimoto@chromium.org
-zentaro@chromium.org
-
-# Chrome OS Settings
-per-file *os_settings*=file://chrome/browser/resources/settings/chromeos/OWNERS
-
-# Reviewers for icon updates related to device subpages (ex. Audio, per-device
-# keyboard, etc).
-per-file icons.html=ashleydp@google.com
-per-file icons.html=gavinwill@chromium.org
-per-file icons.html=jimmyxgong@chromium.org
 
 # Happiness Tracking Surveys (HaTS)
 per-file hats_browser_proxy.ts=sauski@google.com
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts b/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts
index 2e3072ec..cd08772d 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts
+++ b/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts
@@ -539,6 +539,10 @@
       const deleteFile = !this.shouldHideDeleteFileOption_() &&
           this.$.deleteFileOption.checked;
       await this.passwordManager_.resetImporter(deleteFile);
+      if (!this.shouldHideDeleteFileOption_) {
+        chrome.metricsPrivate.recordBoolean(
+            'PasswordManager.Import.FileDeletionSelected', deleteFile);
+      }
     }
     this.$.dialog.close();
   }
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index 21f55a9a..c39df3f 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -43,8 +43,6 @@
       "chrome://resources/cr_components/app_management/app_management.mojom-webui.js",
       "chrome://resources/ash/common/bluetooth/cros_bluetooth_config.js",
       "chrome://resources/ash/common/cellular_setup/mojo_interface_provider.js",
-      "chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js",
-      "chrome://resources/ash/common/connectivity/passpoint.mojom-webui.js",
       "chrome://resources/ash/common/hotspot/cros_hotspot_config.js",
       "chrome://resources/ash/common/hotspot/cros_hotspot_config.mojom-webui.js",
       "chrome://resources/ash/common/network/mojo_interface_provider.js",
diff --git a/chrome/browser/resources/settings/chromeos/OWNERS b/chrome/browser/resources/settings/chromeos/OWNERS
index df0d785..647bbe8 100644
--- a/chrome/browser/resources/settings/chromeos/OWNERS
+++ b/chrome/browser/resources/settings/chromeos/OWNERS
@@ -13,16 +13,16 @@
 cowmoo@google.com
 
 # Subdir OWNERS can approve global changes related to their subdir.
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/crostini_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/device_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/guest_os/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/internet_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/keyboard_shortcut_banner/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/multidevice_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/nearby_share_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_apps_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_bluetooth_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_files_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_languages_page/OWNERS
-per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_printing_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/crostini_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/device_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/guest_os/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/internet_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/keyboard_shortcut_banner/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/multidevice_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/nearby_share_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/os_apps_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/os_bluetooth_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/os_files_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/os_languages_page/OWNERS
+per-file lazy_load.ts,os_settings.gni,os_settings.ts,os_settings_icons.html=file://chrome/browser/resources/settings/chromeos/os_printing_page/OWNERS
diff --git a/chrome/browser/resources/settings/chromeos/device_page/fake_input_device_data.ts b/chrome/browser/resources/settings/chromeos/device_page/fake_input_device_data.ts
index 3fafe042..ede6ecd 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/fake_input_device_data.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/fake_input_device_data.ts
@@ -56,6 +56,7 @@
     metaKey: MetaKey.kLauncher,
     modifierKeys: [
       ModifierKey.kAlt,
+      ModifierKey.kAssistant,
       ModifierKey.kBackspace,
       ModifierKey.kCapsLock,
       ModifierKey.kControl,
diff --git a/chrome/browser/resources/settings/chromeos/device_page/keyboard.html b/chrome/browser/resources/settings/chromeos/device_page/keyboard.html
index 0978612f2e..3effdd4 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/keyboard.html
+++ b/chrome/browser/resources/settings/chromeos/device_page/keyboard.html
@@ -156,7 +156,6 @@
     on-click="onShowKeyboardShortcutViewerClick_"
     label="$i18n{showKeyboardShortcutViewer}"
     external
-    button-aria-description="$i18n{opensInNewTab}"
     deep-link-focus-id$="[[Setting.kKeyboardShortcuts]]"></cr-link-row>
 <cr-link-row id="showLanguagesInput"
     class="hr" on-click="onShowInputSettingsClick_"
diff --git a/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.html b/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.html
index eacfc05d..aff8e05 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.html
+++ b/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.html
@@ -52,12 +52,12 @@
 <div class="settings-box">
   <div>
     <div id="keyLabelContainer" class="start key-container">
-      <template is="dom-if" if="[[!metaKeyIcon]]" restamp>
+      <template is="dom-if" if="[[!keyIcon]]" restamp>
         <div id="keyLabel"
             aria-hidden="true">[[keyLabel]]</div>
       </template>
-      <template is="dom-if" if="[[metaKeyIcon]]" restamp>
-        <iron-icon icon="[[metaKeyIcon]]"></iron-icon>
+      <template is="dom-if" if="[[keyIcon]]" restamp>
+        <iron-icon icon="[[keyIcon]]"></iron-icon>
       </template>
     </div>
   </div>
diff --git a/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.ts b/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.ts
index 8c2d889..0b7dee46 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/keyboard_remap_modifier_key_row.ts
@@ -33,7 +33,7 @@
   MODIFIER_REMAPPED = 'modifier-remapped',
 }
 
-type MetaKeyIcon = 'cr:search'|'os-settings:launcher'|'';
+type KeyIcon = 'cr:search'|'os-settings:launcher'|'os-settings:assistant'|'';
 const KeyboardRemapModifierKeyRowElementBase = I18nMixin(PolymerElement);
 
 export class KeyboardRemapModifierKeyRowElement extends
@@ -69,7 +69,6 @@
 
       metaKey: {
         type: Number,
-        observer: 'onMetaKeyChanged',
       },
 
       key: {
@@ -84,9 +83,10 @@
         type: Object,
       },
 
-      metaKeyIcon: {
+      keyIcon: {
         type: String,
         value: '',
+        computed: 'getKeyIcon(key, metaKey)',
       },
     };
   }
@@ -94,13 +94,19 @@
   protected keyLabel: string;
   private metaKeyLabel: string;
   private keyMapTargets: DropdownMenuOptionList;
-  private metaKeyIcon: MetaKeyIcon;
+  private keyIcon: KeyIcon;
   keyState: KeyState;
   pref: chrome.settingsPrivate.PrefObject;
   metaKey: MetaKey;
   key: ModifierKey;
   defaultRemappings: {[key: number]: ModifierKey};
 
+  override ready() {
+    super.ready();
+
+    this.setUpKeyMapTargets();
+  }
+
   static get template(): HTMLTemplateElement {
     return getTemplate();
   }
@@ -115,30 +121,21 @@
         KeyState.MODIFIER_REMAPPED;
   }
 
-  private onMetaKeyChanged(): void {
-    if (this.key === ModifierKey.kMeta) {
-      this.metaKeyIcon = this.getMetaKeyIcon();
-    }
-    this.setUpKeyMapTargets();
-  }
-
   /**
-   * Populate the metaKey label required in the keyMapTargets menu dropdown.
+   * Populate the metaKey label according to metaKey.
    */
   private getMetaKeyLabel(): string {
     switch (this.metaKey) {
       case MetaKey.kCommand: {
-        return this.i18n('keyboardKeyCommand');
+        return this.i18n('perDeviceKeyboardKeyCommand');
       }
       case MetaKey.kExternalMeta: {
-        return this.i18n('keyboardKeyExternalMeta');
+        return this.i18n('perDeviceKeyboardKeyExternalMeta');
       }
-      case MetaKey.kLauncher: {
-        return this.i18n('keyboardKeyLauncher');
-      }
-      case MetaKey.kSearch: {
-        return this.i18n('keyboardKeySearch');
-      }
+      // Launcher and Search key will display icon instead of text.
+      case MetaKey.kLauncher:
+      case MetaKey.kSearch:
+        return '';
     }
   }
 
@@ -148,22 +145,22 @@
   private getKeyLabel(): string {
     switch (this.key) {
       case ModifierKey.kAlt: {
-        return this.i18n('keyboardKeyAlt');
+        return this.i18n('perDeviceKeyboardKeyAlt');
       }
       case ModifierKey.kAssistant: {
-        return this.i18n('keyboardKeyAssistant');
+        return this.i18n('perDeviceKeyboardKeyAssistant');
       }
       case ModifierKey.kBackspace: {
-        return this.i18n('keyboardKeyBackspace');
+        return this.i18n('perDeviceKeyboardKeyBackspace');
       }
       case ModifierKey.kCapsLock: {
-        return this.i18n('keyboardKeyCapsLock');
+        return this.i18n('perDeviceKeyboardKeyCapsLock');
       }
       case ModifierKey.kControl: {
-        return this.i18n('keyboardKeyCtrl');
+        return this.i18n('perDeviceKeyboardKeyCtrl');
       }
       case ModifierKey.kEscape: {
-        return this.i18n('keyboardKeyEscape');
+        return this.i18n('perDeviceKeyboardKeyEscape');
       }
       case ModifierKey.kMeta: {
         return this.getMetaKeyLabel();
@@ -178,46 +175,51 @@
     this.keyMapTargets = [
       {
         value: ModifierKey.kMeta,
-        name: this.i18n('keyboardKeySearch'),
+        name: this.i18n('perDeviceKeyboardKeySearch'),
       },
       {
         value: ModifierKey.kControl,
-        name: this.i18n('keyboardKeyCtrl'),
+        name: this.i18n('perDeviceKeyboardKeyCtrl'),
       },
       {
         value: ModifierKey.kAlt,
-        name: this.i18n('keyboardKeyAlt'),
+        name: this.i18n('perDeviceKeyboardKeyAlt'),
       },
       {
         value: ModifierKey.kCapsLock,
-        name: this.i18n('keyboardKeyCapsLock'),
+        name: this.i18n('perDeviceKeyboardKeyCapsLock'),
       },
       {
         value: ModifierKey.kEscape,
-        name: this.i18n('keyboardKeyEscape'),
+        name: this.i18n('perDeviceKeyboardKeyEscape'),
       },
       {
         value: ModifierKey.kBackspace,
-        name: this.i18n('keyboardKeyBackspace'),
+        name: this.i18n('perDeviceKeyboardKeyBackspace'),
       },
       {
         value: ModifierKey.kAssistant,
-        name: this.i18n('keyboardKeyAssistant'),
+        name: this.i18n('perDeviceKeyboardKeyAssistant'),
       },
       {
         value: ModifierKey.kVoid,
-        name: this.i18n('keyboardKeyDisabled'),
+        name: this.i18n('perDeviceKeyboardKeyDisabled'),
       },
     ];
   }
 
-  private getMetaKeyIcon(): MetaKeyIcon {
-    if (this.metaKey === MetaKey.kSearch) {
-      return 'cr:search';
+  private getKeyIcon(): KeyIcon {
+    if (this.key === ModifierKey.kMeta) {
+      if (this.metaKey === MetaKey.kSearch) {
+        return 'cr:search';
+      }
+      if (this.metaKey === MetaKey.kLauncher) {
+        return 'os-settings:launcher';
+      }
+    } else if (this.key === ModifierKey.kAssistant) {
+      return 'os-settings:assistant';
     }
-    if (this.metaKey === MetaKey.kLauncher) {
-      return 'os-settings:launcher';
-    }
+
     return '';
   }
 }
diff --git a/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard.html b/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard.html
index 2105141..12f97b9 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard.html
+++ b/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard.html
@@ -58,7 +58,6 @@
     on-click="onShowKeyboardShortcutViewerTap"
     label="$i18n{showKeyboardShortcutViewer}"
     external
-    button-aria-description="$i18n{opensInNewTab}"
     deep-link-focus-id$="[[Setting.kKeyboardShortcuts]]">
 </cr-link-row>
 <cr-link-row id="showLanguagesInput"
diff --git a/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard_remap_keys.html b/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard_remap_keys.html
index 16be18e..eadc923 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard_remap_keys.html
+++ b/chrome/browser/resources/settings/chromeos/device_page/per_device_keyboard_remap_keys.html
@@ -23,35 +23,35 @@
       default-remappings="[[defaultRemappings]]"
       key="[[modifierKey.kMeta]]" id="metaKey"
       meta-key="[[keyboard.metaKey]]"
-      aria-label="$i18n{keyboardKeySearch}"
+      aria-label="$i18n{perDeviceKeyboardKeySearch}"
       pref="{{fakeMetaPref}}">
   </keyboard-remap-modifier-key-row>
   <keyboard-remap-modifier-key-row
       default-remappings="[[defaultRemappings]]"
       key="[[modifierKey.kControl]]" id="ctrlKey"
       meta-key="[[keyboard.metaKey]]"
-      aria-label="$i18n{keyboardKeyCtrl}"
+      aria-label="$i18n{perDeviceKeyboardKeyCtrl}"
       pref="{{fakeCtrlPref}}">
   </keyboard-remap-modifier-key-row>
   <keyboard-remap-modifier-key-row
       default-remappings="[[defaultRemappings]]"
       key="[[modifierKey.kAlt]]" id="altKey"
       meta-key="[[keyboard.metaKey]]"
-      aria-label="$i18n{keyboardKeyAlt}"
+      aria-label="$i18n{perDeviceKeyboardKeyAlt}"
       pref="{{fakeAltPref}}">
   </keyboard-remap-modifier-key-row>
   <keyboard-remap-modifier-key-row
       default-remappings="[[defaultRemappings]]"
       key="[[modifierKey.kEscape]]" id="escapeKey"
       meta-key="[[keyboard.metaKey]]"
-      aria-label="$i18n{keyboardKeyEscape}"
+      aria-label="$i18n{perDeviceKeyboardKeyEscape}"
       pref="{{fakeEscPref}}">
   </keyboard-remap-modifier-key-row>
   <keyboard-remap-modifier-key-row
       default-remappings="[[defaultRemappings]]"
       key="[[modifierKey.kBackspace]]" id="backspaceKey"
       meta-key="[[keyboard.metaKey]]"
-      aria-label="$i18n{keyboardKeyBackspace}"
+      aria-label="$i18n{perDeviceKeyboardKeyBackspace}"
       pref="{{fakeBackspacePref}}">
   </keyboard-remap-modifier-key-row>
   <template is="dom-if" if="[[hasAssistantKey]]" restamp>
@@ -59,7 +59,7 @@
       default-remappings="[[defaultRemappings]]"
       key="[[modifierKey.kAssistant]]" id="assistantKey"
       meta-key="[[keyboard.metaKey]]"
-      aria-label="$i18n{keyboardKeyAssistant}"
+      aria-label="$i18n{perDeviceKeyboardKeyAssistant}"
       pref="{{fakeAssistantPref}}">
   </keyboard-remap-modifier-key-row>
   </template>
@@ -68,7 +68,7 @@
       default-remappings="[[defaultRemappings]]"
       key="[[modifierKey.kCapsLock]]" id="capsLockKey"
       meta-key="[[keyboard.metaKey]]"
-      aria-label="$i18n{keyboardKeyCapsLock}"
+      aria-label="$i18n{perDeviceKeyboardKeyCapsLock}"
       pref="{{fakeCapsLockPref}}">
   </keyboard-remap-modifier-key-row>
   </template>
diff --git a/chrome/browser/resources/settings/chromeos/device_page/storage.html b/chrome/browser/resources/settings/chromeos/device_page/storage.html
index 0f2aacf..3735605 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/storage.html
+++ b/chrome/browser/resources/settings/chromeos/device_page/storage.html
@@ -173,20 +173,17 @@
 <cr-link-row id="myFilesSize" class="hr" on-click="onMyFilesClick_"
     label="$i18n{storageItemMyFiles}"
     sub-label="$i18n{storageSizeComputing}"
-    external
-    button-aria-description="$i18n{opensInNewTab}">
+    external>
 </cr-link-row>
 <cr-link-row id="browsingDataSize" class="hr" on-click="onBrowsingDataClick_"
     label="$i18n{storageItemBrowsingData}"
     sub-label="$i18n{storageSizeComputing}"
-    external
-    button-aria-description="$i18n{opensInNewTab}">
+    external>
 </cr-link-row>
 <cr-link-row id="appsSize" class="hr" on-click="onAppsClick_"
     label="$i18n{storageItemApps}"
     sub-label="$i18n{storageSizeComputing}"
-    external
-    button-aria-description="$i18n{opensInNewTab}">
+    external>
 </cr-link-row>
 <template is="dom-if" if="[[showDriveOfflineStorage_]]">
   <cr-link-row id="driveOfflineSize" class="hr" on-click="onDriveOfflineClick_"
diff --git a/chrome/browser/resources/settings/chromeos/device_page/stylus.html b/chrome/browser/resources/settings/chromeos/device_page/stylus.html
index 58a5991..e2159ced 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/stylus.html
+++ b/chrome/browser/resources/settings/chromeos/device_page/stylus.html
@@ -73,8 +73,7 @@
     hidden$="[[!prefs.arc.enabled.value]]"
     label="$i18n{stylusFindMoreAppsPrimary}"
     sub-label="$i18n{stylusFindMoreAppsSecondary}"
-    external
-    button-aria-description="$i18n{opensInNewTab}">
+    external>
 </cr-link-row>
 
 <template is="dom-if" if="[[supportsLockScreen_(selectedApp_)]]">
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_subpage.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_subpage.html
index 5fbf89b..1bda1df 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_subpage.html
@@ -325,23 +325,6 @@
     </template>
   </template>
 
-  <!-- Passpoint provider link -->
-  <template is="dom-if" if="[[shouldShowPasspointProviderRow_(
-        managedProperties_)]]">
-    <div id="passpointProviderRow" class="settings-box two-line"
-        on-click="onPasspointRowClicked_">
-      <div class="flex settings-box-text">
-        <div>$i18n{passpointProviderLabel}</div>
-        <div class="secondary">
-          [[getPasspointSubscriptionName_(passpointSubscription_)]]
-        </div>
-      </div>
-      <cr-icon-button class="subpage-arrow"
-          aria-roledescription="$i18n{subpageArrowRoleDescription}">
-      </cr-icon-button>
-    </div>
-  </template>
-
   <template is="dom-if" if="[[hasAdvancedSection_(managedProperties_,
                               propertiesReceived_, showMeteredToggle_,
                               deviceState_)]]">
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_subpage.ts b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_subpage.ts
index 61f0c4bd..ae2db334 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_subpage.ts
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_subpage.ts
@@ -36,8 +36,6 @@
 import './settings_traffic_counters.js';
 import './tether_connection_dialog.js';
 
-import {MojoConnectivityProvider} from 'chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js';
-import {PasspointServiceInterface, PasspointSubscription} from 'chrome://resources/ash/common/connectivity/passpoint.mojom-webui.js';
 import {isActiveSim, processDeviceState} from 'chrome://resources/ash/common/network/cellular_utils.js';
 import {CrPolicyNetworkBehaviorMojo, CrPolicyNetworkBehaviorMojoInterface} from 'chrome://resources/ash/common/network/cr_policy_network_behavior_mojo.js';
 import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
@@ -309,19 +307,6 @@
         },
       },
 
-      isPasspointSettingsEnabled_: {
-        type: Boolean,
-        value() {
-          return loadTimeData.valueExists('isPasspointSettingsEnabled') &&
-              loadTimeData.getBoolean('isPasspointSettingsEnabled');
-        },
-      },
-
-      passpointSubscription_: {
-        type: Object,
-        notify: true,
-      },
-
       advancedExpanded_: Boolean,
 
       networkExpanded_: Boolean,
@@ -396,7 +381,6 @@
   private ipAddress_: string;
   private isApnRevampEnabled_: boolean;
   private isPasspointEnabled_: boolean;
-  private isPasspointSettingsEnabled_: boolean;
   private isSecondaryUser_: boolean;
   private isTrafficCountersEnabled_: boolean;
   private isWifiSyncEnabled_: boolean;
@@ -406,8 +390,6 @@
   private networkExpanded_: boolean;
   private osSyncBrowserProxy_: OsSyncBrowserProxy;
   private outOfRange_: boolean;
-  private passpointService_: PasspointServiceInterface;
-  private passpointSubscription_: PasspointSubscription|null;
   private pendingSimLockDeepLink_: boolean;
   private preferNetwork_: boolean;
   private primaryUserEmail_: string;
@@ -454,8 +436,6 @@
 
     this.networkConfig_ =
         MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote();
-    this.passpointService_ =
-        MojoConnectivityProvider.getInstance().getPasspointService();
 
     this.osSyncBrowserProxy_ = OsSyncBrowserProxyImpl.getInstance();
   }
@@ -966,11 +946,6 @@
       const response =
           await this.networkConfig_.getManagedProperties(this.guid);
       this.getPropertiesCallback_(response.result);
-      if (this.isPasspointWifi_(this.managedProperties_)) {
-        const response = await this.passpointService_.getPasspointSubscription(
-            this.managedProperties_!.typeProperties.wifi!.passpointId!);
-        this.passpointSubscription_ = response.result;
-      }
     }
   }
 
@@ -2160,30 +2135,6 @@
         MatchType.kNoMatch;
   }
 
-  private shouldShowPasspointProviderRow_(managedProperties: ManagedProperties|
-                                          undefined) {
-    return this.isPasspointSettingsEnabled_ &&
-        this.isPasspointWifi_(managedProperties);
-  }
-
-  private getPasspointSubscriptionName_(subscription: PasspointSubscription|
-                                        null): string {
-    if (!subscription) {
-      return '';
-    }
-    if (subscription.friendlyName && subscription.friendlyName !== '') {
-      return subscription.friendlyName;
-    }
-    return subscription.domains[0];
-  }
-
-  private onPasspointRowClicked_(): void {
-    const showPasspointEvent = new CustomEvent(
-        'show-passpoint-detail',
-        {bubbles: true, composed: true, detail: this.passpointSubscription_});
-    this.dispatchEvent(showPasspointEvent);
-  }
-
   private onPasspointRemovalDialogCancel_(): void {
     this.getPasspointRemovalDialog_().close();
   }
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_known_networks_subpage.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_known_networks_subpage.html
index dd2c2aab..f5cd216 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_known_networks_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_known_networks_subpage.html
@@ -69,29 +69,6 @@
   </template>
 </div>
 
-<template is="dom-if"
-    if="[[shouldShowPasspointSection_(isPasspointSettingsEnabled_,
-        passpointSubscriptionsList_)]]">
-  <div class="settings-box settings-box-text">
-    <div class="secondary">$i18n{passpointSectionLabel}</div>
-  </div>
-  <div id="passpointSubscriptionList" class="list-frame vertical-list">
-    <template is="dom-repeat" items="[[passpointSubscriptionsList_]]">
-      <div class="list-item">
-        <cr-link-row embedded label="[[getSubscriptionDisplayName_(item)]]"
-            on-click="onSubscriptionListItemTap_"
-            role-description="$i18n{subpageArrowRoleDescription}">
-        </cr-link-row>
-        <div class="separator"></div>
-        <cr-icon-button class="icon-more-vert" tabindex$="[[tabindex]]"
-            on-click="onSubscriptionMenuButtonTap_"
-            title="[[getSubscriptionMenuButtonTitle_(item)]]">
-        </cr-icon-button>
-      </div>
-    </template>
-  </div>
-</template>
-
 <cr-action-menu id="dotsMenu" role-description="$i18n{menu}">
   <button class="dropdown-item" hidden="[[!showAddPreferred_]]"
       on-click="onAddPreferredClick_">
@@ -107,8 +84,3 @@
   </button>
 </cr-action-menu>
 
-<cr-action-menu id="subscriptionDotsMenu" role-description="$i18n{menu}">
-  <button class="dropdown-item" on-click="onSubscriptionForgetTap_">
-    $i18n{knownNetworksMenuForget}
-  </button>
-</cr-action-menu>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_known_networks_subpage.ts b/chrome/browser/resources/settings/chromeos/internet_page/internet_known_networks_subpage.ts
index 153ad462..fec64d5 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_known_networks_subpage.ts
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_known_networks_subpage.ts
@@ -14,15 +14,12 @@
 import 'chrome://resources/cr_elements/icons.html.js';
 import './internet_shared.css.js';
 
-import {MojoConnectivityProvider} from 'chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js';
-import {PasspointServiceInterface, PasspointSubscription} from 'chrome://resources/ash/common/connectivity/passpoint.mojom-webui.js';
 import {CrPolicyNetworkBehaviorMojo, CrPolicyNetworkBehaviorMojoInterface} from 'chrome://resources/ash/common/network/cr_policy_network_behavior_mojo.js';
 import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
 import {NetworkListenerBehavior, NetworkListenerBehaviorInterface} from 'chrome://resources/ash/common/network/network_listener_behavior.js';
 import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
 import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
 import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js';
-import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {ConfigProperties, CrosNetworkConfigRemote, FilterType, NetworkStateProperties, NO_LIMIT} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
 import {NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
 import {DomRepeatEvent, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -37,12 +34,10 @@
 import {Route} from '../router.js';
 
 import {getTemplate} from './internet_known_networks_subpage.html.js';
-import {PasspointListenerMixin, PasspointListenerMixinInterface} from './passpoint_listener_mixin.js';
 
 interface SettingsInternetKnownNetworksPageElement {
   $: {
     dotsMenu: CrActionMenuElement,
-    subscriptionDotsMenu: CrActionMenuElement,
   };
 }
 
@@ -52,12 +47,10 @@
           NetworkListenerBehavior,
           CrPolicyNetworkBehaviorMojo,
         ],
-        PasspointListenerMixin(
-            DeepLinkingMixin(RouteObserverMixin(I18nMixin(PolymerElement))))) as
+        DeepLinkingMixin(RouteObserverMixin(I18nMixin(PolymerElement)))) as
     Constructor<PolymerElement&I18nMixinInterface&RouteObserverMixinInterface&
                 DeepLinkingMixinInterface&NetworkListenerBehaviorInterface&
-                CrPolicyNetworkBehaviorMojoInterface&
-                PasspointListenerMixinInterface>;
+                CrPolicyNetworkBehaviorMojoInterface>;
 
 class SettingsInternetKnownNetworksPageElement extends
     SettingsInternetKnownNetworksPageElementBase {
@@ -89,25 +82,6 @@
         },
       },
 
-      isPasspointSettingsEnabled_: {
-        type: Boolean,
-        value() {
-          return loadTimeData.valueExists('isPasspointSettingsEnabled') &&
-              loadTimeData.getBoolean('isPasspointSettingsEnabled');
-        },
-      },
-
-      /**
-       * List of all the passpoint subscriptions available.
-       */
-      passpointSubscriptionsList_: {
-        type: Array,
-        notify: true,
-        value() {
-          return [];
-        },
-      },
-
       showAddPreferred_: Boolean,
 
       showRemovePreferred_: Boolean,
@@ -145,11 +119,8 @@
   private enableForget_: boolean;
   private networkConfig_: CrosNetworkConfigRemote;
   private networkStateList_: OncMojo.NetworkStateProperties[];
-  private passpointService_: PasspointServiceInterface;
-  private passpointSubscriptionsList_: PasspointSubscription[];
   private pendingSettingId_: Setting|null;
   private selectedGuid_: string;
-  private selectedSubscriptionId_: string;
   private showAddPreferred_: boolean;
   private showRemovePreferred_: boolean;
 
@@ -157,13 +128,9 @@
     super();
 
     this.selectedGuid_ = '';
-    this.selectedSubscriptionId_ = '';
 
     this.networkConfig_ =
         MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote();
-
-    this.passpointService_ =
-        MojoConnectivityProvider.getInstance().getPasspointService();
   }
 
   /**
@@ -187,7 +154,6 @@
   /** CrosNetworkConfigObserver impl */
   override onNetworkStateListChanged(): void {
     this.refreshNetworks_();
-    this.refreshSubscriptions_();
   }
 
   /** CrosNetworkConfigObserver impl */
@@ -206,7 +172,6 @@
 
   private networkTypeChanged_(): void {
     this.refreshNetworks_();
-    this.refreshSubscriptions_();
   }
 
   /**
@@ -236,15 +201,6 @@
     }
   }
 
-  private async refreshSubscriptions_(): Promise<void> {
-    if (this.networkType !== NetworkType.kWiFi) {
-      this.passpointSubscriptionsList_ = [];
-      return;
-    }
-    const response = await this.passpointService_.listPasspointSubscriptions();
-    this.passpointSubscriptionsList_ = response.result;
-  }
-
   private networkIsPreferred_(networkState: OncMojo.NetworkStateProperties):
       boolean {
     // Currently we treat NetworkStateProperties.Priority as a boolean.
@@ -271,21 +227,6 @@
     return OncMojo.getNetworkStateDisplayName(networkState);
   }
 
-  private shouldShowPasspointSection_(
-      isPasspointSettingsEnabled: boolean,
-      subscriptionsList: PasspointSubscription[]): boolean {
-    return this.networkType === NetworkType.kWiFi &&
-        isPasspointSettingsEnabled && subscriptionsList.length > 0;
-  }
-
-  private getSubscriptionDisplayName_(subscription: PasspointSubscription):
-      string {
-    if (subscription.friendlyName && subscription.friendlyName !== '') {
-      return subscription.friendlyName;
-    }
-    return subscription.domains[0];
-  }
-
   private getEnterpriseIconAriaLabel_(
       networkState: OncMojo.NetworkStateProperties): string {
     return this.i18n(
@@ -385,59 +326,12 @@
     event.stopPropagation();
   }
 
-  private onSubscriptionListItemTap_(
-      event: DomRepeatEvent<PasspointSubscription>): void {
-    const showPasspointEvent = new CustomEvent(
-        'show-passpoint-detail',
-        {bubbles: true, composed: true, detail: event.model.item});
-    this.dispatchEvent(showPasspointEvent);
-    event.stopPropagation();
-  }
-
   /**
    * Make sure events in embedded components do not propagate to onDetailsClick_.
    */
   private doNothing_(event: Event): void {
     event.stopPropagation();
   }
-
-  private onSubscriptionMenuButtonTap_(
-      event: DomRepeatEvent<PasspointSubscription>): void {
-    const button = event.target as HTMLButtonElement;
-    this.selectedSubscriptionId_ = event.model.item.id;
-    this.$.subscriptionDotsMenu.showAt(button);
-    event.stopPropagation();
-  }
-
-  private getSubscriptionMenuButtonTitle_(subscription: PasspointSubscription):
-      string {
-    return this.i18n(
-        'knownNetworksMenuButtonTitle',
-        this.getSubscriptionDisplayName_(subscription));
-  }
-
-  private async onSubscriptionForgetTap_(): Promise<void> {
-    this.$.subscriptionDotsMenu.close();
-    this.selectedSubscriptionId_ = '';
-    const response = await this.passpointService_.deletePasspointSubscription(
-        this.selectedSubscriptionId_);
-    if (!response.success) {
-      console.warn(
-          'Forget subscription failed for: ' + this.selectedSubscriptionId_);
-    }
-  }
-
-  override async onPasspointSubscriptionAdded(subscription:
-                                                  PasspointSubscription) {
-    this.push('passpointSubscriptionsList_', subscription);
-  }
-
-  override onPasspointSubscriptionRemoved(subscription: PasspointSubscription) {
-    const list = this.passpointSubscriptionsList_.filter((sub) => {
-      return sub.id !== subscription.id;
-    });
-    this.passpointSubscriptionsList_ = list;
-  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html
index 2d156ac..2a1c9aa 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html
@@ -182,14 +182,6 @@
     </os-settings-subpage>
   </template>
 
-  <template is="dom-if" route-path="/passpointDetail" restamp>
-    <os-settings-subpage
-        page-title="[[getPasspointSubscriptionName_(passpointSubscription_)]]">
-      <settings-passpoint-subpage>
-      </settings-passpoint-subpage>
-    </os-settings-subpage>
-  </template>
-
 </os-settings-animated-pages>
 
 <template is="dom-if" if="[[showInternetConfig_]]" restamp>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.ts b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.ts
index 2d9774b..31cec52 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.ts
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.ts
@@ -32,7 +32,6 @@
 
 import {CellularSetupPageName} from 'chrome://resources/ash/common/cellular_setup/cellular_types.js';
 import {getNumESimProfiles} from 'chrome://resources/ash/common/cellular_setup/esim_manager_utils.js';
-import {PasspointSubscription} from 'chrome://resources/ash/common/connectivity/passpoint.mojom-webui.js';
 import {HotspotInfo} from 'chrome://resources/ash/common/hotspot/cros_hotspot_config.mojom-webui.js';
 import {hasActiveCellularNetwork, isConnectedToNonCellularNetwork} from 'chrome://resources/ash/common/network/cellular_utils.js';
 import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
@@ -82,7 +81,6 @@
         CustomEvent<{networkState: NetworkStateProperties}>;
     'show-known-networks': CustomEvent<NetworkType>;
     'show-networks': CustomEvent<NetworkType>;
-    'show-passpoint-detail': CustomEvent<PasspointSubscription>;
   }
 }
 
@@ -313,14 +311,6 @@
       isCreateCustomApnButtonDisabled_: {
         type: Boolean,
       },
-
-      /**
-       * Passpoint subscription set by show-passpoint-detail.
-       */
-      passpointSubscription_: {
-        type: Object,
-        notify: true,
-      },
     };
   }
 
@@ -343,7 +333,6 @@
   private isHotspotFeatureEnabled_: boolean;
   private knownNetworksType_: NetworkType;
   private networkConfig_: CrosNetworkConfigRemote;
-  private passpointSubscription_: PasspointSubscription|undefined;
   private pendingShowCellularSetupDialogAttemptPageName_: CellularSetupPageName|
       null;
   private pendingShowSimLockDialog_: boolean;
@@ -405,9 +394,6 @@
     this.addEventListener('show-hotspot-config-dialog', () => {
       this.onShowHotspotConfigDialog_();
     });
-    this.addEventListener('show-passpoint-detail', (event) => {
-      this.onShowPasspointDetails_(event);
-    });
     this.addEventListener('show-error-toast', (event) => {
       this.onShowErrorToast_(event);
     });
@@ -953,25 +939,6 @@
         this.shadowRoot!.querySelector<ApnSubpageElement>('#apnSubpage'));
     apnSubpage.openApnDetailDialogInCreateMode();
   }
-
-  private onShowPasspointDetails_(event: CustomEvent<PasspointSubscription>):
-      void {
-    this.passpointSubscription_ = event.detail;
-    const params = new URLSearchParams();
-    params.append('id', this.passpointSubscription_.id);
-    Router.getInstance().navigateTo(routes.PASSPOINT_DETAIL, params);
-  }
-
-  private getPasspointSubscriptionName_(subscription: PasspointSubscription|
-                                        undefined): string {
-    if (!subscription) {
-      return '';
-    }
-    if (subscription.friendlyName && subscription.friendlyName !== '') {
-      return subscription.friendlyName;
-    }
-    return subscription.domains[0];
-  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/passpoint_listener_mixin.ts b/chrome/browser/resources/settings/chromeos/internet_page/passpoint_listener_mixin.ts
deleted file mode 100644
index a775ac7..0000000
--- a/chrome/browser/resources/settings/chromeos/internet_page/passpoint_listener_mixin.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Mixin to be used by Polymer elements that want to listen for
- * Passpoint subscription events.
- */
-
-import {MojoConnectivityProvider} from 'chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js';
-import {PasspointEventsListenerReceiver, PasspointSubscription} from 'chrome://resources/ash/common/connectivity/passpoint.mojom-webui.js';
-import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-type Constructor<T> = new (...args: any[]) => T;
-
-export const PasspointListenerMixin = dedupingMixin(
-    <T extends Constructor<PolymerElement>>(superClass: T): T&
-    Constructor<PasspointListenerMixinInterface> => {
-      class PasspointListenerMixin extends superClass implements
-          PasspointListenerMixinInterface {
-        private listener_: PasspointEventsListenerReceiver|null;
-
-        constructor(...args: any[]) {
-          super(...args);
-
-          this.listener_ = null;
-        }
-
-        override connectedCallback() {
-          super.connectedCallback();
-
-          this.listener_ = new PasspointEventsListenerReceiver(this);
-          MojoConnectivityProvider.getInstance()
-              .getPasspointService()
-              .registerPasspointListener(
-                  this.listener_.$.bindNewPipeAndPassRemote());
-        }
-
-        override disconnectedCallback() {
-          super.disconnectedCallback();
-
-          if (this.listener_) {
-            this.listener_.$.close();
-          }
-        }
-
-        onPasspointSubscriptionAdded(_: PasspointSubscription): void {}
-        onPasspointSubscriptionRemoved(_: PasspointSubscription): void {}
-      }
-      return PasspointListenerMixin;
-    });
-
-export interface PasspointListenerMixinInterface {
-  onPasspointSubscriptionAdded(subscription: PasspointSubscription): void;
-  onPasspointSubscriptionRemoved(subscription: PasspointSubscription): void;
-}
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/passpoint_subpage.html b/chrome/browser/resources/settings/chromeos/internet_page/passpoint_subpage.html
deleted file mode 100644
index b45671107..0000000
--- a/chrome/browser/resources/settings/chromeos/internet_page/passpoint_subpage.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<style include="settings-shared">
-</style>
-<div>
-  <!-- TODO(b/266151248) add Passpoint details content. -->
-</div>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/passpoint_subpage.ts b/chrome/browser/resources/settings/chromeos/internet_page/passpoint_subpage.ts
deleted file mode 100644
index f74f0b86..0000000
--- a/chrome/browser/resources/settings/chromeos/internet_page/passpoint_subpage.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Polymer element for displaying the details of a Passpoint
- * subscription.
- */
-
-import '../../settings_shared.css.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 {getTemplate} from './passpoint_subpage.html.js';
-
-const SettingsPasspointSubpageElementBase = I18nMixin(PolymerElement);
-
-class SettingsPasspointSubpageElement extends
-    SettingsPasspointSubpageElementBase {
-  static get is() {
-    return 'settings-passpoint-subpage' as const;
-  }
-
-  static get template() {
-    return getTemplate();
-  }
-
-  static get properties() {
-    return {};
-  }
-
-  constructor() {
-    super();
-  }
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    [SettingsPasspointSubpageElement.is]: SettingsPasspointSubpageElement;
-  }
-}
-
-customElements.define(
-    SettingsPasspointSubpageElement.is, SettingsPasspointSubpageElement);
diff --git a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_page.ts b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_page.ts
index 3fe099c..a1f9a1d 100644
--- a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_page.ts
+++ b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_page.ts
@@ -28,7 +28,8 @@
 const SettingsKerberosPageElementBase =
     WebUiListenerMixin(I18nMixin(PolymerElement));
 
-class SettingsKerberosPageElement extends SettingsKerberosPageElementBase {
+export class SettingsKerberosPageElement extends
+    SettingsKerberosPageElementBase {
   static get is() {
     return 'settings-kerberos-page';
   }
diff --git a/chrome/browser/resources/settings/chromeos/lazy_load.ts b/chrome/browser/resources/settings/chromeos/lazy_load.ts
index 694046ad..e1a662de 100644
--- a/chrome/browser/resources/settings/chromeos/lazy_load.ts
+++ b/chrome/browser/resources/settings/chromeos/lazy_load.ts
@@ -24,7 +24,6 @@
 import './internet_page/internet_detail_subpage.js';
 import './internet_page/internet_known_networks_subpage.js';
 import './internet_page/internet_subpage.js';
-import './internet_page/passpoint_subpage.js';
 import './os_a11y_page/manage_a11y_subpage.js';
 import './os_a11y_page/text_to_speech_page.js';
 import './os_a11y_page/display_and_magnification_page.js';
diff --git a/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_subpage.html b/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_subpage.html
index e3e393a..9dfe311b 100644
--- a/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_subpage.html
@@ -165,7 +165,6 @@
       label="$i18n{nearbyShareManageContactsRowTitle}"
       sub-label="[[getManageContactsSubLabel_(manageContactsUrl_)]]"
       external
-      button-aria-description="$i18n{opensInNewTab}"
       deep-link-focus-id$="[[Setting.kNearbyShareContacts]]">
   </cr-link-row>
   <div class="settings-box two-line" id="dataUsageRow">
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/display_and_magnification_page.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/display_and_magnification_page.html
index 39ef79f..352d97f1 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/display_and_magnification_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/display_and_magnification_page.html
@@ -211,7 +211,6 @@
       label="$i18n{appearanceSettingsTitle}" on-click="onAppearanceClick_"
       sub-label="$i18n{appearanceSettingsDescription}"
       external
-      button-aria-description="$i18n{opensInNewTab}"
       embedded>
   </cr-link-row>
 </template>
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_subpage.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_subpage.html
index c333b9c..8043a3e 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_subpage.html
@@ -66,8 +66,7 @@
       <cr-link-row id="chromeVoxSubpageButton"
           class="settings-box" on-click="onChromeVoxSettingsClick_"
           label="$i18n{chromeVoxOptionsLabel}"
-          external
-          button-aria-description="$i18n{opensInNewTab}">
+          external>
       </cr-link-row>
     </template>
   </div>
@@ -75,8 +74,7 @@
     <cr-link-row id="chromeVoxTutorialButton"
         class="settings-box" on-click="onChromeVoxTutorialClick_"
         label="$i18n{chromeVoxTutorialLabel}"
-        external
-        button-aria-description="$i18n{opensInNewTab}">
+        external>
     </cr-link-row>
   </div>
 </iron-collapse>
@@ -103,8 +101,7 @@
       <cr-link-row id="selectToSpeakSubpageButton"
           class="settings-box" on-click="onSelectToSpeakSettingsClick_"
           label="$i18n{selectToSpeakOptionsLabel}"
-          external
-          button-aria-description="$i18n{opensInNewTab}">
+          external>
       </cr-link-row>
     </template>
   </div>
@@ -209,7 +206,6 @@
       label="$i18n{appearanceSettingsTitle}" on-click="onAppearanceClick_"
       sub-label="$i18n{appearanceSettingsDescription}"
       external
-      button-aria-description="$i18n{opensInNewTab}"
       embedded>
   </cr-link-row>
 </template>
@@ -441,7 +437,6 @@
       id="additionalFeaturesLink" class="hr"
       label="$i18n{additionalFeaturesTitle}"
       on-click="onAdditionalFeaturesClick_"
-      external
-      button-aria-description="$i18n{opensInNewTab}">
+      external>
   </cr-link-row>
 </template>
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html
index 29d00a2e..f0d5bce 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html
@@ -60,8 +60,7 @@
           id="additionalFeaturesLink" class="hr"
           label="$i18n{additionalFeaturesTitle}"
           on-click="onAdditionalFeaturesClick_"
-          external
-          button-aria-description="$i18n{opensInNewTab}">
+          external>
       </cr-link-row>
     </template>
   </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/text_to_speech_page.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/text_to_speech_page.html
index dc9ce26..397e88e 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/text_to_speech_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/text_to_speech_page.html
@@ -39,8 +39,7 @@
       <cr-link-row id="chromeVoxSubpageButton"
           class="settings-box" on-click="onChromeVoxSettingsClick_"
           label="$i18n{chromeVoxOptionsLabel}"
-          external
-          button-aria-description="$i18n{opensInNewTab}">
+          external>
       </cr-link-row>
     </template>
   </div>
@@ -48,8 +47,7 @@
     <cr-link-row id="chromeVoxTutorialButton"
         class="settings-box" on-click="onChromeVoxTutorialClick_"
         label="$i18n{chromeVoxTutorialLabel}"
-        external
-        button-aria-description="$i18n{opensInNewTab}">
+        external>
     </cr-link-row>
   </div>
 </iron-collapse>
@@ -77,8 +75,7 @@
       <cr-link-row id="selectToSpeakSubpageButton"
           class="settings-box" on-click="onSelectToSpeakSettingsClick_"
           label="$i18n{selectToSpeakOptionsLabel}"
-          external
-          button-aria-description="$i18n{opensInNewTab}">
+          external>
       </cr-link-row>
     </template>
   </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
index 4d8476e..f787e57e 100644
--- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
@@ -177,7 +177,6 @@
             on-click="onReleaseNotesClick_"
             label="$i18n{aboutShowReleaseNotes}"
             external
-            button-aria-description="$i18n{opensInNewTab}"
             deep-link-focus-id$="[[Setting.kSeeWhatsNew]]">
         </cr-link-row>
       </template>
@@ -187,14 +186,12 @@
             label="$i18n{aboutShowReleaseNotes}"
             title="$i18n{aboutReleaseNotesOffline}"
             external
-            button-aria-description="$i18n{opensInNewTab}"
             deep-link-focus-id$="[[Setting.kSeeWhatsNew]]">
         </cr-link-row>
       </template>
       <cr-link-row class="hr" id="help" on-click="onHelpClick_"
           label="$i18n{aboutGetHelpUsingChromeOs}"
           external
-          button-aria-description="$i18n{opensInNewTab}"
           deep-link-focus-id$="[[Setting.kGetHelpWithChromeOs]]">
       </cr-link-row>
 <if expr="_google_chrome">
@@ -203,7 +200,6 @@
           hidden="[[!prefs.feedback_allowed.value]]"
           label="[[getReportIssueLabel_()]]"
           external
-          button-aria-description="$i18n{opensInNewTab}"
           deep-link-focus-id$="[[Setting.kReportAnIssue]]">
       </cr-link-row>
 </if>
@@ -211,14 +207,12 @@
           on-click="onDiagnosticsClick_"
           label="$i18n{aboutDiagnostics}"
           external
-          button-aria-description="$i18n{opensInNewTab}"
           deep-link-focus-id$="[[Setting.kDiagnostics]]">
       </cr-link-row>
       <cr-link-row class="hr" id="firmwareUpdates"
           on-click="onFirmwareUpdatesClick_"
           label="$i18n{aboutFirmwareUpdates}"
           external
-          button-aria-description="$i18n{opensInNewTab}"
           using-slotted-label
           deep-link-focus-id$="[[Setting.kFirmwareUpdates]]">
         <iron-icon id="firmwareUpdateBadge"
@@ -240,8 +234,7 @@
       <cr-link-row class="hr" on-click="onManagementPageClick_"
           start-icon="cr:domain" label="$i18n{managementPage}"
           hidden$="[[!isManaged_]]"
-          external
-          button-aria-description="$i18n{opensInNewTab}">
+          external>
       </cr-link-row>
     </div>
     <template is="dom-if" route-path="/help/details">
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/android_apps_subpage.html b/chrome/browser/resources/settings/chromeos/os_apps_page/android_apps_subpage.html
index 253589a7..02534072 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/android_apps_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/android_apps_subpage.html
@@ -4,7 +4,6 @@
   <cr-link-row id="manageApps" label="$i18n{androidAppsManageApps}"
       on-click="onManageAndroidAppsClick_"
       external
-      button-aria-description="$i18n{opensInNewTab}"
       deep-link-focus-id$="[[Setting.kManageAndroidPreferences]]">
   </cr-link-row>
 </template>
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/os_apps_page.html b/chrome/browser/resources/settings/chromeos/os_apps_page/os_apps_page.html
index b0d82d18..dd15a497 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/os_apps_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/os_apps_page.html
@@ -62,7 +62,6 @@
         <cr-link-row id="manageApps" label="$i18n{androidAppsManageApps}"
             on-click="onManageAndroidAppsClick_"
             external
-            button-aria-description="$i18n{opensInNewTab}"
             deep-link-focus-id$="[[Setting.kManageAndroidPreferences]]">
         </cr-link-row>
       </template>
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html
index c44bbedc..a7d835b 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html
@@ -131,8 +131,7 @@
         <cr-link-row id="manageGoogleAccountLanguage"
             label="$i18n{manageGoogleAccountLanguageLabel}"
             on-click="openManageGoogleAccountLanguage_"
-            external
-            button-aria-description="$i18n{opensInNewTab}">
+            external>
         </cr-link-row>
       </div>
     </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_subpage.html b/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_subpage.html
index 985dbad..e30c297 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_subpage.html
@@ -134,8 +134,7 @@
           label="$i18n{manageBrowserSyncedDataTitle}"
           hidden="[[!showSyncSettingsRevamp_]]"
           on-click="onManageChromeBrowserSyncClick_"
-          external
-          button-aria-description="$i18n{opensInNewTab}">
+          external>
       </cr-link-row>
 
       <cr-link-row id="syncDashboardLink" class="hr"
@@ -143,8 +142,7 @@
           sub-label="[[getManageSyncedDataSubtitle_()]]"
           on-click="onSyncDashboardLinkClick_"
           hidden="[[syncStatus.supervisedUser]]"
-          external
-          button-aria-description="$i18n{opensInNewTab}">
+          external>
       </cr-link-row>
 
       <cr-expand-button id="encryptionDescription"
diff --git a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers.html b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers.html
index ea93941..e4c9051 100644
--- a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers.html
+++ b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers.html
@@ -73,12 +73,15 @@
 <template is="dom-if"
     if="[[doesAccountHaveSavedPrinters_(savedPrinters_)]]" restamp>
   <div id="savedPrintersContainer">
-    <div class="settings-box first">
+    <div class="padded first">
       <div class="start">
         <span aria-label$="[[savedPrintersAriaLabel_]]">
           $i18n{savedPrintersTitle}
         </span>
       </div>
+      <div class="secondary" hidden="[[!isPrinterSettingsRevampEnabled_]]">
+        $i18n{savedPrintersSubtext}
+      </div>
     </div>
 
     <settings-cups-saved-printers id="savedPrinters"
@@ -90,13 +93,24 @@
 </template>
 <template is="dom-if" if="[[attemptedLoadingPrinters_]]">
   <div class="padded first" id="nearbyPrinters">
-    <div aria-label$="[[nearbyPrintersAriaLabel_]]">
+    <div aria-label$="[[nearbyPrintersAriaLabel_]]"
+        hidden="[[isPrinterSettingsRevampEnabled_]]">
       $i18n{nearbyPrintersListTitle}
     </div>
+    <div id="availablePrintersReadyTitle"
+        aria-label$="[[nearbyPrintersAriaLabel_]]"
+        hidden="[[!isPrinterSettingsRevampEnabled_]]">
+      $i18n{availablePrintersReadyTitle}
+    </div>
     <localized-link class="secondary"
         localized-string="$i18n{nearbyPrintersListDescription}"
-        link-url="$i18n{printingCUPSPrintLearnMoreUrl}">
+        link-url="$i18n{printingCUPSPrintLearnMoreUrl}"
+        hidden="[[isPrinterSettingsRevampEnabled_]]">
     </localized-link>
+    <div id="availablePrintersReadySubtext" class="secondary"
+        hidden="[[!isPrinterSettingsRevampEnabled_]]">
+      $i18n{availablePrintersReadySubtext}
+    </div>
     <template is="dom-if" if="[[!addPrinterButtonActive_(canAddPrinter,
       prefs.native_printing.user_native_printers_allowed.value)]]">
       <cr-policy-pref-indicator
diff --git a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers.ts b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers.ts
index 165db63f..3221b8d7 100644
--- a/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers.ts
+++ b/chrome/browser/resources/settings/chromeos/os_printing_page/cups_printers.ts
@@ -179,6 +179,17 @@
           Setting.kSavedPrinters,
         ]),
       },
+
+      /**
+       * True when the "printer-settings-revamp" feature flag is enabled.
+       */
+      isPrinterSettingsRevampEnabled_: {
+        type: Boolean,
+        value: () => {
+          return loadTimeData.getBoolean('isPrinterSettingsRevampEnabled');
+        },
+        readOnly: true,
+      },
     };
   }
 
diff --git a/chrome/browser/resources/settings/chromeos/os_printing_page/os_printing_page.html b/chrome/browser/resources/settings/chromeos/os_printing_page/os_printing_page.html
index e75064c..c51a7a1 100644
--- a/chrome/browser/resources/settings/chromeos/os_printing_page/os_printing_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_printing_page/os_printing_page.html
@@ -11,7 +11,6 @@
         label="$i18n{printJobsTitle}"
         sub-label="$i18n{printJobsSublabel}"
         external
-        button-aria-description="$i18n{opensInNewTab}"
         deep-link-focus-id$="[[Setting.kPrintJobs]]">
     </cr-link-row>
     <cr-link-row class="hr" id="scanningApp"
@@ -19,7 +18,6 @@
         label="$i18n{scanAppTitle}"
         sub-label="$i18n{scanAppSublabel}"
         external
-        button-aria-description="$i18n{opensInNewTab}"
         deep-link-focus-id$="[[Setting.kScanningApp]]">
     </cr-link-row>
   </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_search_page/google_assistant_subpage.html b/chrome/browser/resources/settings/chromeos/os_search_page/google_assistant_subpage.html
index a5381d48..eab68d49 100644
--- a/chrome/browser/resources/settings/chromeos/os_search_page/google_assistant_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/os_search_page/google_assistant_subpage.html
@@ -111,7 +111,6 @@
   <cr-link-row id="google-assistant-settings" class="hr"
       on-click="onGoogleAssistantSettingsTapped_"
       label="$i18n{googleAssistantSettings}"
-      external
-      button-aria-description="$i18n{opensInNewTab}">
+      external>
   </cr-link-row>
 </template>
diff --git a/chrome/browser/resources/settings/chromeos/os_search_page/search_engine.html b/chrome/browser/resources/settings/chromeos/os_search_page/search_engine.html
index 107f28f..67dc065 100644
--- a/chrome/browser/resources/settings/chromeos/os_search_page/search_engine.html
+++ b/chrome/browser/resources/settings/chromeos/os_search_page/search_engine.html
@@ -13,6 +13,5 @@
     label="$i18n{osSearchEngineLabel}"
     sub-label="[[currentSearchEngine_.name]]"
     on-click="onSearchEngineLinkClick_"
-    external
-    button-aria-description="$i18n{opensInNewTab}">
+    external>
 </cr-link-row>
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni
index c53d60d..d21a0d0 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.gni
+++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -86,7 +86,6 @@
   "chromeos/internet_page/network_proxy_section.ts",
   "chromeos/internet_page/network_summary_item.ts",
   "chromeos/internet_page/network_summary.ts",
-  "chromeos/internet_page/passpoint_subpage.ts",
   "chromeos/internet_page/settings_traffic_counters.ts",
   "chromeos/internet_page/tether_connection_dialog.ts",
   "chromeos/kerberos_page/kerberos_accounts.ts",
@@ -332,7 +331,6 @@
   "chromeos/guest_os/guest_os_browser_proxy.ts",
   "chromeos/internet_page/cellular_setup_settings_delegate.ts",
   "chromeos/internet_page/internet_page_browser_proxy.ts",
-  "chromeos/internet_page/passpoint_listener_mixin.ts",
   "chromeos/kerberos_page/kerberos_accounts_browser_proxy.ts",
   "chromeos/lazy_load.ts",
   "chromeos/lock_state_mixin.ts",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.ts b/chrome/browser/resources/settings/chromeos/os_settings.ts
index 87c512a..09d0fab 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings.ts
@@ -130,7 +130,8 @@
 export {InternetPageBrowserProxy, InternetPageBrowserProxyImpl} from './internet_page/internet_page_browser_proxy.js';
 export {NetworkSummaryElement} from './internet_page/network_summary.js';
 export {NetworkSummaryItemElement} from './internet_page/network_summary_item.js';
-export {KerberosAccountsBrowserProxyImpl, KerberosConfigErrorCode, KerberosErrorType} from './kerberos_page/kerberos_accounts_browser_proxy.js';
+export {KerberosAccount, KerberosAccountsBrowserProxy, KerberosAccountsBrowserProxyImpl, KerberosConfigErrorCode, KerberosErrorType, ValidateKerberosConfigResult} from './kerberos_page/kerberos_accounts_browser_proxy.js';
+export {SettingsKerberosPageElement} from './kerberos_page/kerberos_page.js';
 export {recordClick, recordNavigation, recordPageBlur, recordPageFocus, recordSearch, recordSettingChange, setUserActionRecorderForTesting} from './metrics_recorder.js';
 export * as appNotificationHandlerMojom from './mojom-webui/app_notification_handler.mojom-webui.js';
 export * as crosAudioConfigMojom from './mojom-webui/cros_audio_config.mojom-webui.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_routes.ts b/chrome/browser/resources/settings/chromeos/os_settings_routes.ts
index 68fa54e..8dc4a4e5 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_routes.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings_routes.ts
@@ -182,7 +182,6 @@
   OS_SEARCH: Route;
   OS_SYNC: Route;
   OS_PEOPLE: Route;
-  PASSPOINT_DETAIL: Route;
   PER_DEVICE_KEYBOARD: Route;
   PER_DEVICE_KEYBOARD_REMAP_KEYS: Route;
   PER_DEVICE_MOUSE: Route;
@@ -250,10 +249,6 @@
     r.APN =
         createSubpage(r.INTERNET, routesMojom.APN_SUBPAGE_PATH, Subpage.kApn);
   }
-  if (loadTimeData.getBoolean('isPasspointSettingsEnabled')) {
-    r.PASSPOINT_DETAIL =
-        createSubpage(r.INTERNET, 'passpointDetail', Subpage.kPasspointDetails);
-  }
 
   // Bluetooth section.
   r.BLUETOOTH = createSection(
diff --git a/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.html b/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.html
index 9a2a0c9..2cf06ac0a 100644
--- a/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.html
+++ b/chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_page.html
@@ -13,8 +13,7 @@
         start-icon="cr20:kite"
         label="$i18n{parentalControlsPageTitle}"
         sub-label="$i18n{parentalControlsPageViewSettingsLabel}"
-        external
-        button-aria-description="$i18n{opensInNewTab}">
+        external>
     </cr-link-row>
   </template>
   <template is="dom-if" if="[[!isChild_]]">
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
index fc80f7e..6b28433 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
@@ -5,8 +5,7 @@
         label="$i18n{personalizationHubTitle}"
         sub-label="$i18n{personalizationHubSubtitle}"
         on-click="openPersonalizationHub_"
-        external
-        button-aria-description="$i18n{opensInNewTab}">
+        external>
     </cr-link-row>
   </div>
 
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.html b/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.html
index efb37bca..16bd92e 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.html
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.html
@@ -32,6 +32,10 @@
     height: 18px;
     width: 18px;
   }
+
+  :host-context([chrome-refresh-2023]) .sp-labelless-input:hover {
+    --cr-input-background-color: transparent;
+  }
 </style>
 
 <cr-url-list-item
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.ts
index 47b009a2..0d0b91af 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.ts
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmark_row.ts
@@ -96,6 +96,16 @@
   trailingIconTooltip: string;
   imageUrls: string[];
 
+  constructor() {
+    super();
+
+    // The row has a [tabindex] attribute on it to move focus using iron-list
+    // but the row itself should not be focusable. By setting `delegatesFocus`
+    // to true, the browser will automatically move focus to the focusable
+    // elements within it when the row itself tries to gain focus.
+    this.attachShadow({mode: 'open', delegatesFocus: true});
+  }
+
   override connectedCallback() {
     super.connectedCallback();
     this.onInputDisplayChange_();
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html
index 91f9b92a..9cfb433e 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.html
@@ -226,8 +226,7 @@
     </sp-heading>
 
     <div id="bookmarks" class="bookmarks sp-scroller"
-        hidden="[[hasNoBookmarksInActiveFolder_(shownBookmarks_,
-                                                activeFolderPath_.*)]]"
+        hidden="[[!shownBookmarks_.length]]"
         role="[[getBookmarksListRole_(editing_)]]"
         aria-multiselectable="[[editing_]]" scrollable>
       <iron-list id="shownBookmarksIronList"
@@ -278,8 +277,7 @@
   </div>
 
   <sp-empty-state
-      hidden="[[!hasNoBookmarksInActiveFolder_(shownBookmarks_,
-                                               activeFolderPath_.*)]]"
+      hidden="[[shownBookmarks_.length]]"
       guest$="[[guestMode_]]"
       image-path="[[getEmptyImagePath_(labels_.*, searchQuery_)]]"
       dark-image-path="[[getEmptyImagePathDark_(labels_.*, searchQuery_)]]"
@@ -288,8 +286,7 @@
   </sp-empty-state>
   <sp-footer
       hidden="[[shouldShowEmptySearchState_(labels_.*, searchQuery_)]]"
-      pinned="[[!hasNoBookmarksInActiveFolder_(shownBookmarks_,
-                                               activeFolderPath_.*)]]">
+      pinned="[[shownBookmarks_.length]]">
     <cr-button class="floating-button"
         hidden="[[hideAddTabButton_(editing_)]]"
         on-click="onAddTabClicked_"
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
index 993c567b..137aa3c 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
@@ -693,22 +693,7 @@
   }
 
   private shouldHideHeader_(): boolean {
-    return this.hasActiveLabels_() || !!this.searchQuery_ ||
-        this.hasNoBookmarks_();
-  }
-
-  private hasNoBookmarks_(): boolean {
-    return this.hasNoBookmarksInActiveFolder_() && !this.getActiveFolder_();
-  }
-
-  private hasNoBookmarksInActiveFolder_(): boolean {
-    for (const bookmark of this.shownBookmarks_) {
-      if (bookmark.url || bookmark.parentId !== '0' ||
-          bookmark.children!.length) {
-        return false;
-      }
-    }
-    return true;
+    return this.hasActiveLabels_() || !!this.searchQuery_;
   }
 
   private getSelectedDescription_() {
diff --git a/chrome/browser/resources/side_panel/companion/companion.ts b/chrome/browser/resources/side_panel/companion/companion.ts
index 8852818..18c47c3 100644
--- a/chrome/browser/resources/side_panel/companion/companion.ts
+++ b/chrome/browser/resources/side_panel/companion/companion.ts
@@ -36,7 +36,13 @@
   // Arguments for MethodType.kOnOpenInNewTabButtonURLChanged.
   URL_FOR_OPEN_IN_NEW_TAB = 'urlForOpenInNewTab',
 
-  // Arguments for browser -> iframe communcation.
+  // Arguments for MethodType.kRecordUiSurfaceShown.
+  UI_SURFACE = 'ui_surface',
+
+  // Arguments for MethodType.kRecordUiSurfaceShown.
+  CHILD_ELEMENT_COUNT = 'child_element_count',
+
+  // Arguments for browser -> iframe communication.
   COMPANION_UPDATE_PARAMS = 'companion_update_params',
 }
 
@@ -154,6 +160,11 @@
     const openInNewTabUrl = new Url();
     openInNewTabUrl.url = data[ParamType.URL_FOR_OPEN_IN_NEW_TAB];
     companionProxy.handler.onOpenInNewTabButtonURLChanged(openInNewTabUrl);
+  } else if (methodType === MethodType.kRecordUiSurfaceShown) {
+    companionProxy.handler.recordUiSurfaceShown(
+        data[ParamType.UI_SURFACE], data[ParamType.CHILD_ELEMENT_COUNT]);
+  } else if (methodType === MethodType.kRecordUiSurfaceClicked) {
+    companionProxy.handler.recordUiSurfaceClicked(data[ParamType.UI_SURFACE]);
   }
 }
 
diff --git a/chrome/browser/resources/side_panel/shared/sp_shared_style.css b/chrome/browser/resources/side_panel/shared/sp_shared_style.css
index edf5dae..110f079 100644
--- a/chrome/browser/resources/side_panel/shared/sp_shared_style.css
+++ b/chrome/browser/resources/side_panel/shared/sp_shared_style.css
@@ -82,3 +82,8 @@
   --cr-input-padding-start: 8px;
   --cr-input-padding-top: 8px;
 }
+
+:host-context([chrome-refresh-2023]) .sp-labelless-input:hover {
+  --cr-input-background-color:
+      var(--color-side-panel-textfield-background-hover);
+}
diff --git a/chrome/browser/segmentation_platform/segmentation_platform_config.cc b/chrome/browser/segmentation_platform/segmentation_platform_config.cc
index 885f535..8793e26 100644
--- a/chrome/browser/segmentation_platform/segmentation_platform_config.cc
+++ b/chrome/browser/segmentation_platform/segmentation_platform_config.cc
@@ -112,6 +112,16 @@
 
 #endif  // BUILDFLAG(IS_ANDROID)
 
+std::unique_ptr<Config> GetConfigForWebAppInstallationPromo() {
+  auto config = std::make_unique<Config>();
+  config->segmentation_key = kWebAppInstallationPromoKey;
+  config->segmentation_uma_name = kWebAppInstallationPromoUmaName;
+  config->AddSegmentId(
+      SegmentId::OPTIMIZATION_TARGET_WEB_APP_INSTALLATION_PROMO);
+  config->on_demand_execution = true;
+  return config;
+}
+
 }  // namespace
 
 std::vector<std::unique_ptr<Config>> GetSegmentationPlatformConfig(
@@ -143,6 +153,7 @@
   configs.emplace_back(CrossDeviceUserSegment::GetConfig());
   configs.emplace_back(ResumeHeavyUserModel::GetConfig());
   configs.emplace_back(DeviceSwitcherModel::GetConfig());
+  configs.emplace_back(GetConfigForWebAppInstallationPromo());
 
   base::EraseIf(configs, [](const auto& config) { return !config.get(); });
 
diff --git a/chrome/browser/ssl/https_upgrades_browsertest.cc b/chrome/browser/ssl/https_upgrades_browsertest.cc
index ed1941c..170f0856 100644
--- a/chrome/browser/ssl/https_upgrades_browsertest.cc
+++ b/chrome/browser/ssl/https_upgrades_browsertest.cc
@@ -97,7 +97,7 @@
     mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
     host_resolver()->AddRule("*", "127.0.0.1");
 
-    // Set up "bad-https.test" as a hostname with an SSL error. HTTPS upgrades
+    // Set up "bad-https.com" as a hostname with an SSL error. HTTPS upgrades
     // to this host will fail.
     scoped_refptr<net::X509Certificate> cert(https_server_.GetCertificate());
     net::CertVerifyResult verify_result;
@@ -105,10 +105,10 @@
     verify_result.verified_cert = cert;
     verify_result.cert_status = net::CERT_STATUS_COMMON_NAME_INVALID;
     mock_cert_verifier_.mock_cert_verifier()->AddResultForCertAndHost(
-        cert, "bad-https.test", verify_result,
+        cert, "bad-https.com", verify_result,
         net::ERR_CERT_COMMON_NAME_INVALID);
     mock_cert_verifier_.mock_cert_verifier()->AddResultForCertAndHost(
-        cert, "www.bad-https.test", verify_result,
+        cert, "www.bad-https.com", verify_result,
         net::ERR_CERT_COMMON_NAME_INVALID);
 
     http_server_.AddDefaultHandlers(GetChromeTestDataDir());
@@ -226,8 +226,8 @@
 // enabled.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        UrlWithHttpScheme_ShouldUpgrade) {
-  GURL http_url = http_server()->GetURL("foo.test", "/simple.html");
-  GURL https_url = https_server()->GetURL("foo.test", "/simple.html");
+  GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
+  GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
 
   // The NavigateToURL() call returns `false` because the navigation is
   // redirected to HTTPS.
@@ -252,7 +252,7 @@
                                     1);
 
     // Also record general request metrics.
-    histograms()->ExpectTotalCount(kNavigationRequestSecurityLevelHistogram, 3);
+    histograms()->ExpectTotalCount(kNavigationRequestSecurityLevelHistogram, 2);
     histograms()->ExpectBucketCount(kNavigationRequestSecurityLevelHistogram,
                                     NavigationRequestSecurityLevel::kSecure, 1);
     histograms()->ExpectBucketCount(kNavigationRequestSecurityLevelHistogram,
@@ -265,7 +265,7 @@
                                     Event::kUpgradeNotAttempted, 1);
 
     // Also record general request metrics.
-    histograms()->ExpectTotalCount(kNavigationRequestSecurityLevelHistogram, 2);
+    histograms()->ExpectTotalCount(kNavigationRequestSecurityLevelHistogram, 1);
     histograms()->ExpectBucketCount(kNavigationRequestSecurityLevelHistogram,
                                     NavigationRequestSecurityLevel::kInsecure,
                                     1);
@@ -276,7 +276,7 @@
 // navigation should end up on that exact URL.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        UrlWithHttpsScheme_ShouldLoad) {
-  GURL https_url = https_server()->GetURL("foo.test", "/simple.html");
+  GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(content::NavigateToURL(contents, https_url));
 
@@ -308,8 +308,9 @@
                                   1);
 }
 
-// Test that HTTPS Upgrades are skipped for non-publicly routable (RFC1918/4193)
-// IP address hostnames, but HTTPS-First Mode should still apply.
+// Test that HTTPS Upgrades are skipped for non-unique hostnames, such as
+// non-publicly routable (RFC1918/4193) IP addresses, but HTTPS-First Mode
+// should still apply.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        NonRoutableIPAddress_ShouldNotUpgrade) {
   // This test is only interesting for HTTPS-Upgrades and HTTPS-First Mode.
@@ -371,7 +372,7 @@
   // wouldn't receive the traffic (since it relies on DNS).
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
-  if (IsHttpUpgradingEnabled()) {
+  if (IsHttpInterstitialEnabled()) {
     EXPECT_FALSE(content::NavigateToURL(contents, nonunique_url1));
     EXPECT_FALSE(content::NavigateToURL(contents, nonunique_url2));
     // Other histograms are still recorded.
@@ -380,6 +381,12 @@
                                     2);
     histograms()->ExpectBucketCount(kNavigationRequestSecurityLevelHistogram,
                                     NavigationRequestSecurityLevel::kSecure, 2);
+  } else if (IsHttpUpgradingEnabled()) {
+    // When HFM is not enabled but upgrading is, Chrome does NOT upgrade, so
+    // other histograms are not recorded.
+    EXPECT_TRUE(content::NavigateToURL(contents, nonunique_url1));
+    EXPECT_TRUE(content::NavigateToURL(contents, nonunique_url2));
+    histograms()->ExpectTotalCount(kNavigationRequestSecurityLevelHistogram, 2);
   } else {
     EXPECT_TRUE(content::NavigateToURL(contents, nonunique_url1));
     EXPECT_TRUE(content::NavigateToURL(contents, nonunique_url2));
@@ -398,7 +405,7 @@
 // exact URL, even if the site has an SSL error.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        UrlWithHttpsScheme_BrokenSSL_ShouldNotFallback) {
-  GURL https_url = https_server()->GetURL("bad-https.test", "/simple.html");
+  GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_FALSE(content::NavigateToURL(contents, https_url));
@@ -419,8 +426,8 @@
 // interstitial.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        UrlWithHttpScheme_BrokenSSL_ShouldInterstitial) {
-  GURL http_url = http_server()->GetURL("bad-https.test", "/simple.html");
-  GURL https_url = https_server()->GetURL("bad-https.test", "/simple.html");
+  GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
+  GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
@@ -451,7 +458,7 @@
 // clicks through the interstitial, they should end up on the HTTP URL.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        InterstitialBypassed_HttpFallbackLoaded) {
-  GURL http_url = http_server()->GetURL("bad-https.test", "/simple.html");
+  GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
@@ -500,8 +507,8 @@
   if (!IsHttpUpgradingEnabled()) {
     return;
   }
-  GURL http_url = http_server()->GetURL("foo.test", "/close-socket");
-  GURL https_url = https_server()->GetURL("foo.test", "/close-socket");
+  GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
+  GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
@@ -525,8 +532,8 @@
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        HttpsParentHttpSubframeNavigation_Blocked) {
   const GURL parent_url(
-      https_server()->GetURL("foo.test", "/iframe_blank.html"));
-  const GURL iframe_url(http_server()->GetURL("foo.test", "/simple.html"));
+      https_server()->GetURL("foo.com", "/iframe_blank.html"));
+  const GURL iframe_url(http_server()->GetURL("foo.com", "/simple.html"));
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(content::NavigateToURL(contents, parent_url));
@@ -547,8 +554,8 @@
                        HttpParentHttpSubframeNavigation_NotUpgraded) {
   // The parent frame will fail to upgrade to HTTPS.
   const GURL parent_url(
-      http_server()->GetURL("bad-https.test", "/iframe_blank.html"));
-  const GURL iframe_url(http_server()->GetURL("bar.test", "/simple.html"));
+      http_server()->GetURL("bad-https.com", "/iframe_blank.html"));
+  const GURL iframe_url(http_server()->GetURL("bar.com", "/simple.html"));
 
   // Navigate to `parent_url` and bypass the HTTPS-Only Mode warning.
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
@@ -607,7 +614,7 @@
   ASSERT_TRUE(timeout_server.Start());
   HttpsUpgradesInterceptor::SetHttpsPortForTesting(timeout_server.port());
 
-  const GURL http_url = http_server()->GetURL("foo.test", "/simple.html");
+  const GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
 
@@ -619,23 +626,23 @@
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
 }
 
-// Tests that an HTTP POST form navigation to "bar.test" from an HTTP page on
-// "foo.test" is not upgraded to HTTPS. (HTTP form navigations from HTTPS are
+// Tests that an HTTP POST form navigation to "bar.com" from an HTTP page on
+// "foo.com" is not upgraded to HTTPS. (HTTP form navigations from HTTPS are
 // blocked by the Mixed Forms warning.)
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest, HttpPageHttpPost_NotUpgraded) {
-  // Point the HTTP form target to "bar.test".
+  // Point the HTTP form target to "bar.com".
   base::StringPairs replacement_text;
   replacement_text.emplace_back(make_pair(
       "REPLACE_WITH_HOST_AND_PORT",
-      net::HostPortPair::FromURL(http_server()->GetURL("foo.test", "/"))
+      net::HostPortPair::FromURL(http_server()->GetURL("foo.com", "/"))
           .ToString()));
   auto replacement_path = net::test_server::GetFilePathWithReplacements(
       "/ssl/page_with_form_targeting_http_url.html", replacement_text);
 
-  // Navigate to the page hosting the form on "foo.test".
+  // Navigate to the page hosting the form on "foo.com".
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   content::NavigateToURLBlockUntilNavigationsComplete(
-      contents, http_server()->GetURL("bad-https.test", replacement_path), 1);
+      contents, http_server()->GetURL("bad-https.com", replacement_path), 1);
 
   if (IsHttpInterstitialEnabled()) {
     // The HTTPS-Only Mode interstitial should trigger.
@@ -662,7 +669,7 @@
   nav_observer.Wait();
 
   // Check that the navigation has ended up on the HTTP target.
-  EXPECT_EQ("foo.test", contents->GetLastCommittedURL().host());
+  EXPECT_EQ("foo.com", contents->GetLastCommittedURL().host());
   EXPECT_TRUE(contents->GetLastCommittedURL().SchemeIs(url::kHttpScheme));
 
   // Verify that no new navigation event metrics were recorded for the POST
@@ -681,8 +688,8 @@
 // host would imply a redirect loop.)
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        HttpsToHttpRedirect_ShouldUpgrade) {
-  GURL target_url = http_server()->GetURL("bar.test", "/title1.html");
-  GURL url = https_server()->GetURL("foo.test",
+  GURL target_url = http_server()->GetURL("bar.com", "/title1.html");
+  GURL url = https_server()->GetURL("foo.com",
                                     "/server-redirect?" + target_url.spec());
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
@@ -710,7 +717,7 @@
                                     Event::kUpgradeNotAttempted, 1);
   }
 
-  EXPECT_EQ("bar.test", contents->GetLastCommittedURL().host());
+  EXPECT_EQ("bar.com", contents->GetLastCommittedURL().host());
 }
 
 // Tests that navigating to an HTTPS page that downgrades to HTTP on the same
@@ -735,7 +742,7 @@
         // the EmbeddedTestServer has no notion of virtual hosts). This
         // explicitly sets the hostname back to the test host so that this
         // doesn't fail due to the exception for localhost.
-        http_downgrade.SetHostStr("foo.test");
+        http_downgrade.SetHostStr("foo.com");
         auto redirect_url = request.GetURL().ReplaceComponents(http_downgrade);
         auto response = std::make_unique<net::test_server::BasicHttpResponse>();
         response->set_code(net::HTTP_TEMPORARY_REDIRECT);
@@ -745,7 +752,7 @@
   ASSERT_TRUE(downgrading_server.Start());
   HttpsUpgradesInterceptor::SetHttpsPortForTesting(downgrading_server.port());
 
-  GURL url = downgrading_server.GetURL("foo.test", "/");
+  GURL url = downgrading_server.GetURL("foo.com", "/");
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, url);
 
@@ -767,8 +774,8 @@
 // net error would be a security level of NONE.)
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        NetErrorOnUpgrade_SecurityLevelWarning) {
-  GURL http_url = http_server()->GetURL("foo.test", "/close-socket");
-  GURL https_url = https_server()->GetURL("foo.test", "/close-socket");
+  GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
+  GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   auto* helper = SecurityStateTabHelper::FromWebContents(contents);
@@ -799,8 +806,8 @@
 // the interstitial, the security level should still be WARNING.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        BrokenSSLOnUpgrade_SecurityLevelWarning) {
-  GURL http_url = http_server()->GetURL("bad-https.test", "/simple.html");
-  GURL https_url = https_server()->GetURL("bad-https.test", "/simple.html");
+  GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
+  GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   auto* helper = SecurityStateTabHelper::FromWebContents(contents);
@@ -848,7 +855,7 @@
         response->set_code(net::HTTP_TEMPORARY_REDIRECT);
         response->AddCustomHeader(
             "Location",
-            "https://bad-https.test:" +
+            "https://bad-https.com:" +
                 base::NumberToString(
                     HttpsUpgradesInterceptor::GetHttpsPortForTesting()) +
                 "/simple.html");
@@ -857,9 +864,9 @@
   HttpsUpgradesInterceptor::SetHttpPortForTesting(upgrading_server.port());
   ASSERT_TRUE(upgrading_server.Start());
 
-  GURL http_url = upgrading_server.GetURL("bad-https.test", "/simple.html");
+  GURL http_url = upgrading_server.GetURL("bad-https.com", "/simple.html");
   // HTTPS server will have a cert error.
-  GURL https_url = https_server()->GetURL("bad-https.test", "/simple.html");
+  GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
@@ -913,8 +920,8 @@
     return;
   }
 
-  GURL http_url = http_server()->GetURL("foo.test", "/close-socket");
-  GURL https_url = https_server()->GetURL("foo.test", "/close-socket");
+  GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
+  GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
@@ -958,9 +965,9 @@
     return;
   }
 
-  GURL http_url = http_server()->GetURL("foo.test", "/close-socket");
-  GURL bad_https_url = https_server()->GetURL("foo.test", "/close-socket");
-  GURL good_https_url = https_server()->GetURL("foo.test", "/ssl/google.html");
+  GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
+  GURL bad_https_url = https_server()->GetURL("foo.com", "/close-socket");
+  GURL good_https_url = https_server()->GetURL("foo.com", "/ssl/google.html");
 
   ASSERT_EQ(http_url.host(), bad_https_url.host());
   ASSERT_EQ(bad_https_url.host(), good_https_url.host());
@@ -1012,7 +1019,7 @@
       http_url.host(), tab->GetPrimaryMainFrame()->GetStoragePartition()));
 
   // Load "logo.gif" as an image on the page.
-  GURL image = https_server()->GetURL("foo.test", "/ssl/google_files/logo.gif");
+  GURL image = https_server()->GetURL("foo.com", "/ssl/google_files/logo.gif");
   bool result = false;
   EXPECT_TRUE(ExecuteScriptAndExtractBool(
       tab,
@@ -1036,8 +1043,8 @@
     return;
   }
 
-  GURL http_url = http_server()->GetURL("foo.test", "/close-socket");
-  GURL https_url = https_server()->GetURL("foo.test", "/close-socket");
+  GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
+  GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
@@ -1068,8 +1075,8 @@
     return;
   }
 
-  GURL http_url = http_server()->GetURL("foo.test", "/close-socket");
-  GURL https_url = https_server()->GetURL("foo.test", "/close-socket");
+  GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
+  GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
@@ -1113,7 +1120,7 @@
 
   // Visit a host that doesn't support HTTPS for the first time, and click
   // through the HTTPS-First Mode interstitial to allowlist the host.
-  GURL http_url = http_server()->GetURL("bad-https.test", "/simple.html");
+  GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
   NavigateAndWaitForFallback(contents, http_url);
 
   if (IsHttpInterstitialEnabled()) {
@@ -1169,7 +1176,7 @@
 
   // Visit a host that doesn't support HTTPS for the first time, and click
   // through the HTTPS-First Mode interstitial to allowlist the host.
-  GURL http_url = http_server()->GetURL("bad-https.test", "/simple.html");
+  GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
   NavigateAndWaitForFallback(contents, http_url);
 
   if (IsHttpInterstitialEnabled()) {
@@ -1220,7 +1227,7 @@
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
 
   // URL for HTTPS server that will result in a certificate error.
-  GURL https_url = https_server()->GetURL("bad-https.test", "/simple.html");
+  GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
   // HTTP version of that URL that will get upgraded to HTTPS (but with the
   // correct port for the HTTPS server -- the test code can configure
@@ -1254,13 +1261,10 @@
   histograms()->ExpectTotalCount(kEventHistogram, 0);
 
   // Verify that general navigation request metrics were recorded.
-  histograms()->ExpectTotalCount(kNavigationRequestSecurityLevelHistogram, 3);
+  histograms()->ExpectTotalCount(kNavigationRequestSecurityLevelHistogram, 2);
   histograms()->ExpectBucketCount(kNavigationRequestSecurityLevelHistogram,
                                   NavigationRequestSecurityLevel::kHstsUpgraded,
                                   1);
-  histograms()->ExpectBucketCount(
-      kNavigationRequestSecurityLevelHistogram,
-      NavigationRequestSecurityLevel::kNonUniqueHostname, 1);
   histograms()->ExpectBucketCount(kNavigationRequestSecurityLevelHistogram,
                                   NavigationRequestSecurityLevel::kSecure, 1);
 }
@@ -1275,8 +1279,7 @@
     return;
   }
 
-  GURL good_https_url =
-      https_server()->GetURL("site1.test", "/defaultresponse");
+  GURL good_https_url = https_server()->GetURL("site1.com", "/defaultresponse");
 
   // Set up a new test server instance so it can have a custom handler.
   net::EmbeddedTestServer downgrading_server{
@@ -1293,7 +1296,7 @@
         // the EmbeddedTestServer has no notion of virtual hosts). This
         // explicitly sets the hostname back to the test host so that this
         // doesn't fail due to the exception for localhost.
-        http_downgrade.SetHostStr("site2.test");
+        http_downgrade.SetHostStr("site2.com");
         auto redirect_url = request.GetURL().ReplaceComponents(http_downgrade);
         auto response = std::make_unique<net::test_server::BasicHttpResponse>();
         response->set_code(net::HTTP_TEMPORARY_REDIRECT);
@@ -1303,7 +1306,7 @@
   ASSERT_TRUE(downgrading_server.Start());
   HttpsUpgradesInterceptor::SetHttpsPortForTesting(downgrading_server.port());
 
-  GURL downgrading_https_url = downgrading_server.GetURL("site2.test", "/");
+  GURL downgrading_https_url = downgrading_server.GetURL("site2.com", "/");
   GURL::Replacements swap_http_scheme;
   swap_http_scheme.SetSchemeStr(url::kHttpScheme);
   GURL downgrading_http_url =
@@ -1365,10 +1368,10 @@
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
-  // Without any policy allowlist, navigate to HTTP URL on foo.test. It *should*
+  // Without any policy allowlist, navigate to HTTP URL on foo.com. It *should*
   // get upgraded to HTTPS.
-  auto http_url = http_server()->GetURL("foo.test", "/simple.html");
-  auto https_url = https_server()->GetURL("foo.test", "/simple.html");
+  auto http_url = http_server()->GetURL("foo.com", "/simple.html");
+  auto https_url = https_server()->GetURL("foo.com", "/simple.html");
   EXPECT_FALSE(content::NavigateToURL(contents, http_url));
   EXPECT_EQ(https_url, contents->GetLastCommittedURL());
 
@@ -1376,8 +1379,8 @@
   auto* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
   auto* prefs = profile->GetPrefs();
   base::Value::List allowlist;
-  allowlist.Append("foo.test");
-  allowlist.Append("[*.]bar.test");
+  allowlist.Append("foo.com");
+  allowlist.Append("[*.]bar.com");
   allowlist.Append(http_server()->GetIPLiteralString());
   // These cases should not work, but the policy->pref mapping won't immediately
   // reject them.
@@ -1385,47 +1388,47 @@
   allowlist.Append("*");
   prefs->SetList(prefs::kHttpAllowlist, std::move(allowlist));
 
-  // Navigate to HTTP URL on foo.test. It should not get upgraded to HTTPS and
+  // Navigate to HTTP URL on foo.com. It should not get upgraded to HTTPS and
   // no interstitial should be shown.
-  http_url = http_server()->GetURL("foo.test", "/simple.html");
-  https_url = https_server()->GetURL("foo.test", "/simple.html");
+  http_url = http_server()->GetURL("foo.com", "/simple.html");
+  https_url = https_server()->GetURL("foo.com", "/simple.html");
   EXPECT_TRUE(content::NavigateToURL(contents, http_url));
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
   EXPECT_FALSE(
       chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial(
           contents));
 
-  // Navigate to HTTP URL on bar.test. Same result.
-  http_url = http_server()->GetURL("bar.test", "/simple.html");
-  https_url = https_server()->GetURL("bar.test", "/simple.html");
+  // Navigate to HTTP URL on bar.com. Same result.
+  http_url = http_server()->GetURL("bar.com", "/simple.html");
+  https_url = https_server()->GetURL("bar.com", "/simple.html");
   EXPECT_TRUE(content::NavigateToURL(contents, http_url));
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
   EXPECT_FALSE(
       chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial(
           contents));
 
-  // Navigate to HTTP URL on bar.bar.test. Same result as subdomain wildcard
+  // Navigate to HTTP URL on bar.bar.com. Same result as subdomain wildcard
   // was specified.
-  http_url = http_server()->GetURL("bar.bar.test", "/simple.html");
-  https_url = https_server()->GetURL("bar.bar.test", "/simple.html");
+  http_url = http_server()->GetURL("bar.bar.com", "/simple.html");
+  https_url = https_server()->GetURL("bar.bar.com", "/simple.html");
   EXPECT_TRUE(content::NavigateToURL(contents, http_url));
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
   EXPECT_FALSE(
       chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial(
           contents));
 
-  // Navigate to HTTP URL on foo.foo.test. Subdomains of foo.test should not be
+  // Navigate to HTTP URL on foo.foo.com. Subdomains of foo.com should not be
   // considered as being in the allowlist as no wildcard was specified. This
   // should get upgraded to HTTPS.
-  http_url = http_server()->GetURL("foo.foo.test", "/simple.html");
-  https_url = https_server()->GetURL("foo.foo.test", "/simple.html");
+  http_url = http_server()->GetURL("foo.foo.com", "/simple.html");
+  https_url = https_server()->GetURL("foo.foo.com", "/simple.html");
   EXPECT_FALSE(content::NavigateToURL(contents, http_url));
   EXPECT_EQ(https_url, contents->GetLastCommittedURL());
 
-  // Navigate to HTTP URL on baz.test, which is not on the allowlist. Should get
+  // Navigate to HTTP URL on baz.com, which is not on the allowlist. Should get
   // upgraded to HTTPS.
-  http_url = http_server()->GetURL("baz.test", "/simple.html");
-  https_url = https_server()->GetURL("baz.test", "/simple.html");
+  http_url = http_server()->GetURL("baz.com", "/simple.html");
+  https_url = https_server()->GetURL("baz.com", "/simple.html");
   EXPECT_FALSE(content::NavigateToURL(contents, http_url));
   EXPECT_EQ(https_url, contents->GetLastCommittedURL());
 
@@ -1448,8 +1451,8 @@
 
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  GURL http_url = http_server()->GetURL("foo.test", "/simple.html");
-  GURL https_url = https_server()->GetURL("foo.test", "/simple.html");
+  GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
+  GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
 
   if (IsHttpInterstitialEnabled()) {
     // HTTPS-First Mode should supercede HTTPS-Upgrades and upgrade the
@@ -1484,8 +1487,8 @@
                        MAYBE_InsecureContentSettingDisablesUpgrades) {
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  GURL http_url = http_server()->GetURL("foo.test", "/simple.html");
-  GURL https_url = https_server()->GetURL("foo.test", "/simple.html");
+  GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
+  GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
   auto* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
   auto* host_content_settings_map =
       HostContentSettingsMapFactory::GetForProfile(profile);
@@ -1542,21 +1545,21 @@
 // Should not crash when DCHECKS are enabled.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest, crbug1431026) {
   GURL www_bad_https_url =
-      https_server()->GetURL("www.bad-https.test", "/simple.html");
+      https_server()->GetURL("www.bad-https.com", "/simple.html");
   GURL www_http_url =
-      http_server()->GetURL("www.bad-https.test", "/simple.html");
+      http_server()->GetURL("www.bad-https.com", "/simple.html");
 
   // Configure HTTP and bad-HTTPS URLs which redirect to www. subdomain.
   std::string www_redirect_path =
       base::StrCat({"/server-redirect?", www_http_url.spec()});
   GURL redirecting_bad_https_url =
-      https_server()->GetURL("bad-https.test", www_redirect_path);
+      https_server()->GetURL("bad-https.com", www_redirect_path);
   GURL redirecting_http_url =
-      http_server()->GetURL("bad-https.test", www_redirect_path);
+      http_server()->GetURL("bad-https.com", www_redirect_path);
 
   // A good HTTPS URL which redirects to an HTTP URL, which also redirects.
   GURL initial_redirecting_good_https_url = https_server()->GetURL(
-      "good-https.test",
+      "good-https.com",
       base::StrCat({"/server-redirect-301?", redirecting_http_url.spec()}));
 
   auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
@@ -1564,14 +1567,14 @@
       content::NavigateToURL(contents, initial_redirecting_good_https_url));
 
   if (IsHttpInterstitialEnabled()) {
-    // Should be showing interstitial on http://bad-https.test/.
+    // Should be showing interstitial on http://bad-https.com/.
     EXPECT_EQ(redirecting_http_url, contents->GetLastCommittedURL());
     EXPECT_TRUE(
         chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial(
             contents));
   } else {
     // Either due to no upgrades, or due to fast fallback to HTTP, this should
-    // end up on http://www.bad-https.test.
+    // end up on http://www.bad-https.com.
     EXPECT_EQ(www_http_url, contents->GetLastCommittedURL());
     EXPECT_FALSE(
         chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial(
diff --git a/chrome/browser/ssl/https_upgrades_interceptor.cc b/chrome/browser/ssl/https_upgrades_interceptor.cc
index 66945b3..4bac628 100644
--- a/chrome/browser/ssl/https_upgrades_interceptor.cc
+++ b/chrome/browser/ssl/https_upgrades_interceptor.cc
@@ -262,17 +262,15 @@
     RecordNavigationRequestSecurityLevel(
         NavigationRequestSecurityLevel::kNonUniqueHostname);
 
-    // For HTTPS-Upgrades, skip attempting to upgrade non-routable IP address
-    // literals (i.e., RFC1918/4193) as they can't get publicly-trusted
-    // certificates.
+    // For HTTPS-Upgrades, skip attempting to upgrade non-unique hostnames
+    // as they can't get publicly-trusted certificates.
     //
     // HTTPS-First Mode does not exempt these hosts in order to ensure that
     // Chrome shows the HTTP interstitial before navigation to them.
     // Potentially, these could fast-fail instead and skip directly to the
     // interstitial.
     if (base::FeatureList::IsEnabled(features::kHttpsUpgrades) &&
-        !http_interstitial_enabled_ &&
-        tentative_resource_request.url.HostIsIPAddress()) {
+        !http_interstitial_enabled_) {
       std::move(callback).Run({});
       return;
     }
diff --git a/chrome/browser/storage_access_api/api_browsertest.cc b/chrome/browser/storage_access_api/api_browsertest.cc
index 3efde4d..839a8d35 100644
--- a/chrome/browser/storage_access_api/api_browsertest.cc
+++ b/chrome/browser/storage_access_api/api_browsertest.cc
@@ -1717,6 +1717,43 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(StorageAccessAPIBrowserTest,
+                       DismissalAllowsFuturePrompts) {
+  NavigateToPageWithFrame(kHostA);
+  NavigateFrameTo(EchoCookiesURL(kHostB));
+
+  prompt_factory()->set_response_type(
+      permissions::PermissionRequestManager::DISMISS);
+
+  {
+    // The first request should show a prompt, which is dismissed.
+    permissions::PermissionRequestObserver observer(
+        browser()->tab_strip_model()->GetActiveWebContents());
+    EXPECT_FALSE(
+        content::ExecJs(GetFrame(), "document.requestStorageAccess()"));
+    ASSERT_TRUE(observer.request_shown());
+    EXPECT_EQ(false,
+              content::EvalJs(GetFrame(), "document.hasStorageAccess()"));
+    ASSERT_EQ(prompt_factory()->TotalRequestCount(), 1);
+  }
+
+  prompt_factory()->set_response_type(
+      permissions::PermissionRequestManager::ACCEPT_ALL);
+
+  {
+    // However, subsequent requests should be able to re-prompt.
+    permissions::PermissionRequestObserver observer(
+        browser()->tab_strip_model()->GetActiveWebContents());
+
+    EXPECT_TRUE(
+        storage::test::RequestAndCheckStorageAccessForFrame(GetFrame()));
+
+    // Verify a prompt was shown.
+    EXPECT_TRUE(observer.request_shown());
+    EXPECT_EQ(prompt_factory()->TotalRequestCount(), 2);
+  }
+}
+
 class StorageAccessAPIWithImplicitGrantsBrowserTest
     : public StorageAccessAPIBaseBrowserTest {
  public:
diff --git a/chrome/browser/support_tool/ash/chrome_user_logs_data_collector_unittest.cc b/chrome/browser/support_tool/ash/chrome_user_logs_data_collector_unittest.cc
index fdeca26..d4f8640 100644
--- a/chrome/browser/support_tool/ash/chrome_user_logs_data_collector_unittest.cc
+++ b/chrome/browser/support_tool/ash/chrome_user_logs_data_collector_unittest.cc
@@ -52,14 +52,14 @@
 const FakeUserLog kFakeUserLogs[] = {
     {/*path=*/base::FilePath("log/chrome"), /*log_name=*/"chrome",
      /*log_contents=*/"Fake Chrome logs\nUser is fakeusername@example.com",
-     /*redacted_contents=*/"Fake Chrome logs\nUser is <email: 1>"},
+     /*redacted_contents=*/"Fake Chrome logs\nUser is (email: 1)"},
     {/*path=*/base::FilePath("log/chrome_00000000-000000"),
      /*log_name=*/"chrome_00000000-000000",
      /*log_contents=*/"Sample logs", /*redacted_contents=*/"Sample logs"},
     {/*path=*/base::FilePath("log/chrome_00000000-111111"),
      /*log_name=*/"chrome_00000000-111111",
      /*log_contents=*/"Sample logs with PII chrome://resources/f?user=bar",
-     /*redacted_contents=*/"Sample logs with PII <URL: 1>"}};
+     /*redacted_contents=*/"Sample logs with PII (URL: 1)"}};
 
 const PIIMap kExpectedPIIMap = {
     {redaction::PIIType::kEmail, {"fakeusername@example.com"}},
diff --git a/chrome/browser/support_tool/ash/network_health_data_collector_unittest.cc b/chrome/browser/support_tool/ash/network_health_data_collector_unittest.cc
index 0595385..92951a45 100644
--- a/chrome/browser/support_tool/ash/network_health_data_collector_unittest.cc
+++ b/chrome/browser/support_tool/ash/network_health_data_collector_unittest.cc
@@ -65,9 +65,9 @@
     "Type: kEthernet\n"
     "State: kOnline\n"
     "Portal State: kOnline\n"
-    "MAC Address: [MAC OUI=aa:aa:aa IFACE=1]\n"
-    "IPV4 Address: <IPv4: 1>\n"
-    "IPV6 Addresses: <IPv6: 1>\n"
+    "MAC Address: (MAC OUI=aa:aa:aa IFACE=1)\n"
+    "IPV4 Address: (IPv4: 1)\n"
+    "IPV6 Addresses: (IPv6: 1)\n"
     "\n"
     "Name: wifi_none_1\n"
     "GUID: wifi_none_1\n"
@@ -78,9 +78,9 @@
     "Signal Strength (Average): 81.25555419921875\n"
     "Signal Strength (Deviation): 3.1622776985168457\n"
     "Signal Strength (Samples): [80,80,75,75,82,82,75,75,80,80,85,85,85]\n"
-    "MAC Address: [MAC OUI=aa:bb:cc IFACE=2]\n"
+    "MAC Address: (MAC OUI=aa:bb:cc IFACE=2)\n"
     "IPV4 Address: N/A\n"
-    "IPV6 Addresses: <IPv6: 2>\n"
+    "IPV6 Addresses: (IPv6: 2)\n"
     "\n";
 
 const PIIMap kExpectedPIIMap = {
diff --git a/chrome/browser/support_tool/ash/network_routes_data_collector_unittest.cc b/chrome/browser/support_tool/ash/network_routes_data_collector_unittest.cc
index 7e734e06..5c8dae5 100644
--- a/chrome/browser/support_tool/ash/network_routes_data_collector_unittest.cc
+++ b/chrome/browser/support_tool/ash/network_routes_data_collector_unittest.cc
@@ -81,21 +81,21 @@
     "9: from all lookup main\n"
     "10: from all fwmark 0x3ea0000/0xffff0000 lookup 1002\n"
     "10: from all oif eth0 lookup 1002\n"
-    "10: from <IPv4: 1>/23 lookup 1002\n"
+    "10: from (IPv4: 1)/23 lookup 1002\n"
     "10: from all iif eth0 lookup 1002\n"
     "32765: from all lookup 1002\n"
     "32766: from all lookup main\n"
     "32767: from all lookup default\n"
     "\n"
     "[ ip -4/-6 route show table all ]\n"
-    "default via <IPv4: 2> dev eth0 table 1002 metric 10\n"
+    "default via (IPv4: 2) dev eth0 table 1002 metric 10\n"
     "100.115.92.0/30 dev arcbr0 proto kernel scope link src 100.115.92.1\n"
     "100.115.92.4/30 dev arc_eth0 proto kernel scope link src "
     "100.115.92.5\n"
     "100.115.92.12/30 dev arc_wlan0 proto kernel scope link src "
     "100.115.92.13\n"
     "100.115.92.128/30 via 100.115.92.129 dev arc_ns0\n"
-    "<IPv4: 3>/23 dev eth0 proto kernel scope link src <IPv4: 1>\n"
+    "(IPv4: 3)/23 dev eth0 proto kernel scope link src (IPv4: 1)\n"
     "broadcast 100.115.92.0 dev arcbr0 table local proto kernel scope link "
     "src 100.115.92.1\n"
     "local 100.115.92.1 dev arcbr0 table local proto kernel scope host src "
@@ -108,31 +108,31 @@
     "100.115.92.12/30 dev arc_wlan0 proto kernel scope link src 100.115.92.13\n"
     "100.115.92.128/30 via 100.115.92.129 dev arc_ns0\n"
     "100.115.92.140/30 dev arc_ns9 proto kernel scope link src 100.115.92.141\n"
-    "<IPv4: 3>/23 dev eth0 proto kernel scope link src <IPv4: 1>\n"
+    "(IPv4: 3)/23 dev eth0 proto kernel scope link src (IPv4: 1)\n"
     "\n"
     "[ ip -4/-6 route show table 1002 ]\n"
-    "default via <IPv4: 2> dev eth0 metric 10\n"
+    "default via (IPv4: 2) dev eth0 metric 10\n"
     "\n"
     "[ ip -4/-6 rule list ]\n"
     "0: from all lookup local\n"
     "9: from all lookup main\n"
     "10: from all fwmark 0x3ea0000/0xffff0000 lookup 1002\n"
     "10: from all oif eth0 lookup 1002\n"
-    "10: from <IPv4: 1>/23 lookup 1002\n"
+    "10: from (IPv4: 1)/23 lookup 1002\n"
     "10: from all iif eth0 lookup 1002\n"
     "32765: from all lookup 1002\n"
     "32766: from all lookup main\n"
     "32767: from all lookup default\n"
     "\n"
     "[ ip -4/-6 route show table all ]\n"
-    "default via <IPv4: 2> dev eth0 table 1002 metric 10\n"
+    "default via (IPv4: 2) dev eth0 table 1002 metric 10\n"
     "100.115.92.0/30 dev arcbr0 proto kernel scope link src 100.115.92.1\n"
     "100.115.92.4/30 dev arc_eth0 proto kernel scope link src "
     "100.115.92.5\n"
     "100.115.92.12/30 dev arc_wlan0 proto kernel scope link src "
     "100.115.92.13\n"
     "100.115.92.128/30 via 100.115.92.129 dev arc_ns0\n"
-    "<IPv4: 3>/23 dev eth0 proto kernel scope link src <IPv4: 1>\n"
+    "(IPv4: 3)/23 dev eth0 proto kernel scope link src (IPv4: 1)\n"
     "broadcast 100.115.92.0 dev arcbr0 table local proto kernel scope link "
     "src 100.115.92.1\n"
     "local 100.115.92.1 dev arcbr0 table local proto kernel scope host src "
@@ -145,10 +145,10 @@
     "100.115.92.12/30 dev arc_wlan0 proto kernel scope link src 100.115.92.13\n"
     "100.115.92.128/30 via 100.115.92.129 dev arc_ns0\n"
     "100.115.92.140/30 dev arc_ns9 proto kernel scope link src 100.115.92.141\n"
-    "<IPv4: 3>/23 dev eth0 proto kernel scope link src <IPv4: 1>\n"
+    "(IPv4: 3)/23 dev eth0 proto kernel scope link src (IPv4: 1)\n"
     "\n"
     "[ ip -4/-6 route show table 1002 ]\n"
-    "default via <IPv4: 2> dev eth0 metric 10\n";
+    "default via (IPv4: 2) dev eth0 metric 10\n";
 }  // namespace
 
 class NetworkRoutesDataCollectorTest : public ::testing::Test {
diff --git a/chrome/browser/support_tool/ash/shill_data_collector_unittest.cc b/chrome/browser/support_tool/ash/shill_data_collector_unittest.cc
index a4e8d01..9094344 100644
--- a/chrome/browser/support_tool/ash/shill_data_collector_unittest.cc
+++ b/chrome/browser/support_tool/ash/shill_data_collector_unittest.cc
@@ -73,26 +73,26 @@
          "Name": "stub_wifi_device1",
          "Type": "wifi"
       })",
-     /*test_logs_pii_redacted=*/R"("/device/wifi1": {
+     /*test_logs_pii_redacted=*/R"data("/device/wifi1": {
          "Address": "23456789abcd",
          "DBus.Object": "/device/wifi1",
          "DBus.Service": "org.freedesktop.ModemManager1",
          "IPConfigs": {
             "ipconfig_v4_path": {
-               "Address": "<IPv4: 1>",
-               "Gateway": "<IPv4: 2>",
+               "Address": "(IPv4: 1)",
+               "Gateway": "(IPv4: 2)",
                "Method": "ipv4",
                "Prefixlen": 1,
-               "WebProxyAutoDiscoveryUrl": "<URL: 1>"
+               "WebProxyAutoDiscoveryUrl": "(URL: 1)"
             },
             "ipconfig_v6_path": {
-               "Address": "<IPv6: 1>",
+               "Address": "(IPv6: 1)",
                "Method": "ipv6"
             }
          },
          "Name": "*** MASKED ***",
          "Type": "wifi"
-      })"},
+      })data"},
     {/*data_source_name=*/kNetworkServices,
      /*test_logs=*/R"("/service/wifi1": {
          "Connectable": true,
diff --git a/chrome/browser/support_tool/ash/system_logs_data_collector_unittest.cc b/chrome/browser/support_tool/ash/system_logs_data_collector_unittest.cc
index 56a4b733..df445c9 100644
--- a/chrome/browser/support_tool/ash/system_logs_data_collector_unittest.cc
+++ b/chrome/browser/support_tool/ash/system_logs_data_collector_unittest.cc
@@ -40,7 +40,7 @@
 const std::map<std::string, std::string> kExpectedLogs = {
     {"Sample Log",
      // Redacted version of "Your email address is abc@abc.com"
-     "Your email address is <email: 1>"}};
+     "Your email address is (email: 1)"}};
 
 constexpr char kExpectedLogName[] = "Sample Log";
 
diff --git a/chrome/browser/support_tool/ash/system_state_data_collector_unittest.cc b/chrome/browser/support_tool/ash/system_state_data_collector_unittest.cc
index f21c081e..34ae8ee 100644
--- a/chrome/browser/support_tool/ash/system_state_data_collector_unittest.cc
+++ b/chrome/browser/support_tool/ash/system_state_data_collector_unittest.cc
@@ -44,7 +44,7 @@
      // file.
      "Sample Log.txt",
      // Redacted version of "Your email address is abc@abc.com"
-     "Your email address is <email: 1>"}};
+     "Your email address is (email: 1)"}};
 
 // The PII in the sample logs that `FakeDebugDaemonClient` returns in
 // `GetFeedbackLogs()` call.
diff --git a/chrome/browser/support_tool/system_log_source_data_collector_adaptor_unittest.cc b/chrome/browser/support_tool/system_log_source_data_collector_adaptor_unittest.cc
index 84c3586..f3e066c 100644
--- a/chrome/browser/support_tool/system_log_source_data_collector_adaptor_unittest.cc
+++ b/chrome/browser/support_tool/system_log_source_data_collector_adaptor_unittest.cc
@@ -49,7 +49,7 @@
      /*test_logs_pii_redacted=*/
      "Collected data for testing:\n"
      "Will contain some PII sensitive info to test functionality.\n"
-     "Some IP addresss as PII here: <0.0.0.0/8: 1>, <IPv6: 1>\n"},
+     "Some IP addresss as PII here: (0.0.0.0/8: 1), (IPv6: 1)\n"},
     {/*data_source_name=*/"test-log-source-url",
      /*test_logs=*/
      "More data for testing for this log source:\n"
@@ -59,7 +59,7 @@
      /*test_logs_pii_redacted=*/
      "More data for testing for this log source:\n"
      "For example some URL address that could be visited by user\n"
-     "is <URL: 1> and this will be considered as PII.\n"},
+     "is (URL: 1) and this will be considered as PII.\n"},
 };
 
 // The PII sensitive data that the test data contains.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 3691ac8b..971ecfc1 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -5182,6 +5182,7 @@
       "views/side_panel/extensions/extension_side_panel_coordinator.h",
       "views/side_panel/extensions/extension_side_panel_manager.cc",
       "views/side_panel/extensions/extension_side_panel_manager.h",
+      "views/side_panel/extensions/extension_side_panel_utils.cc",
       "views/side_panel/feed/feed_side_panel_coordinator.cc",
       "views/side_panel/feed/feed_side_panel_coordinator.h",
       "views/side_panel/history_clusters/history_clusters_side_panel_controller.cc",
@@ -5496,6 +5497,8 @@
       "views/webid/account_selection_bubble_view_interface.h",
       "views/webid/fedcm_account_selection_view_desktop.cc",
       "views/webid/fedcm_account_selection_view_desktop.h",
+      "views/webid/fedcm_modal_dialog_view.cc",
+      "views/webid/fedcm_modal_dialog_view.h",
       "views/webid/identity_provider_display_data.cc",
       "views/webid/identity_provider_display_data.h",
       "webauthn/account_hover_list_model.cc",
@@ -5824,7 +5827,6 @@
       "extensions/app_launch_params.h",
       "extensions/application_launch.cc",
       "extensions/application_launch.h",
-      "extensions/create_side_panel_manager.h",
       "extensions/extension_action_platform_delegate.h",
       "extensions/extension_action_view_controller.cc",
       "extensions/extension_action_view_controller.h",
@@ -5846,6 +5848,7 @@
       "extensions/extension_popup_types.h",
       "extensions/extension_settings_overridden_dialog.cc",
       "extensions/extension_settings_overridden_dialog.h",
+      "extensions/extension_side_panel_utils.h",
       "extensions/extensions_container.h",
       "extensions/extensions_dialogs.h",
       "extensions/extensions_overrides/simple_overrides.cc",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index d11d9fd6..16cb8948 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -5583,9 +5583,18 @@
       </message>
 
       <!-- WebID Account Selection strings -->
-      <message name="IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT" desc="Header for sign in sheet. Sheet is shown to prompt user for sign in consent.">
+      <message name="IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_SIGNIN" desc="Header for sign in sheet. Sheet is shown to prompt user to sign in to a website using an account from an identity provider.">
         Sign in to <ph name="SITE_ETLD_PLUS_ONE">%1$s<ex>rp.example</ex></ph> with <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">%2$s<ex>idp.com</ex></ph>
       </message>
+      <message name="IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_SIGNUP" desc="Header for sign up sheet. Sheet is shown to prompt user to sign up to a website using an account from an identity provider.">
+        Sign up to <ph name="SITE_ETLD_PLUS_ONE">%1$s<ex>rp.example</ex></ph> with <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">%2$s<ex>idp.com</ex></ph>
+      </message>
+      <message name="IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_USE" desc="Header for use sheet. Sheet is shown to prompt user to use a website using an account from an identity provider.">
+        Use <ph name="SITE_ETLD_PLUS_ONE">%1$s<ex>rp.example</ex></ph> with <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">%2$s<ex>idp.com</ex></ph>
+      </message>
+      <message name="IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_CONTINUE" desc="Header for continue sheet. Sheet is shown to prompt user to continue to a website using an account from an identity provider.">
+        Continue to <ph name="SITE_ETLD_PLUS_ONE">%1$s<ex>rp.example</ex></ph> with <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">%2$s<ex>idp.com</ex></ph>
+      </message>
       <message name="IDS_ACCOUNT_SELECTION_SHEET_SUBTITLE_EXPLICIT" desc="Message shown when the user is shown the federated identity login prompt. This message is the subtitle for the sign in sheet, which contains the top-level domain of the page the user is visiting when the user is receiving a prompt from an iframe embedded on such page.">
         on <ph name="MAIN_FRAME_ETLD_PLUS_ONE">%1$s<ex>main-frame.example</ex></ph>
       </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT.png.sha1
deleted file mode 100644
index 3495694..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-1ec33329ddb565a004c132101ae2524cc39ece46
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_CONTINUE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_CONTINUE.png.sha1
new file mode 100644
index 0000000..56f0079
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_CONTINUE.png.sha1
@@ -0,0 +1 @@
+c4cde90d1a5fdbb8f0cf08c204d047b474cc06e3
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_SIGNIN.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_SIGNIN.png.sha1
new file mode 100644
index 0000000..93a5ece
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_SIGNIN.png.sha1
@@ -0,0 +1 @@
+0ba7099e113e7adb2e47cdba38436a611cbc1789
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_SIGNUP.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_SIGNUP.png.sha1
new file mode 100644
index 0000000..90c4a72
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_SIGNUP.png.sha1
@@ -0,0 +1 @@
+49210a3e24b453b7da8afb1f9dcf80b6fc794323
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_USE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_USE.png.sha1
new file mode 100644
index 0000000..06bc7e9
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT_USE.png.sha1
@@ -0,0 +1 @@
+ee5c337e9319fb448d597985327316e569ebc552
\ No newline at end of file
diff --git a/chrome/browser/ui/android/webid/account_selection_view_android.cc b/chrome/browser/ui/android/webid/account_selection_view_android.cc
index 77d4297..bdc1309 100644
--- a/chrome/browser/ui/android/webid/account_selection_view_android.cc
+++ b/chrome/browser/ui/android/webid/account_selection_view_android.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/android/webid/jni_headers/IdentityProviderMetadata_jni.h"
 #include "chrome/browser/ui/webid/account_selection_view.h"
 #include "content/public/browser/identity_request_dialog_controller.h"
+#include "third_party/blink/public/mojom/webid/federated_auth_request.mojom.h"
 #include "ui/android/color_utils_android.h"
 #include "ui/android/window_android.h"
 #include "url/android/gurl_android.h"
@@ -37,6 +38,7 @@
       ConvertUTF8ToJavaString(env, account.name),
       ConvertUTF8ToJavaString(env, account.given_name),
       url::GURLAndroid::FromNativeGURL(env, account.picture),
+      base::android::ToJavaArrayOfStrings(env, account.hints),
       account.login_state == Account::LoginState::kSignIn);
 }
 
@@ -82,6 +84,7 @@
     JNIEnv* env,
     const JavaParamRef<jobjectArray>& string_fields_obj,
     const JavaParamRef<jobject>& picture_url_obj,
+    const JavaParamRef<jobjectArray>& account_hints,
     bool is_sign_in) {
   std::vector<std::string> string_fields;
   AppendJavaStringArrayToStringVector(env, string_fields_obj, &string_fields);
@@ -94,7 +97,31 @@
       is_sign_in ? Account::LoginState::kSignIn : Account::LoginState::kSignUp;
 
   GURL picture_url = *url::GURLAndroid::ToNativeGURL(env, picture_url_obj);
-  return Account(account_id, email, name, given_name, picture_url, login_state);
+
+  std::vector<std::string> hints;
+  AppendJavaStringArrayToStringVector(env, account_hints, &hints);
+  return Account(account_id, email, name, given_name, picture_url, hints,
+                 login_state);
+}
+
+ScopedJavaLocalRef<jstring> ConvertRpContextToJavaString(
+    JNIEnv* env,
+    blink::mojom::RpContext rp_context) {
+  std::string rp_context_string;
+  switch (rp_context) {
+    case blink::mojom::RpContext::kSignUp:
+      rp_context_string = "signup";
+      break;
+    case blink::mojom::RpContext::kUse:
+      rp_context_string = "use";
+      break;
+    case blink::mojom::RpContext::kContinue:
+      rp_context_string = "continue";
+      break;
+    default:
+      rp_context_string = "signin";
+  }
+  return ConvertUTF8ToJavaString(env, rp_context_string);
 }
 
 }  // namespace
@@ -139,13 +166,15 @@
   ScopedJavaLocalRef<jobject> client_id_metadata_obj =
       ConvertToJavaClientIdMetadata(env,
                                     identity_provider_data[0].client_metadata);
+
   Java_AccountSelectionBridge_showAccounts(
       env, java_object_internal_,
       ConvertUTF8ToJavaString(env, top_frame_for_display),
       ConvertUTF8ToJavaString(env, iframe_url_for_display.value_or("")),
       ConvertUTF8ToJavaString(env, identity_provider_data[0].idp_for_display),
       accounts_obj, idp_metadata_obj, client_id_metadata_obj,
-      sign_in_mode == Account::SignInMode::kAuto);
+      sign_in_mode == Account::SignInMode::kAuto,
+      ConvertRpContextToJavaString(env, identity_provider_data[0].rp_context));
 }
 
 void AccountSelectionViewAndroid::ShowFailureDialog(
@@ -178,11 +207,13 @@
     const JavaParamRef<jobject>& idp_config_url,
     const JavaParamRef<jobjectArray>& account_string_fields,
     const JavaParamRef<jobject>& account_picture_url,
+    const JavaParamRef<jobjectArray>& account_hints,
     bool is_sign_in) {
   GURL config_url = *url::GURLAndroid::ToNativeGURL(env, idp_config_url);
   delegate_->OnAccountSelected(
-      config_url, ConvertFieldsToAccount(env, account_string_fields,
-                                         account_picture_url, is_sign_in));
+      config_url,
+      ConvertFieldsToAccount(env, account_string_fields, account_picture_url,
+                             account_hints, is_sign_in));
   // The AccountSelectionViewAndroid may be destroyed.
   // AccountSelectionView::Delegate::OnAccountSelected() might delete this.
   // See https://crbug.com/1393650 for details.
diff --git a/chrome/browser/ui/android/webid/account_selection_view_android.h b/chrome/browser/ui/android/webid/account_selection_view_android.h
index b7d4403..bc07560b 100644
--- a/chrome/browser/ui/android/webid/account_selection_view_android.h
+++ b/chrome/browser/ui/android/webid/account_selection_view_android.h
@@ -37,6 +37,7 @@
       const base::android::JavaParamRef<jobject>& idp_config_url,
       const base::android::JavaParamRef<jobjectArray>& account_string_fields,
       const base::android::JavaParamRef<jobject>& account_picture_url,
+      const base::android::JavaParamRef<jobjectArray>& account_hints,
       bool is_sign_in);
   void OnDismiss(JNIEnv* env, jint dismiss_reason);
 
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java
index 7d8b6be..7f69cc2 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBridge.java
@@ -75,21 +75,24 @@
         mNativeView = 0;
     }
 
-    /* Shows the accounts in a bottom sheet UI allowing user to select one.
+    /**
+     * Shows the accounts in a bottom sheet UI allowing user to select one.
      *
      * @param topFrameForDisplay is the formatted RP top frame URL to display in the FedCM prompt.
      * @param iframeForDisplay is the formatted RP iframe URL to display in the FedCM prompt.
      * @param idpForDisplay is the formatted IDP URL to display in the FedCM prompt.
      * @param accounts is the list of accounts to be shown.
      * @param isAutoReauthn represents whether this is an auto re-authn flow.
+     * @param rpContext is a {@link String} representing the desired text to be used in the title of
+     *         the FedCM prompt: "signin", "continue", etc.
      */
     @CalledByNative
     private void showAccounts(String topFrameForDisplay, String iframeForDisplay,
             String idpForDisplay, Account[] accounts, IdentityProviderMetadata idpMetadata,
-            ClientIdMetadata clientIdMetadata, boolean isAutoReauthn) {
+            ClientIdMetadata clientIdMetadata, boolean isAutoReauthn, String rpContext) {
         assert accounts != null && accounts.length > 0;
         mAccountSelectionComponent.showAccounts(topFrameForDisplay, iframeForDisplay, idpForDisplay,
-                Arrays.asList(accounts), idpMetadata, clientIdMetadata, isAutoReauthn);
+                Arrays.asList(accounts), idpMetadata, clientIdMetadata, isAutoReauthn, rpContext);
     }
 
     @CalledByNative
@@ -116,14 +119,16 @@
             // optimization to avoid needing multiple JNI getters on the Account class on for each
             // field.
             AccountSelectionBridgeJni.get().onAccountSelected(mNativeView, idpConfigUrl,
-                    account.getStringFields(), account.getPictureUrl(), account.isSignIn());
+                    account.getStringFields(), account.getPictureUrl(), account.getHints(),
+                    account.isSignIn());
         }
     }
 
     @NativeMethods
     interface Natives {
         void onAccountSelected(long nativeAccountSelectionViewAndroid, GURL idpConfigUrl,
-                String[] accountFields, GURL accountPictureUrl, boolean isSignedIn);
+                String[] accountFields, GURL accountPictureUrl, String[] accountHints,
+                boolean isSignedIn);
         void onDismiss(long nativeAccountSelectionViewAndroid,
                 @IdentityRequestDialogDismissReason int dismissReason);
     }
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
index 9fa5e78..10ae329 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
@@ -95,15 +95,16 @@
             JUnitTestGURLs.getGURL(JUnitTestGURLs.RED_3);
     private static final GURL TEST_CONFIG_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_2);
 
-    private static final Account ANA = new Account(
-            "Ana", "ana@one.test", "Ana Doe", "Ana", TEST_PROFILE_PIC, /*isSignIn=*/true);
-    private static final Account BOB =
-            new Account("Bob", "", "Bob", "", TEST_PROFILE_PIC, /*isSignIn=*/true);
-    private static final Account CARL = new Account(
-            "Carl", "carl@three.test", "Carl Test", ":)", TEST_PROFILE_PIC, /*isSignIn=*/true);
+    private static final Account ANA = new Account("Ana", "ana@one.test", "Ana Doe", "Ana",
+            TEST_PROFILE_PIC, /*hints=*/new String[0], /*isSignIn=*/true);
+    private static final Account BOB = new Account(
+            "Bob", "", "Bob", "", TEST_PROFILE_PIC, /*hints=*/new String[0], /*isSignIn=*/true);
+    private static final Account CARL = new Account("Carl", "carl@three.test", "Carl Test", ":)",
+            TEST_PROFILE_PIC, /*hints=*/new String[0], /*isSignIn=*/true);
     private static final Account NEW_USER = new Account("602214076", "goto@email.example",
-            "Sam E. Goto", "Sam", TEST_PROFILE_PIC, /*isSignIn=*/false);
-
+            "Sam E. Goto", "Sam", TEST_PROFILE_PIC, /*hints=*/new String[0], /*isSignIn=*/false);
+    private static final String[] RP_CONTEXTS =
+            new String[] {"signin", "signup", "use", "continue"};
     private static final ClientIdMetadata CLIENT_ID_METADATA =
             new ClientIdMetadata(TEST_URL_TERMS_OF_SERVICE, TEST_URL_PRIVACY_POLICY);
 
@@ -161,7 +162,8 @@
                 .fetchImage(any(), any(Callback.class));
 
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false /* isAutoReauthn */);
+                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false /* isAutoReauthn */,
+                "signin" /* rpContext */);
 
         PropertyModel headerModel = mModel.get(ItemProperties.HEADER);
         assertEquals(HeaderType.SIGN_IN, headerModel.get(TYPE));
@@ -185,7 +187,8 @@
                 .fetchImage(any(), any(Callback.class));
 
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false /* isAutoReauthn */);
+                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false /* isAutoReauthn */,
+                "signin" /* rpContext */);
 
         PropertyModel headerModel = mModel.get(ItemProperties.HEADER);
         // Brand icon should be transparent placeholder icon. This is useful so that the header text
@@ -203,7 +206,7 @@
                 new IdentityProviderMetadata(Color.BLACK, Color.BLACK, "", TEST_CONFIG_URL);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
                 Arrays.asList(ANA), idpMetadataNoBrandIconUrl, CLIENT_ID_METADATA,
-                false /* isAutoReauthn */);
+                false /* isAutoReauthn */, "signin" /* rpContext */);
 
         PropertyModel headerModel = mModel.get(ItemProperties.HEADER);
         assertNull(headerModel.get(IDP_BRAND_ICON));
@@ -218,7 +221,7 @@
     public void testShowAccountSignUpHeader() {
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
                 Arrays.asList(NEW_USER), IDP_METADATA, CLIENT_ID_METADATA,
-                false /* isAutoReauthn */);
+                false /* isAutoReauthn */, "signin" /* rpContext */);
 
         PropertyModel headerModel = mModel.get(ItemProperties.HEADER);
         assertEquals(HeaderType.SIGN_IN, headerModel.get(TYPE));
@@ -227,7 +230,8 @@
     @Test
     public void testShowAccountsSetsAccountListAndRequestsAvatar() {
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         assertEquals("Incorrect item sheet count", 2, mSheetAccountItems.size());
         assertNull(mSheetAccountItems.get(0).model.get(AVATAR));
         assertNull(mSheetAccountItems.get(1).model.get(AVATAR));
@@ -243,7 +247,8 @@
     @Test
     public void testFetchAvatarUpdatesModel() {
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Collections.singletonList(CARL), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Collections.singletonList(CARL), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         assertEquals("Incorrect item sheet count", 1, mSheetAccountItems.size());
         assertEquals("Incorrect account", CARL, mSheetAccountItems.get(0).model.get(ACCOUNT));
         assertNull(mSheetAccountItems.get(0).model.get(AVATAR));
@@ -268,7 +273,8 @@
     @Test
     public void testShowAccountsFormatPslOrigins() {
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         assertEquals(3, countAllItems()); // Header + two Accounts
         assertEquals("Incorrect item sheet count", 2, mSheetAccountItems.size());
     }
@@ -276,14 +282,16 @@
     @Test
     public void testClearsAccountListWhenShowingAgain() {
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Collections.singletonList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Collections.singletonList(ANA), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         assertEquals(3, countAllItems()); // Header + Account + Continue Button
         assertEquals(1, mSheetAccountItems.size());
         assertEquals("Incorrect account", ANA, mSheetAccountItems.get(0).model.get(ACCOUNT));
 
         // Showing the sheet a second time should replace all changed accounts.
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Collections.singletonList(BOB), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Collections.singletonList(BOB), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         assertEquals(3, countAllItems()); // Header + Account + Continue Button
         assertEquals(1, mSheetAccountItems.size());
         assertEquals("Incorrect account", BOB, mSheetAccountItems.get(0).model.get(ACCOUNT));
@@ -293,7 +301,8 @@
     public void testShowAccountsSetsVisible() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA, CARL, BOB), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA, CARL, BOB), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         verify(mMockBottomSheetController, times(1)).requestShowContent(any(), eq(true));
 
         assertFalse(mMediator.wasDismissed());
@@ -303,7 +312,8 @@
     public void testCallsCallbackAndHidesOnSelectingItemDoesNotRecordIndexForSingleAccount() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false /* isAutoReauthn */,
+                "signin" /* rpContext */);
         // Do not let test inputs be ignored.
         mMediator.setComponentShowTime(-1000);
         assertFalse(mMediator.wasDismissed());
@@ -323,7 +333,8 @@
     public void testCallsCallbackAndHidesOnSelectingItem() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA, CARL), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA, CARL), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         // Do not let test inputs be ignored.
         mMediator.setComponentShowTime(-1000);
         assertFalse(mMediator.wasDismissed());
@@ -340,7 +351,8 @@
     public void testCallsDelegateAndHidesOnSingleAccountDismiss() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false /* isAutoReauthn */,
+                "signin" /* rpContext */);
         pressBack();
         verify(mMockDelegate).onDismissed(IdentityRequestDialogDismissReason.OTHER);
         assertTrue(mMediator.wasDismissed());
@@ -350,7 +362,8 @@
     public void testCallsDelegateAndHidesOnAccountPickerDismiss() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         pressBack();
         verify(mMockDelegate).onDismissed(IdentityRequestDialogDismissReason.OTHER);
         assertTrue(mMediator.wasDismissed());
@@ -360,7 +373,8 @@
     public void testCallsDelegateAndHidesOnAccountPickerSelectSignIn() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         mMediator.onAccountSelected(ANA);
         verify(mMockDelegate).onAccountSelected(TEST_CONFIG_URL, ANA);
         assertFalse(mMediator.wasDismissed());
@@ -372,7 +386,8 @@
     public void testShowsTosOnMultiAccountSelectSignUp() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA, NEW_USER), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA, NEW_USER), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         mMediator.onAccountSelected(NEW_USER);
 
         assertFalse(mMediator.wasDismissed());
@@ -386,7 +401,8 @@
     public void testShowsAccountPickerOnTosDismiss() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA, NEW_USER), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(ANA, NEW_USER), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         mMediator.onAccountSelected(NEW_USER);
 
         pressBack();
@@ -404,7 +420,8 @@
     public void testCallsDelegateAndHidesOnAutoReauthn() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, true);
+                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, true /* isAutoReauthn */,
+                "signin" /* rpContext */);
         // Auto reauthenticates if no action is taken.
         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
         verify(mMockDelegate).onAccountSelected(TEST_CONFIG_URL, ANA);
@@ -417,7 +434,8 @@
     public void testCallsDelegateAndHidesOnlyOnceWithAutoReauthn() {
         when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, true);
+                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, true /* isAutoReauthn */,
+                "signin" /* rpContext */);
         // Auto reauthenticates even if dismissed.
         pressBack();
         verify(mMockDelegate).onDismissed(IdentityRequestDialogDismissReason.OTHER);
@@ -431,7 +449,8 @@
     @Test
     public void testShowDataSharingConsentForSingleNewAccount() {
         mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(NEW_USER), IDP_METADATA, CLIENT_ID_METADATA, false);
+                Arrays.asList(NEW_USER), IDP_METADATA, CLIENT_ID_METADATA,
+                false /* isAutoReauthn */, "signin" /* rpContext */);
         // For new user we expect header + account + consent text + continue btn
         assertEquals(4, countAllItems());
         assertEquals("Incorrect item sheet count", 1, mSheetAccountItems.size());
@@ -451,25 +470,33 @@
 
     @Test
     public void testShowVerifySheetExplicitSignin() {
-        when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
-        mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(NEW_USER), IDP_METADATA, CLIENT_ID_METADATA,
-                false /* isAutoReauthn */);
-        mMediator.showVerifySheet(ANA);
+        for (String rpContext : RP_CONTEXTS) {
+            when(mMockBottomSheetController.requestShowContent(any(), anyBoolean()))
+                    .thenReturn(true);
+            mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
+                    Arrays.asList(NEW_USER), IDP_METADATA, CLIENT_ID_METADATA,
+                    false /* isAutoReauthn */, "signin" /* rpContext */);
+            mMediator.showVerifySheet(ANA);
 
-        assertEquals(1, mSheetAccountItems.size());
-        assertEquals(HeaderType.VERIFY, mModel.get(ItemProperties.HEADER).get(TYPE));
+            assertEquals(1, mSheetAccountItems.size());
+            assertEquals(HeaderType.VERIFY, mModel.get(ItemProperties.HEADER).get(TYPE));
+        }
     }
 
     @Test
     public void testShowVerifySheetAutoReauthn() {
-        when(mMockBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
-        // showVerifySheet is called in showAccounts when isAutoReauthn is true
-        mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
-                Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, true /* isAutoReauthn */);
+        for (String rpContext : RP_CONTEXTS) {
+            when(mMockBottomSheetController.requestShowContent(any(), anyBoolean()))
+                    .thenReturn(true);
+            // showVerifySheet is called in showAccounts when isAutoReauthn is true
+            mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, TEST_ETLD_PLUS_ONE_2,
+                    Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, true /* isAutoReauthn */,
+                    "signin" /* rpContext */);
 
-        assertEquals(1, mSheetAccountItems.size());
-        assertEquals(HeaderType.VERIFY_AUTO_REAUTHN, mModel.get(ItemProperties.HEADER).get(TYPE));
+            assertEquals(1, mSheetAccountItems.size());
+            assertEquals(
+                    HeaderType.VERIFY_AUTO_REAUTHN, mModel.get(ItemProperties.HEADER).get(TYPE));
+        }
     }
 
     private void pressBack() {
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java
index e154acf2..ec04c2b 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java
@@ -117,9 +117,9 @@
     @Override
     public void showAccounts(String topFrameEtldPlusOne, String iframeEtldPlusOne,
             String idpEtldPlusOne, List<Account> accounts, IdentityProviderMetadata idpMetadata,
-            ClientIdMetadata clientMetadata, boolean isAutoReauthn) {
+            ClientIdMetadata clientMetadata, boolean isAutoReauthn, String rpContext) {
         mMediator.showAccounts(topFrameEtldPlusOne, iframeEtldPlusOne, idpEtldPlusOne, accounts,
-                idpMetadata, clientMetadata, isAutoReauthn);
+                idpMetadata, clientMetadata, isAutoReauthn, rpContext);
     }
 
     @Override
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTest.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTest.java
index 3ab5ccc..90bba27f 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTest.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTest.java
@@ -94,9 +94,10 @@
     private static final GURL TEST_PROFILE_PIC =
             JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_1_WITH_PATH);
 
-    private static final Account ANA =
-            new Account("Ana", "ana@one.test", "Ana Doe", "Ana", TEST_PROFILE_PIC, true);
-    private static final Account BOB = new Account("Bob", "", "Bob", "", TEST_PROFILE_PIC, false);
+    private static final Account ANA = new Account("Ana", "ana@one.test", "Ana Doe", "Ana",
+            TEST_PROFILE_PIC, /*hints=*/new String[0], true);
+    private static final Account BOB =
+            new Account("Bob", "", "Bob", "", TEST_PROFILE_PIC, /*hints=*/new String[0], false);
 
     private static final IdentityProviderMetadata IDP_METADATA =
             new IdentityProviderMetadata(Color.BLACK, Color.BLACK, null, null);
@@ -140,7 +141,7 @@
         runOnUiThreadBlocking(() -> {
             mAccountSelection.showAccounts(EXAMPLE_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1,
                     TEST_ETLD_PLUS_ONE_2, Arrays.asList(ANA, BOB), IDP_METADATA, mClientIdMetadata,
-                    false);
+                    false /* isAutoReauthn */, "signin" /* rpContext */);
         });
         pollUiThread(() -> getBottomSheetState() == BottomSheetController.SheetState.FULL);
 
@@ -154,7 +155,7 @@
         runOnUiThreadBlocking(() -> {
             mAccountSelection.showAccounts(EXAMPLE_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1,
                     TEST_ETLD_PLUS_ONE_2, Arrays.asList(BOB), IDP_METADATA, mClientIdMetadata,
-                    false);
+                    false /* isAutoReauthn */, "signin" /* rpContext */);
         });
         pollUiThread(() -> getBottomSheetState() == BottomSheetController.SheetState.FULL);
 
@@ -212,7 +213,7 @@
         runOnUiThreadBlocking(() -> {
             mAccountSelection.showAccounts(EXAMPLE_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1,
                     TEST_ETLD_PLUS_ONE_2, Arrays.asList(ANA, BOB), IDP_METADATA, mClientIdMetadata,
-                    false);
+                    false /* isAutoReauthn */, "signin" /* rpContext */);
         });
         waitForEvent(mMockBridge).onDismissed(IdentityRequestDialogDismissReason.OTHER);
         verify(mMockBridge, never()).onAccountSelected(any(), any());
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java
index fcc923c..05ab115 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java
@@ -91,6 +91,7 @@
     private IdentityProviderMetadata mIdpMetadata;
     private Bitmap mBrandIcon;
     private ClientIdMetadata mClientMetadata;
+    private String mRpContext;
 
     // All of the user's accounts.
     private List<Account> mAccounts;
@@ -181,11 +182,11 @@
     private void handleBackPress() {
         mSelectedAccount = null;
         showAccountsInternal(mTopFrameForDisplay, mIframeForDisplay, mIdpForDisplay, mAccounts,
-                mIdpMetadata, mClientMetadata, /*isAutoReauthn=*/false);
+                mIdpMetadata, mClientMetadata, /*isAutoReauthn=*/false, mRpContext);
     }
 
     private PropertyModel createHeaderItem(HeaderType headerType, String topFrameForDisplay,
-            String iframeForDisplay, String idpForDisplay, IdentityProviderMetadata idpMetadata) {
+            String iframeForDisplay, String idpForDisplay, String rpContext) {
         Runnable closeOnClickRunnable = () -> {
             onDismissed(IdentityRequestDialogDismissReason.CLOSE_BUTTON);
 
@@ -202,6 +203,7 @@
                 .with(HeaderProperties.TOP_FRAME_FOR_DISPLAY, topFrameForDisplay)
                 .with(HeaderProperties.IFRAME_FOR_DISPLAY, iframeForDisplay)
                 .with(HeaderProperties.TYPE, headerType)
+                .with(HeaderProperties.RP_CONTEXT, rpContext)
                 .build();
     }
 
@@ -256,7 +258,7 @@
 
     void showAccounts(String topFrameForDisplay, String iframeForDisplay, String idpForDisplay,
             List<Account> accounts, IdentityProviderMetadata idpMetadata,
-            ClientIdMetadata clientMetadata, boolean isAutoReauthn) {
+            ClientIdMetadata clientMetadata, boolean isAutoReauthn, String rpContext) {
         if (!TextUtils.isEmpty(idpMetadata.getBrandIconUrl())) {
             // Use placeholder icon so that the header text wrapping does not change when the icon
             // is fetched.
@@ -267,7 +269,7 @@
 
         mSelectedAccount = accounts.size() == 1 ? accounts.get(0) : null;
         showAccountsInternal(topFrameForDisplay, iframeForDisplay, idpForDisplay, accounts,
-                idpMetadata, clientMetadata, isAutoReauthn);
+                idpMetadata, clientMetadata, isAutoReauthn, rpContext);
         setComponentShowTime(SystemClock.elapsedRealtime());
 
         if (!TextUtils.isEmpty(idpMetadata.getBrandIconUrl())) {
@@ -294,13 +296,14 @@
 
     private void showAccountsInternal(String topFrameForDisplay, String iframeForDisplay,
             String idpForDisplay, List<Account> accounts, IdentityProviderMetadata idpMetadata,
-            ClientIdMetadata clientMetadata, boolean isAutoReauthn) {
+            ClientIdMetadata clientMetadata, boolean isAutoReauthn, String rpContext) {
         mTopFrameForDisplay = topFrameForDisplay;
         mIframeForDisplay = iframeForDisplay;
         mIdpForDisplay = idpForDisplay;
         mAccounts = accounts;
         mIdpMetadata = idpMetadata;
         mClientMetadata = clientMetadata;
+        mRpContext = rpContext;
 
         if (mSelectedAccount != null) {
             accounts = Arrays.asList(mSelectedAccount);
@@ -344,7 +347,7 @@
 
     private void updateHeader() {
         PropertyModel headerModel = createHeaderItem(
-                mHeaderType, mTopFrameForDisplay, mIframeForDisplay, mIdpForDisplay, mIdpMetadata);
+                mHeaderType, mTopFrameForDisplay, mIframeForDisplay, mIdpForDisplay, mRpContext);
         mModel.set(ItemProperties.HEADER, headerModel);
     }
 
@@ -413,7 +416,7 @@
         mSelectedAccount = selectedAccount;
         if (oldSelectedAccount == null && !mSelectedAccount.isSignIn()) {
             showAccountsInternal(mTopFrameForDisplay, mIframeForDisplay, mIdpForDisplay, mAccounts,
-                    mIdpMetadata, mClientMetadata, /*isAutoReauthn=*/false);
+                    mIdpMetadata, mClientMetadata, /*isAutoReauthn=*/false, mRpContext);
             return;
         }
 
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java
index 888db76..60eda23 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java
@@ -70,9 +70,11 @@
                 new ReadableObjectPropertyKey<>("brand_icon");
         static final ReadableObjectPropertyKey<HeaderType> TYPE =
                 new ReadableObjectPropertyKey<>("type");
+        static final ReadableObjectPropertyKey<String> RP_CONTEXT =
+                new ReadableObjectPropertyKey<>("rp_context");
 
         static final PropertyKey[] ALL_KEYS = {CLOSE_ON_CLICK_LISTENER, IDP_FOR_DISPLAY,
-                TOP_FRAME_FOR_DISPLAY, IFRAME_FOR_DISPLAY, IDP_BRAND_ICON, TYPE};
+                TOP_FRAME_FOR_DISPLAY, IFRAME_FOR_DISPLAY, IDP_BRAND_ICON, TYPE, RP_CONTEXT};
 
         private HeaderProperties() {}
     }
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java
index 8e358a83..8c9ddf1 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java
@@ -296,7 +296,8 @@
     static void bindHeaderView(PropertyModel model, View view, PropertyKey key) {
         if (key == HeaderProperties.TOP_FRAME_FOR_DISPLAY
                 || key == HeaderProperties.IFRAME_FOR_DISPLAY
-                || key == HeaderProperties.IDP_FOR_DISPLAY || key == HeaderProperties.TYPE) {
+                || key == HeaderProperties.IDP_FOR_DISPLAY || key == HeaderProperties.TYPE
+                || key == HeaderProperties.RP_CONTEXT) {
             Resources resources = view.getResources();
             TextView headerTitleText = view.findViewById(R.id.header_title);
             TextView headerSubtitleText = view.findViewById(R.id.header_subtitle);
@@ -316,7 +317,8 @@
             }
 
             String title = computeHeaderTitle(resources, headerType, rpUrlForDisplayInTitle,
-                    model.get(HeaderProperties.IDP_FOR_DISPLAY));
+                    model.get(HeaderProperties.IDP_FOR_DISPLAY),
+                    model.get(HeaderProperties.RP_CONTEXT));
             headerTitleText.setText(title);
 
             // Make instructions for closing the bottom sheet part of the header's content
@@ -379,8 +381,8 @@
         return R.string.verify_sheet_title_auto_reauthn;
     }
 
-    private static String computeHeaderTitle(
-            Resources resources, HeaderProperties.HeaderType type, String rpUrl, String idpUrl) {
+    private static String computeHeaderTitle(Resources resources, HeaderProperties.HeaderType type,
+            String rpUrl, String idpUrl, String rpContext) {
         if (type == HeaderProperties.HeaderType.VERIFY) {
             return resources.getString(getVerifyHeaderStringId());
         }
@@ -388,7 +390,20 @@
             return resources.getString(getVerifyHeaderAutoReauthnStringId());
         }
         @StringRes
-        int titleStringId = R.string.account_selection_sheet_title_explicit;
+        int titleStringId;
+        switch (rpContext) {
+            case "signup":
+                titleStringId = R.string.account_selection_sheet_title_explicit_signup;
+                break;
+            case "use":
+                titleStringId = R.string.account_selection_sheet_title_explicit_use;
+                break;
+            case "continue":
+                titleStringId = R.string.account_selection_sheet_title_explicit_continue;
+                break;
+            default:
+                titleStringId = R.string.account_selection_sheet_title_explicit_signin;
+        }
         return String.format(resources.getString(titleStringId), rpUrl, idpUrl);
     }
 
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java
index 21c20b5e..cad8178 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java
@@ -64,11 +64,26 @@
     private static final GURL TEST_PROFILE_PIC = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL);
     private static final GURL TEST_CONFIG_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_1);
 
-    private static final Account ANA =
-            new Account("Ana", "ana@email.example", "Ana Doe", "Ana", TEST_PROFILE_PIC, true);
+    private static final Account ANA = new Account("Ana", "ana@email.example", "Ana Doe", "Ana",
+            TEST_PROFILE_PIC, /*hints=*/new String[0], true);
     private static final Account NO_ONE =
-            new Account("", "", "No Subject", "", TEST_PROFILE_PIC, true);
-    private static final Account BOB = new Account("Bob", "", "Bob", "", TEST_PROFILE_PIC, true);
+            new Account("", "", "No Subject", "", TEST_PROFILE_PIC, /*hints=*/new String[0], true);
+    private static final Account BOB =
+            new Account("Bob", "", "Bob", "", TEST_PROFILE_PIC, /*hints=*/new String[0], true);
+
+    private class RpContext {
+        public String mValue;
+        public int mTitleId;
+        RpContext(String value, int titleId) {
+            mValue = value;
+            mTitleId = titleId;
+        }
+    }
+    private final RpContext[] mRpContexts = new RpContext[] {
+            new RpContext("signin", R.string.account_selection_sheet_title_explicit_signin),
+            new RpContext("signup", R.string.account_selection_sheet_title_explicit_signup),
+            new RpContext("use", R.string.account_selection_sheet_title_explicit_use),
+            new RpContext("continue", R.string.account_selection_sheet_title_explicit_continue)};
 
     @Rule
     public ActivityScenarioRule<TestActivity> mActivityScenarioRule =
@@ -105,14 +120,15 @@
                         .with(HeaderProperties.TOP_FRAME_FOR_DISPLAY, "example.org")
                         .with(HeaderProperties.IFRAME_FOR_DISPLAY, "")
                         .with(HeaderProperties.IDP_FOR_DISPLAY, "idp.org")
+                        .with(HeaderProperties.RP_CONTEXT, "signin")
                         .build());
         assertEquals(View.VISIBLE, mContentView.getVisibility());
         TextView title = mContentView.findViewById(R.id.header_title);
         TextView subtitle = mContentView.findViewById(R.id.header_subtitle);
 
         assertEquals("Incorrect title",
-                mResources.getString(
-                        R.string.account_selection_sheet_title_explicit, "example.org", "idp.org"),
+                mResources.getString(R.string.account_selection_sheet_title_explicit_signin,
+                        "example.org", "idp.org"),
                 title.getText());
         assertEquals("Incorrect subtitle", "", subtitle.getText());
     }
@@ -125,13 +141,14 @@
                         .with(HeaderProperties.TOP_FRAME_FOR_DISPLAY, "example.org")
                         .with(HeaderProperties.IFRAME_FOR_DISPLAY, "iframe-example.org")
                         .with(HeaderProperties.IDP_FOR_DISPLAY, "idp.org")
+                        .with(HeaderProperties.RP_CONTEXT, "signin")
                         .build());
         assertEquals(View.VISIBLE, mContentView.getVisibility());
         TextView title = mContentView.findViewById(R.id.header_title);
         TextView subtitle = mContentView.findViewById(R.id.header_subtitle);
 
         assertEquals("Incorrect title",
-                mResources.getString(R.string.account_selection_sheet_title_explicit,
+                mResources.getString(R.string.account_selection_sheet_title_explicit_signin,
                         "iframe-example.org", "idp.org"),
                 title.getText());
         assertEquals("Incorrect subtitle",
@@ -147,6 +164,7 @@
                         .with(HeaderProperties.TYPE, HeaderType.VERIFY)
                         .with(HeaderProperties.TOP_FRAME_FOR_DISPLAY, "example.org")
                         .with(HeaderProperties.IDP_FOR_DISPLAY, "idp.org")
+                        .with(HeaderProperties.RP_CONTEXT, "signin")
                         .build());
         assertEquals(View.VISIBLE, mContentView.getVisibility());
         TextView title = mContentView.findViewById(R.id.header_title);
@@ -164,6 +182,7 @@
                         .with(HeaderProperties.TYPE, HeaderType.VERIFY_AUTO_REAUTHN)
                         .with(HeaderProperties.TOP_FRAME_FOR_DISPLAY, "example.org")
                         .with(HeaderProperties.IDP_FOR_DISPLAY, "idp.org")
+                        .with(HeaderProperties.RP_CONTEXT, "signin")
                         .build());
         assertEquals(View.VISIBLE, mContentView.getVisibility());
         TextView title = mContentView.findViewById(R.id.header_title);
@@ -267,6 +286,53 @@
         assertEquals(expectedTextColor, continueButton.getTextColors().getDefaultColor());
     }
 
+    @Test
+    public void testRpContextTitleDisplayedWithoutIframe() {
+        for (RpContext rpContext : mRpContexts) {
+            mModel.set(ItemProperties.HEADER,
+                    new PropertyModel.Builder(HeaderProperties.ALL_KEYS)
+                            .with(HeaderProperties.TYPE, HeaderType.SIGN_IN)
+                            .with(HeaderProperties.TOP_FRAME_FOR_DISPLAY, "example.org")
+                            .with(HeaderProperties.IFRAME_FOR_DISPLAY, "")
+                            .with(HeaderProperties.IDP_FOR_DISPLAY, "idp.org")
+                            .with(HeaderProperties.RP_CONTEXT, rpContext.mValue)
+                            .build());
+            assertEquals(View.VISIBLE, mContentView.getVisibility());
+            TextView title = mContentView.findViewById(R.id.header_title);
+            TextView subtitle = mContentView.findViewById(R.id.header_subtitle);
+
+            assertEquals("Incorrect title",
+                    mResources.getString(rpContext.mTitleId, "example.org", "idp.org"),
+                    title.getText());
+            assertEquals("Incorrect subtitle", "", subtitle.getText());
+        }
+    }
+
+    @Test
+    public void testRpContextTitleDisplayedWithIframe() {
+        for (RpContext rpContext : mRpContexts) {
+            mModel.set(ItemProperties.HEADER,
+                    new PropertyModel.Builder(HeaderProperties.ALL_KEYS)
+                            .with(HeaderProperties.TYPE, HeaderType.SIGN_IN)
+                            .with(HeaderProperties.TOP_FRAME_FOR_DISPLAY, "example.org")
+                            .with(HeaderProperties.IFRAME_FOR_DISPLAY, "iframe-example.org")
+                            .with(HeaderProperties.IDP_FOR_DISPLAY, "idp.org")
+                            .with(HeaderProperties.RP_CONTEXT, rpContext.mValue)
+                            .build());
+            assertEquals(View.VISIBLE, mContentView.getVisibility());
+            TextView title = mContentView.findViewById(R.id.header_title);
+            TextView subtitle = mContentView.findViewById(R.id.header_subtitle);
+
+            assertEquals("Incorrect title",
+                    mResources.getString(rpContext.mTitleId, "iframe-example.org", "idp.org"),
+                    title.getText());
+            assertEquals("Incorrect subtitle",
+                    mResources.getString(
+                            R.string.account_selection_sheet_subtitle_explicit, "example.org"),
+                    subtitle.getText());
+        }
+    }
+
     private RecyclerView getAccounts() {
         return mContentView.findViewById(R.id.sheet_item_list);
     }
diff --git a/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionComponent.java b/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionComponent.java
index fa35208..0238c60f 100644
--- a/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionComponent.java
+++ b/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionComponent.java
@@ -44,10 +44,13 @@
      * @param idpMetadata Metadata related to identity provider.
      * @param clientMetadata Metadata related to relying party.
      * @param isAutoReauthn A {@link boolean} that represents whether this is an auto re-authn flow.
+     * @param rpContext is a {@link String} representing the desired text to be used in the title of
+     *         the FedCM prompt: "signin", "continue", etc.
+
      */
     void showAccounts(String topFrameEtldPlusOne, String iframeEtldPlusOne, String idpEtldPlusOne,
             List<Account> accounts, IdentityProviderMetadata idpMetadata,
-            ClientIdMetadata clientMetadata, boolean isAutoReauthn);
+            ClientIdMetadata clientMetadata, boolean isAutoReauthn, String rpContext);
 
     /**
      * Closes the outstanding bottom sheet.
diff --git a/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/data/Account.java b/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/data/Account.java
index b4c3bf3..53477c84 100644
--- a/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/data/Account.java
+++ b/chrome/browser/ui/android/webid/java/src/org/chromium/chrome/browser/ui/android/webid/data/Account.java
@@ -17,6 +17,7 @@
     private final String mName;
     private final String mGivenName;
     private final GURL mPictureUrl;
+    private final String[] mHints;
     private final boolean mIsSignIn;
 
     /**
@@ -27,13 +28,14 @@
      */
     @CalledByNative
     public Account(String subject, String email, String name, String givenName, GURL pictureUrl,
-            boolean isSignIn) {
+            String[] hints, boolean isSignIn) {
         assert subject != null : "Account subject is null!";
         mSubject = subject;
         mEmail = email;
         mName = name;
         mGivenName = givenName;
         mPictureUrl = pictureUrl;
+        mHints = hints;
         mIsSignIn = isSignIn;
     }
 
@@ -57,12 +59,16 @@
         return mPictureUrl;
     }
 
+    public String[] getHints() {
+        return mHints;
+    }
+
     public boolean isSignIn() {
         return mIsSignIn;
     }
 
-    // Return all the String fields. Note that this excludes non-string fields in particular
-    // mPictureUrl.
+    // Return all the String fields. Note that this excludes non-string fields, in particular
+    // mPictureUrl and mHints.
     public String[] getStringFields() {
         return new String[] {mSubject, mEmail, mName, mGivenName};
     }
diff --git a/chrome/browser/ui/ash/desks/desks_client_browsertest.cc b/chrome/browser/ui/ash/desks/desks_client_browsertest.cc
index b10e1dd..9370ad6 100644
--- a/chrome/browser/ui/ash/desks/desks_client_browsertest.cc
+++ b/chrome/browser/ui/ash/desks/desks_client_browsertest.cc
@@ -1613,7 +1613,7 @@
   aura::Window* window = browser()->window()->GetNativeWindow();
 
   // Snap the window to the left.
-  const ash::WMEvent left_snap_event(ash::WM_EVENT_SNAP_PRIMARY);
+  const ash::WindowSnapWMEvent left_snap_event(ash::WM_EVENT_SNAP_PRIMARY);
   ash::WindowState::Get(window)->OnWMEvent(&left_snap_event);
   ASSERT_EQ(gfx::Rect(1000, 1000), window->GetBoundsInScreen());
 
diff --git a/chrome/browser/ui/ash/thumbnail_loader.cc b/chrome/browser/ui/ash/thumbnail_loader.cc
index e1a73a5..417fe30 100644
--- a/chrome/browser/ui/ash/thumbnail_loader.cc
+++ b/chrome/browser/ui/ash/thumbnail_loader.cc
@@ -25,6 +25,7 @@
 #include "extensions/browser/api/messaging/channel_endpoint.h"
 #include "extensions/browser/api/messaging/message_service.h"
 #include "extensions/browser/api/messaging/native_message_host.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/api/messaging/messaging_endpoint.h"
 #include "extensions/common/api/messaging/port_id.h"
 #include "extensions/common/api/messaging/serialization_format.h"
@@ -434,7 +435,8 @@
       extensions::ChannelEndpoint(profile_), port_id,
       extensions::MessagingEndpoint::ForNativeApp(kNativeMessageHostName),
       std::move(native_message_port), file_manager::kImageLoaderExtensionId,
-      GURL(), std::string() /* channel_name */);
+      GURL(), extensions::ChannelType::kNative,
+      std::string() /* channel_name */);
 }
 
 void ThumbnailLoader::OnThumbnailLoaded(
diff --git a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc
index f670932..c4b31bf 100644
--- a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc
@@ -33,6 +33,7 @@
 #include "components/bookmarks/browser/bookmark_client.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
+#include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
 #include "components/bookmarks/common/bookmark_metrics.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
 #include "components/bookmarks/managed/managed_bookmark_service.h"
@@ -309,6 +310,7 @@
       base::RecordAction(UserMetricsAction("BookmarkBar_ContextMenu_Remove"));
       RecordBookmarkRemoved(opened_from_);
 
+      bookmarks::ScopedGroupBookmarkActions group_remove(model_);
       for (const auto* node : selection_)
         model_->Remove(node, bookmarks::metrics::BookmarkEditSource::kUser);
       selection_.clear();
diff --git a/chrome/browser/ui/browser_element_identifiers.cc b/chrome/browser/ui/browser_element_identifiers.cc
index 9b338be..433cd50 100644
--- a/chrome/browser/ui/browser_element_identifiers.cc
+++ b/chrome/browser/ui/browser_element_identifiers.cc
@@ -35,6 +35,7 @@
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kPriceTrackingChipElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kPriceTrackingBookmarkViewElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kReadLaterSidePanelWebViewElementId);
+DEFINE_ELEMENT_IDENTIFIER_VALUE(kSavedTabGroupBarElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kSavedTabGroupButtonElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kSidePanelButtonElementId);
 DEFINE_ELEMENT_IDENTIFIER_VALUE(kSidePanelElementId);
diff --git a/chrome/browser/ui/browser_element_identifiers.h b/chrome/browser/ui/browser_element_identifiers.h
index e4ae600c..83b3dd0 100644
--- a/chrome/browser/ui/browser_element_identifiers.h
+++ b/chrome/browser/ui/browser_element_identifiers.h
@@ -44,6 +44,7 @@
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kPriceTrackingChipElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kPriceTrackingBookmarkViewElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kReadLaterSidePanelWebViewElementId);
+DECLARE_ELEMENT_IDENTIFIER_VALUE(kSavedTabGroupBarElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kSavedTabGroupButtonElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kSidePanelButtonElementId);
 DECLARE_ELEMENT_IDENTIFIER_VALUE(kSidePanelElementId);
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h
index a14d4b61..60fff5a 100644
--- a/chrome/browser/ui/color/chrome_color_id.h
+++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -136,6 +136,12 @@
   E_CPONLY(kColorNewTabButtonFocusRing) \
   E_CPONLY(kColorNewTabButtonInkDropFrameActive) \
   E_CPONLY(kColorNewTabButtonInkDropFrameInactive) \
+  /* New tab button colors for ChromeRefresh.*/ \
+  /* TODO (crbug.com/1399942) remove when theming works */ \
+  E_CPONLY(kColorNewTabButtonCRForegroundFrameActive) \
+  E_CPONLY(kColorNewTabButtonCRForegroundFrameInactive) \
+  E_CPONLY(kColorNewTabButtonCRBackgroundFrameActive) \
+  E_CPONLY(kColorNewTabButtonCRBackgroundFrameInactive) \
   /* New Tab Page colors. */ \
   E_CPONLY(kColorNewTabPageActionButtonBackground) \
   E_CPONLY(kColorNewTabPageActionButtonBorder) \
@@ -340,6 +346,7 @@
   E_CPONLY(kColorSidePanelFilterChipBackgroundHover) \
   E_CPONLY(kColorSidePanelFilterChipBackgroundSelected) \
   E_CPONLY(kColorSidePanelScrollbarThumb) \
+  E_CPONLY(kColorSidePanelTextfieldBackgroundHover) \
   E_CPONLY(kColorSidePanelTextfieldBorder) \
   /* Status bubble colors. */ \
   E_CPONLY(kColorStatusBubbleBackgroundFrameActive) \
diff --git a/chrome/browser/ui/color/material_chrome_color_mixer.cc b/chrome/browser/ui/color/material_chrome_color_mixer.cc
index 9233b4eb..3906f884 100644
--- a/chrome/browser/ui/color/material_chrome_color_mixer.cc
+++ b/chrome/browser/ui/color/material_chrome_color_mixer.cc
@@ -55,6 +55,17 @@
   mixer[kColorExtensionIconBadgeBackgroundDefault] =
       ui::PickGoogleColor(ui::kColorSysPrimary, kColorToolbar,
                           color_utils::kMinimumVisibleContrastRatio);
+  mixer[kColorFeaturePromoBubbleBackground] = {ui::kColorSysPrimary};
+  mixer[kColorFeaturePromoBubbleButtonBorder] = {
+      kColorFeaturePromoBubbleForeground};
+  mixer[kColorFeaturePromoBubbleCloseButtonInkDrop] =
+      AdjustHighlightColorForContrast(kColorFeaturePromoBubbleForeground,
+                                      kColorFeaturePromoBubbleBackground);
+  mixer[kColorFeaturePromoBubbleDefaultButtonBackground] = {
+      kColorFeaturePromoBubbleForeground};
+  mixer[kColorFeaturePromoBubbleDefaultButtonForeground] = {
+      kColorFeaturePromoBubbleBackground};
+  mixer[kColorFeaturePromoBubbleForeground] = {ui::kColorSysOnPrimary};
   mixer[kColorFlyingIndicatorBackground] = {kColorToolbar};
   mixer[kColorFlyingIndicatorForeground] = {kColorToolbarButtonIcon};
   mixer[kColorFrameCaptionActive] = {ui::kColorSysOnHeaderPrimary};
diff --git a/chrome/browser/ui/color/material_side_panel_color_mixer.cc b/chrome/browser/ui/color/material_side_panel_color_mixer.cc
index 7a0615d9..a6494ca 100644
--- a/chrome/browser/ui/color/material_side_panel_color_mixer.cc
+++ b/chrome/browser/ui/color/material_side_panel_color_mixer.cc
@@ -38,5 +38,7 @@
   mixer[kColorSidePanelFilterChipBackgroundSelected] = {
       ui::kColorSysTonalContainer};
 
+  mixer[kColorSidePanelTextfieldBackgroundHover] = {
+      ui::kColorSysStateHoverOnSubtle};
   mixer[kColorSidePanelTextfieldBorder] = {ui::kColorSysNeutralOutline};
 }
diff --git a/chrome/browser/ui/color/material_tab_strip_color_mixer.cc b/chrome/browser/ui/color/material_tab_strip_color_mixer.cc
index 6fab445..5f1661f 100644
--- a/chrome/browser/ui/color/material_tab_strip_color_mixer.cc
+++ b/chrome/browser/ui/color/material_tab_strip_color_mixer.cc
@@ -59,13 +59,18 @@
       ui::SetAlpha(ui::kColorSysOnSurface, kWebUiTabStripTabSeparatorAlpha);
   mixer[kColorWebUiTabStripTabText] = {ui::kColorSysOnSurface};
 
+  // TabDivider colors.
+  mixer[kColorTabDividerFrameActive] = {ui::kColorSysOnHeaderDivider};
+  mixer[kColorTabDividerFrameInactive] = {ui::kColorSysOnHeaderDividerInactive};
+
   // Tabstrip Button colors.
-  mixer[kColorNewTabButtonForegroundFrameActive] = {
+  mixer[kColorNewTabButtonCRForegroundFrameActive] = {
       ui::kColorSysOnSurfacePrimary};
-  mixer[kColorNewTabButtonForegroundFrameInactive] = {
+  mixer[kColorNewTabButtonCRForegroundFrameInactive] = {
       ui::kColorSysOnSurfacePrimaryInactive};
-  mixer[kColorNewTabButtonBackgroundFrameActive] = {
+  mixer[kColorNewTabButtonCRBackgroundFrameActive] = {
       ui::kColorSysHeaderContainer};
-  mixer[kColorNewTabButtonBackgroundFrameInactive] = {
+  mixer[kColorNewTabButtonCRBackgroundFrameInactive] = {
       ui::kColorSysHeaderContainerInactive};
+  // MISSING 2
 }
diff --git a/chrome/browser/ui/color/tab_strip_color_mixer.cc b/chrome/browser/ui/color/tab_strip_color_mixer.cc
index 863116d..3c03078 100644
--- a/chrome/browser/ui/color/tab_strip_color_mixer.cc
+++ b/chrome/browser/ui/color/tab_strip_color_mixer.cc
@@ -141,13 +141,10 @@
   mixer[kColorTabDividerFrameActive] = {kColorToolbar};
   mixer[kColorTabDividerFrameInactive] = {kColorToolbar};
 
-  // TODO (crbug.com/1399942): update to respect original values once theming is
-  // correctly supported.
-  mixer[kColorNewTabButtonForegroundFrameActive] = {kColorToolbarButtonIcon};
-  mixer[kColorNewTabButtonForegroundFrameInactive] = {
-      kColorToolbarButtonIconInactive};
-  mixer[kColorNewTabButtonBackgroundFrameActive] = {kColorToolbar};
-  mixer[kColorNewTabButtonBackgroundFrameInactive] = {kColorToolbar};
+  mixer[kColorNewTabButtonBackgroundFrameActive] = {
+      kColorTabBackgroundInactiveFrameActive};
+  mixer[kColorNewTabButtonBackgroundFrameInactive] = {
+      kColorTabBackgroundInactiveFrameInactive};
   mixer[kColorNewTabButtonFocusRing] = ui::PickGoogleColorTwoBackgrounds(
       ui::kColorFocusableBorderFocused,
       ui::GetResultingPaintColor(kColorNewTabButtonBackgroundFrameActive,
@@ -158,6 +155,14 @@
   mixer[kColorNewTabButtonInkDropFrameInactive] =
       ui::GetColorWithMaxContrast(kColorNewTabButtonBackgroundFrameInactive);
 
+  // TODO (crbug.com/1399942): consolidate the new tab button color ids once the
+  // refresh flag is enabled by default.
+  mixer[kColorNewTabButtonCRForegroundFrameActive] = {kColorToolbarButtonIcon};
+  mixer[kColorNewTabButtonCRForegroundFrameInactive] = {
+      kColorToolbarButtonIconInactive};
+  mixer[kColorNewTabButtonCRBackgroundFrameActive] = {kColorToolbar};
+  mixer[kColorNewTabButtonCRBackgroundFrameInactive] = {kColorToolbar};
+
   /* WebUI Tab Strip colors. */
   // TODO(https://crbug.com/1060398): Update the tab strip color to respond
   // appopriately to activation changes.
diff --git a/chrome/browser/ui/commander/simple_command_source.cc b/chrome/browser/ui/commander/simple_command_source.cc
index 727a38b..fd52cef5 100644
--- a/chrome/browser/ui/commander/simple_command_source.cc
+++ b/chrome/browser/ui/commander/simple_command_source.cc
@@ -62,6 +62,7 @@
       {IDC_FOCUS_TOOLBAR, u"Focus toolbar"},
       {IDC_OPEN_FILE, u"Open file"},
       {IDC_TASK_MANAGER, u"Show task manager"},
+      {IDC_TRANSLATE_PAGE, u"Google Translate"},
       {IDC_SHOW_BOOKMARK_MANAGER, u"Show bookmark manager"},
       {IDC_SHOW_DOWNLOADS, u"Show downloads"},
       {IDC_CLEAR_BROWSING_DATA, u"Clear browsing data"},
diff --git a/chrome/browser/ui/extensions/create_side_panel_manager.h b/chrome/browser/ui/extensions/create_side_panel_manager.h
deleted file mode 100644
index 295d918..0000000
--- a/chrome/browser/ui/extensions/create_side_panel_manager.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2023 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_EXTENSIONS_CREATE_SIDE_PANEL_MANAGER_H_
-#define CHROME_BROWSER_UI_EXTENSIONS_CREATE_SIDE_PANEL_MANAGER_H_
-
-class Profile;
-
-namespace content {
-class WebContents;
-}  // namespace content
-
-namespace extensions {
-
-// Implemented by extension_side_panel_manager.cc in views/.
-void CreateSidePanelManagerForWebContents(Profile* profile,
-                                          content::WebContents* web_contents);
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_UI_EXTENSIONS_CREATE_SIDE_PANEL_MANAGER_H_
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc
index f96fa86a..5b6c264 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -16,6 +16,7 @@
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/api/commands/command_service.h"
+#include "chrome/browser/extensions/api/side_panel/side_panel_service.h"
 #include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/extensions/extension_view.h"
 #include "chrome/browser/extensions/extension_view_host.h"
@@ -25,6 +26,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/extensions/extension_action_platform_delegate.h"
 #include "chrome/browser/ui/extensions/extension_popup_types.h"
+#include "chrome/browser/ui/extensions/extension_side_panel_utils.h"
 #include "chrome/browser/ui/extensions/extensions_container.h"
 #include "chrome/browser/ui/extensions/icon_with_badge_image_source.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h"
@@ -265,18 +267,28 @@
 
 bool ExtensionActionViewController::IsEnabled(
     content::WebContents* web_contents) const {
-  if (!ExtensionIsValid())
+  if (!ExtensionIsValid()) {
     return false;
+  }
+
+  int tab_id = sessions::SessionTabHelper::IdForTab(web_contents).id();
+  if (extension_action_->GetIsVisible(tab_id)) {
+    return true;
+  }
 
   extensions::SitePermissionsHelper::SiteInteraction site_interaction =
       GetSiteInteraction(web_contents);
+  if (site_interaction ==
+          extensions::SitePermissionsHelper::SiteInteraction::kWithheld ||
+      site_interaction ==
+          extensions::SitePermissionsHelper::SiteInteraction::kActiveTab) {
+    return true;
+  }
 
-  return extension_action_->GetIsVisible(
-             sessions::SessionTabHelper::IdForTab(web_contents).id()) ||
-         site_interaction ==
-             extensions::SitePermissionsHelper::SiteInteraction::kWithheld ||
-         site_interaction ==
-             extensions::SitePermissionsHelper::SiteInteraction::kActiveTab;
+  extensions::SidePanelService* side_panel_service =
+      extensions::SidePanelService::Get(browser_->profile());
+  return side_panel_service &&
+         side_panel_service->HasSidePanelActionForTab(*extension(), tab_id);
 }
 
 bool ExtensionActionViewController::IsShowingPopup() const {
@@ -361,11 +373,16 @@
   // This method is only called to execute an action by the user, so we can
   // always grant tab permissions.
   constexpr bool kGrantTabPermissions = true;
-  if (action_runner->RunAction(extension(), kGrantTabPermissions) ==
-      extensions::ExtensionAction::ACTION_SHOW_POPUP) {
+  extensions::ExtensionAction::ShowAction action =
+      action_runner->RunAction(extension(), kGrantTabPermissions);
+
+  if (action == extensions::ExtensionAction::ACTION_SHOW_POPUP) {
     constexpr bool kByUser = true;
     GetPreferredPopupViewController()->TriggerPopup(
         PopupShowAction::kShow, kByUser, ShowPopupCallback());
+  } else if (action == extensions::ExtensionAction::ACTION_TOGGLE_SIDE_PANEL) {
+    extensions::side_panel_util::ToggleExtensionSidePanel(browser_,
+                                                          extension()->id());
   }
 }
 
@@ -610,10 +627,16 @@
   // We only grayscale the icon if it cannot interact with the page and the icon
   // is disabled.
   bool action_is_visible = extension_action_->GetIsVisible(tab_id);
+
+  extensions::SidePanelService* side_panel_service =
+      extensions::SidePanelService::Get(browser_->profile());
+  bool has_side_panel_action =
+      side_panel_service &&
+      side_panel_service->HasSidePanelActionForTab(*extension(), tab_id);
   bool grayscale =
       GetSiteInteraction(web_contents) ==
           extensions::SitePermissionsHelper::SiteInteraction::kNone &&
-      !action_is_visible;
+      !action_is_visible && !has_side_panel_action;
   image_source->set_grayscale(grayscale);
 
   if (base::FeatureList::IsEnabled(
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
index 6acdbea..d983b39 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/extensions/api/side_panel/side_panel_service.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/extensions/extension_action_test_util.h"
@@ -30,6 +31,7 @@
 #include "chrome/browser/ui/extensions/icon_with_badge_image_source.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
+#include "chrome/common/extensions/api/side_panel.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "components/sessions/content/session_tab_helper.h"
@@ -55,6 +57,15 @@
 using UserSiteSetting = extensions::PermissionsManager::UserSiteSetting;
 using HoverCardState = ToolbarActionViewController::HoverCardState;
 
+namespace {
+
+std::unique_ptr<KeyedService> BuildSidePanelService(
+    content::BrowserContext* context) {
+  return std::make_unique<extensions::SidePanelService>(context);
+}
+
+}  // namespace
+
 class ExtensionActionViewControllerUnitTest : public BrowserWithTestWindowTest {
  public:
   ExtensionActionViewControllerUnitTest() = default;
@@ -989,3 +1000,79 @@
   EXPECT_EQ(GetHoverCardSiteAccessState(controllerC, web_contents),
             HoverCardState::SiteAccess::kAllExtensionsAllowed);
 }
+
+class ExtensionActionViewControllerWithSidePanelUnitTest
+    : public ExtensionActionViewControllerUnitTest {
+ public:
+  ExtensionActionViewControllerWithSidePanelUnitTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        extensions_features::kExtensionSidePanelIntegration);
+  }
+
+  void SetUp() override {
+    ExtensionActionViewControllerUnitTest::SetUp();
+    extensions::SidePanelService::GetFactoryInstance()->SetTestingFactory(
+        profile(), base::BindRepeating(&BuildSidePanelService));
+  }
+
+ protected:
+  extensions::SidePanelService* side_panel_service() {
+    return extensions::SidePanelService::Get(profile());
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Test that the extension action is enabled if opening the side panel on icon
+// click is enabled and the extension has a side panel for the current tab.
+TEST_F(ExtensionActionViewControllerWithSidePanelUnitTest,
+       ActionEnabledIfSidePanelPresent) {
+  scoped_refptr<const extensions::Extension> extension =
+      extensions::ExtensionBuilder("just side panel")
+          .SetLocation(ManifestLocation::kInternal)
+          .SetManifestVersion(3)
+          .AddPermission("sidePanel")
+          .Build();
+
+  extension_service()->GrantPermissions(extension.get());
+  extension_service()->AddExtension(extension.get());
+  side_panel_service()->SetOpenSidePanelOnIconClick(extension->id(), true);
+
+  ExtensionActionViewController* const action_controller =
+      GetViewControllerForId(extension->id());
+  ASSERT_TRUE(action_controller);
+  EXPECT_EQ(extension.get(), action_controller->extension());
+
+  AddTab(browser(), GURL("https://www.chromium.org/"));
+  content::WebContents* web_contents = GetActiveWebContents();
+  int tab_id = sessions::SessionTabHelper::IdForTab(web_contents).id();
+
+  // If the preference is true but there is no side panel for the current tab,
+  // the action should be disabled.
+  std::unique_ptr<IconWithBadgeImageSource> image_source =
+      action_controller->GetIconImageSourceForTesting(web_contents,
+                                                      view_size());
+  EXPECT_TRUE(image_source->grayscale());
+  EXPECT_FALSE(action_controller->IsEnabled(web_contents));
+
+  // Set a side panel for the current tab. This should enable the extension's
+  // action.
+  extensions::api::side_panel::PanelOptions options;
+  options.enabled = true;
+  options.path = "panel.html";
+  options.tab_id = tab_id;
+  side_panel_service()->SetOptions(*extension, std::move(options));
+
+  image_source = action_controller->GetIconImageSourceForTesting(web_contents,
+                                                                 view_size());
+  EXPECT_FALSE(image_source->grayscale());
+  EXPECT_TRUE(action_controller->IsEnabled(web_contents));
+
+  // Setting the preference to false should disable the extension's action.
+  side_panel_service()->SetOpenSidePanelOnIconClick(extension->id(), false);
+  image_source = action_controller->GetIconImageSourceForTesting(web_contents,
+                                                                 view_size());
+  EXPECT_TRUE(image_source->grayscale());
+  EXPECT_FALSE(action_controller->IsEnabled(web_contents));
+}
diff --git a/chrome/browser/ui/extensions/extension_side_panel_utils.h b/chrome/browser/ui/extensions/extension_side_panel_utils.h
new file mode 100644
index 0000000..b388d57
--- /dev/null
+++ b/chrome/browser/ui/extensions/extension_side_panel_utils.h
@@ -0,0 +1,29 @@
+// Copyright 2023 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_EXTENSIONS_EXTENSION_SIDE_PANEL_UTILS_H_
+#define CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_SIDE_PANEL_UTILS_H_
+
+#include "extensions/common/extension_id.h"
+
+class Browser;
+class Profile;
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace extensions::side_panel_util {
+
+// Implemented by extension_side_panel_utils.cc in views/.
+void CreateSidePanelManagerForWebContents(Profile* profile,
+                                          content::WebContents* web_contents);
+
+// Implemented by extension_side_panel_utils.cc in views/.
+void ToggleExtensionSidePanel(Browser* browser,
+                              const ExtensionId& extension_id);
+
+}  // namespace extensions::side_panel_util
+
+#endif  // CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_SIDE_PANEL_UTILS_H_
diff --git a/chrome/browser/ui/lacros/snap_controller_lacros.cc b/chrome/browser/ui/lacros/snap_controller_lacros.cc
index bd40598..a621e08 100644
--- a/chrome/browser/ui/lacros/snap_controller_lacros.cc
+++ b/chrome/browser/ui/lacros/snap_controller_lacros.cc
@@ -53,7 +53,8 @@
 
 void SnapControllerLacros::CommitSnap(aura::Window* window,
                                       chromeos::SnapDirection snap,
-                                      float snap_ratio) {
+                                      float snap_ratio,
+                                      SnapRequestSource snap_request_source) {
   if (auto* wayland_extension = WaylandExtensionForAuraWindow(window)) {
     wayland_extension->CommitSnap(ToWaylandWindowSnapDirection(snap),
                                   snap_ratio);
diff --git a/chrome/browser/ui/lacros/snap_controller_lacros.h b/chrome/browser/ui/lacros/snap_controller_lacros.h
index d82d228..0cbb48ec 100644
--- a/chrome/browser/ui/lacros/snap_controller_lacros.h
+++ b/chrome/browser/ui/lacros/snap_controller_lacros.h
@@ -22,7 +22,8 @@
                        bool allow_haptic_feedback) override;
   void CommitSnap(aura::Window* window,
                   chromeos::SnapDirection snap,
-                  float snap_ratio) override;
+                  float snap_ratio,
+                  SnapRequestSource snap_request_source) override;
 };
 
 #endif  // CHROME_BROWSER_UI_LACROS_SNAP_CONTROLLER_LACROS_H_
diff --git a/chrome/browser/ui/side_panel/companion/companion_utils.cc b/chrome/browser/ui/side_panel/companion/companion_utils.cc
index c33c497..1115116 100644
--- a/chrome/browser/ui/side_panel/companion/companion_utils.cc
+++ b/chrome/browser/ui/side_panel/companion/companion_utils.cc
@@ -15,6 +15,10 @@
 
 namespace companion {
 
+bool IsCompanionFeatureEnabled() {
+  return base::FeatureList::IsEnabled(features::kSidePanelCompanion);
+}
+
 bool IsSearchInCompanionSidePanelSupported(const Browser* browser) {
   if (!browser) {
     return false;
@@ -23,14 +27,15 @@
   DCHECK(profile);
   return search::DefaultSearchProviderIsGoogle(profile) &&
          !profile->IsOffTheRecord() && browser->is_type_normal() &&
-         base::FeatureList::IsEnabled(features::kSidePanelCompanion);
+         IsCompanionFeatureEnabled();
 }
 
 bool IsSearchWebInCompanionSidePanelSupported(const Browser* browser) {
   if (!browser) {
     return false;
   }
-  return IsSearchInCompanionSidePanelSupported(browser);
+  return IsSearchInCompanionSidePanelSupported(browser) &&
+         features::kEnableOpenCompanionForWebSearch.Get();
 }
 
 bool IsSearchImageInCompanionSidePanelSupported(const Browser* browser) {
diff --git a/chrome/browser/ui/side_panel/companion/companion_utils.h b/chrome/browser/ui/side_panel/companion/companion_utils.h
index ac2edc5..88bb452e 100644
--- a/chrome/browser/ui/side_panel/companion/companion_utils.h
+++ b/chrome/browser/ui/side_panel/companion/companion_utils.h
@@ -10,6 +10,9 @@
 
 namespace companion {
 
+// Returns true if the companion feature is enabled.
+bool IsCompanionFeatureEnabled();
+
 // Returns true if browser is valid, DSE is Google, and the side panel companion
 // feature is enabled.
 bool IsSearchInCompanionSidePanelSupported(const Browser* browser);
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index c8421d4..a96a254 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -229,7 +229,7 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
 #include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/browser/ui/extensions/create_side_panel_manager.h"
+#include "chrome/browser/ui/extensions/extension_side_panel_utils.h"
 #include "chrome/browser/ui/web_applications/web_app_metrics.h"
 #include "chrome/browser/ui/web_applications/web_app_metrics_tab_helper.h"
 #include "chrome/browser/web_applications/policy/pre_redirection_url_observer.h"
@@ -614,7 +614,8 @@
 
   if (base::FeatureList::IsEnabled(
           extensions_features::kExtensionSidePanelIntegration)) {
-    extensions::CreateSidePanelManagerForWebContents(profile, web_contents);
+    extensions::side_panel_util::CreateSidePanelManagerForWebContents(
+        profile, web_contents);
   }
 
   extensions::WebNavigationTabObserver::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
index 4f7fed5..53abbbe3 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
@@ -19,13 +19,6 @@
 class TabStripModel;
 class Profile;
 
-struct TabGroupIdHash {
- public:
-  size_t operator()(const tab_groups::TabGroupId& group_id) const {
-    return base::TokenHash()(group_id.token());
-  }
-};
-
 // Serves to maintain and listen to browsers who contain saved tab groups and
 // update the model if a saved tab group was changed.
 class SavedTabGroupModelListener : public BrowserListObserver,
@@ -70,7 +63,7 @@
   // Testing Accessors.
   std::unordered_map<tab_groups::TabGroupId,
                      LocalTabGroupListener,
-                     TabGroupIdHash>&
+                     tab_groups::TabGroupIdHash>&
   GetLocalTabGroupListenerMapForTesting() {
     return local_tab_group_listeners_;
   }
@@ -79,7 +72,7 @@
   // The LocalTabGroupListeners for each saved tab group that's currently open.
   std::unordered_map<tab_groups::TabGroupId,
                      LocalTabGroupListener,
-                     TabGroupIdHash>
+                     tab_groups::TabGroupIdHash>
       local_tab_group_listeners_;
   raw_ptr<SavedTabGroupModel> model_ = nullptr;
   raw_ptr<Profile> profile_;
diff --git a/chrome/browser/ui/tabs/tab_group.cc b/chrome/browser/ui/tabs/tab_group.cc
index dfdbea11..86238b7 100644
--- a/chrome/browser/ui/tabs/tab_group.cc
+++ b/chrome/browser/ui/tabs/tab_group.cc
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/feature_list.h"
-#include "base/guid.h"
 #include "chrome/browser/favicon/favicon_utils.h"
 #include "chrome/browser/ui/tab_ui_helper.h"
 #include "chrome/browser/ui/tabs/tab_group_controller.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 0a17b70..bf20178 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <unordered_map>
 #include <utility>
 
 #include "base/auto_reset.h"
@@ -40,6 +41,8 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble.h"
 #include "chrome/browser/ui/tab_ui_helper.h"
+#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h"
+#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
 #include "chrome/browser/ui/tabs/tab.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_group.h"
@@ -47,6 +50,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/user_notes/user_notes_controller.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
 #include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
@@ -56,6 +60,7 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/feature_engagement/public/feature_constants.h"
 #include "components/reading_list/core/reading_list_model.h"
+#include "components/saved_tab_groups/saved_tab_group_model.h"
 #include "components/send_tab_to_self/metrics_util.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
@@ -1414,9 +1419,13 @@
     case CommandCloseOtherTabs: {
       ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
+      const std::vector<int> indices =
+          GetIndicesClosedByCommand(context_index, command_id);
+
+      DisconnectSavedTabGroups(indices);
+
       base::RecordAction(UserMetricsAction("TabContextMenu_CloseOtherTabs"));
-      CloseTabs(GetWebContentsesByIndices(
-                    GetIndicesClosedByCommand(context_index, command_id)),
+      CloseTabs(GetWebContentsesByIndices(indices),
                 TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
       break;
     }
@@ -1424,9 +1433,13 @@
     case CommandCloseTabsToRight: {
       ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
+      const std::vector<int> indices =
+          GetIndicesClosedByCommand(context_index, command_id);
+
+      DisconnectSavedTabGroups(indices);
+
       base::RecordAction(UserMetricsAction("TabContextMenu_CloseTabsToRight"));
-      CloseTabs(GetWebContentsesByIndices(
-                    GetIndicesClosedByCommand(context_index, command_id)),
+      CloseTabs(GetWebContentsesByIndices(indices),
                 TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
       break;
     }
@@ -2370,6 +2383,37 @@
   group_model_->GetTabGroup(group)->AddTab();
 }
 
+void TabStripModel::DisconnectSavedTabGroups(
+    const std::vector<int>& indices) const {
+  if (!base::FeatureList::IsEnabled(features::kTabGroupsSave)) {
+    return;
+  }
+
+  SavedTabGroupKeyedService* const keyed_service =
+      SavedTabGroupServiceFactory::GetForProfile(profile_);
+  const SavedTabGroupModel* const stg_model = keyed_service->model();
+
+  // Count the tabs in each group in `indices`.
+  std::unordered_map<tab_groups::TabGroupId, size_t, tab_groups::TabGroupIdHash>
+      tabs_per_group;
+  for (const int index : indices) {
+    const absl::optional<tab_groups::TabGroupId> group =
+        GetTabGroupForTab(index);
+    if (group.has_value() && stg_model->Contains(group.value())) {
+      tabs_per_group[group.value()]++;
+    }
+  }
+
+  // Disconnect each group fully contained in `indices`.
+  for (const auto& [group, count] : tabs_per_group) {
+    const gfx::Range grouped_tabs =
+        group_model_->GetTabGroup(group)->ListTabs();
+    if (grouped_tabs.length() == count) {
+      keyed_service->DisconnectLocalTabGroup(group);
+    }
+  }
+}
+
 int TabStripModel::SetTabPinnedImpl(int index, bool pinned) {
   CHECK(ContainsIndex(index));
   if (contents_data_[index]->pinned() == pinned)
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index c1e901cb..0f19f2b 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -769,6 +769,9 @@
   // index would change.
   void GroupTab(int index, const tab_groups::TabGroupId& group);
 
+  // Disconnects any saved tab groups whose tabs are a subset of `indices`.
+  void DisconnectSavedTabGroups(const std::vector<int>& indices) const;
+
   // Changes the pinned state of the tab at `index`, moving it in the process if
   // necessary. Returns the new index of the tab.
   int SetTabPinnedImpl(int index, bool pinned);
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index ba2a88e..3aa4da01 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -309,18 +309,17 @@
           .value(),
       kVisitChromeWebStoreMenuItem);
   if (features::IsChromeRefresh2023()) {
-    const int kIconSize = 16;
     SetIcon(
         GetIndexOfCommandId(IDC_EXTENSIONS_SUBMENU_MANAGE_EXTENSIONS).value(),
         ui::ImageModel::FromVectorIcon(
             vector_icons::kExtensionChromeRefreshIcon, ui::kColorMenuIcon,
-            kIconSize));
+            kDefaultIconSize));
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     SetIcon(
         GetIndexOfCommandId(IDC_EXTENSIONS_SUBMENU_VISIT_CHROME_WEB_STORE)
             .value(),
         ui::ImageModel::FromVectorIcon(vector_icons::kGoogleChromeWebstoreIcon,
-                                       ui::kColorMenuIcon, kIconSize));
+                                       ui::kColorMenuIcon, kDefaultIconSize));
 #endif
   }
 }
@@ -445,7 +444,8 @@
 #elif BUILDFLAG(IS_CHROMEOS_ASH)
          command_id == IDC_LACROS_DATA_MIGRATION ||
 #endif
-         command_id == IDC_INSTALL_PWA || command_id == IDC_UPGRADE_DIALOG;
+         (command_id == IDC_INSTALL_PWA && !features::IsChromeRefresh2023()) ||
+         command_id == IDC_UPGRADE_DIALOG;
 }
 
 std::u16string AppMenuModel::GetLabelForCommandId(int command_id) const {
@@ -657,6 +657,14 @@
       LogMenuAction(MENU_ACTION_PRINT);
       break;
 
+    case IDC_TRANSLATE_PAGE:
+      if (!uma_action_recorded_) {
+        UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.TranslatePage",
+                                   delta);
+      }
+      LogMenuAction(MENU_ACTION_TRANSLATE_PAGE);
+      break;
+
     case IDC_ROUTE_MEDIA:
       if (!uma_action_recorded_)
         UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.Cast", delta);
@@ -1070,11 +1078,10 @@
     SetElementIdentifierAt(GetIndexOfCommandId(IDC_EXTENSIONS_SUBMENU).value(),
                            kExtensionsMenuItem);
     if (features::IsChromeRefresh2023()) {
-      constexpr int kIconSize = 16;
       SetIcon(GetIndexOfCommandId(IDC_EXTENSIONS_SUBMENU).value(),
               ui::ImageModel::FromVectorIcon(
                   vector_icons::kExtensionChromeRefreshIcon, ui::kColorMenuIcon,
-                  kIconSize));
+                  kDefaultIconSize));
     }
   }
 
@@ -1089,6 +1096,11 @@
   if (media_router::MediaRouterEnabled(browser()->profile()))
     AddItemWithStringId(IDC_ROUTE_MEDIA, IDS_MEDIA_ROUTER_MENU_ITEM_TITLE);
 
+  // TODO(josephjoopark): Update translate string with StringId when finalized.
+  if (features::IsChromeRefresh2023()) {
+    AddItem(IDC_TRANSLATE_PAGE, u"Google Translate");
+  }
+
   if (features::IsChromeRefresh2023()) {
     sub_menus_.push_back(
         std::make_unique<FindAndEditSubMenuModel>(this, browser_));
@@ -1101,6 +1113,12 @@
   if (absl::optional<std::u16string> name =
           GetInstallPWAAppMenuItemName(browser_)) {
     AddItem(IDC_INSTALL_PWA, *name);
+    if (features::IsChromeRefresh2023()) {
+      SetIcon(
+          GetIndexOfCommandId(IDC_INSTALL_PWA).value(),
+          ui::ImageModel::FromVectorIcon(kInstallDesktopChromeRefreshIcon,
+                                         ui::kColorMenuIcon, kDefaultIconSize));
+    }
   } else if (absl::optional<web_app::AppId> app_id =
                  web_app::GetWebAppForActiveTab(browser_)) {
     auto* provider =
@@ -1115,6 +1133,11 @@
       AddItem(
           IDC_OPEN_IN_PWA_WINDOW,
           l10n_util::GetStringFUTF16(IDS_OPEN_IN_APP_WINDOW, truncated_name));
+      if (features::IsChromeRefresh2023()) {
+        SetIcon(GetIndexOfCommandId(IDC_OPEN_IN_PWA_WINDOW).value(),
+                ui::ImageModel::FromVectorIcon(
+                    kDesktopWindowsIcon, ui::kColorMenuIcon, kDefaultIconSize));
+      }
     }
   }
 
@@ -1230,6 +1253,7 @@
     set_icon(IDC_BOOKMARKS_MENU, kBookmarksListsMenuIcon);
     set_icon(IDC_ZOOM_MENU, kZoomInIcon);
     set_icon(IDC_PRINT, kPrintMenuIcon);
+    set_icon(IDC_TRANSLATE_PAGE, kTranslateChromeRefreshIcon);
     set_icon(IDC_ROUTE_MEDIA, kCastMenuIcon);
     set_icon(IDC_FIND_AND_EDIT_MENU, kSearchMenuIcon);
     set_icon(IDC_AUTOFILL_MENU, kKeyChromeRefreshIcon);
diff --git a/chrome/browser/ui/toolbar/app_menu_model.h b/chrome/browser/ui/toolbar/app_menu_model.h
index 00d7ad3..55fb00d 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.h
+++ b/chrome/browser/ui/toolbar/app_menu_model.h
@@ -84,6 +84,7 @@
   // Only used by ExtensionsMenuModel sub menu.
   MENU_ACTION_VISIT_CHROME_WEB_STORE = 57,
   MENU_ACTION_PASSWORD_MANAGER = 58,
+  MENU_ACTION_TRANSLATE_PAGE = 59,
   LIMIT_MENU_ACTION
 };
 
diff --git a/chrome/browser/ui/url_identity.cc b/chrome/browser/ui/url_identity.cc
index 34ba091..f3ac7546 100644
--- a/chrome/browser/ui/url_identity.cc
+++ b/chrome/browser/ui/url_identity.cc
@@ -80,10 +80,8 @@
 absl::optional<web_app::AppId> GetIsolatedWebAppIdFromUrl(const GURL& url) {
   base::expected<web_app::IsolatedWebAppUrlInfo, std::string> url_info =
       web_app::IsolatedWebAppUrlInfo::Create(url);
-  if (!url_info.has_value()) {
-    return absl::nullopt;
-  }
-  return url_info.value().app_id();
+  return url_info.has_value() ? absl::make_optional(url_info.value().app_id())
+                              : absl::nullopt;
 }
 
 UrlIdentity CreateIsolatedWebAppIdentityFromUrl(Profile* profile,
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index c273f71..43ed89aa 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -38,6 +38,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/favicon/favicon_utils.h"
+#include "chrome/browser/preloading/chrome_preloading.h"
 #include "chrome/browser/preloading/prerender/prerender_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
@@ -182,6 +183,17 @@
   kMaxValue = kMouseClick,
 };
 
+// These are used as control the behavior of kBookmarkTriggerForPrerender2.
+const base::FeatureParam<int> kPrerenderStartDelayOnMouseHoverByMiliSeconds{
+    &features::kBookmarkTriggerForPrerender2,
+    "prerender_start_delay_on_mouse_hover_ms", 300};
+const base::FeatureParam<bool> kPrerenderBookmarkBarOnMousePressedTrigger{
+    &features::kBookmarkTriggerForPrerender2,
+    "prerender_bookmarkbar_on_mouse_pressed_trigger", true};
+const base::FeatureParam<bool> kPrerenderBookmarkBarOnMouseHoverTrigger{
+    &features::kBookmarkTriggerForPrerender2,
+    "prerender_bookmarkbar_on_mouse_hover_trigger", true};
+
 // BookmarkButtonBase -----------------------------------------------
 
 // Base class for non-menu hosting buttons used on the bookmark bar.
@@ -337,6 +349,18 @@
         "Prerender.Experimental.BookmarkUrlButtonEvent",
         PreloadBookmarkMetricsEvent::kMouseOver);
     BookmarkButtonBase::OnMouseEntered(event);
+
+    if (base::FeatureList::IsEnabled(features::kBookmarkTriggerForPrerender2) &&
+        kPrerenderBookmarkBarOnMouseHoverTrigger.Get() &&
+        url_->SchemeIs("https")) {
+      preloading_timer_.Start(
+          FROM_HERE,
+          base::Milliseconds(
+              kPrerenderStartDelayOnMouseHoverByMiliSeconds.Get()),
+          base::BindRepeating(
+              &BookmarkButton::StartPrerendering, base::Unretained(this),
+              chrome_preloading_predictor::kMouseHoverOnBookmarkBar, *url_));
+    }
   }
 
   void OnMouseExited(const ui::MouseEvent& event) override {
@@ -366,18 +390,11 @@
             duration);
       }
     }
-    if (event.IsOnlyLeftMouseButton()) {
-      // TODO(https://crbug.com/1422819): Cancel the prerendering if the mouse
-      // exits without triggering PressedCallback. Prerender only for https
-      // scheme, and add an enum metric to report the protocol scheme.
-      if (base::FeatureList::IsEnabled(
-              features::kBookmarkTriggerForPrerender2)) {
-        PrerenderManager::CreateForWebContents(
-            browser_->tab_strip_model()->GetActiveWebContents());
-        auto* prerender_manager = PrerenderManager::FromWebContents(
-            browser_->tab_strip_model()->GetActiveWebContents());
-        prerender_manager->StartPrerenderBookmark(*url_);
-      }
+    if (event.IsOnlyLeftMouseButton() &&
+        base::FeatureList::IsEnabled(features::kBookmarkTriggerForPrerender2) &&
+        kPrerenderBookmarkBarOnMousePressedTrigger.Get()) {
+      StartPrerendering(chrome_preloading_predictor::kPointerDownOnBookmarkBar,
+                        *url_);
     }
     return result;
   }
@@ -388,6 +405,22 @@
   }
 
  private:
+  void StartPrerendering(content::PreloadingPredictor predictor, GURL url) {
+    // TODO(https://crbug.com/1422819): Cancel the prerendering if the mouse
+    // exits without triggering PressedCallback. Prerender only for https
+    // scheme, and add an enum metric to report the protocol scheme.
+    CHECK(
+        base::FeatureList::IsEnabled(features::kBookmarkTriggerForPrerender2));
+    if (!prerender_handle_) {
+      PrerenderManager::CreateForWebContents(
+          browser_->tab_strip_model()->GetActiveWebContents());
+      auto* prerender_manager = PrerenderManager::FromWebContents(
+          browser_->tab_strip_model()->GetActiveWebContents());
+      prerender_handle_ =
+          prerender_manager->StartPrerenderBookmark(url, predictor);
+    }
+  }
+
   // A cached value of maximum width for tooltip to skip generating
   // new tooltip text.
   mutable int max_tooltip_width_ = 0;
@@ -395,6 +428,8 @@
   PressedCallback callback_;
   const raw_ref<const GURL> url_;
   const raw_ptr<Browser> browser_;
+  base::WeakPtr<content::PrerenderHandle> prerender_handle_;
+  base::RetainingOneShotTimer preloading_timer_;
 
   // Information for metrics.
   absl::optional<base::TimeTicks> mouse_entered_time_;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
index 6b09499..c7c23d6e 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
@@ -339,13 +339,10 @@
 using ukm::builders::Preloading_Prediction;
 static const auto kMockElapsedTime =
     base::ScopedMockElapsedTimersForTest::kMockElapsedTime;
-class PrerenderBookmarkBarNavigationTest : public BookmarkBarNavigationTest {
- public:
-  PrerenderBookmarkBarNavigationTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kBookmarkTriggerForPrerender2);
-  }
 
+class PrerenderBookmarkBarNavigationTestBase
+    : public BookmarkBarNavigationTest {
+ public:
   content::WebContents* GetActiveWebContents() {
     return browser()->tab_strip_model()->GetActiveWebContents();
   }
@@ -353,9 +350,6 @@
   void SetUpOnMainThread() override {
     BookmarkBarNavigationTest::SetUpOnMainThread();
     test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
-    ukm_entry_builder_ =
-        std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>(
-            chrome_preloading_predictor::kPointerDownOnBookmarkBar);
     scoped_test_timer_ =
         std::make_unique<base::ScopedMockElapsedTimersForTest>();
   }
@@ -364,10 +358,6 @@
     return test_ukm_recorder_.get();
   }
 
-  const content::test::PreloadingAttemptUkmEntryBuilder& ukm_entry_builder() {
-    return *ukm_entry_builder_;
-  }
-
   void CreateBookmarkButton() {
     // Populate bookmark bar with a single bookmark.
     bookmarks::BookmarkModel* model =
@@ -404,10 +394,7 @@
   }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
-  std::unique_ptr<content::test::PreloadingAttemptUkmEntryBuilder>
-      ukm_entry_builder_;
   std::unique_ptr<base::ScopedMockElapsedTimersForTest> scoped_test_timer_;
 };
 
@@ -416,7 +403,39 @@
 
 constexpr int kPreloadingTriggeringOutcomeSuccess = 5;
 
-IN_PROC_BROWSER_TEST_F(PrerenderBookmarkBarNavigationTest,
+class PrerenderBookmarkBarOnPressedNavigationTest
+    : public PrerenderBookmarkBarNavigationTestBase {
+ public:
+  PrerenderBookmarkBarOnPressedNavigationTest() {
+    // Mousedown prerender trigger is disabled explicitly and onHover delay is
+    // set to 0ms for testing.
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {
+            {features::kBookmarkTriggerForPrerender2,
+             {{"prerender_bookmarkbar_on_mouse_pressed_trigger", "true"},
+              {"prerender_bookmarkbar_on_mouse_hover_trigger", "false"}}},
+        },
+        /*disabled_features=*/{});
+  }
+
+  const content::test::PreloadingAttemptUkmEntryBuilder& ukm_entry_builder() {
+    return *ukm_entry_builder_;
+  }
+
+  void SetUpOnMainThread() override {
+    PrerenderBookmarkBarNavigationTestBase::SetUpOnMainThread();
+    ukm_entry_builder_ =
+        std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>(
+            chrome_preloading_predictor::kPointerDownOnBookmarkBar);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  std::unique_ptr<content::test::PreloadingAttemptUkmEntryBuilder>
+      ukm_entry_builder_;
+};
+
+IN_PROC_BROWSER_TEST_F(PrerenderBookmarkBarOnPressedNavigationTest,
                        PrerenderActivation) {
   base::HistogramTester histogram_tester;
   // Navigate to an non-empty tab
@@ -462,3 +481,83 @@
       "Preloading.Prerender.Attempt.PointerDownOnBookmarkBar.TriggeringOutcome",
       kPreloadingTriggeringOutcomeSuccess, 1);
 }
+
+class PrerenderBookmarkBarOnHoverNavigationTest
+    : public PrerenderBookmarkBarNavigationTestBase {
+ public:
+  PrerenderBookmarkBarOnHoverNavigationTest() {
+    // Mousedown prerender trigger is disabled explicitly and onHover delay is
+    // set to 0ms for testing.
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {
+            {features::kBookmarkTriggerForPrerender2,
+             {{"prerender_start_delay_on_mouse_hover_ms", "0"},
+              {"prerender_bookmarkbar_on_mouse_pressed_trigger", "false"},
+              {"prerender_bookmarkbar_on_mouse_hover_trigger", "true"}}},
+        },
+        /*disabled_features=*/{});
+  }
+
+  const content::test::PreloadingAttemptUkmEntryBuilder& ukm_entry_builder() {
+    return *ukm_entry_builder_;
+  }
+
+  void SetUpOnMainThread() override {
+    PrerenderBookmarkBarNavigationTestBase::SetUpOnMainThread();
+    ukm_entry_builder_ =
+        std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>(
+            chrome_preloading_predictor::kMouseHoverOnBookmarkBar);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  std::unique_ptr<content::test::PreloadingAttemptUkmEntryBuilder>
+      ukm_entry_builder_;
+};
+
+IN_PROC_BROWSER_TEST_F(PrerenderBookmarkBarOnHoverNavigationTest,
+                       PrerenderActivation) {
+  base::HistogramTester histogram_tester;
+  // Navigate to an non-empty tab
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), https_test_server()->GetURL("/empty.html")));
+
+  content::NavigationHandleObserver activation_observer(
+      GetActiveWebContents(),
+      https_test_server()->GetURL("/empty.html?prerender"));
+
+  CreateBookmarkButton();
+  NavigateToBookmarkByMousePressed();
+
+  {
+    ukm::SourceId ukm_source_id = activation_observer.next_page_ukm_source_id();
+    auto ukm_entries = test_ukm_recorder()->GetEntries(
+        Preloading_Attempt::kEntryName,
+        content::test::kPreloadingAttemptUkmMetrics);
+    EXPECT_EQ(ukm_entries.size(), 1u);
+
+    std::vector<UkmEntry> expected_entries = {
+        ukm_entry_builder().BuildEntry(
+            ukm_source_id, content::PreloadingType::kPrerender,
+            content::PreloadingEligibility::kEligible,
+            content::PreloadingHoldbackStatus::kAllowed,
+            content::PreloadingTriggeringOutcome::kSuccess,
+            content::PreloadingFailureReason::kUnspecified,
+            /*accurate=*/true,
+            /*ready_time=*/kMockElapsedTime),
+    };
+    EXPECT_THAT(ukm_entries,
+                testing::UnorderedElementsAreArray(expected_entries))
+        << content::test::ActualVsExpectedUkmEntriesToString(ukm_entries,
+                                                             expected_entries);
+  }
+
+  EXPECT_EQ(GetActiveWebContents()->GetLastCommittedURL(),
+            https_test_server()->GetURL("/empty.html?prerender"));
+  histogram_tester.ExpectUniqueSample(
+      "Prerender.Experimental.PrerenderHostFinalStatus.Embedder_BookmarkBar",
+      kFinalStatusActivated, 1);
+  histogram_tester.ExpectUniqueSample(
+      "Preloading.Prerender.Attempt.MouseHoverOnBookmarkBar.TriggeringOutcome",
+      kPreloadingTriggeringOutcomeSuccess, 1);
+}
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
index 319182a..5394fc31 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
@@ -12,6 +12,7 @@
 #include "base/uuid.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils_desktop.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
@@ -40,6 +41,7 @@
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/layout_types.h"
+#include "ui/views/view_class_properties.h"
 #include "ui/views/view_utils.h"
 
 namespace {
@@ -52,6 +54,9 @@
 // buttons.
 constexpr int kButtonPadding = 2;
 
+// The thickness, in dips, of the drop indicators during drop sessions.
+constexpr int kDropIndicatorThicknessDips = 2;
+
 SavedTabGroupModel* GetSavedTabGroupModelFromBrowser(Browser* browser) {
   DCHECK(browser);
   SavedTabGroupKeyedService* keyed_service =
@@ -115,7 +120,56 @@
   void OnPaint(gfx::Canvas* canvas) override {
     views::View::OnPaint(canvas);
 
-    // TODO(crbug/1426200): paint a drop indicator
+    MaybePaintDropIndicatorInOverflow(canvas);
+  }
+
+  void MaybePaintDropIndicatorInOverflow(gfx::Canvas* canvas) {
+    const absl::optional<int> overflow_menu_indicator_index =
+        CalculateDropIndicatorIndexInOverflow();
+    if (!overflow_menu_indicator_index.has_value()) {
+      return;
+    }
+
+    const int y = overflow_menu_indicator_index.value() > 0
+                      ? children()[overflow_menu_indicator_index.value() - 1]
+                                ->bounds()
+                                .bottom() +
+                            kOverflowMenuButtonPadding / 2
+                      : kDropIndicatorThicknessDips / 2;
+
+    const gfx::Rect drop_indicator_bounds =
+        gfx::Rect(0, y - kDropIndicatorThicknessDips / 2, width(),
+                  kDropIndicatorThicknessDips);
+    canvas->FillRect(drop_indicator_bounds,
+                     GetColorProvider()->GetColor(kColorBookmarkBarForeground));
+  }
+
+  // Returns the index within the overflow menu the drop indicator should be
+  // painted at, or nullopt if no indicator should be painted.
+  absl::optional<int> CalculateDropIndicatorIndexInOverflow() {
+    const absl::optional<int> indicator_index =
+        parent_bar_->CalculateDropIndicatorIndexInCombinedSpace();
+    if (!indicator_index.has_value()) {
+      return absl::nullopt;
+    }
+
+    const int overflow_menu_indicator_index =
+        indicator_index.value() - kMaxVisibleButtons;
+    if (overflow_menu_indicator_index < 0) {
+      // The drop index is not in the overflow menu. No drop indicator.
+      return absl::nullopt;
+    }
+
+    const bool came_from_bar = parent_bar_->saved_tab_group_model_
+                                   ->GetIndexOf(parent_bar_->drag_data_->guid())
+                                   .value() < kMaxVisibleButtons;
+    if (overflow_menu_indicator_index == 0 && came_from_bar) {
+      // The drop index is on the border between the overflow menu and the bar,
+      // and because the group came from the bar, it will stay in the bar.
+      return absl::nullopt;
+    }
+
+    return overflow_menu_indicator_index;
   }
 
  private:
@@ -131,6 +185,8 @@
     : saved_tab_group_model_(saved_tab_group_model),
       browser_(browser),
       animations_enabled_(animations_enabled) {
+  SetProperty(views::kElementIdentifierKey, kSavedTabGroupBarElementId);
+
   std::unique_ptr<views::LayoutManager> layout_manager =
       std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kHorizontal,
@@ -237,6 +293,9 @@
 
   drag_data_->SetInsertionIndex(drop_index);
   SchedulePaint();
+  if (overflow_menu_) {
+    overflow_menu_->SchedulePaint();
+  }
 }
 
 void SavedTabGroupBar::HandleDrop() {
@@ -279,8 +338,12 @@
   drag_data_->SetLocation(event.location());
   UpdateDropIndex();
 
-  // Show the overflow menu when dragging over the overflow button.
-  if (event.location().x() >= overflow_button_->bounds().x()) {
+  const bool dragging_over_button =
+      event.location().x() >= overflow_button_->bounds().x();
+  const bool would_drop_into_overflow =
+      drag_data_->insertion_index() >= static_cast<size_t>(kMaxVisibleButtons);
+
+  if (dragging_over_button || would_drop_into_overflow) {
     MaybeShowOverflowMenu();
   } else if (event.location().y() < bounds().bottom()) {
     // Hide the overflow menu if dragging in the bar but not over the button.
@@ -315,35 +378,7 @@
 void SavedTabGroupBar::OnPaint(gfx::Canvas* canvas) {
   views::View::OnPaint(canvas);
 
-  if (drag_data_ && drag_data_->insertion_index().has_value()) {
-    const int insertion_index = drag_data_->insertion_index().value();
-    const int current_index =
-        saved_tab_group_model_->GetIndexOf(drag_data_->guid()).value();
-
-    absl::optional<int> indicator_index = insertion_index;
-    if (insertion_index > current_index) {
-      // `insertion_index` doesn't include `current_index`, add it back in if
-      // needed.
-      indicator_index = insertion_index + 1;
-    } else if (insertion_index == current_index) {
-      // Hide the indicator when the drop wouldn't reorder anything.
-      indicator_index = absl::nullopt;
-    }
-
-    if (indicator_index.has_value()) {
-      constexpr int kDropIndicatorWidth = 2;
-      const int x =
-          indicator_index > 0
-              ? children()[indicator_index.value() - 1]->bounds().right() +
-                    GetLayoutConstant(TOOLBAR_ELEMENT_PADDING) / 2
-              : kDropIndicatorWidth / 2;
-
-      const gfx::Rect drop_indicator_bounds = gfx::Rect(
-          x - kDropIndicatorWidth / 2, 0, kDropIndicatorWidth, height());
-      canvas->FillRect(drop_indicator_bounds, GetColorProvider()->GetColor(
-                                                  kColorBookmarkBarForeground));
-    }
-  }
+  MaybePaintDropIndicatorInBar(canvas);
 }
 
 void SavedTabGroupBar::SavedTabGroupAddedLocally(const base::Uuid& guid) {
@@ -637,3 +672,72 @@
 void SavedTabGroupBar::ShowOverflowButton() {
   overflow_button_->SetVisible(true);
 }
+
+void SavedTabGroupBar::MaybePaintDropIndicatorInBar(gfx::Canvas* canvas) {
+  const absl::optional<int> indicator_index =
+      CalculateDropIndicatorIndexInBar();
+  if (!indicator_index.has_value()) {
+    return;
+  }
+
+  const int x =
+      indicator_index.value() > 0
+          ? children()[indicator_index.value() - 1]->bounds().right() +
+                GetLayoutConstant(TOOLBAR_ELEMENT_PADDING) / 2
+          : kDropIndicatorThicknessDips / 2;
+
+  const gfx::Rect drop_indicator_bounds =
+      gfx::Rect(x - kDropIndicatorThicknessDips / 2, 0,
+                kDropIndicatorThicknessDips, height());
+  canvas->FillRect(drop_indicator_bounds,
+                   GetColorProvider()->GetColor(kColorBookmarkBarForeground));
+}
+
+absl::optional<int> SavedTabGroupBar::CalculateDropIndicatorIndexInBar() const {
+  const absl::optional<int> indicator_index =
+      CalculateDropIndicatorIndexInCombinedSpace();
+  if (!indicator_index.has_value()) {
+    return absl::nullopt;
+  }
+
+  if (indicator_index.value() > kMaxVisibleButtons) {
+    // The drop index is not in the bar.
+    return absl::nullopt;
+  }
+
+  const bool came_from_overflow_menu =
+      saved_tab_group_model_->GetIndexOf(drag_data_->guid()).value() >=
+      kMaxVisibleButtons;
+  if (indicator_index.value() == kMaxVisibleButtons &&
+      came_from_overflow_menu) {
+    // The drop index is on the border between the overflow menu and the bar,
+    // and because the group came from the overflow menu, it will stay in the
+    // overflow menu.
+    return absl::nullopt;
+  }
+
+  return indicator_index;
+}
+
+absl::optional<int>
+SavedTabGroupBar::CalculateDropIndicatorIndexInCombinedSpace() const {
+  if (!drag_data_ || !drag_data_->insertion_index().has_value()) {
+    return absl::nullopt;
+  }
+
+  const int insertion_index = drag_data_->insertion_index().value();
+  const int current_index =
+      saved_tab_group_model_->GetIndexOf(drag_data_->guid()).value();
+
+  if (insertion_index > current_index) {
+    // `insertion_index` doesn't include `current_index`, add it back in if
+    // needed.
+    return insertion_index + 1;
+  } else if (insertion_index == current_index) {
+    // Hide the indicator when the drop wouldn't reorder anything.
+    return absl::nullopt;
+  }
+
+  // Otherwise we can show an indicator at the actual drop index.
+  return insertion_index;
+}
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.h b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.h
index 29da491..c341c99e 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.h
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.h
@@ -143,6 +143,18 @@
   // Reorders the dragged group to its new index.
   void HandleDrop();
 
+  // Paints the drop indicator, if one should be shown.
+  void MaybePaintDropIndicatorInBar(gfx::Canvas* canvas);
+
+  // Calculates the index in the saved tab groups bar at which we should show a
+  // drop indicator, or nullopt if we should not show an indicator in the bar.
+  absl::optional<int> CalculateDropIndicatorIndexInBar() const;
+
+  // Calculates the index (in saved tab group model space, so across the bar and
+  // the overflow menu) at which we should show a drop indicator, or nullopt if
+  // we should not show an indicator anywhere at all.
+  absl::optional<int> CalculateDropIndicatorIndexInCombinedSpace() const;
+
   // Provides a callback that returns the page navigator
   base::RepeatingCallback<content::PageNavigator*()> GetPageNavigatorGetter();
 
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
index a74f782..8bebfe93 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
@@ -2,18 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/test/bind.h"
 #include "base/test/gtest_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
+#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h"
+#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
 #include "chrome/browser/ui/tabs/tab_menu_model.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
 #include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_group_header.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/test/interaction/interaction_test_util_browser.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "chrome/test/interaction/tracked_element_webcontents.h"
@@ -21,6 +26,7 @@
 #include "components/bookmarks/common/bookmark_pref_names.h"
 #include "components/power_bookmarks/core/power_bookmark_features.h"
 #include "components/prefs/pref_service.h"
+#include "components/tab_groups/tab_group_id.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/interaction/element_identifier.h"
@@ -29,6 +35,7 @@
 #include "ui/base/test/ui_controls.h"
 #include "ui/views/interaction/element_tracker_views.h"
 #include "ui/views/interaction/interaction_test_util_views.h"
+#include "ui/views/view_utils.h"
 
 class SavedTabGroupInteractiveTest : public InteractiveBrowserTest {
  public:
@@ -41,12 +48,18 @@
   }
 
   MultiStep ShowBookmarksBar() {
-    return Steps(MoveMouseTo(kAppMenuButtonElementId), ClickMouse(),
+    return Steps(PressButton(kAppMenuButtonElementId),
                  SelectMenuItem(AppMenuModel::kBookmarksMenuItem),
                  SelectMenuItem(BookmarkSubMenuModel::kShowBookmarkBarMenuItem),
                  WaitForShow(kBookmarkBarElementId));
   }
 
+  StepBuilder FinishTabstripAnimations() {
+    return std::move(WithView(kTabStripElementId, [](TabStrip* tab_strip) {
+                       tab_strip->StopAnimating(true);
+                     }).SetDescription("FinishTabstripAnimation"));
+  }
+
   MultiStep HoverTabAt(int index) {
     const char kTabToHover[] = "Tab to hover";
     return Steps(NameDescendantViewByType<Tab>(kBrowserViewElementId,
@@ -54,11 +67,46 @@
                  MoveMouseTo(kTabToHover));
   }
 
-  MultiStep HoverTabGroupHeaderAt(int index) {
+  MultiStep HoverTabGroupHeader(tab_groups::TabGroupId group_id) {
     const char kTabGroupHeaderToHover[] = "Tab group header to hover";
-    return Steps(NameDescendantViewByType<TabGroupHeader>(
-                     kBrowserViewElementId, kTabGroupHeaderToHover, index),
-                 MoveMouseTo(kTabGroupHeaderToHover));
+    return Steps(
+        FinishTabstripAnimations(),
+        NameDescendantView(
+            kBrowserViewElementId, kTabGroupHeaderToHover,
+            base::BindRepeating(
+                [](tab_groups::TabGroupId group_id, const views::View* view) {
+                  const TabGroupHeader* header =
+                      views::AsViewClass<TabGroupHeader>(view);
+                  if (!header) {
+                    return false;
+                  }
+                  return header->group().value() == group_id;
+                },
+                group_id)),
+        MoveMouseTo(kTabGroupHeaderToHover));
+  }
+
+  MultiStep SaveGroupLeaveEditorBubbleOpen(tab_groups::TabGroupId group_id) {
+    return Steps(EnsureNotPresent(kTabGroupEditorBubbleId),
+                 // Right click on the header to open the editor bubble.
+                 HoverTabGroupHeader(group_id), ClickMouse(ui_controls::RIGHT),
+                 // Wait for the tab group editor bubble to appear.
+                 WaitForShow(kTabGroupEditorBubbleId),
+                 // Click the save toggle and make sure the saved tab group
+                 // appears in the bookmarks bar.
+                 PressButton(kTabGroupEditorBubbleSaveToggleId));
+  }
+
+  MultiStep SaveGroupAndCloseEditorBubble(tab_groups::TabGroupId group_id) {
+    return Steps(SaveGroupLeaveEditorBubbleOpen(group_id),
+                 // Close the editor bubble view. Must flush events first to
+                 // avoid closing a view while it's in the stack frame above us.
+                 FlushEvents(), HoverTabGroupHeader(group_id), ClickMouse());
+  }
+
+  std::unique_ptr<content::WebContents> CreateWebContents() {
+    return content::WebContents::Create(
+        content::WebContents::CreateParams(browser()->profile()));
   }
 
  private:
@@ -66,42 +114,82 @@
 };
 
 IN_PROC_BROWSER_TEST_F(SavedTabGroupInteractiveTest, CreateGroupAndSave) {
-  RunTestSequence(
-      ShowBookmarksBar(),
-      // Ensure no tab groups save buttons in the bookmarks bar are present.
-      EnsureNotPresent(kSavedTabGroupButtonElementId),
-      // Right click anywhere on the tab to open the context menu.
-      HoverTabAt(0), ClickMouse(ui_controls::RIGHT),
-      // Select option to create a new tab group and wait for the tab group
-      // editor bubble to appear.
-      SelectMenuItem(TabMenuModel::kAddToNewGroupItemIdentifier),
-      WaitForShow(kTabGroupEditorBubbleId),
-      // Click the save toggle and make sure the saved tab group appears in the
-      // bookmarks bar.
-      MoveMouseTo(kTabGroupEditorBubbleSaveToggleId), ClickMouse(),
-      WaitForShow(kSavedTabGroupButtonElementId));
+  const tab_groups::TabGroupId group_id =
+      browser()->tab_strip_model()->AddToNewGroup({0});
+
+  RunTestSequence(ShowBookmarksBar(),
+                  // Ensure no tab groups save buttons in the bookmarks bar
+                  // are present.
+                  EnsureNotPresent(kSavedTabGroupButtonElementId),
+                  // Add tab at index 0 to a new group and save it.
+                  SaveGroupLeaveEditorBubbleOpen(group_id),
+                  WaitForShow(kSavedTabGroupButtonElementId, true));
 }
 
 IN_PROC_BROWSER_TEST_F(SavedTabGroupInteractiveTest,
                        UnsaveGroupFromTabGroupHeader) {
+  const tab_groups::TabGroupId group_id =
+      browser()->tab_strip_model()->AddToNewGroup({0});
+
   RunTestSequence(
+      // Show the bookmarks bar where the buttons will be displayed.
       ShowBookmarksBar(),
       // Ensure no tab groups save buttons in the bookmarks bar are present.
       EnsureNotPresent(kSavedTabGroupButtonElementId),
-      // Right click anywhere on the tab to open the context menu.
-      HoverTabAt(0), ClickMouse(ui_controls::RIGHT),
-      // Select option to create a new tab group and wait for the tab group
-      // editor bubble to appear.
-      SelectMenuItem(TabMenuModel::kAddToNewGroupItemIdentifier),
-      WaitForShow(kTabGroupEditorBubbleId),
-      // Click the save toggle and make sure the saved tab group appears in the
-      // bookmarks bar.
-      MoveMouseTo(kTabGroupEditorBubbleSaveToggleId), ClickMouse(),
-      WaitForShow(kSavedTabGroupButtonElementId),
+      SaveGroupLeaveEditorBubbleOpen(group_id),
+      WaitForShow(kSavedTabGroupButtonElementId, true),
       // Click the save toggle again and make sure the saved tab group
       // disappears from the bookmarks bar.
-      MoveMouseTo(kTabGroupEditorBubbleSaveToggleId), ClickMouse(),
-      WaitForHide(kSavedTabGroupButtonElementId));
+      PressButton(kTabGroupEditorBubbleSaveToggleId),
+      WaitForHide(kSavedTabGroupButtonElementId),
+      // Click the first tab to close the context menu. Mac builders fail if the
+      // context menu stays open.
+      HoverTabAt(0), ClickMouse(ui_controls::LEFT));
+}
+
+// TODO(crbug.com/1432770): Re-enable this test once it doesn't get stuck in
+// drag and drop. Maybe related issue - the relative positioning seems to be
+// interpreted as an absolute position.
+IN_PROC_BROWSER_TEST_F(SavedTabGroupInteractiveTest,
+                       DISABLED_DragGroupWithinBar) {
+  // Create two tab groups with one tab each.
+  const tab_groups::TabGroupId group_id_1 =
+      browser()->tab_strip_model()->AddToNewGroup({0});
+  browser()->tab_strip_model()->InsertWebContentsAt(1, CreateWebContents(),
+                                                    AddTabTypes::ADD_NONE);
+  const tab_groups::TabGroupId group_id_2 =
+      browser()->tab_strip_model()->AddToNewGroup({1});
+  BrowserView::GetBrowserViewForBrowser(browser())->tabstrip()->StopAnimating(
+      true);
+
+  const char kSavedTabGroupButton1[] = "SavedTabGroupButton1";
+  const char kSavedTabGroupButton2[] = "SavedTabGroupButton2";
+  auto right_center =
+      base::BindLambdaForTesting([](ui::TrackedElement* element) {
+        return element->AsA<views::TrackedElementViews>()
+            ->view()
+            ->GetLocalBounds()
+            .right_center();
+      });
+
+  RunTestSequence(
+      // This comment fixes the auto formatting, do not remove.
+      ShowBookmarksBar(),
+      // Save the groups.
+      SaveGroupAndCloseEditorBubble(group_id_1),
+      SaveGroupAndCloseEditorBubble(group_id_2),
+      // Find the buttons in the saved tab groups bar.
+      NameChildViewByType<SavedTabGroupButton>(kSavedTabGroupBarElementId,
+                                               kSavedTabGroupButton1, 0),
+      NameChildViewByType<SavedTabGroupButton>(kSavedTabGroupBarElementId,
+                                               kSavedTabGroupButton2, 1),
+      // Drag button 1 to the right of button 2.
+      MoveMouseTo(kSavedTabGroupButton1),
+      DragMouseTo(kSavedTabGroupButton2, std::move(right_center)));
+
+  SavedTabGroupModel* model =
+      SavedTabGroupServiceFactory::GetForProfile(browser()->profile())->model();
+  EXPECT_EQ(1, model->GetIndexOf(group_id_1).value());
 }
 
 // TODO(dljames): Write a test to unsave a group from a saved group button's
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container_interactive_uitest.cc
index c5c4a96..5bb5e8b4 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_container_interactive_uitest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container_interactive_uitest.cc
@@ -750,81 +750,93 @@
   ExtensionTestMessageListener injection_listener(kInjectionSucceededMessage);
   injection_listener.set_extension_id(extension()->id());
 
-  GURL url = embedded_test_server()->GetURL("example.com", "/title1.html");
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   extensions::ExtensionActionRunner* runner =
       extensions::ExtensionActionRunner::GetForWebContents(web_contents);
   BlockedActionWaiter blocked_action_waiter(runner);
-  {
-    content::TestNavigationObserver observer(web_contents);
-    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
-    EXPECT_TRUE(observer.last_navigation_succeeded());
-  }
-
-  // Access to `url` should have been withheld.
-  blocked_action_waiter.WaitAndReset();
-  EXPECT_TRUE(runner->WantsToRun(extension()));
   extensions::PermissionsManager* permissions_manager =
       extensions::PermissionsManager::Get(profile());
-  EXPECT_FALSE(
-      permissions_manager->HasGrantedHostPermission(*extension(), url));
-  EXPECT_EQ(tooltip_wants_access, GetActionTooltip());
-  EXPECT_FALSE(injection_listener.was_satisfied());
 
-  extensions::ExtensionContextMenuModel* extension_menu =
-      GetExtensionContextMenu();
-  ASSERT_TRUE(extension_menu);
-
-  // Allow the extension to run on this site. This should show a refresh page
-  // bubble. Accept the bubble.
+  // Navigate to urlA. The extension should have withheld access.
+  GURL urlA = embedded_test_server()->GetURL("example.com", "/title1.html");
   {
     content::TestNavigationObserver observer(web_contents);
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), urlA));
+    EXPECT_TRUE(observer.last_navigation_succeeded());
+
+    blocked_action_waiter.WaitAndReset();
+    EXPECT_TRUE(runner->WantsToRun(extension()));
+    EXPECT_FALSE(
+        permissions_manager->HasGrantedHostPermission(*extension(), urlA));
+    EXPECT_EQ(tooltip_wants_access, GetActionTooltip());
+    EXPECT_FALSE(injection_listener.was_satisfied());
+  }
+
+  {
+    // Open the extension's context menu.
+    extensions::ExtensionContextMenuModel* extension_menu =
+        GetExtensionContextMenu();
+    ASSERT_TRUE(extension_menu);
+
+    // Allow the extension to run on this site. This should show a refresh page
+    // bubble. Accept the bubble.
+    content::TestNavigationObserver observer(web_contents);
     runner->accept_bubble_for_testing(true);
     extension_menu->ExecuteCommand(
         extensions::ExtensionContextMenuModel::PAGE_ACCESS_RUN_ON_SITE,
-        0 /* event_flags */);
+        /*event_flags=*/0);
     observer.WaitForNavigationFinished();
     EXPECT_TRUE(observer.last_navigation_succeeded());
-  }
 
-  // The extension should have injected and the extension should no longer want
-  // to run.
-  ASSERT_TRUE(injection_listener.WaitUntilSatisfied());
-  injection_listener.Reset();
-  EXPECT_TRUE(permissions_manager->HasGrantedHostPermission(*extension(), url));
-  EXPECT_EQ(tooltip_has_access, GetActionTooltip());
-  EXPECT_FALSE(runner->WantsToRun(extension()));
+    // The extension should have injected and the extension should no longer
+    // want to run.
+    ASSERT_TRUE(injection_listener.WaitUntilSatisfied());
+    injection_listener.Reset();
+    EXPECT_FALSE(runner->WantsToRun(extension()));
+    EXPECT_TRUE(
+        permissions_manager->HasGrantedHostPermission(*extension(), urlA));
+    EXPECT_EQ(tooltip_has_access, GetActionTooltip());
+  }
 
   // Now navigate to a different host. The extension should have blocked
   // actions.
+  GURL urlB = embedded_test_server()->GetURL("abc.com", "/title1.html");
   {
-    url = embedded_test_server()->GetURL("abc.com", "/title1.html");
     content::TestNavigationObserver observer(web_contents);
-    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), urlB));
     EXPECT_TRUE(observer.last_navigation_succeeded());
+
+    blocked_action_waiter.WaitAndReset();
+    EXPECT_TRUE(runner->WantsToRun(extension()));
+    EXPECT_FALSE(
+        permissions_manager->HasGrantedHostPermission(*extension(), urlB));
+    EXPECT_EQ(tooltip_wants_access, GetActionTooltip());
+    EXPECT_FALSE(injection_listener.was_satisfied());
   }
-  blocked_action_waiter.WaitAndReset();
-  EXPECT_TRUE(runner->WantsToRun(extension()));
-  EXPECT_FALSE(
-      permissions_manager->HasGrantedHostPermission(*extension(), url));
-  EXPECT_EQ(tooltip_wants_access, GetActionTooltip());
-  EXPECT_FALSE(injection_listener.was_satisfied());
 
-  // Allow the extension to run on all sites this time. This should again show a
-  // refresh bubble. Dismiss it.
-  runner->accept_bubble_for_testing(false);
-  extension_menu->ExecuteCommand(
-      extensions::ExtensionContextMenuModel::PAGE_ACCESS_RUN_ON_ALL_SITES,
-      0 /* event_flags */);
+  {
+    // Re open the menu again, since the menu contents don't update dynamically.
+    extensions::ExtensionContextMenuModel* extension_menu =
+        GetExtensionContextMenu();
+    ASSERT_TRUE(extension_menu);
 
-  // Permissions to the extension should now be been granted, and the
-  // extension should still be in wants-to-run state because we didn't refresh
-  // the page.
-  EXPECT_TRUE(runner->WantsToRun(extension()));
-  EXPECT_TRUE(permissions_manager->HasGrantedHostPermission(*extension(), url));
-  EXPECT_EQ(tooltip_wants_access, GetActionTooltip());
-  EXPECT_FALSE(injection_listener.was_satisfied());
+    // Allow the extension to run on all sites this time. This should again show
+    // a refresh bubble. Dismiss it.
+    runner->accept_bubble_for_testing(false);
+    extension_menu->ExecuteCommand(
+        extensions::ExtensionContextMenuModel::PAGE_ACCESS_RUN_ON_ALL_SITES,
+        /*event_flags=*/0);
+
+    // Permissions to the extension should now be been granted, and the
+    // extension should still be in wants-to-run state because we didn't refresh
+    // the page.
+    EXPECT_TRUE(runner->WantsToRun(extension()));
+    EXPECT_TRUE(
+        permissions_manager->HasGrantedHostPermission(*extension(), urlB));
+    EXPECT_EQ(tooltip_wants_access, GetActionTooltip());
+    EXPECT_FALSE(injection_listener.was_satisfied());
+  }
 }
 
 // Tests page access modifications through the context menu which don't require
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
index 352a7be..e8d0bb44 100644
--- a/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
@@ -96,7 +96,7 @@
   window->SetBounds(restored_bounds);
 
   // Snap the window to the left.
-  const ash::WMEvent left_snap_event(ash::WM_EVENT_SNAP_PRIMARY);
+  const ash::WindowSnapWMEvent left_snap_event(ash::WM_EVENT_SNAP_PRIMARY);
   ash::WindowState::Get(window)->OnWMEvent(&left_snap_event);
   const gfx::Size snapped_size = window->GetBoundsInScreen().size();
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
index 1bcd6819..19a94bd 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 
 #include "base/containers/cxx20_erase.h"
-#include "base/functional/bind.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -17,7 +16,6 @@
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
@@ -36,10 +34,8 @@
 #include "chromeos/ui/base/window_properties.h"
 #include "chromeos/ui/base/window_state_type.h"
 #include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h"
-#include "chromeos/ui/frame/caption_buttons/frame_size_button.h"
 #include "chromeos/ui/frame/default_frame_header.h"
 #include "chromeos/ui/frame/frame_utils.h"
-#include "chromeos/ui/wm/features.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
@@ -161,15 +157,6 @@
       AddChildView(std::make_unique<chromeos::FrameCaptionButtonContainerView>(
           frame(), std::move(tab_search_button)));
   caption_button_container_->UpdateCaptionButtonState(false /*=animate*/);
-  auto* size_button = caption_button_container_->size_button();
-
-  if (chromeos::wm::features::IsWindowLayoutMenuEnabled() && size_button) {
-    // base::Unretained() is safe since `this` also destroys
-    // `caption_button_container` and its `size_button`.
-    size_button->SetFeedbackButtonCallback(base::BindRepeating(
-        &BrowserNonClientFrameViewChromeOS::ShowFeedbackPageForMenu,
-        base::Unretained(this)));
-  }
 
   // Initializing the TabIconView is expensive, so only do it if we need to.
   if (browser_view()->ShouldShowWindowIcon()) {
@@ -905,16 +892,6 @@
   return header;
 }
 
-void BrowserNonClientFrameViewChromeOS::ShowFeedbackPageForMenu() {
-  chrome::ShowFeedbackPage(
-      /*browser=*/browser_view()->browser(),
-      /*source=*/chrome::kFeedbackSourceWindowLayoutMenu,
-      /*description_template*/ "#WindowLayoutMenu\n",
-      /*description_placeholder_text=*/std::string(),
-      /*category_tag=*/std::string(),
-      /*extra_diagnostics=*/std::string());
-}
-
 void BrowserNonClientFrameViewChromeOS::UpdateTopViewInset() {
   // In immersive fullscreen mode, the top view inset property should be 0.
   const bool immersive =
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
index 0b9cf93..5f0abe8 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
@@ -165,9 +165,6 @@
   // Creates the frame header for the browser window.
   std::unique_ptr<chromeos::FrameHeader> CreateFrameHeader();
 
-  // Shows a dogfood feedpage page for the multitask menu.
-  void ShowFeedbackPageForMenu();
-
   // Triggers the web-app origin and icon animations, assumes the web-app UI
   // elements exist.
   void StartWebAppAnimation();
diff --git a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc
index 401b50d7..311d0835 100644
--- a/chrome/browser/ui/views/overlay/video_overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/video_overlay_window_views.cc
@@ -1174,7 +1174,8 @@
   // At this point, the aura surface will be created so we can set it to pip and
   // its aspect ratio. Let Exo handle adding a rounded corner decorartor.
   desktop_window_tree_host->GetWaylandExtension()->SetPip();
-  desktop_window_tree_host->SetAspectRatio(gfx::SizeF(natural_size_));
+  desktop_window_tree_host->SetAspectRatio(gfx::SizeF(natural_size_),
+                                           /*excluded_margin=*/gfx::Size());
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view.cc b/chrome/browser/ui/views/page_action/pwa_install_view.cc
index 553a24e..0e61c82 100644
--- a/chrome/browser/ui/views/page_action/pwa_install_view.cc
+++ b/chrome/browser/ui/views/page_action/pwa_install_view.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/app/chrome_command_ids.h"
+#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
@@ -180,7 +181,7 @@
 
 const gfx::VectorIcon& PwaInstallView::GetVectorIcon() const {
   return OmniboxFieldTrial::IsChromeRefreshIconsEnabled()
-             ? omnibox::kInstallDesktopChromeRefreshIcon
+             ? kInstallDesktopChromeRefreshIcon
              : omnibox::kInstallDesktopIcon;
 }
 
diff --git a/chrome/browser/ui/views/profiles/profiles_pixel_test_utils.cc b/chrome/browser/ui/views/profiles/profiles_pixel_test_utils.cc
index b729a5cf..3a249930 100644
--- a/chrome/browser/ui/views/profiles/profiles_pixel_test_utils.cc
+++ b/chrome/browser/ui/views/profiles/profiles_pixel_test_utils.cc
@@ -85,6 +85,7 @@
   }
   if (params.use_chrome_refresh_2023_style) {
     enabled_features.push_back(features::kChromeRefresh2023);
+    enabled_features.push_back(features::kChromeWebuiRefresh2023);
   }
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
   if (params.use_fre_style) {
diff --git a/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_browsertest.cc b/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_browsertest.cc
index d367b96..a1f5aab 100644
--- a/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_browsertest.cc
+++ b/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_browsertest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/extensions/extension_action_test_helper.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/side_panel/extensions/extension_side_panel_coordinator.h"
 #include "chrome/browser/ui/views/side_panel/extensions/extension_side_panel_manager.h"
@@ -50,6 +51,8 @@
 
   void WaitForEntryShown() { entry_shown_run_loop_.Run(); }
 
+  void WaitForEntryHidden() { entry_hidden_run_loop_.Run(); }
+
   void WaitForIconUpdated() { icon_updated_run_loop_.Run(); }
 
  private:
@@ -57,11 +60,16 @@
     entry_shown_run_loop_.QuitWhenIdle();
   }
 
+  void OnEntryHidden(SidePanelEntry* entry) override {
+    entry_hidden_run_loop_.QuitWhenIdle();
+  }
+
   void OnEntryIconUpdated(SidePanelEntry* entry) override {
     icon_updated_run_loop_.QuitWhenIdle();
   }
 
   base::RunLoop entry_shown_run_loop_;
+  base::RunLoop entry_hidden_run_loop_;
   base::RunLoop icon_updated_run_loop_;
   base::ScopedObservation<SidePanelEntry, SidePanelEntryObserver>
       side_panel_entry_observation_{this};
@@ -160,6 +168,20 @@
         << function->GetError();
   }
 
+  // Calls chrome.sidePanel.setPanelBehavior() for the given `extension` and
+  // `openPanelOnActionClick`, and returns when the API call is complete.
+  void RunSetPanelBehavior(const Extension& extension,
+                           bool openPanelOnActionClick) {
+    auto function = base::MakeRefCounted<SidePanelSetPanelBehaviorFunction>();
+    function->set_extension(&extension);
+
+    std::string args =
+        base::StringPrintf(R"([{"openPanelOnActionClick":%s}])",
+                           openPanelOnActionClick ? "true" : "false");
+    EXPECT_TRUE(api_test_utils::RunFunction(function.get(), args, profile()))
+        << function->GetError();
+  }
+
   // Disables the extension's side panel for the current tab.
   void DisableForCurrentTab(const Extension& extension) {
     ExtensionSidePanelRegistryWaiter waiter(global_registry(), extension.id());
@@ -1068,6 +1090,112 @@
   EXPECT_FALSE(side_panel_coordinator()->IsSidePanelShowing());
 }
 
+// Test that when the openSidePanelOnClick pref is true, clicking the extension
+// icon will show the extension's entry if it's not shown, or close
+// the side panel if the extension's entry is shown.
+IN_PROC_BROWSER_TEST_F(ExtensionSidePanelBrowserTest,
+                       ToggleExtensionEntryOnUserAction) {
+  scoped_refptr<const extensions::Extension> extension = LoadExtension(
+      test_data_dir_.AppendASCII("api_test/side_panel/simple_default"));
+  ASSERT_TRUE(extension);
+
+  // Create a helper that will click the extension's icon from the menu to
+  // trigger an extension action.
+  std::unique_ptr<ExtensionActionTestHelper> action_helper =
+      ExtensionActionTestHelper::Create(browser());
+
+  SidePanelEntry::Key extension_key = GetKey(extension->id());
+
+  RunSetPanelBehavior(*extension, /*openPanelOnActionClick=*/true);
+  EXPECT_FALSE(side_panel_coordinator()->IsSidePanelShowing());
+
+  {
+    ExtensionTestMessageListener default_path_listener("default_path");
+    // Clicking the icon should show the extension's entry.
+    action_helper->Press(extension->id());
+    ASSERT_TRUE(default_path_listener.WaitUntilSatisfied());
+    EXPECT_TRUE(side_panel_coordinator()->IsSidePanelShowing());
+  }
+
+  // Switch over to another side panel entry.
+  ShowEntryAndWait(SidePanelEntry::Key(SidePanelEntry::Id::kReadingList));
+
+  {
+    TestSidePanelEntryWaiter entry_shown_waiter(
+        global_registry()->GetEntryForKey(extension_key));
+    // Since the extension's entry is not shown, clicking the icon should show
+    // it.
+    action_helper->Press(extension->id());
+    entry_shown_waiter.WaitForEntryShown();
+    EXPECT_TRUE(side_panel_coordinator()->IsSidePanelShowing());
+  }
+
+  {
+    TestSidePanelEntryWaiter entry_hidden_waiter(
+        global_registry()->GetEntryForKey(extension_key));
+    // Clicking the icon when the extension's entry is shown should close the
+    // side panel.
+    action_helper->Press(extension->id());
+    entry_hidden_waiter.WaitForEntryHidden();
+  }
+
+  EXPECT_FALSE(side_panel_coordinator()->IsSidePanelShowing());
+}
+
+// Test that extension action behavior falls back to defaults if the extension
+// has no side panel panel for the current tab (global or contextual) or if the
+// openSidePanelOnClick pref is false.
+IN_PROC_BROWSER_TEST_F(ExtensionSidePanelBrowserTest,
+                       FallbackActionWithoutSidePanel) {
+  scoped_refptr<const extensions::Extension> extension = LoadExtension(
+      test_data_dir_.AppendASCII("api_test/side_panel/with_action_onclick"));
+  ASSERT_TRUE(extension);
+
+  // Create a helper that will click the extension's icon from the menu to
+  // trigger an extension action.
+  std::unique_ptr<ExtensionActionTestHelper> action_helper =
+      ExtensionActionTestHelper::Create(browser());
+
+  SidePanelEntry::Key extension_key = GetKey(extension->id());
+
+  RunSetPanelBehavior(*extension, /*openPanelOnActionClick=*/true);
+  EXPECT_FALSE(side_panel_coordinator()->IsSidePanelShowing());
+
+  {
+    ExtensionTestMessageListener default_path_listener("default_path");
+    // Clicking the icon should show the extension's entry.
+    action_helper->Press(extension->id());
+    ASSERT_TRUE(default_path_listener.WaitUntilSatisfied());
+    EXPECT_TRUE(side_panel_coordinator()->IsSidePanelShowing());
+  }
+
+  // Set the pref to false.
+  RunSetPanelBehavior(*extension, /*openPanelOnActionClick=*/false);
+
+  {
+    ExtensionTestMessageListener action_clicked_listener("action_clicked");
+    // Since the pref is false, clicking the icon will fall back to triggering
+    // chrome.action.onClicked, which satisfies `action_clicked_listener`.
+    action_helper->Press(extension->id());
+    ASSERT_TRUE(action_clicked_listener.WaitUntilSatisfied());
+    EXPECT_TRUE(side_panel_coordinator()->IsSidePanelShowing());
+  }
+
+  // Set the pref to true but disable the extension's side panel for the current
+  // tab.
+  RunSetPanelBehavior(*extension, /*openPanelOnActionClick=*/true);
+  DisableForCurrentTab(*extension);
+
+  {
+    ExtensionTestMessageListener default_path_listener("default_path");
+    ExtensionTestMessageListener action_clicked_listener("action_clicked");
+    // Clicking the icon will fall back to triggering chrome.action.onClicked,
+    action_helper->Press(extension->id());
+    ASSERT_TRUE(action_clicked_listener.WaitUntilSatisfied());
+    EXPECT_FALSE(default_path_listener.was_satisfied());
+  }
+}
+
 // TODO(crbug.com/1378048): Add a test here which requires a browser in
 // ExtensionViewHost for both global and contextual extension entries. One
 // example of this is having a link in the page that the user can open in a new
diff --git a/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_manager.cc b/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_manager.cc
index 80b3ef8..539dc1a 100644
--- a/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_manager.cc
+++ b/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_manager.cc
@@ -6,7 +6,6 @@
 
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/extensions/create_side_panel_manager.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_registry.h"
 #include "content/public/browser/browser_context.h"
@@ -25,12 +24,6 @@
 
 }  // namespace
 
-// Defined in create_side_panel_manager.h
-void CreateSidePanelManagerForWebContents(Profile* profile,
-                                          content::WebContents* web_contents) {
-  ExtensionSidePanelManager::GetOrCreateForWebContents(profile, web_contents);
-}
-
 ExtensionSidePanelManager::ExtensionSidePanelManager(
     Profile* profile,
     Browser* browser,
diff --git a/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_utils.cc b/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_utils.cc
new file mode 100644
index 0000000..45caf3b
--- /dev/null
+++ b/chrome/browser/ui/views/side_panel/extensions/extension_side_panel_utils.cc
@@ -0,0 +1,38 @@
+// Copyright 2023 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/extensions/extension_side_panel_utils.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/side_panel/extensions/extension_side_panel_manager.h"
+#include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h"
+#include "chrome/browser/ui/views/side_panel/side_panel_entry.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/extension_id.h"
+
+namespace extensions::side_panel_util {
+
+// Defined in extension_side_panel_utils.h
+void CreateSidePanelManagerForWebContents(Profile* profile,
+                                          content::WebContents* web_contents) {
+  ExtensionSidePanelManager::GetOrCreateForWebContents(profile, web_contents);
+}
+
+// Defined in extension_side_panel_utils.h
+void ToggleExtensionSidePanel(Browser* browser,
+                              const ExtensionId& extension_id) {
+  SidePanelCoordinator* coordinator =
+      BrowserView::GetBrowserViewForBrowser(browser)->side_panel_coordinator();
+
+  SidePanelEntry::Key extension_key =
+      SidePanelEntry::Key(SidePanelEntry::Id::kExtension, extension_id);
+  if (coordinator->IsSidePanelEntryShowing(extension_key)) {
+    coordinator->Close();
+  } else {
+    coordinator->Show(extension_key);
+  }
+}
+
+}  // namespace extensions::side_panel_util
diff --git a/chrome/browser/ui/views/side_panel/lens/lens_core_tab_side_panel_helper.cc b/chrome/browser/ui/views/side_panel/lens/lens_core_tab_side_panel_helper.cc
index 80a99c1..1560ffef 100644
--- a/chrome/browser/ui/views/side_panel/lens/lens_core_tab_side_panel_helper.cc
+++ b/chrome/browser/ui/views/side_panel/lens/lens_core_tab_side_panel_helper.cc
@@ -16,6 +16,7 @@
 #else
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/side_panel/companion/companion_utils.h"
 #endif  // BUILDFLAG(IS_ANDROID)
 
 namespace lens {
@@ -53,10 +54,15 @@
 }  // namespace internal
 
 bool IsSidePanelEnabledForLens(content::WebContents* web_contents) {
+  // Companion feature being enabled should disable Lens in the side panel.
+  bool is_companion_enabled = false;
+#if !BUILDFLAG(IS_ANDROID)
+  is_companion_enabled = companion::IsCompanionFeatureEnabled();
+#endif
   return search::DefaultSearchProviderIsGoogle(
              lens::internal::GetTemplateURLService(web_contents)) &&
          lens::internal::IsSidePanelEnabled(web_contents) &&
-         lens::features::IsLensSidePanelEnabled();
+         lens::features::IsLensSidePanelEnabled() && !is_companion_enabled;
 }
 
 bool IsSidePanelEnabledForLensRegionSearch(content::WebContents* web_contents) {
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 bbe4317..f024ddc 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
+++ b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
@@ -375,6 +375,12 @@
 }
 
 bool SidePanelCoordinator::IsSidePanelEntryShowing(
+    const SidePanelEntry::Key& entry_key) const {
+  return IsSidePanelShowing() && current_entry_ &&
+         current_entry_->key() == entry_key;
+}
+
+bool SidePanelCoordinator::IsSidePanelEntryShowing(
     const SidePanelEntry* entry) const {
   return IsSidePanelShowing() && current_entry_ &&
          current_entry_.get() == entry;
diff --git a/chrome/browser/ui/views/side_panel/side_panel_coordinator.h b/chrome/browser/ui/views/side_panel/side_panel_coordinator.h
index be4df2d..7d3d964 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_coordinator.h
+++ b/chrome/browser/ui/views/side_panel/side_panel_coordinator.h
@@ -97,6 +97,11 @@
 
   bool IsSidePanelShowing() const;
 
+  // Returns whether `entry_key` is currently being shown in the side panel.
+  // Note: this returns false if `entry` is current loading but not actually
+  // shown.
+  bool IsSidePanelEntryShowing(const SidePanelEntry::Key& entry_key) const;
+
   // Returns whether `entry` is currently being shown in the side panel. Note:
   // this returns false if `entry` is current loading but not actually shown.
   bool IsSidePanelEntryShowing(const SidePanelEntry* entry) const;
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc
index 704e9196..77ce369 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.cc
+++ b/chrome/browser/ui/views/tabs/new_tab_button.cc
@@ -67,6 +67,24 @@
                            ui::EF_MIDDLE_MOUSE_BUTTON);
 #endif
 
+  if (features::IsChromeRefresh2023()) {
+    foreground_frame_active_color_id_ =
+        kColorNewTabButtonCRForegroundFrameActive;
+    foreground_frame_inactive_color_id_ =
+        kColorNewTabButtonCRForegroundFrameInactive;
+    background_frame_active_color_id_ =
+        kColorNewTabButtonCRBackgroundFrameActive;
+    background_frame_inactive_color_id_ =
+        kColorNewTabButtonCRBackgroundFrameInactive;
+  } else {
+    foreground_frame_active_color_id_ = kColorNewTabButtonForegroundFrameActive;
+    foreground_frame_inactive_color_id_ =
+        kColorNewTabButtonForegroundFrameInactive;
+    background_frame_active_color_id_ = kColorNewTabButtonBackgroundFrameActive;
+    background_frame_inactive_color_id_ =
+        kColorNewTabButtonBackgroundFrameInactive;
+  }
+
   ink_drop_container_ =
       AddChildView(std::make_unique<views::InkDropContainerView>());
 
@@ -117,8 +135,8 @@
   if (features::IsChromeRefresh2023()) {
     return GetColorProvider()->GetColor(
         tab_strip_->ShouldPaintAsActiveFrame()
-            ? kColorNewTabButtonForegroundFrameActive
-            : kColorNewTabButtonForegroundFrameInactive);
+            ? foreground_frame_active_color_id_
+            : foreground_frame_inactive_color_id_);
   }
   return tab_strip_->GetTabForegroundColor(TabActive::kInactive);
 }
@@ -263,8 +281,8 @@
   } else {
     flags.setColor(GetColorProvider()->GetColor(
         tab_strip_->ShouldPaintAsActiveFrame()
-            ? kColorNewTabButtonBackgroundFrameActive
-            : kColorNewTabButtonBackgroundFrameInactive));
+            ? background_frame_active_color_id_
+            : background_frame_inactive_color_id_));
   }
 
   canvas->DrawPath(GetBorderPath(gfx::Point(), scale, false), flags);
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.h b/chrome/browser/ui/views/tabs/new_tab_button.h
index 4781c16..6f882fa3 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.h
+++ b/chrome/browser/ui/views/tabs/new_tab_button.h
@@ -98,6 +98,12 @@
 
   base::CallbackListSubscription paint_as_active_subscription_;
 
+  // Stored ColorId values to differentiate for ChromeRefresh.
+  ui::ColorId foreground_frame_active_color_id_;
+  ui::ColorId foreground_frame_inactive_color_id_;
+  ui::ColorId background_frame_active_color_id_;
+  ui::ColorId background_frame_inactive_color_id_;
+
   // For tracking whether this object has been destroyed. Must be last.
   base::WeakPtrFactory<NewTabButton> weak_factory_{this};
 };
diff --git a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
index 5b91c89..a28dd2b 100644
--- a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
@@ -654,6 +654,10 @@
   SavedTabGroupKeyedService* const saved_tab_group_service =
       SavedTabGroupServiceFactory::GetForProfile(browser_->profile());
 
+  if (!saved_tab_group_service) {
+    return l10n_util::GetStringUTF16(IDS_TAB_GROUP_HEADER_CXMENU_DELETE_GROUP);
+  }
+
   return saved_tab_group_service->model()->Contains(group_)
              ? l10n_util::GetStringUTF16(
                    IDS_TAB_GROUP_HEADER_CXMENU_CLOSE_GROUP)
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc
index 563fef0..eac19b09d 100644
--- a/chrome/browser/ui/views/tabs/tab_style_views.cc
+++ b/chrome/browser/ui/views/tabs/tab_style_views.cc
@@ -97,6 +97,9 @@
   // treated as an active tab regardless of its true current state.
   virtual int GetStrokeThickness(bool should_paint_as_active = false) const;
 
+  virtual bool ShouldPaintTabBackgroundColor(TabActive active,
+                                             bool has_custom_background) const;
+
   // Returns the progress (0 to 1) of the hover animation.
   double GetHoverAnimationValue() const override;
 
@@ -134,9 +137,6 @@
   // Gets the throb value. A value of 0 indicates no throbbing.
   float GetThrobValue() const;
 
-  bool ShouldPaintTabBackgroundColor(TabActive active,
-                                     bool has_custom_background) const;
-
   // When selected, non-active, non-hovered tabs are adjacent to each other,
   // there are anti-aliasing artifacts in the overlapped lower arc region. This
   // returns how to modify the tab shape to eliminate the lower arcs on the
@@ -848,8 +848,7 @@
 
   canvas->ClipPath(fill_path, true);
 
-  if ((tab_->IsActive() || tab_->IsSelected()) &&
-      ShouldPaintTabBackgroundColor(active, fill_id.has_value())) {
+  if (ShouldPaintTabBackgroundColor(active, fill_id.has_value())) {
     cc::PaintFlags flags;
     flags.setAntiAlias(true);
     flags.setColor(GetTabBackgroundColor(active));
@@ -997,6 +996,8 @@
   int GetStrokeThickness(bool should_paint_as_active = false) const override;
   void PaintBackgroundHover(gfx::Canvas* canvas, float scale) const override;
   SkColor GetTabSeparatorColor() const override;
+  bool ShouldPaintTabBackgroundColor(TabActive active,
+                                     bool has_custom_background) const override;
 };
 
 ChromeRefresh2023TabStyleViews::ChromeRefresh2023TabStyleViews(Tab* tab)
@@ -1066,6 +1067,14 @@
                           : kColorTabDividerFrameInactive);
 }
 
+bool ChromeRefresh2023TabStyleViews::ShouldPaintTabBackgroundColor(
+    TabActive active,
+    bool has_custom_background) const {
+  return (tab()->IsActive() || tab()->IsSelected()) &&
+         GM2TabStyleViews::ShouldPaintTabBackgroundColor(active,
+                                                         has_custom_background);
+}
+
 }  // namespace
 
 // static
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc
index e5ac6ac1..67418448 100644
--- a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc
@@ -68,7 +68,7 @@
       std::string(kEmailBase) + account_suffix,
       std::string(kNameBase) + account_suffix,
       std::string(kGivenNameBase) + account_suffix, GURL::EmptyGURL(),
-      login_state);
+      std::vector<std::string>(), login_state);
 }
 
 std::vector<content::IdentityRequestAccount> CreateTestIdentityRequestAccounts(
diff --git a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_browsertest.cc b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_browsertest.cc
index 76dce00..40654a9 100644
--- a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_browsertest.cc
+++ b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_browsertest.cc
@@ -28,7 +28,8 @@
 
   void ShowUi(const std::string& name) override {
     std::vector<content::IdentityRequestAccount> accounts = {
-        {"id", "email", "name", "given_name", GURL::EmptyGURL()}};
+        {"id", "email", "name", "given_name", GURL::EmptyGURL(),
+         std::vector<std::string>()}};
     account_selection_view()->Show(
         "top-frame-example.com",
         absl::make_optional<std::string>("iframe-example.com"),
diff --git a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc
index 5ab768ec..d4ddbf2 100644
--- a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc
+++ b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc
@@ -178,7 +178,7 @@
     std::vector<content::IdentityRequestAccount> accounts;
     for (const auto& account_info : account_infos) {
       accounts.emplace_back(account_info.first, "", "", "", GURL::EmptyGURL(),
-                            account_info.second);
+                            std::vector<std::string>(), account_info.second);
     }
     return IdentityProviderDisplayData(u"", content::IdentityProviderMetadata(),
                                        content::ClientMetadata(GURL(), GURL()),
diff --git a/chrome/browser/ui/views/webid/fedcm_modal_dialog_view.cc b/chrome/browser/ui/views/webid/fedcm_modal_dialog_view.cc
new file mode 100644
index 0000000..751fb46
--- /dev/null
+++ b/chrome/browser/ui/views/webid/fedcm_modal_dialog_view.cc
@@ -0,0 +1,112 @@
+// Copyright 2023 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/views/webid/fedcm_modal_dialog_view.h"
+
+#include "components/constrained_window/constrained_window_views.h"
+#include "components/url_formatter/elide_url.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/webview/webview.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/table_layout.h"
+
+FedCmModalDialogView::FedCmModalDialogView(content::WebContents* web_contents,
+                                           const GURL& url)
+    : web_contents_(web_contents), curr_origin_(url::Origin::Create(url)) {
+  SetModalType(ui::MODAL_TYPE_CHILD);
+  SetButtons(ui::DIALOG_BUTTON_NONE);
+  Init(url);
+}
+
+FedCmModalDialogView::~FedCmModalDialogView() = default;
+
+// static
+FedCmModalDialogView* FedCmModalDialogView::ShowFedCmModalDialog(
+    content::WebContents* web_contents,
+    const GURL& url) {
+  // This dialog owns itself. DialogDelegateView will delete |dialog| instance.
+  FedCmModalDialogView* dialog = new FedCmModalDialogView(web_contents, url);
+  constrained_window::ShowWebModalDialogViews(dialog, web_contents);
+  return dialog;
+}
+
+void FedCmModalDialogView::Init(const GURL& url) {
+  constexpr int kDialogMinWidth = 512;
+  constexpr int kDialogHeight = 450;
+  constexpr int kVerticalInset = 8;
+  constexpr int kHeaderHorizontalInset = 16;
+
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical));
+
+  auto contents_wrapper = std::make_unique<views::View>();
+  contents_wrapper->SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical));
+  contents_wrapper->SetBorder(views::CreateEmptyBorder(
+      gfx::Insets::TLBR(kVerticalInset, kHeaderHorizontalInset, kVerticalInset,
+                        kHeaderHorizontalInset)));
+
+  auto* header_view =
+      contents_wrapper->AddChildView(std::make_unique<views::View>());
+  header_view = PopulateSheetHeaderView(header_view, url);
+
+  auto* web_view = contents_wrapper->AddChildView(
+      std::make_unique<views::WebView>(web_contents_->GetBrowserContext()));
+
+  web_view->SetPreferredSize(gfx::Size(kDialogMinWidth, kDialogHeight));
+  web_view->LoadInitialURL(url);
+
+  web_modal::WebContentsModalDialogManager::CreateForWebContents(
+      web_view->GetWebContents());
+  web_modal::WebContentsModalDialogManager::FromWebContents(
+      web_view->GetWebContents())
+      ->SetDelegate(this);
+
+  Observe(web_view->GetWebContents());
+
+  contents_wrapper_ = AddChildView(std::move(contents_wrapper));
+}
+
+views::View* FedCmModalDialogView::PopulateSheetHeaderView(
+    views::View* container,
+    const GURL& url) {
+  views::TableLayout* layout =
+      container->SetLayoutManager(std::make_unique<views::TableLayout>());
+  layout->AddRows(1, views::TableLayout::kFixedSize);
+
+  // Origin column.
+  layout->AddColumn(
+      views::LayoutAlignment::kStretch, views::LayoutAlignment::kStretch,
+      /*horizontal_resize=*/1.0, views::TableLayout::ColumnSize::kUsePreferred,
+      /*fixed_width=*/0,
+      /*min_width=*/0);
+  layout->AddRows(1, views::TableLayout::kFixedSize);
+
+  // Add the origin label.
+  origin_label_ = container->AddChildView(std::make_unique<views::Label>(
+      url_formatter::FormatOriginForSecurityDisplay(
+          curr_origin_, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC)));
+  origin_label_->SetElideBehavior(gfx::ELIDE_HEAD);
+  origin_label_->SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY);
+
+  return container;
+}
+
+void FedCmModalDialogView::PrimaryPageChanged(content::Page& page) {
+  const url::Origin origin = page.GetMainDocument().GetLastCommittedOrigin();
+  if (!origin_label_ || origin.IsSameOriginWith(curr_origin_)) {
+    return;
+  }
+
+  // Update the origin label.
+  origin_label_->SetText(url_formatter::FormatOriginForSecurityDisplay(
+      origin, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
+  curr_origin_ = origin;
+}
+
+BEGIN_METADATA(FedCmModalDialogView, views::DialogDelegateView)
+END_METADATA
diff --git a/chrome/browser/ui/views/webid/fedcm_modal_dialog_view.h b/chrome/browser/ui/views/webid/fedcm_modal_dialog_view.h
new file mode 100644
index 0000000..d99c233
--- /dev/null
+++ b/chrome/browser/ui/views/webid/fedcm_modal_dialog_view.h
@@ -0,0 +1,51 @@
+// Copyright 2023 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_VIEWS_WEBID_FEDCM_MODAL_DIALOG_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_WEBID_FEDCM_MODAL_DIALOG_VIEW_H_
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
+#include "content/public/browser/page.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/window/dialog_delegate.h"
+
+// A dialog allowing the user to complete a flow (e.g. signing in to an identity
+// provider) prompted by FedCM.
+class FedCmModalDialogView : public views::DialogDelegateView,
+                             public content::WebContentsObserver,
+                             public ChromeWebModalDialogManagerDelegate {
+ public:
+  METADATA_HEADER(FedCmModalDialogView);
+  FedCmModalDialogView(content::WebContents* web_contents, const GURL& url);
+  FedCmModalDialogView(const FedCmModalDialogView&) = delete;
+  FedCmModalDialogView& operator=(const FedCmModalDialogView&) = delete;
+  ~FedCmModalDialogView() override;
+
+  // Shows a modal dialog of |url| prompted by FedCM on |web_contents|. The
+  // |url| is commonly but not limited to a URL which allows the user to sign in
+  // with an identity provider.
+  static FedCmModalDialogView* ShowFedCmModalDialog(
+      content::WebContents* web_contents,
+      const GURL& url);
+
+ private:
+  views::View* PopulateSheetHeaderView(views::View* container, const GURL& url);
+  void Init(const GURL& url);
+
+  // content::WebContentsObserver:
+  void PrimaryPageChanged(content::Page& page) override;
+
+  raw_ptr<content::WebContents> web_contents_;
+  raw_ptr<views::View> contents_wrapper_;
+  raw_ptr<views::Label> origin_label_;
+  url::Origin curr_origin_;
+
+  base::WeakPtrFactory<FedCmModalDialogView> weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_WEBID_FEDCM_MODAL_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/views/webid/fedcm_modal_dialog_view_browsertest.cc b/chrome/browser/ui/views/webid/fedcm_modal_dialog_view_browsertest.cc
new file mode 100644
index 0000000..c1931f75
--- /dev/null
+++ b/chrome/browser/ui/views/webid/fedcm_modal_dialog_view_browsertest.cc
@@ -0,0 +1,32 @@
+// Copyright 2023 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/functional/callback_helpers.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/test/test_browser_dialog.h"
+#include "chrome/browser/ui/views/webid/fedcm_modal_dialog_view.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test.h"
+
+class FedCmModalDialogViewBrowserTest : public DialogBrowserTest {
+ public:
+  FedCmModalDialogViewBrowserTest() = default;
+  ~FedCmModalDialogViewBrowserTest() override = default;
+
+  void ShowUi(const std::string& name) override {
+    FedCmModalDialogView::ShowFedCmModalDialog(
+        browser()->tab_strip_model()->GetActiveWebContents(),
+        GURL(u"https://example.com"));
+  }
+
+ private:
+  base::WeakPtrFactory<FedCmModalDialogViewBrowserTest> weak_factory_{this};
+};
+
+IN_PROC_BROWSER_TEST_F(FedCmModalDialogViewBrowserTest, InvokeUi_default) {
+  ShowAndVerifyUi();
+}
diff --git a/chrome/browser/ui/views/webid/fedcm_modal_dialog_view_unittest.cc b/chrome/browser/ui/views/webid/fedcm_modal_dialog_view_unittest.cc
new file mode 100644
index 0000000..0436b85d
--- /dev/null
+++ b/chrome/browser/ui/views/webid/fedcm_modal_dialog_view_unittest.cc
@@ -0,0 +1,73 @@
+// Copyright 2023 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/views/webid/fedcm_modal_dialog_view.h"
+
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/views/chrome_views_test_base.h"
+#include "content/public/test/test_web_contents_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/views/controls/label.h"
+
+class FedCmModalDialogView;
+
+namespace {
+
+std::vector<std::string> GetChildClassNames(views::View* parent) {
+  std::vector<std::string> child_class_names;
+  for (views::View* child_view : parent->children()) {
+    child_class_names.push_back(child_view->GetClassName());
+  }
+  return child_class_names;
+}
+
+views::View* GetViewWithClassName(views::View* parent,
+                                  const std::string& class_name) {
+  for (views::View* child_view : parent->children()) {
+    if (child_view->GetClassName() == class_name) {
+      return child_view;
+    }
+  }
+  return nullptr;
+}
+
+}  // namespace
+
+class FedCmModalDialogViewTest : public ChromeViewsTestBase {
+ public:
+  FedCmModalDialogViewTest() {
+    web_contents_ = web_contents_factory_.CreateWebContents(&testing_profile_);
+  }
+
+ protected:
+  content::WebContents* web_contents() { return web_contents_; }
+
+ private:
+  TestingProfile testing_profile_;
+  content::TestWebContentsFactory web_contents_factory_;
+  raw_ptr<content::WebContents>
+      web_contents_;  // Owned by `web_contents_factory_`.
+};
+
+TEST_F(FedCmModalDialogViewTest, Init) {
+  FedCmModalDialogView modal_dialog_view =
+      FedCmModalDialogView(web_contents(), GURL(u"https://example.com"));
+  views::View* view = modal_dialog_view.GetContentsView();
+
+  const std::vector<views::View*> container = view->children();
+  ASSERT_EQ(container.size(), 1u);
+
+  // Check for header and web view.
+  const std::vector<views::View*> children = container[0]->children();
+  ASSERT_EQ(children.size(), 2u);
+  EXPECT_THAT(GetChildClassNames(container[0]),
+              testing::ElementsAreArray({"View", "WebView"}));
+
+  // Check origin label in header.
+  views::View* header = children[0];
+  views::Label* origin_label =
+      static_cast<views::Label*>(GetViewWithClassName(header, "Label"));
+  ASSERT_TRUE(origin_label);
+  EXPECT_EQ(origin_label->GetText(), u"example.com");
+}
diff --git a/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog_browsertest.cc b/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog_browsertest.cc
index 972ed54..a866f3b 100644
--- a/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog_browsertest.cc
@@ -31,94 +31,71 @@
   return first.status == second.status &&
          first.parent_access_token == second.parent_access_token;
 }
+
+parent_access_ui::mojom::ParentAccessParamsPtr GetTestParamsForFlowType(
+    parent_access_ui::mojom::ParentAccessParams::FlowType flow_type) {
+  switch (flow_type) {
+    case parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess:
+      return parent_access_ui::mojom::ParentAccessParams::New(
+          flow_type,
+          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
+              parent_access_ui::mojom::WebApprovalsParams::New()),
+          /*is_disabled=*/false);
+    case parent_access_ui::mojom::ParentAccessParams::FlowType::
+        kExtensionAccess:
+      return parent_access_ui::mojom::ParentAccessParams::New(
+          flow_type,
+          parent_access_ui::mojom::FlowTypeParams::NewExtensionApprovalsParams(
+              parent_access_ui::mojom::ExtensionApprovalsParams::New()),
+          /*is_disabled=*/false);
+  }
+}
 }  // namespace
 
 namespace ash {
 
-using ParentAccessDialogBrowserTest = ParentAccessChildUserBrowserTestBase;
+class ParentAccessDialogBrowserTest
+    : public ParentAccessChildUserBrowserTestBase,
+      public testing::WithParamInterface<
+          parent_access_ui::mojom::ParentAccessParams::FlowType> {
+ public:
+  ParentAccessDialogBrowserTest() = default;
+
+  parent_access_ui::mojom::ParentAccessParams::FlowType GetTestedFlowType()
+      const {
+    return GetParam();
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    ParentAccessDialogBrowserTest,
+    testing::Values(
+        parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
+        parent_access_ui::mojom::ParentAccessParams::FlowType::
+            kExtensionAccess));
 
 // Verify that the dialog is shown and correctly configured.
-IN_PROC_BROWSER_TEST_F(ParentAccessDialogBrowserTest, ShowDialog) {
+IN_PROC_BROWSER_TEST_P(ParentAccessDialogBrowserTest, ShowDialog) {
   base::RunLoop run_loop;
 
-  // Create the callback.
   ParentAccessDialog::Callback callback = base::BindLambdaForTesting(
       [&](std::unique_ptr<ParentAccessDialog::Result> result) -> void {
         EXPECT_EQ(result->status,
                   ParentAccessDialog::Result::Status::kCanceled);
         run_loop.Quit();
       });
-
-  // Show the dialog.
   ParentAccessDialogProvider provider;
   ParentAccessDialogProvider::ShowError error = provider.Show(
-      parent_access_ui::mojom::ParentAccessParams::New(
-          parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
-          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
-              parent_access_ui::mojom::WebApprovalsParams::New()),
-          /*is_disabled=*/false),
-      std::move(callback));
+      GetTestParamsForFlowType(GetTestedFlowType()), std::move(callback));
 
-  // Verify it is showing.
+  // Verify dialog is showing.
   ASSERT_EQ(error, ParentAccessDialogProvider::ShowError::kNone);
   ASSERT_NE(ParentAccessDialog::GetInstance(), nullptr);
   const ParentAccessDialog* dialog = ParentAccessDialog::GetInstance();
   parent_access_ui::mojom::ParentAccessParams* params =
       dialog->GetParentAccessParamsForTest();
-  EXPECT_EQ(
-      params->flow_type,
-      parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess);
-
-  // Verify that it is correctly configured.
-  EXPECT_EQ(dialog->GetDialogContentURL().spec(),
-            chrome::kChromeUIParentAccessURL);
-  EXPECT_TRUE(dialog->ShouldShowCloseButton());
-  EXPECT_EQ(dialog->GetDialogModalType(), ui::ModalType::MODAL_TYPE_SYSTEM);
-
-  // Send ESCAPE keypress.  EventGenerator requires the root window, which has
-  // to be fetched from the Ash shell.
-  ui::test::EventGenerator generator(Shell::Get()->GetPrimaryRootWindow());
-  generator.PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
-
-  // The dialog instance should be gone after ESC is pressed.
-  EXPECT_EQ(ParentAccessDialog::GetInstance(), nullptr);
-
-  run_loop.Run();
-}
-
-IN_PROC_BROWSER_TEST_F(ParentAccessDialogBrowserTest,
-                       ShowDialogWithParentAccessDisabled) {
-  base::RunLoop run_loop;
-
-  // Create the callback.
-  // TODO(b/266830608): Change this to kDisabled once the disabled state is
-  // implemented in ParentAccess mojo interface.
-  ParentAccessDialog::Callback callback = base::BindLambdaForTesting(
-      [&](std::unique_ptr<ParentAccessDialog::Result> result) -> void {
-        EXPECT_EQ(result->status,
-                  ParentAccessDialog::Result::Status::kCanceled);
-        run_loop.Quit();
-      });
-
-  // Show the dialog.
-  ParentAccessDialogProvider provider;
-  ParentAccessDialogProvider::ShowError error =
-      provider.Show(parent_access_ui::mojom::ParentAccessParams::New(
-                        parent_access_ui::mojom::ParentAccessParams::FlowType::
-                            kExtensionAccess,
-                        nullptr,
-                        /*is_disabled=*/true),
-                    std::move(callback));
-
-  // Verify it is showing.
-  ASSERT_EQ(error, ParentAccessDialogProvider::ShowError::kNone);
-  ASSERT_NE(ParentAccessDialog::GetInstance(), nullptr);
-  const ParentAccessDialog* dialog = ParentAccessDialog::GetInstance();
-  parent_access_ui::mojom::ParentAccessParams* params =
-      dialog->GetParentAccessParamsForTest();
-  EXPECT_EQ(
-      params->flow_type,
-      parent_access_ui::mojom::ParentAccessParams::FlowType::kExtensionAccess);
+  EXPECT_EQ(params->flow_type, GetTestedFlowType());
 
   // Verify that it is correctly configured.
   EXPECT_EQ(dialog->GetDialogContentURL().spec(),
@@ -138,7 +115,7 @@
 }
 
 // Verify that the dialog is closed on Approve.
-IN_PROC_BROWSER_TEST_F(ParentAccessDialogBrowserTest, SetApproved) {
+IN_PROC_BROWSER_TEST_P(ParentAccessDialogBrowserTest, SetApproved) {
   base::RunLoop run_loop;
 
   ParentAccessDialog::Result expected_result;
@@ -147,24 +124,16 @@
   expected_result.parent_access_token_expire_timestamp =
       base::Time::FromDoubleT(123456L);
 
-  // Create the callback.
   ParentAccessDialog::Callback callback = base::BindLambdaForTesting(
       [&](std::unique_ptr<ParentAccessDialog::Result> result) -> void {
         EXPECT_TRUE(DialogResultsEqual(*result, expected_result));
         run_loop.Quit();
       });
 
-  // Show the dialog.
   ParentAccessDialogProvider provider;
-  provider.Show(
-      parent_access_ui::mojom::ParentAccessParams::New(
-          parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
-          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
-              parent_access_ui::mojom::WebApprovalsParams::New()),
-          /*is_disabled=*/false),
-      std::move(callback));
+  provider.Show(GetTestParamsForFlowType(GetTestedFlowType()),
+                std::move(callback));
 
-  // Set the result.
   ParentAccessDialog::GetInstance()->SetApproved(
       expected_result.parent_access_token,
       expected_result.parent_access_token_expire_timestamp);
@@ -176,30 +145,22 @@
 }
 
 // Verify that the dialog is closed on Decline.
-IN_PROC_BROWSER_TEST_F(ParentAccessDialogBrowserTest, SetDeclined) {
+IN_PROC_BROWSER_TEST_P(ParentAccessDialogBrowserTest, SetDeclined) {
   base::RunLoop run_loop;
 
   ParentAccessDialog::Result expected_result;
   expected_result.status = ParentAccessDialog::Result::Status::kDeclined;
 
-  // Create the callback.
   ParentAccessDialog::Callback callback = base::BindLambdaForTesting(
       [&](std::unique_ptr<ParentAccessDialog::Result> result) -> void {
         EXPECT_TRUE(DialogResultsEqual(*result, expected_result));
         run_loop.Quit();
       });
 
-  // Show the dialog.
   ParentAccessDialogProvider provider;
-  provider.Show(
-      parent_access_ui::mojom::ParentAccessParams::New(
-          parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
-          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
-              parent_access_ui::mojom::WebApprovalsParams::New()),
-          /*is_disabled=*/false),
-      std::move(callback));
+  provider.Show(GetTestParamsForFlowType(GetTestedFlowType()),
+                std::move(callback));
 
-  // Set the result.
   ParentAccessDialog::GetInstance()->SetDeclined();
 
   run_loop.Run();
@@ -209,30 +170,22 @@
 }
 
 // Verify that the dialog is closed on Cancel.
-IN_PROC_BROWSER_TEST_F(ParentAccessDialogBrowserTest, SetCanceled) {
+IN_PROC_BROWSER_TEST_P(ParentAccessDialogBrowserTest, SetCanceled) {
   base::RunLoop run_loop;
 
   ParentAccessDialog::Result expected_result;
   expected_result.status = ParentAccessDialog::Result::Status::kCanceled;
 
-  // Create the callback.
   ParentAccessDialog::Callback callback = base::BindLambdaForTesting(
       [&](std::unique_ptr<ParentAccessDialog::Result> result) -> void {
         EXPECT_TRUE(DialogResultsEqual(*result, expected_result));
         run_loop.Quit();
       });
 
-  // Show the dialog.
   ParentAccessDialogProvider provider;
-  provider.Show(
-      parent_access_ui::mojom::ParentAccessParams::New(
-          parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
-          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
-              parent_access_ui::mojom::WebApprovalsParams::New()),
-          /*is_disabled=*/false),
-      std::move(callback));
+  provider.Show(GetTestParamsForFlowType(GetTestedFlowType()),
+                std::move(callback));
 
-  // Set the result.
   ParentAccessDialog::GetInstance()->SetCanceled();
 
   run_loop.Run();
@@ -242,30 +195,22 @@
 }
 
 // Verify that the dialog is closed on Cancel.
-IN_PROC_BROWSER_TEST_F(ParentAccessDialogBrowserTest, SetError) {
+IN_PROC_BROWSER_TEST_P(ParentAccessDialogBrowserTest, SetError) {
   base::RunLoop run_loop;
 
   ParentAccessDialog::Result expected_result;
   expected_result.status = ParentAccessDialog::Result::Status::kError;
 
-  // Create the callback.
   ParentAccessDialog::Callback callback = base::BindLambdaForTesting(
       [&](std::unique_ptr<ParentAccessDialog::Result> result) -> void {
         EXPECT_TRUE(DialogResultsEqual(*result, expected_result));
         run_loop.Quit();
       });
 
-  // Show the dialog.
   ParentAccessDialogProvider provider;
-  provider.Show(
-      parent_access_ui::mojom::ParentAccessParams::New(
-          parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
-          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
-              parent_access_ui::mojom::WebApprovalsParams::New()),
-          /*is_disabled=*/false),
-      std::move(callback));
+  provider.Show(GetTestParamsForFlowType(GetTestedFlowType()),
+                std::move(callback));
 
-  // Set the result.
   ParentAccessDialog::GetInstance()->SetError();
 
   // The dialog instance should not be closed in the error state.
@@ -278,30 +223,22 @@
 
 // Verify that if dialog is destroyed without a Result,  it reports being
 // canceled.
-IN_PROC_BROWSER_TEST_F(ParentAccessDialogBrowserTest, DestroyedWithoutResult) {
+IN_PROC_BROWSER_TEST_P(ParentAccessDialogBrowserTest, DestroyedWithoutResult) {
   base::RunLoop run_loop;
 
   ParentAccessDialog::Result expected_result;
   expected_result.status = ParentAccessDialog::Result::Status::kCanceled;
 
-  // Create the callback.
   ParentAccessDialog::Callback callback = base::BindLambdaForTesting(
       [&](std::unique_ptr<ParentAccessDialog::Result> result) -> void {
         EXPECT_TRUE(DialogResultsEqual(*result, expected_result));
         run_loop.Quit();
       });
 
-  // Show the dialog.
   ParentAccessDialogProvider provider;
-  provider.Show(
-      parent_access_ui::mojom::ParentAccessParams::New(
-          parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
-          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
-              parent_access_ui::mojom::WebApprovalsParams::New()),
-          /*is_disabled=*/false),
-      std::move(callback));
+  provider.Show(GetTestParamsForFlowType(GetTestedFlowType()),
+                std::move(callback));
 
-  // Set the result.
   ParentAccessDialog::GetInstance()->Close();
 
   run_loop.Run();
@@ -310,35 +247,22 @@
   EXPECT_EQ(ParentAccessDialog::GetInstance(), nullptr);
 }
 
-IN_PROC_BROWSER_TEST_F(ParentAccessDialogBrowserTest,
+IN_PROC_BROWSER_TEST_P(ParentAccessDialogBrowserTest,
                        ErrorOnDialogAlreadyVisible) {
   base::HistogramTester histogram_tester;
-  // Show the dialog.
   ParentAccessDialogProvider provider;
   ParentAccessDialogProvider::ShowError error = provider.Show(
-      parent_access_ui::mojom::ParentAccessParams::New(
-          parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
-          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
-              parent_access_ui::mojom::WebApprovalsParams::New()),
-          /*is_disabled=*/false),
-      base::DoNothing());
+      GetTestParamsForFlowType(GetTestedFlowType()), base::DoNothing());
 
-  // Verify it is showing.
+  // Verify the dialog is showing.
   ASSERT_EQ(error, ParentAccessDialogProvider::ShowError::kNone);
   ASSERT_NE(ParentAccessDialog::GetInstance(), nullptr);
   parent_access_ui::mojom::ParentAccessParams* params =
       ParentAccessDialog::GetInstance()->GetParentAccessParamsForTest();
-  EXPECT_EQ(
-      params->flow_type,
-      parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess);
+  EXPECT_EQ(params->flow_type, GetTestedFlowType());
 
-  error = provider.Show(
-      parent_access_ui::mojom::ParentAccessParams::New(
-          parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
-          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
-              parent_access_ui::mojom::WebApprovalsParams::New()),
-          false),
-      base::DoNothing());
+  error = provider.Show(GetTestParamsForFlowType(GetTestedFlowType()),
+                        base::DoNothing());
 
   // Verify an error was returned indicating it can't be shown again.
   EXPECT_EQ(error,
@@ -354,33 +278,79 @@
   histogram_tester.ExpectUniqueSample(
       parent_access::GetHistogramTitleForFlowType(
           parent_access::kParentAccessWidgetShowDialogErrorHistogramBase,
-          parent_access_ui::mojom::ParentAccessParams::FlowType::
-              kWebsiteAccess),
+          GetTestedFlowType()),
       ParentAccessDialogProvider::ShowErrorType::kAlreadyVisible, 1);
 }
 
-using ParentAccessDialogRegularUserBrowserTest =
-    ParentAccessRegularUserBrowserTestBase;
+using ParentAccessDialogExtensionApprovalsDisabledTest =
+    ParentAccessChildUserBrowserTestBase;
+
+// Only test disabled case for Extension flow because it is not possible for
+// other flows.
+IN_PROC_BROWSER_TEST_F(ParentAccessDialogExtensionApprovalsDisabledTest,
+                       SetDisabled) {
+  base::RunLoop run_loop;
+
+  ParentAccessDialog::Result expected_result;
+  expected_result.status = ParentAccessDialog::Result::Status::kDisabled;
+
+  ParentAccessDialog::Callback callback = base::BindLambdaForTesting(
+      [&](std::unique_ptr<ParentAccessDialog::Result> result) -> void {
+        EXPECT_TRUE(DialogResultsEqual(*result, expected_result));
+        run_loop.Quit();
+      });
+
+  ParentAccessDialogProvider provider;
+  provider.Show(
+      parent_access_ui::mojom::ParentAccessParams::New(
+          parent_access_ui::mojom::ParentAccessParams::FlowType::
+              kExtensionAccess,
+          parent_access_ui::mojom::FlowTypeParams::NewExtensionApprovalsParams(
+              parent_access_ui::mojom::ExtensionApprovalsParams::New()),
+          /*is_disabled=*/true),
+      std::move(callback));
+
+  ParentAccessDialog::GetInstance()->SetDisabled();
+
+  run_loop.Run();
+
+  // The dialog instance should be gone after SetResult() is called.
+  EXPECT_EQ(ParentAccessDialog::GetInstance(), nullptr);
+}
+
+class ParentAccessDialogRegularUserBrowserTest
+    : public ParentAccessRegularUserBrowserTestBase,
+      public testing::WithParamInterface<
+          parent_access_ui::mojom::ParentAccessParams::FlowType> {
+ public:
+  ParentAccessDialogRegularUserBrowserTest() = default;
+
+  parent_access_ui::mojom::ParentAccessParams::FlowType GetTestedFlowType()
+      const {
+    return GetParam();
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    ParentAccessDialogRegularUserBrowserTest,
+    testing::Values(
+        parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
+        parent_access_ui::mojom::ParentAccessParams::FlowType::
+            kExtensionAccess));
 
 // Verify that the dialog is not shown for non child users.
-IN_PROC_BROWSER_TEST_F(ParentAccessDialogRegularUserBrowserTest,
+IN_PROC_BROWSER_TEST_P(ParentAccessDialogRegularUserBrowserTest,
                        ErrorForNonChildUser) {
   base::HistogramTester histogram_tester;
-  // Show the dialog.
+
   ParentAccessDialogProvider provider;
   ParentAccessDialogProvider::ShowError error = provider.Show(
-      parent_access_ui::mojom::ParentAccessParams::New(
-          parent_access_ui::mojom::ParentAccessParams::FlowType::kWebsiteAccess,
-          parent_access_ui::mojom::FlowTypeParams::NewWebApprovalsParams(
-              parent_access_ui::mojom::WebApprovalsParams::New()),
-          /*is_disabled=*/false),
-      base::DoNothing());
+      GetTestParamsForFlowType(GetTestedFlowType()), base::DoNothing());
 
-  // Verify it is not showing.
+  // Verify the dialog is not showing and metrics were recorded.
   EXPECT_EQ(error, ParentAccessDialogProvider::ShowError::kNotAChildUser);
   EXPECT_EQ(ParentAccessDialog::GetInstance(), nullptr);
-
-  // Verify that metrics were recorded.
   histogram_tester.ExpectUniqueSample(
       parent_access::GetHistogramTitleForFlowType(
           parent_access::kParentAccessWidgetShowDialogErrorHistogramBase,
@@ -389,8 +359,7 @@
   histogram_tester.ExpectUniqueSample(
       parent_access::GetHistogramTitleForFlowType(
           parent_access::kParentAccessWidgetShowDialogErrorHistogramBase,
-          parent_access_ui::mojom::ParentAccessParams::FlowType::
-              kWebsiteAccess),
+          GetTestedFlowType()),
       ParentAccessDialogProvider::ShowErrorType::kNotAChildUser, 1);
 }
 
diff --git a/chrome/browser/ui/webui/cr_components/history_clusters/history_clusters_util.cc b/chrome/browser/ui/webui/cr_components/history_clusters/history_clusters_util.cc
index 9b3ff42..a4c3bd24 100644
--- a/chrome/browser/ui/webui/cr_components/history_clusters/history_clusters_util.cc
+++ b/chrome/browser/ui/webui/cr_components/history_clusters/history_clusters_util.cc
@@ -7,6 +7,7 @@
 #include "base/feature_list.h"
 #include "chrome/browser/history_clusters/history_clusters_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/history/core/common/pref_names.h"
 #include "components/history_clusters/core/config.h"
@@ -46,9 +47,8 @@
       "isHistoryClustersImagesEnabled",
       history_clusters::GetConfig().images &&
           base::FeatureList::IsEnabled(page_image_service::kImageService));
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
+
   source->AddBoolean("isHistoryClustersImageCover",
                      history_clusters::GetConfig().images_cover);
 
diff --git a/chrome/browser/ui/webui/intro/intro_ui.cc b/chrome/browser/ui/webui/intro/intro_ui.cc
index 20aa657..b76078b 100644
--- a/chrome/browser/ui/webui/intro/intro_ui.cc
+++ b/chrome/browser/ui/webui/intro/intro_ui.cc
@@ -123,9 +123,7 @@
                      base::FeatureList::IsEnabled(switches::kTangibleSync));
 #endif
 
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   // Unretained ok: `this` owns the handler.
   auto intro_handler = std::make_unique<IntroHandler>(
diff --git a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc
index 499e364..2985ee5 100644
--- a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc
+++ b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc
@@ -31,6 +31,7 @@
 #include "chrome/grit/nearby_share_dialog_resources_map.h"
 #include "chrome/grit/theme_resources.h"
 #include "chromeos/components/sharesheet/constants.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
@@ -41,6 +42,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/views/controls/webview/webview.h"
+#include "ui/webui/color_change_listener/color_change_handler.h"
 
 namespace nearby_share {
 
@@ -96,6 +98,8 @@
       "isOnePageOnboardingEnabled",
       base::FeatureList::IsEnabled(features::kNearbySharingOnePageOnboarding));
   RegisterNearbySharedStrings(html_source);
+  html_source->AddBoolean("isJellyEnabled",
+                          chromeos::features::IsJellyEnabled());
   html_source->UseStringsJs();
 
   // Register callback to handle "cancel-button-event" from nearby_*.html files.
@@ -152,6 +156,12 @@
   nearby_sharing_service->GetContactManager()->Bind(std::move(receiver));
 }
 
+void NearbyShareDialogUI::BindInterface(
+    mojo::PendingReceiver<color_change_listener::mojom::PageHandler> receiver) {
+  color_provider_handler_ = std::make_unique<ui::ColorChangeHandler>(
+      web_ui()->GetWebContents(), std::move(receiver));
+}
+
 bool NearbyShareDialogUI::HandleKeyboardEvent(
     content::WebContents* source,
     const content::NativeWebKeyboardEvent& event) {
diff --git a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.h b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.h
index 618fd9a..b70fb5d 100644
--- a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.h
+++ b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.h
@@ -20,9 +20,14 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
 #include "ui/webui/mojo_web_ui_controller.h"
+#include "ui/webui/resources/cr_components/color_change_listener/color_change_listener.mojom.h"
 
 class NearbySharingService;
 
+namespace ui {
+class ColorChangeHandler;
+}  // namespace ui
+
 namespace views {
 class WebView;
 }  // namespace views
@@ -67,6 +72,11 @@
   // keyed service.
   void BindInterface(
       mojo::PendingReceiver<nearby_share::mojom::ContactManager> receiver);
+  // Instantiates the implementor of the mojom::PageHandler mojo interface
+  // passing the pending receiver that will be internally bound.
+  void BindInterface(
+      mojo::PendingReceiver<color_change_listener::mojom::PageHandler>
+          receiver);
 
   // content::WebContentsDelegate:
   bool HandleKeyboardEvent(
@@ -99,6 +109,7 @@
   raw_ptr<NearbySharingService, ExperimentalAsh> nearby_service_;
   raw_ptr<views::WebView, ExperimentalAsh> web_view_ = nullptr;
   views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
+  std::unique_ptr<ui::ColorChangeHandler> color_provider_handler_;
 
   WEB_UI_CONTROLLER_TYPE_DECL();
 };
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
index 64558d0..27e796b9 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -13,7 +13,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/types/expected.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/webui_util.h"
@@ -118,8 +117,6 @@
   return endpoint_results_list;
 }
 
-using ResolveHostResult = base::expected<base::Value, std::string>;
-
 // This class implements network::mojom::ResolveHostClient.
 class NetInternalsResolveHostClient : public network::mojom::ResolveHostClient {
  public:
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
index 66644bb..d80a83f 100644
--- a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
@@ -56,6 +56,11 @@
 #include "chrome/grit/chrome_unscaled_resources.h"
 #endif
 
+#if !BUILDFLAG(OPTIMIZE_WEBUI)
+#include "chrome/grit/settings_shared_resources.h"
+#include "chrome/grit/settings_shared_resources_map.h"
+#endif
+
 namespace {
 
 std::u16string InsertBrandedPasswordManager(int message_id) {
@@ -76,6 +81,11 @@
       base::make_span(kPasswordManagerResources, kPasswordManagerResourcesSize),
       IDR_PASSWORD_MANAGER_PASSWORD_MANAGER_HTML);
 
+#if !BUILDFLAG(OPTIMIZE_WEBUI)
+  source->AddResourcePaths(
+      base::make_span(kSettingsSharedResources, kSettingsSharedResourcesSize));
+#endif
+
   static constexpr webui::LocalizedString kStrings[] = {
     {"accountStorageToggleLabel",
      IDS_PASSWORD_MANAGER_UI_ACCOUNT_STORAGE_TOGGLE_LABEL},
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index fb8f472..641551c 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -332,9 +332,7 @@
                         IDS_PRINT_PREVIEW_SYSTEM_DIALOG_OPTION, shortcut_text));
 #endif
 
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      ::features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   // Register strings for the PDF viewer, so that $i18n{} replacements work.
   base::Value::Dict pdf_strings;
@@ -415,13 +413,7 @@
   web_ui->AddMessageHandler(std::move(handler));
 
 #if BUILDFLAG(ENABLE_OOP_PRINTING)
-  // Register with print backend service manager; it is beneficial to have a
-  // the print backend service be present and ready for at least as long as
-  // this UI is around.
-  if (base::FeatureList::IsEnabled(features::kEnableOopPrintDrivers)) {
-    service_manager_client_id_ =
-        PrintBackendServiceManager::GetInstance().RegisterQueryClient();
-  }
+  RegisterPrintBackendServiceManagerClient();
 #endif
 }
 
@@ -440,25 +432,32 @@
   content::URLDataSource::Add(profile, std::make_unique<ThemeSource>(profile));
 
 #if BUILDFLAG(ENABLE_OOP_PRINTING)
-  // Register with print backend service manager; it is beneficial to have a
-  // the print backend service be present and ready for at least as long as
-  // this UI is around.
-  if (base::FeatureList::IsEnabled(features::kEnableOopPrintDrivers)) {
-    service_manager_client_id_ =
-        PrintBackendServiceManager::GetInstance().RegisterQueryClient();
-  }
+  RegisterPrintBackendServiceManagerClient();
 #endif
 }
 
 PrintPreviewUI::~PrintPreviewUI() {
 #if BUILDFLAG(ENABLE_OOP_PRINTING)
+  UnregisterPrintBackendServiceManagerClient();
+#endif
+  ClearPreviewUIId();
+}
+
+#if BUILDFLAG(ENABLE_OOP_PRINTING)
+void PrintPreviewUI::RegisterPrintBackendServiceManagerClient() {
+  if (base::FeatureList::IsEnabled(features::kEnableOopPrintDrivers)) {
+    service_manager_client_id_ =
+        PrintBackendServiceManager::GetInstance().RegisterQueryClient();
+  }
+}
+
+void PrintPreviewUI::UnregisterPrintBackendServiceManagerClient() {
   if (base::FeatureList::IsEnabled(features::kEnableOopPrintDrivers)) {
     PrintBackendServiceManager::GetInstance().UnregisterClient(
         service_manager_client_id_);
   }
-#endif
-  ClearPreviewUIId();
 }
+#endif  // BUILDFLAG(ENABLE_OOP_PRINTING)
 
 mojo::PendingAssociatedRemote<mojom::PrintPreviewUI>
 PrintPreviewUI::BindPrintPreviewUI() {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.h b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
index 944978e7..4ec4981 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
@@ -258,6 +258,15 @@
                             mojom::PrintCompositor::Status status,
                             base::ReadOnlySharedMemoryRegion region);
 
+#if BUILDFLAG(ENABLE_OOP_PRINTING)
+  // Registers this PrintPreviewUI with the PrintBackendServiceManager. It is
+  // beneficial to have the Print Backend service be present and ready for at
+  // least as long as this UI is around.
+  void RegisterPrintBackendServiceManagerClient();
+
+  void UnregisterPrintBackendServiceManagerClient();
+#endif  // BUILDFLAG(ENABLE_OOP_PRINTING)
+
   WEB_UI_CONTROLLER_TYPE_DECL();
 
   base::TimeTicks initial_preview_start_time_;
diff --git a/chrome/browser/ui/webui/settings/ash/device_section.cc b/chrome/browser/ui/webui/settings/ash/device_section.cc
index 9e547ba..4f46daa 100644
--- a/chrome/browser/ui/webui/settings/ash/device_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/device_section.cc
@@ -833,6 +833,27 @@
       {"keyboardAccentMarksSubLabel",
        IDS_SETTINGS_KEYBOARD_ACCENT_MARKS_SUB_LABEL},
       {"noKeyboardsConnected", IDS_SETTINGS_KEYBOARD_NO_KEYBOARDS_HELP_MESSAGE},
+      {"perDeviceKeyboardKeyAlt",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_ALT},
+      {"perDeviceKeyboardKeyAssistant",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ASSISTANT},
+      {"perDeviceKeyboardKeyBackspace",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_BACKSPACE},
+      {"perDeviceKeyboardKeyCapsLock",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_CAPS_LOCK},
+      {"perDeviceKeyboardKeyCommand",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_COMMAND},
+      {"perDeviceKeyboardKeyCtrl",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_LEFT_CTRL},
+      {"perDeviceKeyboardKeyDisabled",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_DISABLED},
+      {"perDeviceKeyboardKeyEscape",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_ESCAPE},
+      {"perDeviceKeyboardKeyExternalMeta",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_EXTERNAL_META},
+      {"perDeviceKeyboardKeySearch",
+       IDS_SETTINGS_PER_DEVICE_KEYBOARD_KEY_SEARCH},
+
   };
   html_source->AddLocalizedStrings(keyboard_strings);
 
diff --git a/chrome/browser/ui/webui/settings/ash/internet_section.cc b/chrome/browser/ui/webui/settings/ash/internet_section.cc
index 073b8040..5ecaa33 100644
--- a/chrome/browser/ui/webui/settings/ash/internet_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/internet_section.cc
@@ -49,7 +49,6 @@
 using ::chromeos::settings::mojom::kKnownNetworksSubpagePath;
 using ::chromeos::settings::mojom::kMobileDataNetworksSubpagePath;
 using ::chromeos::settings::mojom::kNetworkSectionPath;
-using ::chromeos::settings::mojom::kPasspointDetailSubpagePath;
 using ::chromeos::settings::mojom::kTetherDetailsSubpagePath;
 using ::chromeos::settings::mojom::kVpnDetailsSubpagePath;
 using ::chromeos::settings::mojom::kWifiDetailsSubpagePath;
@@ -995,8 +994,6 @@
        IDS_SETTINGS_INTERNET_HOTSPOT_CONFIG_INVALID_CONFIGURATION_ERROR_MESSAGE},
       {"hotspotConfigNotLoginErrorMessage",
        IDS_SETTINGS_INTERNET_HOTSPOT_CONFIG_NOT_LOGIN_ERROR_MESSAGE},
-      {"passpointProviderLabel", IDS_SETTINGS_INTERNET_PASSPOINT_PROVIDER},
-      {"passpointSectionLabel", IDS_SETTINGS_INTERNET_PASSPOINT_SECTION_LABEL},
   };
   html_source->AddLocalizedStrings(kLocalizedStrings);
 
@@ -1183,13 +1180,6 @@
                             kMobileDataNetworksSettings, generator);
   generator->RegisterTopLevelAltSetting(mojom::Setting::kMobileOnOff);
 
-  // Passpoint details.
-  generator->RegisterNestedSubpage(
-      IDS_SETTINGS_INTERNET_PASSPOINT_DETAILS,
-      mojom::Subpage::kPasspointDetails, mojom::Subpage::kKnownNetworks,
-      mojom::SearchResultIcon::kWifi, mojom::SearchResultDefaultRank::kMedium,
-      mojom::kPasspointDetailSubpagePath);
-
   // Cellular details. Cellular details are considered a child of the mobile
   // data subpage. However, note that if Instant Tethering is not available,
   // clicking on "Mobile data" at the Network section navigates users directly
diff --git a/chrome/browser/ui/webui/settings/ash/printing_section.cc b/chrome/browser/ui/webui/settings/ash/printing_section.cc
index f862612..f708216 100644
--- a/chrome/browser/ui/webui/settings/ash/printing_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/printing_section.cc
@@ -142,6 +142,8 @@
       {"printerModel", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_MODEL},
       {"printerQueue", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_QUEUE},
       {"savedPrintersTitle", IDS_SETTINGS_PRINTING_CUPS_SAVED_PRINTERS_TITLE},
+      {"savedPrintersSubtext",
+       IDS_SETTINGS_PRINTING_CUPS_SAVED_PRINTERS_SUBTEXT},
       {"savedPrintersCountMany",
        IDS_SETTINGS_PRINTING_CUPS_PRINTERS_SAVED_PRINTERS_COUNT_MANY},
       {"savedPrintersCountOne",
@@ -155,6 +157,10 @@
        IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTERS_MANUALLY_TITLE},
       {"manufacturerAndModelDialogTitle",
        IDS_SETTINGS_PRINTING_CUPS_SELECT_MANUFACTURER_AND_MODEL_TITLE},
+      {"availablePrintersReadyTitle",
+       IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS_READY},
+      {"availablePrintersReadySubtext",
+       IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS_READY_SUBTEXT},
       {"nearbyPrintersListTitle",
        IDS_SETTINGS_PRINTING_CUPS_PRINTERS_AVAILABLE_PRINTERS},
       {"nearbyPrintersCountMany",
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom b/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom
index 05c447d3..dfa3307 100644
--- a/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom
+++ b/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom
@@ -45,7 +45,6 @@
   kVpnDetails = 7,
   kApn = 8,
   kHotspotDetails = 9,
-  kPasspointDetails = 10,
 
   // Bluetooth section.
   kBluetoothDevices = 100,
@@ -189,7 +188,6 @@
 const string kVpnDetailsSubpagePath = "networkDetail";
 const string kApnSubpagePath = "apn";
 const string kHotspotSubpagePath = "hotspotDetail";
-const string kPasspointDetailSubpagePath = "passpointDetail";
 
 // Bluetooth section.
 const string kBluetoothSectionPath = "bluetooth";
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 3a64ca5..946e7f2 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1898,12 +1898,11 @@
       base::FeatureList::IsEnabled(features::kHttpsOnlyMode));
 
 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
-  html_source->AddBoolean(
-      "showChromeRootStoreCertificates",
+  html_source->AddBoolean("showChromeRootStoreCertificates",
 #if BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
-      SystemNetworkContextManager::GetInstance()->IsUsingChromeRootStore()
+                          SystemNetworkContextManager::IsUsingChromeRootStore()
 #else
-      true
+                          true
 #endif
   );
 
diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chrome/browser/ui/webui/settings/site_settings_helper.cc
index 6f3cf7f..e3dae9f 100644
--- a/chrome/browser/ui/webui/settings/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_helper.cc
@@ -174,6 +174,9 @@
     {ContentSettingsType::NOTIFICATION_PERMISSION_REVIEW, nullptr},
     {ContentSettingsType::FEDERATED_IDENTITY_IDENTITY_PROVIDER_SIGNIN_STATUS,
      nullptr},
+    // PPAPI_BROKER has been deprecated. The content setting is not used or
+    // called from UI, so we don't need a representation JS string.
+    {ContentSettingsType::DEPRECATED_PPAPI_BROKER, nullptr},
     {ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, nullptr},
     {ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS, nullptr},
     // TODO(crbug.com/1408520): Update JavaScript string representation when
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 f595d88..8ed857c5e 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
@@ -196,9 +196,7 @@
                         ? base::NumberToString(managed->managed_node()->id())
                         : "");
 
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   content::URLDataSource::Add(
       profile, std::make_unique<FaviconSource>(
diff --git a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc
index f8b6735..377018a 100644
--- a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h"
 
 #include "build/build_config.h"
+#include "chrome/browser/companion/core/companion_metrics_logger.h"
 #include "chrome/browser/companion/core/companion_permission_utils.h"
 #include "chrome/browser/companion/core/companion_url_builder.h"
 #include "chrome/browser/companion/core/promo_handler.h"
@@ -26,6 +27,7 @@
 #include "components/unified_consent/url_keyed_data_collection_consent_helper.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/url_util.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
 #include "url/gurl.h"
 
 namespace companion {
@@ -48,6 +50,10 @@
 CompanionPageHandler::~CompanionPageHandler() = default;
 
 void CompanionPageHandler::PrimaryPageChanged(content::Page& page) {
+  ukm::SourceId ukm_source_id =
+      web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId();
+  metrics_logger_ = std::make_unique<CompanionMetricsLogger>(ukm_source_id);
+
   // Only notify the companion UI the page changed if we can share
   // information about the page by user consent.
   if (!IsUserPermittedToSharePageInfoWithCompanion(GetProfile()->GetPrefs())) {
@@ -66,6 +72,9 @@
     auto* active_web_contents =
         GetBrowser()->tab_strip_model()->GetActiveWebContents();
     Observe(active_web_contents);
+    ukm::SourceId ukm_source_id =
+        web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId();
+    metrics_logger_ = std::make_unique<CompanionMetricsLogger>(ukm_source_id);
     auto* helper =
         companion::CompanionTabHelper::FromWebContents(active_web_contents);
     helper->SetCompanionPageHandler(weak_ptr_factory_.GetWeakPtr());
@@ -112,6 +121,10 @@
 
 void CompanionPageHandler::OnImageQuery(
     side_panel::mojom::ImageQuery image_query) {
+  GURL modified_upload_url = url_builder_->AppendCompanionParamsToURL(
+      image_query.upload_url, web_contents()->GetVisibleURL(),
+      /*text_query=*/"");
+  image_query.upload_url = modified_upload_url;
   page_->OnImageQuery(image_query.Clone());
 }
 
@@ -123,6 +136,7 @@
     side_panel::mojom::PromoType promo_type,
     side_panel::mojom::PromoAction promo_action) {
   promo_handler_->OnPromoAction(promo_type, promo_action);
+  metrics_logger_->OnPromoAction(promo_type, promo_action);
 }
 
 void CompanionPageHandler::OnRegionSearchClicked() {
@@ -148,6 +162,17 @@
   companion_helper->UpdateNewTabButtonState();
 }
 
+void CompanionPageHandler::RecordUiSurfaceShown(
+    side_panel::mojom::UiSurface ui_surface,
+    uint32_t child_element_count) {
+  metrics_logger_->RecordUiSurfaceShown(ui_surface, child_element_count);
+}
+
+void CompanionPageHandler::RecordUiSurfaceClicked(
+    side_panel::mojom::UiSurface ui_surface) {
+  metrics_logger_->RecordUiSurfaceClicked(ui_surface);
+}
+
 void CompanionPageHandler::EnableMsbb(bool enable_msbb) {
   auto* consent_service =
       UnifiedConsentServiceFactory::GetForProfile(GetProfile());
diff --git a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h
index 54ef26dc..f677990 100644
--- a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h
+++ b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h
@@ -22,6 +22,7 @@
 class Profile;
 
 namespace companion {
+class CompanionMetricsLogger;
 class CompanionUrlBuilder;
 class PromoHandler;
 class SigninDelegate;
@@ -45,6 +46,9 @@
   void OnRegionSearchClicked() override;
   void OnExpsOptInStatusAvailable(bool is_exps_opted_in) override;
   void OnOpenInNewTabButtonURLChanged(const ::GURL& url_to_open) override;
+  void RecordUiSurfaceShown(side_panel::mojom::UiSurface ui_surface,
+                            uint32_t child_element_count) override;
+  void RecordUiSurfaceClicked(side_panel::mojom::UiSurface ui_surface) override;
 
   // content::WebContentsObserver:
   void PrimaryPageChanged(content::Page& page) override;
@@ -82,6 +86,9 @@
   std::unique_ptr<PromoHandler> promo_handler_;
   GURL open_in_new_tab_url_;
 
+  // Logs metrics for companion page. Reset when there is a new navigation.
+  std::unique_ptr<CompanionMetricsLogger> metrics_logger_;
+
   base::WeakPtrFactory<CompanionPageHandler> weak_ptr_factory_{this};
 };
 }  // namespace companion
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
index 7d45361..85f7bf4 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
@@ -97,9 +97,7 @@
       "modulesEnabled",
       ntp::HasModulesEnabled(module_id_names_,
                              IdentityManagerFactory::GetForProfile(profile_)));
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   webui::SetupWebUIDataSource(
       source,
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 a2ec56d..0605a71e 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
@@ -69,9 +69,7 @@
       "hasUnseenReadingListEntries",
       reading_list_model->loaded() ? reading_list_model->unseen_size() : false);
 
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   content::URLDataSource::Add(
       profile, std::make_unique<FaviconSource>(
diff --git a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_side_panel_ui.cc b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_side_panel_ui.cc
index 81eca59..68d39ec 100644
--- a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_side_panel_ui.cc
+++ b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_side_panel_ui.cc
@@ -63,9 +63,7 @@
   }
   source->AddBoolean("guestMode", profile->IsGuestSession());
 
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   webui::SetupWebUIDataSource(source,
                               base::make_span(kSidePanelUserNotesResources,
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc
index 0c02c22..3a9a26cb 100644
--- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc
+++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc
@@ -92,10 +92,7 @@
       "script-src chrome://resources chrome://test chrome://webui-test "
       "'self';");
   webui::EnableTrustedTypesCSP(source);
-
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   if (web_ui->GetWebContents()->GetVisibleURL().query() == "debug") {
     // Not intended to be hooked to anything. The bubble will not initialize it
diff --git a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
index 4c9f8ef..0808cc4c 100644
--- a/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
+++ b/chrome/browser/ui/webui/signin/enterprise_profile_welcome_ui.cc
@@ -82,9 +82,7 @@
       "isTangibleSyncStyleEnabled",
       base::FeatureList::IsEnabled(kEnterpriseWelcomeTangibleSyncStyle) &&
           base::FeatureList::IsEnabled(switches::kTangibleSync));
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 }
 
 EnterpriseProfileWelcomeUI::~EnterpriseProfileWelcomeUI() = default;
diff --git a/chrome/browser/ui/webui/signin/profile_customization_ui.cc b/chrome/browser/ui/webui/signin/profile_customization_ui.cc
index d06029d..6d8ec69f 100644
--- a/chrome/browser/ui/webui/signin/profile_customization_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_customization_ui.cc
@@ -106,9 +106,7 @@
   source->AddBoolean("isLocalProfileCreation",
                      GetProfileCustomizationStyle(url) ==
                          ProfileCustomizationStyle::kLocalProfileCreation);
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   if (url.query() == "debug") {
     // Not intended to be hooked to anything. The bubble will not initialize it
diff --git a/chrome/browser/ui/webui/signin/profile_picker_ui.cc b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
index 9e17bdad..1f67b9f 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
@@ -238,9 +238,7 @@
   html_source->AddString("managedDeviceDisclaimer",
                          GetManagedDeviceDisclaimer());
 
-  html_source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(html_source);
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
   std::string remove_warning_profile = l10n_util::GetStringFUTF8(
diff --git a/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.cc b/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.cc
index 93bc0c3..fc697d93b 100644
--- a/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.cc
+++ b/chrome/browser/ui/webui/signin/signin_email_confirmation_ui.cc
@@ -65,9 +65,7 @@
   webui::SetLoadTimeDataDefaults(g_browser_process->GetApplicationLocale(),
                                  &strings);
   source->AddLocalizedStrings(strings);
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 }
 
 SigninEmailConfirmationUI::~SigninEmailConfirmationUI() {}
diff --git a/chrome/browser/ui/webui/signin/signin_reauth_ui.cc b/chrome/browser/ui/webui/signin/signin_reauth_ui.cc
index b1365b7..d661ac6 100644
--- a/chrome/browser/ui/webui/signin/signin_reauth_ui.cc
+++ b/chrome/browser/ui/webui/signin/signin_reauth_ui.cc
@@ -116,9 +116,7 @@
 
   source->AddString("accountImageUrl", GetAccountImageURL(profile));
 
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   signin_metrics::ReauthAccessPoint access_point =
       GetReauthAccessPointForReauthConfirmationURL(
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
index 79ccbc3..a478ad4 100644
--- a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
+++ b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
@@ -151,9 +151,7 @@
 
   AddStringResource(source, "syncLoadingConfirmationTitle",
                     IDS_SYNC_LOADING_CONFIRMATION_TITLE);
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   if (is_sync_allowed) {
     InitializeForSyncConfirmation(source, GetSyncConfirmationStyle(url));
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
index e0bd802..a282eb371 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
@@ -58,9 +58,7 @@
 
   html_source->AddString("tabIdDataType", kWebUITabIdDataType);
   html_source->AddString("tabGroupIdDataType", kWebUITabGroupIdDataType);
-  html_source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(html_source);
 
   static constexpr webui::LocalizedString kStrings[] = {
       {"tabListTitle", IDS_ACCNAME_TAB_LIST},
diff --git a/chrome/browser/ui/webui/webui_gallery/webui_gallery_ui.cc b/chrome/browser/ui/webui/webui_gallery/webui_gallery_ui.cc
index 805c50e..6e9ce4984 100644
--- a/chrome/browser/ui/webui/webui_gallery/webui_gallery_ui.cc
+++ b/chrome/browser/ui/webui/webui_gallery/webui_gallery_ui.cc
@@ -33,9 +33,7 @@
       network::mojom::CSPDirectiveName::FrameAncestors,
       "frame-ancestors 'self';");
 
-  source->AddString(
-      "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+  webui::SetupChromeRefresh2023(source);
 
   // TODO(colehorvitz): Promote to a place where it can be easily registered
   // by many WebUIs.
diff --git a/chrome/browser/ui/webui/webui_util.cc b/chrome/browser/ui/webui/webui_util.cc
index 87b6ca5..4a170d65 100644
--- a/chrome/browser/ui/webui/webui_util.cc
+++ b/chrome/browser/ui/webui/webui_util.cc
@@ -10,6 +10,7 @@
 #include "content/public/browser/web_ui_data_source.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/resources/grit/webui_resources.h"
 
@@ -86,6 +87,12 @@
   source->AddString(message, str);
 }
 
+void SetupChromeRefresh2023(content::WebUIDataSource* source) {
+  source->AddString(
+      "chromeRefresh2023Attribute",
+      features::IsChromeWebuiRefresh2023() ? "chrome-refresh-2023" : "");
+}
+
 #if defined(TOOLKIT_VIEWS)
 
 namespace {
diff --git a/chrome/browser/ui/webui/webui_util.h b/chrome/browser/ui/webui/webui_util.h
index 999b64b6..4faa94a 100644
--- a/chrome/browser/ui/webui/webui_util.h
+++ b/chrome/browser/ui/webui/webui_util.h
@@ -45,6 +45,9 @@
                         const std::string& message,
                         int id);
 
+// Adds string to use on HTML to enable Refresh 2023 styles for WebUI.
+void SetupChromeRefresh2023(content::WebUIDataSource* source);
+
 #if defined(TOOLKIT_VIEWS)
 
 // Returns whether WebContents should use dark mode colors depending on the
diff --git a/chrome/browser/web_applications/commands/externally_managed_install_command.cc b/chrome/browser/web_applications/commands/externally_managed_install_command.cc
index c9070bce..f7cf2599c 100644
--- a/chrome/browser/web_applications/commands/externally_managed_install_command.cc
+++ b/chrome/browser/web_applications/commands/externally_managed_install_command.cc
@@ -9,7 +9,7 @@
 
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/commands/web_app_command.h"
 #include "chrome/browser/web_applications/external_install_options.h"
diff --git a/chrome/browser/web_applications/commands/fetch_manifest_and_install_command.cc b/chrome/browser/web_applications/commands/fetch_manifest_and_install_command.cc
index 0b6e90e1..ca6721918 100644
--- a/chrome/browser/web_applications/commands/fetch_manifest_and_install_command.cc
+++ b/chrome/browser/web_applications/commands/fetch_manifest_and_install_command.cc
@@ -9,6 +9,7 @@
 
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
+#include "base/strings/to_string.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/web_applications/commands/install_from_info_command.cc b/chrome/browser/web_applications/commands/install_from_info_command.cc
index 0bb088e..8c43b897 100644
--- a/chrome/browser/web_applications/commands/install_from_info_command.cc
+++ b/chrome/browser/web_applications/commands/install_from_info_command.cc
@@ -11,6 +11,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/to_string.h"
 #include "chrome/browser/web_applications/locks/app_lock.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
 #include "chrome/browser/web_applications/web_app.h"
diff --git a/chrome/browser/web_applications/commands/install_from_sync_command.cc b/chrome/browser/web_applications/commands/install_from_sync_command.cc
index e8098f8..efea58b 100644
--- a/chrome/browser/web_applications/commands/install_from_sync_command.cc
+++ b/chrome/browser/web_applications/commands/install_from_sync_command.cc
@@ -10,7 +10,7 @@
 #include "base/containers/flat_set.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/commands/web_app_command.h"
diff --git a/chrome/browser/web_applications/commands/install_placeholder_command.cc b/chrome/browser/web_applications/commands/install_placeholder_command.cc
index d29e560..0b269670 100644
--- a/chrome/browser/web_applications/commands/install_placeholder_command.cc
+++ b/chrome/browser/web_applications/commands/install_placeholder_command.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/strings/to_string.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/web_applications/commands/install_preloaded_verified_app_command.cc b/chrome/browser/web_applications/commands/install_preloaded_verified_app_command.cc
index d34551f..81d6d971 100644
--- a/chrome/browser/web_applications/commands/install_preloaded_verified_app_command.cc
+++ b/chrome/browser/web_applications/commands/install_preloaded_verified_app_command.cc
@@ -11,7 +11,7 @@
 #include "base/containers/flat_set.h"
 #include "base/containers/flat_tree.h"
 #include "base/functional/bind.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "chrome/browser/web_applications/locks/shared_web_contents_lock.h"
 #include "chrome/browser/web_applications/locks/shared_web_contents_with_app_lock.h"
 #include "chrome/browser/web_applications/locks/web_app_lock_manager.h"
diff --git a/chrome/browser/web_applications/commands/manifest_update_check_command.cc b/chrome/browser/web_applications/commands/manifest_update_check_command.cc
index d727302..5a741f76 100644
--- a/chrome/browser/web_applications/commands/manifest_update_check_command.cc
+++ b/chrome/browser/web_applications/commands/manifest_update_check_command.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/web_applications/commands/manifest_update_check_command.h"
 
 #include "base/feature_list.h"
+#include "base/strings/to_string.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/web_applications/callback_utils.h"
diff --git a/chrome/browser/web_applications/commands/manifest_update_finalize_command.cc b/chrome/browser/web_applications/commands/manifest_update_finalize_command.cc
index 28268698..88eb54a 100644
--- a/chrome/browser/web_applications/commands/manifest_update_finalize_command.cc
+++ b/chrome/browser/web_applications/commands/manifest_update_finalize_command.cc
@@ -8,7 +8,7 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
diff --git a/chrome/browser/web_applications/commands/sub_app_install_command.cc b/chrome/browser/web_applications/commands/sub_app_install_command.cc
index 31749a8..0bf4c30a 100644
--- a/chrome/browser/web_applications/commands/sub_app_install_command.cc
+++ b/chrome/browser/web_applications/commands/sub_app_install_command.cc
@@ -12,7 +12,7 @@
 #include "base/containers/flat_map.h"
 #include "base/functional/callback.h"
 #include "base/ranges/algorithm.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/commands/web_app_command.h"
diff --git a/chrome/browser/web_applications/commands/update_protocol_handler_approval_command.cc b/chrome/browser/web_applications/commands/update_protocol_handler_approval_command.cc
index 79013ff6..5fc5ab8 100644
--- a/chrome/browser/web_applications/commands/update_protocol_handler_approval_command.cc
+++ b/chrome/browser/web_applications/commands/update_protocol_handler_approval_command.cc
@@ -13,7 +13,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "chrome/browser/web_applications/locks/app_lock.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
diff --git a/chrome/browser/web_applications/commands/web_app_uninstall_command.cc b/chrome/browser/web_applications/commands/web_app_uninstall_command.cc
index e73c4e0..e6f06de 100644
--- a/chrome/browser/web_applications/commands/web_app_uninstall_command.cc
+++ b/chrome/browser/web_applications/commands/web_app_uninstall_command.cc
@@ -11,7 +11,7 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/locks/all_apps_lock.h"
 #include "chrome/browser/web_applications/user_uninstalled_preinstalled_web_app_prefs.h"
diff --git a/chrome/browser/web_applications/externally_managed_app_manager.cc b/chrome/browser/web_applications/externally_managed_app_manager.cc
index bfbbad5..bee1e1e 100644
--- a/chrome/browser/web_applications/externally_managed_app_manager.cc
+++ b/chrome/browser/web_applications/externally_managed_app_manager.cc
@@ -15,7 +15,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/ranges/algorithm.h"
 #include "base/stl_util.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/values.h"
 #include "build/chromeos_buildflags.h"
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.cc b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.cc
index 4d7be92..a24c6b1b 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.cc
@@ -182,7 +182,7 @@
             }
             // Dev mode proxy mode does not use Web Bundles, hence there is no
             // bundle to validate / trust and no signatures to check.
-            OnTrustAndSignaturesChecked(absl::nullopt);
+            OnTrustAndSignaturesChecked(base::ok());
           }},
       location_);
 }
@@ -205,16 +205,12 @@
       base::BindOnce(
           [](base::expected<std::unique_ptr<IsolatedWebAppResponseReader>,
                             IsolatedWebAppResponseReaderFactory::Error> reader)
-              -> absl::optional<IsolatedWebAppResponseReaderFactory::Error> {
-            // Convert expected<Reader,Error> into optional<Error> to match the
-            // signature of `OnTrustAndSignaturesChecked`. This is necessary for
-            // compatibility with the dev mode proxy case, where
-            // `OnTrustAndSignaturesChecked` is called with `absl::nullopt` to
-            // indicate success.
+              -> base::expected<void,
+                                IsolatedWebAppResponseReaderFactory::Error> {
             if (!reader.has_value()) {
-              return std::move(reader.error());
+              return base::unexpected(std::move(reader.error()));
             }
-            return absl::nullopt;
+            return base::ok();
           })
           .Then(base::BindOnce(
               &InstallIsolatedWebAppCommand::OnTrustAndSignaturesChecked,
@@ -222,9 +218,10 @@
 }
 
 void InstallIsolatedWebAppCommand::OnTrustAndSignaturesChecked(
-    absl::optional<IsolatedWebAppResponseReaderFactory::Error> error) {
-  if (error) {
-    ReportFailure(IsolatedWebAppResponseReaderFactory::ErrorToString(*error));
+    base::expected<void, IsolatedWebAppResponseReaderFactory::Error> result) {
+  if (!result.has_value()) {
+    ReportFailure(
+        IsolatedWebAppResponseReaderFactory::ErrorToString(result.error()));
     return;
   }
 
@@ -284,17 +281,16 @@
   UpdateWebAppInfoFromManifest(manifest, manifest_url, &info);
 
   if (!manifest.id.has_value()) {
-    return base::unexpected{
-        base::StrCat({"Manifest `id` is not present. manifest_url: ",
-                      manifest_url.possibly_invalid_spec()})};
+    return base::unexpected("Manifest `id` is not present. manifest_url: " +
+                            manifest_url.possibly_invalid_spec());
   }
 
   // In other installations the best-effort encoding is fine, but for isolated
   // apps we have the opportunity to report this error.
   absl::optional<std::string> encoded_id = UTF16ToUTF8(*manifest.id);
   if (!encoded_id.has_value()) {
-    return base::unexpected{
-        "Failed to convert manifest `id` from UTF16 to UTF8."};
+    return base::unexpected(
+        "Failed to convert manifest `id` from UTF16 to UTF8.");
   }
 
   if (!encoded_id->empty()) {
@@ -307,16 +303,16 @@
     // the application and do not include other information in order to be able
     // to identify Isolated Web Apps by origin because there is always only 1
     // app per origin.
-    return base::unexpected{base::StrCat(
-        {R"(Manifest `id` must be "/". Resolved manifest id: )", *encoded_id})};
+    return base::unexpected(
+        R"(Manifest `id` must be "/". Resolved manifest id: )" + *encoded_id);
   }
 
   url::Origin origin = url_info_.origin();
   if (manifest.scope != origin.GetURL()) {
-    return base::unexpected{
+    return base::unexpected(
         base::StrCat({"Scope should resolve to the origin. scope: ",
                       manifest.scope.possibly_invalid_spec(),
-                      ", origin: ", origin.Serialize()})};
+                      ", origin: ", origin.Serialize()}));
   }
 
   if (info.title.empty()) {
@@ -445,8 +441,8 @@
   SignalCompletionAndSelfDestruct(
       CommandResult::kFailure,
       base::BindOnce(std::move(callback_),
-                     base::unexpected{InstallIsolatedWebAppCommandError{
-                         .message = std::string{message}}}));
+                     base::unexpected(InstallIsolatedWebAppCommandError{
+                         .message = std::string(message)})));
 }
 
 void InstallIsolatedWebAppCommand::ReportSuccess() {
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h
index b1e8292d..9d665c8d 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_command.h
@@ -132,7 +132,7 @@
 
   void CheckTrustAndSignaturesOfBundle(const base::FilePath& path);
   void OnTrustAndSignaturesChecked(
-      absl::optional<IsolatedWebAppResponseReaderFactory::Error> error);
+      base::expected<void, IsolatedWebAppResponseReaderFactory::Error> result);
 
   void CreateStoragePartition();
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.cc b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.cc
index 68f4b7c..d0de53c 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/command_line.h"
@@ -36,8 +37,7 @@
     base::expected<InstallIsolatedWebAppCommandSuccess,
                    InstallIsolatedWebAppCommandError> result) {
   if (!result.has_value()) {
-    LOG(ERROR) << "Isolated web app auto installation "
-                  "failed. Error: "
+    LOG(ERROR) << "Isolated web app auto installation failed. Error: "
                << result.error();
   }
 }
@@ -100,8 +100,7 @@
     const IsolatedWebAppLocation& location,
     base::expected<IsolatedWebAppUrlInfo, std::string> url_info) {
   if (!url_info.has_value()) {
-    LOG(ERROR) << base::StrCat(
-        {"Failed to get IsolationInfo: ", url_info.error()});
+    LOG(ERROR) << "Failed to get IsolationInfo: " << url_info.error();
     return;
   }
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
index b1e83a7b..5e4e90f 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
@@ -202,12 +202,10 @@
                                     ? ReadResponseHeadStatus::kSuccess
                                     : GetStatusFromError(response.error()));
 
-  if (!response.has_value()) {
-    std::move(callback).Run(
-        base::unexpected(ReadResponseError::ForError(response.error())));
-    return;
-  }
-  std::move(callback).Run(std::move(*response));
+  std::move(callback).Run(std::move(response).transform_error(
+      static_cast<ReadResponseError (*)(
+          const IsolatedWebAppResponseReader::Error&)>(
+          &ReadResponseError::ForError)));
 }
 
 IsolatedWebAppReaderRegistry::ReadResponseHeadStatus
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader.cc
index 472b4bd..671c9991 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader.cc
@@ -65,15 +65,14 @@
     ReadResponseCallback callback,
     base::expected<web_package::mojom::BundleResponsePtr, Error>
         response_head) {
-  if (!response_head.has_value()) {
-    std::move(callback).Run(base::unexpected(response_head.error()));
-    return;
-  }
-  // Since `this` owns `reader_`, we only pass a weak pointer to it to the
-  // `Response` object. If `this` is deleted, it makes sense that the pointer to
-  // the `reader_` contained in `Response` also becomes invalid.
-  std::move(callback).Run(
-      Response(std::move(*response_head), reader_->AsWeakPtr()));
+  std::move(callback).Run(response_head.transform(
+      [this](web_package::mojom::BundleResponsePtr& ptr) {
+        // Since `this` owns `reader_`, we only pass a weak pointer to it to the
+        // `Response` object. If `this` is deleted, it makes sense that the
+        // pointer to the `reader_` contained in `Response` also becomes
+        // invalid.
+        return Response(std::move(ptr), reader_->AsWeakPtr());
+      }));
 }
 
 IsolatedWebAppResponseReader::Response::Response(
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc
index 4a7cab85..ad94af61 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc
@@ -169,9 +169,9 @@
   if (!error_and_status.has_value()) {
     if (auto error_message = validator_->ValidateMetadata(
             web_bundle_id, reader->GetPrimaryURL(), reader->GetEntries());
-        error_message.has_value()) {
+        !error_message.has_value()) {
       error_and_status = std::make_pair(
-          MetadataError(*error_message),
+          MetadataError(error_message.error()),
           ReadIntegrityBlockAndMetadataStatus::kMetadataValidationError);
     }
   }
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.cc
index f262c10..24ec7516 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.cc
@@ -4,12 +4,13 @@
 
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
 
+#include <utility>
+
 #include "base/files/file_path.h"
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
 #include "base/functional/overloaded.h"
 #include "base/strings/strcat.h"
-#include "base/strings/stringprintf.h"
 #include "base/types/expected.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_location.h"
 #include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h"
@@ -74,9 +75,9 @@
           // reachable.
           DCHECK(error_ptr);
 
-          std::move(callback).Run(base::unexpected(base::StrCat(
-              {"Failed to read the integrity block of the signed web bundle: ",
-               (*error_ptr)->message})));
+          std::move(callback).Run(base::unexpected(
+              "Failed to read the integrity block of the signed web bundle: " +
+              (*error_ptr)->message));
         }
       },
       std::move(reader), std::move(callback_second));
@@ -96,8 +97,8 @@
   }
   if (!url.SchemeIs(chrome::kIsolatedAppScheme)) {
     return base::unexpected(
-        base::StringPrintf("The URL scheme must be %s, but was %s",
-                           chrome::kIsolatedAppScheme, url.scheme().c_str()));
+        base::StrCat({"The URL scheme must be ", chrome::kIsolatedAppScheme,
+                      ", but was ", url.scheme()}));
   }
 
   // Valid isolated-app:// `GURL`s can never include credentials or ports, since
@@ -110,9 +111,9 @@
   auto web_bundle_id = web_package::SignedWebBundleId::Create(url.host());
   if (!web_bundle_id.has_value()) {
     return base::unexpected(
-        base::StringPrintf("The host of isolated-app:// URLs must be a valid "
-                           "Signed Web Bundle ID (got %s): %s",
-                           url.host().c_str(), web_bundle_id.error().c_str()));
+        base::StrCat({"The host of isolated-app:// URLs must be a valid Signed "
+                      "Web Bundle ID (got ",
+                      url.host(), "): ", web_bundle_id.error()}));
   }
 
   return IsolatedWebAppUrlInfo(*web_bundle_id);
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory.cc
index 91297108..35029d7 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory.cc
@@ -172,13 +172,13 @@
   const WebApp* iwa = registrar.GetAppById(url_info.app_id());
 
   if (iwa == nullptr || !iwa->is_locally_installed()) {
-    return base::unexpected(base::StrCat(
-        {"Isolated Web App not installed: ", url_info.origin().Serialize()}));
+    return base::unexpected("Isolated Web App not installed: " +
+                            url_info.origin().Serialize());
   }
 
   if (!iwa->isolation_data().has_value()) {
-    return base::unexpected(base::StrCat(
-        {"App is not an Isolated Web App: ", url_info.origin().Serialize()}));
+    return base::unexpected("App is not an Isolated Web App: " +
+                            url_info.origin().Serialize());
   }
 
   return *iwa;
@@ -219,9 +219,8 @@
     if (!response.has_value()) {
       LogErrorMessageToConsole(
           frame_tree_node_id_,
-          base::StringPrintf(
-              "Failed to read response from Signed Web Bundle: %s",
-              response.error().message.c_str()));
+          "Failed to read response from Signed Web Bundle: " +
+              response.error().message);
       switch (response.error().type) {
         case IsolatedWebAppReaderRegistry::ReadResponseError::Type::kOtherError:
           loader_client_->OnComplete(
@@ -505,8 +504,8 @@
   content::StoragePartition* storage_partition = profile_->GetStoragePartition(
       url_info.storage_partition_config(profile_), /*can_create=*/false);
   if (storage_partition == nullptr) {
-    LogErrorAndFail(base::StrCat({"Storage not found for Isolated Web App: ",
-                                  resource_request.url.spec()}),
+    LogErrorAndFail("Storage not found for Isolated Web App: " +
+                        resource_request.url.spec(),
                     std::move(loader_client));
     return;
   }
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.cc
index 1d3a0769..e8d364e 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.cc
@@ -4,8 +4,10 @@
 
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h"
 
+#include <string>
+#include <utility>
+
 #include "base/functional/callback.h"
-#include "base/strings/stringprintf.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_trust_checker.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
 #include "chrome/common/url_constants.h"
@@ -44,7 +46,7 @@
   std::move(callback).Run(absl::nullopt);
 }
 
-absl::optional<std::string> IsolatedWebAppValidator::ValidateMetadata(
+base::expected<void, std::string> IsolatedWebAppValidator::ValidateMetadata(
     const web_package::SignedWebBundleId& web_bundle_id,
     const absl::optional<GURL>& primary_url,
     const std::vector<GURL>& entries) {
@@ -52,8 +54,8 @@
   // URLs make no sense for Isolated Web Apps - the "primary URL" should be
   // retrieved from the web app manifest's `start_url` field.
   if (primary_url.has_value()) {
-    return base::StringPrintf("Primary URL must not be present, but was %s",
-                              primary_url->possibly_invalid_spec().c_str());
+    return base::unexpected("Primary URL must not be present, but was " +
+                            primary_url->possibly_invalid_spec());
   }
 
   // Verify that the bundle only contains isolated-app:// URLs using the
@@ -62,30 +64,30 @@
     base::expected<IsolatedWebAppUrlInfo, std::string> url_info =
         IsolatedWebAppUrlInfo::Create(entry);
     if (!url_info.has_value()) {
-      return base::StringPrintf("The URL of an exchange is invalid: %s",
-                                url_info.error().c_str());
+      return base::unexpected("The URL of an exchange is invalid: " +
+                              url_info.error());
     }
 
     const web_package::SignedWebBundleId& entry_web_bundle_id =
         url_info->web_bundle_id();
     if (entry_web_bundle_id != web_bundle_id) {
-      return base::StringPrintf(
-          "The URL of an exchange contains the wrong Signed Web Bundle ID: %s",
-          entry_web_bundle_id.id().c_str());
+      return base::unexpected(
+          "The URL of an exchange contains the wrong Signed Web Bundle ID: " +
+          entry_web_bundle_id.id());
     }
     if (entry.has_ref()) {
-      return base::StringPrintf(
+      return base::unexpected(
           "The URL of an exchange is invalid: URLs must not have a fragment "
           "part.");
     }
     if (entry.has_query()) {
-      return base::StringPrintf(
+      return base::unexpected(
           "The URL of an exchange is invalid: URLs must not have a query "
           "part.");
     }
   }
 
-  return absl::nullopt;
+  return base::ok();
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h
index b683bfba..c9ddc34 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/functional/callback_forward.h"
+#include "base/types/expected.h"
 #include "components/web_package/signed_web_bundles/signed_web_bundle_signature_stack.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -38,9 +39,8 @@
       base::OnceCallback<void(absl::optional<std::string>)> callback);
 
   // Validates that the metadata of the Isolated Web App is valid given the
-  // `web_bundle_id`. Returns `absl::nullopt` on success, or an error message if
-  // metadata is invalid.
-  [[nodiscard]] virtual absl::optional<std::string> ValidateMetadata(
+  // `web_bundle_id`.
+  [[nodiscard]] virtual base::expected<void, std::string> ValidateMetadata(
       const web_package::SignedWebBundleId& web_bundle_id,
       const absl::optional<GURL>& primary_url,
       const std::vector<GURL>& entries);
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator_unittest.cc
index ac87657..14c16002 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h"
 
 #include <memory>
+#include <string>
 #include <tuple>
 
 #include "base/containers/span.h"
@@ -159,7 +160,7 @@
       public ::testing::WithParamInterface<
           std::tuple<absl::optional<std::string>,
                      std::vector<std::string>,
-                     absl::optional<std::string>>> {
+                     std::string>> {
  public:
   IsolatedWebAppValidatorMetadataTest()
       : primary_url_(std::get<0>(GetParam())),
@@ -172,7 +173,7 @@
  protected:
   absl::optional<GURL> primary_url_;
   std::vector<GURL> entries_;
-  absl::optional<std::string> error_message_;
+  std::string error_message_;
 };
 
 TEST_P(IsolatedWebAppValidatorMetadataTest, Validate) {
@@ -183,7 +184,8 @@
   auto isolated_web_app_trust_checker =
       std::make_unique<MockIsolatedWebAppTrustChecker>();
   IsolatedWebAppValidator validator(std::move(isolated_web_app_trust_checker));
-  EXPECT_EQ(validator.ValidateMetadata(*web_bundle_id, primary_url_, entries_),
+  EXPECT_EQ(validator.ValidateMetadata(*web_bundle_id, primary_url_, entries_)
+                .error_or(std::string()),
             error_message_);
 }
 
@@ -193,7 +195,7 @@
     ::testing::Values(
         std::make_tuple(absl::nullopt,
                         std::vector<std::string>({kUrl}),
-                        absl::nullopt),
+                        std::string()),
         std::make_tuple(absl::nullopt,
                         std::vector<std::string>({kUrl, kUrl + "/foo#bar"}),
                         "The URL of an exchange is invalid: URLs must not have "
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.cc
index 2dece4b..e7fd94e 100644
--- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_external_install_options.h"
 
-#include "base/strings/stringprintf.h"
 #include "base/types/expected.h"
 #include "base/values.h"
 #include "chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_constants.h"
@@ -58,8 +57,8 @@
       web_bundle_id =
           web_package::SignedWebBundleId::Create(*web_bundle_id_raw);
   if (!web_bundle_id.has_value()) {
-    return base::unexpected(base::StringPrintf("Wrong Web Bundle ID value: %s",
-                                               web_bundle_id.error().c_str()));
+    return base::unexpected("Wrong Web Bundle ID value: " +
+                            web_bundle_id.error());
   }
 
   if (web_bundle_id->type() !=
diff --git a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager.cc b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager.cc
index 5d26c268..298d5485 100644
--- a/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/policy/isolated_web_app_policy_manager.cc
@@ -359,12 +359,11 @@
   if (!result.has_value()) {
     LOG(ERROR) << "Could not install the IWA "
                << current_app_->web_bundle_id().id();
-    SetResultAndContinue(
-        EphemeralAppInstallResult::kErrorCantInstallFromWebBundle);
-    return;
   }
-
-  SetResultAndContinue(EphemeralAppInstallResult::kSuccess);
+  SetResultAndContinue(
+      result.has_value()
+          ? EphemeralAppInstallResult::kSuccess
+          : EphemeralAppInstallResult::kErrorCantInstallFromWebBundle);
 }
 
 void IsolatedWebAppPolicyManager::WipeCurrentIwaDirectory() {
diff --git a/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.cc b/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.cc
index 65656dc..db33efd 100644
--- a/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.cc
@@ -15,7 +15,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/notreached.h"
 #include "base/numerics/safe_conversions.h"
-#include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
@@ -154,9 +153,9 @@
         std::move(read_error_callback),
         web_package::mojom::BundleIntegrityBlockParseError::New(
             web_package::mojom::BundleParseErrorType::kFormatError,
-            base::StringPrintf("Error while parsing the Signed Web Bundle's "
-                               "integrity block: %s",
-                               integrity_block.error().c_str())));
+            "Error while parsing the Signed Web Bundle's integrity "
+            "block: " +
+                integrity_block.error()));
     return;
   }
 
@@ -338,12 +337,11 @@
   if (entry_it == entries_.end()) {
     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
         FROM_HERE,
-        base::BindOnce(
-            std::move(callback),
-            base::unexpected(ReadResponseError::ForResponseNotFound(
-                base::StringPrintf("The Web Bundle does not contain a response "
-                                   "for the provided URL: %s",
-                                   url.spec().c_str())))));
+        base::BindOnce(std::move(callback),
+                       base::unexpected(ReadResponseError::ForResponseNotFound(
+                           "The Web Bundle does not contain a response for the "
+                           "provided URL: " +
+                           url.spec()))));
     return;
   }
 
@@ -481,9 +479,8 @@
           FROM_HERE,
           base::BindOnce(
               std::move(response_callback),
-              base::unexpected(
-                  ReadResponseError::ForParserInternalError(base::StringPrintf(
-                      "Unable to open file: %s", error->c_str())))));
+              base::unexpected(ReadResponseError::ForParserInternalError(
+                  "Unable to open file: " + *error))));
     }
     return;
   }
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index ebf2ae7..510f621 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -16,7 +16,7 @@
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "base/values.h"
 #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
 #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h"
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc
index d7ad75cf..62d13f9 100644
--- a/chrome/browser/web_applications/web_app_registrar.cc
+++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -16,7 +16,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/observer_list.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 089754e..dced6b8 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1682321667-228cd2240473df9e4cba42bd6dce0a1f9a2d8655.profdata
+chrome-chromeos-amd64-generic-main-1682395070-53932ac322b8d88c913e134667a61301f3a08778.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index f368dff..de432b2 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1682337200-5299fdca8aef9f77bddc11a8e764390d478f5709.profdata
+chrome-linux-main-1682380580-ef4efb8c1a8e9719efd90c36c7901b6c2266cdd1.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 1cea2587..3cb32a8 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1682351986-8ed2b2f46238bdf2904d724249589069861e8cae.profdata
+chrome-mac-arm-main-1682402204-e8adbe292d5312460ee7b93ea70b4557db052873.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 8a4e158..09154bfb 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1682337200-6876ac0deabd605c5ba2032f56b651f391ead56e.profdata
+chrome-mac-main-1682380580-4e554c999ab317cbac826f0074ba0c91e5302d05.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 07efc07..945f7dd 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1682348397-46d998e3219286ae7ce1a9e713229107625154c1.profdata
+chrome-win32-main-1682380580-5f849d5d683c548ca93e4556a67fed8045f1611c.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 5d110f315..786a6b9 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1682348397-19546752424be0b7a659b515dafebef9f73fb604.profdata
+chrome-win64-main-1682391585-a115d4971820deb7faa049a20fe2cb6de5db08d5.profdata
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 9554fef..3b40984 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -590,6 +590,9 @@
 const char kThisTabCaptureAutoAccept[] = "auto-accept-this-tab-capture";
 const char kThisTabCaptureAutoReject[] = "auto-reject-this-tab-capture";
 
+// Custom delay for memory log. This should be used only for testing purpose.
+const char kTestMemoryLogDelayInMinutes[] = "test-memory-log-delay-in-minutes";
+
 // Passes the name of the current running automated test to Chrome.
 const char kTestName[] = "test-name";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 7fd54c7..f0f55d5 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -179,6 +179,7 @@
 extern const char kSystemLogUploadFrequency[];
 extern const char kThisTabCaptureAutoAccept[];
 extern const char kThisTabCaptureAutoReject[];
+extern const char kTestMemoryLogDelayInMinutes[];
 extern const char kTestName[];
 extern const char kTrustedDownloadSources[];
 extern const char kTryChromeAgain[];
diff --git a/chrome/renderer/extensions/api/extension_hooks_delegate_unittest.cc b/chrome/renderer/extensions/api/extension_hooks_delegate_unittest.cc
index 63cd0a4..70fb2e1 100644
--- a/chrome/renderer/extensions/api/extension_hooks_delegate_unittest.cc
+++ b/chrome/renderer/extensions/api/extension_hooks_delegate_unittest.cc
@@ -198,9 +198,9 @@
   // Open a receiver for the message.
   EXPECT_CALL(*ipc_message_sender(),
               SendOpenMessagePort(MSG_ROUTING_NONE, port_id));
-  messaging_service()->DispatchOnConnect(script_context_set(), port_id,
-                                         kChannel, tab_connection_info,
-                                         external_connection_info, nullptr);
+  messaging_service()->DispatchOnConnect(
+      script_context_set(), port_id, ChannelType::kSendRequest, kChannel,
+      tab_connection_info, external_connection_info, nullptr);
   ::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
   EXPECT_TRUE(
       messaging_service()->HasPortForTesting(script_context(), port_id));
diff --git a/chrome/services/printing/print_backend_service_impl.cc b/chrome/services/printing/print_backend_service_impl.cc
index 85e0ab1..67b9c18 100644
--- a/chrome/services/printing/print_backend_service_impl.cc
+++ b/chrome/services/printing/print_backend_service_impl.cc
@@ -19,6 +19,7 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/threading/sequence_bound.h"
+#include "base/types/expected.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -590,6 +591,22 @@
           std::move(caps_and_info)));
 }
 
+#if BUILDFLAG(IS_WIN)
+void PrintBackendServiceImpl::GetPaperPrintableArea(
+    const std::string& printer_name,
+    const PrintSettings::RequestedMedia& media,
+    mojom::PrintBackendService::GetPaperPrintableAreaCallback callback) {
+  CHECK(print_backend_);
+  crash_keys_ = std::make_unique<crash_keys::ScopedPrinterInfo>(
+      print_backend_->GetPrinterDriverInfo(printer_name));
+
+  absl::optional<gfx::Rect> printable_area_um =
+      print_backend_->GetPaperPrintableArea(printer_name, media.vendor_id,
+                                            media.size_microns);
+  std::move(callback).Run(printable_area_um.value_or(gfx::Rect()));
+}
+#endif
+
 void PrintBackendServiceImpl::EstablishPrintingContext(uint32_t context_id
 #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
                                                        ,
@@ -937,14 +954,12 @@
     return base::unexpected(value_result->get_result_code());
   }
 
-  base::expected<XpsCapabilities, mojom::ResultCode> xps_capabilities =
-      ParseValueForXpsPrinterCapabilities(value_result->get_capabilities());
-  if (!xps_capabilities.has_value()) {
-    DLOG(ERROR) << "Failure parsing value of XPS capabilities of printer "
-                << printer_name << ", error: " << xps_capabilities.error();
-    return base::unexpected(xps_capabilities.error());
-  }
-  return std::move(xps_capabilities).value();
+  return ParseValueForXpsPrinterCapabilities(value_result->get_capabilities())
+      .transform_error([&](mojom::ResultCode code) {
+        DLOG(ERROR) << "Failure parsing value of XPS capabilities of printer "
+                    << printer_name << ", error: " << code;
+        return code;
+      });
 }
 #endif  // BUILDFLAG(IS_WIN)
 
diff --git a/chrome/services/printing/print_backend_service_impl.h b/chrome/services/printing/print_backend_service_impl.h
index f31eba3..dd25010 100644
--- a/chrome/services/printing/print_backend_service_impl.h
+++ b/chrome/services/printing/print_backend_service_impl.h
@@ -161,6 +161,13 @@
   void FetchCapabilities(
       const std::string& printer_name,
       mojom::PrintBackendService::FetchCapabilitiesCallback callback) override;
+#if BUILDFLAG(IS_WIN)
+  void GetPaperPrintableArea(
+      const std::string& printer_name,
+      const PrintSettings::RequestedMedia& media,
+      mojom::PrintBackendService::GetPaperPrintableAreaCallback callback)
+      override;
+#endif
   void EstablishPrintingContext(uint32_t context_id
 #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
                                 ,
diff --git a/chrome/services/printing/public/mojom/print_backend_service.mojom b/chrome/services/printing/public/mojom/print_backend_service.mojom
index 9d79b09..42acff3 100644
--- a/chrome/services/printing/public/mojom/print_backend_service.mojom
+++ b/chrome/services/printing/public/mojom/print_backend_service.mojom
@@ -111,6 +111,17 @@
   FetchCapabilities(string printer_name)
     => (PrinterCapsAndInfoResult printer_caps_and_info);
 
+  // Gets the printable area for a particular paper size.  Windows only, as a
+  // workaround for the high cost of trying to get printable area for all paper
+  // sizes in `FetchCapabilities()`.  Returns an empty area if there is any
+  // error in retrieving the printable area.
+  // TODO(crbug.com/1424368):  Remove this if
+  // `PrintBackendWin::GetPrinterSemanticCapsAndDefaults()` can be made to
+  // fetch the all printable areas in a performant manner.
+  [EnableIf=is_win]
+  GetPaperPrintableArea(string printer_name, RequestedMedia media)
+    => (gfx.mojom.Rect printable_area_um);
+
   // Creates a printing context that can persist across multiple calls.
   // Necessary to ensure that the context used for system dialogs is still
   // available by the time that printing is started.  The printing context
diff --git a/chrome/services/qrcode_generator/qrcode_generator_service_impl.cc b/chrome/services/qrcode_generator/qrcode_generator_service_impl.cc
index d401677..b132a49 100644
--- a/chrome/services/qrcode_generator/qrcode_generator_service_impl.cc
+++ b/chrome/services/qrcode_generator/qrcode_generator_service_impl.cc
@@ -195,7 +195,7 @@
 }
 
 void QRCodeGeneratorServiceImpl::RenderBitmap(
-    const uint8_t* data,
+    base::span<const uint8_t> data,
     const gfx::Size data_size,
     const mojom::GenerateQRCodeRequestPtr& request,
     mojom::GenerateQRCodeResponsePtr* response) {
@@ -321,19 +321,17 @@
     std::move(callback).Run(std::move(response));
     return;
   }
-  auto& qr_data_span = qr_data->data;
-
   // The least significant bit of each byte in |qr_data.span| is set if the tile
   // should be black.
-  for (size_t i = 0; i < qr_data_span.size(); i++) {
-    qr_data_span[i] &= 1;
+  for (uint8_t& byte : qr_data->data) {
+    byte &= 1;
   }
 
-  response->data.insert(response->data.begin(), qr_data_span.begin(),
-                        qr_data_span.end());
+  response->data = std::move(qr_data->data);
   response->data_size = {qr_data->qr_size, qr_data->qr_size};
   response->error_code = mojom::QRCodeGeneratorError::NONE;
-  RenderBitmap(qr_data_span.data(), response->data_size, request, &response);
+  RenderBitmap(base::make_span(response->data), response->data_size, request,
+               &response);
 
   std::move(callback).Run(std::move(response));
 }
diff --git a/chrome/services/qrcode_generator/qrcode_generator_service_impl.h b/chrome/services/qrcode_generator/qrcode_generator_service_impl.h
index d63ff1a..3ce775d 100644
--- a/chrome/services/qrcode_generator/qrcode_generator_service_impl.h
+++ b/chrome/services/qrcode_generator/qrcode_generator_service_impl.h
@@ -75,7 +75,7 @@
   // |response| is the mojo service request object to Generate().
   //     The bitmap will be populated as a response field if requested by the
   //     client.
-  void RenderBitmap(const uint8_t* data,
+  void RenderBitmap(base::span<const uint8_t> data,
                     const gfx::Size data_size,
                     const mojom::GenerateQRCodeRequestPtr& request,
                     mojom::GenerateQRCodeResponsePtr* response);
diff --git a/chrome/services/qrcode_generator/qrcode_generator_service_pixeltest.cc b/chrome/services/qrcode_generator/qrcode_generator_service_pixeltest.cc
new file mode 100644
index 0000000..7e1fe067
--- /dev/null
+++ b/chrome/services/qrcode_generator/qrcode_generator_service_pixeltest.cc
@@ -0,0 +1,88 @@
+// Copyright 2023 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 "base/test/bind.h"
+#include "chrome/services/qrcode_generator/public/cpp/qrcode_generator_service.h"
+#include "chrome/services/qrcode_generator/public/mojom/qrcode_generator.mojom.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/test/browser_test.h"
+#include "ui/base/test/skia_gold_pixel_diff.h"
+
+namespace qrcode_generator {
+namespace {
+
+class QrCodeGeneratorServicePixelTest : public PlatformBrowserTest {
+ public:
+  QrCodeGeneratorServicePixelTest() = default;
+
+  void TestGolden(const std::string& data,
+                  const mojom::CenterImage& center_image,
+                  const mojom::ModuleStyle& module_style,
+                  const mojom::LocatorStyle& locator_style) {
+    mojom::GenerateQRCodeRequestPtr request =
+        mojom::GenerateQRCodeRequest::New();
+    request->data = data;
+    request->should_render = true;
+    request->center_image = center_image;
+    request->render_module_style = module_style;
+    request->render_locator_style = locator_style;
+
+    mojom::GenerateQRCodeResponsePtr response;
+    mojo::Remote<mojom::QRCodeGeneratorService> qr_service =
+        LaunchQRCodeGeneratorService();
+    base::RunLoop run_loop;
+    qr_service->GenerateQRCode(
+        std::move(request),
+        base::BindLambdaForTesting([&](mojom::GenerateQRCodeResponsePtr r) {
+          response = std::move(r);
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+
+    // Verify that we got a successful response.
+    ASSERT_TRUE(response);
+    ASSERT_EQ(response->error_code, mojom::QRCodeGeneratorError::NONE);
+
+    // Version 1 of QR codes has 21x21 modules/tiles/pixels.  Verify that the
+    // returned QR image has a size that is at least 21x21.
+    ASSERT_GE(response->data_size.width(), 21);
+
+    // The `data_size` should indicate a square + should be consistent with
+    // the size of the actual `data`.
+    ASSERT_EQ(response->data_size.width(), response->data_size.height());
+    ASSERT_EQ(static_cast<int32_t>(response->data.size()),
+              response->data_size.width() * response->data_size.height());
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS_LACROS)
+    // Verify image contents through go/chrome-engprod-skia-gold.
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            "browser-ui-tests-verify-pixels")) {
+      const ::testing::TestInfo* test_info =
+          ::testing::UnitTest::GetInstance()->current_test_info();
+      ui::test::SkiaGoldPixelDiff pixel_diff;
+      pixel_diff.Init(test_info->test_suite_name());
+      ASSERT_TRUE(
+          pixel_diff.CompareScreenshot(test_info->name(), response->bitmap));
+    }
+#endif
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(QrCodeGeneratorServicePixelTest,
+                       DinoWithRoundQrPixelsAndLocators) {
+  TestGolden("https://example.com", mojom::CenterImage::CHROME_DINO,
+             mojom::ModuleStyle::CIRCLES, mojom::LocatorStyle::ROUNDED);
+}
+
+IN_PROC_BROWSER_TEST_F(QrCodeGeneratorServicePixelTest,
+                       PassKeyWithSquareQrPixelsAndLocators) {
+  TestGolden("https://example.com", mojom::CenterImage::PASSKEY_ICON,
+             mojom::ModuleStyle::DEFAULT_SQUARES,
+             mojom::LocatorStyle::DEFAULT_SQUARE);
+}
+
+}  // namespace
+}  // namespace qrcode_generator
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 4a1ce75..45c0253 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -493,8 +493,8 @@
       "../browser/download/download_browsertest_utils.h",
       "../browser/performance_manager/test_support/fake_frame_throttling_delegate.cc",
       "../browser/performance_manager/test_support/fake_frame_throttling_delegate.h",
-      "../browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.cc",
-      "../browser/performance_manager/test_support/fake_high_efficiency_mode_delegate.h",
+      "../browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.cc",
+      "../browser/performance_manager/test_support/fake_high_efficiency_mode_toggle_delegate.h",
       "../browser/performance_manager/test_support/fake_power_monitor_source.cc",
       "../browser/performance_manager/test_support/fake_power_monitor_source.h",
       "../browser/performance_manager/test_support/page_discarding_utils.cc",
@@ -1372,6 +1372,8 @@
       "//chrome/common:version_header",
       "//chrome/common/privacy_budget:test_support",
       "//chrome/renderer",
+      "//chrome/services/qrcode_generator/public/cpp",
+      "//chrome/services/qrcode_generator/public/mojom",
       "//chrome/services/removable_storage_writer:lib",
       "//chrome/test/data/webui:resources_grit",
       "//chrome/test/data/webui:web_ui_test_bindings",
@@ -1965,6 +1967,7 @@
       "../browser/metrics/ukm_background_recorder_browsertest.cc",
       "../browser/metrics/ukm_browsertest.cc",
       "../browser/metrics/usage_scenario/tab_usage_scenario_tracker_browsertest.cc",
+      "../browser/metrics/variations/field_trials_on_off_browsertest.cc",
       "../browser/metrics/variations/force_field_trials_browsertest.cc",
       "../browser/metrics/variations/variations_http_headers_browsertest.cc",
       "../browser/metrics/variations/variations_safe_mode_browsertest.cc",
@@ -2344,6 +2347,7 @@
       "../browser/ui/views/webid/fake_delegate.cc",
       "../browser/ui/views/webid/fake_delegate.h",
       "../browser/ui/views/webid/fedcm_account_selection_view_desktop_browsertest.cc",
+      "../browser/ui/views/webid/fedcm_modal_dialog_view_browsertest.cc",
       "../browser/ui/views/webview_accessibility_browsertest.cc",
       "../browser/ui/webauthn/authenticator_dialog_browsertest.cc",
       "../browser/ui/webui/app_service_internals/app_service_internals_browsertest.cc",
@@ -2419,6 +2423,7 @@
       "../renderer/translate/per_frame_translate_agent_browsertest.cc",
       "../renderer/translate/translate_agent_browsertest.cc",
       "../renderer/translate/translate_script_browsertest.cc",
+      "../services/qrcode_generator/qrcode_generator_service_pixeltest.cc",
       "base/devtools_listener.cc",
       "base/devtools_listener.h",
       "base/devtools_listener_browsertest.cc",
@@ -5634,7 +5639,6 @@
     "../browser/performance_manager/decorators/frozen_frame_aggregator_unittest.cc",
     "../browser/performance_manager/decorators/helpers/page_live_state_decorator_helper_unittest.cc",
     "../browser/performance_manager/decorators/page_aggregator_unittest.cc",
-    "../browser/performance_manager/decorators/process_metrics_decorator_unittest.cc",
     "../browser/performance_manager/decorators/process_priority_aggregator_unittest.cc",
     "../browser/performance_manager/mechanisms/page_freezer_unittest.cc",
     "../browser/performance_manager/metrics/memory_pressure_metrics_unittest.cc",
@@ -7149,6 +7153,7 @@
       "../browser/ui/views/webid/fake_delegate.cc",
       "../browser/ui/views/webid/fake_delegate.h",
       "../browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc",
+      "../browser/ui/views/webid/fedcm_modal_dialog_view_unittest.cc",
       "../browser/ui/webauthn/sheet_models_unittest.cc",
       "../browser/ui/webui/access_code_cast/access_code_cast_handler_unittest.cc",
       "../browser/ui/webui/browser_command/browser_command_handler_unittest.cc",
diff --git a/chrome/test/base/chromeos/ash_browser_test_starter.cc b/chrome/test/base/chromeos/ash_browser_test_starter.cc
index 39f9295..857980a 100644
--- a/chrome/test/base/chromeos/ash_browser_test_starter.cc
+++ b/chrome/test/base/chromeos/ash_browser_test_starter.cc
@@ -61,8 +61,7 @@
     int retry_count = 1;
     while (base::PathExists(test_output_folder) && retry_count < 5) {
       test_output_folder = output_file_path.DirName().Append(
-          test_name + base::ToString(".retry_") +
-          base::NumberToString(retry_count));
+          test_name + ".retry_" + base::NumberToString(retry_count));
       ++retry_count;
     }
     // Unlikely the path still exist. But in case it happens, we would let
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index 9e7cba89..2c5122b 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -1075,10 +1075,9 @@
   base::JSONWriter::Write(*prefs, &prefs_str);
   VLOG(0) << "Populating " << path.BaseName().value()
           << " file: " << PrettyPrintValue(base::Value(prefs->Clone()));
-  if (!base::WriteFile(path, prefs_str)) {
-    return Status(kUnknownError, "failed to write prefs file");
-  }
-  return Status(kOk);
+  return base::WriteFile(path, prefs_str)
+             ? Status(kOk)
+             : Status(kUnknownError, "failed to write prefs file");
 }
 
 Status PrepareUserDataDir(const base::FilePath& user_data_dir,
diff --git a/chrome/test/data/android/url_overriding/navigation_from_bfcache-1.html b/chrome/test/data/android/url_overriding/navigation_from_bfcache-1.html
index 144b715..f7e2bcb 100644
--- a/chrome/test/data/android/url_overriding/navigation_from_bfcache-1.html
+++ b/chrome/test/data/android/url_overriding/navigation_from_bfcache-1.html
@@ -3,7 +3,9 @@
     <meta name='viewport' content='width=device-width, initial-scale=1.0'>
   </head>
   <body>
-    <a href='navigation_from_bfcache-2.html' id='link'>Click me and then hit back.</a>
+    <a href='navigation_from_bfcache-2.html'>Click me and then hit back.
+      <div style='height:10000px; width:100%;'></div>
+    </a>
     <script>
       window.addEventListener('pageshow', (event) => {
         if (event.persisted) {
diff --git a/chrome/test/data/android/url_overriding/navigation_to_file_scheme_via_intent_uri.html b/chrome/test/data/android/url_overriding/navigation_to_file_scheme_via_intent_uri.html
deleted file mode 100644
index 49a581f..0000000
--- a/chrome/test/data/android/url_overriding/navigation_to_file_scheme_via_intent_uri.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-Intent URI example taken from crbug.com/1056754 with package modification here.
--->
-<head>
-    <meta name="viewport"
-          content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
-</head>
-
-<body>
-<a id="scheme_file" target='_blank' href='intent:///x.mhtml#Intent;package=org.chromium.chrome.tests;action=android.intent.action.VIEW;scheme=file;end;'>
-    Intent URI with scheme file!!
-</a> <br>
-
-<a id="scheme_mixed_case_file" target='_blank' href='intent:///x.mhtml#Intent;package=org.chromium.chrome.tests;action=android.intent.action.VIEW;scheme=FiLe;end;'>
-    Intent URI with scheme FiLe!!
-</a><br>
-
-<a id="null_scheme" target='_blank' href='intent:///x.mhtml#Intent;package=org.chromium.chrome.tests;action=android.intent.action.VIEW;end;'>
-    Intent URI with NULL scheme!!
-</a><br>
-
-<a id="empty_scheme" target='_blank' href='intent:///x.mhtml#Intent;package=org.chromium.chrome.tests;action=android.intent.action.VIEW;scheme=;end;'>
-    Intent URI with empty scheme!!
-</a><br>
-
-</body>
-
-</html>
\ No newline at end of file
diff --git a/chrome/test/data/android/url_overriding/open_window_from_link_user_gesture.html b/chrome/test/data/android/url_overriding/open_window_from_link_user_gesture.html
index 3022819..9538d9ce 100644
--- a/chrome/test/data/android/url_overriding/open_window_from_link_user_gesture.html
+++ b/chrome/test/data/android/url_overriding/open_window_from_link_user_gesture.html
@@ -5,7 +5,7 @@
     content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
 </head>
 <body>
-<a target='_blank' href='intent://test/#Intent;scheme=externalappscheme;end'>
+<a target='_blank' href='PARAM_URL'>
   Click to open App!!
   <div style='height:10000px; width:100%;'></div>
 </a>
diff --git a/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/default_path.html b/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/default_path.html
new file mode 100644
index 0000000..2e9921c
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/default_path.html
@@ -0,0 +1,3 @@
+<body>SIDEPANEL</body>
+
+<script src="./default_path.js"></script>
diff --git a/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/default_path.js b/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/default_path.js
new file mode 100644
index 0000000..991c073d
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/default_path.js
@@ -0,0 +1,5 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.test.sendMessage('default_path');
diff --git a/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/manifest.json b/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/manifest.json
new file mode 100644
index 0000000..34001ebc
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/manifest.json
@@ -0,0 +1,11 @@
+{
+  "name": "Side panel extension with action.onclick",
+  "version": "1.0",
+  "manifest_version": 3,
+  "permissions": ["sidePanel"],
+  "background": {
+    "service_worker": "worker.js"
+  },
+  "action": {},
+  "side_panel": {"default_path": "default_path.html"}
+}
diff --git a/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/worker.js b/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/worker.js
new file mode 100644
index 0000000..6a14b05
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/side_panel/with_action_onclick/worker.js
@@ -0,0 +1,7 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.action.onClicked.addListener(() => {
+  chrome.test.sendMessage('action_clicked');
+});
diff --git a/chrome/test/data/webui/chromeos/BUILD.gn b/chrome/test/data/webui/chromeos/BUILD.gn
index b8f71365..c2c7b7fc 100644
--- a/chrome/test/data/webui/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/BUILD.gn
@@ -72,7 +72,6 @@
     "ash_common/i18n_behavior_test.js",
     "chai_assert.js",
     "fake_network_config_mojom.js",
-    "fake_passpoint_service_mojom.ts",
     "mock_controller.js",
     "mock_controller.m.js",
     "set_time_dialog_test.js",
diff --git a/chrome/test/data/webui/chromeos/fake_passpoint_service_mojom.ts b/chrome/test/data/webui/chromeos/fake_passpoint_service_mojom.ts
deleted file mode 100644
index b307ebf..0000000
--- a/chrome/test/data/webui/chromeos/fake_passpoint_service_mojom.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2023 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 PasspointService for testing.
- */
-import {assert} from 'chrome://resources/ash/common/assert.js';
-import {PasspointEventsListenerRemote, PasspointServiceInterface, PasspointSubscription} from 'chrome://resources/ash/common/connectivity/passpoint.mojom-webui.js';
-
-export class FakePasspointService implements PasspointServiceInterface {
-  private subs_: Map<string, PasspointSubscription>;
-
-  constructor() {
-    /**
-     * @private {!Map<string, !PasspointSubscription>}
-     */
-    this.subs_ = new Map();
-  }
-
-  addSubscription(sub: PasspointSubscription): void {
-    assert(sub !== undefined);
-    this.subs_.set(sub.id, sub);
-  }
-
-  resetForTest(): void {
-    this.subs_ = new Map();
-  }
-
-  getPasspointSubscription(id: string):
-      Promise<{result: PasspointSubscription | null}> {
-    return new Promise(resolve => {
-      const sub = this.subs_.get(id);
-      resolve({result: sub ? sub : null});
-    });
-  }
-
-  listPasspointSubscriptions(): Promise<{result: PasspointSubscription[]}> {
-    return new Promise(resolve => {
-      resolve({result: Array.from(this.subs_, ([_, value]) => (value))});
-    });
-  }
-
-  registerPasspointListener(_: PasspointEventsListenerRemote) {
-    // Listener is ignored for now.
-  }
-
-  deletePasspointSubscription(id: string): Promise<{success: boolean}> {
-    return new Promise(resolve => {
-      resolve({success: this.subs_.delete(id)});
-    });
-  }
-}
diff --git a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
index 12c510e..79edfc5 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
@@ -420,6 +420,9 @@
         5, durationOptions!.length, 'Duration should have exactly 5 options');
 
     const optionFiveMin = durationOptions[0];
+    const optionTenMin = durationOptions[1];
+    assertTrue(
+        optionTenMin!.checked, 'Ten minutes option is initially selected');
     personalizationStore.expectAction(
         AmbientActionName.SET_SCREEN_SAVER_DURATION);
 
diff --git a/chrome/test/data/webui/chromeos/scanning/loading_page_test.js b/chrome/test/data/webui/chromeos/scanning/loading_page_test.js
index e2bfc17..df6b31c 100644
--- a/chrome/test/data/webui/chromeos/scanning/loading_page_test.js
+++ b/chrome/test/data/webui/chromeos/scanning/loading_page_test.js
@@ -120,8 +120,10 @@
     assertTrue(learnMoreEventFired);
   });
 
+  // TODO(b/276493795): After the Jelly experiment is launched, remove test.
   // Verify correct 'no scanners' svg displayed when page is in dark mode.
   test('noScannersSvgSetByColorScheme', async () => {
+    await setJellyEnabled(false);
     const lightModeSvg = `${scanningSrcBase}svg/no_scanners.svg`;
     const darkModeSvg = `${scanningSrcBase}svg/no_scanners_dark.svg`;
     const getNoScannersSvg = () => (/** @type {!HTMLImageElement} */ (
@@ -137,6 +139,25 @@
     assertEquals(darkModeSvg, getNoScannersSvg().src);
   });
 
+  // Verify "no scanners" dynamic SVG use when dynamic colors enabled.
+  test('jellyColors_NoScannersSvg', async () => {
+    await setJellyEnabled(true);
+    const dynamicSvg = `svg/illo_no_scanner.svg#illo_no_scanner`;
+    const getNoScannersSvgValue = () =>
+        (/** @type {!SVGUseElement} */ (
+             loadingPage.shadowRoot.querySelector('#noScannersDiv > svg > use'))
+             .href.baseVal);
+
+    // Setup UI to display no scanners div.
+    loadingPage.appState = AppState.NO_SCANNERS;
+    await setFakePrefersColorSchemeDark(false);
+    assertEquals(dynamicSvg, getNoScannersSvgValue());
+
+    // Mock media query state for dark mode.
+    await setFakePrefersColorSchemeDark(true);
+    assertEquals(dynamicSvg, getNoScannersSvgValue());
+  });
+
   // TODO(b/276493795): After the Jelly experiment is launched, remove test.
   // Verify correct 'loading scanners' svg displayed when page is in dark mode.
   test('scanLoadingSvgSetByColorScheme', async () => {
diff --git a/chrome/test/data/webui/chromeos/scanning/scan_preview_test.js b/chrome/test/data/webui/chromeos/scanning/scan_preview_test.js
index 9b2ac81..d327c582 100644
--- a/chrome/test/data/webui/chromeos/scanning/scan_preview_test.js
+++ b/chrome/test/data/webui/chromeos/scanning/scan_preview_test.js
@@ -72,6 +72,12 @@
   let fakePrefersColorSchemeDarkMediaQuery;
 
   /**
+   * Type alias for SVGUseElement.
+   * @typedef {{href: {baseVal: string}}}
+   */
+  let SVGUseElement;
+
+  /**
    * @param {boolean} enabled
    * @return {!Promise}
    */
@@ -82,6 +88,17 @@
     return flushTasks();
   }
 
+  /**
+   * @param {boolean} enabled
+   * @returns {!Promise}
+   */
+  function setJellyEnabled(enabled) {
+    assertTrue(!!scanPreview);
+    scanPreview.setIsJellyEnabledForTesting(enabled);
+
+    return flushTasks();
+  }
+
   setup(() => {
     fakeAccessibilityFeatures_ = new FakeAccessibilityFeatures();
     setAccessibilityFeaturesForTesting(fakeAccessibilityFeatures_);
@@ -443,8 +460,10 @@
         });
   });
 
+  // TODO(b/276493795): After the Jelly experiment is launched, remove test.
   // Verify correct svg displayed when page is in dark mode.
   test('readyToScanSvgSetByColorScheme', async () => {
+    await setJellyEnabled(false);
     const srcBase = 'chrome://scanning/';
     const lightModeSvg = `${srcBase}svg/ready_to_scan.svg`;
     const darkModeSvg = `${srcBase}svg/ready_to_scan_dark.svg`;
@@ -459,4 +478,23 @@
     await setFakePrefersColorSchemeDark(true);
     assertEquals(darkModeSvg, getReadyToScanSvg().src);
   });
+
+  // Verify "loading scanners" dynamic SVG use when dynamic colors enabled.
+  test('jellyColors_LoadingScannersSvg', async () => {
+    await setJellyEnabled(true);
+    const dynamicSvg = `svg/illo_ready_to_scan.svg#illo_ready_to_scan`;
+
+    const getLoadingScannersSvgValue = () =>
+        (/** @type {!SVGUseElement} */ (
+             scanPreview.shadowRoot.querySelector('#readyToScanSvg > use'))
+             .href.baseVal);
+
+    // Setup UI to display no scanners div.
+    await setFakePrefersColorSchemeDark(false);
+    assertEquals(dynamicSvg, getLoadingScannersSvgValue());
+
+    // Mock media query state for dark mode.
+    await setFakePrefersColorSchemeDark(true);
+    assertEquals(dynamicSvg, getLoadingScannersSvgValue());
+  });
 });
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/search_box_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/search_box_test.ts
index b129a23..6819ef8a 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/search_box_test.ts
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/search_box_test.ts
@@ -9,11 +9,12 @@
 import {IronDropdownElement} from 'chrome://resources/polymer/v3_0/iron-dropdown/iron-dropdown.js';
 import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {fakeSearchResults} from 'chrome://shortcut-customization/js/fake_data.js';
+import {CycleTabsTextSearchResult, fakeSearchResults, TakeScreenshotSearchResult} from 'chrome://shortcut-customization/js/fake_data.js';
 import {FakeShortcutSearchHandler} from 'chrome://shortcut-customization/js/search/fake_shortcut_search_handler.js';
 import {SearchBoxElement} from 'chrome://shortcut-customization/js/search/search_box.js';
 import {SearchResultRowElement} from 'chrome://shortcut-customization/js/search/search_result_row.js';
 import {setShortcutSearchHandlerForTesting} from 'chrome://shortcut-customization/js/search/shortcut_search_handler.js';
+import {AcceleratorState, MojoSearchResult} from 'chrome://shortcut-customization/js/shortcut_types.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
 import {eventToPromise} from 'chrome://webui-test/test_util.js';
@@ -320,4 +321,122 @@
     selectedRowInnerElement.click();
     assertFalse(dropdownElement.opened);
   });
+
+  test('Search availability changed', async () => {
+    [searchBoxElement, searchFieldElement, dropdownElement,
+     resultsListElement] = initSearchBoxElement();
+
+    await simulateSearch('query');
+
+    assertTrue(dropdownElement.opened);
+    assertEquals(3, searchBoxElement.searchResults.length);
+
+    // Add a new search result, but don't trigger the observer callback.
+    handler.setFakeSearchResult(
+        [...fakeSearchResults, TakeScreenshotSearchResult]);
+    assertTrue(dropdownElement.opened);
+    assertEquals(3, searchBoxElement.searchResults.length);
+
+    // Trigger the observer callback.
+    searchBoxElement.onSearchResultsAvailabilityChanged();
+    await waitForSearchResultsFetched();
+    // Check that the list updates when the dropdown is open, and the dropdown
+    // remains open.
+    assertTrue(dropdownElement.opened);
+    assertEquals(4, searchBoxElement.searchResults.length);
+
+    // User clicks outside the search box, closing the dropdown.
+    searchBoxElement.blur();
+    assertFalse(dropdownElement.opened);
+
+    // Reset the fake results.
+    handler.setFakeSearchResult(fakeSearchResults);
+
+    // Dropdown should still be closed, and the search results should not have
+    // updated yet.
+    assertFalse(dropdownElement.opened);
+    assertEquals(4, searchBoxElement.searchResults.length);
+
+    // Trigger the observer callback.
+    searchBoxElement.onSearchResultsAvailabilityChanged();
+    await waitForSearchResultsFetched();
+
+    // Check that the list updates when the dropdown is closed, and the dropdown
+    // remains closed.
+    assertFalse(dropdownElement.opened);
+    assertEquals(3, searchBoxElement.searchResults.length);
+
+    // The first item should be selected immediately when the search results
+    // change even if the change occurred while the dropdown was closed.
+    searchFieldElement.getSearchInput().focus();
+    await waitForListUpdate();
+    assertTrue(dropdownElement.opened);
+    const selectedRow = strictQuery(
+        'search-result-row[selected]', dropdownElement, SearchResultRowElement);
+    const selectedItem =
+        resultsListElement.selectedItem as (MojoSearchResult | undefined);
+    assertTrue(!!selectedItem);
+    assertEquals(
+        selectedRow.searchResult.acceleratorLayoutInfo.description,
+        selectedItem.acceleratorLayoutInfo.description);
+  });
+
+  test('Filter disabled search results', async () => {
+    [searchBoxElement, searchFieldElement, dropdownElement,
+     resultsListElement] = initSearchBoxElement();
+
+    // This SearchResult is of standard layout, and contains two
+    // AcceleratorInfos. We disable one of them to verify that the disabled
+    // AcceleratorInfo is not shown.
+    const disabledFirstAcceleratorInfo =
+        TakeScreenshotSearchResult.acceleratorInfos[0]!;
+    disabledFirstAcceleratorInfo.state =
+        AcceleratorState.kDisabledByUnavailableKeys;
+
+    const partiallyDisabledSearchResult: MojoSearchResult = {
+      ...TakeScreenshotSearchResult,
+      acceleratorInfos: [
+        disabledFirstAcceleratorInfo,
+        TakeScreenshotSearchResult.acceleratorInfos[1]!,
+      ],
+    };
+
+    handler.setFakeSearchResult(
+        [partiallyDisabledSearchResult, CycleTabsTextSearchResult]);
+
+    await simulateSearch('query');
+
+    assertTrue(dropdownElement.opened);
+    assertEquals(2, searchBoxElement.searchResults.length);
+
+    // Check that the disabled AcceleratorInfo is not present in the
+    // acceleratorInfos list of the search result.
+    assertEquals(1, searchBoxElement.searchResults[0]?.acceleratorInfos.length);
+    assertEquals(
+        TakeScreenshotSearchResult.acceleratorInfos[1],
+        searchBoxElement.searchResults[0]?.acceleratorInfos[0]);
+
+    // Create a SearchResult that doesn't have any enabled AcceleratorInfos.
+    const disabledSecondAcceleratorInfo =
+        TakeScreenshotSearchResult.acceleratorInfos[1]!;
+    disabledSecondAcceleratorInfo.state =
+        AcceleratorState.kDisabledByUnavailableKeys;
+    const fullyDisabledSearchResult: MojoSearchResult = {
+      ...TakeScreenshotSearchResult,
+      acceleratorInfos:
+          [disabledFirstAcceleratorInfo, disabledSecondAcceleratorInfo],
+    };
+
+    handler.setFakeSearchResult(
+        [fullyDisabledSearchResult, CycleTabsTextSearchResult]);
+
+    searchBoxElement.onSearchResultsAvailabilityChanged();
+    await simulateSearch('query');
+
+    assertTrue(dropdownElement.opened);
+    assertEquals(1, searchBoxElement.searchResults.length);
+    assertEquals(
+        CycleTabsTextSearchResult.acceleratorLayoutInfo.description,
+        searchBoxElement.searchResults[0]?.acceleratorLayoutInfo.description);
+  });
 });
diff --git a/chrome/test/data/webui/nearby_share/nearby_share_app_test.js b/chrome/test/data/webui/nearby_share/nearby_share_app_test.js
index 87de80f..39462f4 100644
--- a/chrome/test/data/webui/nearby_share/nearby_share_app_test.js
+++ b/chrome/test/data/webui/nearby_share/nearby_share_app_test.js
@@ -56,13 +56,11 @@
   }
 
   suite('EnabledTests', function() {
-    setup(function() {
-      sharedSetup(/*enabled=*/ true, /*isOnboardingComplete=*/ true);
-    });
-
     teardown(sharedTeardown);
 
     test('renders discovery page when enabled', async function() {
+      sharedSetup(/*enabled=*/ true, /*isOnboardingComplete=*/ true);
+
       assertEquals('NEARBY-SHARE-APP', shareAppElement.tagName);
       assertEquals(null, shareAppElement.shadowRoot.querySelector('.active'));
       // We have to wait for settings to return from the mojo after which
@@ -70,6 +68,27 @@
       await waitAfterNextRender(shareAppElement);
       assertTrue(isPageActive('discovery'));
     });
+
+    [false, true].forEach(isJellyEnabled => {
+      test(
+          'Dynamic theme CSS is added when isJellyEnabled is set', async () => {
+            loadTimeData.overrideValues({
+              isJellyEnabled: isJellyEnabled,
+            });
+
+            sharedSetup(/*enabled=*/ true, /*isOnboardingComplete=*/ true);
+
+            const linkEl = document.querySelector(
+                'link[href*=\'chrome://theme/colors.css\']');
+            if (isJellyEnabled) {
+              assertTrue(!!linkEl);
+              assertTrue(document.body.classList.contains('jelly-enabled'));
+            } else {
+              assertEquals(null, linkEl);
+              assertFalse(document.body.classList.contains('jelly-enabled'));
+            }
+          });
+    });
   });
 
   suite('DisabledTests', function() {
diff --git a/chrome/test/data/webui/password_manager/BUILD.gn b/chrome/test/data/webui/password_manager/BUILD.gn
index 3cd56e7..e525e407 100644
--- a/chrome/test/data/webui/password_manager/BUILD.gn
+++ b/chrome/test/data/webui/password_manager/BUILD.gn
@@ -14,7 +14,6 @@
     "checkup_details_section_test.ts",
     "checkup_section_test.ts",
     "edit_password_dialog_test.ts",
-    "extension_controlled_icon_test.ts",
     "move_passwords_dialog_test.ts",
     "password_details_card_test.ts",
     "password_details_section_test.ts",
@@ -27,7 +26,6 @@
     "passwords_section_test.ts",
     "settings_section_test.ts",
     "site_favicon_test.ts",
-    "test_extension_control_browser_proxy.ts",
     "test_password_manager_proxy.ts",
     "test_promo_cards_browser_proxy.ts",
     "test_sync_browser_proxy.ts",
diff --git a/chrome/test/data/webui/password_manager/extension_controlled_icon_test.ts b/chrome/test/data/webui/password_manager/extension_controlled_icon_test.ts
deleted file mode 100644
index 3061020..0000000
--- a/chrome/test/data/webui/password_manager/extension_controlled_icon_test.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2023 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 test of the extension_controlled_icon, modeled after the
- * equivalent extension_controlled_indicator_tests in settings.
- */
-
-// clang-format off
-import 'chrome://password-manager/password_manager.js';
-
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {OpenWindowProxyImpl, ExtensionControlBrowserProxyImpl, ExtensionControlledIconElement} from 'chrome://password-manager/password_manager.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {TestOpenWindowProxy} from 'chrome://webui-test/test_open_window_proxy.js';
-
-import {TestExtensionControlBrowserProxy} from './test_extension_control_browser_proxy.js';
-
-// clang-format on
-
-suite('ExtensionControlledIconTest', function() {
-  let browserProxy: TestExtensionControlBrowserProxy;
-  let extensionControlledIcon: ExtensionControlledIconElement;
-
-  let openWindowProxy: TestOpenWindowProxy;
-
-  setup(function() {
-    document.body.innerHTML = window.trustedTypes!.emptyHTML;
-    browserProxy = new TestExtensionControlBrowserProxy();
-    ExtensionControlBrowserProxyImpl.setInstance(browserProxy);
-    openWindowProxy = new TestOpenWindowProxy();
-    OpenWindowProxyImpl.setInstance(openWindowProxy);
-
-    extensionControlledIcon =
-        document.createElement('extension-controlled-icon');
-    extensionControlledIcon.extensionId = 'peiafolljookckjknpgofpbjobgbmpge';
-    extensionControlledIcon.extensionCanBeDisabled = true;
-    extensionControlledIcon.extensionName = 'The Bestest Name Ever';
-    document.body.appendChild(extensionControlledIcon);
-    flush();
-  });
-
-  test('disable button tracks extensionCanBeDisabled', function() {
-    assertTrue(extensionControlledIcon.extensionCanBeDisabled);
-    assertTrue(!!extensionControlledIcon.shadowRoot!.querySelector('#disable'));
-
-    extensionControlledIcon.extensionCanBeDisabled = false;
-    flush();
-    assertFalse(
-        !!extensionControlledIcon.shadowRoot!.querySelector('#disable'));
-  });
-
-  test('label icon and text', function() {
-    const imgSrc =
-        extensionControlledIcon.shadowRoot!.querySelector('img')!.src;
-    assertTrue(imgSrc.includes(extensionControlledIcon.extensionId));
-
-    const label = extensionControlledIcon.shadowRoot!.querySelector('span');
-    assertTrue(!!label);
-    assertTrue(
-        label.textContent!.includes(extensionControlledIcon.extensionName));
-  });
-
-  test('tapping manage button invokes browser proxy', async function() {
-    const button =
-        extensionControlledIcon.shadowRoot!.querySelector<HTMLElement>(
-            '#manage');
-    assertTrue(!!button);
-    button.click();
-    const url = await openWindowProxy.whenCalled('openUrl');
-    assertEquals(
-        url, `chrome://extensions/?id=${extensionControlledIcon.extensionId}`);
-  });
-
-  test('tapping disable button invokes browser proxy', async function() {
-    const button =
-        extensionControlledIcon.shadowRoot!.querySelector<HTMLElement>(
-            '#disable');
-    assertTrue(!!button);
-    button.click();
-    const extensionId = await browserProxy.whenCalled('disableExtension');
-    assertEquals(extensionId, extensionControlledIcon.extensionId);
-  });
-});
diff --git a/chrome/test/data/webui/password_manager/password_manager_browsertest.js b/chrome/test/data/webui/password_manager/password_manager_browsertest.js
index 0b5ec9a..0c8fae9 100644
--- a/chrome/test/data/webui/password_manager/password_manager_browsertest.js
+++ b/chrome/test/data/webui/password_manager/password_manager_browsertest.js
@@ -30,7 +30,6 @@
  ['Checkup', 'checkup_section_test.js'],
  ['CheckupDetails', 'checkup_details_section_test.js'],
  ['EditPassword', 'edit_password_dialog_test.js'],
- ['ExtensionControlledIcon', 'extension_controlled_icon_test.js'],
  ['MovePasswordsDialog', 'move_passwords_dialog_test.js'],
  ['PasswordCard', 'password_details_card_test.js'],
  ['PasswordDetails', 'password_details_section_test.js'],
diff --git a/chrome/test/data/webui/password_manager/settings_section_test.ts b/chrome/test/data/webui/password_manager/settings_section_test.ts
index 6283e166..e53807d 100644
--- a/chrome/test/data/webui/password_manager/settings_section_test.ts
+++ b/chrome/test/data/webui/password_manager/settings_section_test.ts
@@ -113,8 +113,8 @@
     await flushTasks();
 
     assertTrue(settings.$.passwordToggle.checked);
-    assertTrue(!!settings.$.passwordToggle.shadowRoot!.querySelector(
-        '#extensionIcon'));
+    assertTrue(
+        !!settings.shadowRoot!.querySelector('extension-controlled-indicator'));
   });
 
   test('no extension control icon by default', async function() {
@@ -126,7 +126,7 @@
     assertTrue(settings.$.passwordToggle.checked);
     settings.$.passwordToggle.click();
     assertFalse(!!settings.$.passwordToggle.shadowRoot!.querySelector(
-        '#extensionIcon'));
+        'extension-controlled-indicator'));
   });
 
   test('pref updated externally', async function() {
diff --git a/chrome/test/data/webui/password_manager/test_extension_control_browser_proxy.ts b/chrome/test/data/webui/password_manager/test_extension_control_browser_proxy.ts
deleted file mode 100644
index 54be63a3..0000000
--- a/chrome/test/data/webui/password_manager/test_extension_control_browser_proxy.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {ExtensionControlBrowserProxy} from 'chrome://password-manager/password_manager.js';
-import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
-
-export class TestExtensionControlBrowserProxy extends TestBrowserProxy
-    implements ExtensionControlBrowserProxy {
-  constructor() {
-    super([
-      'disableExtension',
-    ]);
-  }
-
-  disableExtension(extensionId: string) {
-    this.methodCalled('disableExtension', extensionId);
-  }
-}
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn
index 84e839cc..84122b0 100644
--- a/chrome/test/data/webui/settings/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -35,7 +35,6 @@
     "fake_canvas_context.js",
     "fake_cros_audio_config_test.js",
     "fake_input_method_private.js",
-    "fake_input_device_settings_provider_test.js",
     "fake_language_settings_private.js",
     "fake_media_devices.ts",
     "fake_metrics_private.ts",
@@ -63,8 +62,6 @@
     "internet_page_tests.js",
     "internet_subpage_tests.js",
     "internet_subpage_menu_test.js",
-    "kerberos_accounts_test.js",
-    "kerberos_page_test.js",
     "lock_screen_subpage_test.ts",
     "manage_users_subpage_tests.js",
     "multidevice_feature_item_tests.js",
@@ -114,7 +111,6 @@
     "test_crostini_browser_proxy.js",
     "test_cups_printers_browser_proxy.js",
     "test_device_name_browser_proxy.js",
-    "test_kerberos_accounts_browser_proxy.js",
     "test_metrics_consent_browser_proxy.ts",
     "test_os_languages_browser_proxy.js",
     "test_os_languages_metrics_proxy.js",
@@ -169,6 +165,7 @@
     "date_time_page/timezone_subpage_test.ts",
 
     "device_page/device_page_tests.js",
+    "device_page/fake_input_device_settings_provider_test.ts",
     "device_page/per_device_keyboard_remap_keys_test.ts",
     "device_page/per_device_keyboard_subsection_test.ts",
     "device_page/per_device_keyboard_test.ts",
@@ -190,6 +187,10 @@
     "internet_page/test_internet_page_browser_proxy.ts",
     "internet_page/tether_connection_dialog_test.ts",
 
+    "kerberos_page/kerberos_accounts_test.js",
+    "kerberos_page/kerberos_page_test.ts",
+    "kerberos_page/test_kerberos_accounts_browser_proxy.ts",
+
     "keyboard_shortcut_banner/keyboard_shortcut_banner_test.ts",
 
     "multidevice_page/multidevice_page_tests.js",
diff --git a/chrome/test/data/webui/settings/chromeos/cups_printer_page_tests.js b/chrome/test/data/webui/settings/chromeos/cups_printer_page_tests.js
index ffd90c5f..a61bdc7 100644
--- a/chrome/test/data/webui/settings/chromeos/cups_printer_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/cups_printer_page_tests.js
@@ -44,6 +44,54 @@
   cupsPrintersBrowserProxy.setEulaUrl(eulaUrl);
 }
 
+suite('CupsPrinterUITests', () => {
+  let page = null;
+
+  setup(() => {
+    PolymerTest.clearBody();
+    page = document.createElement('settings-cups-printers');
+    document.body.appendChild(page);
+    assertTrue(!!page);
+    flush();
+  });
+
+  teardown(() => {
+    page.remove();
+    page = null;
+  });
+
+  // Verify the Saved printers section strings.
+  test('SavedPrintersText', () => {
+    return flushTasks()
+        .then(() => {
+          page.savedPrinters_ = [createPrinterListEntry(
+              'nameA', 'printerAddress', 'idA', PrinterType.SAVED)];
+          return flushTasks();
+        })
+        .then(() => {
+          assertEquals(
+              loadTimeData.getString('savedPrintersSubtext'),
+              page.shadowRoot
+                  .querySelector('#savedPrintersContainer .secondary')
+                  .textContent.trim());
+        });
+  });
+
+  // Verify the Nearby printers section strings.
+  test('AvailablePrintersText', () => {
+    return flushTasks().then(() => {
+      assertEquals(
+          loadTimeData.getString('availablePrintersReadyTitle'),
+          page.shadowRoot.querySelector('#availablePrintersReadyTitle')
+              .textContent.trim());
+      assertEquals(
+          loadTimeData.getString('availablePrintersReadySubtext'),
+          page.shadowRoot.querySelector('#availablePrintersReadySubtext')
+              .textContent.trim());
+    });
+  });
+});
+
 suite('CupsAddPrinterDialogTests', function() {
   function fillAddManuallyDialog(addDialog) {
     const name = addDialog.shadowRoot.querySelector('#printerNameInput');
diff --git a/chrome/test/data/webui/settings/chromeos/device_page/fake_input_device_settings_provider_test.ts b/chrome/test/data/webui/settings/chromeos/device_page/fake_input_device_settings_provider_test.ts
new file mode 100644
index 0000000..7feeb45
--- /dev/null
+++ b/chrome/test/data/webui/settings/chromeos/device_page/fake_input_device_settings_provider_test.ts
@@ -0,0 +1,95 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {FakeInputDeviceSettingsProvider, fakeKeyboards, fakeMice, fakePointingSticks, fakeTouchpads} from 'chrome://os-settings/chromeos/os_settings.js';
+import {assertDeepEquals} from 'chrome://webui-test/chai_assert.js';
+
+suite('FakeInputDeviceSettings', () => {
+  let provider: FakeInputDeviceSettingsProvider;
+
+  setup(() => {
+    provider = new FakeInputDeviceSettingsProvider();
+  });
+
+  test('setFakeKeyboards', async () => {
+    provider.setFakeKeyboards(fakeKeyboards);
+    const result = await provider.getConnectedKeyboardSettings();
+    assertDeepEquals(fakeKeyboards, result);
+  });
+
+  test('setFakeTouchpads', async () => {
+    provider.setFakeTouchpads(fakeTouchpads);
+    const result = await provider.getConnectedTouchpadSettings();
+    assertDeepEquals(fakeTouchpads, result);
+  });
+
+  test('setFakeMice', async () => {
+    provider.setFakeMice(fakeMice);
+    const result = await provider.getConnectedMouseSettings();
+    assertDeepEquals(fakeMice, result);
+  });
+
+  test('setFakePointingSticks', async () => {
+    provider.setFakePointingSticks(fakePointingSticks);
+    const result = await provider.getConnectedPointingStickSettings();
+    assertDeepEquals(fakePointingSticks, result);
+  });
+
+  test('setKeyboardSettings', async () => {
+    provider.setFakeKeyboards(fakeKeyboards);
+    // Update the first keyboard settings with the second keyboard settings.
+    const updatedFirstKeyboard = {
+      ...fakeKeyboards[0],
+      settings: {...fakeKeyboards[1]!.settings},
+    };
+    provider.setKeyboardSettings(
+        updatedFirstKeyboard.id!, updatedFirstKeyboard.settings);
+    // Verify if the first keyboard settings are updated.
+    const result = await provider.getConnectedKeyboardSettings();
+    assertDeepEquals(updatedFirstKeyboard, result[0]);
+  });
+
+  test('setMouseSettings', async () => {
+    provider.setFakeMice(fakeMice);
+    // Update the first mouse settings with the second mouse settings.
+    const updatedFirstMouse = {
+      ...fakeMice[0],
+      settings: {...fakeMice[1]!.settings},
+    };
+    provider.setMouseSettings(
+        updatedFirstMouse.id!, updatedFirstMouse.settings);
+    // Verify if the first mouse settings are updated.
+    const result = await provider.getConnectedMouseSettings();
+    assertDeepEquals(updatedFirstMouse, result[0]);
+  });
+
+  test('setTouchpadSettings', async () => {
+    provider.setFakeTouchpads(fakeTouchpads);
+    // Update the first touchpad settings with the second touchpad settings.
+    const updatedFirstTouchpad = {
+      ...fakeTouchpads[0],
+      settings: {...fakeTouchpads[1]!.settings},
+    };
+    provider.setTouchpadSettings(
+        updatedFirstTouchpad.id!, updatedFirstTouchpad.settings);
+    // Verify if the first touchpad settings are updated.
+    const result = await provider.getConnectedTouchpadSettings();
+    assertDeepEquals(updatedFirstTouchpad, result[0]);
+  });
+
+  test('setPointingStickSettings', async () => {
+    provider.setFakePointingSticks(fakePointingSticks);
+    // Update the first point stick settings with the second point stick
+    // settings.
+    const updatedFirstPointingStick = {
+      ...fakePointingSticks[0],
+      settings: {...fakePointingSticks[1]!.settings},
+    };
+    provider.setPointingStickSettings(
+        updatedFirstPointingStick.id!, updatedFirstPointingStick.settings);
+    // Verify if the first point stick settings are updated.
+    const result = await provider.getConnectedPointingStickSettings();
+    assertDeepEquals(updatedFirstPointingStick, result[0]);
+  });
+});
diff --git a/chrome/test/data/webui/settings/chromeos/device_page/per_device_keyboard_remap_keys_test.ts b/chrome/test/data/webui/settings/chromeos/device_page/per_device_keyboard_remap_keys_test.ts
index eb76f3a..6d15599 100644
--- a/chrome/test/data/webui/settings/chromeos/device_page/per_device_keyboard_remap_keys_test.ts
+++ b/chrome/test/data/webui/settings/chromeos/device_page/per_device_keyboard_remap_keys_test.ts
@@ -67,6 +67,7 @@
         page.shadowRoot!.querySelector<KeyboardRemapModifierKeyRowElement>(
             '#altKey');
     assert(altKeyRow);
+    assertEquals('alt', altKeyRow.get('keyLabel'));
     const altKeyDropdown = altKeyRow.shadowRoot!.querySelector('#keyDropdown');
     assert(altKeyDropdown);
     assertEquals(
@@ -82,6 +83,7 @@
         page.shadowRoot!.querySelector<KeyboardRemapModifierKeyRowElement>(
             '#ctrlKey');
     assert(ctrlKeyRow);
+    assertEquals('ctrl', ctrlKeyRow.get('keyLabel'));
     const ctrlKeyMappedTo =
         fakeKeyboards[0]!.settings.modifierRemappings[ModifierKey.kControl]!
             .toString();
@@ -100,7 +102,7 @@
         page.shadowRoot!.querySelector<KeyboardRemapModifierKeyRowElement>(
             '#metaKey');
     assert(metaKeyRow);
-    assertEquals('Command', metaKeyRow.get('keyLabel'));
+    assertEquals('command', metaKeyRow.get('keyLabel'));
 
     // Verify that the icon is hidden.
     const commandKeyIcon = metaKeyRow.shadowRoot!.querySelector('iron-icon');
@@ -154,17 +156,30 @@
     // Verify that the remapped key icon is highlighted.
     assertEquals('modifier-remapped', altKeyRow.keyState);
 
-    // Verify that the label for meta key is displayed as the
-    // the target key in the new keyboard remapping settings.
+    // Verify that the label for meta key is empty and the key icon is
+    // displayed as launcher.
     const metaKeyRow =
         page.shadowRoot!.querySelector<KeyboardRemapModifierKeyRowElement>(
             '#metaKey');
     assert(metaKeyRow);
-    assertEquals('Launcher', metaKeyRow.get('keyLabel'));
+    assertEquals('', metaKeyRow.get('keyLabel'));
+    assertEquals('os-settings:launcher', metaKeyRow.get('keyIcon'));
 
     const launcherKeyIcon = metaKeyRow.shadowRoot!.querySelector('iron-icon');
     assert(launcherKeyIcon);
     assertEquals('os-settings:launcher', launcherKeyIcon.icon);
+
+    // Verify that the label for assistant key is displayed as icon.
+    const assistantKeyRow =
+        page.shadowRoot!.querySelector<KeyboardRemapModifierKeyRowElement>(
+            '#assistantKey');
+    assert(assistantKeyRow);
+    assertEquals('assistant', assistantKeyRow.get('keyLabel'));
+
+    const assistantKeyIcon =
+        assistantKeyRow.shadowRoot!.querySelector('iron-icon');
+    assert(assistantKeyIcon);
+    assertEquals('os-settings:assistant', assistantKeyIcon.icon);
   });
 
   /**
diff --git a/chrome/test/data/webui/settings/chromeos/fake_input_device_settings_provider_test.js b/chrome/test/data/webui/settings/chromeos/fake_input_device_settings_provider_test.js
deleted file mode 100644
index 4be9200..0000000
--- a/chrome/test/data/webui/settings/chromeos/fake_input_device_settings_provider_test.js
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {FakeInputDeviceSettingsProvider, fakeKeyboards, fakeMice, fakePointingSticks, fakeTouchpads} from 'chrome://os-settings/chromeos/os_settings.js';
-import {assertDeepEquals} from 'chrome://webui-test/chai_assert.js';
-
-suite('FakeInputDeviceSettings', function() {
-  /**
-   * @type {?FakeInputDeviceSettingsProvider}
-   */
-  let provider = null;
-
-  setup(() => {
-    provider = new FakeInputDeviceSettingsProvider();
-  });
-
-  teardown(() => {
-    provider = null;
-  });
-
-  test('setFakeKeyboards', () => {
-    provider.setFakeKeyboards(fakeKeyboards);
-    return provider.getConnectedKeyboardSettings().then(
-        result => assertDeepEquals(fakeKeyboards, result));
-  });
-
-  test('setFakeTouchpads', () => {
-    provider.setFakeTouchpads(fakeTouchpads);
-    return provider.getConnectedTouchpadSettings().then(
-        result => assertDeepEquals(fakeTouchpads, result));
-  });
-
-  test('setFakeMice', () => {
-    provider.setFakeMice(fakeMice);
-    return provider.getConnectedMouseSettings().then(
-        result => assertDeepEquals(fakeMice, result));
-  });
-
-  test('setFakePointingSticks', () => {
-    provider.setFakePointingSticks(fakePointingSticks);
-    return provider.getConnectedPointingStickSettings().then(
-        result => assertDeepEquals(fakePointingSticks, result));
-  });
-
-  test('setKeyboardSettings', () => {
-    provider.setFakeKeyboards(fakeKeyboards);
-    // Update the first keyboard settings with the second keyboard settings.
-    const updatedFirstKeyboard = {
-      ...fakeKeyboards[0],
-      settings: {...fakeKeyboards[1].settings},
-    };
-    provider.setKeyboardSettings(
-        updatedFirstKeyboard.id, updatedFirstKeyboard.settings);
-    // Verify if the first keyboard settings are updated.
-    return provider.getConnectedKeyboardSettings().then(
-        result => assertDeepEquals(updatedFirstKeyboard, result[0]));
-  });
-
-  test('setMouseSettings', () => {
-    provider.setFakeMice(fakeMice);
-    // Update the first mouse settings with the second mouse settings.
-    const updatedFirstMouse = {
-      ...fakeMice[0],
-      settings: {...fakeMice[1].settings},
-    };
-    provider.setMouseSettings(updatedFirstMouse.id, updatedFirstMouse.settings);
-    // Verify if the first mouse settings are updated.
-    return provider.getConnectedMouseSettings().then(
-        result => assertDeepEquals(updatedFirstMouse, result[0]));
-  });
-
-  test('setTouchpadSettings', () => {
-    provider.setFakeTouchpads(fakeTouchpads);
-    // Update the first touchpad settings with the second touchpad settings.
-    const updatedFirstTouchpad = {
-      ...fakeTouchpads[0],
-      settings: {...fakeTouchpads[1].settings},
-    };
-    provider.setTouchpadSettings(
-        updatedFirstTouchpad.id, updatedFirstTouchpad.settings);
-    // Verify if the first touchpad settings are updated.
-    return provider.getConnectedTouchpadSettings().then(
-        result => assertDeepEquals(updatedFirstTouchpad, result[0]));
-  });
-
-  test('setPointingStickSettings', () => {
-    provider.setFakePointingSticks(fakePointingSticks);
-    // Update the first point stick settings with the second point stick
-    // settings.
-    const updatedFirstPointingStick = {
-      ...fakePointingSticks[0],
-      settings: {...fakePointingSticks[1].settings},
-    };
-    provider.setPointingStickSettings(
-        updatedFirstPointingStick.id, updatedFirstPointingStick.settings);
-    // Verify if the first point stick settings are updated.
-    return provider.getConnectedPointingStickSettings().then(
-        result => assertDeepEquals(updatedFirstPointingStick, result[0]));
-  });
-});
\ No newline at end of file
diff --git a/chrome/test/data/webui/settings/chromeos/internet_known_networks_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/internet_known_networks_subpage_tests.js
index 985513b..5c080d48 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_known_networks_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_known_networks_subpage_tests.js
@@ -5,7 +5,6 @@
 import 'chrome://os-settings/chromeos/lazy_load.js';
 
 import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
-import {MojoConnectivityProvider} from 'chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js';
 import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
 import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
 import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
@@ -14,10 +13,7 @@
 import {NetworkType, OncSource} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {FakeNetworkConfig} from 'chrome://webui-test/chromeos/fake_network_config_mojom.js';
-import {FakePasspointService} from 'chrome://webui-test/chromeos/fake_passpoint_service_mojom.js';
 import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
-import {eventToPromise} from 'chrome://webui-test/test_util.js';
-
 
 suite('InternetKnownNetworksPage', function() {
   /** @type {?SettingsInternetKnownNetworksPageElement} */
@@ -26,9 +22,6 @@
   /** @type {?CrosNetworkConfigRemote} */
   let mojoApi_ = null;
 
-  /** @type {?PasspointServiceRemote} */
-  let passpointServiceApi_ = null;
-
   suiteSetup(function() {
     loadTimeData.overrideValues({
       internetAddConnection: 'internetAddConnection',
@@ -44,9 +37,6 @@
 
     mojoApi_ = new FakeNetworkConfig();
     MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
-    passpointServiceApi_ = new FakePasspointService();
-    MojoConnectivityProvider.getInstance().setPasspointServiceForTest(
-        passpointServiceApi_);
 
     // Disable animations so sub-pages open within one event loop.
     testing.Test.disableAnimationsAndTransitions();
@@ -63,18 +53,12 @@
     mojoApi_.addNetworksForTest(networks);
   }
 
-  function setSubscriptionForTest(subscription) {
-    passpointServiceApi_.resetForTest();
-    passpointServiceApi_.addSubscription(subscription);
-  }
-
   setup(function() {
     PolymerTest.clearBody();
     internetKnownNetworksPage =
         document.createElement('settings-internet-known-networks-subpage');
     assertTrue(!!internetKnownNetworksPage);
     mojoApi_.resetForTest();
-    passpointServiceApi_.resetForTest();
     document.body.appendChild(internetKnownNetworksPage);
     return flushAsync();
   });
@@ -185,144 +169,5 @@
           internetKnownNetworksPage.i18n(
               'knownNetworksMenuButtonTitle', 'wifi1'));
     });
-
-    test('Passpoint is disabled', async () => {
-      loadTimeData.overrideValues({isPasspointSettingsEnabled: false});
-      internetKnownNetworksPage.networkType = NetworkType.kWiFi;
-      mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
-      passpointServiceApi_.addSubscription({
-        id: 'a_passpoint_id',
-        friendlyName: 'My Passpoint provider',
-      });
-      const preferredWifi =
-          OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi2');
-      preferredWifi.priority = 1;
-      const notPreferredWifi =
-          OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi1');
-      setNetworksForTest(NetworkType.kWiFi, [
-        notPreferredWifi,
-        preferredWifi,
-      ]);
-
-      const params = new URLSearchParams();
-      params.append('settingId', '7');
-      Router.getInstance().navigateTo(routes.KNOWN_NETWORKS, params);
-
-      await flushAsync();
-
-      assertFalse(!!internetKnownNetworksPage.shadowRoot.querySelector(
-          '#passpointSubscriptionList'));
-    });
-
-    test('Passpoint is enabled without subscriptions', async () => {
-      loadTimeData.overrideValues({isPasspointSettingsEnabled: true});
-      internetKnownNetworksPage.networkType = NetworkType.kWiFi;
-      mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
-      const preferredWifi =
-          OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi2');
-      preferredWifi.priority = 1;
-      const notPreferredWifi =
-          OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi1');
-      setNetworksForTest(NetworkType.kWiFi, [
-        notPreferredWifi,
-        preferredWifi,
-      ]);
-
-      const params = new URLSearchParams();
-      params.append('settingId', '7');
-      Router.getInstance().navigateTo(routes.KNOWN_NETWORKS, params);
-
-      await flushAsync();
-
-      assertFalse(!!internetKnownNetworksPage.shadowRoot.querySelector(
-          '#passpointSubscriptionList'));
-    });
-
-    test('Passpoint is enabled with subscriptions', async () => {
-      loadTimeData.overrideValues({isPasspointSettingsEnabled: true});
-      internetKnownNetworksPage.networkType = NetworkType.kWiFi;
-      mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
-      const firstSubId = 'passpoint_id_1';
-      passpointServiceApi_.addSubscription({
-        id: firstSubId,
-        friendlyName: 'My Passpoint provider',
-      });
-      passpointServiceApi_.addSubscription({
-        id: 'passpoint_id_2',
-        friendlyName: 'My second Passpoint provider',
-      });
-      const preferredWifi =
-          OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi2');
-      preferredWifi.priority = 1;
-      const notPreferredWifi =
-          OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi1');
-      setNetworksForTest(NetworkType.kWiFi, [
-        notPreferredWifi,
-        preferredWifi,
-      ]);
-
-      const params = new URLSearchParams();
-      params.append('settingId', '7');
-      Router.getInstance().navigateTo(routes.KNOWN_NETWORKS, params);
-
-      await flushAsync();
-
-      // Check the list is visible and show two subscriptions.
-      const list = internetKnownNetworksPage.shadowRoot.querySelector(
-          '#passpointSubscriptionList');
-      assertTrue(!!list);
-      const items = list.querySelectorAll('div.list-item');
-      assertEquals(2, items.length);
-
-      // Check a click on the row sends to the details page.
-      const row = items[0].querySelector('cr-link-row');
-      assertTrue(!!row);
-      const showDetailPromise = eventToPromise('show-passpoint-detail', window);
-      row.click();
-      const showDetailEvent = await showDetailPromise;
-      assertEquals(firstSubId, showDetailEvent.detail.id);
-    });
-
-    test('Passpoint menu allows removal', async () => {
-      loadTimeData.overrideValues({isPasspointSettingsEnabled: true});
-      internetKnownNetworksPage.networkType = NetworkType.kWiFi;
-      mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
-      passpointServiceApi_.addSubscription({
-        id: 'passpoint_id',
-        friendlyName: 'My Passpoint provider',
-      });
-      const preferredWifi =
-          OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi2');
-      preferredWifi.priority = 1;
-      const notPreferredWifi =
-          OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi1');
-      setNetworksForTest(NetworkType.kWiFi, [
-        notPreferredWifi,
-        preferredWifi,
-      ]);
-
-      const params = new URLSearchParams();
-      params.append('settingId', '7');
-      Router.getInstance().navigateTo(routes.KNOWN_NETWORKS, params);
-      await flushAsync();
-
-      // Check the list is visible and show two subscriptions.
-      const list = internetKnownNetworksPage.shadowRoot.querySelector(
-          '#passpointSubscriptionList');
-      assertTrue(!!list);
-      const items = list.querySelectorAll('div.list-item');
-      assertEquals(1, items.length);
-
-      // Trigger the dots menu.
-      const menuButton = items[0].querySelector('.icon-more-vert');
-      assertTrue(!!menuButton);
-      menuButton.click();
-      await waitAfterNextRender(menuButton);
-
-      const menu = internetKnownNetworksPage.shadowRoot.querySelector(
-          '#subscriptionDotsMenu');
-      assertTrue(!!menu);
-      assertTrue(menu.open);
-    });
   });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/internet_page/internet_detail_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/internet_page/internet_detail_subpage_tests.js
index 548db97..36701dee 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_page/internet_detail_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_page/internet_detail_subpage_tests.js
@@ -5,7 +5,6 @@
 import 'chrome://os-settings/chromeos/lazy_load.js';
 
 import {InternetPageBrowserProxyImpl, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
-import {MojoConnectivityProvider} from 'chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js';
 import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
 import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
 import {getDeepActiveElement} from 'chrome://resources/ash/common/util.js';
@@ -13,7 +12,6 @@
 import {ConnectionStateType, DeviceStateType, NetworkType, OncSource, PolicySource, PortalState} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {FakeNetworkConfig} from 'chrome://webui-test/chromeos/fake_network_config_mojom.js';
-import {FakePasspointService} from 'chrome://webui-test/chromeos/fake_passpoint_service_mojom.js';
 import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
 import {eventToPromise} from 'chrome://webui-test/test_util.js';
 
@@ -26,9 +24,6 @@
   /** @type {?CrosNetworkConfigRemote} */
   let mojoApi_ = null;
 
-  /** @type {?PasspointServiceRemote} */
-  let passpointServiceApi_ = null;
-
   /** @type {?TestInternetPageBrowserProxy} */
   let browserProxy = null;
 
@@ -70,9 +65,6 @@
   suiteSetup(function() {
     mojoApi_ = new FakeNetworkConfig();
     MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
-    passpointServiceApi_ = new FakePasspointService();
-    MojoConnectivityProvider.getInstance().setPasspointServiceForTest(
-        passpointServiceApi_);
 
     // Disable animations so sub-pages open within one event loop.
     testing.Test.disableAnimationsAndTransitions();
@@ -89,11 +81,6 @@
     mojoApi_.addNetworksForTest(networks);
   }
 
-  function setSubscriptionForTest(subscription) {
-    passpointServiceApi_.resetForTest();
-    passpointServiceApi_.addSubscription(subscription);
-  }
-
   function getAllowSharedProxy() {
     const proxySection =
         internetDetailPage.shadowRoot.querySelector('network-proxy-section');
@@ -678,71 +665,6 @@
                 '#passpointRemovalDialog'));
           });
     });
-
-    [true, false].forEach(isPasspointSettingsEnabled => {
-      test('WiFi network with Passpoint shows provider row', async () => {
-        loadTimeData.overrideValues({
-          isPasspointEnabled: true,
-          isPasspointSettingsEnabled: isPasspointSettingsEnabled,
-        });
-        init();
-
-        const subId = 'a_passpoint_id';
-        setSubscriptionForTest({
-          id: subId,
-          friendlyName: 'My Passpoint provider',
-        });
-        mojoApi_.resetForTest();
-        mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
-        const wifiNetwork =
-            getManagedProperties(NetworkType.kWiFi, 'wifi_passpoint');
-        wifiNetwork.source = OncSource.kUser;
-        wifiNetwork.connectable = true;
-        wifiNetwork.typeProperties.wifi.passpointId = subId;
-        wifiNetwork.typeProperties.wifi.passpointMatchType = MatchType.kHome;
-        mojoApi_.setManagedPropertiesForTest(wifiNetwork);
-
-        internetDetailPage.init(
-            'wifi_passpoint_guid', 'WiFi', 'wifi_passpoint');
-        await flushAsync();
-
-        const row = internetDetailPage.shadowRoot.querySelector(
-            '#passpointProviderRow');
-        // The row is present only when Passpoint is enabled.
-        assertEquals(isPasspointSettingsEnabled, !!row);
-
-        if (isPasspointSettingsEnabled) {
-          const showDetailPromise =
-              eventToPromise('show-passpoint-detail', window);
-          row.click();
-          const showDetailEvent = await showDetailPromise;
-          assertEquals(subId, showDetailEvent.detail.id);
-        }
-      });
-    });
-
-    test(
-        'WiFi network without Passpoint does not show provider row',
-        async () => {
-          loadTimeData.overrideValues({
-            isPasspointEnabled: true,
-            isPasspointSettingsEnabled: true,
-          });
-          init();
-          mojoApi_.resetForTest();
-          mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
-          const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi');
-          wifiNetwork.source = OncSource.kUser;
-          wifiNetwork.connectable = true;
-          mojoApi_.setManagedPropertiesForTest(wifiNetwork);
-
-          internetDetailPage.init('wifi_guid', 'WiFi', 'wifi');
-          await flushAsync();
-
-          assertFalse(!!internetDetailPage.shadowRoot.querySelector(
-              '#passpointProviderRow'));
-        });
-
   });
 
   suite('DetailsPageVPN', function() {
diff --git a/chrome/test/data/webui/settings/chromeos/internet_page_tests.js b/chrome/test/data/webui/settings/chromeos/internet_page_tests.js
index 19f5ac4c..e6e3f93e 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_page_tests.js
@@ -8,7 +8,6 @@
 import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
 import {CellularSetupPageName} from 'chrome://resources/ash/common/cellular_setup/cellular_types.js';
 import {setESimManagerRemoteForTesting} from 'chrome://resources/ash/common/cellular_setup/mojo_interface_provider.js';
-import {MojoConnectivityProvider} from 'chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js';
 import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
 import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
 import {getDeepActiveElement} from 'chrome://resources/ash/common/util.js';
@@ -17,7 +16,6 @@
 import {ConnectionStateType, DeviceStateType, NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {FakeNetworkConfig} from 'chrome://webui-test/chromeos/fake_network_config_mojom.js';
-import {FakePasspointService} from 'chrome://webui-test/chromeos/fake_passpoint_service_mojom.js';
 import {FakeESimManagerRemote} from 'chrome://webui-test/cr_components/chromeos/cellular_setup/fake_esim_manager_remote.js';
 import {waitAfterNextRender, waitBeforeNextRender} from 'chrome://webui-test/polymer_test_util.js';
 import {eventToPromise, isVisible} from 'chrome://webui-test/test_util.js';
@@ -35,9 +33,6 @@
   /** @type {?ESimManagerRemote} */
   let eSimManagerRemote;
 
-  /** @type {PasspointServiceInterface} */
-  let passpointService_ = null;
-
   suiteSetup(function() {
     // Disable animations so sub-pages open within one event loop.
     testing.Test.disableAnimationsAndTransitions();
@@ -179,9 +174,6 @@
     MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
     eSimManagerRemote = new FakeESimManagerRemote();
     setESimManagerRemoteForTesting(eSimManagerRemote);
-    passpointService_ = new FakePasspointService();
-    MojoConnectivityProvider.getInstance().setPasspointServiceForTest(
-        passpointService_);
 
     PolymerTest.clearBody();
   });
@@ -880,21 +872,6 @@
         assertFalse(!!getApnTooltip());
         assertFalse(getApnButton().disabled);
       });
-
-  test('Nagivate to Passpoint detail page', async () => {
-    await init();
-
-    const params = new URLSearchParams();
-    params.append('id', 'a_passpoint_id');
-
-    // Navigate straight to Passpoint detail subpage.
-    Router.getInstance().navigateTo(routes.PASSPOINT_DETAIL, params);
-    internetPage.currentRouteChanged(routes.PASSPOINT_DETAIL, undefined);
-
-    const passpointDetailPage =
-        internetPage.shadowRoot.querySelector('settings-passpoint-subpage');
-    assertTrue(!!passpointDetailPage);
-  });
   // TODO(stevenjb): Figure out a way to reliably test navigation. Currently
   // such tests are flaky.
 });
diff --git a/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js b/chrome/test/data/webui/settings/chromeos/kerberos_page/kerberos_accounts_test.js
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js
rename to chrome/test/data/webui/settings/chromeos/kerberos_page/kerberos_accounts_test.js
diff --git a/chrome/test/data/webui/settings/chromeos/kerberos_page_test.js b/chrome/test/data/webui/settings/chromeos/kerberos_page/kerberos_page_test.ts
similarity index 69%
rename from chrome/test/data/webui/settings/chromeos/kerberos_page_test.js
rename to chrome/test/data/webui/settings/chromeos/kerberos_page/kerberos_page_test.ts
index c15ea7f..47ee5795 100644
--- a/chrome/test/data/webui/settings/chromeos/kerberos_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/kerberos_page/kerberos_page_test.ts
@@ -2,20 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {KerberosAccountsBrowserProxyImpl, Route, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {KerberosAccountsBrowserProxyImpl, Route, Router, routes, SettingsKerberosPageElement} from 'chrome://os-settings/chromeos/os_settings.js';
+import {assert} from 'chrome://resources/js/assert_ts.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
 import {assertEquals, assertFalse} from 'chrome://webui-test/chai_assert.js';
 
 import {TestKerberosAccountsBrowserProxy} from './test_kerberos_accounts_browser_proxy.js';
 
-suite('KerberosPageTests', function() {
-  let browserProxy = null;
+suite('<settings-kerberos-page>', () => {
+  let kerberosPage: SettingsKerberosPageElement;
+  let browserProxy: TestKerberosAccountsBrowserProxy;
 
-  /** @type {SettingsKerberosPageElement} */
-  let kerberosPage = null;
-
-  setup(function() {
+  setup(() => {
     routes.BASIC = new Route('/'),
     routes.KERBEROS = routes.BASIC.createSection('/kerberos', 'kerberos');
     routes.KERBEROS_ACCOUNTS_V2 =
@@ -25,13 +23,11 @@
 
     browserProxy = new TestKerberosAccountsBrowserProxy();
     KerberosAccountsBrowserProxyImpl.setInstanceForTesting(browserProxy);
-    PolymerTest.clearBody();
   });
 
-  teardown(function() {
+  teardown(() => {
     kerberosPage.remove();
     Router.getInstance().resetRouteForTesting();
-    KerberosAccountsBrowserProxyImpl.setInstanceForTesting(undefined);
   });
 
   test('Kerberos Section contains a link to Kerberos Accounts', () => {
@@ -40,13 +36,14 @@
     flush();
 
     // Sub-page trigger is shown.
-    const subpageTrigger = kerberosPage.shadowRoot.querySelector(
+    const subpageTrigger = kerberosPage.shadowRoot!.querySelector<HTMLElement>(
         '#kerberos-accounts-subpage-trigger');
+    assert(subpageTrigger);
     assertFalse(subpageTrigger.hidden);
 
     // Sub-page trigger navigates to Kerberos Accounts V2.
     subpageTrigger.click();
     assertEquals(
-        Router.getInstance().currentRoute, routes.KERBEROS_ACCOUNTS_V2);
+        routes.KERBEROS_ACCOUNTS_V2, Router.getInstance().currentRoute);
   });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/test_kerberos_accounts_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/kerberos_page/test_kerberos_accounts_browser_proxy.ts
similarity index 68%
rename from chrome/test/data/webui/settings/chromeos/test_kerberos_accounts_browser_proxy.js
rename to chrome/test/data/webui/settings/chromeos/kerberos_page/test_kerberos_accounts_browser_proxy.ts
index 6b9b499..0e6fc40 100644
--- a/chrome/test/data/webui/settings/chromeos/test_kerberos_accounts_browser_proxy.js
+++ b/chrome/test/data/webui/settings/chromeos/kerberos_page/test_kerberos_accounts_browser_proxy.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {KerberosConfigErrorCode, KerberosErrorType} from 'chrome://os-settings/chromeos/os_settings.js';
+import {KerberosAccount, KerberosAccountsBrowserProxy, KerberosConfigErrorCode, KerberosErrorType, ValidateKerberosConfigResult} from 'chrome://os-settings/chromeos/os_settings.js';
 import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
 
 // List of fake accounts.
@@ -39,8 +39,10 @@
   },
 ];
 
-/** @implements {KerberosAccountsBrowserProxy} */
-export class TestKerberosAccountsBrowserProxy extends TestBrowserProxy {
+export class TestKerberosAccountsBrowserProxy extends TestBrowserProxy
+    implements KerberosAccountsBrowserProxy {
+  addAccountError: KerberosErrorType;
+  validateConfigResult: ValidateKerberosConfigResult;
   constructor() {
     super([
       'getAccounts',
@@ -56,38 +58,35 @@
     // Simulated error from a validateConfig call.
     this.validateConfigResult = {
       error: KerberosErrorType.NONE,
-      errorInfo: {code: KerberosConfigErrorCode.NONE},
+      errorInfo: {code: KerberosConfigErrorCode.NONE, lineIndex: 0},
     };
   }
 
-  /** @override */
-  getAccounts() {
+  getAccounts(): Promise<KerberosAccount[]> {
     this.methodCalled('getAccounts');
     return Promise.resolve(TEST_KERBEROS_ACCOUNTS);
   }
 
-  /** @override */
-  addAccount(principalName, password, rememberPassword, config, allowExisting) {
+  addAccount(
+      principalName: string, password: string, rememberPassword: boolean,
+      config: string, allowExisting: boolean): Promise<KerberosErrorType> {
     this.methodCalled(
         'addAccount',
         [principalName, password, rememberPassword, config, allowExisting]);
     return Promise.resolve(this.addAccountError);
   }
 
-  /** @override */
-  removeAccount(account) {
+  removeAccount(account: KerberosAccount): Promise<KerberosErrorType> {
     this.methodCalled('removeAccount', account);
     return Promise.resolve(KerberosErrorType.NONE);
   }
 
-  /** @override */
-  validateConfig(account) {
-    this.methodCalled('validateConfig', account);
+  validateConfig(krb5Conf: string): Promise<ValidateKerberosConfigResult> {
+    this.methodCalled('validateConfig', krb5Conf);
     return Promise.resolve(this.validateConfigResult);
   }
 
-  /** @override */
-  setAsActiveAccount(account) {
+  setAsActiveAccount(account: KerberosAccount): void {
     this.methodCalled('setAsActiveAccount', account);
   }
 }
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
index 7b584f35..7ed2617d 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -245,11 +245,18 @@
    {enabled: ['ash::features::kPrinterSettingsRevamp']}
  ],
  ['CupsPrinterLandingPage', 'cups_printer_landing_page_tests.js'],
- ['CupsPrinterPage', 'cups_printer_page_tests.js'],
+ [
+   'CupsPrinterPage', 'cups_printer_page_tests.js',
+   {enabled: ['ash::features::kPrinterSettingsRevamp']}
+ ],
  ['DateTimePage', 'date_time_page_tests.js'],
  ['DateTimePageTimezoneSelector', 'date_time_page/timezone_selector_test.js'],
  ['DateTimePageTimezoneSubpage', 'date_time_page/timezone_subpage_test.js'],
  [
+   'DevicePageFakeInputDeviceSettingsProvider',
+   'device_page/fake_input_device_settings_provider_test.js'
+ ],
+ [
    'DevicePagePerDeviceKeyboard', 'device_page/per_device_keyboard_test.js',
    {enabled: ['ash::features::kInputDeviceSettingsSplit']}
  ],
@@ -296,7 +303,6 @@
  ['EsimRemoveProfileDialog', 'esim_remove_profile_dialog_test.js'],
  ['EsimRenameDialog', 'esim_rename_dialog_test.js'],
  ['FakeCrosAudioConfig', 'fake_cros_audio_config_test.js'],
- ['FakeInputDeviceSettings', 'fake_input_device_settings_provider_test.js'],
  ['FingerprintListSubpage', 'fingerprint_list_subpage_test.js'],
  ['GoogleAssistantSubpage', 'google_assistant_subpage_test.js'],
  ['GuestOsSharedPaths', 'guest_os_shared_paths_test.js'],
@@ -327,12 +333,8 @@
  ['InternetDetailMenu', 'internet_detail_menu_test.js'],
  ['InternetKnownNetworksSubpage', 'internet_known_networks_subpage_tests.js'],
  [
-   'InternetPage', 'internet_page_tests.js', {
-     enabled: [
-       'ash::features::kApnRevamp', 'ash::features::kPasspointSettings',
-       'ash::features::kPasspointARCSupport'
-     ]
-   }
+   'InternetPage', 'internet_page_tests.js',
+   {enabled: ['ash::features::kApnRevamp']}
  ],
  [
    'InternetPageCellularSetupDialog',
@@ -354,8 +356,8 @@
  ],
  ['InternetSubpage', 'internet_subpage_tests.js'],
  ['InternetSubpageMenu', 'internet_subpage_menu_test.js'],
- ['KerberosAccounts', 'kerberos_accounts_test.js'],
- ['KerberosPage', 'kerberos_page_test.js'],
+ ['KerberosPage', 'kerberos_page/kerberos_page_test.js'],
+ ['KerberosPageKerberosAccounts', 'kerberos_page/kerberos_accounts_test.js'],
  [
    'KeyboardShortcutBanner',
    'keyboard_shortcut_banner/keyboard_shortcut_banner_test.js'
diff --git a/chrome/test/ppapi/ppapi_test.h b/chrome/test/ppapi/ppapi_test.h
index 5f3b1ab..b9cb2ae8 100644
--- a/chrome/test/ppapi/ppapi_test.h
+++ b/chrome/test/ppapi/ppapi_test.h
@@ -192,4 +192,6 @@
                          const std::string& test_case) override;
 };
 
+class PPAPIBrokerInfoBarTest : public OutOfProcessPPAPITest {};
+
 #endif  // CHROME_TEST_PPAPI_PPAPI_TEST_H_
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn
index a8b138c3..92ae6311d 100644
--- a/chromecast/base/BUILD.gn
+++ b/chromecast/base/BUILD.gn
@@ -322,7 +322,6 @@
       "$java_src_dir/org/chromium/chromecast/base/OwnedScope.java",
       "$java_src_dir/org/chromium/chromecast/base/Scope.java",
       "$java_src_dir/org/chromium/chromecast/base/Sequencer.java",
-      "$java_src_dir/org/chromium/chromecast/base/Subscription.java",
       "$java_src_dir/org/chromium/chromecast/base/Unit.java",
 
       # TODO(sanfin): Move these files to another target.
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/Cell.java b/chromecast/base/java/src/org/chromium/chromecast/base/Cell.java
index c3c31ba0..37e1ce29 100644
--- a/chromecast/base/java/src/org/chromium/chromecast/base/Cell.java
+++ b/chromecast/base/java/src/org/chromium/chromecast/base/Cell.java
@@ -20,7 +20,7 @@
  *
  * @param <T> The type of the activation data.
  */
-public class Cell<T> extends Observable<T> {
+public class Cell<T> implements Observable<T> {
     private final Sequencer mSequencer = new Sequencer();
     private final List<Observer<? super T>> mObservers = new ArrayList<>();
     private final Map<Observer<? super T>, Scope> mScopeMap = new HashMap<>();
@@ -32,7 +32,7 @@
     }
 
     @Override
-    public Subscription subscribe(Observer<? super T> observer) {
+    public Scope subscribe(Observer<? super T> observer) {
         mSequencer.sequence(() -> {
             mObservers.add(observer);
             notifyEnter(observer);
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/Controller.java b/chromecast/base/java/src/org/chromium/chromecast/base/Controller.java
index 9fbed2c..5ff1150e 100644
--- a/chromecast/base/java/src/org/chromium/chromecast/base/Controller.java
+++ b/chromecast/base/java/src/org/chromium/chromecast/base/Controller.java
@@ -19,14 +19,14 @@
  *
  * @param <T> The type of the activation data.
  */
-public class Controller<T> extends Observable<T> {
+public class Controller<T> implements Observable<T> {
     private final Sequencer mSequencer = new Sequencer();
     private final List<Observer<? super T>> mObservers = new ArrayList<>();
     private final Map<Observer<? super T>, Scope> mScopeMap = new HashMap<>();
     private T mData;
 
     @Override
-    public Subscription subscribe(Observer<? super T> observer) {
+    public Scope subscribe(Observer<? super T> observer) {
         mSequencer.sequence(() -> {
             mObservers.add(observer);
             if (mData != null) notifyEnter(observer);
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/Observable.java b/chromecast/base/java/src/org/chromium/chromecast/base/Observable.java
index ec6de127..98c55e67 100644
--- a/chromecast/base/java/src/org/chromium/chromecast/base/Observable.java
+++ b/chromecast/base/java/src/org/chromium/chromecast/base/Observable.java
@@ -19,17 +19,18 @@
  *
  * @param <T> The type of the activation data.
  */
-public abstract class Observable<T> {
+@FunctionalInterface
+public interface Observable<T> {
     /**
      * Tracks this Observable with the given observer.
      *
      * When this Observable is activated, the observer will be opened with the activation data to
      * produce a scope. When this Observable is deactivated, that scope will be closed.
      *
-     * When the returned Subscription is closed, the observer's scopes will be closed and the
-     * observer will no longer be notified of updates.
+     * When the returned Scope (referred to as a "subscription") is closed, the observer's scopes
+     * will be closed and the observer will no longer be notified of updates.
      */
-    public abstract Subscription subscribe(Observer<? super T> observer);
+    Scope subscribe(Observer<? super T> observer);
 
     /**
      * Creates an Observable that opens observers's scopes only if both `this` and `other` are
@@ -38,7 +39,7 @@
      * This is useful for creating an event handler that should only activate when two events
      * have occurred, but those events may occur in any order.
      */
-    public final <U> Observable<Both<T, U>> and(Observable<U> other) {
+    default <U> Observable<Both<T, U>> and(Observable<U> other) {
         return flatMap(t -> other.flatMap(u -> just(Both.both(t, u))));
     }
 
@@ -53,8 +54,8 @@
      *   x.or(empty()) == x
      *   empty().or(x) == x
      */
-    public final Observable<T> or(Observable<T> other) {
-        return make(observer -> subscribe(observer).and(other.subscribe(observer)));
+    default Observable<T> or(Observable<T> other) {
+        return observer -> subscribe(observer).and(other.subscribe(observer));
     }
 
     /**
@@ -64,13 +65,13 @@
      * subscribed. This operator filters these out and only notifies the observer of changes that
      * occur after the moment of subscription.
      */
-    public final Observable<T> after() {
-        return make(observer -> {
+    default Observable<T> after() {
+        return observer -> {
             Box<Boolean> after = new Box<Boolean>(false);
-            Subscription sub = subscribe(t -> after.value ? observer.open(t) : Scope.NO_OP);
+            Scope sub = subscribe(t -> after.value ? observer.open(t) : Scope.NO_OP);
             after.value = true;
             return sub;
-        });
+        };
     }
 
     /**
@@ -78,14 +79,14 @@
      *
      * This is similar to `and()`, but does not activate if `other` is activated before `this`.
      */
-    public final <U> Observable<Both<T, U>> andThen(Observable<U> other) {
+    default <U> Observable<Both<T, U>> andThen(Observable<U> other) {
         return and(other.after());
     }
 
     /**
      * Returns an Observable that applies the given Function to this Observable's activation values.
      */
-    public final <R> Observable<R> map(Function<? super T, ? extends R> f) {
+    default <R> Observable<R> map(Function<? super T, ? extends R> f) {
         return flatMap(t -> just(f.apply(t)));
     }
 
@@ -109,23 +110,23 @@
      *
      *   getFooAsync().flatMap(foo -> getBarAsync(foo)).subscribe(bar -> useBar(bar));
      */
-    public final <R> Observable<R> flatMap(
+    default <R> Observable<R> flatMap(
             Function<? super T, ? extends Observable<? extends R>> f) {
-        return make(observer -> subscribe(t -> f.apply(t).subscribe(r -> observer.open(r))));
+        return observer -> subscribe(t -> f.apply(t).subscribe(r -> observer.open(r)));
     }
 
     /**
      * Returns an Observable that is only activated when `this` is activated with a value such that
      * the given `predicate` returns true.
      */
-    public final Observable<T> filter(Predicate<? super T> predicate) {
+    default Observable<T> filter(Predicate<? super T> predicate) {
         return flatMap(t -> predicate.test(t) ? just(t) : empty());
     }
 
     /**
      * Returns an Observable with its type mapped to Unit.
      */
-    public final Observable<Unit> opaque() {
+    default Observable<Unit> opaque() {
         return map(x -> Unit.unit());
     }
 
@@ -157,15 +158,12 @@
      *       return Scope.NO_OP;
      *   });
      */
-    // NOTE: This is private for now to limit how many things use it until it has better test
-    // coverage, but it can be used by other operators.
-    final <U, A extends Observable<U>> Observable<U> accumulate(
+    default <U, A extends Observable<U>> Observable<U> accumulate(
             Supplier<A> factory, BiFunction<A, T, ? extends Scope> acc) {
-        return make(observer -> {
+        return observer -> {
             A current = factory.get();
-            Subscription sub = subscribe(t -> acc.apply(current, t));
-            return sub.and(current.subscribe(observer));
-        });
+            return subscribe(t -> acc.apply(current, t)).and(current.subscribe(observer));
+        };
     }
 
     /**
@@ -178,7 +176,7 @@
      * Observable emits `true`, `true`, `false`, `true`, in that order, the distinctUntilChanged()
      * Observable will emit `true`, `false`, `true` (dropping the redundant `true`).
      */
-    public final Observable<T> distinctUntilChanged() {
+    default Observable<T> distinctUntilChanged() {
         return accumulate(Controller::new, (c, t) -> {
             c.set(t);
             return Scope.NO_OP;
@@ -203,7 +201,7 @@
      * previous activations, or keep track of ordering in a way that can't be done with pure monadic
      * operations.
      */
-    public final <A> Observable<A> fold(A start, BiFunction<A, T, A> acc, BiFunction<A, T, A> dim) {
+    default <A> Observable<A> fold(A start, BiFunction<A, T, A> acc, BiFunction<A, T, A> dim) {
         return accumulate(() -> new Cell<A>(start), (current, t) -> {
             current.mutate(a -> acc.apply(a, t));
             return () -> current.mutate(a -> dim.apply(a, t));
@@ -214,35 +212,22 @@
      * Returns an Observable that contains the number of activations in |this|, which updates
      * dynamically as |this| updates.
      */
-    public final Observable<Integer> count() {
+    default Observable<Integer> count() {
         return fold(0, (n, x) -> n + 1, (n, x) -> n - 1);
     }
 
     /**
      * Returns an Observable that is activated only when the given Observable is not activated.
      */
-    public static Observable<?> not(Observable<?> observable) {
+    static Observable<?> not(Observable<?> observable) {
         return observable.count().filter(n -> n == 0);
     }
 
     /**
-     * Allows creating an Observable with a functional interface.
-     */
-    public static <T> Observable<T> make(
-            Function<? super Observer<? super T>, ? extends Scope> impl) {
-        return new Observable<T>() {
-            @Override
-            public Subscription subscribe(Observer<? super T> observer) {
-                return impl.apply(observer)::close;
-            }
-        };
-    }
-
-    /**
      * A degenerate Observable that has no data.
      */
-    public static <T> Observable<T> empty() {
-        return make(observer -> Scope.NO_OP);
+    static <T> Observable<T> empty() {
+        return observer -> Scope.NO_OP;
     }
 
     /**
@@ -250,9 +235,9 @@
      *
      * This is the "return" operation in the Observable monad.
      */
-    public static <T> Observable<T> just(T value) {
+    static <T> Observable<T> just(T value) {
         if (value == null) return empty();
-        return make(observer -> observer.open(value));
+        return observer -> observer.open(value);
     }
 
     /**
@@ -266,8 +251,8 @@
      * control the logging level, or use alternative loggers, and 2) when using chromium's logger,
      * see the right file name and line number in the logs.
      */
-    public Observable<T> debug(Consumer<String> logger) {
-        return make(observer -> {
+    default Observable<T> debug(Consumer<String> logger) {
+        return observer -> {
             logger.accept("subscribe");
             Scope subscription = subscribe(data -> {
                 logger.accept(new StringBuilder("open ").append(data).toString());
@@ -278,7 +263,7 @@
             });
             Scope debugUnsubscribe = () -> logger.accept("unsubscribe");
             return subscription.and(debugUnsubscribe);
-        });
+        };
     }
 
     /**
@@ -286,7 +271,7 @@
      * after a certain amount of time has elapsed, preferably on the same thread that posted the
      * Runnable.
      */
-    public interface Scheduler {
+    interface Scheduler {
         void postDelayed(Runnable runnable, long delay);
     }
 
@@ -304,12 +289,12 @@
      * preferably on the same thread that invoked its postDelayed() method, unless the observers of
      * this Observable are thread-safe.
      */
-    public static Observable<?> alarm(Scheduler scheduler, long ms) {
-        return make(observer -> {
+    static Observable<?> alarm(Scheduler scheduler, long ms) {
+        return observer -> {
             Controller<Unit> activation = new Controller<>();
             scheduler.postDelayed(() -> activation.set(Unit.unit()), ms);
             return activation.subscribe(observer);
-        });
+        };
     }
 
     /**
@@ -322,7 +307,7 @@
      * preferably on the same thread that invoked its postDelayed() method, unless the observers of
      * this Observable are thread-safe.
      */
-    public final Observable<T> delay(Scheduler scheduler, long ms) {
+    default Observable<T> delay(Scheduler scheduler, long ms) {
         return flatMap(t -> alarm(scheduler, ms).map(x -> t));
     }
 }
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/OwnedScope.java b/chromecast/base/java/src/org/chromium/chromecast/base/OwnedScope.java
index 200a60c..edc6bd0 100644
--- a/chromecast/base/java/src/org/chromium/chromecast/base/OwnedScope.java
+++ b/chromecast/base/java/src/org/chromium/chromecast/base/OwnedScope.java
@@ -19,7 +19,7 @@
  *
  *   // A static method on a Service implementation like this can provide an easy connection API.
  *   public static Observable<IFoo> connect(Context context) {
- *       return Observable.make(observer -> {
+ *       return observer -> {
  *           // Use an OwnedScope to avoid a null check in onServiceDisconnected().
  *           OwnedScope subscription = new OwnedScope();
  *           ServiceConnection connection = new ServiceConnection() {
@@ -37,7 +37,7 @@
  *           };
  *           context.bindService(new Intent(context, FooService.class), connection);
  *           return subscription.and(() -> context.unbindService(connection));
- *       });
+ *       };
  *   }
  *
  * An OwnedScope can also be useful for cleanup in clients for such APIs:
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/Subscription.java b/chromecast/base/java/src/org/chromium/chromecast/base/Subscription.java
deleted file mode 100644
index dd8ce5b..0000000
--- a/chromecast/base/java/src/org/chromium/chromecast/base/Subscription.java
+++ /dev/null
@@ -1,17 +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.
-
-package org.chromium.chromecast.base;
-
-/**
- * When closed, unsubscribe an Observer from an Observable.
- *
- * This is returned from Observable#subscribe() when subscribing an Observer to an Observable. When
- * The close() method is called on a Subscription, all open Scopes from the Observer will be closed
- * and the Observer will not be opened again.
- *
- * This is an alias for Scope, but is easier to understand in terms of its role when referred to as
- * a "Subscription".
- */
-public interface Subscription extends Scope {}
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableAndTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableAndTest.java
index ad5cd39..871f8a80 100644
--- a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableAndTest.java
+++ b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableAndTest.java
@@ -126,14 +126,11 @@
 
     @Test
     public void testAndCartesianProduct() {
-        ReactiveRecorder r = ReactiveRecorder.record(
-                Observable
-                        .make(observer
-                                -> observer.open(1).and(observer.open(2)).and(observer.open(3)))
-                        .and(Observable.make(observer
-                                -> observer.open("a")
-                                           .and(observer.open("b"))
-                                           .and(observer.open("c")))));
+        Observable<Integer> numbers =
+                observer -> observer.open(1).and(observer.open(2)).and(observer.open(3));
+        Observable<String> letters =
+                observer -> observer.open("a").and(observer.open("b")).and(observer.open("c"));
+        ReactiveRecorder r = ReactiveRecorder.record(numbers.and(letters));
         r.verify()
                 .opened(Both.both(1, "a"))
                 .opened(Both.both(1, "b"))
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableDebugTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableDebugTest.java
index cd866e4e..a7c7d5a 100644
--- a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableDebugTest.java
+++ b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableDebugTest.java
@@ -23,10 +23,10 @@
 @Batch(Batch.UNIT_TESTS)
 public class ObservableDebugTest {
     @Test
-    public void testDebugSubscription() {
+    public void testDebugScope() {
         Controller<Unit> a = new Controller<>();
         List<String> events = new ArrayList<>();
-        Subscription sub = a.debug(events::add).subscribe(x -> () -> {});
+        Scope sub = a.debug(events::add).subscribe(x -> () -> {});
         assertThat(events, contains("subscribe"));
         events.clear();
         sub.close();
@@ -37,7 +37,7 @@
     public void testDebugUnitActivations() {
         Controller<Unit> a = new Controller<>();
         List<String> events = new ArrayList<>();
-        Subscription sub = a.debug(events::add).subscribe(x -> () -> {});
+        Scope sub = a.debug(events::add).subscribe(x -> () -> {});
         events.clear();
         a.set(Unit.unit());
         assertThat(events, contains("open ()"));
@@ -53,7 +53,7 @@
         // first.
         Controller<Unit> a = new Controller<>();
         List<String> events = new ArrayList<>();
-        Subscription sub = a.debug(events::add).subscribe(x -> () -> {});
+        Scope sub = a.debug(events::add).subscribe(x -> () -> {});
         a.set(Unit.unit());
         events.clear();
         sub.close();
@@ -64,7 +64,7 @@
     public void testDebugString() {
         Controller<String> a = new Controller<>();
         List<String> events = new ArrayList<>();
-        Subscription sub = a.debug(events::add).subscribe(x -> () -> {});
+        Scope sub = a.debug(events::add).subscribe(x -> () -> {});
         events.clear();
         a.set("a");
         assertThat(events, contains("open a"));
@@ -78,10 +78,10 @@
 
     @Test
     public void testDebugMultipleIntegers() {
-        Observable<Integer> a = Observable.make(
-                observer -> observer.open(1).and(observer.open(2)).and(observer.open(3))::close);
+        Observable<Integer> a =
+                observer -> observer.open(1).and(observer.open(2)).and(observer.open(3));
         List<String> events = new ArrayList<>();
-        Subscription sub = a.debug(events::add).subscribe(x -> () -> {});
+        Scope sub = a.debug(events::add).subscribe(x -> () -> {});
         assertThat(events, contains("subscribe", "open 1", "open 2", "open 3"));
         events.clear();
         sub.close();
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableDelayTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableDelayTest.java
index d50b8ff..5a5afc0 100644
--- a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableDelayTest.java
+++ b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableDelayTest.java
@@ -124,8 +124,8 @@
     @Test
     public void testDelayHigherCardinalityObservable() {
         FakeScheduler scheduler = new FakeScheduler();
-        Observable<Integer> src = Observable.make(
-                observer -> observer.open(10).and(observer.open(20)).and(observer.open(30)));
+        Observable<Integer> src =
+                observer -> observer.open(10).and(observer.open(20)).and(observer.open(30));
         ReactiveRecorder recorder = ReactiveRecorder.record(src.delay(scheduler, 100));
         recorder.verify().end();
         scheduler.fastForwardBy(100);
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableFoldTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableFoldTest.java
index ae17a5ea1..1127b0c 100644
--- a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableFoldTest.java
+++ b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableFoldTest.java
@@ -66,8 +66,8 @@
 
     @Test
     public void multipleIntegers() {
-        ReactiveRecorder r = ReactiveRecorder.record(sum(Observable.make(
-                observer -> observer.open(1).and(observer.open(2)).and(observer.open(3)))));
+        ReactiveRecorder r = ReactiveRecorder.record(sum(
+                observer -> observer.open(1).and(observer.open(2)).and(observer.open(3))));
         r.verify().opened(6).end();
         r.unsubscribe();
         r.verify().closed(6).end();
@@ -75,8 +75,8 @@
 
     @Test
     public void multipleStrings() {
-        ReactiveRecorder r = ReactiveRecorder.record(transitionString(Observable.make(
-                observer -> observer.open("a").and(observer.open("b")).and(observer.open("c")))));
+        ReactiveRecorder r = ReactiveRecorder.record(transitionString(
+                observer -> observer.open("a").and(observer.open("b")).and(observer.open("c"))));
         r.verify().opened("+a+b+c").end();
         r.unsubscribe();
         r.verify().closed("+a+b+c").end();
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableMiscellaneousTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableMiscellaneousTest.java
index 5727e39f..e7f6cc9 100644
--- a/chromecast/base/java/test/org/chromium/chromecast/base/ObservableMiscellaneousTest.java
+++ b/chromecast/base/java/test/org/chromium/chromecast/base/ObservableMiscellaneousTest.java
@@ -28,19 +28,19 @@
 public class ObservableMiscellaneousTest {
     @Test
     public void testMakeNotifyOneAtATime() {
-        ReactiveRecorder r = ReactiveRecorder.record(Observable.make(observer -> {
+        ReactiveRecorder r = ReactiveRecorder.record(observer -> {
             observer.open(1).close();
             observer.open(2).close();
             observer.open(3).close();
             return Scope.NO_OP;
-        }));
+        });
         r.verify().opened(1).closed(1).opened(2).closed(2).opened(3).closed(3).end();
     }
 
     @Test
     public void testMakeNotifyAllAtOnce() {
-        ReactiveRecorder r = ReactiveRecorder.record(Observable.make(
-                observer -> observer.open("a").and(observer.open("b")).and(observer.open("c"))));
+        ReactiveRecorder r = ReactiveRecorder.record(
+                observer -> observer.open("a").and(observer.open("b")).and(observer.open("c")));
         r.verify().opened("a").opened("b").opened("c").end();
         r.unsubscribe();
         r.verify().closed("c").closed("b").closed("a").end();
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/ObserverTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/ObserverTest.java
index be9165a3..ba2c18b4 100644
--- a/chromecast/base/java/test/org/chromium/chromecast/base/ObserverTest.java
+++ b/chromecast/base/java/test/org/chromium/chromecast/base/ObserverTest.java
@@ -120,7 +120,7 @@
         Cell<Integer> ints = new Cell<>(0);
         Cell<String> strings = new Cell<>("a");
         List<String> result = new ArrayList<>();
-        Subscription sub = ints.and(strings).subscribe(Observer.both((Integer i, String s) -> {
+        Scope sub = ints.and(strings).subscribe(Observer.both((Integer i, String s) -> {
             result.add("opened " + i + " " + s);
             return () -> result.add("closed " + i + " " + s);
         }));
diff --git a/chromeos/ash/components/dbus/resourced/fake_resourced_client.h b/chromeos/ash/components/dbus/resourced/fake_resourced_client.h
index 1a9bf49..f5b38ff 100644
--- a/chromeos/ash/components/dbus/resourced/fake_resourced_client.h
+++ b/chromeos/ash/components/dbus/resourced/fake_resourced_client.h
@@ -46,6 +46,9 @@
 
   int get_exit_game_mode_count() const { return exit_game_mode_count_; }
 
+  uint32_t get_critical_margin_bps() const { return critical_margin_bps_; }
+  uint32_t get_moderate_margin_bps() const { return moderate_margin_bps_; }
+
   void AddObserver(Observer* observer) override;
 
   void RemoveObserver(Observer* observer) override;
diff --git a/chromeos/ash/components/dbus/resourced/resourced_client.cc b/chromeos/ash/components/dbus/resourced/resourced_client.cc
index 3cfc5182..11547d7 100644
--- a/chromeos/ash/components/dbus/resourced/resourced_client.cc
+++ b/chromeos/ash/components/dbus/resourced/resourced_client.cc
@@ -322,8 +322,8 @@
 }
 
 // static
-void ResourcedClient::InitializeFake() {
-  new FakeResourcedClient();
+FakeResourcedClient* ResourcedClient::InitializeFake() {
+  return new FakeResourcedClient();
 }
 
 // static
diff --git a/chromeos/ash/components/dbus/resourced/resourced_client.h b/chromeos/ash/components/dbus/resourced/resourced_client.h
index 14650da..a46a709 100644
--- a/chromeos/ash/components/dbus/resourced/resourced_client.h
+++ b/chromeos/ash/components/dbus/resourced/resourced_client.h
@@ -17,6 +17,8 @@
 
 namespace ash {
 
+class FakeResourcedClient;
+
 // ResourcedClient is used to communicate with the org.chromium.ResourceManager
 // service. The browser uses the ResourceManager service to get resource usage
 // status.
@@ -78,7 +80,8 @@
   static void Initialize(dbus::Bus* bus);
 
   // Creates and initializes a fake global instance if not already created.
-  static void InitializeFake();
+  // The newly created object will persist until Shutdown() is called.
+  static FakeResourcedClient* InitializeFake();
 
   // Destroys the global instance.
   static void Shutdown();
diff --git a/chromeos/ash/components/memory/BUILD.gn b/chromeos/ash/components/memory/BUILD.gn
index 37281a1..2533ae9f0 100644
--- a/chromeos/ash/components/memory/BUILD.gn
+++ b/chromeos/ash/components/memory/BUILD.gn
@@ -48,6 +48,7 @@
     ":memory",
     "//base/test:test_support",
     "//build:chromeos_buildflags",
+    "//chromeos/ash/components/dbus/resourced",
     "//components/memory_pressure",
     "//mojo/core/embedder",
     "//services/resource_coordinator/public/cpp/memory_instrumentation",
@@ -58,6 +59,7 @@
     "memory_unittest.cc",
     "pagemap_unittest.cc",
     "pressure/system_memory_pressure_evaluator_unittest.cc",
+    "swap_configuration_unittest.cc",
     "zram_writeback_controller_unittest.cc",
   ]
 }
diff --git a/chromeos/ash/components/memory/memory.cc b/chromeos/ash/components/memory/memory.cc
index 7ed63ea..f962b65d 100644
--- a/chromeos/ash/components/memory/memory.cc
+++ b/chromeos/ash/components/memory/memory.cc
@@ -21,8 +21,8 @@
 
 namespace ash {
 
-COMPONENT_EXPORT(ASH_MEMORY) void UpdateMemoryParameters() {
-  ConfigureSwap();
+COMPONENT_EXPORT(ASH_MEMORY) void UpdateMemoryParameters(bool arc_enabled) {
+  ConfigureSwap(arc_enabled);
 }
 
 namespace memory {
diff --git a/chromeos/ash/components/memory/memory.h b/chromeos/ash/components/memory/memory.h
index 92f77d062c..ac5af70 100644
--- a/chromeos/ash/components/memory/memory.h
+++ b/chromeos/ash/components/memory/memory.h
@@ -19,7 +19,7 @@
 namespace ash {
 
 // It should be called when some memory configuration is changed.
-COMPONENT_EXPORT(ASH_MEMORY) void UpdateMemoryParameters();
+COMPONENT_EXPORT(ASH_MEMORY) void UpdateMemoryParameters(bool arc_enabled);
 
 namespace memory {
 
diff --git a/chromeos/ash/components/memory/swap_configuration.cc b/chromeos/ash/components/memory/swap_configuration.cc
index a98659b3..b9e4ae4 100644
--- a/chromeos/ash/components/memory/swap_configuration.cc
+++ b/chromeos/ash/components/memory/swap_configuration.cc
@@ -34,17 +34,29 @@
 const base::FeatureParam<int> kCrOSExtraFreeMb{&kCrOSTuneExtraFree,
                                                "CrOSExtraFreeMb", -1};
 
-BASE_FEATURE(kCrOSMemoryPressureSignalStudy,
-             "ChromeOSMemoryPressureSignalStudy",
+// There are going to be 2 separate experiments for memory pressure signal, one
+// for ARC enabled users and one for ARC disabled users.
+BASE_FEATURE(kCrOSMemoryPressureSignalStudyNonArc,
+             "ChromeOSMemoryPressureSignalStudyNonArc",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-const base::FeatureParam<int>
-    kCrOSMemoryPressureSignalStudyCriticalThresholdPrecentageBps{
-        &kCrOSMemoryPressureSignalStudy, "critical_threshold_percentage", 520};
+const base::FeatureParam<int> kCrOSMemoryPressureSignalStudyNonArcCriticalBps{
+    &kCrOSMemoryPressureSignalStudyNonArc, "critical_threshold_percentage",
+    520};
 
-const base::FeatureParam<int>
-    kCrOSMemoryPressureSignalStudyModerateThresholdPrecentageBps{
-        &kCrOSMemoryPressureSignalStudy, "moderate_threshold_percentage", 4000};
+const base::FeatureParam<int> kCrOSMemoryPressureSignalStudyNonArcModerateBps{
+    &kCrOSMemoryPressureSignalStudyNonArc, "moderate_threshold_percentage",
+    4000};
+
+BASE_FEATURE(kCrOSMemoryPressureSignalStudyArc,
+             "ChromeOSMemoryPressureSignalStudyArc",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+const base::FeatureParam<int> kCrOSMemoryPressureSignalStudyArcCriticalBps{
+    &kCrOSMemoryPressureSignalStudyArc, "critical_threshold_percentage", 520};
+
+const base::FeatureParam<int> kCrOSMemoryPressureSignalStudyArcModerateBps{
+    &kCrOSMemoryPressureSignalStudyArc, "moderate_threshold_percentage", 4000};
 
 BASE_FEATURE(kCrOSEnableZramWriteback,
              "ChromeOSZramWriteback",
@@ -178,19 +190,33 @@
                << "KB and " << moderate << "KB";
 }
 
-void ConfigureResourcedPressureThreshold() {
+void ConfigureResourcedPressureThreshold(bool arc_enabled) {
   if (!ResourcedClient::Get()) {
     return;
   }
 
-  if (base::FeatureList::IsEnabled(kCrOSMemoryPressureSignalStudy)) {
+  bool experiment_enabled = false;
+  int critical_bps = 0;
+  int moderate_bps = 0;
+  if (arc_enabled) {
+    experiment_enabled =
+        base::FeatureList::IsEnabled(kCrOSMemoryPressureSignalStudyArc);
+    if (experiment_enabled) {
+      critical_bps = kCrOSMemoryPressureSignalStudyArcCriticalBps.Get();
+      moderate_bps = kCrOSMemoryPressureSignalStudyArcModerateBps.Get();
+    }
+  } else {
+    experiment_enabled =
+        base::FeatureList::IsEnabled(kCrOSMemoryPressureSignalStudyNonArc);
+    if (experiment_enabled) {
+      critical_bps = kCrOSMemoryPressureSignalStudyNonArcCriticalBps.Get();
+      moderate_bps = kCrOSMemoryPressureSignalStudyNonArcModerateBps.Get();
+    }
+  }
+
+  if (experiment_enabled) {
     // We need to send a debus message to resourced with the critical threshold
     // value (in bps).
-    int critical_bps =
-        kCrOSMemoryPressureSignalStudyCriticalThresholdPrecentageBps.Get();
-    int moderate_bps =
-        kCrOSMemoryPressureSignalStudyModerateThresholdPrecentageBps.Get();
-
     if (critical_bps < 520 || critical_bps > 2500 || moderate_bps > 7500 ||
         moderate_bps < 2000 || critical_bps >= moderate_bps) {
       // To avoid a potentially catastrophic misconfiguration we
@@ -211,8 +237,8 @@
 
 }  // namespace
 
-void ConfigureSwap() {
-  ConfigureResourcedPressureThreshold();
+void ConfigureSwap(bool arc_enabled) {
+  ConfigureResourcedPressureThreshold(arc_enabled);
   ConfigureExtraFreeIfEnabled();
   ConfigureRamVsSwapWeightIfEnabled();
   ConfigureMinFilelistIfEnabled();
diff --git a/chromeos/ash/components/memory/swap_configuration.h b/chromeos/ash/components/memory/swap_configuration.h
index 469d023..6dccbc4 100644
--- a/chromeos/ash/components/memory/swap_configuration.h
+++ b/chromeos/ash/components/memory/swap_configuration.h
@@ -29,6 +29,31 @@
 BASE_DECLARE_FEATURE(kCrOSTuneExtraFree);
 extern const base::FeatureParam<int> kCrOSExtraFreeMb;
 
+// Controls the threshold at which memory pressure signals are sent for
+// arc-disabled devices.
+COMPONENT_EXPORT(ASH_MEMORY)
+BASE_DECLARE_FEATURE(kCrOSMemoryPressureSignalStudyNonArc);
+
+COMPONENT_EXPORT(ASH_MEMORY)
+extern const base::FeatureParam<int>
+    kCrOSMemoryPressureSignalStudyNonArcCriticalBps;
+
+COMPONENT_EXPORT(ASH_MEMORY)
+extern const base::FeatureParam<int>
+    kCrOSMemoryPressureSignalStudyNonArcModerateBps;
+
+// Similar to above but for arc-enabled devices.
+COMPONENT_EXPORT(ASH_MEMORY)
+BASE_DECLARE_FEATURE(kCrOSMemoryPressureSignalStudyArc);
+
+COMPONENT_EXPORT(ASH_MEMORY)
+extern const base::FeatureParam<int>
+    kCrOSMemoryPressureSignalStudyArcCriticalBps;
+
+COMPONENT_EXPORT(ASH_MEMORY)
+extern const base::FeatureParam<int>
+    kCrOSMemoryPressureSignalStudyArcModerateBps;
+
 // This feature and params control the zram writeback behavior.
 COMPONENT_EXPORT(ASH_MEMORY) BASE_DECLARE_FEATURE(kCrOSEnableZramWriteback);
 
@@ -89,7 +114,7 @@
 
 // Configure swap will configure any swap related experiments that this user may
 // be opted into.
-COMPONENT_EXPORT(ASH_MEMORY) void ConfigureSwap();
+COMPONENT_EXPORT(ASH_MEMORY) void ConfigureSwap(bool arc_enabled);
 
 }  // namespace ash
 
diff --git a/chromeos/ash/components/memory/swap_configuration_unittest.cc b/chromeos/ash/components/memory/swap_configuration_unittest.cc
new file mode 100644
index 0000000..8cb724f9
--- /dev/null
+++ b/chromeos/ash/components/memory/swap_configuration_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/memory/swap_configuration.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "chromeos/ash/components/dbus/resourced/fake_resourced_client.h"
+#include "chromeos/ash/components/dbus/resourced/resourced_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+namespace memory {
+
+namespace {
+class SwapConfigurationPressureThreshold : public testing::Test {
+ public:
+  void SetUp() override {
+    resourced_client_ = ResourcedClient::InitializeFake();
+  }
+
+  void TearDown() override { ResourcedClient::Shutdown(); }
+
+ protected:
+  base::test::TaskEnvironment task_environment_;
+  base::test::ScopedFeatureList feature_list_;
+  FakeResourcedClient* resourced_client_ = nullptr;
+};
+
+}  // namespace
+
+TEST_F(SwapConfigurationPressureThreshold, NoArcDefault) {
+  feature_list_.InitAndEnableFeature(kCrOSMemoryPressureSignalStudyNonArc);
+  ConfigureSwap(/*arc_enabled=*/false);
+
+  EXPECT_EQ(resourced_client_->get_critical_margin_bps(), 520u);
+  EXPECT_EQ(resourced_client_->get_moderate_margin_bps(), 4000u);
+}
+
+TEST_F(SwapConfigurationPressureThreshold, NoArcCustom) {
+  feature_list_.InitAndEnableFeatureWithParameters(
+      kCrOSMemoryPressureSignalStudyNonArc,
+      {{kCrOSMemoryPressureSignalStudyNonArcCriticalBps.name, "1500"},
+       {kCrOSMemoryPressureSignalStudyNonArcModerateBps.name, "6000"}});
+  ConfigureSwap(/*arc_enabled=*/false);
+
+  EXPECT_EQ(resourced_client_->get_critical_margin_bps(), 1500u);
+  EXPECT_EQ(resourced_client_->get_moderate_margin_bps(), 6000u);
+}
+
+TEST_F(SwapConfigurationPressureThreshold, ArcDefault) {
+  feature_list_.InitAndEnableFeature(kCrOSMemoryPressureSignalStudyArc);
+  ConfigureSwap(/*arc_enabled=*/true);
+
+  EXPECT_EQ(resourced_client_->get_critical_margin_bps(), 520u);
+  EXPECT_EQ(resourced_client_->get_moderate_margin_bps(), 4000u);
+}
+
+TEST_F(SwapConfigurationPressureThreshold, ArcCustom) {
+  feature_list_.InitAndEnableFeatureWithParameters(
+      kCrOSMemoryPressureSignalStudyArc,
+      {{kCrOSMemoryPressureSignalStudyArcCriticalBps.name, "800"},
+       {kCrOSMemoryPressureSignalStudyArcModerateBps.name, "6000"}});
+  ConfigureSwap(/*arc_enabled=*/true);
+
+  EXPECT_EQ(resourced_client_->get_critical_margin_bps(), 800u);
+  EXPECT_EQ(resourced_client_->get_moderate_margin_bps(), 6000u);
+}
+
+}  // namespace memory
+}  // namespace ash
diff --git a/chromeos/ash/components/network/cellular_esim_installer.h b/chromeos/ash/components/network/cellular_esim_installer.h
index 68b20e77..adf3795 100644
--- a/chromeos/ash/components/network/cellular_esim_installer.h
+++ b/chromeos/ash/components/network/cellular_esim_installer.h
@@ -104,6 +104,7 @@
                            InstallProfileAlreadyConnected);
   FRIEND_TEST_ALL_PREFIXES(CellularPolicyHandlerTest, InstallProfileSuccess);
   FRIEND_TEST_ALL_PREFIXES(CellularPolicyHandlerTest, InstallProfileFailure);
+  FRIEND_TEST_ALL_PREFIXES(CellularPolicyHandlerTest, RetryInstallProfile);
 
   // These values are persisted to logs. Entries should not be renumbered and
   // numeric values should never be reused.
diff --git a/chromeos/ash/components/network/cellular_policy_handler.cc b/chromeos/ash/components/network/cellular_policy_handler.cc
index ef0bede..afcd4e4 100644
--- a/chromeos/ash/components/network/cellular_policy_handler.cc
+++ b/chromeos/ash/components/network/cellular_policy_handler.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/ash/components/network/cellular_policy_handler.h"
 
+#include "base/containers/contains.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "base/value_iterators.h"
@@ -287,7 +288,19 @@
   auto current_request = std::move(remaining_install_requests_.front());
   PopRequest();
   if (hermes_status != HermesResponseStatus::kSuccess) {
-    ScheduleRetry(std::move(current_request), InstallRetryReason::kOther);
+    if (!base::Contains(kHermesUserErrorCodes, hermes_status)) {
+      NET_LOG(ERROR)
+          << "Failed to install an eSIM profile due to a non-user error: "
+          << hermes_status << ", scheduling a retry.";
+      ScheduleRetry(std::move(current_request),
+                    base::Contains(kHermesInternalErrorCodes, hermes_status)
+                        ? InstallRetryReason::kInternalError
+                        : InstallRetryReason::kOther);
+    } else {
+      NET_LOG(ERROR)
+          << "Failed to install an eSIM profile due to a user error: "
+          << hermes_status << ", not scheduling a retry.";
+    }
     ProcessRequests();
     return;
   }
@@ -310,7 +323,8 @@
 void CellularPolicyHandler::ScheduleRetry(
     std::unique_ptr<InstallPolicyESimRequest> request,
     InstallRetryReason reason) {
-  if (request->retry_backoff.failure_count() >= kInstallRetryLimit) {
+  if (reason != InstallRetryReason::kInternalError &&
+      request->retry_backoff.failure_count() >= kInstallRetryLimit) {
     NET_LOG(ERROR) << "Install policy eSIM profile with SMDP address: "
                    << request->smdp_address << " failed " << kInstallRetryLimit
                    << " times.";
@@ -320,7 +334,7 @@
 
   request->retry_backoff.InformOfRequest(/*succeeded=*/false);
 
-  if (reason != InstallRetryReason::kMissingNonCellularConnectivity) {
+  if (reason == InstallRetryReason::kOther) {
     request->retry_backoff.SetCustomReleaseTime(base::TimeTicks::Now() +
                                                 kInstallRetryDelay);
   }
@@ -378,7 +392,7 @@
                  << ". Timed out waiting for EUICC or profile list.";
   auto current_request = std::move(remaining_install_requests_.front());
   PopRequest();
-  ScheduleRetry(std::move(current_request), InstallRetryReason::kOther);
+  ScheduleRetry(std::move(current_request), InstallRetryReason::kInternalError);
   ProcessRequests();
 }
 
diff --git a/chromeos/ash/components/network/cellular_policy_handler.h b/chromeos/ash/components/network/cellular_policy_handler.h
index 77d1357..a2db6f7 100644
--- a/chromeos/ash/components/network/cellular_policy_handler.h
+++ b/chromeos/ash/components/network/cellular_policy_handler.h
@@ -71,9 +71,33 @@
   // reason for retrying is.
   enum class InstallRetryReason {
     kMissingNonCellularConnectivity = 0,
-    kOther,
+    kInternalError = 1,
+    kUserError = 2,
+    kOther
   };
 
+  // HermesUserErrorCodes indicate errors made by the user. These can be due
+  // to bad input or a valid input that has already been successfully processed.
+  // In such errors, we do not attempt to retry.
+  const std::array<HermesResponseStatus, 4> kHermesUserErrorCodes = {
+      HermesResponseStatus::kErrorAlreadyDisabled,
+      HermesResponseStatus::kErrorAlreadyEnabled,
+      HermesResponseStatus::kErrorInvalidActivationCode,
+      HermesResponseStatus::kErrorInvalidIccid};
+
+  // HermesInternalErrorCodes indicate system failure during the installation
+  // process. These error can happen due to code bugs or reasons unrelated to
+  // user input. In these cases, we retry using an exponental backoff policy to
+  // attempt the installation again.
+  const std::array<HermesResponseStatus, 7> kHermesInternalErrorCodes = {
+      HermesResponseStatus::kErrorUnknown,
+      HermesResponseStatus::kErrorInternalLpaFailure,
+      HermesResponseStatus::kErrorWrongState,
+      HermesResponseStatus::kErrorSendApduFailure,
+      HermesResponseStatus::kErrorUnexpectedModemManagerState,
+      HermesResponseStatus::kErrorModemMessageProcessing,
+      HermesResponseStatus::kErrorPendingProfile};
+
   friend class CellularPolicyHandlerTest;
 
   // Represents policy eSIM install request parameters. Requests are queued and
diff --git a/chromeos/ash/components/network/cellular_policy_handler_unittest.cc b/chromeos/ash/components/network/cellular_policy_handler_unittest.cc
index a1e7b6c..0a41d730 100644
--- a/chromeos/ash/components/network/cellular_policy_handler_unittest.cc
+++ b/chromeos/ash/components/network/cellular_policy_handler_unittest.cc
@@ -61,6 +61,7 @@
 const char kWifiGuid[] = "wifi_guid";
 const char kWifiName[] = "wifi";
 const base::TimeDelta kInstallationRetryDelay = base::Days(1);
+const base::TimeDelta kInstallationRetryDelayExponential = base::Minutes(12);
 
 void CheckShillConfiguration(bool is_installed) {
   std::string service_path =
@@ -373,6 +374,75 @@
   CheckIccidSmdpPairInPref(/*is_installed=*/true);
 }
 
+TEST_F(CellularPolicyHandlerTest, RetryInstallProfile) {
+  SetupEuicc();
+
+  base::HistogramTester histogram_tester;
+
+  const std::string policy =
+      GenerateCellularPolicy(HermesEuiccClient::Get()
+                                 ->GetTestInterface()
+                                 ->GenerateFakeActivationCode());
+
+  // Make the first installation attempt fail due to an user error
+  HermesEuiccClient::Get()
+      ->GetTestInterface()
+      ->SetNextInstallProfileFromActivationCodeResult(
+          HermesResponseStatus::kErrorAlreadyDisabled);
+  InstallESimPolicy(policy,
+                    HermesEuiccClient::Get()
+                        ->GetTestInterface()
+                        ->GenerateFakeActivationCode(),
+                    /*expect_install_success=*/false);
+
+  FastForwardBy(kInstallationRetryDelay + base::Minutes(5));
+
+  // As this is an user error, retry shouldn't happen
+  histogram_tester.ExpectBucketCount(
+      kInstallViaPolicyOperationHistogram,
+      CellularESimInstaller::InstallESimProfileResult::kSuccess,
+      /*expected_count=*/0);
+
+  // Make the second installation attempt fail due to a dependency error
+  HermesEuiccClient::Get()
+      ->GetTestInterface()
+      ->SetNextInstallProfileFromActivationCodeResult(
+          HermesResponseStatus::kErrorSendHttpsFailure);
+  InstallESimPolicy(policy,
+                    HermesEuiccClient::Get()
+                        ->GetTestInterface()
+                        ->GenerateFakeActivationCode(),
+                    /*expect_install_success=*/false);
+
+  FastForwardBy(kInstallationRetryDelay + base::Minutes(5));
+
+  // For dependency errors, retry should happen after the wait time of one day
+  histogram_tester.ExpectBucketCount(
+      kInstallViaPolicyOperationHistogram,
+      CellularESimInstaller::InstallESimProfileResult::kSuccess,
+      /*expected_count=*/1);
+
+  // Make the third installation attempt fail due to an internal error
+  HermesEuiccClient::Get()
+      ->GetTestInterface()
+      ->SetNextInstallProfileFromActivationCodeResult(
+          HermesResponseStatus::kErrorUnknown);
+  InstallESimPolicy(policy,
+                    HermesEuiccClient::Get()
+                        ->GetTestInterface()
+                        ->GenerateFakeActivationCode(),
+                    /*expect_install_success=*/false);
+
+  FastForwardBy(kInstallationRetryDelayExponential);
+
+  // For internal errors, retry should follow an exponential backoff with the
+  // initial delay of 5 minutes.
+  histogram_tester.ExpectBucketCount(
+      kInstallViaPolicyOperationHistogram,
+      CellularESimInstaller::InstallESimProfileResult::kSuccess,
+      /*expected_count=*/2);
+}
+
 TEST_F(CellularPolicyHandlerTest, InstallProfileFailure) {
   SetupEuicc();
 
diff --git a/chromeos/ash/components/phonehub/BUILD.gn b/chromeos/ash/components/phonehub/BUILD.gn
index 111345fd..451d9420 100644
--- a/chromeos/ash/components/phonehub/BUILD.gn
+++ b/chromeos/ash/components/phonehub/BUILD.gn
@@ -35,6 +35,8 @@
     "connection_scheduler.h",
     "connection_scheduler_impl.cc",
     "connection_scheduler_impl.h",
+    "cros_state_message_recorder.cc",
+    "cros_state_message_recorder.h",
     "cros_state_sender.cc",
     "cros_state_sender.h",
     "do_not_disturb_controller.cc",
@@ -262,6 +264,7 @@
     "camera_roll_manager_impl_unittest.cc",
     "camera_roll_thumbnail_decoder_impl_unittest.cc",
     "connection_scheduler_impl_unittest.cc",
+    "cros_state_message_recorder_unittest.cc",
     "cros_state_sender_unittest.cc",
     "do_not_disturb_controller_impl_unittest.cc",
     "feature_setup_response_processor_unittest.cc",
diff --git a/chromeos/ash/components/phonehub/cros_state_message_recorder.cc b/chromeos/ash/components/phonehub/cros_state_message_recorder.cc
new file mode 100644
index 0000000..c49a112d
--- /dev/null
+++ b/chromeos/ash/components/phonehub/cros_state_message_recorder.cc
@@ -0,0 +1,92 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/phonehub/cros_state_message_recorder.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "chromeos/ash/components/multidevice/logging/logging.h"
+
+namespace ash::phonehub {
+
+CrosStateMessageRecorder::CrosStateMessageRecorder(
+    FeatureStatusProvider* feature_status_provider)
+    : feature_status_provider_(feature_status_provider) {
+  feature_status_provider_->AddObserver(this);
+}
+
+CrosStateMessageRecorder::~CrosStateMessageRecorder() {
+  feature_status_provider_->RemoveObserver(this);
+}
+
+void CrosStateMessageRecorder::OnFeatureStatusChanged() {
+  switch (feature_status_provider_->GetStatus()) {
+    case FeatureStatus::kEnabledButDisconnected:
+      [[fallthrough]];
+    case FeatureStatus::kNotEligibleForFeature:
+      [[fallthrough]];
+    case FeatureStatus::kEligiblePhoneButNotSetUp:
+      [[fallthrough]];
+    case FeatureStatus::kPhoneSelectedAndPendingSetup:
+      [[fallthrough]];
+    case FeatureStatus::kDisabled:
+      [[fallthrough]];
+    case FeatureStatus::kUnavailableBluetoothOff:
+      [[fallthrough]];
+    case FeatureStatus::kLockOrSuspended:
+      RecordWhenDisconnected();
+      [[fallthrough]];
+    case FeatureStatus::kEnabledAndConnecting:
+      is_cros_state_message_sent_ = false;
+      is_phone_status_snapshot_processed_ = false;
+      message_sent_timestamp_ = base::Time();
+      break;
+
+    // Devices connected. No actions needed.
+    case FeatureStatus::kEnabledAndConnected:
+      break;
+  }
+}
+
+void CrosStateMessageRecorder::RecordCrosStateMessageSent() {
+  // If SendMessage() is invoked after disconnected then do not log.
+  if (feature_status_provider_->GetStatus() !=
+          FeatureStatus::kEnabledAndConnected ||
+      is_cros_state_message_sent_) {
+    return;
+  }
+
+  // Update the timestamp for CrosState message sent.
+  message_sent_timestamp_ = base::Time::NowFromSystemTime();
+  is_cros_state_message_sent_ = true;
+}
+
+void CrosStateMessageRecorder::RecordPhoneStatusSnapShotReceived() {
+  // If PhoneStatusSnapshot is processed after disconnected then do not log.
+  if (feature_status_provider_->GetStatus() !=
+          FeatureStatus::kEnabledAndConnected ||
+      is_phone_status_snapshot_processed_) {
+    return;
+  }
+  base::UmaHistogramLongTimes(
+      "PhoneHub.InitialPhoneStatusSnapshot.Latency",
+      base::Time::NowFromSystemTime() - message_sent_timestamp_);
+  base::UmaHistogramBoolean("PhoneHub.InitialPhoneStatusSnapshot.Received",
+                            true);
+  message_sent_timestamp_ = base::Time();
+  is_phone_status_snapshot_processed_ = true;
+}
+
+void CrosStateMessageRecorder::RecordWhenDisconnected() {
+  if (!is_cros_state_message_sent_) {
+    // No CrosState message has been sent to phone yet, do nothing.
+    return;
+  }
+
+  if (!is_phone_status_snapshot_processed_) {
+    base::UmaHistogramBoolean("PhoneHub.InitialPhoneStatusSnapshot.Received",
+                              false);
+  }
+}
+
+}  // namespace ash::phonehub
diff --git a/chromeos/ash/components/phonehub/cros_state_message_recorder.h b/chromeos/ash/components/phonehub/cros_state_message_recorder.h
new file mode 100644
index 0000000..3c5fd3d7
--- /dev/null
+++ b/chromeos/ash/components/phonehub/cros_state_message_recorder.h
@@ -0,0 +1,46 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_ASH_COMPONENTS_PHONEHUB_CROS_STATE_MESSAGE_RECORDER_H_
+#define CHROMEOS_ASH_COMPONENTS_PHONEHUB_CROS_STATE_MESSAGE_RECORDER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/raw_ptr.h"
+#include "base/time/time.h"
+#include "chromeos/ash/components/phonehub/feature_status_provider.h"
+
+namespace ash::phonehub {
+
+// To record when a CrosState message is sent and if/when a PhoneStatusSnapShot
+// message is received.
+class CrosStateMessageRecorder : FeatureStatusProvider::Observer {
+ public:
+  explicit CrosStateMessageRecorder(
+      FeatureStatusProvider* feature_status_provider);
+  CrosStateMessageRecorder(const CrosStateMessageRecorder&) = delete;
+  CrosStateMessageRecorder& operator=(const CrosStateMessageRecorder&) = delete;
+  ~CrosStateMessageRecorder() override;
+
+  // FeatureStatusProvider::Observer:
+  void OnFeatureStatusChanged() override;
+
+  void RecordCrosStateMessageSent();
+  void RecordPhoneStatusSnapShotReceived();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(CrosStateMessageRecorderTest, RecordLatency);
+  FRIEND_TEST_ALL_PREFIXES(CrosStateMessageRecorderTest, RecordSuccess);
+
+  void RecordWhenDisconnected();
+
+  raw_ptr<FeatureStatusProvider, ExperimentalAsh> feature_status_provider_;
+  bool is_cros_state_message_sent_ = false;
+  bool is_phone_status_snapshot_processed_ = false;
+  // The priority queue to keep timestamp when CrosState message is sent.
+  base::Time message_sent_timestamp_;
+};
+
+}  // namespace ash::phonehub
+
+#endif  // CHROMEOS_ASH_COMPONENTS_PHONEHUB_CROS_STATE_MESSAGE_RECORDER_H_
diff --git a/chromeos/ash/components/phonehub/cros_state_message_recorder_unittest.cc b/chromeos/ash/components/phonehub/cros_state_message_recorder_unittest.cc
new file mode 100644
index 0000000..f557f97
--- /dev/null
+++ b/chromeos/ash/components/phonehub/cros_state_message_recorder_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/phonehub/cros_state_message_recorder.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "chromeos/ash/components/phonehub/fake_feature_status_provider.h"
+#include "chromeos/ash/components/phonehub/feature_status_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash::phonehub {
+namespace {
+constexpr auto kLatencyDelta = base::Milliseconds(500u);
+}  // namespace
+
+class CrosStateMessageRecorderTest : public testing::Test {
+ protected:
+  CrosStateMessageRecorderTest() = default;
+  CrosStateMessageRecorderTest(const CrosStateMessageRecorderTest&) = delete;
+  CrosStateMessageRecorderTest& operator=(const CrosStateMessageRecorderTest&) =
+      delete;
+  ~CrosStateMessageRecorderTest() override = default;
+
+  void SetUp() override {
+    feature_status_provider_ = std::make_unique<FakeFeatureStatusProvider>();
+    recorder_ = std::make_unique<CrosStateMessageRecorder>(
+        feature_status_provider_.get());
+  }
+
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+  std::unique_ptr<FakeFeatureStatusProvider> feature_status_provider_;
+  std::unique_ptr<CrosStateMessageRecorder> recorder_;
+  base::HistogramTester histogram_tester_;
+};
+
+TEST_F(CrosStateMessageRecorderTest, RecordLatency) {
+  feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected);
+  recorder_->RecordCrosStateMessageSent();
+  task_environment_.FastForwardBy(kLatencyDelta);
+  recorder_->RecordPhoneStatusSnapShotReceived();
+  histogram_tester_.ExpectTimeBucketCount(
+      "PhoneHub.InitialPhoneStatusSnapshot.Latency", kLatencyDelta,
+      /*expected_count=*/1);
+  histogram_tester_.ExpectBucketCount(
+      "PhoneHub.InitialPhoneStatusSnapshot.Received", true, 1);
+  EXPECT_TRUE(recorder_->message_sent_timestamp_.is_null());
+
+  feature_status_provider_->SetStatus(FeatureStatus::kEnabledButDisconnected);
+  recorder_->RecordCrosStateMessageSent();
+  EXPECT_FALSE(recorder_->is_cros_state_message_sent_);
+
+  recorder_->RecordPhoneStatusSnapShotReceived();
+  EXPECT_FALSE(recorder_->is_phone_status_snapshot_processed_);
+}
+
+TEST_F(CrosStateMessageRecorderTest, RecordSuccess) {
+  feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected);
+  recorder_->RecordCrosStateMessageSent();
+
+  feature_status_provider_->SetStatus(FeatureStatus::kUnavailableBluetoothOff);
+  histogram_tester_.ExpectBucketCount(
+      "PhoneHub.InitialPhoneStatusSnapshot.Received", true, 0);
+  histogram_tester_.ExpectBucketCount(
+      "PhoneHub.InitialPhoneStatusSnapshot.Received", false, 1);
+  EXPECT_FALSE(recorder_->is_cros_state_message_sent_);
+  EXPECT_FALSE(recorder_->is_phone_status_snapshot_processed_);
+
+  feature_status_provider_->SetStatus(FeatureStatus::kEnabledButDisconnected);
+  histogram_tester_.ExpectBucketCount(
+      "PhoneHub.InitialPhoneStatusSnapshot.Received", true, 0);
+  histogram_tester_.ExpectBucketCount(
+      "PhoneHub.InitialPhoneStatusSnapshot.Received", false, 1);
+
+  feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected);
+  recorder_->RecordCrosStateMessageSent();
+  recorder_->RecordPhoneStatusSnapShotReceived();
+  feature_status_provider_->SetStatus(FeatureStatus::kEnabledButDisconnected);
+  histogram_tester_.ExpectBucketCount(
+      "PhoneHub.InitialPhoneStatusSnapshot.Received", true, 1);
+  histogram_tester_.ExpectBucketCount(
+      "PhoneHub.InitialPhoneStatusSnapshot.Received", false, 1);
+}
+
+}  // namespace ash::phonehub
diff --git a/chromeos/ash/components/phonehub/message_sender_impl.cc b/chromeos/ash/components/phonehub/message_sender_impl.cc
index d259926..78f41cf 100644
--- a/chromeos/ash/components/phonehub/message_sender_impl.cc
+++ b/chromeos/ash/components/phonehub/message_sender_impl.cc
@@ -10,6 +10,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chromeos/ash/components/phonehub/cros_state_message_recorder.h"
 #include "chromeos/ash/components/phonehub/util/histogram_util.h"
 #include "chromeos/ash/services/secure_channel/public/cpp/client/connection_manager.h"
 
@@ -33,8 +34,10 @@
 }  // namespace
 
 MessageSenderImpl::MessageSenderImpl(
-    secure_channel::ConnectionManager* connection_manager)
-    : connection_manager_(connection_manager) {
+    secure_channel::ConnectionManager* connection_manager,
+    CrosStateMessageRecorder* cros_state_message_recorder)
+    : connection_manager_(connection_manager),
+      cros_state_message_recorder_(cros_state_message_recorder) {
   DCHECK(connection_manager_);
 }
 
@@ -66,6 +69,7 @@
   }
 
   SendMessage(proto::MessageType::PROVIDE_CROS_STATE, &request);
+  cros_state_message_recorder_->RecordCrosStateMessageSent();
 }
 
 void MessageSenderImpl::SendUpdateNotificationModeRequest(
diff --git a/chromeos/ash/components/phonehub/message_sender_impl.h b/chromeos/ash/components/phonehub/message_sender_impl.h
index 5a8155d6..32242ef 100644
--- a/chromeos/ash/components/phonehub/message_sender_impl.h
+++ b/chromeos/ash/components/phonehub/message_sender_impl.h
@@ -5,12 +5,13 @@
 #ifndef CHROMEOS_ASH_COMPONENTS_PHONEHUB_MESSAGE_SENDER_IMPL_H_
 #define CHROMEOS_ASH_COMPONENTS_PHONEHUB_MESSAGE_SENDER_IMPL_H_
 
-#include "base/memory/raw_ptr.h"
 #include "chromeos/ash/components/phonehub/message_sender.h"
 
 #include <stdint.h>
 #include <string>
+#include "base/memory/raw_ptr.h"
 
+#include "chromeos/ash/components/phonehub/cros_state_message_recorder.h"
 #include "chromeos/ash/components/phonehub/proto/phonehub_api.pb.h"
 
 namespace ash {
@@ -23,8 +24,8 @@
 
 class MessageSenderImpl : public MessageSender {
  public:
-  explicit MessageSenderImpl(
-      secure_channel::ConnectionManager* connection_manager);
+  MessageSenderImpl(secure_channel::ConnectionManager* connection_manager,
+                    CrosStateMessageRecorder* cros_state_message_recorder);
   ~MessageSenderImpl() override;
 
   // MessageSender:
@@ -55,6 +56,8 @@
 
   raw_ptr<secure_channel::ConnectionManager, ExperimentalAsh>
       connection_manager_;
+  raw_ptr<CrosStateMessageRecorder, ExperimentalAsh>
+      cros_state_message_recorder_;
 };
 
 }  // namespace phonehub
diff --git a/chromeos/ash/components/phonehub/message_sender_unittest.cc b/chromeos/ash/components/phonehub/message_sender_unittest.cc
index c904bf8..554957e 100644
--- a/chromeos/ash/components/phonehub/message_sender_unittest.cc
+++ b/chromeos/ash/components/phonehub/message_sender_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/constants/ash_features.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chromeos/ash/components/phonehub/fake_feature_status_provider.h"
 #include "chromeos/ash/components/phonehub/proto/phonehub_api.pb.h"
 #include "chromeos/ash/services/secure_channel/public/cpp/client/fake_connection_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -29,8 +30,12 @@
   void SetUp() override {
     fake_connection_manager_ =
         std::make_unique<secure_channel::FakeConnectionManager>();
-    message_sender_ =
-        std::make_unique<MessageSenderImpl>(fake_connection_manager_.get());
+    fake_feature_status_provider_ =
+        std::make_unique<FakeFeatureStatusProvider>();
+    cros_state_message_recorder_ = std::make_unique<CrosStateMessageRecorder>(
+        fake_feature_status_provider_.get());
+    message_sender_ = std::make_unique<MessageSenderImpl>(
+        fake_connection_manager_.get(), cros_state_message_recorder_.get());
   }
 
   void VerifyMessage(proto::MessageType expected_message_type,
@@ -58,6 +63,8 @@
 
   std::unique_ptr<secure_channel::FakeConnectionManager>
       fake_connection_manager_;
+  std::unique_ptr<FakeFeatureStatusProvider> fake_feature_status_provider_;
+  std::unique_ptr<CrosStateMessageRecorder> cros_state_message_recorder_;
   std::unique_ptr<MessageSenderImpl> message_sender_;
 };
 
diff --git a/chromeos/ash/components/phonehub/phone_hub_manager_impl.cc b/chromeos/ash/components/phonehub/phone_hub_manager_impl.cc
index 85e909f..113cbbc8 100644
--- a/chromeos/ash/components/phonehub/phone_hub_manager_impl.cc
+++ b/chromeos/ash/components/phonehub/phone_hub_manager_impl.cc
@@ -16,6 +16,7 @@
 #include "chromeos/ash/components/phonehub/camera_roll_download_manager.h"
 #include "chromeos/ash/components/phonehub/camera_roll_manager_impl.h"
 #include "chromeos/ash/components/phonehub/connection_scheduler_impl.h"
+#include "chromeos/ash/components/phonehub/cros_state_message_recorder.h"
 #include "chromeos/ash/components/phonehub/cros_state_sender.h"
 #include "chromeos/ash/components/phonehub/do_not_disturb_controller_impl.h"
 #include "chromeos/ash/components/phonehub/feature_status_provider_impl.h"
@@ -82,10 +83,13 @@
           chromeos::PowerManagerClient::Get())),
       user_action_recorder_(std::make_unique<UserActionRecorderImpl>(
           feature_status_provider_.get())),
+      cros_state_message_recorder_(std::make_unique<CrosStateMessageRecorder>(
+          feature_status_provider_.get())),
       message_receiver_(
           std::make_unique<MessageReceiverImpl>(connection_manager_.get())),
-      message_sender_(
-          std::make_unique<MessageSenderImpl>(connection_manager_.get())),
+      message_sender_(std::make_unique<MessageSenderImpl>(
+          connection_manager_.get(),
+          cros_state_message_recorder_.get())),
       phone_model_(std::make_unique<MutablePhoneModel>()),
       cros_state_sender_(std::make_unique<CrosStateSender>(
           message_sender_.get(),
@@ -152,7 +156,8 @@
           pref_service,
           app_stream_manager_.get(),
           app_stream_launcher_data_model_.get(),
-          icon_decoder_.get())),
+          icon_decoder_.get(),
+          cros_state_message_recorder_.get())),
       tether_controller_(
           std::make_unique<TetherControllerImpl>(phone_model_.get(),
                                                  user_action_recorder_.get(),
@@ -328,6 +333,7 @@
   phone_model_.reset();
   message_sender_.reset();
   message_receiver_.reset();
+  cros_state_message_recorder_.reset();
   user_action_recorder_.reset();
   feature_status_provider_.reset();
   connection_manager_.reset();
diff --git a/chromeos/ash/components/phonehub/phone_hub_manager_impl.h b/chromeos/ash/components/phonehub/phone_hub_manager_impl.h
index 162d100b..0894b17 100644
--- a/chromeos/ash/components/phonehub/phone_hub_manager_impl.h
+++ b/chromeos/ash/components/phonehub/phone_hub_manager_impl.h
@@ -11,6 +11,7 @@
 #include "base/memory/raw_ptr.h"
 #include "chromeos/ash/components/phonehub/app_stream_launcher_data_model.h"
 #include "chromeos/ash/components/phonehub/app_stream_manager.h"
+#include "chromeos/ash/components/phonehub/cros_state_message_recorder.h"
 #include "chromeos/ash/components/phonehub/feature_setup_response_processor.h"
 #include "chromeos/ash/components/phonehub/icon_decoder.h"
 #include "chromeos/ash/components/phonehub/phone_hub_manager.h"
@@ -109,6 +110,7 @@
   std::unique_ptr<secure_channel::ConnectionManager> connection_manager_;
   std::unique_ptr<FeatureStatusProvider> feature_status_provider_;
   std::unique_ptr<UserActionRecorder> user_action_recorder_;
+  std::unique_ptr<CrosStateMessageRecorder> cros_state_message_recorder_;
   std::unique_ptr<MessageReceiver> message_receiver_;
   std::unique_ptr<MessageSender> message_sender_;
   std::unique_ptr<MutablePhoneModel> phone_model_;
diff --git a/chromeos/ash/components/phonehub/phone_status_processor.cc b/chromeos/ash/components/phonehub/phone_status_processor.cc
index 9daf10d2..1bdc43ae 100644
--- a/chromeos/ash/components/phonehub/phone_status_processor.cc
+++ b/chromeos/ash/components/phonehub/phone_status_processor.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "chromeos/ash/components/phonehub/app_stream_manager.h"
+#include "chromeos/ash/components/phonehub/cros_state_message_recorder.h"
 #include "chromeos/ash/components/phonehub/do_not_disturb_controller.h"
 #include "chromeos/ash/components/phonehub/find_my_device_controller.h"
 #include "chromeos/ash/components/phonehub/icon_decoder.h"
@@ -228,7 +229,8 @@
     PrefService* pref_service,
     AppStreamManager* app_stream_manager,
     AppStreamLauncherDataModel* app_stream_launcher_data_model,
-    IconDecoder* icon_decoder)
+    IconDecoder* icon_decoder,
+    CrosStateMessageRecorder* cros_state_message_recorder)
     : do_not_disturb_controller_(do_not_disturb_controller),
       feature_status_provider_(feature_status_provider),
       message_receiver_(message_receiver),
@@ -242,7 +244,8 @@
       pref_service_(pref_service),
       app_stream_manager_(app_stream_manager),
       app_stream_launcher_data_model_(app_stream_launcher_data_model),
-      icon_decoder_(icon_decoder) {
+      icon_decoder_(icon_decoder),
+      cros_state_message_recorder_(cros_state_message_recorder) {
   DCHECK(do_not_disturb_controller_);
   DCHECK(feature_status_provider_);
   DCHECK(message_receiver_);
@@ -254,6 +257,7 @@
   DCHECK(pref_service_);
   DCHECK(app_stream_manager_);
   DCHECK(icon_decoder_);
+  DCHECK(cros_state_message_recorder_);
 
   message_receiver_->AddObserver(this);
   feature_status_provider_->AddObserver(this);
@@ -408,6 +412,7 @@
   }
   multidevice_feature_access_manager_
       ->UpdatedFeatureSetupConnectionStatusIfNeeded();
+  cros_state_message_recorder_->RecordPhoneStatusSnapShotReceived();
 }
 
 void PhoneStatusProcessor::OnPhoneStatusUpdateReceived(
diff --git a/chromeos/ash/components/phonehub/phone_status_processor.h b/chromeos/ash/components/phonehub/phone_status_processor.h
index 891e025..eb0727d 100644
--- a/chromeos/ash/components/phonehub/phone_status_processor.h
+++ b/chromeos/ash/components/phonehub/phone_status_processor.h
@@ -30,6 +30,7 @@
 class ScreenLockManager;
 class RecentAppsInteractionHandler;
 class AppStreamManager;
+class CrosStateMessageRecorder;
 
 // Responsible for receiving incoming protos and calling on clients to update
 // their models.
@@ -60,7 +61,8 @@
       PrefService* pref_service,
       AppStreamManager* app_stream_manager,
       AppStreamLauncherDataModel* app_stream_launcher_data_model,
-      IconDecoder* icon_decoder_);
+      IconDecoder* icon_decoder_,
+      CrosStateMessageRecorder* cros_state_message_recorder);
   ~PhoneStatusProcessor() override;
 
   PhoneStatusProcessor(const PhoneStatusProcessor&) = delete;
@@ -128,6 +130,8 @@
   raw_ptr<AppStreamLauncherDataModel, ExperimentalAsh>
       app_stream_launcher_data_model_;
   raw_ptr<IconDecoder, ExperimentalAsh> icon_decoder_;
+  raw_ptr<CrosStateMessageRecorder, ExperimentalAsh>
+      cros_state_message_recorder_;
   base::TimeTicks connection_initialized_timestamp_ = base::TimeTicks();
   bool has_received_first_app_list_update_ = false;
 
diff --git a/chromeos/ash/components/phonehub/phone_status_processor_unittest.cc b/chromeos/ash/components/phonehub/phone_status_processor_unittest.cc
index 437806e..86d6543 100644
--- a/chromeos/ash/components/phonehub/phone_status_processor_unittest.cc
+++ b/chromeos/ash/components/phonehub/phone_status_processor_unittest.cc
@@ -20,6 +20,7 @@
 #include "chromeos/ash/components/multidevice/remote_device_test_util.h"
 #include "chromeos/ash/components/phonehub/app_stream_launcher_data_model.h"
 #include "chromeos/ash/components/phonehub/app_stream_manager.h"
+#include "chromeos/ash/components/phonehub/cros_state_message_recorder.h"
 #include "chromeos/ash/components/phonehub/fake_do_not_disturb_controller.h"
 #include "chromeos/ash/components/phonehub/fake_feature_status_provider.h"
 #include "chromeos/ash/components/phonehub/fake_find_my_device_controller.h"
@@ -167,6 +168,8 @@
         icon_decoder_.get()->decoder_delegate_.get());
     app_stream_launcher_data_model_ =
         std::make_unique<AppStreamLauncherDataModel>();
+    cros_state_message_recorder_ = std::make_unique<CrosStateMessageRecorder>(
+        fake_feature_status_provider_.get());
 
     multidevice_setup::RegisterFeaturePrefs(pref_service_.registry());
   }
@@ -181,7 +184,7 @@
         fake_multidevice_setup_client_.get(), mutable_phone_model_.get(),
         fake_recent_apps_interaction_handler_.get(), &pref_service_,
         &app_stream_manager_, app_stream_launcher_data_model_.get(),
-        icon_decoder_.get());
+        icon_decoder_.get(), cros_state_message_recorder_.get());
   }
 
   void InitializeNotificationProto(proto::Notification* notification,
@@ -235,6 +238,7 @@
   std::unique_ptr<FakeRecentAppsInteractionHandler>
       fake_recent_apps_interaction_handler_;
   std::unique_ptr<IconDecoderImpl> icon_decoder_;
+  std::unique_ptr<CrosStateMessageRecorder> cros_state_message_recorder_;
   raw_ptr<TestDecoderDelegate, ExperimentalAsh> decoder_delegate_;
   TestingPrefServiceSimple pref_service_;
   AppStreamManager app_stream_manager_;
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index c1ba0f6f..c37c5ffc8 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -352,10 +352,6 @@
       <message name="IDS_TABLET_MULTITASK_MENU_NUDGE_TEXT" desc="Text that is shown when the tablet multitask menu nudge is displayed.">
         Swipe down for more layout options
       </message>
-      <message name="IDS_MULTITASK_MENU_FEEDBACK_BUTTON_NAME" desc="Button text of the dogfood feedback button on the multitask menu.">
-        Send feedback
-      </message>
-
       <if expr="chromeos_ash">
         <!-- The following strings are located here for accessibility from both //ash and //chrome -->
         <message name="IDS_ENABLE_BLUETOOTH" desc="The message to display in the network list when Tether is enabled but Bluetooth is disabled.">
@@ -2611,6 +2607,9 @@
         <message name="IDS_PERSONALIZATION_APP_KEYBOARD_BACKLIGHT_TITLE" desc="Title for the keyboard backlight section of personalization hub.">
           Keyboard backlight
         </message>
+        <message name="IDS_PERSONALIZATION_APP_KEYBOARD_ZONES_TITLE" desc="Title for the keyboard zones in zone customization section of personalization hub.">
+          Keyboard zones
+        </message>
         <message name="IDS_PERSONALIZATION_APP_KEYBOARD_BACKLIGHT_WALLPAPER_COLOR_LABEL" desc="Label for the wallpaper extracted color in the keyboard backlight section of personalization hub.">
           Wallpaper color
         </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_MULTITASK_MENU_FEEDBACK_BUTTON_NAME.png.sha1 b/chromeos/chromeos_strings_grd/IDS_MULTITASK_MENU_FEEDBACK_BUTTON_NAME.png.sha1
deleted file mode 100644
index 152b4eb9..0000000
--- a/chromeos/chromeos_strings_grd/IDS_MULTITASK_MENU_FEEDBACK_BUTTON_NAME.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e7a4f444dccf41be524918e20e7f36ed8ccbdb73
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_KEYBOARD_ZONES_TITLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_KEYBOARD_ZONES_TITLE.png.sha1
new file mode 100644
index 0000000..72104de
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_KEYBOARD_ZONES_TITLE.png.sha1
@@ -0,0 +1 @@
+7c0df6190a8b12e5e91d51d955e0da30b6829b0a
\ No newline at end of file
diff --git a/chromeos/crosapi/mojom/feedback.mojom b/chromeos/crosapi/mojom/feedback.mojom
index 55ea975f..657347a 100644
--- a/chromeos/crosapi/mojom/feedback.mojom
+++ b/chromeos/crosapi/mojom/feedback.mojom
@@ -23,7 +23,8 @@
   [MinVersion=2] kLacrosSadTabPage = 4,
   [MinVersion=2] kLacrosChromeLabs = 5,
   [MinVersion=2] kLacrosQuickAnswers = 6,
-  [MinVersion=3] kLacrosWindowLayoutMenu = 7,
+  // Deprecated as the window layout menu feedback button has been removed.
+  [MinVersion=3] kDeprecatedLacrosWindowLayoutMenu = 7,
 };
 
 [Stable]
diff --git a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
index 46231bd..747fc38 100644
--- a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
+++ b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -813,8 +813,9 @@
 }
 
 void FrameCaptionButtonContainerView::CommitSnap(SnapDirection snap) {
-  SnapController::Get()->CommitSnap(frame_->GetNativeWindow(), snap,
-                                    kDefaultSnapRatio);
+  SnapController::Get()->CommitSnap(
+      frame_->GetNativeWindow(), snap, kDefaultSnapRatio,
+      SnapController::SnapRequestSource::kSnapButton);
 }
 
 MultitaskMenuNudgeController*
diff --git a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
index 05f3b446..df343d8 100644
--- a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
+++ b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
@@ -11,7 +11,6 @@
 #include "base/component_export.h"
 #include "base/memory/raw_ptr.h"
 #include "chromeos/ui/frame/caption_buttons/caption_button_model.h"
-#include "chromeos/ui/frame/caption_buttons/frame_size_button.h"
 #include "chromeos/ui/frame/caption_buttons/frame_size_button_delegate.h"
 #include "chromeos/ui/frame/caption_buttons/snap_controller.h"
 #include "chromeos/ui/frame/multitask_menu/multitask_menu_nudge_controller.h"
@@ -103,7 +102,7 @@
     raw_ptr<FrameCaptionButtonContainerView> container_view_;
   };
 
-  chromeos::FrameSizeButton* size_button() { return size_button_; }
+  views::FrameCaptionButton* size_button() { return size_button_; }
 
   // Sets whether the buttons should be painted as active. Does not schedule
   // a repaint.
@@ -216,7 +215,7 @@
   raw_ptr<views::FrameCaptionButton> close_button_ = nullptr;
 
   // Stored as a `FrameSizeButton` so the multitask menu can be accessed.
-  raw_ptr<chromeos::FrameSizeButton> size_button_ = nullptr;
+  raw_ptr<views::FrameCaptionButton> size_button_ = nullptr;
 
   // Handles showing the educational nudge for the clamshell multitask menu.
   MultitaskMenuNudgeController nudge_controller_;
diff --git a/chromeos/ui/frame/caption_buttons/frame_size_button.cc b/chromeos/ui/frame/caption_buttons/frame_size_button.cc
index 92e4850..115fdca 100644
--- a/chromeos/ui/frame/caption_buttons/frame_size_button.cc
+++ b/chromeos/ui/frame/caption_buttons/frame_size_button.cc
@@ -260,12 +260,9 @@
         /*anchor=*/this, GetWidget(),
         /*close_on_move_out=*/entry_type ==
             MultitaskMenuEntryType::kFrameSizeButtonHover);
-    auto* menu_delegate_ptr = menu_delegate.get();
     multitask_menu_widget_ =
         base::WrapUnique(views::BubbleDialogDelegateView::CreateBubble(
             std::move(menu_delegate)));
-    menu_delegate_ptr->multitask_menu_view()->feedback_button()->SetCallback(
-        feedback_callback_);
     multitask_menu_widget_->Show();
     delegate_->GetMultitaskMenuNudgeController()->OnMenuOpened(
         /*tablet_mode=*/false);
@@ -282,12 +279,6 @@
   }
 }
 
-void FrameSizeButton::SetFeedbackButtonCallback(PressedCallback callback) {
-  // Callback cannot be set on the button here as the multitask menu has not
-  // been created yet, so store it for when it does get created.
-  feedback_callback_ = callback;
-}
-
 bool FrameSizeButton::OnMousePressed(const ui::MouseEvent& event) {
   if (IsTriggerableEvent(event)) {
     StartLongTapDelayTimer(event);
diff --git a/chromeos/ui/frame/caption_buttons/frame_size_button.h b/chromeos/ui/frame/caption_buttons/frame_size_button.h
index 03f4079..2b2ce7d 100644
--- a/chromeos/ui/frame/caption_buttons/frame_size_button.h
+++ b/chromeos/ui/frame/caption_buttons/frame_size_button.h
@@ -58,10 +58,6 @@
   // preview will be deleted and the button will be set back to its normal mode.
   void CancelSnap();
 
-  // Stores the callback in member variable `feedback_callback_` for when
-  // `multitask_menu_` is initialized.
-  void SetFeedbackButtonCallback(PressedCallback callback);
-
   // views::FrameCaptionButton:
   bool OnMousePressed(const ui::MouseEvent& event) override;
   bool OnMouseDragged(const ui::MouseEvent& event) override;
@@ -158,10 +154,6 @@
 
   absl::optional<display::ScopedDisplayObserver> display_observer_;
 
-  // The callback set on the `MultitaskMenuView` feedback button when it
-  // is created.
-  PressedCallback feedback_callback_;
-
   base::WeakPtrFactory<FrameSizeButton> weak_factory_{this};
 };
 
diff --git a/chromeos/ui/frame/caption_buttons/snap_controller.h b/chromeos/ui/frame/caption_buttons/snap_controller.h
index 6394b92..ef3327ba 100644
--- a/chromeos/ui/frame/caption_buttons/snap_controller.h
+++ b/chromeos/ui/frame/caption_buttons/snap_controller.h
@@ -40,6 +40,17 @@
 // The singleton that implements the interface is provided by Ash.
 class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) SnapController {
  public:
+  // The sources of the snap request that are from the window size button.
+  // Currently there can be two sources: either by long pressing on the size
+  // button and then pressing on one of the snap buttons, or by hovering the
+  // size button to show the window layout menu and then pressing on one of the
+  // snap options.
+  enum class SnapRequestSource {
+    kSnapButton,
+    kWindowLayoutMenu,
+    kFromLacrosSnapButtonOrWindowLayoutMenu,
+  };
+
   virtual ~SnapController();
 
   static SnapController* Get();
@@ -57,7 +68,8 @@
   // window, if any.
   virtual void CommitSnap(aura::Window* window,
                           SnapDirection snap,
-                          float snap_ratio) = 0;
+                          float snap_ratio,
+                          SnapRequestSource snap_request_source) = 0;
 
  protected:
   SnapController();
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu.cc b/chromeos/ui/frame/multitask_menu/multitask_menu.cc
index f9cc80a..0215fd7 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu.cc
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu.cc
@@ -27,10 +27,6 @@
 // Padding between the elements.
 constexpr int kPaddingNarrow = 8;
 
-// Dogfood feedback button layout values.
-constexpr int kButtonWidth = 120;
-constexpr int kButtonHeight = 28;
-
 }  // namespace
 
 MultitaskMenu::MultitaskMenu(views::View* anchor,
@@ -65,9 +61,8 @@
       base::BindRepeating(&MultitaskMenu::HideBubble, base::Unretained(this)),
       buttons, close_on_move_out ? anchor : nullptr));
 
-  auto* layout = multitask_menu_view_->SetLayoutManager(
-      std::make_unique<views::TableLayout>());
-  layout->AddPaddingColumn(views::TableLayout::kFixedSize, kPaddingWide)
+  multitask_menu_view_->SetLayoutManager(std::make_unique<views::TableLayout>())
+      ->AddPaddingColumn(views::TableLayout::kFixedSize, kPaddingWide)
       .AddColumn(views::LayoutAlignment::kCenter,
                  views::LayoutAlignment::kCenter,
                  views::TableLayout::kFixedSize,
@@ -82,16 +77,7 @@
       .AddRows(1, views::TableLayout::kFixedSize, 0)
       .AddPaddingRow(views::TableLayout::kFixedSize, kPaddingNarrow)
       .AddRows(1, views::TableLayout::kFixedSize, 0)
-      .AddPaddingRow(views::TableLayout::kFixedSize, kPaddingWide)
-      .AddRows(1, views::TableLayout::kFixedSize, kButtonHeight)
       .AddPaddingRow(views::TableLayout::kFixedSize, kPaddingWide);
-  layout->SetChildViewIgnoredByLayout(multitask_menu_view_->feedback_button(),
-                                      true);
-  auto pref_size = multitask_menu_view_->GetPreferredSize();
-  multitask_menu_view_->feedback_button()->SetBounds(
-      (pref_size.width() - kButtonWidth) / 2,
-      pref_size.height() - kButtonHeight - kPaddingWide, kButtonWidth,
-      kButtonHeight);
 
   display_observer_.emplace(this);
 }
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu.h b/chromeos/ui/frame/multitask_menu/multitask_menu.h
index 32d09c6..763991a 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu.h
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu.h
@@ -34,7 +34,7 @@
   MultitaskMenu& operator=(const MultitaskMenu&) = delete;
   ~MultitaskMenu() override;
 
-  MultitaskMenuView* multitask_menu_view() {
+  MultitaskMenuView* multitask_menu_view_for_testing() {
     return multitask_menu_view_.get();
   }
 
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc b/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
index fc2c0b6..857ad5b 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
@@ -21,7 +21,6 @@
 #include "chromeos/ui/frame/multitask_menu/multitask_button.h"
 #include "chromeos/ui/frame/multitask_menu/multitask_menu_metrics.h"
 #include "chromeos/ui/frame/multitask_menu/split_button_view.h"
-#include "chromeos/ui/vector_icons/vector_icons.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/base/default_style.h"
@@ -29,15 +28,7 @@
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/display/screen.h"
 #include "ui/events/types/event_type.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/paint_vector_icon.h"
-#include "ui/gfx/text_constants.h"
-#include "ui/views/animation/ink_drop.h"
-#include "ui/views/animation/ink_drop_host.h"
 #include "ui/views/background.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/widget/widget.h"
 
@@ -50,18 +41,10 @@
 constexpr int kCenterPadding = 4;
 constexpr int kLabelFontSize = 13;
 
-// Dogfood feedback button layout values.
-constexpr int kButtonHeight = 28;
-// The space between the text and image in the feedback button.
-constexpr int kButtonImageSpacing = 4;
-// Divisor to determine the radius of the rounded corners for the button.
-constexpr float kButtonRadDivisor = 2.f;
-constexpr gfx::Insets kButtonInsets = gfx::Insets::TLBR(0, 6, 0, 8);
-
 // If the menu was opened as a result of hovering over the frame size button,
 // moving the mouse outside the menu or size button will result in closing it
 // after 3 seconds have elapsed.
-constexpr base::TimeDelta kMouseExitMenuTimeout = base::Seconds(3);
+constexpr base::TimeDelta kMouseExitMenuTimeout = base::Milliseconds(250);
 
 // Creates multitask button with label.
 std::unique_ptr<views::View> CreateButtonContainer(
@@ -231,28 +214,6 @@
     float_button_for_testing_ = float_button.get();
     AddChildView(CreateButtonContainer(std::move(float_button), message_id));
   }
-
-  // Dogfood feedback button. This button is added as a child view as it
-  // prevents having to create separate instances in `MultitaskMenu` and
-  // `TabletModeMultitaskMenuView`, and does not require a separate
-  // `LayoutManager`.
-  feedback_button_ = AddChildView(std::make_unique<views::LabelButton>(
-      views::Button::PressedCallback(),
-      l10n_util::GetStringUTF16(IDS_MULTITASK_MENU_FEEDBACK_BUTTON_NAME)));
-
-  feedback_button_->SetImageLabelSpacing(kButtonImageSpacing);
-  feedback_button_->SetBorder(views::CreateEmptyBorder(kButtonInsets));
-  feedback_button_->SetHorizontalAlignment(
-      gfx::HorizontalAlignment::ALIGN_CENTER);
-  feedback_button_->SetBackground(views::CreateThemedRoundedRectBackground(
-      ui::kColorMultitaskFeedbackButtonLabelBackground,
-      kButtonHeight / kButtonRadDivisor));
-
-  views::InkDropHost* const ink_drop = views::InkDrop::Get(feedback_button_);
-  ink_drop->SetMode(views::InkDropHost::InkDropMode::ON);
-  ink_drop->SetBaseColor(SK_ColorGRAY);
-  views::InstallRoundRectHighlightPathGenerator(
-      feedback_button_, gfx::Insets(), kButtonHeight / kButtonRadDivisor);
 }
 
 MultitaskMenuView::~MultitaskMenuView() {
@@ -266,23 +227,6 @@
       GetWidget(), close_callback_, anchor_view_);
 }
 
-void MultitaskMenuView::OnThemeChanged() {
-  // Must be called at the beginning of the function.
-  views::View::OnThemeChanged();
-
-  auto* color_provider = GetColorProvider();
-  feedback_button_->SetTextColor(
-      views::Button::STATE_NORMAL,
-      color_provider->GetColor(
-          ui::kColorMultitaskFeedbackButtonLabelForeground));
-  feedback_button_->SetImage(
-      views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(
-          kDogfoodPawIcon,
-          color_provider->GetColor(
-              ui::kColorMultitaskFeedbackButtonLabelForeground)));
-}
-
 void MultitaskMenuView::OnWindowDestroying(aura::Window* window) {
   CHECK(window_observation_.IsObservingSource(window));
 
@@ -313,16 +257,19 @@
 }
 
 void MultitaskMenuView::SplitButtonPressed(SnapDirection direction) {
-  SnapController::Get()->CommitSnap(window_, direction, kDefaultSnapRatio);
+  SnapController::Get()->CommitSnap(
+      window_, direction, kDefaultSnapRatio,
+      SnapController::SnapRequestSource::kWindowLayoutMenu);
   close_callback_.Run();
   RecordMultitaskMenuActionType(MultitaskMenuActionType::kHalfSplitButton);
 }
 
 void MultitaskMenuView::PartialButtonPressed(SnapDirection direction) {
-  SnapController::Get()->CommitSnap(window_, direction,
-                                    direction == SnapDirection::kPrimary
-                                        ? kTwoThirdSnapRatio
-                                        : kOneThirdSnapRatio);
+  SnapController::Get()->CommitSnap(
+      window_, direction,
+      direction == SnapDirection::kPrimary ? kTwoThirdSnapRatio
+                                           : kOneThirdSnapRatio,
+      SnapController::SnapRequestSource::kWindowLayoutMenu);
   close_callback_.Run();
 
   base::RecordAction(base::UserMetricsAction(
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_view.h b/chromeos/ui/frame/multitask_menu/multitask_menu_view.h
index 3b69cae..9090301 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu_view.h
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu_view.h
@@ -6,10 +6,10 @@
 #define CHROMEOS_UI_FRAME_MULTITASK_MENU_MULTITASK_MENU_VIEW_H_
 
 #include "base/memory/raw_ptr.h"
+#include "base/scoped_observation.h"
 #include "chromeos/ui/frame/caption_buttons/snap_controller.h"
 #include "ui/aura/window_observer.h"
 #include "ui/base/metadata/metadata_header_macros.h"
-#include "ui/views/controls/button/label_button.h"
 #include "ui/views/view.h"
 
 namespace views {
@@ -22,9 +22,7 @@
 class MultitaskButton;
 class SplitButtonView;
 
-// Contains buttons which can fullscreen, snap, or float a window. Also
-// contains a separate button to open a dogfood feedback page, to be removed in
-// M114/launch.
+// Contains buttons which can fullscreen, snap, or float a window.
 class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) MultitaskMenuView
     : public views::View,
       public aura::WindowObserver {
@@ -52,12 +50,8 @@
 
   ~MultitaskMenuView() override;
 
-  SplitButtonView* partial_button() { return partial_button_.get(); }
-  views::LabelButton* feedback_button() { return feedback_button_.get(); }
-
   // views::View:
   void AddedToWidget() override;
-  void OnThemeChanged() override;
 
   // aura::WindowObserver:
   void OnWindowDestroying(aura::Window* parent_window) override;
@@ -72,6 +66,8 @@
   // that 3 second dealy to
   static void SetSkipMouseOutDelayForTesting(bool val);
 
+  SplitButtonView* partial_button() { return partial_button_.get(); }
+
   // For testing.
   SplitButtonView* half_button_for_testing() {
     return half_button_for_testing_.get();
@@ -93,9 +89,8 @@
   void FloatButtonPressed();
 
   raw_ptr<SplitButtonView> partial_button_ = nullptr;
-  raw_ptr<views::LabelButton> feedback_button_ = nullptr;
 
-  // Saved for testing purpose.
+  // Saved for testing purposes.
   raw_ptr<SplitButtonView> half_button_for_testing_ = nullptr;
   raw_ptr<MultitaskButton> full_button_for_testing_ = nullptr;
   raw_ptr<MultitaskButton> float_button_for_testing_ = nullptr;
diff --git a/chromeos/ui/vector_icons/BUILD.gn b/chromeos/ui/vector_icons/BUILD.gn
index a29d9e4..1ac4854 100644
--- a/chromeos/ui/vector_icons/BUILD.gn
+++ b/chromeos/ui/vector_icons/BUILD.gn
@@ -13,7 +13,6 @@
     "assistant.icon",
     "calculate.icon",
     "conversion_path.icon",
-    "dogfood_paw.icon",
     "enterprise.icon",
     "filetype_archive.icon",
     "filetype_audio.icon",
diff --git a/chromeos/ui/vector_icons/dogfood_paw.icon b/chromeos/ui/vector_icons/dogfood_paw.icon
deleted file mode 100644
index d354b3c4..0000000
--- a/chromeos/ui/vector_icons/dogfood_paw.icon
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2023 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, 8.13f, 7.71f,
-R_ARC_TO, 1.46f, 1.46f, 0, 1, 0, 0, -2.92f,
-R_ARC_TO, 1.46f, 1.46f, 0, 0, 0, 0, 2.92f,
-CLOSE,
-R_MOVE_TO, -2.39f, 2.5f,
-R_ARC_TO, 1.46f, 1.46f, 0, 1, 0, 0, -2.92f,
-R_ARC_TO, 1.46f, 1.46f, 0, 0, 0, 0, 2.92f,
-CLOSE,
-R_MOVE_TO, 7.39f, -3.96f,
-R_ARC_TO, 1.46f, 1.46f, 0, 1, 1, -2.92f, 0,
-R_ARC_TO, 1.46f, 1.46f, 0, 0, 1, 2.92f, 0,
-CLOSE,
-R_MOVE_TO, 1.14f, 3.96f,
-R_ARC_TO, 1.46f, 1.46f, 0, 1, 0, 0, -2.92f,
-R_ARC_TO, 1.46f, 1.46f, 0, 0, 0, 0, 2.92f,
-CLOSE,
-R_MOVE_TO, -3.74f, -1.57f,
-R_CUBIC_TO, 0.45f, 0.15f, 0.76f, 0.45f, 1.05f, 0.78f,
-R_CUBIC_TO, 0.15f, 0.17f, 0.29f, 0.35f, 0.44f, 0.53f,
-R_CUBIC_TO, 0.31f, 0.38f, 0.62f, 0.75f, 0.97f, 1.1f,
-R_LINE_TO, 0.23f, 0.23f,
-R_CUBIC_TO, 0.71f, 0.71f, 1.45f, 1.45f, 1.24f, 2.51f,
-R_CUBIC_TO, -0.13f, 0.67f, -0.57f, 1.18f, -1.27f, 1.4f,
-R_CUBIC_TO, -0.19f, 0.06f, -0.64f, 0, -1.22f, -0.07f,
-R_CUBIC_TO, -0.61f, -0.08f, -1.36f, -0.18f, -2.12f, -0.18f,
-R_CUBIC_TO, -0.77f, 0, -1.5f, 0.1f, -2.08f, 0.18f,
-R_CUBIC_TO, -0.53f, 0.07f, -0.93f, 0.13f, -1.12f, 0.07f,
-R_CUBIC_TO, -0.7f, -0.22f, -1.15f, -0.73f, -1.28f, -1.4f,
-R_CUBIC_TO, -0.21f, -1.07f, 0.53f, -1.81f, 1.24f, -2.52f,
-R_LINE_TO, 0.22f, -0.22f,
-R_CUBIC_TO, 0.32f, -0.33f, 0.61f, -0.68f, 0.89f, -1.03f,
-R_CUBIC_TO, 0.16f, -0.2f, 0.32f, -0.4f, 0.49f, -0.59f,
-R_CUBIC_TO, 0.29f, -0.33f, 0.57f, -0.63f, 1.02f, -0.78f,
-R_CUBIC_TO, 0.2f, -0.06f, 0.41f, -0.09f, 0.62f, -0.09f,
-R_CUBIC_TO, 0, 0, 0.49f, 0.03f, 0.69f, 0.09f,
-CLOSE
\ No newline at end of file
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index a6f14a99..b5db5ea 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -493,11 +493,6 @@
 // </div>
 std::u16string InferLabelFromOverlayingSuccessor(
     const WebFormControlElement& element) {
-  if (!base::FeatureList::IsEnabled(
-          features::kAutofillSupportPoorMansPlaceholder)) {
-    return std::u16string();
-  }
-
   WebNode next = element.NextSibling();
   while (!next.IsNull() && !next.IsElementNode())
     next = next.NextSibling();
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 8315f46..c5c4d2f 100644
--- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -51,8 +51,7 @@
 using ::testing::ElementsAre;
 using ::testing::Values;
 
-namespace autofill {
-namespace form_util {
+namespace autofill::form_util {
 namespace {
 
 struct AutofillFieldUtilCase {
@@ -233,9 +232,6 @@
 }
 
 TEST_F(FormAutofillUtilsTest, InferLabelForElementTest) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kAutofillSupportPoorMansPlaceholder);
-
   static const AutofillFieldUtilCase test_cases[] = {
       {"DIV table test 1", R"(
        <div>
@@ -298,9 +294,6 @@
 }
 
 TEST_F(FormAutofillUtilsTest, InferLabelSourceTest) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kAutofillSupportPoorMansPlaceholder);
-
   struct AutofillFieldLabelSourceCase {
     const char* html;
     const FormFieldData::LabelSource label_source;
@@ -1760,5 +1753,4 @@
 }
 
 }  // namespace
-}  // namespace form_util
-}  // namespace autofill
+}  // namespace autofill::form_util
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 3dc6299..12e0787 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -501,13 +501,6 @@
              "AutofillSplitCreditCardNumbersCautiously",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enables support for artificial placeholders, implemented by placing text on
-// top of the input field using CSS.
-// TODO(crbug.com/1396374): Remove when launched.
-BASE_FEATURE(kAutofillSupportPoorMansPlaceholder,
-             "AutofillSupportPoorMansPlaceholder",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Controls whether Autofill should search prefixes of all words/tokens when
 // filtering profiles, or only on prefixes of the whole string.
 BASE_FEATURE(kAutofillTokenPrefixMatching,
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index edccb06..fbe3e08 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -177,8 +177,6 @@
 BASE_DECLARE_FEATURE(kAutofillSplitCreditCardNumbersCautiously);
 COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillTokenPrefixMatching);
 COMPONENT_EXPORT(AUTOFILL)
-BASE_DECLARE_FEATURE(kAutofillSupportPoorMansPlaceholder);
-COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillUseAlternativeStateNameMap);
 COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(kAutofillUseImprovedLabelDisambiguation);
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc
index 8a38173b..592bccb 100644
--- a/components/content_settings/core/common/content_settings.cc
+++ b/components/content_settings/core/common/content_settings.cc
@@ -41,7 +41,6 @@
     {ContentSettingsType::MEDIASTREAM_MIC, 12},
     {ContentSettingsType::MEDIASTREAM_CAMERA, 13},
     {ContentSettingsType::PROTOCOL_HANDLERS, 14},
-    // Removed PPAPI_BROKER in M114.
     {ContentSettingsType::AUTOMATIC_DOWNLOADS, 16},
     {ContentSettingsType::MIDI_SYSEX, 17},
     {ContentSettingsType::SSL_CERT_DECISIONS, 19},
diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h
index dc56439f..4eb53ed 100644
--- a/components/content_settings/core/common/content_settings_types.h
+++ b/components/content_settings/core/common/content_settings_types.h
@@ -35,6 +35,7 @@
   MEDIASTREAM_MIC,
   MEDIASTREAM_CAMERA,
   PROTOCOL_HANDLERS,
+  DEPRECATED_PPAPI_BROKER,
   AUTOMATIC_DOWNLOADS,
   MIDI_SYSEX,
   SSL_CERT_DECISIONS,
diff --git a/components/crash/core/common/BUILD.gn b/components/crash/core/common/BUILD.gn
index 1fd713f..57c02da 100644
--- a/components/crash/core/common/BUILD.gn
+++ b/components/crash/core/common/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/buildflag_header.gni")
 import("//build/config/cronet/config.gni")
+import("//build/config/features.gni")
 import("//components/gwp_asan/buildflags/buildflags.gni")
 
 declare_args() {
@@ -26,15 +27,17 @@
   }
 }
 
-use_crashpad_annotation = (is_mac || is_win || is_android ||
-                           (is_linux && !is_castos)) && !use_crash_key_stubs
+use_crashpad_annotation =
+    (is_mac || (is_ios && use_blink && !is_official_build) || is_win ||
+     is_android || (is_linux && !is_castos)) && !use_crash_key_stubs
 
 # Causes both Crashpad and Breakpad crash keys to be used. Both key
 # implementations will be instantiated and set, doubling the storage
 # used for keys. This is intended to be used temporarily to test Crashpad
 # integrations without disabling Breakpad.
 use_combined_annotations =
-    ((is_ios && !is_cronet_build) || is_chromeos) && !use_crash_key_stubs
+    ((is_ios && (!use_blink || is_official_build) && !is_cronet_build) ||
+     is_chromeos) && !use_crash_key_stubs
 
 buildflag_header("crash_buildflags") {
   header = "crash_buildflags.h"
@@ -189,7 +192,7 @@
     sources += [ "objc_zombie_unittest.mm" ]
   }
 
-  if (is_ios) {
+  if (is_ios && use_combined_annotations) {
     sources += [ "crash_key_breakpad_ios_unittest.cc" ]
     deps += [ "//third_party/breakpad:client" ]
     include_dirs = [ "//third_party/breakpad/breakpad/src/" ]
diff --git a/components/enterprise/browser/reporting/policy_info.cc b/components/enterprise/browser/reporting/policy_info.cc
index eb6698f2..f50a991 100644
--- a/components/enterprise/browser/reporting/policy_info.cc
+++ b/components/enterprise/browser/reporting/policy_info.cc
@@ -134,8 +134,10 @@
 
   for (auto extension_iter : *policies.FindDict("extensionPolicies")) {
     const base::Value& policies_value = extension_iter.second;
-    if (policies_value.DictSize() == 0)
+    if (policies_value.GetDict().size() == 0) {
       continue;
+    }
+
     auto* extension = profile_info->add_extension_policies();
     extension->set_extension_id(extension_iter.first);
     for (auto policy_iter : policies_value.GetDict()) {
diff --git a/components/exo/DEPS b/components/exo/DEPS
index ca401e9..9612462 100644
--- a/components/exo/DEPS
+++ b/components/exo/DEPS
@@ -25,14 +25,12 @@
 ]
 
 specific_include_rules = {
-  "surface_unittest\.cc": [
-    "+components/viz/test",
-  ],
   ".*test.*\.cc": [
     "+chromeos/ash/components/test",
     "+chromeos/ui/wm",
     "+components/viz/service/frame_sinks",
     "+components/viz/service/surfaces",
+    "+components/viz/test",
   ],
   "ui_lock_controller_unittest\.cc": [
     "+chromeos/dbus/power",
diff --git a/components/exo/buffer_unittest.cc b/components/exo/buffer_unittest.cc
index b783c69..b45c219 100644
--- a/components/exo/buffer_unittest.cc
+++ b/components/exo/buffer_unittest.cc
@@ -17,11 +17,11 @@
 #include "components/exo/test/exo_test_helper.h"
 #include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/test/surface_tree_host_test_util.h"
+#include "components/viz/test/test_in_process_context_provider.h"
 #include "gpu/command_buffer/client/raster_interface.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/env.h"
 #include "ui/compositor/compositor.h"
-#include "ui/compositor/test/in_process_context_provider.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/gpu_fence_handle.h"
 #include "ui/gfx/gpu_memory_buffer.h"
@@ -268,7 +268,7 @@
           ->context_factory()
           ->SharedMainThreadRasterContextProvider()
           .get();
-  static_cast<ui::InProcessContextProvider*>(context_provider)
+  static_cast<viz::TestInProcessContextProvider*>(context_provider)
       ->SendOnContextLost();
 }
 
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 90d89ec..5f6b39e 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -65,6 +65,7 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/widget/widget.h"
+#include "ui/views/window/caption_button_types.h"
 #include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/core/window_util.h"
 
@@ -241,9 +242,22 @@
 
   // Overridden from ash::CaptionButtonModel:
   bool IsVisible(views::CaptionButtonIcon icon) const override {
+    // TODO(b/276933044): Remove this workaround when ARC is uprevved.
+    if (icon == views::CaptionButtonIcon::CAPTION_BUTTON_ICON_FLOAT) {
+      return !(
+          visible_button_mask_ &
+          (1
+           << views::CaptionButtonIcon::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE));
+    }
     return visible_button_mask_ & (1 << icon);
   }
   bool IsEnabled(views::CaptionButtonIcon icon) const override {
+    if (icon == views::CaptionButtonIcon::CAPTION_BUTTON_ICON_FLOAT) {
+      return !(
+          enabled_button_mask_ &
+          (1
+           << views::CaptionButtonIcon::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE));
+    }
     return enabled_button_mask_ & (1 << icon);
   }
   bool InZoomMode() const override {
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index a28ccb12..bd91258 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1377,12 +1377,22 @@
     shell_surface->SetFrameButtons(visible_buttons, 0);
     const chromeos::CaptionButtonModel* model = container->model();
     for (auto not_visible : kAllButtons) {
-      if (not_visible != visible) {
+      if (not_visible == views::CAPTION_BUTTON_ICON_FLOAT) {
+        // Float is dependent only on maximize/restore.
+        EXPECT_EQ(
+            !model->IsVisible(views::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE),
+            model->IsVisible(views::CAPTION_BUTTON_ICON_FLOAT));
+      } else if (not_visible != visible) {
         EXPECT_FALSE(model->IsVisible(not_visible));
       }
     }
     EXPECT_TRUE(model->IsVisible(visible));
-    EXPECT_FALSE(model->IsEnabled(visible));
+    if (visible == views::CAPTION_BUTTON_ICON_FLOAT) {
+      EXPECT_EQ(!model->IsEnabled(views::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE),
+                model->IsEnabled(views::CAPTION_BUTTON_ICON_FLOAT));
+    } else {
+      EXPECT_FALSE(model->IsEnabled(visible));
+    }
   }
 
   // Enable
@@ -1391,12 +1401,22 @@
     shell_surface->SetFrameButtons(kAllButtonMask, enabled_buttons);
     const chromeos::CaptionButtonModel* model = container->model();
     for (auto not_enabled : kAllButtons) {
-      if (not_enabled != enabled) {
+      if (not_enabled == views::CAPTION_BUTTON_ICON_FLOAT) {
+        // Float is dependent only on maximize/restore.
+        EXPECT_EQ(
+            !model->IsEnabled(views::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE),
+            model->IsEnabled(views::CAPTION_BUTTON_ICON_FLOAT));
+      } else if (not_enabled != enabled) {
         EXPECT_FALSE(model->IsEnabled(not_enabled));
       }
     }
     EXPECT_TRUE(model->IsEnabled(enabled));
-    EXPECT_TRUE(model->IsVisible(enabled));
+    if (enabled == views::CAPTION_BUTTON_ICON_FLOAT) {
+      EXPECT_EQ(!model->IsVisible(views::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE),
+                model->IsVisible(views::CAPTION_BUTTON_ICON_FLOAT));
+    } else {
+      EXPECT_TRUE(model->IsVisible(enabled));
+    }
   }
 
   // Zoom mode
@@ -1857,7 +1877,7 @@
 
   EnableTabletMode(true);
 
-  ash::WMEvent event(ash::WM_EVENT_SNAP_PRIMARY);
+  ash::WindowSnapWMEvent event(ash::WM_EVENT_SNAP_PRIMARY);
   window_state->OnWMEvent(&event);
   EXPECT_EQ(window_state->GetStateType(), WindowStateType::kPrimarySnapped);
 
@@ -2420,7 +2440,7 @@
   surface->Commit();
   EXPECT_EQ(gfx::Rect(50, 68, 200, 332), widget->GetWindowBoundsInScreen());
 
-  ash::WMEvent event(ash::WM_EVENT_SNAP_PRIMARY);
+  ash::WindowSnapWMEvent event(ash::WM_EVENT_SNAP_PRIMARY);
   ash::WindowState::Get(window)->OnWMEvent(&event);
   EXPECT_EQ(gfx::Rect(0, 32, 400, 568), delegate->requested_bounds().back());
 
@@ -2466,6 +2486,19 @@
   surface->Commit();
   EXPECT_FALSE(shell_surface->CanResize());
 
+  // Test that the float caption button is visible on unresizable apps.
+  EXPECT_TRUE(chromeos::wm::CanFloatWindow(
+      shell_surface->GetWidget()->GetNativeWindow()));
+  ash::NonClientFrameViewAsh* frame_view =
+      static_cast<ash::NonClientFrameViewAsh*>(
+          shell_surface->GetWidget()->non_client_view()->frame_view());
+  const chromeos::CaptionButtonModel* model =
+      static_cast<chromeos::HeaderView*>(frame_view->GetHeaderView())
+          ->caption_button_container()
+          ->model();
+  EXPECT_TRUE(model->IsVisible(views::CAPTION_BUTTON_ICON_FLOAT));
+  EXPECT_TRUE(model->IsEnabled(views::CAPTION_BUTTON_ICON_FLOAT));
+
   shell_surface->SetResizeLockType(
       ash::ArcResizeLockType::RESIZE_ENABLED_TOGGLABLE);
   surface->Commit();
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 47b37965..8824cffc 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -291,8 +291,10 @@
 void CommitSnap(aura::Window* window,
                 chromeos::SnapDirection snap_direction,
                 float snap_ratio) {
-  chromeos::SnapController::Get()->CommitSnap(window, snap_direction,
-                                              snap_ratio);
+  chromeos::SnapController::Get()->CommitSnap(
+      window, snap_direction, snap_ratio,
+      chromeos::SnapController::SnapRequestSource::
+          kFromLacrosSnapButtonOrWindowLayoutMenu);
 }
 
 }  // namespace
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index c1b309dd..c67ba10 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -1261,7 +1261,7 @@
   EXPECT_EQ(buffer_size,
             shell_surface->GetWidget()->GetWindowBoundsInScreen().size());
 
-  ash::WMEvent event(ash::WM_EVENT_CYCLE_SNAP_PRIMARY);
+  ash::WindowSnapWMEvent event(ash::WM_EVENT_CYCLE_SNAP_PRIMARY);
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
 
   // Enter snapped mode.
@@ -2995,7 +2995,8 @@
   // Make sure we are in a non-snapped state before testing state change.
   ASSERT_FALSE(state->IsSnapped());
 
-  auto snap_event = std::make_unique<ash::WMEvent>(ash::WM_EVENT_SNAP_PRIMARY);
+  auto snap_event =
+      std::make_unique<ash::WindowSnapWMEvent>(ash::WM_EVENT_SNAP_PRIMARY);
 
   // Trigger a snap event, this should cause a configure event.
   state->OnWMEvent(snap_event.get());
diff --git a/components/exo/wayland/zcr_remote_shell_impl_unittest.cc b/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
index 4adef3a..fb0fcc9 100644
--- a/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
+++ b/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
@@ -248,7 +248,7 @@
   auto* const window = widget->GetNativeWindow();
 
   // Snap window.
-  ash::WMEvent event(ash::WM_EVENT_SNAP_PRIMARY);
+  ash::WindowSnapWMEvent event(ash::WM_EVENT_SNAP_PRIMARY);
   ash::WindowState::Get(window)->OnWMEvent(&event);
   shell_surface->SetSnapPrimary(chromeos::kDefaultSnapRatio);
   shell_surface->SetGeometry(gfx::Rect(0, 0, 400, 520));
diff --git a/components/feedback/redaction_tool/redaction_tool.cc b/components/feedback/redaction_tool/redaction_tool.cc
index 7bbeb9e92..7e605cf 100644
--- a/components/feedback/redaction_tool/redaction_tool.cc
+++ b/components/feedback/redaction_tool/redaction_tool.cc
@@ -629,7 +629,7 @@
       // If not found, build up a replacement MAC address by generating a new
       // NIC part.
       int mac_id = mac_addresses_.size() - kNumUnredactedMacs;
-      replacement_mac = base::StringPrintf("[MAC OUI=%s IFACE=%d]",
+      replacement_mac = base::StringPrintf("(MAC OUI=%s IFACE=%d)",
                                            oui_string.c_str(), mac_id);
       mac_addresses_[mac] = replacement_mac;
     }
@@ -691,7 +691,7 @@
     if (replacement_hash.empty()) {
       // If not found, build up a replacement value.
       replacement_hash = base::StringPrintf(
-          "<HASH:%s %zd>", hash_prefix_string.c_str(), hashes_.size());
+          "(HASH:%s %zd)", hash_prefix_string.c_str(), hashes_.size());
       hashes_[hash] = replacement_hash;
     }
     if (detected != nullptr) {
@@ -833,7 +833,7 @@
       // The weird NumberToString trick is because Windows does not like
       // to deal with %zu and a size_t in printf, nor does it support %llu.
       replacement_id = base::StringPrintf(
-          "<%s: %s>", pattern.alias,
+          "(%s: %s)", pattern.alias,
           base::NumberToString(identifier_space->size() + 1).c_str());
       (*identifier_space)[matched_id_as_string] = replacement_id;
     } else {
@@ -951,7 +951,7 @@
         // The weird NumberToString trick is because Windows does not like
         // to deal with %zu and a size_t in printf, nor does it support %llu.
         replacement_id = base::StringPrintf(
-            "<%s: %s>",
+            "(%s: %s)",
             replacement_id.empty() ? pattern.alias : replacement_id.c_str(),
             base::NumberToString(identifier_space->size() + 1).c_str());
         (*identifier_space)[matched_id_as_string] = replacement_id;
diff --git a/components/feedback/redaction_tool/redaction_tool_unittest.cc b/components/feedback/redaction_tool/redaction_tool_unittest.cc
index 0fc9dd9..8e67cbff 100644
--- a/components/feedback/redaction_tool/redaction_tool_unittest.cc
+++ b/components/feedback/redaction_tool/redaction_tool_unittest.cc
@@ -33,72 +33,72 @@
 // the input and output of the redactor.
 const StringWithRedaction kStringsWithRedactions[] = {
     {"aaaaaaaa [SSID=123aaaaaa]aaaaa",  // SSID.
-     "aaaaaaaa [SSID=<SSID: 1>]aaaaa", PIIType::kSSID},
+     "aaaaaaaa [SSID=(SSID: 1)]aaaaa", PIIType::kSSID},
     {"aaaaaaaahttp://tets.comaaaaaaa",  // URL.
-     "aaaaaaaa<URL: 1>", PIIType::kURL},
+     "aaaaaaaa(URL: 1)", PIIType::kURL},
     {"u:object_r:system_data_file:s0:c512,c768",  // No PII, it is an SELinux
                                                   // context.
      "u:object_r:system_data_file:s0:c512,c768", PIIType::kNone},
     {"aaaaaemail@example.comaaa",  // Email address.
-     "<email: 1>", PIIType::kEmail},
+     "(email: 1)", PIIType::kEmail},
     {"example@@1234",  // No PII, it is not a valid email address.
      "example@@1234", PIIType::kNone},
     {"255.255.155.2",  // IP address.
-     "<IPv4: 1>", PIIType::kIPAddress},
+     "(IPv4: 1)", PIIType::kIPAddress},
     {"255.255.155.255",  // IP address.
-     "<IPv4: 2>", PIIType::kIPAddress},
+     "(IPv4: 2)", PIIType::kIPAddress},
     {"127.0.0.1",  // IPv4 loopback.
-     "<127.0.0.0/8: 3>", PIIType::kIPAddress},
+     "(127.0.0.0/8: 3)", PIIType::kIPAddress},
     {"127.255.0.1",  // IPv4 loopback.
-     "<127.0.0.0/8: 4>", PIIType::kIPAddress},
+     "(127.0.0.0/8: 4)", PIIType::kIPAddress},
     {"0.0.0.0",  // Any IPv4.
-     "<0.0.0.0/8: 5>", PIIType::kIPAddress},
+     "(0.0.0.0/8: 5)", PIIType::kIPAddress},
     {"0.255.255.255",  // Any IPv4.
-     "<0.0.0.0/8: 6>", PIIType::kIPAddress},
+     "(0.0.0.0/8: 6)", PIIType::kIPAddress},
     {"10.10.10.100",  // IPv4 private class A.
-     "<10.0.0.0/8: 7>", PIIType::kIPAddress},
+     "(10.0.0.0/8: 7)", PIIType::kIPAddress},
     {"10.10.10.100",  // Intentional duplicate.
-     "<10.0.0.0/8: 7>", PIIType::kIPAddress},
+     "(10.0.0.0/8: 7)", PIIType::kIPAddress},
     {"10.10.10.101",  // IPv4 private class A.
-     "<10.0.0.0/8: 8>", PIIType::kIPAddress},
+     "(10.0.0.0/8: 8)", PIIType::kIPAddress},
     {"10.255.255.255",  // IPv4 private class A.
-     "<10.0.0.0/8: 9>", PIIType::kIPAddress},
+     "(10.0.0.0/8: 9)", PIIType::kIPAddress},
     {"172.16.0.0",  // IPv4 private class B.
-     "<172.16.0.0/12: 10>", PIIType::kIPAddress},
+     "(172.16.0.0/12: 10)", PIIType::kIPAddress},
     {"172.31.255.255",  // IPv4 private class B.
-     "<172.16.0.0/12: 11>", PIIType::kIPAddress},
+     "(172.16.0.0/12: 11)", PIIType::kIPAddress},
     {"172.11.5.5",  // IP address.
-     "<IPv4: 12>", PIIType::kIPAddress},
+     "(IPv4: 12)", PIIType::kIPAddress},
     {"172.111.5.5",  // IP address.
-     "<IPv4: 13>", PIIType::kIPAddress},
+     "(IPv4: 13)", PIIType::kIPAddress},
     {"192.168.0.0",  // IPv4 private class C.
-     "<192.168.0.0/16: 14>", PIIType::kIPAddress},
+     "(192.168.0.0/16: 14)", PIIType::kIPAddress},
     {"192.168.255.255",  // IPv4 private class C.
-     "<192.168.0.0/16: 15>", PIIType::kIPAddress},
+     "(192.168.0.0/16: 15)", PIIType::kIPAddress},
     {"192.169.2.120",  // IP address.
-     "<IPv4: 16>", PIIType::kIPAddress},
+     "(IPv4: 16)", PIIType::kIPAddress},
     {"169.254.0.1",  // Link local.
-     "<169.254.0.0/16: 17>", PIIType::kIPAddress},
+     "(169.254.0.0/16: 17)", PIIType::kIPAddress},
     {"169.200.0.1",  // IP address.
-     "<IPv4: 18>", PIIType::kIPAddress},
+     "(IPv4: 18)", PIIType::kIPAddress},
     {"fe80::",  // Link local.
-     "<fe80::/10: 1>", PIIType::kIPAddress},
+     "(fe80::/10: 1)", PIIType::kIPAddress},
     {"fe80::ffff",  // Link local.
-     "<fe80::/10: 2>", PIIType::kIPAddress},
+     "(fe80::/10: 2)", PIIType::kIPAddress},
     {"febf:ffff::ffff",  // Link local.
-     "<fe80::/10: 3>", PIIType::kIPAddress},
+     "(fe80::/10: 3)", PIIType::kIPAddress},
     {"fecc::1111",  // IP address.
-     "<IPv6: 4>", PIIType::kIPAddress},
+     "(IPv6: 4)", PIIType::kIPAddress},
     {"224.0.0.24",  // Multicast.
-     "<224.0.0.0/4: 19>", PIIType::kIPAddress},
+     "(224.0.0.0/4: 19)", PIIType::kIPAddress},
     {"240.0.0.0",  // IP address.
-     "<IPv4: 20>", PIIType::kIPAddress},
+     "(IPv4: 20)", PIIType::kIPAddress},
     {"255.255.255.255",  // Broadcast.
      "255.255.255.255", PIIType::kNone},
     {"100.115.92.92",  // ChromeOS.
      "100.115.92.92", PIIType::kNone},
     {"100.115.91.92",  // IP address.
-     "<IPv4: 21>", PIIType::kIPAddress},
+     "(IPv4: 21)", PIIType::kIPAddress},
     {"1.1.1.1",  // DNS
      "1.1.1.1", PIIType::kNone},
     {"8.8.8.8",  // DNS
@@ -106,7 +106,7 @@
     {"8.8.4.4",  // DNS
      "8.8.4.4", PIIType::kNone},
     {"8.8.8.4",  // IP address.
-     "<IPv4: 22>", PIIType::kIPAddress},
+     "(IPv4: 22)", PIIType::kIPAddress},
     {"255.255.259.255",  // Not an IP address.
      "255.255.259.255", PIIType::kNone},
     {"255.300.255.255",  // Not an IP address.
@@ -116,11 +116,11 @@
     {"Revision: 81600.0000.00.29.19.16_DO",  // Modem firmware
      "Revision: 81600.0000.00.29.19.16_DO", PIIType::kNone},
     {"aaaa123.123.45.4aaa",  // IP address.
-     "aaaa<IPv4: 23>aaa", PIIType::kIPAddress},
+     "aaaa(IPv4: 23)aaa", PIIType::kIPAddress},
     {"11:11;11::11",  // IP address.
-     "11:11;<IPv6: 5>", PIIType::kIPAddress},
+     "11:11;(IPv6: 5)", PIIType::kIPAddress},
     {"11::11",  // IP address.
-     "<IPv6: 5>", PIIType::kIPAddress},
+     "(IPv6: 5)", PIIType::kIPAddress},
     {"11:11:abcdef:0:0:0:0:0",  // No PII.
      "11:11:abcdef:0:0:0:0:0", PIIType::kNone},
     {"::",  // Unspecified.
@@ -138,39 +138,39 @@
     {"ff01::2",  // All routers (interface local).
      "ff01::2", PIIType::kNone},
     {"ff01::3",  // Multicast (interface local).
-     "<ff01::/16: 6>", PIIType::kIPAddress},
+     "(ff01::/16: 6)", PIIType::kIPAddress},
     {"ff02::1",  // All nodes address (link local).
      "ff02::1", PIIType::kNone},
     {"ff02::2",  // All routers (link local).
      "ff02::2", PIIType::kNone},
     {"ff02::3",  // Multicast (link local).
-     "<ff02::/16: 7>", PIIType::kIPAddress},
+     "(ff02::/16: 7)", PIIType::kIPAddress},
     {"ff02::fb",  // mDNSv6 (link local).
-     "<ff02::/16: 8>", PIIType::kIPAddress},
+     "(ff02::/16: 8)", PIIType::kIPAddress},
     {"ff08::fb",  // mDNSv6.
-     "<IPv6: 9>", PIIType::kIPAddress},
+     "(IPv6: 9)", PIIType::kIPAddress},
     {"ff0f::101",  // All NTP servers.
-     "<IPv6: 10>", PIIType::kIPAddress},
+     "(IPv6: 10)", PIIType::kIPAddress},
     {"::ffff:cb0c:10ea",  // IPv4-mapped IPV6 (IP address).
-     "<IPv6: 11>", PIIType::kIPAddress},
+     "(IPv6: 11)", PIIType::kIPAddress},
     {"::ffff:a0a:a0a",  // IPv4-mapped IPV6 (private class A).
-     "<M 10.0.0.0/8: 12>", PIIType::kIPAddress},
+     "(M 10.0.0.0/8: 12)", PIIType::kIPAddress},
     {"::ffff:a0a:a0a",  // Intentional duplicate.
-     "<M 10.0.0.0/8: 12>", PIIType::kIPAddress},
+     "(M 10.0.0.0/8: 12)", PIIType::kIPAddress},
     {"::ffff:ac1e:1e1e",  // IPv4-mapped IPV6 (private class B).
-     "<M 172.16.0.0/12: 13>", PIIType::kIPAddress},
+     "(M 172.16.0.0/12: 13)", PIIType::kIPAddress},
     {"::ffff:c0a8:640a",  // IPv4-mapped IPV6 (private class C).
-     "<M 192.168.0.0/16: 14>", PIIType::kIPAddress},
+     "(M 192.168.0.0/16: 14)", PIIType::kIPAddress},
     {"::ffff:6473:5c01",  // IPv4-mapped IPV6 (Chrome).
-     "<M 100.115.92.1: 15>", PIIType::kIPAddress},
+     "(M 100.115.92.1: 15)", PIIType::kIPAddress},
     {"64:ff9b::a0a:a0a",  // IPv4-translated 6to4 IPV6 (private class A).
-     "<T 10.0.0.0/8: 16>", PIIType::kIPAddress},
+     "(T 10.0.0.0/8: 16)", PIIType::kIPAddress},
     {"64:ff9b::6473:5c01",  // IPv4-translated 6to4 IPV6 (Chrome).
-     "<T 100.115.92.1: 17>", PIIType::kIPAddress},
+     "(T 100.115.92.1: 17)", PIIType::kIPAddress},
     {"::0101:ffff:c0a8:640a",  // IP address.
-     "<IPv6: 18>", PIIType::kIPAddress},
+     "(IPv6: 18)", PIIType::kIPAddress},
     {"aa:aa:aa:aa:aa:aa",  // MAC address (BSSID).
-     "[MAC OUI=aa:aa:aa IFACE=1]", PIIType::kMACAddress},
+     "(MAC OUI=aa:aa:aa IFACE=1)", PIIType::kMACAddress},
     {"chrome://resources/foo",  // Secure chrome resource, exempt.
      "chrome://resources/foo", PIIType::kNone},
     {"chrome://settings/crisper.js",  // Exempt settings URLs.
@@ -180,14 +180,14 @@
      "chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
      PIIType::kNone},
     {"chrome://resources/f?user=bar",  // Potentially PII in parameter.
-     "<URL: 2>", PIIType::kURL},
+     "(URL: 2)", PIIType::kURL},
     {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js?bar=x",
-     "<URL: 3>", PIIType::kURL},  // Potentially PII in parameter.
+     "(URL: 3)", PIIType::kURL},  // Potentially PII in parameter.
     {"isolated-app://airugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaac/",
-     "<URL: 4>", PIIType::kURL},  // URL
+     "(URL: 4)", PIIType::kURL},  // URL
     {"/root/27540283740a0897ab7c8de0f809add2bacde78f/foo",
-     "/root/<HASH:2754 1>/foo", PIIType::kStableIdentifier},  // Hash string.
-    {"B3mcFTkQAHofv94DDTUuVJGGEI/BbzsyDncplMCR2P4=", "<UID: 1>",
+     "/root/(HASH:2754 1)/foo", PIIType::kStableIdentifier},  // Hash string.
+    {"B3mcFTkQAHofv94DDTUuVJGGEI/BbzsyDncplMCR2P4=", "(UID: 1)",
      PIIType::kStableIdentifier},
 #if BUILDFLAG(IS_CHROMEOS_ASH)  // We only redact Android paths on Chrome OS.
     // Allowed android storage path.
@@ -241,26 +241,26 @@
   EXPECT_EQ("foo\nbar\n", redactor_.Redact("foo\nbar\n"));
 
   // Make sure MAC address redaction is invoked.
-  EXPECT_EQ("[MAC OUI=02:46:8a IFACE=1]",
+  EXPECT_EQ("(MAC OUI=02:46:8a IFACE=1)",
             redactor_.Redact("02:46:8a:ce:13:57"));
 
   // Make sure hash redaction is invoked.
-  EXPECT_EQ("<HASH:1122 1>",
+  EXPECT_EQ("(HASH:1122 1)",
             redactor_.Redact("11223344556677889900AABBCCDDEEFF"));
 
   // Make sure custom pattern redaction is invoked.
-  EXPECT_EQ("Cell ID: '<CellID: 1>'", RedactCustomPatterns("Cell ID: 'A1B2'"));
+  EXPECT_EQ("Cell ID: '(CellID: 1)'", RedactCustomPatterns("Cell ID: 'A1B2'"));
 
   // Make sure UUIDs are redacted.
   EXPECT_EQ(
-      "REQUEST localhost - - \"POST /printers/<UUID: 1> HTTP/1.1\" 200 291 "
+      "REQUEST localhost - - \"POST /printers/(UUID: 1) HTTP/1.1\" 200 291 "
       "Create-Job successful-ok",
       redactor_.Redact(
           "REQUEST localhost - - \"POST /printers/"
           "cb738a9f-6433-4d95-a81e-94e4ae0ed30b HTTP/1.1\" 200 291 Create-Job "
           "successful-ok"));
   EXPECT_EQ(
-      "REQUEST localhost - - \"POST /printers/<UUID: 2> HTTP/1.1\" 200 286 "
+      "REQUEST localhost - - \"POST /printers/(UUID: 2) HTTP/1.1\" 200 286 "
       "Create-Job successful-ok",
       redactor_.Redact(
           "REQUEST localhost - - \"POST /printers/"
@@ -272,28 +272,28 @@
   EXPECT_EQ("", RedactMACAddresses(""));
   EXPECT_EQ("foo\nbar\n", RedactMACAddresses("foo\nbar\n"));
   EXPECT_EQ("11:22:33:44:55", RedactMACAddresses("11:22:33:44:55"));
-  EXPECT_EQ("[MAC OUI=aa:bb:cc IFACE=1]",
+  EXPECT_EQ("(MAC OUI=aa:bb:cc IFACE=1)",
             RedactMACAddresses("aa:bb:cc:dd:ee:ff"));
-  EXPECT_EQ("[MAC OUI=aa:bb:cc IFACE=1]",
+  EXPECT_EQ("(MAC OUI=aa:bb:cc IFACE=1)",
             RedactMACAddresses("aa_bb_cc_dd_ee_ff"));
-  EXPECT_EQ("[MAC OUI=aa:bb:cc IFACE=1]",
+  EXPECT_EQ("(MAC OUI=aa:bb:cc IFACE=1)",
             RedactMACAddresses("aa-bb-cc-dd-ee-ff"));
   EXPECT_EQ("00:00:00:00:00:00", RedactMACAddresses("00:00:00:00:00:00"));
   EXPECT_EQ("ff:ff:ff:ff:ff:ff", RedactMACAddresses("ff:ff:ff:ff:ff:ff"));
   EXPECT_EQ(
-      "BSSID: [MAC OUI=aa:bb:cc IFACE=1] in the middle\n"
-      "[MAC OUI=bb:cc:dd IFACE=2] start of line\n"
-      "end of line [MAC OUI=aa:bb:cc IFACE=1]\n"
+      "BSSID: (MAC OUI=aa:bb:cc IFACE=1) in the middle\n"
+      "(MAC OUI=bb:cc:dd IFACE=2) start of line\n"
+      "end of line (MAC OUI=aa:bb:cc IFACE=1)\n"
       "no match across lines aa:bb:cc:\n"
       "dd:ee:ff two on the same line:\n"
-      "x [MAC OUI=bb:cc:dd IFACE=2] [MAC OUI=cc:dd:ee IFACE=3] x\n",
+      "x (MAC OUI=bb:cc:dd IFACE=2) (MAC OUI=cc:dd:ee IFACE=3) x\n",
       RedactMACAddresses("BSSID: aa:bb:cc:dd:ee:ff in the middle\n"
                          "bb:cc:dd:ee:ff:00 start of line\n"
                          "end of line aa:bb:cc:dd:ee:ff\n"
                          "no match across lines aa:bb:cc:\n"
                          "dd:ee:ff two on the same line:\n"
                          "x bb:cc:dd:ee:ff:00 cc:dd:ee:ff:00:11 x\n"));
-  EXPECT_EQ("Remember [MAC OUI=bb:cc:dd IFACE=2]?",
+  EXPECT_EQ("Remember (MAC OUI=bb:cc:dd IFACE=2)?",
             RedactMACAddresses("Remember bB:Cc:DD:ee:ff:00?"));
 }
 
@@ -312,26 +312,26 @@
       RedactHashes("11223344556677889900aabbccddeeff11223344556677889900aabb"
                    "ccddeeff11"));
   // Test all 3 valid lengths.
-  EXPECT_EQ("<HASH:aabb 1>", RedactHashes("aabbccddeeff00112233445566778899"));
-  EXPECT_EQ("<HASH:aabb 2>",
+  EXPECT_EQ("(HASH:aabb 1)", RedactHashes("aabbccddeeff00112233445566778899"));
+  EXPECT_EQ("(HASH:aabb 2)",
             RedactHashes("aabbccddeeff00112233445566778899aabbccdd"));
   EXPECT_EQ(
-      "<HASH:9988 3>",
+      "(HASH:9988 3)",
       RedactHashes(
           "99887766554433221100ffeeddccbbaaaabbccddeeff00112233445566778899"));
   // Skip 32 byte hashes that have a at least 3 whitespace chars before it.
-  EXPECT_EQ("  <HASH:aabb 1>",
+  EXPECT_EQ("  (HASH:aabb 1)",
             RedactHashes("  aabbccddeeff00112233445566778899"));
   EXPECT_EQ("   aabbccddeeff00112233445566778899",
             RedactHashes("   aabbccddeeff00112233445566778899"));
   // Multiline test.
   EXPECT_EQ(
-      "Hash value=<HASH:aabb 1>, should be replaced as\n"
-      "well as /<HASH:aabb 1>/ and mixed case of\n"
-      "<HASH:aabb 1> but we don't go across lines\n"
+      "Hash value=(HASH:aabb 1), should be replaced as\n"
+      "well as /(HASH:aabb 1)/ and mixed case of\n"
+      "(HASH:aabb 1) but we don't go across lines\n"
       "aabbccddeeff\n00112233445566778899 but allow multiple on a line "
-      "<HASH:aabb 4>-"
-      "<HASH:0011 5>\n",
+      "(HASH:aabb 4)-"
+      "(HASH:0011 5)\n",
       RedactHashes(
           "Hash value=aabbccddeeff00112233445566778899, should be replaced as\n"
           "well as /aabbccddeeff00112233445566778899/ and mixed case of\n"
@@ -344,83 +344,83 @@
 TEST_F(RedactionToolTest, RedactCustomPatterns) {
   EXPECT_EQ("", RedactCustomPatterns(""));
 
-  EXPECT_EQ("Cell ID: '<CellID: 1>'", RedactCustomPatterns("Cell ID: 'A1B2'"));
-  EXPECT_EQ("Cell ID: '<CellID: 2>'", RedactCustomPatterns("Cell ID: 'C1D2'"));
-  EXPECT_EQ("foo Cell ID: '<CellID: 1>' bar",
+  EXPECT_EQ("Cell ID: '(CellID: 1)'", RedactCustomPatterns("Cell ID: 'A1B2'"));
+  EXPECT_EQ("Cell ID: '(CellID: 2)'", RedactCustomPatterns("Cell ID: 'C1D2'"));
+  EXPECT_EQ("foo Cell ID: '(CellID: 1)' bar",
             RedactCustomPatterns("foo Cell ID: 'A1B2' bar"));
 
-  EXPECT_EQ("foo Location area code: '<LocAC: 1>' bar",
+  EXPECT_EQ("foo Location area code: '(LocAC: 1)' bar",
             RedactCustomPatterns("foo Location area code: 'A1B2' bar"));
 
-  EXPECT_EQ("foo\na SSID='<SSID: 1>' b\n'",
+  EXPECT_EQ("foo\na SSID='(SSID: 1)' b\n'",
             RedactCustomPatterns("foo\na SSID='Joe's' b\n'"));
-  EXPECT_EQ("ssid '<SSID: 2>'", RedactCustomPatterns("ssid 'My AP'"));
+  EXPECT_EQ("ssid '(SSID: 2)'", RedactCustomPatterns("ssid 'My AP'"));
   EXPECT_EQ("bssid 'aa:bb'", RedactCustomPatterns("bssid 'aa:bb'"));
 
-  EXPECT_EQ("Scan SSID - hexdump(len=6): <SSIDHex: 1>\nfoo",
+  EXPECT_EQ("Scan SSID - hexdump(len=6): (SSIDHex: 1)\nfoo",
             RedactCustomPatterns(
                 "Scan SSID - hexdump(len=6): 47 6f 6f 67 6c 65\nfoo"));
 
   EXPECT_EQ(
-      "a\nb [SSID=<SSID: 3>] [SSID=<SSID: 1>] [SSID=foo\nbar] b",
+      "a\nb [SSID=(SSID: 3)] [SSID=(SSID: 1)] [SSID=foo\nbar] b",
       RedactCustomPatterns("a\nb [SSID=foo] [SSID=Joe's] [SSID=foo\nbar] b"));
-  EXPECT_EQ("ssid=\"<SSID: 4>\"",
+  EXPECT_EQ("ssid=\"(SSID: 4)\"",
             RedactCustomPatterns("ssid=\"LittleTsunami\""));
-  EXPECT_EQ("* SSID=<SSID: 5>", RedactCustomPatterns("* SSID=agnagna"));
+  EXPECT_EQ("* SSID=(SSID: 5)", RedactCustomPatterns("* SSID=agnagna"));
 
-  EXPECT_EQ("Specifier: <ArcNetworkFactory#1> SSID: \"<SSID: 6>\" foo",
+  EXPECT_EQ("Specifier: (ArcNetworkFactory#1) SSID: \"(SSID: 6)\" foo",
             RedactCustomPatterns(
-                "Specifier: <ArcNetworkFactory#1> SSID: \"GoogleGuest1\" foo"));
-  EXPECT_EQ("Specifier: <ArcNetworkFactory#1> SSID: '<SSID: 7>' foo",
+                "Specifier: (ArcNetworkFactory#1) SSID: \"GoogleGuest1\" foo"));
+  EXPECT_EQ("Specifier: (ArcNetworkFactory#1) SSID: '(SSID: 7)' foo",
             RedactCustomPatterns(
-                "Specifier: <ArcNetworkFactory#1> SSID: 'GoogleGuest2' foo"));
-  EXPECT_EQ("Specifier: <ArcNetworkFactory#1> SSID: <SSID: 8>",
+                "Specifier: (ArcNetworkFactory#1) SSID: 'GoogleGuest2' foo"));
+  EXPECT_EQ("Specifier: (ArcNetworkFactory#1) SSID: (SSID: 8)",
             RedactCustomPatterns(
-                "Specifier: <ArcNetworkFactory#1> SSID: GoogleGuest3"));
+                "Specifier: (ArcNetworkFactory#1) SSID: GoogleGuest3"));
   EXPECT_EQ(
-      "Specifier: <ArcNetworkFactory#1> SSID: <SSID: 9>",
+      "Specifier: (ArcNetworkFactory#1) SSID: (SSID: 9)",
       RedactCustomPatterns(
-          "Specifier: <ArcNetworkFactory#1> SSID: less than 32 characters"));
-  EXPECT_EQ("Specifier: <ArcNetworkFactory#1> SSID: <SSID: 10>foo",
-            RedactCustomPatterns("Specifier: <ArcNetworkFactory#1> SSID: this "
+          "Specifier: (ArcNetworkFactory#1) SSID: less than 32 characters"));
+  EXPECT_EQ("Specifier: (ArcNetworkFactory#1) SSID: (SSID: 10)foo",
+            RedactCustomPatterns("Specifier: (ArcNetworkFactory#1) SSID: this "
                                  "line is 32 characters long!foo"));
   EXPECT_EQ(
       "<WifiNetworkSpecifier [, SSID Match pattern=PatternMatcher{LITERAL: "
-      "<SSID: 11>}, ...]",
+      "(SSID: 11)}, ...]",
       RedactCustomPatterns("<WifiNetworkSpecifier [, SSID Match "
                            "pattern=PatternMatcher{LITERAL: Google-A}, ...]"));
 
-  EXPECT_EQ("SerialNumber: <Serial: 1>",
+  EXPECT_EQ("SerialNumber: (Serial: 1)",
             RedactCustomPatterns("SerialNumber: 1217D7EF"));
-  EXPECT_EQ("serial  number: <Serial: 2>",
+  EXPECT_EQ("serial  number: (Serial: 2)",
             RedactCustomPatterns("serial  number: 50C971FEE7F3x010900"));
-  EXPECT_EQ("SerialNumber: <Serial: 3>",
+  EXPECT_EQ("SerialNumber: (Serial: 3)",
             RedactCustomPatterns("SerialNumber: EVT23-17BA01-004"));
-  EXPECT_EQ("serial=\"<Serial: 4>\"",
+  EXPECT_EQ("serial=\"(Serial: 4)\"",
             RedactCustomPatterns("serial=\"1234AA5678\""));
-  EXPECT_EQ("\"serial_number\"=\"<Serial: 1>\"",
+  EXPECT_EQ("\"serial_number\"=\"(Serial: 1)\"",
             RedactCustomPatterns("\"serial_number\"=\"1217D7EF\""));
-  EXPECT_EQ("SerialNumber: <Serial: 5>",
+  EXPECT_EQ("SerialNumber: (Serial: 5)",
             RedactCustomPatterns("SerialNumber: 5:00:14.0"));
-  EXPECT_EQ("Serial: <Serial: 6>",
+  EXPECT_EQ("Serial: (Serial: 6)",
             RedactCustomPatterns("Serial: ABCEFG\x01kjmn-as:342/234\\432"));
   // Don't overly redact serial numbers, we only do this for a specific
   // formatting case for edid-decode.
   EXPECT_EQ("Foo serial number 123",
             RedactCustomPatterns("Foo serial number 123"));
-  EXPECT_EQ("Foo Serial Number <Serial: 7>",
+  EXPECT_EQ("Foo Serial Number (Serial: 7)",
             RedactCustomPatterns("Foo Serial Number 123"));
   // redact serial number separated by a | with the label "serial"
-  EXPECT_EQ("serial               | <Serial: 8>",
+  EXPECT_EQ("serial               | (Serial: 8)",
             RedactCustomPatterns("serial               | 0x1cc04416"));
-  EXPECT_EQ("serial               |<Serial: 9>",
+  EXPECT_EQ("serial               |(Serial: 9)",
             RedactCustomPatterns("serial               |0x1cc04417"));
-  EXPECT_EQ("serial|<Serial: 10>", RedactCustomPatterns("serial|0x1cc04418"));
-  EXPECT_EQ("serial|<Serial: 11>", RedactCustomPatterns("serial|agnagna"));
+  EXPECT_EQ("serial|(Serial: 10)", RedactCustomPatterns("serial|0x1cc04418"));
+  EXPECT_EQ("serial|(Serial: 11)", RedactCustomPatterns("serial|agnagna"));
   // redact attested device id that is also a serial number
-  EXPECT_EQ("\"attested_device_id\"=\"<Serial: 12>\"",
+  EXPECT_EQ("\"attested_device_id\"=\"(Serial: 12)\"",
             RedactCustomPatterns("\"attested_device_id\"=\"5CD045B0DZ\""));
-  EXPECT_EQ("\"attested_device_id\"=\"<Serial: 13>\"",
+  EXPECT_EQ("\"attested_device_id\"=\"(Serial: 13)\"",
             RedactCustomPatterns("\"attested_device_id\"=\"5CD04-5B0DZ\""));
   // The dash cannot appear first or last.
   EXPECT_EQ("\"attested_device_id\"=\"-5CD045B0DZ\"",
@@ -429,10 +429,10 @@
             RedactCustomPatterns("\"attested_device_id\"=\"5CD045B0DZ-\""));
 
   // Valid PSM identifiers.
-  EXPECT_EQ("PSM id: <PSM ID: 1>", RedactCustomPatterns("PSM id: ABCZ/123xx"));
-  EXPECT_EQ("psm: <PSM ID: 2>", RedactCustomPatterns("psm: ABC123F2/123xx"));
-  EXPECT_EQ("PsM: <PSM ID: 3>", RedactCustomPatterns("PsM: abcf6677/123xx"));
-  EXPECT_EQ("PSM determination successful. Identifier <PSM ID: 4> not present.",
+  EXPECT_EQ("PSM id: (PSM ID: 1)", RedactCustomPatterns("PSM id: ABCZ/123xx"));
+  EXPECT_EQ("psm: (PSM ID: 2)", RedactCustomPatterns("psm: ABC123F2/123xx"));
+  EXPECT_EQ("PsM: (PSM ID: 3)", RedactCustomPatterns("PsM: abcf6677/123xx"));
+  EXPECT_EQ("PSM determination successful. Identifier (PSM ID: 4) not present.",
             RedactCustomPatterns("PSM determination successful. Identifier "
                                  "JTFE/223PE6015195 not present."));
   // Wrong number of brand code characters.
@@ -444,27 +444,27 @@
   // PSM mention without whitespace, e.g. in base64-encoded data.
   EXPECT_EQ("PSM+ABCZ/123xx", RedactCustomPatterns("PSM+ABCZ/123xx"));
 
-  EXPECT_EQ("\"gaia_id\":\"<GAIA: 1>\"",
+  EXPECT_EQ("\"gaia_id\":\"(GAIA: 1)\"",
             RedactCustomPatterns("\"gaia_id\":\"1234567890\""));
-  EXPECT_EQ("gaia_id='<GAIA: 2>'", RedactCustomPatterns("gaia_id='987654321'"));
-  EXPECT_EQ("{id: <GAIA: 1>, email:",
+  EXPECT_EQ("gaia_id='(GAIA: 2)'", RedactCustomPatterns("gaia_id='987654321'"));
+  EXPECT_EQ("{id: (GAIA: 1), email:",
             RedactCustomPatterns("{id: 1234567890, email:"));
 
-  EXPECT_EQ("<email: 1>", RedactCustomPatterns("foo@bar.com"));
-  EXPECT_EQ("Email: <email: 1>.", RedactCustomPatterns("Email: foo@bar.com."));
-  EXPECT_EQ("Email:\n<email: 2>\n",
+  EXPECT_EQ("(email: 1)", RedactCustomPatterns("foo@bar.com"));
+  EXPECT_EQ("Email: (email: 1).", RedactCustomPatterns("Email: foo@bar.com."));
+  EXPECT_EQ("Email:\n(email: 2)\n",
             RedactCustomPatterns("Email:\nfooooo@bar.com\n"));
 
-  EXPECT_EQ("[<IPv6: 1>]",
+  EXPECT_EQ("[(IPv6: 1)]",
             RedactCustomPatterns("[2001:0db8:0000:0000:0000:ff00:0042:8329]"));
-  EXPECT_EQ("[<IPv6: 2>]",
+  EXPECT_EQ("[(IPv6: 2)]",
             RedactCustomPatterns("[2001:db8:0:0:0:ff00:42:8329]"));
-  EXPECT_EQ("[<IPv6: 3>]", RedactCustomPatterns("[2001:db8::ff00:42:8329]"));
-  EXPECT_EQ("[<IPv6: 4>]", RedactCustomPatterns("[aa::bb]"));
+  EXPECT_EQ("[(IPv6: 3)]", RedactCustomPatterns("[2001:db8::ff00:42:8329]"));
+  EXPECT_EQ("[(IPv6: 4)]", RedactCustomPatterns("[aa::bb]"));
   EXPECT_EQ("State::Abort", RedactCustomPatterns("State::Abort"));
 
   // Real IPv4 address
-  EXPECT_EQ("<IPv4: 1>", RedactCustomPatterns("192.160.0.1"));
+  EXPECT_EQ("(IPv4: 1)", RedactCustomPatterns("192.160.0.1"));
 
   // Non-PII IPv4 address (see MaybeScrubIPAddress)
   EXPECT_EQ("255.255.255.255", RedactCustomPatterns("255.255.255.255"));
@@ -495,8 +495,8 @@
   EXPECT_EQ("Revision: 10.10.10.10",
             RedactCustomPatterns("Revision: 10.10.10.10"));
 
-  EXPECT_EQ("<URL: 1>", RedactCustomPatterns("http://example.com/foo?test=1"));
-  EXPECT_EQ("Foo <URL: 2> Bar",
+  EXPECT_EQ("(URL: 1)", RedactCustomPatterns("http://example.com/foo?test=1"));
+  EXPECT_EQ("Foo (URL: 2) Bar",
             RedactCustomPatterns("Foo http://192.168.0.1/foo?test=1#123 Bar"));
   const char* kURLs[] = {
       "http://example.com/foo?test=1",
@@ -521,8 +521,8 @@
     SCOPED_TRACE(kURLs[i]);
     std::string got = RedactCustomPatterns(kURLs[i]);
     EXPECT_TRUE(
-        base::StartsWith(got, "<URL: ", base::CompareCase::INSENSITIVE_ASCII));
-    EXPECT_TRUE(base::EndsWith(got, ">", base::CompareCase::INSENSITIVE_ASCII));
+        base::StartsWith(got, "(URL: ", base::CompareCase::INSENSITIVE_ASCII));
+    EXPECT_TRUE(base::EndsWith(got, ")", base::CompareCase::INSENSITIVE_ASCII));
   }
   // Test that "Android:" is not considered a schema with empty hier part.
   EXPECT_EQ("The following applies to Android:",
@@ -541,24 +541,24 @@
   EXPECT_EQ("", RedactCustomPatternWithContext("", kPattern1));
   EXPECT_EQ("foo\nbar\n",
             RedactCustomPatternWithContext("foo\nbar\n", kPattern1));
-  EXPECT_EQ("id '<ID: 1>'",
+  EXPECT_EQ("id '(ID: 1)'",
             RedactCustomPatternWithContext("id '2345'", kPattern1));
-  EXPECT_EQ("id '<ID: 2>'",
+  EXPECT_EQ("id '(ID: 2)'",
             RedactCustomPatternWithContext("id '1234'", kPattern1));
-  EXPECT_EQ("id: '<ID: 2>'",
+  EXPECT_EQ("id: '(ID: 2)'",
             RedactCustomPatternWithContext("id: '1234'", kPattern1));
-  EXPECT_EQ("ID: '<ID: 1>'",
+  EXPECT_EQ("ID: '(ID: 1)'",
             RedactCustomPatternWithContext("ID: '2345'", kPattern1));
-  EXPECT_EQ("x1 id '<ID: 1>' 1x id '<ID: 2>'\nid '<ID: 1>'\n",
+  EXPECT_EQ("x1 id '(ID: 1)' 1x id '(ID: 2)'\nid '(ID: 1)'\n",
             RedactCustomPatternWithContext(
                 "x1 id '2345' 1x id '1234'\nid '2345'\n", kPattern1));
   // Different pattern with same alias should reuse the replacements.
-  EXPECT_EQ("id='<ID: 2>'",
+  EXPECT_EQ("id='(ID: 2)'",
             RedactCustomPatternWithContext("id='1234'", kPattern2));
   // Different alias should not reuse replacement from another pattern.
-  EXPECT_EQ("idg='<IDG: 1>'",
+  EXPECT_EQ("idg='(IDG: 1)'",
             RedactCustomPatternWithContext("idg='1234'", kPattern3));
-  EXPECT_EQ("x<FOO: 1>z",
+  EXPECT_EQ("x(FOO: 1)z",
             RedactCustomPatternWithContext("xyz", {"FOO", "()(y+)()"}));
 }
 
@@ -567,7 +567,7 @@
   // testing.
   CustomPatternWithAlias kPattern = {"pattern", "(o+)", PIIType::kEmail};
   EXPECT_EQ("", RedactCustomPatternWithoutContext("", kPattern));
-  EXPECT_EQ("f<pattern: 1>\nf<pattern: 2>z\nf<pattern: 1>l\n",
+  EXPECT_EQ("f(pattern: 1)\nf(pattern: 2)z\nf(pattern: 1)l\n",
             RedactCustomPatternWithoutContext("fo\nfooz\nfol\n", kPattern));
 }
 
@@ -622,7 +622,7 @@
 }
 
 TEST_F(RedactionToolTest, RedactUid) {
-  EXPECT_EQ("<UID: 1>",
+  EXPECT_EQ("(UID: 1)",
             redactor_.RedactAndKeepSelected(
                 "B3mcFTkQAHofv94DDTUuVJGGEI/BbzsyDncplMCR2P4=", {}));
 }
@@ -636,12 +636,12 @@
     {"chrome://resources/"
      "f?user="
      "99887766554433221100ffeeddccbbaaaabbccddeeff00112233445566778899",
-     "chrome://resources/f?user=<HASH:9988 1>"},  // URL that contains a hash.
+     "chrome://resources/f?user=(HASH:9988 1)"},  // URL that contains a hash.
     {"/root/27540283740a0897ab7c8de0f809add2bacde78f/foo",
-     "/root/<HASH:2754 2>/foo"},  // String that contains a hash.
+     "/root/(HASH:2754 2)/foo"},  // String that contains a hash.
     {"this is the user hash that we need to redact "
      "aabbccddeeff00112233445566778899",
-     "this is the user hash that we need to redact <HASH:aabb 3>"},  // String
+     "this is the user hash that we need to redact (HASH:aabb 3)"},  // String
                                                                      // that
                                                                      // contains
                                                                      // a hash.
@@ -650,7 +650,7 @@
      "android-data/data/data/pa.ckage2/de",  // Android app storage
                                              // path that contains a
                                              // hash.
-     "8.0K\t/home/root/<HASH:aabb 3>/android-data/data/data/pa.ckage2/de"}
+     "8.0K\t/home/root/(HASH:aabb 3)/android-data/data/data/pa.ckage2/de"}
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   };
   std::string redaction_input;
@@ -796,30 +796,30 @@
   std::pair<std::string, std::string> test_cases[] = {
       // UUIDs that come from the 'blkid' tool.
       {"PTUUID=\"985dff64-9c0f-3f49-945b-2d8c2e0238ec\"",
-       "PTUUID=\"<UUID: 1>\""},
-      {"UUID=\"E064-868C\"", "UUID=\"<UUID: 2>\""},
-      {"PARTUUID=\"7D242B2B1C751832\"", "PARTUUID=\"<UUID: 3>\""},
+       "PTUUID=\"(UUID: 1)\""},
+      {"UUID=\"E064-868C\"", "UUID=\"(UUID: 2)\""},
+      {"PARTUUID=\"7D242B2B1C751832\"", "PARTUUID=\"(UUID: 3)\""},
 
       // Volume labels.
-      {"LABEL=\"ntfs\"", "LABEL=\"<Volume Label: 1>\""},
-      {"PARTLABEL=\"SD Card\"", "PARTLABEL=\"<Volume Label: 2>\""},
+      {"LABEL=\"ntfs\"", "LABEL=\"(Volume Label: 1)\""},
+      {"PARTLABEL=\"SD Card\"", "PARTLABEL=\"(Volume Label: 2)\""},
 
       // LVM UUIDd.
       {"{\"pv_fmt\":\"lvm2\", "
        "\"pv_uuid\":\"duD18x-P7QE-sTya-SaeO-aq07-YgEq-xj8UEz\", "
        "\"dev_size\":\"230.33g\"}",
-       "{\"pv_fmt\":\"lvm2\", \"pv_uuid\":\"<UUID: 4>\", "
+       "{\"pv_fmt\":\"lvm2\", \"pv_uuid\":\"(UUID: 4)\", "
        "\"dev_size\":\"230.33g\"}"},
       {"{\"lv_uuid\":\"lKYORl-TWDP-OFLT-yDnB-jlQ7-aQrE-AwA8Oa\", "
        "\"lv_name\":\"[thinpool_tdata]\"",
-       "{\"lv_uuid\":\"<UUID: 5>\", \"lv_name\":\"[thinpool_tdata]\""},
+       "{\"lv_uuid\":\"(UUID: 5)\", \"lv_name\":\"[thinpool_tdata]\""},
 
       // Removable media paths.
-      {"/media/removable/SD Card/", "/media/removable/<Volume Label: 2>/"},
+      {"/media/removable/SD Card/", "/media/removable/(Volume Label: 2)/"},
       {"'/media/removable/My Secret Volume Name' don't redact this",
-       "'/media/removable/<Volume Label: 3>' don't redact this"},
+       "'/media/removable/(Volume Label: 3)' don't redact this"},
       {"0 part /media/removable/My Secret Volume Name         With Spaces   ",
-       "0 part /media/removable/<Volume Label: 4>"},
+       "0 part /media/removable/(Volume Label: 4)"},
   };
   for (const auto& p : test_cases) {
     EXPECT_EQ(redactor_.Redact(p.first), p.second);
diff --git a/components/history_clusters/core/BUILD.gn b/components/history_clusters/core/BUILD.gn
index 0e60c4a..8f55dbe 100644
--- a/components/history_clusters/core/BUILD.gn
+++ b/components/history_clusters/core/BUILD.gn
@@ -60,6 +60,8 @@
     "label_cluster_finalizer.h",
     "noisy_cluster_finalizer.cc",
     "noisy_cluster_finalizer.h",
+    "ntp_visit_scores.cc",
+    "ntp_visit_scores.h",
     "on_device_clustering_backend.cc",
     "on_device_clustering_backend.h",
     "on_device_clustering_features.cc",
@@ -86,6 +88,7 @@
     "//components/pref_registry",
     "//components/prefs",
     "//components/query_parser",
+    "//components/search",
     "//components/search_engines",
     "//components/site_engagement/core",
     "//components/strings:components_strings_grit",
@@ -115,6 +118,7 @@
     "keyword_cluster_finalizer_unittest.cc",
     "label_cluster_finalizer_unittest.cc",
     "noisy_cluster_finalizer_unittest.cc",
+    "ntp_visit_scores_unittest.cc",
     "on_device_clustering_backend_unittest.cc",
     "on_device_clustering_util_unittest.cc",
     "ranking_cluster_finalizer_unittest.cc",
diff --git a/components/history_clusters/core/DEPS b/components/history_clusters/core/DEPS
index b727921..d8d0fc1 100644
--- a/components/history_clusters/core/DEPS
+++ b/components/history_clusters/core/DEPS
@@ -5,6 +5,7 @@
   "+components/pref_registry",
   "+components/prefs",
   "+components/query_parser",
+  "+components/search",
   "+components/search_engines",
   "+components/site_engagement/core",
   "+components/strings/grit/components_strings.h",
diff --git a/components/history_clusters/core/config.cc b/components/history_clusters/core/config.cc
index bf77fa5..33f5c87b 100644
--- a/components/history_clusters/core/config.cc
+++ b/components/history_clusters/core/config.cc
@@ -17,6 +17,7 @@
 #include "components/history_clusters/core/history_clusters_service.h"
 #include "components/history_clusters/core/on_device_clustering_features.h"
 #include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace history_clusters {
@@ -396,6 +397,19 @@
         base::FeatureList::IsEnabled(internal::kJourneysZeroStateFiltering);
   }
 
+  // The `kNtpChromeCartInHistoryClusterModule` child params.
+  {
+    use_ntp_specific_intracluster_ranking = GetFieldTrialParamByFeatureAsBool(
+        ntp_features::kNtpChromeCartInHistoryClusterModule,
+        "use_ntp_specific_intracluster_ranking",
+        use_ntp_specific_intracluster_ranking);
+
+    ntp_visit_duration_ranking_weight = GetFieldTrialParamByFeatureAsDouble(
+        ntp_features::kNtpChromeCartInHistoryClusterModule,
+        "ntp_visit_duration_ranking_weight", ntp_visit_duration_ranking_weight);
+    DCHECK_GE(ntp_visit_duration_ranking_weight, 0.0f);
+  }
+
   // Lonely features without child params.
   {
     non_user_visible_debug =
diff --git a/components/history_clusters/core/config.h b/components/history_clusters/core/config.h
index c7347b4..bc552f0 100644
--- a/components/history_clusters/core/config.h
+++ b/components/history_clusters/core/config.h
@@ -370,6 +370,17 @@
 
   bool apply_zero_state_filtering = false;
 
+  // The `kNtpChromeCartInHistoryClusterModule` child params.
+
+  // Whether to use the NTP-specific algorithms and signals for determining
+  // intracluster ranking.
+  bool use_ntp_specific_intracluster_ranking = false;
+
+  // Returns the weight to use for the visit duration when ranking visits within
+  // a cluster. Will always be greater than or equal to 0 specifically on the
+  // NTP surface when `use_ntp_specific_intracluster_ranking is true`.
+  float ntp_visit_duration_ranking_weight = 1.0;
+
   // Lonely features without child params.
 
   // Enables debug info in non-user-visible surfaces, like Chrome Inspector.
diff --git a/components/history_clusters/core/ntp_visit_scores.cc b/components/history_clusters/core/ntp_visit_scores.cc
new file mode 100644
index 0000000..20c25143
--- /dev/null
+++ b/components/history_clusters/core/ntp_visit_scores.cc
@@ -0,0 +1,14 @@
+// Copyright 2023 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/history_clusters/core/ntp_visit_scores.h"
+
+namespace history_clusters {
+
+float GetNtpVisitAttributesScore(const history::ClusterVisit& visit) {
+  // TODO(crbug/1432431): Implement this.
+  return 0.0;
+}
+
+}  // namespace history_clusters
diff --git a/components/history_clusters/core/ntp_visit_scores.h b/components/history_clusters/core/ntp_visit_scores.h
new file mode 100644
index 0000000..5020d6e
--- /dev/null
+++ b/components/history_clusters/core/ntp_visit_scores.h
@@ -0,0 +1,18 @@
+// Copyright 2023 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_HISTORY_CLUSTERS_CORE_NTP_VISIT_SCORES_H_
+#define COMPONENTS_HISTORY_CLUSTERS_CORE_NTP_VISIT_SCORES_H_
+
+#include "components/history/core/browser/history_types.h"
+
+namespace history_clusters {
+
+// Returns the score for the visit attributes for the NTP History Clusters
+// module.
+float GetNtpVisitAttributesScore(const history::ClusterVisit& visit);
+
+}  // namespace history_clusters
+
+#endif  // COMPONENTS_HISTORY_CLUSTERS_CORE_NTP_VISIT_SCORES_H_
diff --git a/components/history_clusters/core/ntp_visit_scores_unittest.cc b/components/history_clusters/core/ntp_visit_scores_unittest.cc
new file mode 100644
index 0000000..5cefd024
--- /dev/null
+++ b/components/history_clusters/core/ntp_visit_scores_unittest.cc
@@ -0,0 +1,22 @@
+// Copyright 2023 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/history_clusters/core/ntp_visit_scores.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace history_clusters {
+
+namespace {
+
+using NtpVisitScoresTest = testing::Test;
+
+TEST(NtpVisitScoresTest, GetNtpVisitAttributesScore) {
+  history::ClusterVisit visit;
+  EXPECT_EQ(GetNtpVisitAttributesScore(visit), 0.0);
+}
+
+}  // namespace
+
+}  // namespace history_clusters
diff --git a/components/history_clusters/core/on_device_clustering_backend.cc b/components/history_clusters/core/on_device_clustering_backend.cc
index e8727803..e593704 100644
--- a/components/history_clusters/core/on_device_clustering_backend.cc
+++ b/components/history_clusters/core/on_device_clustering_backend.cc
@@ -542,7 +542,8 @@
   std::vector<std::unique_ptr<ClusterFinalizer>> cluster_finalizers;
   cluster_finalizers.push_back(
       std::make_unique<SimilarVisitDeduperClusterFinalizer>());
-  cluster_finalizers.push_back(std::make_unique<RankingClusterFinalizer>());
+  cluster_finalizers.push_back(
+      std::make_unique<RankingClusterFinalizer>(clustering_request_source));
   cluster_finalizers.push_back(std::make_unique<LabelClusterFinalizer>(
       &entity_id_to_entity_metadata_map));
 
@@ -592,7 +593,8 @@
     // TODO(b/259466296): Remove this block once that path is fully launched.
     cluster_finalizers.push_back(
         std::make_unique<SimilarVisitDeduperClusterFinalizer>());
-    cluster_finalizers.push_back(std::make_unique<RankingClusterFinalizer>());
+    cluster_finalizers.push_back(std::make_unique<RankingClusterFinalizer>(
+        ClusteringRequestSource::kJourneysPage));
     cluster_finalizers.push_back(std::make_unique<LabelClusterFinalizer>(
         &entity_id_to_entity_metadata_map));
   }
diff --git a/components/history_clusters/core/ranking_cluster_finalizer.cc b/components/history_clusters/core/ranking_cluster_finalizer.cc
index 1feaf95b..f0e50ccb 100644
--- a/components/history_clusters/core/ranking_cluster_finalizer.cc
+++ b/components/history_clusters/core/ranking_cluster_finalizer.cc
@@ -6,6 +6,7 @@
 
 #include "base/containers/adapters.h"
 #include "components/history_clusters/core/history_clusters_util.h"
+#include "components/history_clusters/core/ntp_visit_scores.h"
 
 namespace history_clusters {
 
@@ -31,7 +32,9 @@
 
 }  // namespace
 
-RankingClusterFinalizer::RankingClusterFinalizer() = default;
+RankingClusterFinalizer::RankingClusterFinalizer(
+    ClusteringRequestSource clustering_request_source)
+    : clustering_request_source_(clustering_request_source) {}
 RankingClusterFinalizer::~RankingClusterFinalizer() = default;
 
 void RankingClusterFinalizer::FinalizeCluster(history::Cluster& cluster) {
@@ -45,7 +48,7 @@
 void RankingClusterFinalizer::CalculateVisitAttributeScoring(
     history::Cluster& cluster,
     base::flat_map<history::VisitID, VisitScores>& url_visit_scores) {
-  for (const history::ClusterVisit& visit : base::Reversed(cluster.visits)) {
+  for (const auto& visit : cluster.visits) {
     auto it = url_visit_scores.find(visit.annotated_visit.visit_row.visit_id);
     if (it == url_visit_scores.end()) {
       auto visit_score = VisitScores();
@@ -54,6 +57,13 @@
     }
     it = url_visit_scores.find(visit.annotated_visit.visit_row.visit_id);
 
+    if (GetConfig().use_ntp_specific_intracluster_ranking &&
+        clustering_request_source_ == ClusteringRequestSource::kNewTabPage) {
+      it->second.set_ntp_visit_attributes_score(
+          GetNtpVisitAttributesScore(visit));
+      return;
+    }
+
     // Check if the visit is bookmarked.
     if (visit.annotated_visit.context_annotations.is_existing_bookmark ||
         visit.annotated_visit.context_annotations.is_new_bookmark) {
@@ -95,7 +105,7 @@
           visit.annotated_visit.context_annotations.total_foreground_duration;
     }
   }
-  for (const history::ClusterVisit& visit : base::Reversed(cluster.visits)) {
+  for (const auto& visit : cluster.visits) {
     float visit_duration_score =
         Smoothstep(0.0f, max_visit_duration.InSecondsF(),
                    visit.annotated_visit.visit_row.visit_duration.InSecondsF());
@@ -123,7 +133,7 @@
     history::Cluster& cluster,
     base::flat_map<history::VisitID, VisitScores>& url_visit_scores) {
   float max_score = -1.0;
-  for (history::ClusterVisit& visit : base::Reversed(cluster.visits)) {
+  for (auto& visit : cluster.visits) {
     // Determine the max score to use for normalizing all the scores.
     auto visit_scores_it =
         url_visit_scores.find(visit.annotated_visit.visit_row.visit_id);
@@ -143,7 +153,7 @@
 
   // Now normalize the score by `max_score` so the values are all between 0
   // and 1.
-  for (history::ClusterVisit& visit : base::Reversed(cluster.visits)) {
+  for (auto& visit : cluster.visits) {
     visit.score = visit.score / max_score;
   }
 }
diff --git a/components/history_clusters/core/ranking_cluster_finalizer.h b/components/history_clusters/core/ranking_cluster_finalizer.h
index a2ffcbe..38f389ea 100644
--- a/components/history_clusters/core/ranking_cluster_finalizer.h
+++ b/components/history_clusters/core/ranking_cluster_finalizer.h
@@ -7,6 +7,7 @@
 
 #include "components/history_clusters/core/cluster_finalizer.h"
 #include "components/history_clusters/core/config.h"
+#include "components/history_clusters/core/history_clusters_types.h"
 #include "components/history_clusters/core/on_device_clustering_features.h"
 
 namespace history_clusters {
@@ -22,6 +23,11 @@
   // weightings between each. Note, this score is not between [0, 1] as
   // normalization will consider all visits within a cluster.
   float GetTotalScore() const {
+    if (ntp_visit_attributes_score_) {
+      return *ntp_visit_attributes_score_ +
+             visit_duration_score_ *
+                 GetConfig().ntp_visit_duration_ranking_weight;
+    }
     return visit_duration_score_ * GetConfig().visit_duration_ranking_weight +
            foreground_duration_score_ *
                GetConfig().foreground_duration_ranking_weight +
@@ -43,6 +49,10 @@
 
   void set_has_url_keyed_image() { has_url_keyed_image_score_ = 1.0; }
 
+  void set_ntp_visit_attributes_score(float score) {
+    ntp_visit_attributes_score_ = score;
+  }
+
  private:
   // The score for the duration associated with a visit.
   float visit_duration_score_ = 0.0;
@@ -54,12 +64,15 @@
   float srp_score_ = 0.0;
   // The score for whether the visit had a URL-keyed image.
   float has_url_keyed_image_score_ = 0.0;
+  // The score for NTP visit attributes.
+  absl::optional<float> ntp_visit_attributes_score_;
 };
 
 // A cluster finalizer that scores visits based on visit duration.
 class RankingClusterFinalizer : public ClusterFinalizer {
  public:
-  RankingClusterFinalizer();
+  explicit RankingClusterFinalizer(
+      ClusteringRequestSource clustering_request_source);
   ~RankingClusterFinalizer() override;
 
   // ClusterFinalizer:
@@ -83,6 +96,8 @@
   void ComputeFinalVisitScores(
       history::Cluster& cluster,
       base::flat_map<history::VisitID, VisitScores>& url_visit_scores);
+
+  const ClusteringRequestSource clustering_request_source_;
 };
 
 }  // namespace history_clusters
diff --git a/components/history_clusters/core/ranking_cluster_finalizer_unittest.cc b/components/history_clusters/core/ranking_cluster_finalizer_unittest.cc
index 2c78e33b..5bd0555 100644
--- a/components/history_clusters/core/ranking_cluster_finalizer_unittest.cc
+++ b/components/history_clusters/core/ranking_cluster_finalizer_unittest.cc
@@ -17,11 +17,21 @@
 class RankingClusterFinalizerTest : public ::testing::Test {
  public:
   void SetUp() override {
-    cluster_finalizer_ = std::make_unique<RankingClusterFinalizer>();
+    // Reset config so tests are clean.
+    Config config;
+    SetConfigForTesting(config);
+
+    cluster_finalizer_ = std::make_unique<RankingClusterFinalizer>(
+        ClusteringRequestSource::kJourneysPage);
   }
 
   void TearDown() override { cluster_finalizer_.reset(); }
 
+  void ResetClusterFinalizer(
+      std::unique_ptr<RankingClusterFinalizer> cluster_finalizer) {
+    cluster_finalizer_ = std::move(cluster_finalizer);
+  }
+
   void FinalizeCluster(history::Cluster& cluster) {
     cluster_finalizer_->FinalizeCluster(cluster);
   }
@@ -136,6 +146,31 @@
           testing::VisitResult(10, 0.5))));
 }
 
+TEST_F(
+    RankingClusterFinalizerTest,
+    ScoreTwoVisitsSameURLBookmarkedNtpFlagOnButStillUsesGenericRankingForJourneysPage) {
+  Config config;
+  config.use_ntp_specific_intracluster_ranking = true;
+  SetConfigForTesting(config);
+
+  // Visit2 has the same URL as Visit1.
+  history::ClusterVisit visit = testing::CreateClusterVisit(
+      testing::CreateDefaultAnnotatedVisit(1, GURL("https://bar.com/")));
+  visit.annotated_visit.context_annotations.is_existing_bookmark = true;
+
+  history::ClusterVisit visit2 = testing::CreateClusterVisit(
+      testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/")));
+  visit2.duplicate_visits.push_back(
+      testing::ClusterVisitToDuplicateClusterVisit(visit));
+
+  history::Cluster cluster;
+  cluster.visits = {visit2};
+  FinalizeCluster(cluster);
+  EXPECT_THAT(testing::ToVisitResults({cluster}),
+              ElementsAre(ElementsAre(testing::VisitResult(
+                  2, 1.0, {history::DuplicateClusterVisit{1}}))));
+}
+
 TEST_F(RankingClusterFinalizerTest, ScoreTwoVisitsSameURLBookmarked) {
   // Visit2 has the same URL as Visit1.
   history::ClusterVisit visit = testing::CreateClusterVisit(
@@ -175,6 +210,61 @@
                                       testing::VisitResult(2, 0.5))));
 }
 
+TEST_F(
+    RankingClusterFinalizerTest,
+    ScoreTwoVisitsWithBookmarksAndDurationNtpButSpecificRankingFlagNotEnabled) {
+  Config config;
+  config.use_ntp_specific_intracluster_ranking = false;
+  SetConfigForTesting(config);
+
+  ResetClusterFinalizer(std::make_unique<RankingClusterFinalizer>(
+      ClusteringRequestSource::kNewTabPage));
+
+  history::ClusterVisit visit = testing::CreateClusterVisit(
+      testing::CreateDefaultAnnotatedVisit(1, GURL("https://bar.com/")));
+  visit.annotated_visit.context_annotations.is_existing_bookmark = true;
+  visit.annotated_visit.visit_row.visit_duration = base::Seconds(20);
+
+  history::ClusterVisit visit2 = testing::CreateClusterVisit(
+      testing::CreateDefaultAnnotatedVisit(2, GURL("https://foo.com/")));
+  visit2.annotated_visit.context_annotations.is_existing_bookmark = true;
+  visit2.annotated_visit.visit_row.visit_duration = base::Seconds(0);
+
+  history::Cluster cluster;
+  cluster.visits = {visit, visit2};
+  FinalizeCluster(cluster);
+  EXPECT_THAT(testing::ToVisitResults({cluster}),
+              ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
+                                      testing::VisitResult(2, 0.5))));
+}
+
+TEST_F(RankingClusterFinalizerTest,
+       NtpScoreTwoVisitsSameDurationOtherAttributesDontMatter) {
+  Config config;
+  config.use_ntp_specific_intracluster_ranking = true;
+  SetConfigForTesting(config);
+
+  ResetClusterFinalizer(std::make_unique<RankingClusterFinalizer>(
+      ClusteringRequestSource::kNewTabPage));
+
+  history::ClusterVisit visit = testing::CreateClusterVisit(
+      testing::CreateDefaultAnnotatedVisit(1, GURL("https://bar.com/")));
+  visit.annotated_visit.context_annotations.is_existing_bookmark = true;
+  visit.annotated_visit.visit_row.visit_duration = base::Seconds(20);
+
+  history::ClusterVisit visit2 = testing::CreateClusterVisit(
+      testing::CreateDefaultAnnotatedVisit(2, GURL("https://foo.com/")));
+  visit2.annotated_visit.context_annotations.is_existing_bookmark = false;
+  visit2.annotated_visit.visit_row.visit_duration = base::Seconds(20);
+
+  history::Cluster cluster;
+  cluster.visits = {visit, visit2};
+  FinalizeCluster(cluster);
+  EXPECT_THAT(testing::ToVisitResults({cluster}),
+              ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
+                                      testing::VisitResult(2, 1.0))));
+}
+
 TEST_F(RankingClusterFinalizerTest,
        ScoreTwoVisitsWithBookmarksAndForegroundDuration) {
   // Visit2 has the same URL as Visit1.
diff --git a/components/lens/lens_url_utils.cc b/components/lens/lens_url_utils.cc
index 3132002d..afea2e8 100644
--- a/components/lens/lens_url_utils.cc
+++ b/components/lens/lens_url_utils.cc
@@ -34,13 +34,6 @@
 constexpr char kStartTimeQueryParameter[] = "st";
 constexpr char kLensMetadataParameter[] = "lm";
 
-// TODO(b/278746005): Refactor code to to have origin in one place.
-// Query parameter for the Chrome WebUI origin. This needs to be different
-// from the WebUI URL constant because it does not include the last '/'.
-inline constexpr char kOriginQueryParameter[] = "origin";
-inline constexpr char kOriginQueryParameterValue[] =
-    "chrome-untrusted://companion-side-panel.top-chrome";
-
 constexpr char kRenderingEnvironmentQueryParameter[] = "re";
 constexpr char kOneLensDesktopWebChromeSidePanel[] = "dcsp";
 constexpr char kOneLensDesktopWebFullscreen[] = "df";
@@ -103,10 +96,6 @@
     case lens::CHROME_SEARCH_COMPANION:
       query_parameters.insert(
           {kRenderingEnvironmentQueryParameter, kChromeSearchCompanion});
-      // This rendering environment also needs to provide an 'origin' parameter
-      // on all requests.
-      query_parameters.insert(
-          {kOriginQueryParameter, kOriginQueryParameterValue});
       break;
     default:
       // Empty strings are ignored when query parameters are built.
diff --git a/components/leveldb_proto/public/proto_database.cc b/components/leveldb_proto/public/proto_database.cc
index 6bc2402..894377d 100644
--- a/components/leveldb_proto/public/proto_database.cc
+++ b/components/leveldb_proto/public/proto_database.cc
@@ -16,7 +16,8 @@
   leveldb_env::Options options;
   options.create_if_missing = true;
   options.max_open_files = 0;  // Use minimum.
-  static bool is_low_end_device = base::SysInfo::IsLowEndDevice();
+  static bool is_low_end_device =
+      base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled();
   if (is_low_end_device)
     options.write_buffer_size = kDatabaseWriteBufferSizeBytesForLowEndDevice;
   else
@@ -24,4 +25,4 @@
   return options;
 }
 
-}  // namespace leveldb_proto
\ No newline at end of file
+}  // namespace leveldb_proto
diff --git a/components/media_router/browser/presentation/local_presentation_manager.cc b/components/media_router/browser/presentation/local_presentation_manager.cc
index f5b68d7..9f3420cb 100644
--- a/components/media_router/browser/presentation/local_presentation_manager.cc
+++ b/components/media_router/browser/presentation/local_presentation_manager.cc
@@ -12,6 +12,7 @@
 #include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
+using blink::mojom::PresentationConnectionResult;
 using blink::mojom::PresentationInfo;
 
 namespace media_router {
@@ -117,9 +118,10 @@
         receiver_connection_receiver,
     const MediaRoute& route) {
   if (!receiver_callback_.is_null()) {
-    receiver_callback_.Run(PresentationInfo::New(presentation_info_),
-                           std::move(controller_connection_remote),
-                           std::move(receiver_connection_receiver));
+    receiver_callback_.Run(PresentationConnectionResult::New(
+        PresentationInfo::New(presentation_info_),
+        std::move(controller_connection_remote),
+        std::move(receiver_connection_receiver)));
   } else {
     pending_controllers_.insert(std::make_pair(
         render_frame_host_id, std::make_unique<ControllerConnection>(
@@ -140,10 +142,10 @@
   DCHECK(receiver_callback_.is_null());
   DCHECK(receiver_web_contents);
   for (auto& controller : pending_controllers_) {
-    receiver_callback.Run(
+    receiver_callback.Run(PresentationConnectionResult::New(
         PresentationInfo::New(presentation_info_),
         std::move(controller.second->controller_connection_remote),
-        std::move(controller.second->receiver_connection_receiver));
+        std::move(controller.second->receiver_connection_receiver)));
   }
   receiver_callback_ = receiver_callback;
   receiver_web_contents_ = receiver_web_contents;
diff --git a/components/media_router/browser/presentation/local_presentation_manager_unittest.cc b/components/media_router/browser/presentation/local_presentation_manager_unittest.cc
index 211339e..96882e6 100644
--- a/components/media_router/browser/presentation/local_presentation_manager_unittest.cc
+++ b/components/media_router/browser/presentation/local_presentation_manager_unittest.cc
@@ -15,8 +15,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+using blink::mojom::PresentationConnectionResultPtr;
 using blink::mojom::PresentationInfo;
-using blink::mojom::PresentationInfoPtr;
 using testing::_;
 
 namespace media_router {
@@ -29,11 +29,8 @@
 
 class MockReceiverConnectionAvailableCallback {
  public:
-  MOCK_METHOD3(
-      OnReceiverConnectionAvailable,
-      void(PresentationInfoPtr,
-           mojo::PendingRemote<blink::mojom::PresentationConnection>,
-           mojo::PendingReceiver<blink::mojom::PresentationConnection>));
+  MOCK_METHOD1(OnReceiverConnectionAvailable,
+               void(PresentationConnectionResultPtr));
 };
 
 class LocalPresentationManagerTest : public content::RenderViewHostTestHarness {
@@ -180,7 +177,7 @@
   VerifyPresentationsSize(0);
 
   RegisterController(std::move(controller));
-  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_, _, _));
+  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_));
   RegisterReceiver(receiver_callback);
 }
 
@@ -192,7 +189,7 @@
   VerifyPresentationsSize(0);
 
   RegisterController(std::move(controller));
-  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_, _, _));
+  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_));
   RegisterReceiver(receiver_callback);
   UnregisterReceiver();
 
@@ -207,7 +204,7 @@
   VerifyPresentationsSize(0);
 
   RegisterController(std::move(controller));
-  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_, _, _));
+  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_));
   RegisterReceiver(receiver_callback);
   UnregisterController();
 
@@ -222,7 +219,7 @@
   VerifyPresentationsSize(0);
 
   RegisterController(std::move(controller));
-  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_, _, _));
+  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_));
   RegisterReceiver(receiver_callback);
   UnregisterReceiver();
   UnregisterController();
@@ -238,7 +235,7 @@
   VerifyPresentationsSize(0);
 
   RegisterController(std::move(controller));
-  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_, _, _));
+  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_));
   RegisterReceiver(receiver_callback);
   UnregisterController();
   UnregisterReceiver();
@@ -256,8 +253,7 @@
                      std::move(controller2));
 
   MockReceiverConnectionAvailableCallback receiver_callback;
-  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_, _, _))
-      .Times(2);
+  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_)).Times(2);
   RegisterReceiver(receiver_callback);
 }
 
@@ -268,8 +264,7 @@
                      std::move(controller1));
 
   MockReceiverConnectionAvailableCallback receiver_callback;
-  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_, _, _))
-      .Times(2);
+  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_)).Times(2);
   RegisterReceiver(receiver_callback);
 
   mojo::PendingRemote<blink::mojom::PresentationConnection> controller2;
@@ -287,8 +282,7 @@
                      std::move(controller2));
 
   MockReceiverConnectionAvailableCallback receiver_callback;
-  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_, _, _))
-      .Times(2);
+  EXPECT_CALL(receiver_callback, OnReceiverConnectionAvailable(_)).Times(2);
   RegisterReceiver(receiver_callback);
   UnregisterController(content::GlobalRenderFrameHostId(1, 1));
   UnregisterController(content::GlobalRenderFrameHostId(1, 1));
@@ -301,16 +295,14 @@
   RegisterController(kPresentationId, std::move(controller1));
 
   MockReceiverConnectionAvailableCallback receiver_callback1;
-  EXPECT_CALL(receiver_callback1, OnReceiverConnectionAvailable(_, _, _))
-      .Times(1);
+  EXPECT_CALL(receiver_callback1, OnReceiverConnectionAvailable(_)).Times(1);
   RegisterReceiver(kPresentationId, receiver_callback1);
 
   mojo::PendingRemote<blink::mojom::PresentationConnection> controller2;
   RegisterController(kPresentationId2, std::move(controller2));
 
   MockReceiverConnectionAvailableCallback receiver_callback2;
-  EXPECT_CALL(receiver_callback2, OnReceiverConnectionAvailable(_, _, _))
-      .Times(1);
+  EXPECT_CALL(receiver_callback2, OnReceiverConnectionAvailable(_)).Times(1);
   RegisterReceiver(kPresentationId2, receiver_callback2);
 
   VerifyPresentationsSize(2);
diff --git a/components/metrics/generate_expired_histograms_array.gni b/components/metrics/generate_expired_histograms_array.gni
index a7e2b36..e807f03 100644
--- a/components/metrics/generate_expired_histograms_array.gni
+++ b/components/metrics/generate_expired_histograms_array.gni
@@ -57,6 +57,7 @@
       "//tools/metrics/histograms/metadata/chromeos_hps/histograms.xml",
       "//tools/metrics/histograms/metadata/chromeos_settings/histograms.xml",
       "//tools/metrics/histograms/metadata/commerce/histograms.xml",
+      "//tools/metrics/histograms/metadata/companion/histograms.xml",
       "//tools/metrics/histograms/metadata/compositing/histograms.xml",
       "//tools/metrics/histograms/metadata/content/histograms.xml",
       "//tools/metrics/histograms/metadata/content_creation/histograms.xml",
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index af49722f..4fdca226 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -58,7 +58,6 @@
     "https_valid_in_chip.icon",
     "incognito.icon",
     "install_desktop.icon",
-    "install_desktop_chrome_refresh.icon",
     "journeys.icon",
     "keyword_search.icon",
     "offline_pin.icon",
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 2506718..f8f777d 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -448,7 +448,7 @@
   constexpr int kDefaultOnNonLowEndDevices = 20000;
 #endif
 
-  if (base::SysInfo::IsLowEndDevice()) {
+  if (base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled()) {
     return kDefaultOnLowEndDevices;
   } else {
     return kDefaultOnNonLowEndDevices;
diff --git a/components/omnibox/browser/vector_icons/install_desktop_chrome_refresh.icon b/components/omnibox/browser/vector_icons/install_desktop_chrome_refresh.icon
deleted file mode 100644
index 3c76cf5..0000000
--- a/components/omnibox/browser/vector_icons/install_desktop_chrome_refresh.icon
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2023 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, 7, 17,
-R_V_LINE_TO, -2,
-H_LINE_TO, 3.5f,
-R_CUBIC_TO, -0.42f, 0, -0.77f, -0.15f, -1.06f, -0.44f,
-ARC_TO, 1.45f, 1.45f, 0, 0, 1, 2, 13.5f,
-R_V_LINE_TO, -9,
-R_CUBIC_TO, 0, -0.42f, 0.15f, -0.77f, 0.44f, -1.06f,
-ARC_TO, 1.45f, 1.45f, 0, 0, 1, 3.5f, 3,
-H_LINE_TO, 11,
-R_V_LINE_TO, 1.5f,
-H_LINE_TO, 3.5f,
-R_V_LINE_TO, 9,
-R_H_LINE_TO, 13,
-V_LINE_TO, 11,
-H_LINE_TO, 18,
-R_V_LINE_TO, 2.5f,
-R_CUBIC_TO, 0, 0.42f, -0.15f, 0.77f, -0.44f, 1.06f,
-ARC_TO, 1.45f, 1.45f, 0, 0, 1, 16.5f, 15,
-H_LINE_TO, 13,
-R_V_LINE_TO, 2,
-H_LINE_TO, 7,
-CLOSE,
-R_MOVE_TO, 7.48f, -6,
-LINE_TO, 11, 7.52f,
-R_LINE_TO, 1.06f, -1.06f,
-R_LINE_TO, 1.69f, 1.69f,
-V_LINE_TO, 3,
-R_H_LINE_TO, 1.5f,
-R_V_LINE_TO, 5.1f,
-R_LINE_TO, 1.69f, -1.69f,
-LINE_TO, 18, 7.48f,
-LINE_TO, 14.48f, 11,
-CLOSE,
-NEW_PATH
diff --git a/components/optimization_guide/content/browser/page_content_annotations_service.cc b/components/optimization_guide/content/browser/page_content_annotations_service.cc
index 6d2542f..86c22a0 100644
--- a/components/optimization_guide/content/browser/page_content_annotations_service.cc
+++ b/components/optimization_guide/content/browser/page_content_annotations_service.cc
@@ -625,15 +625,9 @@
     return;
   }
 
-  base::TimeDelta min_magnitude_between_visits = base::TimeDelta::Max();
   bool did_store_content_annotations = false;
   for (const auto& visit_for_url : base::Reversed(url_result.visits)) {
     if (visit.nav_entry_timestamp != visit_for_url.visit_time) {
-      base::TimeDelta magnitude_between_visits =
-          (visit.nav_entry_timestamp - visit_for_url.visit_time).magnitude();
-      if (magnitude_between_visits < min_magnitude_between_visits) {
-        min_magnitude_between_visits = magnitude_between_visits;
-      }
       continue;
     }
 
@@ -645,19 +639,6 @@
   LogPageContentAnnotationsStorageStatus(
       did_store_content_annotations ? kSuccess : kSpecificVisitForUrlNotFound,
       annotation_type);
-  if (!did_store_content_annotations) {
-    DCHECK_NE(min_magnitude_between_visits, base::TimeDelta::Max());
-    base::UmaHistogramTimes(
-        "OptimizationGuide.PageContentAnnotationsService."
-        "ContentAnnotationsStorageMinMagnitudeForVisitNotFound",
-        min_magnitude_between_visits);
-
-    base::UmaHistogramTimes(
-        "OptimizationGuide.PageContentAnnotationsService."
-        "ContentAnnotationsStorageMinMagnitudeForVisitNotFound." +
-            PageContentAnnotationsTypeToString(annotation_type),
-        min_magnitude_between_visits);
-  }
 }
 
 void PageContentAnnotationsService::GetMetadataForEntityId(
diff --git a/components/optimization_guide/core/model_util.cc b/components/optimization_guide/core/model_util.cc
index dc2a40d..4e1a4cb86 100644
--- a/components/optimization_guide/core/model_util.cc
+++ b/components/optimization_guide/core/model_util.cc
@@ -99,6 +99,8 @@
     case proto::
         OPTIMIZATION_TARGET_NEW_TAB_PAGE_HISTORY_CLUSTERS_MODULE_RANKING:
       return "NewTabPageHistoryClustersModuleRanking";
+    case proto::OPTIMIZATION_TARGET_WEB_APP_INSTALLATION_PROMO:
+      return "WebAppInstallationPromo";
       // Whenever a new value is added, make sure to add it to the OptTarget
       // variant list in
       // //tools/metrics/histograms/metadata/optimization/histograms.xml.
diff --git a/components/optimization_guide/proto/models.proto b/components/optimization_guide/proto/models.proto
index c488cb3..d1c971432 100644
--- a/components/optimization_guide/proto/models.proto
+++ b/components/optimization_guide/proto/models.proto
@@ -186,6 +186,8 @@
   // Target for ranking clusters that have passed minimal filtering for the New
   // Tab Page History Clusters module.
   OPTIMIZATION_TARGET_NEW_TAB_PAGE_HISTORY_CLUSTERS_MODULE_RANKING = 31;
+  // Target for web app install promotion.
+  OPTIMIZATION_TARGET_WEB_APP_INSTALLATION_PROMO = 32;
 }
 
 // The model engine versions that can be used to do model inference.
diff --git a/components/origin_trials/common/persisted_trial_token_unittest.cc b/components/origin_trials/common/persisted_trial_token_unittest.cc
index a41327c..bd9d301 100644
--- a/components/origin_trials/common/persisted_trial_token_unittest.cc
+++ b/components/origin_trials/common/persisted_trial_token_unittest.cc
@@ -7,7 +7,7 @@
 #include <string>
 
 #include "base/containers/flat_set.h"
-#include "base/strings/string_util.h"
+#include "base/strings/to_string.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/origin_trials/trial_token.h"
diff --git a/components/pdf/renderer/pdf_accessibility_tree.cc b/components/pdf/renderer/pdf_accessibility_tree.cc
index 18dda24..e337c90 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree.cc
@@ -54,9 +54,7 @@
 // images.
 class PdfOcrService final {
  public:
-  PdfOcrService(const ui::AXTreeID& parent_tree_id,
-                content::RenderFrame& render_frame)
-      : parent_tree_id_(parent_tree_id) {
+  explicit PdfOcrService(content::RenderFrame& render_frame) {
     if (features::IsPdfOcrEnabled()) {
       render_frame.GetBrowserInterfaceBroker()->GetInterface(
           screen_ai_annotator_.BindNewPipeAndPassReceiver());
@@ -70,17 +68,17 @@
   // Sends the given image to the Screen AIService for processing.
   bool ScheduleImageProcessing(
       const chrome_pdf::AccessibilityImageInfo& image,
-      screen_ai::mojom::ScreenAIAnnotator::PerformOcrCallback callback) {
+      screen_ai::mojom::ScreenAIAnnotator::
+          PerformOcrAndReturnAXTreeUpdateCallback callback) {
     if (!screen_ai_annotator_.is_bound())
       return false;
-    screen_ai_annotator_->PerformOcr(image.image_data, parent_tree_id_,
-                                     std::move(callback));
+    screen_ai_annotator_->PerformOcrAndReturnAXTreeUpdate(image.image_data,
+                                                          std::move(callback));
     return true;
   }
 
  private:
   mojo::Remote<screen_ai::mojom::ScreenAIAnnotator> screen_ai_annotator_;
-  const ui::AXTreeID parent_tree_id_;
 };
 #endif  // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
 
@@ -425,25 +423,22 @@
   return node_ptr;
 }
 
-std::unique_ptr<gfx::Transform> MakeTransformForImage(
+gfx::Transform MakeTransformForImage(
     const chrome_pdf::AccessibilityImageInfo& image) {
   // Nodes created with OCR results from the image will be misaligned on screen
   // if `image_screen_size` is different from `image_pixel_size`. To address
-  // this misalignment issue, an additional transform needs to be created. This
-  // transform will be applied to a leaf node pointing to a child tree that
-  // contains nodes created from OCR results. Once it's applied to that node,
-  // this transform will be applied to all nodes within the child tree.
+  // this misalignment issue, an additional transform needs to be created.
   const gfx::RectF& image_screen_size = image.bounds;
   const gfx::RectF image_pixel_size =
       gfx::RectF(image.image_data.width(), image.image_data.height());
   CHECK(!image_pixel_size.IsEmpty());
 
-  auto transform = std::make_unique<gfx::Transform>();
+  gfx::Transform transform;
   float width_scale_factor =
       image_screen_size.width() / image_pixel_size.width();
   float height_scale_factor =
       image_screen_size.height() / image_pixel_size.height();
-  transform->Scale(width_scale_factor, height_scale_factor);
+  transform.Scale(width_scale_factor, height_scale_factor);
 
   return transform;
 }
@@ -1299,8 +1294,7 @@
     if (render_accessibility &&
         render_accessibility->GetAXMode().has_mode(ui::AXMode::kPDFOcr)) {
       VLOG(2) << "Creating OCR service.";
-      ocr_service_ = std::make_unique<PdfOcrService>(
-          render_accessibility->GetTreeIDForPluginHost(), *render_frame);
+      ocr_service_ = std::make_unique<PdfOcrService>(*render_frame);
     }
   }
 #endif  // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
@@ -1902,7 +1896,7 @@
     const ui::AXNodeID& image_node_id,
     const chrome_pdf::AccessibilityImageInfo& image,
     const ui::AXNodeID& parent_node_id,
-    const ui::AXTreeID& child_tree_id) {
+    const ui::AXTreeUpdate& tree_update) {
   // TODO(accessibility): Following the convensions in this file, this method
   // manipulates the collection of `ui::AXNodeData` stored in the `nodes_` field
   // and then updates the `tree_` using the unserialize mechanism. It would be
@@ -1920,12 +1914,18 @@
     SetOcrCompleteStatus();
   }
 
-  if (child_tree_id == ui::AXTreeIDUnknown()) {
+  if (tree_update.nodes.empty()) {
     VLOG(1) << "Empty OCR data received.";
     return;
   }
 
-  VLOG(1) << "OCR data received: " << child_tree_id.ToString();
+  VLOG(1) << "OCR data received with a child tree update's root id: "
+          << tree_update.root_id;
+  // `tree_update` encodes a subtree that is going to be added to the PDF
+  // accessibility tree directly. Thus, `tree_update.root_id` isn't the root of
+  // the PDF accessibility tree, but the root of the subtree being added.
+  const ui::AXNodeID& page_node_id = tree_update.root_id;
+  DCHECK_NE(page_node_id, ui::kInvalidAXNodeID);
 
   const gfx::RectF& image_bounds = image.bounds;
   DCHECK_NE(image_node_id, ui::kInvalidAXNodeID);
@@ -1941,23 +1941,41 @@
   if (!render_accessibility)
     return;
 
-  ui::AXNodeData* page_node = CreateAndAppendNode(
-      ax::mojom::Role::kRegion, ax::mojom::Restriction::kReadOnly,
-      render_accessibility, &nodes_);
-  page_node->AddBoolAttribute(ax::mojom::BoolAttribute::kIsPageBreakingObject,
-                              true);
-  // TODO(crbug.com/1278249): add an attribute to indicate that this node is
-  // auto-generated.
-  // page_node->AddBoolAttribute(ax::mojom::BoolAttribute::kIsAutoGenerated,
-  // true);
-  page_node->relative_bounds.bounds = image_bounds;
   // Create a Transform to position OCR results on PDF. Without this transform,
   // nodes created from OCR results will have misaligned bounding boxes. This
-  // transform will be applied to all nodes within a child tree pointed by
-  // `child_tree_id`.
-  page_node->relative_bounds.transform = MakeTransformForImage(image);
-  page_node->AddChildTreeId(child_tree_id);
+  // transform will be applied to all nodes from OCR results below.
+  gfx::Transform transform = MakeTransformForImage(image);
 
+  // `nodes_` cannot be empty. The root node and the image node must be there.
+  CHECK(!nodes_.empty());
+  // Update all new nodes' relative_bounds. PDF accessibility tree assumes that
+  // all nodes have bounds relative to its root node.
+  ui::AXNodeData* root_node = nodes_[0].get();
+  // Copy each node from AXTreeUpdate from OCR results to create a new node for
+  // PDF accessibility tree.
+  // TODO(crbug.com/1278249): add an attribute to indicate that these nodes
+  // are auto-generated and have a way to notify the user of that.
+  for (const auto& node_from_ocr : tree_update.nodes) {
+    std::unique_ptr<ui::AXNodeData> new_node =
+        std::make_unique<ui::AXNodeData>(node_from_ocr);
+    if (new_node->id == page_node_id) {
+      // This page node will be replaced with the image node, so it needs to
+      // have the image node's bounds.
+      new_node->relative_bounds.bounds = image_bounds;
+    } else {
+      new_node->relative_bounds.bounds =
+          transform.MapRect(new_node->relative_bounds.bounds);
+      // Make all the other nodes relative to the page node.
+      new_node->relative_bounds.bounds.Offset(image_bounds.x(),
+                                              image_bounds.y());
+    }
+    // Make all nodes relative to the root node.
+    new_node->relative_bounds.offset_container_id = root_node->id;
+    // Move to `nodes_` for later unserialization in UnserializeNodes().
+    nodes_.push_back(std::move(new_node));
+  }
+
+  // Replace the image node with the page node and its subtree built above.
   int num_erased = base::EraseIf(nodes_, [&image_node_id](const auto& node) {
     return node->id == image_node_id;
   });
@@ -1969,7 +1987,7 @@
   DCHECK(parent_node_iter != ranges::end(nodes_));
   num_erased = base::Erase((*parent_node_iter)->child_ids, image_node_id);
   DCHECK_EQ(num_erased, 1);
-  (*parent_node_iter)->child_ids.push_back(page_node->id);
+  (*parent_node_iter)->child_ids.push_back(page_node_id);
 
   if (!did_unserialize_nodes_once_) {
     return;
@@ -1982,7 +2000,16 @@
   update.node_id_to_clear = image_node_id;
   update.root_id = doc_node_->id;
   update.nodes.push_back(**parent_node_iter);
-  update.nodes.push_back(*page_node);
+  // Move new nodes from `nodes_` to `update.nodes` and then remove their empty
+  // placeholders from `nodes_`.
+  auto page_node_iter = ranges::find_if(
+      nodes_,
+      [&page_node_id](const auto& node) { return node->id == page_node_id; });
+  CHECK(page_node_iter != ranges::end(nodes_));
+  ranges::for_each(page_node_iter, nodes_.end(), [&update](const auto& node) {
+    update.nodes.push_back(std::move(*node));
+  });
+  nodes_.erase(page_node_iter, ranges::end(nodes_));
 
   if (!tree_.Unserialize(update)) {
     LOG(FATAL) << tree_.error();
diff --git a/components/pdf/renderer/pdf_accessibility_tree.h b/components/pdf/renderer/pdf_accessibility_tree.h
index db2f13b2..9e7c087 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.h
+++ b/components/pdf/renderer/pdf_accessibility_tree.h
@@ -128,12 +128,14 @@
 
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
   // Removes the image node in the accessibility tree with the specified ID, and
-  // adds a page node hosting a child tree containing the page contents which
-  // will later be provided by the OCR Service.
+  // adds a page node and its child nodes built from OCR results. OCR results
+  // are provided in the format of AXTreeUpdate, which is used for storing both
+  // the page id and the new nodes built from OCR results; this AXTreeUpdate
+  // shouldn't be unserialized directly.
   void OnOcrDataReceived(const ui::AXNodeID& image_node_id,
                          const chrome_pdf::AccessibilityImageInfo& image,
                          const ui::AXNodeID& parent_node_id,
-                         const ui::AXTreeID& child_tree_id);
+                         const ui::AXTreeUpdate& tree_update);
 
   // Increment the number of remaining OCR requests by one. This function will
   // be called whenever PdfAccessibilityTreeBuilder is about to send an OCR
diff --git a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
index 3115a0c..8a58d3b 100644
--- a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
@@ -113,13 +113,13 @@
   text_node2.relative_bounds.bounds = text_bounds2;
   page_node.child_ids.push_back(text_node2.id);
 
-  ui::AXTreeUpdate initial_state;
-  initial_state.root_id = page_node.id;
-  initial_state.nodes = {page_node, text_node1, text_node2};
-  initial_state.has_tree_data = true;
-  initial_state.tree_data.title = "OCR results";
+  ui::AXTreeUpdate child_tree_update;
+  child_tree_update.root_id = page_node.id;
+  child_tree_update.nodes = {page_node, text_node1, text_node2};
+  child_tree_update.has_tree_data = true;
+  child_tree_update.tree_data.title = "OCR results";
 
-  return initial_state;
+  return child_tree_update;
 }
 #endif  // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
 
@@ -2228,19 +2228,13 @@
                                                       {80.0f, 24.0f}};
   constexpr gfx::RectF kTextBoundsBeforeTransform2 = {{16.0f, 88.0f},
                                                       {40.0f, 56.0f}};
-  ui::AXTreeUpdate initial_state = CreateMockOCRResult(
+  ui::AXTreeUpdate child_tree_update = CreateMockOCRResult(
       image.bounds, kTextBoundsBeforeTransform1, kTextBoundsBeforeTransform2);
-  screen_ai::ScreenAIAXTreeSerializer serializer(
-      render_frame->GetRenderAccessibility()->GetTreeIDForPluginHost(),
-      std::move(initial_state.nodes));
   WaitForThreadTasks();
 
-  const ui::AXTree* child_tree = serializer.tree_for_testing();
-  ASSERT_TRUE(child_tree);
-  EXPECT_NE(child_tree->GetAXTreeID(), ui::AXTreeIDUnknown());
-  EXPECT_NE(child_tree->GetAXTreeID(), ax_tree_in_pdf.GetAXTreeID());
+  EXPECT_EQ(child_tree_update.tree_data.tree_id, ui::AXTreeIDUnknown());
   pdf_accessibility_tree.OnOcrDataReceived(
-      image_node->id(), image, paragraph_node->id(), child_tree->GetAXTreeID());
+      image_node->id(), image, paragraph_node->id(), child_tree_update);
   WaitForThreadTasks();
 
   // TODO(crbug.com/1423810): Convert these in-line comments into EXPECT() with
@@ -2277,15 +2271,10 @@
   EXPECT_EQ(ax::mojom::Role::kParagraph, paragraph_node->GetRole());
   ASSERT_EQ(1u, paragraph_node->children().size());
 
-  ui::AXNode* host_node = paragraph_node->children()[0];
-  ASSERT_TRUE(host_node);
-  EXPECT_TRUE(
-      host_node->HasStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
-  ui::AXTreeID child_tree_id = ui::AXTreeID::FromString(
-      host_node->GetStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
-  ASSERT_EQ(child_tree_id, child_tree->GetAXTreeID());
-
-  ASSERT_TRUE(host_node->data().relative_bounds.transform.get());
+  ui::AXNode* region_node = paragraph_node->children()[0];
+  ASSERT_TRUE(region_node);
+  EXPECT_EQ(ax::mojom::Role::kRegion, region_node->GetRole());
+  ASSERT_EQ(2u, region_node->children().size());
 
   // Expected text bounds after applying the transform. These numbers are
   // expected to be kTextBoundsBeforeTransform * 1 / kScaleFactor.
@@ -2294,36 +2283,19 @@
   constexpr gfx::RectF kExpectedTextBoundRelativeToTreeBounds2 = {
       {20.0f, 110.0f}, {50.0f, 70.0f}};
 
-  // Check the child tree.
-  ui::AXNode* child_tree_host_node = child_tree->root();
-  ASSERT_TRUE(child_tree_host_node);
-  EXPECT_EQ(ax::mojom::Role::kRegion, child_tree_host_node->GetRole());
-  ASSERT_EQ(2u, child_tree_host_node->children().size());
-
-  ui::AXNode* child_tree_node = child_tree_host_node->children()[0];
-  ASSERT_TRUE(child_tree_node);
-  EXPECT_EQ(ax::mojom::Role::kStaticText, child_tree_node->GetRole());
-  gfx::RectF bounds = child_tree_node->data().relative_bounds.bounds;
-  CompareRect(kTextBoundsBeforeTransform1, bounds);
-  // After applying the transform via RelativeToTreeBounds.
-  bounds = child_tree->RelativeToTreeBounds(child_tree_node, bounds,
-                                            /*offscreen=*/nullptr,
-                                            /*clip_bounds=*/true,
-                                            /*skip_container_offset=*/true);
-  bounds = ax_tree_in_pdf.RelativeToTreeBounds(host_node, bounds);
+  // Check the nodes from OCR results.
+  ui::AXNode* ocred_node = region_node->children()[0];
+  ASSERT_TRUE(ocred_node);
+  EXPECT_EQ(ax::mojom::Role::kStaticText, ocred_node->GetRole());
+  gfx::RectF bounds = ocred_node->data().relative_bounds.bounds;
+  // The bounds already got updated inside of OnOcrDataReceived().
   CompareRect(kExpectedTextBoundRelativeToTreeBounds1, bounds);
 
-  child_tree_node = child_tree_host_node->children()[1];
-  ASSERT_TRUE(child_tree_node);
-  EXPECT_EQ(ax::mojom::Role::kStaticText, child_tree_node->GetRole());
-  bounds = child_tree_node->data().relative_bounds.bounds;
-  CompareRect(kTextBoundsBeforeTransform2, bounds);
-  // After applying the transform via RelativeToTreeBounds.
-  bounds = child_tree->RelativeToTreeBounds(child_tree_node, bounds,
-                                            /*offscreen=*/nullptr,
-                                            /*clip_bounds=*/true,
-                                            /*skip_container_offset=*/true);
-  bounds = ax_tree_in_pdf.RelativeToTreeBounds(host_node, bounds);
+  ocred_node = region_node->children()[1];
+  ASSERT_TRUE(ocred_node);
+  EXPECT_EQ(ax::mojom::Role::kStaticText, ocred_node->GetRole());
+  bounds = ocred_node->data().relative_bounds.bounds;
+  // The bounds already got updated inside of OnOcrDataReceived().
   CompareRect(kExpectedTextBoundRelativeToTreeBounds2, bounds);
 }
 #endif  // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn
index 59799cb..c3696899 100644
--- a/components/performance_manager/BUILD.gn
+++ b/components/performance_manager/BUILD.gn
@@ -272,6 +272,7 @@
     "decorators/page_live_state_decorator_unittest.cc",
     "decorators/page_load_tracker_decorator_unittest.cc",
     "decorators/process_hosted_content_types_aggregator_unittest.cc",
+    "decorators/process_metrics_decorator_unittest.cc",
     "execution_context/execution_context_attached_data_unittest.cc",
     "execution_context/execution_context_registry_impl_unittest.cc",
     "execution_context_priority/ad_frame_voter_unittest.cc",
diff --git a/components/performance_manager/decorators/process_metrics_decorator.cc b/components/performance_manager/decorators/process_metrics_decorator.cc
index 2c2e1122..1bbb25d 100644
--- a/components/performance_manager/decorators/process_metrics_decorator.cc
+++ b/components/performance_manager/decorators/process_metrics_decorator.cc
@@ -9,7 +9,10 @@
 #include "base/check.h"
 #include "base/feature_list.h"
 #include "base/memory/raw_ptr.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "base/values.h"
 #include "build/build_config.h"
 #include "components/performance_manager/graph/frame_node_impl.h"
 #include "components/performance_manager/graph/graph_impl.h"
@@ -18,6 +21,8 @@
 #include "components/performance_manager/graph/system_node_impl.h"
 #include "components/performance_manager/graph/worker_node_impl.h"
 #include "components/performance_manager/public/features.h"
+#include "components/performance_manager/public/graph/node_data_describer_registry.h"
+#include "components/performance_manager/public/graph/node_data_describer_util.h"
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h"
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
 
@@ -25,6 +30,43 @@
 
 namespace {
 
+void AttributeResourceToFramesAndWorkers(
+    uint64_t resource_value,
+    ProcessNodeImpl* process_node,
+    void (FrameNodeImpl::*frame_node_setter)(uint64_t),
+    void (WorkerNodeImpl::*worker_node_setter)(uint64_t),
+    void (ProcessNodeImpl::*process_node_setter)(uint64_t)) {
+  CHECK(process_node_setter);
+  (process_node->*process_node_setter)(resource_value);
+
+  // Now attribute the resources of the process to its frames and workers
+  // Only renderers can host frames and workers.
+  if (process_node->process_type() != content::PROCESS_TYPE_RENDERER) {
+    return;
+  }
+
+  const size_t frame_and_worker_node_count =
+      process_node->frame_nodes().size() + process_node->worker_nodes().size();
+  if (frame_and_worker_node_count == 0) {
+    return;
+  }
+
+  // For now, equally split the process' resources among all of its frames and
+  // workers.
+  // TODO(anthonyvd): This should be more sophisticated, like attributing the
+  // RSS and PMF to each node proportionally to its V8 heap size.
+  const uint64_t resource_estimate_part =
+      resource_value / frame_and_worker_node_count;
+  CHECK(frame_node_setter);
+  for (FrameNodeImpl* frame : process_node->frame_nodes()) {
+    (frame->*frame_node_setter)(resource_estimate_part);
+  }
+  CHECK(worker_node_setter);
+  for (WorkerNodeImpl* worker : process_node->worker_nodes()) {
+    (worker->*worker_node_setter)(resource_estimate_part);
+  }
+}
+
 // The process metrics refresh interval.
 constexpr base::TimeDelta kMetricsRefreshInterval = base::Minutes(2);
 
@@ -63,8 +105,9 @@
     ~ScopedMetricsInterestTokenImpl() {
   auto* decorator = graph_->GetRegisteredObjectAs<ProcessMetricsDecorator>();
   // This could be destroyed after removing the decorator from the graph.
-  if (decorator)
+  if (decorator) {
     decorator->OnMetricsInterestTokenReleased();
+  }
 }
 
 // static
@@ -77,15 +120,29 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   graph_ = graph;
   graph_->RegisterObject(this);
+  graph_->GetNodeDataDescriberRegistry()->RegisterDescriber(
+      this, "ProcessMetricsDecorator");
 }
 
 void ProcessMetricsDecorator::OnTakenFromGraph(Graph* graph) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CHECK_EQ(graph, graph_);
   StopTimer();
+  graph_->GetNodeDataDescriberRegistry()->UnregisterDescriber(this);
   graph_->UnregisterObject(this);
   graph_ = nullptr;
 }
 
+base::Value::Dict ProcessMetricsDecorator::DescribeSystemNodeData(
+    const SystemNode*) const {
+  base::Value::Dict ret;
+  ret.Set("interest_token_count",
+          base::NumberToString(metrics_interest_token_count_));
+  ret.Set("time_to_next_refresh",
+          TimeDeltaFromNowToValue(refresh_timer_.desired_run_time()));
+  return ret;
+}
+
 void ProcessMetricsDecorator::OnMetricsInterestTokenCreated() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   ++metrics_interest_token_count_;
@@ -107,6 +164,7 @@
 
 void ProcessMetricsDecorator::StartTimer() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CHECK(!refresh_timer_.IsRunning());
   refresh_timer_.Start(
       FROM_HERE, kMetricsRefreshInterval,
       base::BindRepeating(&ProcessMetricsDecorator::RefreshMetrics,
@@ -120,10 +178,20 @@
 
 void ProcessMetricsDecorator::RefreshMetrics() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Asynchronously update memory metrics.
   RequestProcessesMemoryMetrics(base::BindOnce(
       &ProcessMetricsDecorator::DidGetMemoryUsage, weak_factory_.GetWeakPtr()));
 }
 
+void ProcessMetricsDecorator::RefreshMetricsForTesting() {
+  // Tests may refresh the metrics outside the normal schedule. Make sure the
+  // timer isn't running so that RefreshMetrics() can call StartTimer() to
+  // schedule the next refresh.
+  StopTimer();
+  RefreshMetrics();
+}
+
 void ProcessMetricsDecorator::RequestProcessesMemoryMetrics(
     memory_instrumentation::MemoryInstrumentation::RequestGlobalDumpCallback
         callback) {
@@ -168,44 +236,24 @@
   // timestamp to the data.
   for (const auto& process_dump_iter : process_dumps->process_dumps()) {
     // Check if there's a process node associated with this PID.
-    auto* process_node =
+    ProcessNodeImpl* process_node =
         graph_impl->GetProcessNodeByPid(process_dump_iter.pid());
     if (!process_node) {
       continue;
     }
 
-    uint64_t process_pmf = process_dump_iter.os_dump().private_footprint_kb;
-    process_node->set_private_footprint_kb(process_pmf);
-
-    uint64_t process_rss = process_dump_iter.os_dump().resident_set_kb;
-    process_node->set_resident_set_kb(process_rss);
-
-    // Now attribute the RSS and PMF of the process to its frames and workers.
-    // Only renderers can host frames and workers.
-    if (process_node->process_type() != content::PROCESS_TYPE_RENDERER) {
-      continue;
-    }
-
-    size_t frame_and_worker_node_count = process_node->frame_nodes().size() +
-                                         process_node->worker_nodes().size();
-    if (frame_and_worker_node_count > 0) {
-      // For now, equally split the process' RSS and PMF among all of its frames
-      // and workers.
-      // TODO(anthonyvd): This should be more sophisticated, like attributing
-      // the RSS and PMF to each node proportionally to its V8 heap size.
-      uint64_t rss_estimate_part = process_rss / frame_and_worker_node_count;
-      uint64_t pmf_estimate_part = process_pmf / frame_and_worker_node_count;
-
-      for (FrameNodeImpl* frame : process_node->frame_nodes()) {
-        frame->SetResidentSetKbEstimate(rss_estimate_part);
-        frame->SetPrivateFootprintKbEstimate(pmf_estimate_part);
-      }
-
-      for (WorkerNodeImpl* worker : process_node->worker_nodes()) {
-        worker->SetResidentSetKbEstimate(rss_estimate_part);
-        worker->SetPrivateFootprintKbEstimate(pmf_estimate_part);
-      }
-    }
+    // Attribute the RSS and PMF of the process to its frames and workers, also
+    // saving the total in the process node.
+    AttributeResourceToFramesAndWorkers(
+        process_dump_iter.os_dump().resident_set_kb, process_node,
+        &FrameNodeImpl::SetResidentSetKbEstimate,
+        &WorkerNodeImpl::SetResidentSetKbEstimate,
+        &ProcessNodeImpl::set_resident_set_kb);
+    AttributeResourceToFramesAndWorkers(
+        process_dump_iter.os_dump().private_footprint_kb, process_node,
+        &FrameNodeImpl::SetPrivateFootprintKbEstimate,
+        &WorkerNodeImpl::SetPrivateFootprintKbEstimate,
+        &ProcessNodeImpl::set_private_footprint_kb);
   }
 
   GraphImpl::FromGraph(graph_)
diff --git a/chrome/browser/performance_manager/decorators/process_metrics_decorator_unittest.cc b/components/performance_manager/decorators/process_metrics_decorator_unittest.cc
similarity index 82%
rename from chrome/browser/performance_manager/decorators/process_metrics_decorator_unittest.cc
rename to components/performance_manager/decorators/process_metrics_decorator_unittest.cc
index 258fc8b..5f1350e 100644
--- a/chrome/browser/performance_manager/decorators/process_metrics_decorator_unittest.cc
+++ b/components/performance_manager/decorators/process_metrics_decorator_unittest.cc
@@ -7,10 +7,13 @@
 #include <memory>
 
 #include "base/memory/raw_ptr.h"
+#include "base/process/process.h"
 #include "base/run_loop.h"
+#include "base/time/time.h"
 #include "components/performance_manager/graph/process_node_impl.h"
 #include "components/performance_manager/test_support/graph_test_harness.h"
 #include "components/performance_manager/test_support/mock_graphs.h"
+#include "content/public/common/process_type.h"
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h"
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -126,6 +129,11 @@
     mock_graph_ =
         std::make_unique<MockMultiplePagesAndWorkersWithMultipleProcessesGraph>(
             graph());
+    mock_utility_process_ =
+        CreateNode<ProcessNodeImpl>(content::PROCESS_TYPE_UTILITY);
+    mock_utility_process_->SetProcess(base::Process::Current(),
+                                      /*launch_time=*/base::TimeTicks::Now());
+
     EXPECT_FALSE(decorator_raw_->IsTimerRunningForTesting());
     graph()->PassToGraph(std::move(decorator));
     EXPECT_FALSE(decorator_raw_->IsTimerRunningForTesting());
@@ -173,6 +181,14 @@
               mock_graph()->other_worker->private_footprint_kb_estimate());
   }
 
+  void ExpectUtilityProcessResults(uint64_t resident_set_kb,
+                                   uint64_t private_footprint_kb) {
+    EXPECT_EQ(resident_set_kb, mock_utility_process_->resident_set_kb());
+    EXPECT_EQ(private_footprint_kb,
+              mock_utility_process_->private_footprint_kb());
+    // No frames or workers to measure.
+  }
+
   void ResetResults() {
     mock_graph()->process->set_resident_set_kb(0);
     mock_graph()->process->set_private_footprint_kb(0);
@@ -188,8 +204,12 @@
     mock_graph()->child_frame->SetPrivateFootprintKbEstimate(0);
     mock_graph()->other_worker->SetResidentSetKbEstimate(0);
     mock_graph()->other_worker->SetPrivateFootprintKbEstimate(0);
+    mock_utility_process_->set_resident_set_kb(0);
+    mock_utility_process_->set_private_footprint_kb(0);
   }
 
+  TestNodeWrapper<ProcessNodeImpl> mock_utility_process_;
+
  private:
   raw_ptr<TestProcessMetricsDecorator> decorator_raw_;
 
@@ -205,14 +225,18 @@
   // There's no data available initially.
   ExpectProcessResults(0, 0);
   ExpectOtherProcessResults(0, 0);
+  ExpectUtilityProcessResults(0, 0);
 
   // The first measurement should be taken immediately.
   EXPECT_CALL(*decorator(), GetMemoryDump())
-      .WillOnce(Return(ByMove(GenerateMemoryDump(
-          {{mock_graph()->process->process_id(), kFakeResidentSetKb,
-            kFakePrivateFootprintKb},
-           {mock_graph()->other_process->process_id(), kFakeResidentSetKb,
-            kFakePrivateFootprintKb}}))));
+      .WillOnce(Return(ByMove(GenerateMemoryDump({
+          {mock_graph()->process->process_id(), kFakeResidentSetKb,
+           kFakePrivateFootprintKb},
+          {mock_graph()->other_process->process_id(), kFakeResidentSetKb,
+           kFakePrivateFootprintKb},
+          {mock_utility_process_->process_id(), kFakeResidentSetKb,
+           kFakePrivateFootprintKb},
+      }))));
   EXPECT_CALL(sys_node_observer, OnProcessMemoryMetricsAvailable(_));
 
   auto interest_token =
@@ -220,21 +244,26 @@
 
   ExpectProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
   ExpectOtherProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
+  ExpectUtilityProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
   ResetResults();
 
   // Advance the timer, this should trigger a refresh of the metrics.
   EXPECT_CALL(*decorator(), GetMemoryDump())
-      .WillOnce(Return(ByMove(GenerateMemoryDump(
-          {{mock_graph()->process->process_id(), kFakeResidentSetKb,
-            kFakePrivateFootprintKb},
-           {mock_graph()->other_process->process_id(), kFakeResidentSetKb,
-            kFakePrivateFootprintKb}}))));
+      .WillOnce(Return(ByMove(GenerateMemoryDump({
+          {mock_graph()->process->process_id(), kFakeResidentSetKb,
+           kFakePrivateFootprintKb},
+          {mock_graph()->other_process->process_id(), kFakeResidentSetKb,
+           kFakePrivateFootprintKb},
+          {mock_utility_process_->process_id(), kFakeResidentSetKb,
+           kFakePrivateFootprintKb},
+      }))));
   EXPECT_CALL(sys_node_observer, OnProcessMemoryMetricsAvailable(_));
 
   task_env().FastForwardBy(decorator()->GetTimerDelayForTesting());
 
   ExpectProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
   ExpectOtherProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
+  ExpectUtilityProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
   ResetResults();
 
   // Refreshes should stop when there are no tokens left.
@@ -242,12 +271,13 @@
   task_env().FastForwardBy(decorator()->GetTimerDelayForTesting());
   ExpectProcessResults(0, 0);
   ExpectOtherProcessResults(0, 0);
+  ExpectUtilityProcessResults(0, 0);
 
   graph()->RemoveSystemNodeObserver(&sys_node_observer);
 }
 
 TEST_F(ProcessMetricsDecoratorTest, PartialRefresh) {
-  // Only contains the data for one of the two processes.
+  // Only contains the data for one of the three processes.
   EXPECT_CALL(*decorator(), GetMemoryDump())
       .WillOnce(Return(ByMove(GenerateMemoryDump(
           {{mock_graph()->process->process_id(), kFakeResidentSetKb,
@@ -258,6 +288,7 @@
 
   ExpectProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
   ExpectOtherProcessResults(0, 0);
+  ExpectUtilityProcessResults(0, 0);
 
   // Do another partial refresh but this time for the other process. The
   // data attached to |mock_graph()->process| shouldn't change.
@@ -271,6 +302,7 @@
   ExpectProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
   ExpectOtherProcessResults(kFakeResidentSetKb * 2,
                             kFakePrivateFootprintKb * 2);
+  ExpectUtilityProcessResults(0, 0);
 }
 
 TEST_F(ProcessMetricsDecoratorTest, RefreshFailure) {
@@ -282,19 +314,24 @@
 
   ExpectProcessResults(0, 0);
   ExpectOtherProcessResults(0, 0);
+  ExpectUtilityProcessResults(0, 0);
 
   // A failure shouldn't stop the next refresh.
   EXPECT_CALL(*decorator(), GetMemoryDump())
-      .WillOnce(Return(ByMove(GenerateMemoryDump(
-          {{mock_graph()->process->process_id(), kFakeResidentSetKb,
-            kFakePrivateFootprintKb},
-           {mock_graph()->other_process->process_id(), kFakeResidentSetKb,
-            kFakePrivateFootprintKb}}))));
+      .WillOnce(Return(ByMove(GenerateMemoryDump({
+          {mock_graph()->process->process_id(), kFakeResidentSetKb,
+           kFakePrivateFootprintKb},
+          {mock_graph()->other_process->process_id(), kFakeResidentSetKb,
+           kFakePrivateFootprintKb},
+          {mock_utility_process_->process_id(), kFakeResidentSetKb,
+           kFakePrivateFootprintKb},
+      }))));
 
   task_env().FastForwardBy(decorator()->GetTimerDelayForTesting());
 
   ExpectProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
   ExpectOtherProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
+  ExpectUtilityProcessResults(kFakeResidentSetKb, kFakePrivateFootprintKb);
 }
 
 TEST_F(ProcessMetricsDecoratorTest, MetricsInterestTokens) {
diff --git a/components/performance_manager/graph/frame_node_impl_describer.cc b/components/performance_manager/graph/frame_node_impl_describer.cc
index 4783629..71797cb 100644
--- a/components/performance_manager/graph/frame_node_impl_describer.cc
+++ b/components/performance_manager/graph/frame_node_impl_describer.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "components/performance_manager/graph/frame_node_impl.h"
 #include "components/performance_manager/public/graph/node_data_describer_registry.h"
@@ -87,6 +88,13 @@
           ViewportIntersectionToString(impl->viewport_intersection_.value()));
   ret.Set("visibility", FrameNodeVisibilityToString(impl->visibility_.value()));
 
+  base::Value::Dict metrics;
+  metrics.Set("resident_set",
+              base::NumberToString(impl->resident_set_kb_estimate()));
+  metrics.Set("private_footprint",
+              base::NumberToString(impl->private_footprint_kb_estimate()));
+  ret.Set("metrics_estimates", std::move(metrics));
+
   return ret;
 }
 
diff --git a/components/performance_manager/graph/page_node_impl.cc b/components/performance_manager/graph/page_node_impl.cc
index 403e0049..a8b7b4d 100644
--- a/components/performance_manager/graph/page_node_impl.cc
+++ b/components/performance_manager/graph/page_node_impl.cc
@@ -279,16 +279,6 @@
   return main_frame_nodes_;
 }
 
-base::TimeTicks PageNodeImpl::usage_estimate_time() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return usage_estimate_time_;
-}
-
-uint64_t PageNodeImpl::private_footprint_kb_estimate() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return private_footprint_kb_estimate_;
-}
-
 const std::string& PageNodeImpl::browser_context_id() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return browser_context_id_;
@@ -399,18 +389,6 @@
                                          previous_type);
 }
 
-void PageNodeImpl::set_usage_estimate_time(
-    base::TimeTicks usage_estimate_time) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  usage_estimate_time_ = usage_estimate_time;
-}
-
-void PageNodeImpl::set_private_footprint_kb_estimate(
-    uint64_t private_footprint_kb_estimate) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  private_footprint_kb_estimate_ = private_footprint_kb_estimate;
-}
-
 void PageNodeImpl::set_has_nonempty_beforeunload(
     bool has_nonempty_beforeunload) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/performance_manager/graph/page_node_impl.h b/components/performance_manager/graph/page_node_impl.h
index 4657fca..82472dea 100644
--- a/components/performance_manager/graph/page_node_impl.h
+++ b/components/performance_manager/graph/page_node_impl.h
@@ -101,8 +101,6 @@
   bool is_holding_weblock() const;
   bool is_holding_indexeddb_lock() const;
   const base::flat_set<FrameNodeImpl*>& main_frame_nodes() const;
-  base::TimeTicks usage_estimate_time() const;
-  uint64_t private_footprint_kb_estimate() const;
   const GURL& main_frame_url() const;
   int64_t navigation_id() const;
   const std::string& contents_mime_type() const;
@@ -120,9 +118,6 @@
                                             EmbeddingType embedder_type);
   void ClearEmbedderFrameNodeAndEmbeddingType();
 
-  void set_usage_estimate_time(base::TimeTicks usage_estimate_time);
-  void set_private_footprint_kb_estimate(
-      uint64_t private_footprint_kb_estimate);
   void set_has_nonempty_beforeunload(bool has_nonempty_beforeunload);
   void set_freezing_vote(absl::optional<freezing::FreezingVote> freezing_vote);
   void set_page_state(PageState page_state);
@@ -268,13 +263,6 @@
   base::TimeTicks navigation_committed_time_
       GUARDED_BY_CONTEXT(sequence_checker_);
 
-  // The time the most recent resource usage estimate applies to.
-  base::TimeTicks usage_estimate_time_ GUARDED_BY_CONTEXT(sequence_checker_);
-
-  // The most current memory footprint estimate.
-  uint64_t private_footprint_kb_estimate_
-      GUARDED_BY_CONTEXT(sequence_checker_) = 0;
-
   // Indicates whether or not this page has a non-empty beforeunload handler.
   // This is an aggregation of the same value on each frame in the page's frame
   // tree. The aggregation is made at the moment all frames associated with a
diff --git a/components/performance_manager/graph/page_node_impl_describer.cc b/components/performance_manager/graph/page_node_impl_describer.cc
index 7263105..39cfae85 100644
--- a/components/performance_manager/graph/page_node_impl_describer.cc
+++ b/components/performance_manager/graph/page_node_impl_describer.cc
@@ -52,13 +52,6 @@
   result.Set(
       "navigation_committed_time",
       TimeDeltaFromNowToValue(page_node_impl->navigation_committed_time_));
-  result.Set("usage_estimate_time",
-             TimeDeltaFromNowToValue(page_node_impl->usage_estimate_time_));
-  // TODO(pmonette): Instead of emitting a raw number, this could be a human
-  //                 readable string. E.g. "14.8 MiB" instead of "14523".
-  result.Set(
-      "private_footprint_kb_estimate",
-      base::NumberToString(page_node_impl->private_footprint_kb_estimate_));
   result.Set("has_nonempty_beforeunload",
              page_node_impl->has_nonempty_beforeunload_);
   result.Set("main_frame_url", page_node_impl->main_frame_url_.value().spec());
@@ -88,6 +81,15 @@
   result.Set("freezing_vote",
              FreezingVoteToString(page_node_impl->freezing_vote()));
 
+  base::Value::Dict estimates;
+  estimates.Set(
+      "private_footprint_kb",
+      base::NumberToString(page_node_impl->EstimatePrivateFootprintSize()));
+  estimates.Set(
+      "resident_set_size_kb",
+      base::NumberToString(page_node_impl->EstimateResidentSetSize()));
+  result.Set("estimates", std::move(estimates));
+
   return result;
 }
 
diff --git a/components/performance_manager/graph/worker_node_impl.h b/components/performance_manager/graph/worker_node_impl.h
index 178fcf3b..9ef377c 100644
--- a/components/performance_manager/graph/worker_node_impl.h
+++ b/components/performance_manager/graph/worker_node_impl.h
@@ -51,13 +51,9 @@
   void AddClientWorker(WorkerNodeImpl* worker_node);
   void RemoveClientWorker(WorkerNodeImpl* worker_node);
 
-  // Sets the worker priority, and the reason behind it.
+  // Setters are not thread safe.
   void SetPriorityAndReason(const PriorityAndReason& priority_and_reason);
-
-  // Sets the Resident Set Size estimate.
   void SetResidentSetKbEstimate(uint64_t rss_estimate);
-
-  // Sets the Private Footprint Size estimate.
   void SetPrivateFootprintKbEstimate(uint64_t pmf_estimate);
 
   // Invoked when the worker script was fetched and the final response URL is
diff --git a/components/performance_manager/graph/worker_node_impl_describer.cc b/components/performance_manager/graph/worker_node_impl_describer.cc
index 782e9a1..877679a 100644
--- a/components/performance_manager/graph/worker_node_impl_describer.cc
+++ b/components/performance_manager/graph/worker_node_impl_describer.cc
@@ -4,6 +4,8 @@
 
 #include "components/performance_manager/graph/worker_node_impl_describer.h"
 
+#include <utility>
+
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "components/performance_manager/graph/worker_node_impl.h"
@@ -51,6 +53,13 @@
   ret.Set("worker_type", WorkerTypeToString(impl->worker_type()));
   ret.Set("priority", PriorityAndReasonToValue(impl->priority_and_reason()));
 
+  base::Value::Dict metrics;
+  metrics.Set("resident_set",
+              base::NumberToString(impl->resident_set_kb_estimate()));
+  metrics.Set("private_footprint",
+              base::NumberToString(impl->private_footprint_kb_estimate()));
+  ret.Set("metrics_estimates", std::move(metrics));
+
   return ret;
 }
 
diff --git a/components/performance_manager/public/decorators/process_metrics_decorator.h b/components/performance_manager/public/decorators/process_metrics_decorator.h
index 66443da..eda9374 100644
--- a/components/performance_manager/public/decorators/process_metrics_decorator.h
+++ b/components/performance_manager/public/decorators/process_metrics_decorator.h
@@ -8,8 +8,10 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
+#include "base/values.h"
 #include "components/performance_manager/public/graph/graph.h"
 #include "components/performance_manager/public/graph/graph_registered.h"
+#include "components/performance_manager/public/graph/node_data_describer.h"
 
 namespace memory_instrumentation {
 class GlobalMemoryDump;
@@ -17,11 +19,14 @@
 
 namespace performance_manager {
 
+class SystemNode;
+
 // The ProcessMetricsDecorator is responsible for adorning process nodes with
 // performance metrics.
 class ProcessMetricsDecorator
     : public GraphOwned,
-      public GraphRegisteredImpl<ProcessMetricsDecorator> {
+      public GraphRegisteredImpl<ProcessMetricsDecorator>,
+      public NodeDataDescriberDefaultImpl {
  public:
   ProcessMetricsDecorator();
 
@@ -56,6 +61,10 @@
   void OnPassedToGraph(Graph* graph) override;
   void OnTakenFromGraph(Graph* graph) override;
 
+  // NodeDataDescriber
+  base::Value::Dict DescribeSystemNodeData(
+      const SystemNode* node) const override;
+
   void SetGraphForTesting(Graph* graph) { graph_ = graph; }
   bool IsTimerRunningForTesting() const { return refresh_timer_.IsRunning(); }
 
@@ -63,7 +72,7 @@
     return refresh_timer_.GetCurrentDelay();
   }
 
-  void RefreshMetricsForTesting() { RefreshMetrics(); }
+  void RefreshMetricsForTesting();
 
  protected:
   class ScopedMetricsInterestTokenImpl;
@@ -72,7 +81,7 @@
   void StartTimer();
   void StopTimer();
 
-  // Schedule a refresh of the metrics for all the process nodes.
+  // Asynchronously refreshes the metrics for all the process nodes.
   void RefreshMetrics();
 
   // Query the MemoryInstrumentation service to get the memory metrics for all
diff --git a/components/performance_manager/public/graph/frame_node.h b/components/performance_manager/public/graph/frame_node.h
index 53ea21c7..2d6f54e 100644
--- a/components/performance_manager/public/graph/frame_node.h
+++ b/components/performance_manager/public/graph/frame_node.h
@@ -224,6 +224,9 @@
   // proxy may only be dereferenced on the UI thread.
   virtual const RenderFrameHostProxy& GetRenderFrameHostProxy() const = 0;
 
+  // TODO(joenotcharles): Move the resource usage estimates to a separate
+  // class.
+
   // Returns the most recently estimated resident set of the frame, in
   // kilobytes. This is an estimate because RSS is computed by process, and a
   // process can host multiple frames.
diff --git a/components/performance_manager/public/graph/worker_node.h b/components/performance_manager/public/graph/worker_node.h
index 7dde8497..b7f49264 100644
--- a/components/performance_manager/public/graph/worker_node.h
+++ b/components/performance_manager/public/graph/worker_node.h
@@ -118,6 +118,9 @@
   // having that particular priority.
   virtual const PriorityAndReason& GetPriorityAndReason() const = 0;
 
+  // TODO(joenotcharles): Move the resource usage estimates to a separate
+  // class.
+
   // Returns the most recently estimated resident set of the worker, in
   // kilobytes. This is an estimate because RSS is computed by process, and a
   // process can host multiple workers.
diff --git a/components/performance_manager/public/user_tuning/prefs.h b/components/performance_manager/public/user_tuning/prefs.h
index b5f8519..de95971 100644
--- a/components/performance_manager/public/user_tuning/prefs.h
+++ b/components/performance_manager/public/user_tuning/prefs.h
@@ -5,8 +5,6 @@
 #ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_USER_TUNING_PREFS_H_
 #define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_USER_TUNING_PREFS_H_
 
-#include "base/timer/timer.h"
-
 class PrefRegistrySimple;
 class PrefService;
 
@@ -27,10 +25,6 @@
 
 extern const char kHighEfficiencyModeState[];
 
-extern const char kHighEfficiencyModeTimeBeforeDiscardInMinutes[];
-
-extern const int kDefaultHighEfficiencyModeTimeBeforeDiscardInMinutes;
-
 enum class BatterySaverModeState {
   kDisabled = 0,
   kEnabledBelowThreshold = 1,
@@ -59,9 +53,6 @@
 HighEfficiencyModeState GetCurrentHighEfficiencyModeState(
     PrefService* pref_service);
 
-base::TimeDelta GetCurrentHighEfficiencyModeTimeBeforeDiscard(
-    PrefService* pref_service);
-
 BatterySaverModeState GetCurrentBatterySaverModeState(
     PrefService* pref_service);
 
diff --git a/components/performance_manager/user_tuning/prefs.cc b/components/performance_manager/user_tuning/prefs.cc
index 45ea721..1ced436 100644
--- a/components/performance_manager/user_tuning/prefs.cc
+++ b/components/performance_manager/user_tuning/prefs.cc
@@ -17,11 +17,6 @@
 const char kHighEfficiencyModeState[] =
     "performance_tuning.high_efficiency_mode.state";
 
-const char kHighEfficiencyModeTimeBeforeDiscardInMinutes[] =
-    "performance_tuning.high_efficiency_mode.time_before_discard_in_minutes";
-
-const int kDefaultHighEfficiencyModeTimeBeforeDiscardInMinutes = 120;
-
 const char kBatterySaverModeState[] =
     "performance_tuning.battery_saver_mode.state";
 
@@ -37,9 +32,6 @@
 void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(kHighEfficiencyModeEnabled, false);
   registry->RegisterIntegerPref(
-      kHighEfficiencyModeTimeBeforeDiscardInMinutes,
-      kDefaultHighEfficiencyModeTimeBeforeDiscardInMinutes);
-  registry->RegisterIntegerPref(
       kHighEfficiencyModeState,
       static_cast<int>(HighEfficiencyModeState::kDisabled));
   registry->RegisterIntegerPref(
@@ -67,19 +59,6 @@
   return static_cast<HighEfficiencyModeState>(state);
 }
 
-base::TimeDelta GetCurrentHighEfficiencyModeTimeBeforeDiscard(
-    PrefService* pref_service) {
-  int time_before_discard_in_minutes =
-      pref_service->GetInteger(kHighEfficiencyModeTimeBeforeDiscardInMinutes);
-  if (time_before_discard_in_minutes < 0) {
-    pref_service->ClearPref(kHighEfficiencyModeTimeBeforeDiscardInMinutes);
-    time_before_discard_in_minutes =
-        pref_service->GetInteger(kHighEfficiencyModeTimeBeforeDiscardInMinutes);
-  }
-
-  return base::Minutes(time_before_discard_in_minutes);
-}
-
 BatterySaverModeState GetCurrentBatterySaverModeState(
     PrefService* pref_service) {
   int state = pref_service->GetInteger(kBatterySaverModeState);
diff --git a/components/policy/core/common/policy_loader_command_line_unittest.cc b/components/policy/core/common/policy_loader_command_line_unittest.cc
index 3697077..40023eb 100644
--- a/components/policy/core/common/policy_loader_command_line_unittest.cc
+++ b/components/policy/core/common/policy_loader_command_line_unittest.cc
@@ -27,7 +27,7 @@
         std::make_unique<PolicyBundle>(loader->Load());
     PolicyMap& map =
         bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
-    EXPECT_EQ(expected_policies.DictSize(), map.size());
+    EXPECT_EQ(expected_policies.GetDict().size(), map.size());
     for (auto expected_policy : expected_policies.GetDict()) {
       const PolicyMap::Entry* actual_policy = map.Get(expected_policy.first);
       ASSERT_TRUE(actual_policy);
diff --git a/components/qr_code_generator/qr_code_generator.cc b/components/qr_code_generator/qr_code_generator.cc
index aca906a..e2e718f 100644
--- a/components/qr_code_generator/qr_code_generator.cc
+++ b/components/qr_code_generator/qr_code_generator.cc
@@ -612,10 +612,13 @@
       VersionClassForVersion(version_info->version);
   if (version_info != version_info_) {
     version_info_ = version_info;
-    d_.resize(version_info_->total_size());
   }
-  // Previous data and "set" bits must be cleared.
-  memset(&d_[0], 0, version_info_->total_size());
+
+  // If this is the first time `Generate` is called, then `d_` is a brand-new
+  // (empty) vector.  If `Generate` has been called in the past, then `d_` is a
+  // vector in a moved-from state.  Either way, we need to construct a new
+  // vector.
+  d_ = std::vector<uint8_t>(version_info_->total_size(), 0);
 
   const size_t framed_input_size =
       version_info_->group1_data_bytes() + version_info_->group2_data_bytes();
@@ -784,8 +787,10 @@
           kMaskFunctions[best_mask]);
 
   GeneratedCode code;
-  code.data = base::span<uint8_t>(&d_[0], version_info_->total_size());
+  code.data = std::move(d_);
   code.qr_size = version_info_->size;
+  CHECK_EQ(code.data.size(), version_info_->total_size());
+  CHECK_EQ(code.data.size(), static_cast<size_t>(code.qr_size * code.qr_size));
   return code;
 }
 
diff --git a/components/qr_code_generator/qr_code_generator.h b/components/qr_code_generator/qr_code_generator.h
index beb0c82..b9bd3ac 100644
--- a/components/qr_code_generator/qr_code_generator.h
+++ b/components/qr_code_generator/qr_code_generator.h
@@ -34,13 +34,21 @@
 
     ~GeneratedCode();
 
-    // Pixel data; pointer to an array of bytes, where the least-significant
-    // bit of each byte is set if that tile should be "black".
-    // Clients should ensure four modules of padding when rendering the code.
-    // On error, will not be populated, and will evaluate to false.
-    base::span<uint8_t> data;
+    // Pixel data.  The least-significant bit of each byte is set if that
+    // tile/module should be "black".
+    //
+    // Clients should ensure four tiles/modules of padding when rendering the
+    // code.
+    //
+    // On error, will not be populated, and will contain an empty vector.
+    std::vector<uint8_t> data;
 
-    // Width and height (which are equal) of the generated data, in tiles.
+    // Width and height (which are equal) of the generated data, in
+    // tiles/modules.
+    //
+    // The following invariant holds: `qr_size * qr_size == data.size()`.
+    //
+    // On error, will not be populated, and will contain 0.
     int qr_size = 0;
   };
 
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
index 5b28d3f..dff14f8c 100644
--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
+++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
@@ -262,7 +262,8 @@
                           bool is_maximizable) override;
   void SetOpacity(float opacity) override;
   void SetWindowLevel(int32_t level) override;
-  void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
+  void SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                      const gfx::Size& excluded_margin) override;
   void SetCALayerParams(const gfx::CALayerParams& ca_layer_params) override;
   void SetWindowTitle(const std::u16string& title) override;
   void SetIgnoresMouseEvents(bool ignores_mouse_events) override;
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
index 129ba29c..f13ccec 100644
--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
+++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -1506,10 +1506,11 @@
 }
 
 void NativeWidgetNSWindowBridge::SetAspectRatio(
-    const gfx::SizeF& aspect_ratio) {
+    const gfx::SizeF& aspect_ratio,
+    const gfx::Size& excluded_margin) {
   DCHECK(!aspect_ratio.IsEmpty());
-  [window_delegate_
-      setAspectRatio:aspect_ratio.width() / aspect_ratio.height()];
+  [window_delegate_ setAspectRatio:aspect_ratio.width() / aspect_ratio.height()
+                    excludedMargin:excluded_margin];
 }
 
 void NativeWidgetNSWindowBridge::SetCALayerParams(
diff --git a/components/remote_cocoa/app_shim/views_nswindow_delegate.h b/components/remote_cocoa/app_shim/views_nswindow_delegate.h
index 52a803a..ba8f5332 100644
--- a/components/remote_cocoa/app_shim/views_nswindow_delegate.h
+++ b/components/remote_cocoa/app_shim/views_nswindow_delegate.h
@@ -12,6 +12,7 @@
 #import "base/mac/scoped_nsobject.h"
 #include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace remote_cocoa {
 class NativeWidgetNSWindowBridge;
@@ -26,6 +27,7 @@
       _parent;  // Weak. Owns this.
   base::scoped_nsobject<NSCursor> _cursor;
   absl::optional<float> _aspectRatio;
+  gfx::Size _excludedMargin;
 
   // Only valid during a live resize.
   // Used to keep track of whether a resize is happening horizontally or
@@ -69,7 +71,8 @@
 // but its implementation prioritizes the aspect ratio over the minimum size:
 // one of the dimensions can go below the minimum size if that's what it takes
 // to maintain the aspect ratio. This is inacceptable for us.
-- (void)setAspectRatio:(float)aspectRatio;
+- (void)setAspectRatio:(float)aspectRatio
+        excludedMargin:(const gfx::Size&)excludedMargin;
 
 @end
 
diff --git a/components/remote_cocoa/app_shim/views_nswindow_delegate.mm b/components/remote_cocoa/app_shim/views_nswindow_delegate.mm
index c3dc9f3..1b21bb2 100644
--- a/components/remote_cocoa/app_shim/views_nswindow_delegate.mm
+++ b/components/remote_cocoa/app_shim/views_nswindow_delegate.mm
@@ -104,8 +104,10 @@
   DCHECK(!_parent->target_fullscreen_state());
 }
 
-- (void)setAspectRatio:(float)aspectRatio {
+- (void)setAspectRatio:(float)aspectRatio
+        excludedMargin:(const gfx::Size&)excludedMargin {
   _aspectRatio = aspectRatio;
+  _excludedMargin = excludedMargin;
 }
 
 - (NSSize)windowWillResize:(NSWindow*)window toSize:(NSSize)size {
@@ -126,10 +128,11 @@
   if (!maxSize.IsEmpty())
     maxSizeParam = maxSize;
 
-  gfx::SizeRectToAspectRatio(*_resizingHorizontally ? gfx::ResizeEdge::kRight
-                                                    : gfx::ResizeEdge::kBottom,
-                             *_aspectRatio, gfx::Size([window minSize]),
-                             maxSizeParam, &resizedWindowRect);
+  gfx::SizeRectToAspectRatioWithExcludedMargin(
+      *_resizingHorizontally ? gfx::ResizeEdge::kRight
+                             : gfx::ResizeEdge::kBottom,
+      *_aspectRatio, gfx::Size([window minSize]), maxSizeParam, _excludedMargin,
+      resizedWindowRect);
   // Discard any updates to |resizedWindowRect| origin as Cocoa takes care of
   // that.
   return resizedWindowRect.size().ToCGSize();
diff --git a/components/remote_cocoa/common/native_widget_ns_window.mojom b/components/remote_cocoa/common/native_widget_ns_window.mojom
index 5f1d2bcc..397d5106 100644
--- a/components/remote_cocoa/common/native_widget_ns_window.mojom
+++ b/components/remote_cocoa/common/native_widget_ns_window.mojom
@@ -214,8 +214,23 @@
   // Set the window level of the NSWindow.
   SetWindowLevel(int32 level);
 
-  // Set the aspect ratio of the NSWindow. |aspect_ratio| must not be empty.
-  SetAspectRatio(gfx.mojom.SizeF aspect_ratio);
+  // Set the aspect ratio of the NSWindow. `aspect_ratio` must not be empty.
+  // The aspect ratio refers to the client area only; system-drawn window
+  // decorations like a title bar are not considered in the aspect ratio.
+  //
+  // `excluded_margin` is the amount of client area to ignore when computing
+  // the aspect ratio.  This allows for client-drawn window decorations to be
+  // excluded from the aspect-ratio-constrained size, similar to how system-
+  // drawn decorations are excluded.  If no adjustment is needed, such as if
+  // there are no client-drawn window decorations, then set `excluded_margin`
+  // to (0, 0).
+  //
+  // For example, `aspect_ratio` == 1.f, and `excluded_margin` == (10, 15)
+  // would allow a client area size of (40, 45), since (40-10)/(45-15) == 1.
+  // Presumably, (10, 15) of this area would be used to draw client-drawn
+  // decorations, while the remaining (30, 30) would be used for whatever
+  // content is supposed to have a 1.f aspect-ratio.
+  SetAspectRatio(gfx.mojom.SizeF aspect_ratio, gfx.mojom.Size excluded_margin);
 
   // Specify the content to draw in the NSView.
   SetCALayerParams(gfx.mojom.CALayerParams ca_layer_params);
diff --git a/components/safe_browsing/core/browser/verdict_cache_manager.cc b/components/safe_browsing/core/browser/verdict_cache_manager.cc
index d86690e..02bd1a7 100644
--- a/components/safe_browsing/core/browser/verdict_cache_manager.cc
+++ b/components/safe_browsing/core/browser/verdict_cache_manager.cc
@@ -622,7 +622,7 @@
     for (auto item : source.setting_value.GetDict()) {
       if (item.first == base::StringPiece(kRealTimeUrlCacheKey)) {
         stored_verdict_count_real_time_url_check_.value() +=
-            item.second.DictSize();
+            item.second.GetDict().size();
       }
     }
   }
@@ -1060,10 +1060,9 @@
 
   int verdict_cnt = 0;
   if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
-    base::Value* password_on_focus_dict =
-        cache_dictionary_value.GetDict().Find(kPasswordOnFocusCacheKey);
-    verdict_cnt +=
-        password_on_focus_dict ? password_on_focus_dict->DictSize() : 0;
+    base::Value::Dict* password_on_focus_dict =
+        cache_dictionary_value.GetDict().FindDict(kPasswordOnFocusCacheKey);
+    verdict_cnt += password_on_focus_dict ? password_on_focus_dict->size() : 0;
   } else {
     for (auto [key, value] : cache_dictionary_value.GetDict()) {
       if (key == kPasswordOnFocusCacheKey) {
diff --git a/components/segmentation_platform/internal/BUILD.gn b/components/segmentation_platform/internal/BUILD.gn
index 84e5040..29fb323 100644
--- a/components/segmentation_platform/internal/BUILD.gn
+++ b/components/segmentation_platform/internal/BUILD.gn
@@ -302,6 +302,8 @@
     "signals/history_delegate_impl_unittest.cc",
     "signals/mock_histogram_signal_handler.cc",
     "signals/mock_histogram_signal_handler.h",
+    "signals/mock_user_action_signal_handler.cc",
+    "signals/mock_user_action_signal_handler.h",
     "signals/signal_filter_processor_unittest.cc",
     "signals/ukm_config_unittest.cc",
     "signals/ukm_observer_unittest.cc",
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector.cc b/components/segmentation_platform/internal/data_collection/training_data_collector.cc
index 397d44e..e091282 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector.cc
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector.cc
@@ -14,13 +14,14 @@
 std::unique_ptr<TrainingDataCollector> TrainingDataCollector::Create(
     processing::FeatureListQueryProcessor* processor,
     HistogramSignalHandler* histogram_signal_handler,
+    UserActionSignalHandler* user_action_signal_handler,
     StorageService* storage_service,
     std::vector<std::unique_ptr<Config>>* configs,
     PrefService* profile_prefs,
     base::Clock* clock) {
   return std::make_unique<TrainingDataCollectorImpl>(
-      processor, histogram_signal_handler, storage_service, configs,
-      profile_prefs, clock);
+      processor, histogram_signal_handler, user_action_signal_handler,
+      storage_service, configs, profile_prefs, clock);
 }
 
 TrainingDataCollector::TrainingDataCollector() = default;
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector.h b/components/segmentation_platform/internal/data_collection/training_data_collector.h
index 50a4c26..6b5beed 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector.h
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector.h
@@ -11,6 +11,7 @@
 #include "components/segmentation_platform/internal/database/storage_service.h"
 #include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/signals/histogram_signal_handler.h"
+#include "components/segmentation_platform/internal/signals/user_action_signal_handler.h"
 #include "components/segmentation_platform/public/input_context.h"
 #include "components/segmentation_platform/public/proto/model_metadata.pb.h"
 #include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
@@ -40,6 +41,7 @@
   static std::unique_ptr<TrainingDataCollector> Create(
       processing::FeatureListQueryProcessor* processor,
       HistogramSignalHandler* histogram_signal_handler,
+      UserActionSignalHandler* user_action_signal_handler,
       StorageService* storage_service,
       std::vector<std::unique_ptr<Config>>* configs,
       PrefService* profile_prefs,
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
index 66264e2..bd73dee 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.cc
@@ -7,6 +7,7 @@
 
 #include "base/logging.h"
 #include "base/metrics/metrics_hashes.h"
+#include "base/metrics/user_metrics.h"
 #include "base/notreached.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/clock.h"
@@ -99,6 +100,7 @@
 TrainingDataCollectorImpl::TrainingDataCollectorImpl(
     processing::FeatureListQueryProcessor* processor,
     HistogramSignalHandler* histogram_signal_handler,
+    UserActionSignalHandler* user_action_signal_handler,
     StorageService* storage_service,
     std::vector<std::unique_ptr<Config>>* configs,
     PrefService* profile_prefs,
@@ -106,6 +108,7 @@
     : segment_info_database_(storage_service->segment_info_database()),
       feature_list_query_processor_(processor),
       histogram_signal_handler_(histogram_signal_handler),
+      user_action_signal_handler_(user_action_signal_handler),
       signal_storage_config_(storage_service->signal_storage_config()),
       configs_(configs),
       clock_(clock),
@@ -116,6 +119,7 @@
 
 TrainingDataCollectorImpl::~TrainingDataCollectorImpl() {
   histogram_signal_handler_->RemoveObserver(this);
+  user_action_signal_handler_->RemoveObserver(this);
 }
 
 void TrainingDataCollectorImpl::OnModelMetadataUpdated() {
@@ -137,6 +141,7 @@
 void TrainingDataCollectorImpl::OnGetSegmentsInfoList(
     DefaultModelManager::SegmentInfoList segments) {
   histogram_signal_handler_->AddObserver(this);
+  user_action_signal_handler_->AddObserver(this);
   std::map<SegmentId, proto::SegmentInfo> segment_list =
       GetPreferredSegmentInfo(std::move(segments));
 
@@ -206,9 +211,15 @@
       const auto& trigger = training_config.observation_trigger(i);
       if (trigger.has_uma_trigger() &&
           trigger.uma_trigger().has_uma_feature()) {
-        immediate_trigger_histograms_
-            [trigger.uma_trigger().uma_feature().name_hash()]
-                .emplace(segment.first);
+        const auto& feature = trigger.uma_trigger().uma_feature();
+        if (feature.type() == proto::SignalType::USER_ACTION) {
+          immediate_trigger_user_actions_[feature.name_hash()].emplace(
+              segment.first);
+        } else if (feature.type() == proto::SignalType::HISTOGRAM_VALUE ||
+                   feature.type() == proto::SignalType::HISTOGRAM_ENUM) {
+          immediate_trigger_histograms_[feature.name_hash()].emplace(
+              segment.first);
+        }
       }
     }
   }
@@ -232,14 +243,33 @@
     param->output_value = static_cast<float>(sample);
     for (auto segment : segments) {
       segment_info_database_->GetSegmentInfo(
-          segment, base::BindOnce(&TrainingDataCollectorImpl::
-                                      OnHistogramUpdatedReportForSegmentInfo,
-                                  weak_ptr_factory_.GetWeakPtr(), param));
+          segment,
+          base::BindOnce(
+              &TrainingDataCollectorImpl::OnUmaUpdatedReportForSegmentInfo,
+              weak_ptr_factory_.GetWeakPtr(), param));
     }
   }
 }
 
-void TrainingDataCollectorImpl::OnHistogramUpdatedReportForSegmentInfo(
+void TrainingDataCollectorImpl::OnUserAction(const std::string& user_action,
+                                             base::TimeTicks action_time) {
+  // Report training data for all models which output collection is triggered by
+  // |user_action|.
+  auto hash = base::HashMetricName(user_action);
+  auto it = immediate_trigger_user_actions_.find(hash);
+  if (it != immediate_trigger_user_actions_.end()) {
+    auto segments = it->second;
+    for (auto segment : segments) {
+      segment_info_database_->GetSegmentInfo(
+          segment,
+          base::BindOnce(
+              &TrainingDataCollectorImpl::OnUmaUpdatedReportForSegmentInfo,
+              weak_ptr_factory_.GetWeakPtr(), absl::nullopt));
+    }
+  }
+}
+
+void TrainingDataCollectorImpl::OnUmaUpdatedReportForSegmentInfo(
     const absl::optional<ImmediaCollectionParam>& param,
     absl::optional<proto::SegmentInfo> segment) {
   if (segment.has_value()) {
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.h b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.h
index b7c0759..d1eedd2c 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl.h
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl.h
@@ -18,6 +18,7 @@
 #include "components/segmentation_platform/internal/database/segment_info_database.h"
 #include "components/segmentation_platform/internal/proto/model_prediction.pb.h"
 #include "components/segmentation_platform/internal/signals/histogram_signal_handler.h"
+#include "components/segmentation_platform/internal/signals/user_action_signal_handler.h"
 #include "components/segmentation_platform/public/model_provider.h"
 #include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -30,10 +31,12 @@
 
 // Implementation of TrainingDataCollector.
 class TrainingDataCollectorImpl : public TrainingDataCollector,
-                                  public HistogramSignalHandler::Observer {
+                                  public HistogramSignalHandler::Observer,
+                                  public UserActionSignalHandler::Observer {
  public:
   TrainingDataCollectorImpl(processing::FeatureListQueryProcessor* processor,
                             HistogramSignalHandler* histogram_signal_handler,
+                            UserActionSignalHandler* user_action_signal_handler,
                             StorageService* storage_service,
                             std::vector<std::unique_ptr<Config>>* configs,
                             PrefService* profile_prefs,
@@ -56,6 +59,10 @@
   void OnHistogramSignalUpdated(const std::string& histogram_name,
                                 base::HistogramBase::Sample sample) override;
 
+  // UserActionSignalHandler::Observer implementation.
+  void OnUserAction(const std::string& user_action,
+                    base::TimeTicks action_time) override;
+
  private:
   struct TrainingTimings;
 
@@ -65,7 +72,7 @@
       const absl::optional<ImmediaCollectionParam>& param,
       std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> segments);
 
-  void OnHistogramUpdatedReportForSegmentInfo(
+  void OnUmaUpdatedReportForSegmentInfo(
       const absl::optional<ImmediaCollectionParam>& param,
       absl::optional<proto::SegmentInfo> segment);
 
@@ -124,6 +131,7 @@
   const raw_ptr<processing::FeatureListQueryProcessor>
       feature_list_query_processor_;
   const raw_ptr<HistogramSignalHandler> histogram_signal_handler_;
+  const raw_ptr<UserActionSignalHandler> user_action_signal_handler_;
   const raw_ptr<SignalStorageConfig> signal_storage_config_;
   const raw_ptr<std::vector<std::unique_ptr<Config>>> configs_;
   const raw_ptr<base::Clock> clock_;
@@ -147,6 +155,10 @@
   base::flat_map<uint64_t, base::flat_set<proto::SegmentId>>
       immediate_trigger_histograms_;
 
+  // Hash of user actions for trigger based training data collection.
+  base::flat_map<uint64_t, base::flat_set<proto::SegmentId>>
+      immediate_trigger_user_actions_;
+
   // A list of segment IDs that needs to report metrics continuously.
   base::flat_set<SegmentId> continuous_collection_segments_;
 
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc b/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
index 1a02de8..a607083 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
@@ -24,11 +24,13 @@
 #include "components/segmentation_platform/internal/segmentation_ukm_helper.h"
 #include "components/segmentation_platform/internal/selection/segmentation_result_prefs.h"
 #include "components/segmentation_platform/internal/signals/mock_histogram_signal_handler.h"
+#include "components/segmentation_platform/internal/signals/mock_user_action_signal_handler.h"
 #include "components/segmentation_platform/public/config.h"
 #include "components/segmentation_platform/public/features.h"
 #include "components/segmentation_platform/public/local_state_helper.h"
 #include "components/segmentation_platform/public/model_provider.h"
 #include "components/segmentation_platform/public/proto/model_metadata.pb.h"
+#include "components/segmentation_platform/public/proto/types.pb.h"
 #include "components/segmentation_platform/public/segmentation_platform_service.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
@@ -119,7 +121,8 @@
 
     collector_ = std::make_unique<TrainingDataCollectorImpl>(
         &feature_list_processor_, &histogram_signal_handler_,
-        storage_service_.get(), &configs_, &prefs_, &clock_);
+        &user_action_signal_handler_, storage_service_.get(), &configs_,
+        &prefs_, &clock_);
   }
 
  protected:
@@ -140,7 +143,8 @@
     collector_.reset();
     collector_ = std::make_unique<TrainingDataCollectorImpl>(
         &feature_list_processor_, &histogram_signal_handler_,
-        storage_service_.get(), &configs_, &prefs_, &clock_);
+        &user_action_signal_handler_, storage_service_.get(), &configs_,
+        &prefs_, &clock_);
   }
 
   proto::SegmentInfo* CreateSegmentInfo(DecisionType type,
@@ -166,6 +170,7 @@
           uma_trigger->mutable_uma_trigger()->mutable_uma_feature();
       uma_feature->set_name(kHistogramName0);
       uma_feature->set_name_hash(base::HashMetricName(kHistogramName0));
+      uma_feature->set_type(proto::SignalType::HISTOGRAM_VALUE);
     } else if (type == kPeriodicDecisionType) {
       // Add a uma feature output based on |kHistogramName0| if trigger type is
       // PERIODIC.
@@ -174,6 +179,19 @@
     return segment_info;
   }
 
+  void AddUserActionTrigger(proto::SegmentInfo* segment_info,
+                            std::string name) {
+    auto* trigger = segment_info->mutable_model_metadata()
+                        ->mutable_training_outputs()
+                        ->mutable_trigger_config();
+    auto* uma_trigger = trigger->add_observation_trigger();
+    auto* uma_feature =
+        uma_trigger->mutable_uma_trigger()->mutable_uma_feature();
+    uma_feature->set_name(name);
+    uma_feature->set_name_hash(base::HashMetricName(name));
+    uma_feature->set_type(proto::SignalType::USER_ACTION);
+  }
+
   void AddTimeTrigger(proto::SegmentInfo* segment_info, base::TimeDelta delay) {
     // Add a time delay trigger.
     auto* trigger = segment_info->mutable_model_metadata()
@@ -280,6 +298,15 @@
     run_loop.Run();
   }
 
+  void WaitForUserActionSignalUpdated(const std::string& user_action_name,
+                                      base::TimeTicks action_time) {
+    base::RunLoop run_loop;
+    test_recorder_.SetOnAddEntryCallback(
+        Segmentation_ModelExecution::kEntryName, run_loop.QuitClosure());
+    collector_->OnUserAction(user_action_name, action_time);
+    run_loop.Run();
+  }
+
   void WaitForContinuousCollection() {
     base::RunLoop run_loop;
     test_recorder_.SetOnAddEntryCallback(
@@ -296,6 +323,7 @@
   ukm::TestAutoSetUkmRecorder test_recorder_;
   NiceMock<processing::MockFeatureListQueryProcessor> feature_list_processor_;
   NiceMock<MockHistogramSignalHandler> histogram_signal_handler_;
+  NiceMock<MockUserActionSignalHandler> user_action_signal_handler_;
   raw_ptr<NiceMock<MockSignalStorageConfig>> signal_storage_config_;
   raw_ptr<test::TestSegmentInfoDatabase> test_segment_info_db_;
   std::unique_ptr<TrainingDataCollectorImpl> collector_;
@@ -541,6 +569,32 @@
   ExpectResult1Ukm();
 }
 
+// Tests that if uma user action trigger is set, collection will happen when the
+// trigger user action is observed.
+TEST_F(TrainingDataCollectorImplTest, DataCollectionWithUserActionTrigger) {
+  constexpr base::TimeDelta kTriggerDuration = base::Seconds(10);
+  base::Time current = clock()->Now();
+  SetupFeatureProcessorResult1(current, current + kTriggerDuration);
+
+  // Create a segment that contain a uma trigger.
+  AddUserActionTrigger(
+      CreateSegmentInfo(kOnDemandDecisionType, /*upload_tensors=*/true),
+      kHistogramName1);
+  Init();
+
+  // Wait for input collection to be done and cached in memory.
+  auto input_context = base::MakeRefCounted<InputContext>();
+  collector()->OnDecisionTime(kTestOptimizationTarget0, input_context,
+                              proto::TrainingOutputs::TriggerConfig::ONDEMAND);
+  task_environment()->RunUntilIdle();
+  clock()->Advance(kTriggerDuration);
+  ExpectUkmCount(0u);
+
+  // Trigger output collection and ukm data recording.
+  WaitForUserActionSignalUpdated(kHistogramName1, base::TimeTicks());
+  ExpectResult1Ukm();
+}
+
 // A histogram interested by multiple model will trigger multiple UKM reports.
 TEST_F(TrainingDataCollectorImplTest,
        DataCollectionWithUMATrigger_MultipleModels) {
@@ -566,6 +620,7 @@
   auto* uma_feature = uma_trigger->mutable_uma_trigger()->mutable_uma_feature();
   uma_feature->set_name(kHistogramName0);
   uma_feature->set_name_hash(base::HashMetricName(kHistogramName0));
+  uma_feature->set_type(proto::SignalType::HISTOGRAM_VALUE);
 
   // Wait for input collection to be done and cached in memory.
   Init();
diff --git a/components/segmentation_platform/internal/metadata/metadata_utils.cc b/components/segmentation_platform/internal/metadata/metadata_utils.cc
index 7954979..88dbb40 100644
--- a/components/segmentation_platform/internal/metadata/metadata_utils.cc
+++ b/components/segmentation_platform/internal/metadata/metadata_utils.cc
@@ -407,6 +407,19 @@
     }
   }
 
+  // Add uma trigger features.
+  if (model_metadata.training_outputs().has_trigger_config()) {
+    const auto& training_config =
+        model_metadata.training_outputs().trigger_config();
+    for (int i = 0; i < training_config.observation_trigger_size(); i++) {
+      const auto& trigger = training_config.observation_trigger(i);
+      if (trigger.has_uma_trigger() &&
+          trigger.uma_trigger().has_uma_feature()) {
+        features.push_back(trigger.uma_trigger().uma_feature());
+      }
+    }
+  }
+
   return features;
 }
 
diff --git a/components/segmentation_platform/internal/scheduler/execution_service.cc b/components/segmentation_platform/internal/scheduler/execution_service.cc
index e7795af5..67b7a8b 100644
--- a/components/segmentation_platform/internal/scheduler/execution_service.cc
+++ b/components/segmentation_platform/internal/scheduler/execution_service.cc
@@ -57,8 +57,9 @@
 
   training_data_collector_ = TrainingDataCollector::Create(
       feature_list_query_processor_.get(),
-      signal_handler->deprecated_histogram_signal_handler(), storage_service,
-      configs, profile_prefs, clock);
+      signal_handler->deprecated_histogram_signal_handler(),
+      signal_handler->user_action_signal_handler(), storage_service, configs,
+      profile_prefs, clock);
 
   model_executor_ = std::make_unique<ModelExecutorImpl>(
       clock, feature_list_query_processor_.get());
diff --git a/components/segmentation_platform/internal/signals/mock_user_action_signal_handler.cc b/components/segmentation_platform/internal/signals/mock_user_action_signal_handler.cc
new file mode 100644
index 0000000..516abbf
--- /dev/null
+++ b/components/segmentation_platform/internal/signals/mock_user_action_signal_handler.cc
@@ -0,0 +1,14 @@
+// Copyright 2023 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/segmentation_platform/internal/signals/mock_user_action_signal_handler.h"
+
+namespace segmentation_platform {
+
+MockUserActionSignalHandler::MockUserActionSignalHandler()
+    : UserActionSignalHandler(nullptr) {}
+
+MockUserActionSignalHandler::~MockUserActionSignalHandler() = default;
+
+}  // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/signals/mock_user_action_signal_handler.h b/components/segmentation_platform/internal/signals/mock_user_action_signal_handler.h
new file mode 100644
index 0000000..766327ac
--- /dev/null
+++ b/components/segmentation_platform/internal/signals/mock_user_action_signal_handler.h
@@ -0,0 +1,26 @@
+// Copyright 2023 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_SEGMENTATION_PLATFORM_INTERNAL_SIGNALS_MOCK_USER_ACTION_SIGNAL_HANDLER_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SIGNALS_MOCK_USER_ACTION_SIGNAL_HANDLER_H_
+
+#include "components/segmentation_platform/internal/signals/user_action_signal_handler.h"
+
+#include "components/segmentation_platform/public/proto/types.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace segmentation_platform {
+
+class MockUserActionSignalHandler : public UserActionSignalHandler {
+ public:
+  MockUserActionSignalHandler();
+  ~MockUserActionSignalHandler() override;
+
+  MOCK_METHOD(void, SetRelevantUserActions, (std::set<uint64_t>));
+  MOCK_METHOD(void, EnableMetrics, (bool));
+};
+
+}  // namespace segmentation_platform
+
+#endif  // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SIGNALS_MOCK_USER_ACTION_SIGNAL_HANDLER_H_
diff --git a/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc b/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
index 63faeb8..98996495 100644
--- a/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
+++ b/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
@@ -20,6 +20,7 @@
 #include "components/segmentation_platform/internal/signals/histogram_signal_handler.h"
 #include "components/segmentation_platform/internal/signals/history_service_observer.h"
 #include "components/segmentation_platform/internal/signals/mock_histogram_signal_handler.h"
+#include "components/segmentation_platform/internal/signals/mock_user_action_signal_handler.h"
 #include "components/segmentation_platform/internal/signals/user_action_signal_handler.h"
 #include "components/segmentation_platform/public/proto/aggregation.pb.h"
 #include "components/segmentation_platform/public/proto/types.pb.h"
@@ -44,12 +45,6 @@
 }
 
 }  // namespace
-class MockUserActionSignalHandler : public UserActionSignalHandler {
- public:
-  MockUserActionSignalHandler() : UserActionSignalHandler(nullptr) {}
-  MOCK_METHOD(void, SetRelevantUserActions, (std::set<uint64_t>));
-  MOCK_METHOD(void, EnableMetrics, (bool));
-};
 
 class MockHistoryObserver : public HistoryServiceObserver {
  public:
diff --git a/components/segmentation_platform/internal/signals/signal_handler.h b/components/segmentation_platform/internal/signals/signal_handler.h
index 12c24ae..d0f7756 100644
--- a/components/segmentation_platform/internal/signals/signal_handler.h
+++ b/components/segmentation_platform/internal/signals/signal_handler.h
@@ -58,6 +58,9 @@
   HistogramSignalHandler* deprecated_histogram_signal_handler() {
     return histogram_signal_handler_.get();
   }
+  UserActionSignalHandler* user_action_signal_handler() {
+    return user_action_signal_handler_.get();
+  }
 
  private:
   std::unique_ptr<UserActionSignalHandler> user_action_signal_handler_;
diff --git a/components/segmentation_platform/internal/signals/user_action_signal_handler.cc b/components/segmentation_platform/internal/signals/user_action_signal_handler.cc
index eb576c91..14a39fd6 100644
--- a/components/segmentation_platform/internal/signals/user_action_signal_handler.cc
+++ b/components/segmentation_platform/internal/signals/user_action_signal_handler.cc
@@ -4,6 +4,7 @@
 
 #include "components/segmentation_platform/internal/signals/user_action_signal_handler.h"
 
+#include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/metrics/metrics_hashes.h"
 #include "components/segmentation_platform/internal/database/signal_database.h"
@@ -19,6 +20,7 @@
 }
 
 UserActionSignalHandler::~UserActionSignalHandler() {
+  DCHECK(observers_.empty());
   if (metrics_enabled_ && base::GetRecordActionTaskRunner())
     base::RemoveActionCallback(action_callback_);
 }
@@ -43,6 +45,14 @@
   user_actions_ = std::move(user_actions);
 }
 
+void UserActionSignalHandler::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void UserActionSignalHandler::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void UserActionSignalHandler::OnUserAction(const std::string& user_action,
                                            base::TimeTicks action_time) {
   DCHECK(metrics_enabled_);
@@ -51,8 +61,22 @@
   if (iter == user_actions_.end())
     return;
 
-  db_->WriteSample(proto::SignalType::USER_ACTION, user_action_hash,
-                   absl::nullopt, base::DoNothing());
+  db_->WriteSample(
+      proto::SignalType::USER_ACTION, user_action_hash, absl::nullopt,
+      base::BindOnce(&UserActionSignalHandler::OnSampleWritten,
+                     weak_ptr_factory_.GetWeakPtr(), user_action, action_time));
+}
+
+void UserActionSignalHandler::OnSampleWritten(const std::string& user_action,
+                                              base::TimeTicks action_time,
+                                              bool success) {
+  if (!success) {
+    return;
+  }
+
+  for (Observer& ob : observers_) {
+    ob.OnUserAction(user_action, action_time);
+  }
 }
 
 }  // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/signals/user_action_signal_handler.h b/components/segmentation_platform/internal/signals/user_action_signal_handler.h
index 986fe7b..7a5edda 100644
--- a/components/segmentation_platform/internal/signals/user_action_signal_handler.h
+++ b/components/segmentation_platform/internal/signals/user_action_signal_handler.h
@@ -10,6 +10,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/user_metrics.h"
+#include "base/observer_list.h"
 #include "base/time/time.h"
 
 namespace segmentation_platform {
@@ -20,6 +21,18 @@
 // internal database for future processing.
 class UserActionSignalHandler {
  public:
+  class Observer : public base::CheckedObserver {
+   public:
+    // Called when a histogram signal tracked by segmentation platform is
+    // updated and written to database.
+    virtual void OnUserAction(const std::string& user_action,
+                              base::TimeTicks action_time) = 0;
+    ~Observer() override = default;
+
+   protected:
+    Observer() = default;
+  };
+
   explicit UserActionSignalHandler(SignalDatabase* signal_database);
   virtual ~UserActionSignalHandler();
 
@@ -35,9 +48,16 @@
   // This can be called early even before relevant user actions are known.
   virtual void EnableMetrics(bool enable_metrics);
 
+  // Add/Remove observer for histogram update events.
+  virtual void AddObserver(Observer* observer);
+  virtual void RemoveObserver(Observer* observer);
+
  private:
   void OnUserAction(const std::string& user_action,
                     base::TimeTicks action_time);
+  void OnSampleWritten(const std::string& user_action,
+                       base::TimeTicks action_time,
+                       bool success);
 
   // The database storing relevant user actions.
   raw_ptr<SignalDatabase> db_;
@@ -50,6 +70,8 @@
   // else will be filtered out.
   std::set<uint64_t> user_actions_;
 
+  base::ObserverList<Observer> observers_;
+
   // Whether or not the segmentation platform should record metrics events.
   bool metrics_enabled_;
 
diff --git a/components/segmentation_platform/internal/stats.cc b/components/segmentation_platform/internal/stats.cc
index 1fcf875..8f519f92 100644
--- a/components/segmentation_platform/internal/stats.cc
+++ b/components/segmentation_platform/internal/stats.cc
@@ -43,6 +43,7 @@
     case SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT:
     case SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_FEED_USER:
     case SegmentId::OPTIMIZATION_TARGET_CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING:
+    case SegmentId::OPTIMIZATION_TARGET_WEB_APP_INSTALLATION_PROMO:
       return proto::SegmentationModelMetadata::RETURN_TYPE_PROBABILITY;
     case SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER:
     case SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_TABLET_PRODUCTIVITY_USER:
diff --git a/components/segmentation_platform/public/constants.cc b/components/segmentation_platform/public/constants.cc
index 4969ef3..d780ef1 100644
--- a/components/segmentation_platform/public/constants.cc
+++ b/components/segmentation_platform/public/constants.cc
@@ -6,6 +6,7 @@
 
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
+#include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
 
 namespace segmentation_platform {
 
@@ -46,6 +47,8 @@
     return kDeviceSwitcherUmaName;
   } else if (segmentation_key == kTabletProductivityUserKey) {
     return kTabletProductivityUserUmaName;
+  } else if (segmentation_key == kWebAppInstallationPromoKey) {
+    return kWebAppInstallationPromoUmaName;
   } else if (segmentation_key == kDeviceTierKey) {
     return kDeviceTierUmaName;
   } else if (base::StartsWith(segmentation_key, "test_key")) {
@@ -106,6 +109,8 @@
     case proto::SegmentId::
         OPTIMIZATION_TARGET_SEGMENTATION_TABLET_PRODUCTIVITY_USER:
       return "TabletProductivityUserSegment";
+    case proto::SegmentId::OPTIMIZATION_TARGET_WEB_APP_INSTALLATION_PROMO:
+      return "WebAppInstallationPromo";
     case proto::SegmentId::DEVICE_TIER_SEGMENT:
       return "DeviceTierSegment";
     default:
diff --git a/components/segmentation_platform/public/constants.h b/components/segmentation_platform/public/constants.h
index 1070862..e8b2725 100644
--- a/components/segmentation_platform/public/constants.h
+++ b/components/segmentation_platform/public/constants.h
@@ -83,6 +83,11 @@
 const char kTabletProductivityUserKey[] = "tablet_productivity_user";
 const char kTabletProductivityUserUmaName[] = "TabletProductivityUser";
 
+// The key is used to decide whether the user should receive a web app
+// installation promotion.
+const char kWebAppInstallationPromoKey[] = "web_app_installation_promo";
+const char kWebAppInstallationPromoUmaName[] = "WebAppInstallationPromo";
+
 // Key for segment that tells in which tier the device used by the user belongs.
 const char kDeviceTierKey[] = "device_tier";
 const char kDeviceTierUmaName[] = "DeviceTier";
diff --git a/components/segmentation_platform/public/proto/segmentation_platform.proto b/components/segmentation_platform/public/proto/segmentation_platform.proto
index 804077eb..6accf07 100644
--- a/components/segmentation_platform/public/proto/segmentation_platform.proto
+++ b/components/segmentation_platform/public/proto/segmentation_platform.proto
@@ -18,7 +18,7 @@
 enum SegmentId {
   // Reserved fields are `OptimizationTarget`s that are not usde by segmentation
   // to prevent accidental misuse.
-  reserved 1, 2, 3, 7, 8, 9, 13, 14, 15, 19, 20, 24, 25, 26;
+  reserved 1, 2, 3, 7, 8, 9, 13, 14, 15, 19, 20, 24, 25, 26, 30, 31;
 
   OPTIMIZATION_TARGET_UNKNOWN = 0;
   // Target for segmentation: New tab page user.
@@ -51,6 +51,8 @@
   OPTIMIZATION_TARGET_SEGMENTATION_ADAPTIVE_TOOLBAR = 28;
   // Target for segmentation: Determine users who are tabletproductivity users.
   OPTIMIZATION_TARGET_SEGMENTATION_TABLET_PRODUCTIVITY_USER = 29;
+  // Target for web app install promotion.
+  OPTIMIZATION_TARGET_WEB_APP_INSTALLATION_PROMO = 32;
   // Add new entries to OptimizationTarget proto.
 
   // New entries should start from a 1000 if OptimizationTarget does not
diff --git a/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc b/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
index 3efb18f8..9a5fa4c4 100644
--- a/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
+++ b/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
@@ -50,10 +50,11 @@
   // TODO(crbug/1199857): Tune these limits.
   constexpr int kMB = 1024 * 1024;
 #if BUILDFLAG(IS_ANDROID)
-  SkGraphics::SetFontCacheLimit(base::SysInfo::IsLowEndDevice() ? kMB
-                                                                : 8 * kMB);
-  SkGraphics::SetResourceCacheTotalByteLimit(
-      base::SysInfo::IsLowEndDevice() ? 32 * kMB : 64 * kMB);
+  bool is_low_end_mode =
+      base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled();
+  SkGraphics::SetFontCacheLimit(is_low_end_mode ? kMB : 8 * kMB);
+  SkGraphics::SetResourceCacheTotalByteLimit(is_low_end_mode ? 32 * kMB
+                                                             : 64 * kMB);
   SkGraphics::SetResourceCacheSingleAllocationByteLimit(16 * kMB);
 #else
   SkGraphics::SetResourceCacheSingleAllocationByteLimit(64 * kMB);
diff --git a/components/services/screen_ai/proto/visual_annotator_proto_convertor.cc b/components/services/screen_ai/proto/visual_annotator_proto_convertor.cc
index f2316c1..23b9eea0 100644
--- a/components/services/screen_ai/proto/visual_annotator_proto_convertor.cc
+++ b/components/services/screen_ai/proto/visual_annotator_proto_convertor.cc
@@ -29,15 +29,22 @@
 
 namespace {
 
-ui::AXNodeID next_node_id{1};
+// A negative ID for ui::AXNodeID needs to start from -2 as using -1 for this
+// node id is still incorrectly treated as invalid.
+// TODO(crbug.com/1439285): fix code treating -1 as invalid for ui::AXNodeID.
+constexpr int kFirstValidNegativeId = -2;
+
+ui::AXNodeID next_negative_node_id{kFirstValidNegativeId};
 
 // TODO(crbug.com/1278249): Check if this max count will cover different cases.
 constexpr int kUmaMaxNodesCount = 500;
 
-// Returns the next valid ID that can be used for identifying `AXNode`s in the
-// accessibility tree.
-ui::AXNodeID GetNextNodeID() {
-  return next_node_id++;
+// Returns the next valid negative ID that can be used for identifying
+// `AXNode`s in the accessibility tree. Using negative IDs here enables
+// adding nodes built from OCR results to PDF accessibility tree in PDF
+// renderer without updating their IDs.
+ui::AXNodeID GetNextNegativeNodeID() {
+  return next_negative_node_id--;
 }
 
 bool HaveIdenticalFormattingStyle(const chrome_screen_ai::WordBox& word_1,
@@ -293,7 +300,7 @@
   ui::AXNodeData& inline_text_box_node = node_data[node_index];
   DCHECK_EQ(inline_text_box_node.role, ax::mojom::Role::kUnknown);
   inline_text_box_node.role = ax::mojom::Role::kInlineTextBox;
-  inline_text_box_node.id = GetNextNodeID();
+  inline_text_box_node.id = GetNextNegativeNodeID();
   // The union of the bounding boxes in this formatting context is set as the
   // bounding box of `inline_text_box_node`.
   DCHECK(inline_text_box_node.relative_bounds.bounds.IsEmpty());
@@ -339,7 +346,7 @@
   ui::AXNodeData& current_node = node_data[index];
   if (!SerializePredictedType(ui_component.predicted_type(), current_node))
     return;
-  current_node.id = GetNextNodeID();
+  current_node.id = GetNextNegativeNodeID();
   SerializeBoundingBox(ui_component.bounding_box(), parent_node.id,
                        current_node);
   parent_node.child_ids.push_back(current_node.id);
@@ -359,7 +366,7 @@
   DCHECK_EQ(line_box_node.role, ax::mojom::Role::kUnknown);
 
   SerializeContentType(line_box.content_type(), line_box_node);
-  line_box_node.id = GetNextNodeID();
+  line_box_node.id = GetNextNegativeNodeID();
   SerializeBoundingBox(line_box.bounding_box(), parent_node.id, line_box_node);
   // `ax::mojom::NameFrom` should be set to the correct value based on the
   // role.
@@ -385,7 +392,7 @@
 namespace screen_ai {
 
 void ResetNodeIDForTesting() {
-  next_node_id = 1;
+  next_negative_node_id = kFirstValidNegativeId;
 }
 
 // TODO(nektar): Change return value to `std::vector<ui::AXNodeData>` as other
@@ -456,7 +463,7 @@
   if (!visual_annotation.ui_component().empty()) {
     ui::AXNodeData& rootnode = nodes[index++];
     rootnode.role = ax::mojom::Role::kDialog;
-    rootnode.id = GetNextNodeID();
+    rootnode.id = GetNextNegativeNodeID();
     rootnode.relative_bounds.bounds = gfx::RectF(image_rect);
     for (const auto& ui_component : visual_annotation.ui_component())
       SerializeUIComponent(ui_component, index++, rootnode, nodes);
@@ -466,7 +473,8 @@
     // We assume that OCR is performed on a page-by-page basis.
     ui::AXNodeData& page_node = nodes[index++];
     page_node.role = ax::mojom::Role::kRegion;
-    page_node.id = GetNextNodeID();
+    page_node.id = GetNextNegativeNodeID();
+    update.root_id = page_node.id;
     page_node.AddBoolAttribute(ax::mojom::BoolAttribute::kIsPageBreakingObject,
                                true);
     page_node.relative_bounds.bounds = gfx::RectF(image_rect);
diff --git a/components/services/screen_ai/proto/visual_annotator_proto_convertor_unittest.cc b/components/services/screen_ai/proto/visual_annotator_proto_convertor_unittest.cc
index d537965..a0d48da 100644
--- a/components/services/screen_ai/proto/visual_annotator_proto_convertor_unittest.cc
+++ b/components/services/screen_ai/proto/visual_annotator_proto_convertor_unittest.cc
@@ -49,11 +49,11 @@
         VisualAnnotationToAXTreeUpdate(annotation, snapshot_bounds);
 
     const std::string expected_update(
-        "id=1 dialog child_ids=2,3 (0, 0)-(800, 900)\n"
-        "  id=2 button offset_container_id=1 (0, 1)-(2, 3)"
+        "id=-2 dialog child_ids=-3,-4 (0, 0)-(800, 900)\n"
+        "  id=-3 button offset_container_id=-2 (0, 1)-(2, 3)"
         " transform=[ 0 -1 0 0\n  1 0 0 0\n  0 0 1 0\n  0 0 0 1 ]\n"
         "\n"
-        "  id=3 genericContainer offset_container_id=1 (0, 0)-(5, 5) "
+        "  id=-4 genericContainer offset_container_id=-2 (0, 0)-(5, 5) "
         "role_description=Signature\n");
     EXPECT_EQ(expected_update, update.ToString());
   }
@@ -114,12 +114,13 @@
         VisualAnnotationToAXTreeUpdate(annotation, snapshot_bounds);
 
     const std::string expected_update(
-        "id=1 region child_ids=2 (0, 0)-(800, 900) "
+        "AXTreeUpdate: root id -2\n"
+        "id=-2 region child_ids=-3 (0, 0)-(800, 900) "
         "is_page_breaking_object=true\n"
-        "  id=2 staticText name=Hello world child_ids=3 offset_container_id=1 "
-        "(100, 100)-(500, 20) "
+        "  id=-3 staticText name=Hello world child_ids=-4 "
+        "offset_container_id=-2 (100, 100)-(500, 20) "
         "text_direction=rtl language=en\n"
-        "    id=3 inlineTextBox name=Hello world (100, 100)-(500, 20) "
+        "    id=-4 inlineTextBox name=Hello world (100, 100)-(500, 20) "
         "background_color=&C350 color=&61A8 text_direction=rtl language=en "
         "word_starts=0,6 word_ends=6,11\n");
     EXPECT_EQ(expected_update, update.ToString());
diff --git a/components/services/screen_ai/public/mojom/screen_ai_service.mojom b/components/services/screen_ai/public/mojom/screen_ai_service.mojom
index d8ec94ae..fc92629 100644
--- a/components/services/screen_ai/public/mojom/screen_ai_service.mojom
+++ b/components/services/screen_ai/public/mojom/screen_ai_service.mojom
@@ -26,11 +26,11 @@
   // Receives an image, such as a screenshot or a page from a PDF file, as well
   // as the ID of the accessibility tree that contains the image
   // (`parent_tree_id`). It then asks the Screen AI library to perform OCR on
-  // the image. It returns the ID of the accessibility tree which would be
-  // created by the Service containing the output of the library.
-  PerformOcr(skia.mojom.BitmapN32 image,
-    ax.mojom.AXTreeID parent_tree_id) =>
-    (ax.mojom.AXTreeID child_tree_id);
+  // the image. It returns an AXTreeUpdate with nodes built from OCR results.
+  // The returned AXTreeUpdate is not a properly serialized update and is only
+  // a container for the root id of a subtree and nodes built from OCR results.
+  PerformOcrAndReturnAXTreeUpdate(skia.mojom.BitmapN32 image) =>
+    (ax.mojom.AXTreeUpdate update);
 };
 
 // This interface sends accessibility messages from the Screen AI Service to
diff --git a/components/services/screen_ai/screen_ai_service_impl.cc b/components/services/screen_ai/screen_ai_service_impl.cc
index 00f03628..bbacce2 100644
--- a/components/services/screen_ai/screen_ai_service_impl.cc
+++ b/components/services/screen_ai/screen_ai_service_impl.cc
@@ -169,66 +169,82 @@
                                          std::move(main_content_extractor));
 }
 
-void ScreenAIService::PerformVisualAnnotation(
+void ScreenAIService::ExtractSemanticLayout(
     const SkBitmap& image,
     const ui::AXTreeID& parent_tree_id,
-    PerformOcrCallback callback,
-    bool run_ocr,
-    bool run_layout_extraction) {
+    ExtractSemanticLayoutCallback callback) {
   std::unique_ptr<ui::AXTreeUpdate> annotation =
       std::make_unique<ui::AXTreeUpdate>();
   ui::AXTreeUpdate* annotation_ptr = annotation.get();
 
-  // Ownership of |annotation| is passed to the reply function, and hence it is
-  // destroyed after the task function is called, or both functions get
-  // cancelled, so it's safe to pass |annotation_ptr| unretained.
   // We need to get the pointer beforehand since compiler optimizations may
-  // result in binding the reply function (and moving |annotation|) before
+  // result in binding the reply function (and moving `annotation`) before
   // binding the task.
   task_runner_->PostTaskAndReply(
       FROM_HERE,
       base::BindOnce(&ScreenAIService::VisualAnnotationInternal,
                      weak_ptr_factory_.GetWeakPtr(), std::move(image),
-                     std::move(parent_tree_id), run_ocr, run_layout_extraction,
-                     base::Unretained(annotation_ptr)),
+                     /*run_ocr=*/false, /*run_layout_extraction=*/true,
+                     annotation_ptr),
       base::BindOnce(
           [](mojo::Remote<mojom::ScreenAIAnnotatorClient>* client,
-             PerformOcrCallback callback,
+             const ui::AXTreeID& parent_tree_id,
+             ExtractSemanticLayoutCallback callback,
              std::unique_ptr<ui::AXTreeUpdate> update) {
             // The original caller is always replied to, and an AXTreeIDUnknown
             // is sent to tell it that the annotation function was not
             // successful. However the client is only contacted for successful
             // runs and when we have an update.
+            ScreenAIAXTreeSerializer serializer(parent_tree_id,
+                                                std::move(update->nodes));
+            *update = serializer.Serialize();
+            // `ScreenAIAXTreeSerializer` should have assigned a new tree ID to
+            // `update`. Thereby, it should never be an unknown tree ID,
+            // otherwise there has been an unexpected serialization bug.
+            DCHECK_NE(update->tree_data.tree_id, ui::AXTreeIDUnknown())
+                << "Invalid serialization.\n"
+                << update->ToString();
             std::move(callback).Run(update->tree_data.tree_id);
             if (update->tree_data.tree_id != ui::AXTreeIDUnknown())
               (*client)->HandleAXTreeUpdate(*update);
           },
-          &screen_ai_annotator_client_, std::move(callback),
-          std::move(annotation)));
+          &screen_ai_annotator_client_, std::move(parent_tree_id),
+          std::move(callback), std::move(annotation)));
 }
 
-void ScreenAIService::ExtractSemanticLayout(const SkBitmap& image,
-                                            const ui::AXTreeID& parent_tree_id,
-                                            PerformOcrCallback callback) {
-  PerformVisualAnnotation(std::move(image), parent_tree_id, std::move(callback),
-                          /*run_ocr=*/false,
-                          /*run_layout_extraction=*/true);
-}
-
-void ScreenAIService::PerformOcr(const SkBitmap& image,
-                                 const ui::AXTreeID& parent_tree_id,
-                                 PerformOcrCallback callback) {
-  PerformVisualAnnotation(std::move(image), parent_tree_id, std::move(callback),
-                          /*run_ocr=*/true,
-                          /*run_layout_extraction=*/false);
-}
-
-void ScreenAIService::VisualAnnotationInternal(
+void ScreenAIService::PerformOcrAndReturnAXTreeUpdate(
     const SkBitmap& image,
-    const ui::AXTreeID& parent_tree_id,
-    bool run_ocr,
-    bool run_layout_extraction,
-    ui::AXTreeUpdate* annotation) {
+    PerformOcrAndReturnAXTreeUpdateCallback callback) {
+  std::unique_ptr<ui::AXTreeUpdate> annotation =
+      std::make_unique<ui::AXTreeUpdate>();
+  ui::AXTreeUpdate* annotation_ptr = annotation.get();
+
+  // We need to get the pointer beforehand since compiler optimizations may
+  // result in binding the reply function (and moving `annotation`) before
+  // binding the task.
+  task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&ScreenAIService::VisualAnnotationInternal,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(image),
+                     /*run_ocr=*/true, /*run_layout_extraction=*/false,
+                     annotation_ptr),
+      base::BindOnce(
+          [](PerformOcrAndReturnAXTreeUpdateCallback callback,
+             std::unique_ptr<ui::AXTreeUpdate> update) {
+            // The original caller is always replied to, and an empty
+            // AXTreeUpdate tells that the annotation function was not
+            // successful.
+            std::move(callback).Run(*update);
+            // TODO(crbug.com/1434701): Send the AXTreeUpdate to the browser
+            // side client for Backlight.
+          },
+          std::move(callback), std::move(annotation)));
+}
+
+void ScreenAIService::VisualAnnotationInternal(const SkBitmap& image,
+                                               bool run_ocr,
+                                               bool run_layout_extraction,
+                                               ui::AXTreeUpdate* annotation) {
   // Currently we only support either of OCR or LayoutExtraction features.
   DCHECK_NE(run_ocr, run_layout_extraction);
   DCHECK(screen_ai_annotator_client_.is_bound());
@@ -250,16 +266,6 @@
 
   gfx::Rect image_rect(image.width(), image.height());
   *annotation = VisualAnnotationToAXTreeUpdate(annotation_proto, image_rect);
-  ScreenAIAXTreeSerializer serializer(parent_tree_id,
-                                      std::move(annotation->nodes));
-  *annotation = serializer.Serialize();
-
-  // `ScreenAIAXTreeSerializer` should have assigned a new tree ID to `update`.
-  // Thereby, it should never be an unknown tree ID, otherwise there has been an
-  // unexpected serialization bug.
-  DCHECK_NE(annotation->tree_data.tree_id, ui::AXTreeIDUnknown())
-      << "Invalid serialization.\n"
-      << annotation->ToString();
 }
 
 void ScreenAIService::ExtractMainContent(const ui::AXTreeUpdate& snapshot,
diff --git a/components/services/screen_ai/screen_ai_service_impl.h b/components/services/screen_ai/screen_ai_service_impl.h
index 6ece8e2..3fa1ede1 100644
--- a/components/services/screen_ai/screen_ai_service_impl.h
+++ b/components/services/screen_ai/screen_ai_service_impl.h
@@ -60,12 +60,12 @@
   // mojom::ScreenAIAnnotator:
   void ExtractSemanticLayout(const SkBitmap& image,
                              const ui::AXTreeID& parent_tree_id,
-                             PerformOcrCallback callback) override;
+                             ExtractSemanticLayoutCallback callback) override;
 
   // mojom::ScreenAIAnnotator:
-  void PerformOcr(const SkBitmap& image,
-                  const ui::AXTreeID& parent_tree_id,
-                  PerformOcrCallback callback) override;
+  void PerformOcrAndReturnAXTreeUpdate(
+      const SkBitmap& image,
+      PerformOcrAndReturnAXTreeUpdateCallback callback) override;
 
   // mojom::Screen2xMainContentExtractor:
   void ExtractMainContent(const ui::AXTreeUpdate& snapshot,
@@ -92,16 +92,8 @@
       mojo::PendingReceiver<mojom::Screen2xMainContentExtractor>
           main_content_extractor) override;
 
-  // Common section of PerformOcr and ExtractSemanticLayout functions.
-  void PerformVisualAnnotation(const SkBitmap& image,
-                               const ui::AXTreeID& parent_tree_id,
-                               PerformOcrCallback callback,
-                               bool run_ocr,
-                               bool run_layout_extraction);
-
   // Wrapper functions for task scheduler.
   void VisualAnnotationInternal(const SkBitmap& image,
-                                const ui::AXTreeID& parent_tree_id,
                                 bool run_ocr,
                                 bool run_layout_extraction,
                                 ui::AXTreeUpdate* annotation);
diff --git a/components/services/storage/dom_storage/session_storage_impl.cc b/components/services/storage/dom_storage/session_storage_impl.cc
index 4b03f068..9be2391 100644
--- a/components/services/storage/dom_storage/session_storage_impl.cc
+++ b/components/services/storage/dom_storage/session_storage_impl.cc
@@ -110,7 +110,8 @@
       memory_dump_id_(base::StringPrintf("SessionStorage/0x%" PRIXPTR,
                                          reinterpret_cast<uintptr_t>(this))),
       receiver_(this, std::move(receiver)),
-      is_low_end_device_(base::SysInfo::IsLowEndDevice()) {
+      is_low_end_mode_(
+          base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled()) {
   base::trace_event::MemoryDumpManager::GetInstance()
       ->RegisterDumpProviderWithSequencedTaskRunner(
           this, "SessionStorage", std::move(memory_dump_task_runner),
@@ -455,8 +456,9 @@
     purge_reason = SessionStorageCachePurgeReason::kSizeLimitExceeded;
   else if (data_maps_.size() > kMaxSessionStorageAreaCount)
     purge_reason = SessionStorageCachePurgeReason::kAreaCountLimitExceeded;
-  else if (is_low_end_device_)
+  else if (is_low_end_mode_) {
     purge_reason = SessionStorageCachePurgeReason::kInactiveOnLowEndDevice;
+  }
 
   if (purge_reason == SessionStorageCachePurgeReason::kNotNeeded)
     return;
diff --git a/components/services/storage/dom_storage/session_storage_impl.h b/components/services/storage/dom_storage/session_storage_impl.h
index 5f28c5b..645cbe8 100644
--- a/components/services/storage/dom_storage/session_storage_impl.h
+++ b/components/services/storage/dom_storage/session_storage_impl.h
@@ -279,7 +279,7 @@
   // not delete them. Cleared after ScavengeUnusedNamespaces is called.
   std::set<std::string> protected_namespaces_from_scavenge_;
 
-  bool is_low_end_device_;
+  bool is_low_end_mode_;
   // Counts consecutive commit errors. If this number reaches a threshold, the
   // whole database is thrown away.
   int commit_error_count_ = 0;
diff --git a/components/site_isolation/site_isolation_policy.cc b/components/site_isolation/site_isolation_policy.cc
index 8c4b5be..9073df6 100644
--- a/components/site_isolation/site_isolation_policy.cc
+++ b/components/site_isolation/site_isolation_policy.cc
@@ -166,9 +166,9 @@
 bool SiteIsolationPolicy::IsEnterprisePolicyApplicable() {
 #if BUILDFLAG(IS_ANDROID)
   // https://crbug.com/844118: Limiting policy to devices with > 1GB RAM.
-  // Using 1077 rather than 1024 because 1) it helps ensure that devices with
+  // Using 1077 rather than 1024 because it helps ensure that devices with
   // exactly 1GB of RAM won't get included because of inaccuracies or off-by-one
-  // errors and 2) this is the bucket boundary in Memory.Stats.Win.TotalPhys2.
+  // errors.
   bool have_enough_memory = base::SysInfo::AmountOfPhysicalMemoryMB() > 1077;
   return have_enough_memory;
 #else
diff --git a/components/tab_groups/tab_group_id.h b/components/tab_groups/tab_group_id.h
index ab28e104..aba2c4ec 100644
--- a/components/tab_groups/tab_group_id.h
+++ b/components/tab_groups/tab_group_id.h
@@ -43,6 +43,14 @@
   base::Token token_;
 };
 
+// For use in std::unordered_map.
+struct TabGroupIdHash {
+ public:
+  size_t operator()(const tab_groups::TabGroupId& group_id) const {
+    return base::TokenHash()(group_id.token());
+  }
+};
+
 }  // namespace tab_groups
 
 #endif  // COMPONENTS_TAB_GROUPS_TAB_GROUP_ID_H_
diff --git a/components/unified_consent/unified_consent_metrics.cc b/components/unified_consent/unified_consent_metrics.cc
index 6afccc9..ad46929 100644
--- a/components/unified_consent/unified_consent_metrics.cc
+++ b/components/unified_consent/unified_consent_metrics.cc
@@ -95,14 +95,6 @@
       pref_service->GetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled);
   UMA_HISTOGRAM_BOOLEAN(
       "UnifiedConsent.MakeSearchesAndBrowsingBetter.OnProfileLoad", is_enabled);
-
-  // Continue logging the legacy histogram for a few milestones as it is used
-  // for various internal dashboards and this should provide enough time to
-  // migrate them.
-  // TODO(msarda): Remove this histogram in M111 as it will be obsolete then
-  // and replaced by UnifiedConsent.MakeSearchesAndBrowsingBetter.OnProfileLoad.
-  UMA_HISTOGRAM_BOOLEAN(
-      "UnifiedConsent.MakeSearchesAndBrowsingBetter.OnStartup", is_enabled);
 }
 
 void RecordSyncSetupDataTypesHistrogam(syncer::SyncUserSettings* sync_settings,
diff --git a/components/update_client/component.cc b/components/update_client/component.cc
index 3083ed3e..4f4fb8f8 100644
--- a/components/update_client/component.cc
+++ b/components/update_client/component.cc
@@ -1045,13 +1045,9 @@
 void Component::StateDownloadingDiff::DownloadProgress(int64_t downloaded_bytes,
                                                        int64_t total_bytes) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (downloaded_bytes != -1 && total_bytes != -1)
-    CHECK_LE(downloaded_bytes, total_bytes);
-
   auto& component = Component::State::component();
   component.downloaded_bytes_ = downloaded_bytes;
   component.total_bytes_ = total_bytes;
-
   component.NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING);
 }
 
@@ -1121,13 +1117,9 @@
 void Component::StateDownloading::DownloadProgress(int64_t downloaded_bytes,
                                                    int64_t total_bytes) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (downloaded_bytes != -1 && total_bytes != -1)
-    CHECK_LE(downloaded_bytes, total_bytes);
-
   auto& component = Component::State::component();
   component.downloaded_bytes_ = downloaded_bytes;
   component.total_bytes_ = total_bytes;
-
   component.NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING);
 }
 
diff --git a/components/user_education/views/help_bubble_view.cc b/components/user_education/views/help_bubble_view.cc
index b730cdb..0a19417 100644
--- a/components/user_education/views/help_bubble_view.cc
+++ b/components/user_education/views/help_bubble_view.cc
@@ -25,6 +25,7 @@
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/models/image_model.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/color/color_provider.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
@@ -73,9 +74,6 @@
 // Maximum width of the bubble. Longer strings will cause wrapping.
 constexpr int kBubbleMaxWidthDip = 340;
 
-// The insets from the bubble border to the text inside.
-constexpr auto kBubbleContentsInsets = gfx::Insets::VH(16, 20);
-
 // Translates from HelpBubbleArrow to the Views equivalent.
 views::BubbleBorder::Arrow TranslateArrow(HelpBubbleArrow arrow) {
   switch (arrow) {
@@ -122,6 +120,14 @@
     // Prominent style gives a button hover highlight.
     SetProminent(true);
     GetViewAccessibility().OverrideIsLeaf(true);
+
+    // Focus ring rendering varies significantly between pre- and post-refresh
+    // Chrome. The pre-refresh tactic of setting the focus color to background
+    // is actually a hack; the post-refresh approach is more "correct".
+    views::FocusRing::Get(this)->SetColorId(
+        features::IsChromeRefresh2023()
+            ? delegate_->GetHelpBubbleForegroundColorId()
+            : delegate_->GetHelpBubbleBackgroundColorId());
   }
   MdIPHBubbleButton(const MdIPHBubbleButton&) = delete;
   MdIPHBubbleButton& operator=(const MdIPHBubbleButton&) = delete;
@@ -154,11 +160,7 @@
   void OnThemeChanged() override {
     views::MdTextButton::OnThemeChanged();
 
-    const auto* color_provider = GetColorProvider();
-    views::FocusRing::Get(this)->SetColorId(
-        delegate_->GetHelpBubbleBackgroundColorId());
-
-    const SkColor foreground_color = color_provider->GetColor(
+    const SkColor foreground_color = GetColorProvider()->GetColor(
         is_default_button_
             ? delegate_->GetHelpBubbleDefaultButtonForegroundColorId()
             : delegate_->GetHelpBubbleForegroundColorId());
@@ -487,18 +489,23 @@
   const int default_spacing = layout_provider->GetDistanceMetric(
       views::DISTANCE_RELATED_CONTROL_VERTICAL);
 
+  // The insets from the bubble border to the text inside.
+  const gfx::Insets contents_insets = features::IsChromeRefresh2023()
+                                          ? gfx::Insets(20)
+                                          : gfx::Insets::VH(16, 20);
+
   // Create primary layout (vertical).
   SetLayoutManager(std::make_unique<views::FlexLayout>())
       ->SetOrientation(views::LayoutOrientation::kVertical)
       .SetMainAxisAlignment(views::LayoutAlignment::kCenter)
-      .SetInteriorMargin(kBubbleContentsInsets)
+      .SetInteriorMargin(contents_insets)
       .SetCollapseMargins(true)
       .SetDefault(views::kMarginsKey,
                   gfx::Insets::TLBR(0, 0, default_spacing, 0))
       .SetIgnoreDefaultMainAxisMargins(true);
 
   // Set up top row container layout.
-  const int kCloseButtonHeight = 24;
+  const int kCloseButtonHeight = features::IsChromeRefresh2023() ? 20 : 24;
   auto& progress_layout =
       progress_container
           ->SetLayoutManager(std::make_unique<views::FlexLayout>())
@@ -557,8 +564,8 @@
   // the top text container, but still need to be inset to align with the
   // title.
   if (icon_view_) {
-    const int indent = kBubbleContentsInsets.left() + kBodyIconBackgroundSize +
-                       default_spacing;
+    const int indent =
+        contents_insets.left() + kBodyIconBackgroundSize + default_spacing;
     for (size_t i = 1; i < labels_.size(); ++i) {
       labels_[i]->SetProperty(views::kMarginsKey,
                               gfx::Insets::TLBR(0, indent, 0, 0));
@@ -566,13 +573,13 @@
   }
 
   // Set up button container layout.
-  // Add in the default spacing between bubble content and bottom/buttons.
+
+  // Add in spacing between bubble content and bottom/buttons.
   button_container->SetProperty(
       views::kMarginsKey,
-      gfx::Insets::TLBR(
-          layout_provider->GetDistanceMetric(
-              views::DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_CONTROL),
-          0, 0, 0));
+      gfx::Insets::TLBR(layout_provider->GetDistanceMetric(
+                            views::DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_TEXT),
+                        0, 0, 0));
 
   // Create button container internal layout.
   auto& button_layout =
@@ -592,7 +599,7 @@
   // cases - and only those cases - the bubble can switch to a vertical button
   // alignment.
   if (button_container->GetMinimumSize().width() >
-      kBubbleMaxWidthDip - kBubbleContentsInsets.width()) {
+      kBubbleMaxWidthDip - contents_insets.width()) {
     button_layout.SetOrientation(views::LayoutOrientation::kVertical)
         .SetCrossAxisAlignment(views::LayoutAlignment::kEnd)
         .SetDefault(views::kMarginsKey, gfx::Insets::VH(default_spacing, 0))
diff --git a/components/viz/test/test_in_process_context_provider.h b/components/viz/test/test_in_process_context_provider.h
index 428fe4f..f343ce836 100644
--- a/components/viz/test/test_in_process_context_provider.h
+++ b/components/viz/test/test_in_process_context_provider.h
@@ -13,6 +13,7 @@
 #include "base/observer_list.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
+#include "components/viz/common/gpu/context_lost_observer.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
 #include "gpu/config/gpu_feature_info.h"
diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2CredentialRequest.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2CredentialRequest.java
index 1d5d922..14b7bc0 100644
--- a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2CredentialRequest.java
+++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2CredentialRequest.java
@@ -646,6 +646,15 @@
         mWebContents = webContents;
     }
 
+    private String getCredManExceptionType(Throwable exception) {
+        try {
+            return (String) exception.getClass().getMethod("getType").invoke(exception);
+        } catch (ReflectiveOperationException e) {
+            // This will map to UNKNOWN_ERROR.
+            return "Exception details not available";
+        }
+    }
+
     /**
      * Create a credential using the Android 14 CredMan API.
      * TODO: update the version code to U when Chromium builds with Android 14 SDK.
@@ -683,9 +692,19 @@
         OutcomeReceiver receiver = new OutcomeReceiver<Object, Throwable>() {
             @Override
             public void onError(Throwable e) {
-                // TODO: map these errors to more than just `UNKNOWN_ERROR`.
-                Log.e(TAG, "CredMan call failed", e);
-                returnErrorAndResetCallback(AuthenticatorStatus.UNKNOWN_ERROR);
+                String errorType = getCredManExceptionType(e);
+                Log.e(TAG, "CredMan CreateCredential call failed: %s",
+                        errorType + " (" + e.getMessage() + ")");
+                if (errorType.equals(
+                            "android.credentials.CreateCredentialException.TYPE_USER_CANCELED")) {
+                    returnErrorAndResetCallback(AuthenticatorStatus.NOT_ALLOWED_ERROR);
+                } else {
+                    // Includes:
+                    //  * CreateCredentialException.TYPE_UNKNOWN
+                    //  * CreateCredentialException.TYPE_NO_CREATE_OPTIONS
+                    //  * CreateCredentialException.TYPE_INTERRUPTED
+                    returnErrorAndResetCallback(AuthenticatorStatus.UNKNOWN_ERROR);
+                }
             }
 
             @Override
@@ -790,23 +809,18 @@
         OutcomeReceiver<Object, Throwable> receiver = new OutcomeReceiver<>() {
             @Override
             public void onError(Throwable getCredentialException) {
-                try {
-                    Log.e(TAG, "CredMan call failed", getCredentialException);
-                    Class<?> getCredentialExceptionClass = getCredentialException.getClass();
-                    String errorType =
-                            (String) getCredentialExceptionClass.getMethod("getType").invoke(
-                                    getCredentialException);
-                    if (((String) getCredentialExceptionClass.getField("TYPE_USER_CANCELED")
-                                        .get(getCredentialException))
-                                    .equals(errorType)) {
-                        returnErrorAndResetCallback(AuthenticatorStatus.NOT_ALLOWED_ERROR);
-                        return;
-                    }
+                String errorType = getCredManExceptionType(getCredentialException);
+                Log.e(TAG, "CredMan getCredential call failed: %s",
+                        errorType + " (" + getCredentialException.getMessage() + ")");
+                if (errorType.equals(
+                            "android.credentials.GetCredentialException.TYPE_USER_CANCELED")) {
+                    returnErrorAndResetCallback(AuthenticatorStatus.NOT_ALLOWED_ERROR);
+                } else {
+                    // Includes:
+                    //  * GetCredentialException.TYPE_UNKNOWN
+                    //  * GetCredentialException.TYPE_NO_CREATE_OPTIONS
+                    //  * GetCredentialException.TYPE_INTERRUPTED
                     returnErrorAndResetCallback(AuthenticatorStatus.UNKNOWN_ERROR);
-                } catch (ReflectiveOperationException e) {
-                    Log.e(TAG, "Reflection failed; are you running on Android 14?",
-                            getCredentialException);
-                    returnErrorAndResetCallback(AuthenticatorStatus.ANDROID_NOT_SUPPORTED_ERROR);
                 }
             }
 
@@ -910,8 +924,10 @@
         OutcomeReceiver<Object, Throwable> receiver = new OutcomeReceiver<>() {
             @Override
             public void onError(Throwable e) {
-                // TODO: map these errors to more than just `UNKNOWN_ERROR`.
-                Log.e(TAG, "CredMan call failed", e);
+                // prepareGetCredential uses getCredentialException, but it cannot be user
+                // cancelled so all errors map to UNKNOWN_ERROR.
+                Log.e(TAG, "CredMan prepareGetCredential call failed: %s",
+                        getCredManExceptionType(e) + " (" + e.getMessage() + ")");
                 returnErrorAndResetCallback(AuthenticatorStatus.UNKNOWN_ERROR);
             }
 
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc
index 16ffa8f..268b611 100644
--- a/components/webdata/common/web_database.cc
+++ b/components/webdata/common/web_database.cc
@@ -116,9 +116,15 @@
   // Clobber really old databases.
   static_assert(kDeprecatedVersionNumber < kCurrentVersionNumber,
                 "Deprecation version must be less than current");
-  sql::MetaTable::RazeIfIncompatible(
-      &db_, /*lowest_supported_version=*/kDeprecatedVersionNumber + 1,
-      kCurrentVersionNumber);
+  if (!sql::MetaTable::RazeIfIncompatible(
+          &db_, /*lowest_supported_version=*/kDeprecatedVersionNumber + 1,
+          kCurrentVersionNumber)) {
+    // TODO(crbug.com/1430313): Remove DumpWithoutCrashing when bug is fixed.
+    SCOPED_CRASH_KEY_STRING1024("db_init_error", "diagnostics",
+                                GetDiagnostics(db_));
+    base::debug::DumpWithoutCrashing();
+    return sql::INIT_FAILURE;
+  }
 
   // TODO(crbug.com/1430313): Remove DumpWithoutCrashing when bug is fixed.
   if (!db_.is_open()) {
diff --git a/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc b/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc
index b1951871..901b63d 100644
--- a/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc
+++ b/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc
@@ -47,9 +47,10 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "net/http/http_response_headers.h"
 #include "services/data_decoder/public/cpp/data_decoder.h"
+#include "services/network/public/cpp/attribution_utils.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/trigger_attestation.h"
-#include "services/network/public/mojom/attribution.mojom.h"
+#include "services/network/public/mojom/attribution.mojom-forward.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
@@ -479,6 +480,14 @@
 
   switch (header.registrar) {
     case Registrar::kWeb:
+#if BUILDFLAG(IS_ANDROID)
+      if (!network::HasAttributionWebSupport(
+              AttributionManager::GetSupport())) {
+        // TODO(crbug.com/1426450): Report a DevTools issue.
+        MaybeOnRegistrationsFinished(it);
+        break;
+      }
+#endif
       it->pending_web_decodes().emplace_back(std::move(header.header),
                                              std::move(reporting_origin));
       // Only perform the decode if it is the only one in the queue. Otherwise,
@@ -488,9 +497,8 @@
       }
       break;
     case Registrar::kOs:
-      if (AttributionManager::GetOsSupport() ==
-          network::mojom::AttributionOsSupport::kDisabled) {
-        // TODO: Report a DevTools issue.
+      if (!network::HasAttributionOsSupport(AttributionManager::GetSupport())) {
+        // TODO(crbug.com/1426450): Report a DevTools issue.
         MaybeOnRegistrationsFinished(it);
         break;
       }
diff --git a/content/browser/attribution_reporting/attribution_data_host_manager_impl_unittest.cc b/content/browser/attribution_reporting/attribution_data_host_manager_impl_unittest.cc
index c44f294..8080064 100644
--- a/content/browser/attribution_reporting/attribution_data_host_manager_impl_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_data_host_manager_impl_unittest.cc
@@ -65,7 +65,7 @@
 #if BUILDFLAG(IS_ANDROID)
 #include "content/browser/attribution_reporting/attribution_os_level_manager_android.h"
 #include "content/browser/attribution_reporting/os_registration.h"
-#include "services/network/public/mojom/attribution.mojom.h"
+#include "content/browser/attribution_reporting/test/mock_content_browser_client.h"
 #endif
 
 namespace content {
@@ -1103,8 +1103,9 @@
   scoped_feature_list.InitAndEnableFeature(
       network::features::kAttributionReportingCrossAppWeb);
 
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 
   const auto reporter = *SuitableOrigin::Deserialize("https://report.test");
   const auto source_site = *SuitableOrigin::Deserialize("https://source.test");
@@ -1135,8 +1136,9 @@
   scoped_feature_list.InitAndEnableFeature(
       network::features::kAttributionReportingCrossAppWeb);
 
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 
   const auto reporter = *SuitableOrigin::Deserialize("https://report.test");
   const auto source_site = *SuitableOrigin::Deserialize("https://source.test");
@@ -1161,8 +1163,9 @@
   scoped_feature_list.InitAndEnableFeature(
       network::features::kAttributionReportingCrossAppWeb);
 
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 
   auto reporter = *SuitableOrigin::Deserialize("https://report.test");
   auto source_site = *SuitableOrigin::Deserialize("https://source.test");
@@ -2063,8 +2066,9 @@
   scoped_feature_list.InitAndEnableFeature(
       network::features::kAttributionReportingCrossAppWeb);
 
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 
   auto reporting_origin = url::Origin::Create(GURL("https://report.test"));
   auto source_origin = *SuitableOrigin::Deserialize("https://source.test");
@@ -2637,6 +2641,37 @@
   data_host_remote.FlushForTesting();
 }
 
+TEST_F(AttributionDataHostManagerImplTest, WebDisabled_SourceNotRegistered) {
+  MockAttributionReportingContentBrowserClient browser_client;
+  EXPECT_CALL(browser_client, IsWebAttributionReportingAllowed())
+      .WillRepeatedly(testing::Return(false));
+  ScopedContentBrowserClientSetting setting(&browser_client);
+
+  const auto reporter = *SuitableOrigin::Deserialize("https://report.test");
+  const auto source_site = *SuitableOrigin::Deserialize("https://source.test");
+
+  for (auto state : {AttributionOsLevelManagerAndroid::ApiState::kDisabled,
+                     AttributionOsLevelManagerAndroid::ApiState::kEnabled}) {
+    AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+        scoped_api_state_setting(state);
+
+    EXPECT_CALL(mock_manager_, HandleSource).Times(0);
+
+    auto headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+    headers->SetHeader(kAttributionReportingRegisterSourceHeader,
+                       kRegisterSourceJson);
+
+    const blink::AttributionSrcToken attribution_src_token;
+    data_host_manager_.NotifyNavigationRegistrationData(
+        attribution_src_token, headers.get(), reporter, source_site,
+        AttributionInputEvent(), AttributionNavigationType::kAnchor,
+        /*is_within_fenced_frame=*/false, kFrameId, kNavigationId,
+        /*is_final_response=*/false);
+    // Wait for parsing to finish.
+    task_environment_.FastForwardBy(base::TimeDelta());
+  }
+}
+
 #endif  // BUILDFLAG(IS_ANDROID)
 
 }  // namespace
diff --git a/content/browser/attribution_reporting/attribution_internals.mojom b/content/browser/attribution_reporting/attribution_internals.mojom
index 3140515..b18eb525 100644
--- a/content/browser/attribution_reporting/attribution_internals.mojom
+++ b/content/browser/attribution_reporting/attribution_internals.mojom
@@ -217,8 +217,9 @@
 // storage layer.
 interface Handler {
   // Returns the state of the Attribution Reporting API in the WebUI's browsing context.
+  // `attribution_support` is the `Attribution-Reporting-Support` request header value.
   IsAttributionReportingEnabled() => (bool enabled, bool debug_mode,
-                                      bool has_os_support);
+                                      string attribution_support);
 
   // Returns all active sources that are persisted in storage. This does
   // not include expired sources, or sources that can no longer be attributed
diff --git a/content/browser/attribution_reporting/attribution_internals_browsertest.cc b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
index 650cec53..7ee04b8 100644
--- a/content/browser/attribution_reporting/attribution_internals_browsertest.cc
+++ b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
@@ -64,7 +64,6 @@
 #include "content/browser/attribution_reporting/attribution_os_level_manager_android.h"
 #include "content/browser/attribution_reporting/attribution_reporting.mojom.h"
 #include "content/browser/attribution_reporting/os_registration.h"
-#include "services/network/public/mojom/attribution.mojom.h"
 #endif
 
 namespace content {
@@ -523,9 +522,9 @@
   ASSERT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
   static constexpr char kScript[] = R"(
-    const status = document.getElementById('os-support');
+    const status = document.getElementById('attribution-support');
     const setTitleIfDone = (_, obs) => {
-      if (status.innerText === 'disabled') {
+      if (status.innerText === 'web') {
         if (obs) {
           obs.disconnect();
         }
@@ -552,9 +551,9 @@
   ASSERT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
   static constexpr char kScript[] = R"(
-    const status = document.getElementById('os-support');
+    const status = document.getElementById('attribution-support');
     const setTitleIfDone = (_, obs) => {
-      if (status.innerText === 'enabled') {
+      if (status.innerText === 'os, web') {
         if (obs) {
           obs.disconnect();
         }
@@ -570,8 +569,9 @@
   )";
   ASSERT_TRUE(ExecJsInWebUI(JsReplace(kScript, kCompleteTitle)));
 
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 
   TitleWatcher title_watcher(shell()->web_contents(), kCompleteTitle);
   ClickRefreshButton();
diff --git a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
index c1ef987..32f314985 100644
--- a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
+++ b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
@@ -51,7 +51,8 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
 #include "net/base/net_errors.h"
-#include "services/network/public/mojom/attribution.mojom.h"
+#include "services/network/public/cpp/attribution_utils.h"
+#include "services/network/public/mojom/attribution.mojom-forward.h"
 #include "third_party/abseil-cpp/absl/numeric/int128.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
@@ -253,10 +254,10 @@
           /*destination_origin=*/nullptr, /*reporting_origin=*/nullptr);
   bool debug_mode = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kAttributionReportingDebugMode);
-  bool has_os_support = AttributionManager::GetOsSupport() ==
-                        network::mojom::AttributionOsSupport::kEnabled;
-  std::move(callback).Run(attribution_reporting_enabled, debug_mode,
-                          has_os_support);
+  std::move(callback).Run(
+      attribution_reporting_enabled, debug_mode,
+      static_cast<std::string>(network::GetAttributionSupportHeader(
+          AttributionManager::GetSupport())));
 }
 
 void AttributionInternalsHandlerImpl::GetActiveSources(
diff --git a/content/browser/attribution_reporting/attribution_manager.cc b/content/browser/attribution_reporting/attribution_manager.cc
index b59558f..c38c823 100644
--- a/content/browser/attribution_reporting/attribution_manager.cc
+++ b/content/browser/attribution_reporting/attribution_manager.cc
@@ -30,8 +30,8 @@
 }
 
 // static
-network::mojom::AttributionOsSupport AttributionManager::GetOsSupport() {
-  return AttributionManagerImpl::GetOsSupport();
+network::mojom::AttributionSupport AttributionManager::GetSupport() {
+  return AttributionManagerImpl::GetSupport();
 }
 
 }  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_manager.h b/content/browser/attribution_reporting/attribution_manager.h
index a45375e8..f3f5aa6 100644
--- a/content/browser/attribution_reporting/attribution_manager.h
+++ b/content/browser/attribution_reporting/attribution_manager.h
@@ -52,7 +52,7 @@
 
   static AttributionManager* FromBrowserContext(BrowserContext*);
 
-  static network::mojom::AttributionOsSupport GetOsSupport();
+  static network::mojom::AttributionSupport GetSupport();
 
   ~AttributionManager() override = default;
 
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.cc b/content/browser/attribution_reporting/attribution_manager_impl.cc
index 0480509..b91c72b 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl.cc
+++ b/content/browser/attribution_reporting/attribution_manager_impl.cc
@@ -69,6 +69,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
@@ -469,14 +470,35 @@
 }
 
 // static
-network::mojom::AttributionOsSupport AttributionManagerImpl::GetOsSupport() {
+network::mojom::AttributionSupport AttributionManagerImpl::GetSupport() {
 #if BUILDFLAG(IS_ANDROID)
-  return AttributionOsLevelManagerAndroid::GetOsSupport();
+  bool is_web_allowed =
+      GetContentClient()->browser()->IsWebAttributionReportingAllowed();
+  switch (AttributionOsLevelManagerAndroid::GetApiState()) {
+    case AttributionOsLevelManagerAndroid::ApiState::kDisabled:
+      return is_web_allowed ? network::mojom::AttributionSupport::kWeb
+                            : network::mojom::AttributionSupport::kNone;
+    case AttributionOsLevelManagerAndroid::ApiState::kEnabled:
+      return is_web_allowed ? network::mojom::AttributionSupport::kWebAndOs
+                            : network::mojom::AttributionSupport::kOs;
+  }
 #else
-  return network::mojom::AttributionOsSupport::kDisabled;
+  return network::mojom::AttributionSupport::kWeb;
 #endif
 }
 
+#if BUILDFLAG(IS_ANDROID)
+// static
+void AttributionManagerImpl::UpdateSupportForRenderProcessHosts() {
+  network::mojom::AttributionSupport attribution_support = GetSupport();
+
+  for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
+       !it.IsAtEnd(); it.Advance()) {
+    it.GetCurrentValue()->SetAttributionReportingSupport(attribution_support);
+  }
+}
+#endif
+
 AttributionManagerImpl::AttributionManagerImpl(
     StoragePartitionImpl* storage_partition,
     const base::FilePath& user_data_directory,
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.h b/content/browser/attribution_reporting/attribution_manager_impl.h
index a1d2878..d272afe4 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl.h
+++ b/content/browser/attribution_reporting/attribution_manager_impl.h
@@ -113,7 +113,11 @@
       const base::FilePath& user_data_directory,
       scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy);
 
-  static network::mojom::AttributionOsSupport GetOsSupport();
+  static network::mojom::AttributionSupport GetSupport();
+
+#if BUILDFLAG(IS_ANDROID)
+  static void UpdateSupportForRenderProcessHosts();
+#endif
 
   AttributionManagerImpl(
       StoragePartitionImpl* storage_partition,
diff --git a/content/browser/attribution_reporting/attribution_os_level_manager_android.cc b/content/browser/attribution_reporting/attribution_os_level_manager_android.cc
index dae12b1a..27c9358 100644
--- a/content/browser/attribution_reporting/attribution_os_level_manager_android.cc
+++ b/content/browser/attribution_reporting/attribution_os_level_manager_android.cc
@@ -28,8 +28,6 @@
 #include "content/browser/attribution_reporting/os_registration.h"
 #include "content/public/android/content_jni_headers/AttributionOsLevelManager_jni.h"
 #include "content/public/browser/browsing_data_filter_builder.h"
-#include "content/public/browser/render_process_host.h"
-#include "services/network/public/mojom/attribution.mojom-shared.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/android/gurl_android.h"
 #include "url/gurl.h"
@@ -39,10 +37,10 @@
 
 namespace {
 
-using ScopedOsSupportForTesting =
-    ::content::AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting;
+using ScopedApiStateForTesting =
+    ::content::AttributionOsLevelManagerAndroid::ScopedApiStateForTesting;
 
-using network::mojom::AttributionOsSupport;
+using ApiState = ::content::AttributionOsLevelManagerAndroid::ApiState;
 
 #if DCHECK_IS_ON()
 const base::SequenceChecker& GetSequenceChecker() {
@@ -54,25 +52,20 @@
 // This flag is per device and can only be changed by the OS. Currently we don't
 // observe setting changes on the device and the flag is only initialized once
 // on startup. The value may vary in tests.
-absl::optional<AttributionOsSupport> g_os_support
-    GUARDED_BY_CONTEXT(GetSequenceChecker());
+absl::optional<ApiState> g_state GUARDED_BY_CONTEXT(GetSequenceChecker());
 
-void SetOsSupport(AttributionOsSupport os_support) {
+void SetApiState(absl::optional<ApiState> state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(GetSequenceChecker());
 
-  AttributionOsSupport previous =
-      AttributionOsLevelManagerAndroid::GetOsSupport();
+  ApiState previous = AttributionOsLevelManagerAndroid::GetApiState();
 
-  g_os_support = os_support;
+  g_state = state;
 
-  if (previous == os_support) {
+  if (previous == AttributionOsLevelManagerAndroid::GetApiState()) {
     return;
   }
 
-  for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
-       !it.IsAtEnd(); it.Advance()) {
-    it.GetCurrentValue()->SetOsSupportForAttributionReporting(os_support);
-  }
+  AttributionManagerImpl::UpdateSupportForRenderProcessHosts();
 }
 
 int GetDeletionMode(bool delete_rate_limit_data) {
@@ -101,7 +94,7 @@
   }
 }
 
-AttributionOsSupport ConvertToOsSupport(int value) {
+ApiState ConvertToApiState(int value) {
   // See
   // https://developer.android.com/reference/androidx/privacysandbox/ads/adservices/measurement/MeasurementManager
   // for constant values.
@@ -110,11 +103,11 @@
 
   switch (value) {
     case kMeasurementApiStateDisabled:
-      return AttributionOsSupport::kDisabled;
+      return ApiState::kDisabled;
     case kMeasurementApiStateEnabled:
-      return AttributionOsSupport::kEnabled;
+      return ApiState::kEnabled;
     default:
-      return AttributionOsSupport::kDisabled;
+      return ApiState::kDisabled;
   }
 }
 
@@ -123,26 +116,25 @@
 static void JNI_AttributionOsLevelManager_OnMeasurementStateReturned(
     JNIEnv* env,
     jint state) {
-  SetOsSupport(ConvertToOsSupport(state));
+  SetApiState(ConvertToApiState(state));
 
   base::UmaHistogramEnumeration("Conversions.AttributionSupport",
-                                AttributionManagerImpl::GetOsSupport());
+                                AttributionManagerImpl::GetSupport());
 }
 
-ScopedOsSupportForTesting::ScopedOsSupportForTesting(
-    AttributionOsSupport os_support)
-    : previous_(GetOsSupport()) {
-  SetOsSupport(os_support);
+ScopedApiStateForTesting::ScopedApiStateForTesting(ApiState state)
+    : previous_(g_state) {
+  SetApiState(state);
 }
 
-ScopedOsSupportForTesting::~ScopedOsSupportForTesting() {
-  SetOsSupport(previous_);
+ScopedApiStateForTesting::~ScopedApiStateForTesting() {
+  SetApiState(previous_);
 }
 
 // static
-AttributionOsSupport AttributionOsLevelManagerAndroid::GetOsSupport() {
+ApiState AttributionOsLevelManagerAndroid::GetApiState() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(GetSequenceChecker());
-  return g_os_support.value_or(AttributionOsSupport::kDisabled);
+  return g_state.value_or(ApiState::kDisabled);
 }
 
 AttributionOsLevelManagerAndroid::AttributionOsLevelManagerAndroid() {
@@ -222,12 +214,12 @@
 void AttributionOsLevelManagerAndroid::InitializeOsSupport() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(GetSequenceChecker());
 
-  if (g_os_support.has_value()) {
+  if (g_state.has_value()) {
     return;
   }
 
   // Only make the async call once.
-  g_os_support.emplace(AttributionOsSupport::kDisabled);
+  g_state.emplace(ApiState::kDisabled);
 
   Java_AttributionOsLevelManager_getMeasurementApiStatus(
       base::android::AttachCurrentThread(), jobj_);
diff --git a/content/browser/attribution_reporting/attribution_os_level_manager_android.h b/content/browser/attribution_reporting/attribution_os_level_manager_android.h
index 738d65d2..23ffd53 100644
--- a/content/browser/attribution_reporting/attribution_os_level_manager_android.h
+++ b/content/browser/attribution_reporting/attribution_os_level_manager_android.h
@@ -15,7 +15,7 @@
 #include "base/thread_annotations.h"
 #include "content/browser/attribution_reporting/attribution_os_level_manager.h"
 #include "content/common/content_export.h"
-#include "services/network/public/mojom/attribution.mojom-forward.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace content {
 
@@ -24,25 +24,30 @@
 class CONTENT_EXPORT AttributionOsLevelManagerAndroid
     : public AttributionOsLevelManager {
  public:
-  class CONTENT_EXPORT ScopedOsSupportForTesting {
-   public:
-    explicit ScopedOsSupportForTesting(network::mojom::AttributionOsSupport);
-    ~ScopedOsSupportForTesting();
+  enum class ApiState {
+    kDisabled,
+    kEnabled,
+  };
 
-    ScopedOsSupportForTesting(const ScopedOsSupportForTesting&) = delete;
-    ScopedOsSupportForTesting& operator=(const ScopedOsSupportForTesting&) =
+  class CONTENT_EXPORT ScopedApiStateForTesting {
+   public:
+    explicit ScopedApiStateForTesting(ApiState);
+    ~ScopedApiStateForTesting();
+
+    ScopedApiStateForTesting(const ScopedApiStateForTesting&) = delete;
+    ScopedApiStateForTesting& operator=(const ScopedApiStateForTesting&) =
         delete;
 
-    ScopedOsSupportForTesting(ScopedOsSupportForTesting&&) = delete;
-    ScopedOsSupportForTesting& operator=(ScopedOsSupportForTesting&&) = delete;
+    ScopedApiStateForTesting(ScopedApiStateForTesting&&) = delete;
+    ScopedApiStateForTesting& operator=(ScopedApiStateForTesting&&) = delete;
 
    private:
-    const network::mojom::AttributionOsSupport previous_;
+    const absl::optional<ApiState> previous_;
   };
 
   // Returns whether OS-level attribution is enabled. `kDisabled` is returned
   // before the result is returned from JNI.
-  static network::mojom::AttributionOsSupport GetOsSupport();
+  static ApiState GetApiState();
 
   AttributionOsLevelManagerAndroid();
   ~AttributionOsLevelManagerAndroid() override;
diff --git a/content/browser/attribution_reporting/attribution_src_browsertest.cc b/content/browser/attribution_reporting/attribution_src_browsertest.cc
index 29782345..1d45fb6 100644
--- a/content/browser/attribution_reporting/attribution_src_browsertest.cc
+++ b/content/browser/attribution_reporting/attribution_src_browsertest.cc
@@ -57,7 +57,8 @@
 
 #if BUILDFLAG(IS_ANDROID)
 #include "content/browser/attribution_reporting/attribution_os_level_manager_android.h"
-#include "services/network/public/mojom/attribution.mojom.h"
+#include "content/browser/attribution_reporting/test/mock_content_browser_client.h"
+#include "content/public/test/content_browser_test_content_browser_client.h"
 #endif
 
 namespace content {
@@ -761,6 +762,47 @@
   EXPECT_EQ(trigger_data.front().event_triggers.front().data, 7u);
 }
 
+#if BUILDFLAG(IS_ANDROID)
+IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest,
+                       ImgNoneSupported_EligibleHeaderNotSet) {
+  MockAttributionReportingContentBrowserClientBase<
+      ContentBrowserTestContentBrowserClient>
+      browser_client;
+  EXPECT_CALL(browser_client, IsWebAttributionReportingAllowed())
+      .WillRepeatedly(testing::Return(false));
+
+  // Create a separate server as we cannot register a `ControllableHttpResponse`
+  // after the server starts.
+  auto https_server = std::make_unique<net::EmbeddedTestServer>(
+      net::EmbeddedTestServer::TYPE_HTTPS);
+  https_server->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+  net::test_server::RegisterDefaultHandlers(https_server.get());
+  https_server->ServeFilesFromSourceDirectory(
+      "content/test/data/attribution_reporting");
+  https_server->ServeFilesFromSourceDirectory("content/test/data");
+
+  auto register_response =
+      std::make_unique<net::test_server::ControllableHttpResponse>(
+          https_server.get(), "/register_source");
+  ASSERT_TRUE(https_server->Start());
+
+  GURL page_url =
+      https_server->GetURL("b.test", "/page_with_impression_creator.html");
+  ASSERT_TRUE(NavigateToURL(web_contents(), page_url));
+
+  GURL register_url = https_server->GetURL("d.test", "/register_source");
+  ASSERT_TRUE(
+      ExecJs(web_contents(),
+             JsReplace("createAttributionEligibleImgSrc($1);", register_url)));
+
+  register_response->WaitForRequest();
+  EXPECT_FALSE(base::Contains(register_response->http_request()->headers,
+                              "Attribution-Reporting-Eligible"));
+  EXPECT_FALSE(base::Contains(register_response->http_request()->headers,
+                              "Attribution-Reporting-Support"));
+}
+#endif
+
 class AttributionSrcMultipleBackgroundRequestTest
     : public AttributionSrcBrowserTest,
       public ::testing::WithParamInterface<
@@ -1187,8 +1229,9 @@
           https_server.get(), "/register_source2");
   ASSERT_TRUE(https_server->Start());
 
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 
   GURL page_url =
       https_server->GetURL("b.test", "/page_with_impression_creator.html");
@@ -1202,7 +1245,7 @@
   register_response1->WaitForRequest();
   ASSERT_EQ(register_response1->http_request()->headers.at(
                 "Attribution-Reporting-Support"),
-            "web, os");
+            "os, web");
 
   auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
   http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
@@ -1214,7 +1257,7 @@
   register_response2->WaitForRequest();
   ASSERT_EQ(register_response2->http_request()->headers.at(
                 "Attribution-Reporting-Support"),
-            "web, os");
+            "os, web");
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -1242,8 +1285,9 @@
       https_server->GetURL("b.test", "/page_with_impression_creator.html");
   ASSERT_TRUE(NavigateToURL(web_contents(), page_url));
 
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 
   GURL register_url = https_server->GetURL("d.test", "/register_source1");
   ASSERT_TRUE(ExecJs(web_contents(),
@@ -1252,7 +1296,7 @@
   register_response1->WaitForRequest();
   ASSERT_EQ(register_response1->http_request()->headers.at(
                 "Attribution-Reporting-Support"),
-            "web, os");
+            "os, web");
 
   auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
   http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
@@ -1264,7 +1308,7 @@
   register_response2->WaitForRequest();
   ASSERT_EQ(register_response2->http_request()->headers.at(
                 "Attribution-Reporting-Support"),
-            "web, os");
+            "os, web");
 }
 
 struct OsRegistrationTestCase {
@@ -1324,8 +1368,9 @@
           https_server.get(), "/register");
   ASSERT_TRUE(https_server->Start());
 
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 
   GURL page_url =
       https_server->GetURL("b.test", "/page_with_impression_creator.html");
diff --git a/content/browser/attribution_reporting/attribution_storage_unittest.cc b/content/browser/attribution_reporting/attribution_storage_unittest.cc
index 6756fd2d..0a3a3a7 100644
--- a/content/browser/attribution_reporting/attribution_storage_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_storage_unittest.cc
@@ -205,8 +205,8 @@
   base::ScopedTempDir dir_;
 
  private:
-  raw_ptr<ConfigurableStorageDelegate> delegate_;
   std::unique_ptr<AttributionStorage> storage_;
+  raw_ptr<ConfigurableStorageDelegate> delegate_;
 };
 
 TEST_F(AttributionStorageTest,
diff --git a/content/browser/attribution_reporting/attributions_browsertest.cc b/content/browser/attribution_reporting/attributions_browsertest.cc
index 07e5abb..7271318 100644
--- a/content/browser/attribution_reporting/attributions_browsertest.cc
+++ b/content/browser/attribution_reporting/attributions_browsertest.cc
@@ -79,7 +79,8 @@
 
 #if BUILDFLAG(IS_ANDROID)
 #include "content/browser/attribution_reporting/attribution_os_level_manager_android.h"
-#include "services/network/public/mojom/attribution.mojom.h"
+#include "content/browser/attribution_reporting/test/mock_content_browser_client.h"
+#include "content/public/test/content_browser_test_content_browser_client.h"
 #endif
 
 namespace content {
@@ -991,6 +992,43 @@
   expected_report.WaitForReport();
 }
 
+#if BUILDFLAG(IS_ANDROID)
+IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest,
+                       NavigationNoneSupported_EligibleHeaderNotSet) {
+  MockAttributionReportingContentBrowserClientBase<
+      ContentBrowserTestContentBrowserClient>
+      browser_client;
+  EXPECT_CALL(browser_client, IsWebAttributionReportingAllowed())
+      .WillRepeatedly(testing::Return(false));
+
+  auto register_response =
+      std::make_unique<net::test_server::ControllableHttpResponse>(
+          https_server(), "/register_source");
+  ASSERT_TRUE(https_server()->Start());
+
+  GURL impression_url = https_server()->GetURL(
+      "a.test", "/attribution_reporting/page_with_impression_creator.html");
+  EXPECT_TRUE(NavigateToURL(web_contents(), impression_url));
+
+  GURL register_source_url =
+      https_server()->GetURL("d.test", "/register_source");
+
+  EXPECT_TRUE(ExecJs(web_contents(), JsReplace(R"(
+    createAttributionSrcAnchor({id: 'link',
+                        url: $1,
+                        attributionsrc: '',
+                        target: $2});)",
+                                               register_source_url, "_top")));
+  EXPECT_TRUE(ExecJs(web_contents(), "simulateClick('link');"));
+
+  register_response->WaitForRequest();
+  EXPECT_FALSE(base::Contains(register_response->http_request()->headers,
+                              "Attribution-Reporting-Eligible"));
+  EXPECT_FALSE(base::Contains(register_response->http_request()->headers,
+                              "Attribution-Reporting-Support"));
+}
+#endif
+
 class AttributionsPrerenderBrowserTest : public AttributionsBrowserTest {
  public:
   AttributionsPrerenderBrowserTest()
@@ -1221,8 +1259,9 @@
           https_server(), "/register_source_redirect2");
   ASSERT_TRUE(https_server()->Start());
 
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 
   GURL impression_url = https_server()->GetURL(
       "a.test", "/attribution_reporting/page_with_impression_creator.html");
@@ -1245,7 +1284,7 @@
   register_response1->WaitForRequest();
   EXPECT_EQ(register_response1->http_request()->headers.at(
                 "Attribution-Reporting-Support"),
-            "web, os");
+            "os, web");
 
   auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
   http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
@@ -1257,7 +1296,7 @@
   register_response2->WaitForRequest();
   ASSERT_EQ(register_response2->http_request()->headers.at(
                 "Attribution-Reporting-Support"),
-            "web, os");
+            "os, web");
 }
 #endif  // BUILDFLAG(IS_ANDROID)
 
diff --git a/content/browser/attribution_reporting/test/mock_content_browser_client.h b/content/browser/attribution_reporting/test/mock_content_browser_client.h
index bfd5775d..ac2efdb 100644
--- a/content/browser/attribution_reporting/test/mock_content_browser_client.h
+++ b/content/browser/attribution_reporting/test/mock_content_browser_client.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_TEST_MOCK_CONTENT_BROWSER_CLIENT_H_
 #define CONTENT_BROWSER_ATTRIBUTION_REPORTING_TEST_MOCK_CONTENT_BROWSER_CLIENT_H_
 
+#include "build/build_config.h"
+#include "build/buildflag.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/test/test_content_browser_client.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -31,6 +33,10 @@
                const url::Origin* destination_origin,
                const url::Origin* reporting_origin),
               (override));
+
+#if BUILDFLAG(IS_ANDROID)
+  MOCK_METHOD(bool, IsWebAttributionReportingAllowed, (), (override));
+#endif
 };
 
 using MockAttributionReportingContentBrowserClient =
diff --git a/content/browser/compositor/test/test_image_transport_factory.cc b/content/browser/compositor/test/test_image_transport_factory.cc
index c5f25d555..7aaaf70 100644
--- a/content/browser/compositor/test/test_image_transport_factory.cc
+++ b/content/browser/compositor/test/test_image_transport_factory.cc
@@ -7,9 +7,9 @@
 #include <limits>
 #include <utility>
 
+#include "components/viz/test/test_in_process_context_provider.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
-#include "ui/compositor/test/in_process_context_provider.h"
 
 namespace content {
 namespace {
@@ -61,11 +61,13 @@
     return shared_main_context_provider_;
 
   constexpr bool kSupportsLocking = false;
-  shared_main_context_provider_ = ui::InProcessContextProvider::CreateOffscreen(
-      &gpu_memory_buffer_manager_, kSupportsLocking);
+  shared_main_context_provider_ =
+      base::MakeRefCounted<viz::TestInProcessContextProvider>(
+          viz::TestContextType::kGLES2WithRaster, kSupportsLocking);
   auto result = shared_main_context_provider_->BindToCurrentSequence();
-  if (result != gpu::ContextResult::kSuccess)
+  if (result != gpu::ContextResult::kSuccess) {
     shared_main_context_provider_ = nullptr;
+  }
 
   return shared_main_context_provider_;
 }
diff --git a/content/browser/fenced_frame/fenced_frame_browsertest.cc b/content/browser/fenced_frame/fenced_frame_browsertest.cc
index 2214f15..cfd7a2c 100644
--- a/content/browser/fenced_frame/fenced_frame_browsertest.cc
+++ b/content/browser/fenced_frame/fenced_frame_browsertest.cc
@@ -70,6 +70,7 @@
 
 #if BUILDFLAG(IS_ANDROID)
 #include "content/browser/attribution_reporting/attribution_os_level_manager_android.h"
+#include "content/browser/attribution_reporting/test/mock_content_browser_client.h"
 #endif
 
 namespace content {
@@ -4627,6 +4628,12 @@
     struct Event {
       std::string type;
       std::string reporting_destination;
+      // Optional `eventData` field for reportEvent.
+      // 1. If this is `absl::nullopt`, reportEvent is called without the
+      // `eventData` field.
+      // 2. Otherwise, the event data is the given string appended with the
+      // `navigation_index` of each step.
+      absl::optional<std::string> data;
     };
     struct Destination {
       // The origin for the navigation.
@@ -4635,8 +4642,9 @@
       std::string path;
     };
 
-    // Specifies the reporting destination and event type for reportEvent.
-    Event event{"click", "buyer"};
+    // Specifies the reporting destination, event type and event data for
+    // reportEvent.
+    Event event{"click", "buyer", "click data"};
 
     // The initial navigation destination (may be redirected).
     Destination destination;
@@ -4955,17 +4963,31 @@
       }
 
       // Perform the reportEvent call, with a unique body.
-      const char report_event_script[] = R"(
-          window.fence.reportEvent({
-          eventType: $2,
-          eventData: $2 + ' $1',
-          destination: [$3],
-          });
-      )";
-      EXPECT_TRUE(
-          ExecJs(navigation_target_node,
-                 JsReplace(report_event_script, navigation_index,
-                           step.event.type, step.event.reporting_destination)));
+      if (!step.event.data) {
+        // Call reportEvent without `eventData` field.
+        EXPECT_TRUE(ExecJs(
+            navigation_target_node,
+            JsReplace(R"(
+              window.fence.reportEvent({
+                eventType: $1,
+                destination: [$2]
+              });
+            )",
+                      step.event.type, step.event.reporting_destination)));
+      } else {
+        // Call reportEvent with `eventData`.
+        EXPECT_TRUE(
+            ExecJs(navigation_target_node,
+                   JsReplace(R"(
+              window.fence.reportEvent({
+                eventType: $1,
+                eventData: $3 + ' $4',
+                destination: [$2]
+              });
+            )",
+                             step.event.type, step.event.reporting_destination,
+                             step.event.data.value(), navigation_index)));
+      }
 
       // If relevant, check that the event report succeeded.
       if (step.report_event_result == Step::Result::kSuccess) {
@@ -4994,9 +5016,13 @@
         response.WaitForRequest();
 
         // Verify the request has the correct content.
-        EXPECT_EQ(
-            response.http_request()->content,
-            step.event.type + " " + base::NumberToString(navigation_index));
+        if (!step.event.data) {
+          EXPECT_TRUE(response.http_request()->content.empty());
+        } else {
+          EXPECT_EQ(response.http_request()->content,
+                    step.event.data.value() + " " +
+                        base::NumberToString(navigation_index));
+        }
         // Verify the request contains the eligibility header.
         if (step.expect_attribution_reporting_allowed) {
           EXPECT_EQ(response.http_request()->headers.at(
@@ -5103,6 +5129,22 @@
   RunTest(config);
 }
 
+// The `eventData` field of `fence.reportEvent` should be optional.
+IN_PROC_BROWSER_TEST_F(FencedFrameReportEventBrowserTest,
+                       FencedFrameReportEventWithoutEventData) {
+  std::vector<Step> config = {
+      {
+          .is_embedder_initiated = true,
+          .is_opaque = true,
+          .event = {/*type=*/"click", /*reporting_destination=*/"buyer",
+                    /*data=*/absl::nullopt},
+          .destination = {"a.test", "/fenced_frames/title1.html"},
+          .report_event_result = Step::Result::kSuccess,
+      },
+  };
+  RunTest(config);
+}
+
 // reportEvent shouldn't work if there is no associated reporting metadata with
 // the reporting destination.
 IN_PROC_BROWSER_TEST_F(
@@ -5112,7 +5154,9 @@
       {
           .is_embedder_initiated = true,
           .is_opaque = true,
-          .event = {"click", "component-seller"},
+          .event = {/*type=*/"click",
+                    /*reporting_destination=*/"component-seller",
+                    /*data=*/"click data"},
           .destination = {"a.test", "/fenced_frames/title1.html"},
           .report_event_result = Step::Result::kNoDestination,
       },
@@ -5128,7 +5172,8 @@
       {
           .is_embedder_initiated = true,
           .is_opaque = true,
-          .event = {"invalid-event", "buyer"},
+          .event = {/*type=*/"invalid-event", /*reporting_destination=*/"buyer",
+                    /*data=*/"click data"},
           .destination = {"a.test", "/fenced_frames/title1.html"},
           .report_event_result = Step::Result::kNoReportingURL,
       },
@@ -5143,7 +5188,8 @@
       {
           .is_embedder_initiated = true,
           .is_opaque = true,
-          .event = {"click", "seller"},
+          .event = {/*type=*/"click", /*reporting_destination=*/"seller",
+                    /*data=*/"click data"},
           .destination = {"a.test", "/fenced_frames/title1.html"},
           .report_event_result = Step::Result::kInvalidReportingURL,
       },
@@ -5818,6 +5864,88 @@
   }
 }
 
+#if BUILDFLAG(IS_ANDROID)
+IN_PROC_BROWSER_TEST_F(FencedFrameReportEventBrowserTest,
+                       AttributionNoneSupported_EligibleHeaderNotSet) {
+  MockAttributionReportingContentBrowserClientBase<
+      ContentBrowserTestContentBrowserClient>
+      browser_client;
+  EXPECT_CALL(browser_client, IsWebAttributionReportingAllowed())
+      .WillRepeatedly(testing::Return(false));
+
+  net::test_server::ControllableHttpResponse response(https_server(),
+                                                      kReportingURL);
+  ASSERT_TRUE(https_server()->Start());
+
+  GURL main_url = https_server()->GetURL("a.test", "/hello.html");
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetPrimaryFrameTree()
+                            .root();
+  EXPECT_TRUE(ExecJs(root,
+                     "var f = document.createElement('fencedframe');"
+                     "document.body.appendChild(f);"));
+
+  EXPECT_EQ(1U, root->child_count());
+  FrameTreeNode* fenced_frame_root_node =
+      GetFencedFrameRootNode(root->child_at(0));
+  EXPECT_TRUE(fenced_frame_root_node->IsFencedFrameRoot());
+  EXPECT_TRUE(fenced_frame_root_node->IsInFencedFrameTree());
+
+  GURL https_url(
+      https_server()->GetURL("a.test", "/fenced_frames/title1.html"));
+
+  // Create a FencedFrameReporter and pass it reporting metadata.
+  scoped_refptr<FencedFrameReporter> fenced_frame_reporter =
+      CreateFencedFrameReporter();
+  GURL reporting_url(https_server()->GetURL("a.test", kReportingURL));
+  // Set valid reporting metadata for buyer.
+  fenced_frame_reporter->OnUrlMappingReady(
+      blink::FencedFrame::ReportingDestination::kBuyer,
+      {{"click", reporting_url}});
+
+  // Get the urn mapping object.
+  FencedFrameURLMapping& url_mapping =
+      root->current_frame_host()->GetPage().fenced_frame_urls_map();
+
+  // Add url and its reporting metadata to fenced frame url mapping.
+  auto urn_uuid = test::AddAndVerifyFencedFrameURL(&url_mapping, https_url,
+                                                   fenced_frame_reporter);
+
+  TestFencedFrameURLMappingResultObserver mapping_observer;
+  url_mapping.ConvertFencedFrameURNToURL(urn_uuid, &mapping_observer);
+  TestFrameNavigationObserver observer(
+      fenced_frame_root_node->current_frame_host());
+
+  // Navigate the fenced frame.
+  EXPECT_TRUE(ExecJs(
+      root, JsReplace("f.config = new FencedFrameConfig($1);", urn_uuid)));
+
+  observer.WaitForCommit();
+  EXPECT_TRUE(mapping_observer.mapping_complete_observed());
+  EXPECT_EQ(fenced_frame_reporter, mapping_observer.fenced_frame_reporter());
+
+  // Perform the reportEvent call, with a unique body.
+  std::string event_data = "this is a click";
+  std::string report_event_script = JsReplace(R"(
+        window.fence.reportEvent({
+          eventType: 'click',
+          eventData: $1,
+          destination: ['buyer'],
+        });
+      )",
+                                              event_data);
+  EXPECT_TRUE(ExecJs(fenced_frame_root_node, report_event_script));
+
+  response.WaitForRequest();
+  EXPECT_EQ(response.http_request()->content, event_data);
+  EXPECT_FALSE(base::Contains(response.http_request()->headers,
+                              "Attribution-Reporting-Eligible"));
+  EXPECT_FALSE(base::Contains(response.http_request()->headers,
+                              "Attribution-Reporting-Support"));
+}
+#endif
+
 class FencedFrameReportEventAttributionCrossAppWebEnabledBrowserTest
     : public FencedFrameReportEventBrowserTest {
  public:
@@ -5834,8 +5962,9 @@
     FencedFrameReportEventAttributionCrossAppWebEnabledBrowserTest,
     ReportEventSameOriginSetsSupportHeader) {
 #if BUILDFLAG(IS_ANDROID)
-  AttributionOsLevelManagerAndroid::ScopedOsSupportForTesting
-      scoped_os_support_setting(network::mojom::AttributionOsSupport::kEnabled);
+  AttributionOsLevelManagerAndroid::ScopedApiStateForTesting
+      scoped_api_state_setting(
+          AttributionOsLevelManagerAndroid::ApiState::kEnabled);
 #endif
 
   net::test_server::ControllableHttpResponse response(https_server(),
@@ -5912,7 +6041,7 @@
 #if BUILDFLAG(IS_ANDROID)
   EXPECT_EQ(
       response.http_request()->headers.at("Attribution-Reporting-Support"),
-      "web, os");
+      "os, web");
 #else
   EXPECT_EQ(
       response.http_request()->headers.at("Attribution-Reporting-Support"),
@@ -6200,8 +6329,11 @@
     Destination starting_url;
     Destination navigation_url;
 
-    // The message to be sent as part of the payload.
-    std::string message = "data";
+    // Optional message to be sent as part of the payload.
+    // 1. If this is `absl::nullopt`, `setReportEventDataForAutomaticBeacons()`
+    // is called without the `eventData` field.
+    // 2. Otherwise, the event data is the given string.
+    absl::optional<std::string> message = "data";
 
     // Whether there is a call to `setReportEventDataForAutomaticBeacons()`.
     bool register_beacon_data = true;
@@ -6360,15 +6492,33 @@
     ad_frame_observer.WaitForCommit();
 
     if (config.register_beacon_data) {
-      EXPECT_TRUE(ExecJs(
-          ad_frame_root_node,
-          JsReplace("window.fence.setReportEventDataForAutomaticBeacons({"
-                    "eventType: $2,"
-                    "eventData: $1,"
-                    "destination: ['seller', 'buyer']"
-                    "});",
-                    config.message, blink::kFencedFrameTopNavigationBeaconType),
-          ad_frame_execjs_options));
+      if (!config.message) {
+        // Call `setReportEventDataForAutomaticBeacons()` without `eventData`
+        // field.
+        EXPECT_TRUE(
+            ExecJs(ad_frame_root_node,
+                   JsReplace(R"(
+              window.fence.setReportEventDataForAutomaticBeacons({
+                eventType: $1,
+                destination: ['seller', 'buyer']
+              });
+            )",
+                             blink::kFencedFrameTopNavigationBeaconType),
+                   ad_frame_execjs_options));
+      } else {
+        // Call `setReportEventDataForAutomaticBeacons()` with `eventData`.
+        EXPECT_TRUE(ExecJs(ad_frame_root_node,
+                           JsReplace(R"(
+              window.fence.setReportEventDataForAutomaticBeacons({
+                eventType: $1,
+                eventData: $2,
+                destination: ['seller', 'buyer']
+              });
+            )",
+                                     blink::kFencedFrameTopNavigationBeaconType,
+                                     config.message.value()),
+                           ad_frame_execjs_options));
+      }
     }
 
     std::string target;
@@ -6426,7 +6576,11 @@
 
     response.WaitForRequest();
     // Verify the request has the correct content.
-    EXPECT_EQ(response.http_request()->content, config.message);
+    if (!config.message) {
+      EXPECT_TRUE(response.http_request()->content.empty());
+    } else {
+      EXPECT_EQ(response.http_request()->content, config.message);
+    }
     // Verify the request contains the eligibility header.
     EXPECT_EQ(
         response.http_request()->headers.at("Attribution-Reporting-Eligible"),
@@ -6481,6 +6635,28 @@
 }
 
 IN_PROC_BROWSER_TEST_P(FencedFrameAutomaticBeaconBrowserTest,
+                       HasEventDataField) {
+  Config config = {
+      .starting_url = {"a.test", "/fenced_frames/title1.html"},
+      .navigation_url = {"b.test", "/fenced_frames/title1.html"},
+      .message = "Has event data.",
+      .expected_success = true,
+  };
+  RunTest(config);
+}
+
+IN_PROC_BROWSER_TEST_P(FencedFrameAutomaticBeaconBrowserTest,
+                       NoEventDataField) {
+  Config config = {
+      .starting_url = {"a.test", "/fenced_frames/title1.html"},
+      .navigation_url = {"b.test", "/fenced_frames/title1.html"},
+      .message = absl::nullopt,
+      .expected_success = true,
+  };
+  RunTest(config);
+}
+
+IN_PROC_BROWSER_TEST_P(FencedFrameAutomaticBeaconBrowserTest,
                        NoBeaconDataRegistered) {
   Config config = {
       .starting_url = {"a.test", "/fenced_frames/title1.html"},
diff --git a/content/browser/fenced_frame/fenced_frame_reporter.cc b/content/browser/fenced_frame/fenced_frame_reporter.cc
index f979f702..943acc4 100644
--- a/content/browser/fenced_frame/fenced_frame_reporter.cc
+++ b/content/browser/fenced_frame/fenced_frame_reporter.cc
@@ -23,7 +23,6 @@
 #include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/types/pass_key.h"
-#include "components/attribution_reporting/os_registration.h"
 #include "content/browser/attribution_reporting/attribution_beacon_id.h"
 #include "content/browser/attribution_reporting/attribution_data_host_manager.h"
 #include "content/browser/attribution_reporting/attribution_host.h"
@@ -50,6 +49,10 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
+#if BUILDFLAG(IS_ANDROID)
+#include "services/network/public/cpp/attribution_utils.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -292,7 +295,11 @@
       WebContents::FromRenderFrameHost(request_initiator_frame));
   if (attribution_host &&
       request_initiator_frame->IsFeatureEnabled(
-          blink::mojom::PermissionsPolicyFeature::kAttributionReporting)) {
+          blink::mojom::PermissionsPolicyFeature::kAttributionReporting)
+#if BUILDFLAG(IS_ANDROID)
+      && network::HasAttributionSupport(AttributionManager::GetSupport())
+#endif
+  ) {
     BeaconId beacon_id(unique_id_counter.GetNext());
     attribution_reporting_data.emplace(AttributionReportingData{
         .beacon_id = beacon_id,
@@ -374,8 +381,7 @@
                                attribution_reporting_data->is_automatic_beacon
                                    ? "navigation-source"
                                    : "event-source");
-    request->attribution_reporting_os_support =
-        AttributionManager::GetOsSupport();
+    request->attribution_reporting_support = AttributionManager::GetSupport();
   }
 
   // Create and configure `SimpleURLLoader` instance.
diff --git a/content/browser/file_system_access/file_system_chooser_browsertest.cc b/content/browser/file_system_access/file_system_chooser_browsertest.cc
index 2fe28db..0dcb4376f 100644
--- a/content/browser/file_system_access/file_system_chooser_browsertest.cc
+++ b/content/browser/file_system_access/file_system_chooser_browsertest.cc
@@ -1426,7 +1426,9 @@
                    "  self.selected_entry = e;"
                    "  return e.name; })()"));
   EXPECT_EQ(ui::SelectFileDialog::SELECT_OPEN_FILE, dialog_params.type);
-  EXPECT_EQ(test_file_dir, dialog_params.default_path);
+  // Windows file system is case-insensitive.
+  EXPECT_TRUE(base::FilePath::CompareEqualIgnoreCase(
+      test_file_dir.value(), dialog_params.default_path.value()));
 }
 
 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, StartIn_DirectoryHandle) {
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc
index 28ae86c8..241a14e 100644
--- a/content/browser/interest_group/auction_runner_unittest.cc
+++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -3478,8 +3478,9 @@
   EXPECT_THAT(
       result_.report_urls,
       testing::UnorderedElementsAre(
+          // top-level doesn't get highestScoringOtherBid.
           GURL("https://reporting.example.com/"
-               "?highestScoringOtherBid=1&"
+               "?highestScoringOtherBid=0&"
                "highestScoringOtherBidCurrency=???&"
                "bidCurrency=???&bid=2"),
           GURL("https://component2-report.test/"
@@ -3547,6 +3548,448 @@
                    .SetNumInterestGroupsWithOnlyNonKAnonBid(2));
 }
 
+// Test of a component auction where top-level seller and intermediate one use
+// different currencies.
+TEST_F(AuctionRunnerTest, ComponentAuctionMixedCurrency) {
+  const char kBidScript[] = R"(
+    const inBid = %d;
+    function generateBid(
+        interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals,
+        browserSignals) {
+      privateAggregation.reportContributionForEvent('reserved.always', {
+        bucket: {baseValue: 'winning-bid'},
+        value: 1 + 1000 * inBid,
+      });
+      privateAggregation.reportContributionForEvent('reserved.always', {
+        bucket: {baseValue: 'highest-scoring-other-bid'},
+        value: 2 + 1000 * inBid,
+      });
+      return {bid: inBid, render: interestGroup.ads[0].renderUrl,
+              allowComponentAuction: true};
+    }
+
+    function reportWin(
+        auctionSignals, perBuyerSignals, sellerSignals, browserSignals) {
+      let sendReportUrl = "https://buyer-reporting.example.com/";
+      sendReportUrl +=
+          '?highestScoringOtherBid=' + browserSignals.highestScoringOtherBid +
+          '&highestScoringOtherBidCurrency=' +
+          browserSignals.highestScoringOtherBidCurrency +
+          '&bidCurrency=' + browserSignals.bidCurrency +
+          '&bid=' + browserSignals.bid;
+      sendReportTo(sendReportUrl);
+
+      privateAggregation.reportContributionForEvent('reserved.win', {
+        bucket: {baseValue: 'winning-bid'},
+        value: 11 + 1000 * browserSignals.bid,
+      });
+      privateAggregation.reportContributionForEvent('reserved.win', {
+        bucket: {baseValue: 'highest-scoring-other-bid'},
+        value: 12 + 1000 * browserSignals.bid,
+      });
+    }
+  )";
+
+  const char kDecisionScript[] = R"(
+    const inOffset = %d;
+    function scoreAd(adMetadata, bid, auctionConfig, trustedScoringSignals,
+                      browserSignals) {
+      privateAggregation.reportContributionForEvent('reserved.always', {
+        bucket: {baseValue: 'winning-bid'},
+        value: inOffset + 1 + 1000 * bid,
+      });
+      privateAggregation.reportContributionForEvent('reserved.always', {
+        bucket: {baseValue: 'highest-scoring-other-bid'},
+        value: inOffset + 2 + 1000 * bid,
+      });
+      // Pass along a bit less than our conversion.
+      return {desirability: bid,
+              incomingBidInSellerCurrency: bid * 10,
+              bid: bid * 9,
+              allowComponentAuction: true,
+              ad: adMetadata};
+    }
+
+    function reportResult(auctionConfig, browserSignals) {
+      let sendReportUrl = "https://seller-reporting-" + inOffset +
+                          ".example.com/";
+      sendReportUrl +=
+          '?highestScoringOtherBid=' + browserSignals.highestScoringOtherBid +
+          '&highestScoringOtherBidCurrency=' +
+          browserSignals.highestScoringOtherBidCurrency +
+          '&bidCurrency=' + browserSignals.bidCurrency +
+          '&bid=' + browserSignals.bid;
+      sendReportTo(sendReportUrl);
+
+      privateAggregation.reportContributionForEvent('reserved.win', {
+        bucket: {baseValue: 'winning-bid'},
+        value: inOffset + 11 + 1000 * browserSignals.bid,
+      });
+      privateAggregation.reportContributionForEvent('reserved.win', {
+        bucket: {baseValue: 'highest-scoring-other-bid'},
+        value: inOffset + 12 + 1000 * browserSignals.bid,
+      });
+     }
+  )";
+
+  SetUpComponentAuctionAndResponses(/*bidder1_seller=*/kComponentSeller1,
+                                    /*bidder2_seller=*/kComponentSeller1,
+                                    /*bid_from_component_auction_wins=*/true,
+                                    /*report_post_auction_signals=*/true);
+  auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder1Url,
+                                         base::StringPrintf(kBidScript, 1));
+  auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder2Url,
+                                         base::StringPrintf(kBidScript, 2));
+  auction_worklet::AddJavascriptResponse(
+      &url_loader_factory_, kComponentSeller1Url,
+      base::StringPrintf(kDecisionScript, 20));
+  auction_worklet::AddJavascriptResponse(
+      &url_loader_factory_, kSellerUrl,
+      base::StringPrintf(kDecisionScript, 50));
+  ASSERT_EQ(component_auctions_.size(), 1u);
+  component_auctions_[0].non_shared_params.seller_currency =
+      blink::AdCurrency::From("USD");
+  seller_currency_ = blink::AdCurrency::From("CAD");
+
+  RunStandardAuction();
+  EXPECT_THAT(result_.errors, testing::ElementsAre());
+  EXPECT_EQ(GURL("https://ad2.com/"), result_.ad_descriptor->url);
+
+  EXPECT_THAT(
+      result_.report_urls,
+      testing::UnorderedElementsAre(
+          GURL("https://seller-reporting-50.example.com/"
+               "?highestScoringOtherBid=0&highestScoringOtherBidCurrency=???&"
+               "bidCurrency=CAD&bid=180"),
+          GURL("https://seller-reporting-20.example.com/"
+               "?highestScoringOtherBid=10&highestScoringOtherBidCurrency=USD&"
+               "bidCurrency=USD&bid=20"),
+          GURL("https://buyer-reporting.example.com/"
+               "?highestScoringOtherBid=10&highestScoringOtherBidCurrency=USD&"
+               "bidCurrency=???&bid=2")));
+
+  EXPECT_THAT(
+      private_aggregation_manager_.TakePrivateAggregationRequests(),
+      testing::UnorderedElementsAre(
+          testing::Pair(
+              kBidder1,
+              ElementsAreRequests(
+                  // generateBid(), winning-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/20, /*value=*/1001),
+                  // generateBid(), highest-scoring-other-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/10,
+                                                 /*value=*/1002))),
+          testing::Pair(
+              kBidder2,
+              ElementsAreRequests(
+                  // generateBid(), winning-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/20, /*value=*/2001),
+                  // generateBid(), highest-scoring-other-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/10, /*value=*
+                                                                 */
+                                                 2002),
+                  // reportWin(), winning-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/20, /*value=*/2011),
+                  // reportWin(), highest-scoring-other-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/10, /*value=*
+                                                                 */
+                                                 2012))),
+          testing::Pair(
+              kComponentSeller1,
+              ElementsAreRequests(
+                  // scoreAd(), winning-bid, incoming bid 1
+                  BuildPrivateAggregationRequest(/*bucket=*/20, /*value=*/1021),
+                  // scoreAd(), highest-scoring-other-bid, incoming bid 1
+                  BuildPrivateAggregationRequest(/*bucket=*/10, /*value=*
+                                                                 */
+                                                 1022),
+                  // scoreAd(), winning-bid, incoming bid 2
+                  BuildPrivateAggregationRequest(/*bucket=*/20, /*value=*/2021),
+                  // scoreAd(), highest-scoring-other-bid, incoming bid 2
+                  BuildPrivateAggregationRequest(/*bucket=*/10, /*value=*
+                                                                 */
+                                                 2022),
+                  // reportResult(), winning-bid, browserSignals.bid is 20
+                  BuildPrivateAggregationRequest(/*bucket=*/20,
+                                                 /*value=*/20031),
+                  // reportResult(), highest-scoring-other-bid,
+                  // browserSignals.bid is 20
+                  BuildPrivateAggregationRequest(/*bucket=*/10, /*value=*
+                                                                 */
+                                                 20032))),
+          testing::Pair(
+              kSeller,
+              ElementsAreRequests(
+                  // scoreAd(), winning-bid, browserSignals.bid is 18
+                  BuildPrivateAggregationRequest(/*bucket=*/180,
+                                                 /*value=*/18051),
+                  // scoreAd(), highest-scoring-other-bid is 0.
+                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/18052),
+                  // reportResult(), winning-bid, browserSignals.bid is 180.
+                  BuildPrivateAggregationRequest(/*bucket=*/180,
+                                                 /*value=*/180061),
+                  // reportResult() highest-scoring-other-bid is 0.
+                  BuildPrivateAggregationRequest(/*bucket=*/0,
+                                                 /*value=*/180062)))));
+}
+
+// Test of a component auction where top-level seller and intermediate one use
+// different currencies, with two components.
+TEST_F(AuctionRunnerTest, ComponentAuctionMixedCurrency2) {
+  const char kBidScript[] = R"(
+    const inBid = %d;
+    function generateBid(
+        interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals,
+        browserSignals) {
+      privateAggregation.reportContributionForEvent('reserved.always', {
+        bucket: {baseValue: 'winning-bid'},
+        value: 1 + 1000 * inBid,
+      });
+      privateAggregation.reportContributionForEvent('reserved.always', {
+        bucket: {baseValue: 'highest-scoring-other-bid'},
+        value: 2 + 1000 * inBid,
+      });
+      return {bid: inBid, render: interestGroup.ads[0].renderUrl,
+              allowComponentAuction: true};
+    }
+
+    function reportWin(
+        auctionSignals, perBuyerSignals, sellerSignals, browserSignals) {
+      let sendReportUrl = "https://buyer-reporting.example.com/";
+      sendReportUrl +=
+          '?highestScoringOtherBid=' + browserSignals.highestScoringOtherBid +
+          '&highestScoringOtherBidCurrency=' +
+          browserSignals.highestScoringOtherBidCurrency +
+          '&bidCurrency=' + browserSignals.bidCurrency +
+          '&bid=' + browserSignals.bid;
+      sendReportTo(sendReportUrl);
+
+      privateAggregation.reportContributionForEvent('reserved.win', {
+        bucket: {baseValue: 'winning-bid'},
+        value: 11 + 1000 * browserSignals.bid,
+      });
+      privateAggregation.reportContributionForEvent('reserved.win', {
+        bucket: {baseValue: 'highest-scoring-other-bid'},
+        value: 12 + 1000 * browserSignals.bid,
+      });
+    }
+  )";
+
+  const char kDecisionScript[] = R"(
+    const inOffset = %d;
+    function scoreAd(adMetadata, bid, auctionConfig, trustedScoringSignals,
+                      browserSignals) {
+      privateAggregation.reportContributionForEvent('reserved.always', {
+        bucket: {baseValue: 'winning-bid'},
+        value: inOffset + 1 + 1000 * bid,
+      });
+      privateAggregation.reportContributionForEvent('reserved.always', {
+        bucket: {baseValue: 'highest-scoring-other-bid'},
+        value: inOffset + 2 + 1000 * bid,
+      });
+      // Pass along a bit less than our conversion.
+      return {desirability: bid,
+              incomingBidInSellerCurrency: bid * 10,
+              bid: bid * 9,
+              allowComponentAuction: true,
+              ad: adMetadata};
+    }
+
+    function reportResult(auctionConfig, browserSignals) {
+      let sendReportUrl = "https://seller-reporting-" + inOffset +
+                          ".example.com/";
+      sendReportUrl +=
+          '?highestScoringOtherBid=' + browserSignals.highestScoringOtherBid +
+          '&highestScoringOtherBidCurrency=' +
+          browserSignals.highestScoringOtherBidCurrency +
+          '&bidCurrency=' + browserSignals.bidCurrency +
+          '&bid=' + browserSignals.bid;
+      sendReportTo(sendReportUrl);
+
+      privateAggregation.reportContributionForEvent('reserved.win', {
+        bucket: {baseValue: 'winning-bid'},
+        value: inOffset + 11 + 1000 * browserSignals.bid,
+      });
+      privateAggregation.reportContributionForEvent('reserved.win', {
+        bucket: {baseValue: 'highest-scoring-other-bid'},
+        value: inOffset + 12 + 1000 * browserSignals.bid,
+      });
+     }
+  )";
+
+  SetUpComponentAuctionAndResponses(/*bidder1_seller=*/kComponentSeller1,
+                                    /*bidder2_seller=*/kComponentSeller2,
+                                    /*bid_from_component_auction_wins=*/true,
+                                    /*report_post_auction_signals=*/true);
+  auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder1Url,
+                                         base::StringPrintf(kBidScript, 1));
+  auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder2Url,
+                                         base::StringPrintf(kBidScript, 2));
+  auction_worklet::AddJavascriptResponse(
+      &url_loader_factory_, kComponentSeller1Url,
+      base::StringPrintf(kDecisionScript, 20));
+  auction_worklet::AddJavascriptResponse(
+      &url_loader_factory_, kComponentSeller2Url,
+      base::StringPrintf(kDecisionScript, 40));
+  auction_worklet::AddJavascriptResponse(
+      &url_loader_factory_, kSellerUrl,
+      base::StringPrintf(kDecisionScript, 60));
+  ASSERT_EQ(component_auctions_.size(), 2u);
+  component_auctions_[0].non_shared_params.seller_currency =
+      blink::AdCurrency::From("USD");
+  component_auctions_[1].non_shared_params.seller_currency =
+      blink::AdCurrency::From("MXN");
+  seller_currency_ = blink::AdCurrency::From("CAD");
+
+  RunStandardAuction();
+  EXPECT_THAT(result_.errors, testing::ElementsAre());
+  EXPECT_EQ(GURL("https://ad2.com/"), result_.ad_descriptor->url);
+
+  EXPECT_THAT(
+      result_.report_urls,
+      testing::UnorderedElementsAre(
+          GURL("https://seller-reporting-60.example.com/"
+               "?highestScoringOtherBid=0&highestScoringOtherBidCurrency=???&"
+               "bidCurrency=CAD&bid=180"),
+          GURL("https://seller-reporting-40.example.com/"
+               "?highestScoringOtherBid=0&highestScoringOtherBidCurrency=MXN&"
+               "bidCurrency=MXN&bid=20"),
+          GURL("https://buyer-reporting.example.com/"
+               "?highestScoringOtherBid=0&highestScoringOtherBidCurrency=MXN&"
+               "bidCurrency=???&bid=2")));
+
+  EXPECT_THAT(
+      private_aggregation_manager_.TakePrivateAggregationRequests(),
+      testing::UnorderedElementsAre(
+          testing::Pair(
+              kBidder1,
+              ElementsAreRequests(
+                  // generateBid(), winning-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/10, /*value=*/1001),
+                  // generateBid(), highest-scoring-other-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/0,
+                                                 /*value=*/1002))),
+          testing::Pair(
+              kBidder2,
+              ElementsAreRequests(
+                  // generateBid(), winning-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/20, /*value=*/2001),
+                  // generateBid(), highest-scoring-other-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*
+                                                                */
+                                                 2002),
+                  // reportWin(), winning-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/20, /*value=*/2011),
+                  // reportWin(), highest-scoring-other-bid
+                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*
+                                                                */
+                                                 2012))),
+          testing::Pair(
+              kComponentSeller1,
+              ElementsAreRequests(
+                  // scoreAd(), winning-bid, incoming bid 1
+                  BuildPrivateAggregationRequest(/*bucket=*/10, /*value=*/1021),
+                  // scoreAd(), highest-scoring-other-bid, incoming bid 1
+                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*
+                                                                */
+                                                 1022))),
+          testing::Pair(
+              kComponentSeller2,
+              ElementsAreRequests(
+                  // scoreAd(), winning-bid, incoming bid 2
+                  BuildPrivateAggregationRequest(/*bucket=*/20, /*value=*/2041),
+                  // scoreAd(), highest-scoring-other-bid, incoming bid 2
+                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*
+                                                                */
+                                                 2042),
+                  // reportResult(), winning-bid, browserSignals.bid is 20
+                  BuildPrivateAggregationRequest(/*bucket=*/20,
+                                                 /*value=*/20051),
+                  // reportResult(), highest-scoring-other-bid,
+                  // browserSignals.bid is 20
+                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*
+                                                                */
+                                                 20052))),
+          testing::Pair(
+              kSeller,
+              ElementsAreRequests(
+                  // scoreAd(), winning-bid, browserSignals.bid is 9
+                  BuildPrivateAggregationRequest(/*bucket=*/180,
+                                                 /*value=*/9061),
+                  // scoreAd(), highest-scoring-other-bid is 0.
+                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/9062),
+
+                  // scoreAd(), winning-bid, browserSignals.bid is 18
+                  BuildPrivateAggregationRequest(/*bucket=*/180,
+                                                 /*value=*/18061),
+                  // scoreAd(), highest-scoring-other-bid is 0, since not set
+                  // on top-level.
+                  BuildPrivateAggregationRequest(/*bucket=*/0,
+                                                 /*value=*/18062),
+                  // reportResult(), winning-bid, browserSignals.bid is 180.
+                  BuildPrivateAggregationRequest(/*bucket=*/180,
+                                                 /*value=*/180071),
+                  // reportResult() highest-scoring-other-bid is 0, since not
+                  // set on top-level.
+                  BuildPrivateAggregationRequest(/*bucket=*/0,
+                                                 /*value=*/180072)))));
+}
+
+// Test of currency handling in a component auction where bid is passed
+// straight through by the component seller.
+TEST_F(AuctionRunnerTest, ComponentAuctionCurrencyPassThrough) {
+  const char kBidScript[] = R"(
+    const inBid = %d;
+    function generateBid(
+        interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals,
+        browserSignals) {
+      return {bid: inBid, bidCurrency: 'USD',
+              render: interestGroup.ads[0].renderUrl,
+              allowComponentAuction: true};
+    }
+
+    function reportWin(
+        auctionSignals, perBuyerSignals, sellerSignals, browserSignals) {
+    }
+  )";
+
+  const char kDecisionScript[] = R"(
+    const suffix = "%s";
+    function scoreAd(adMetadata, bid, auctionConfig, trustedScoringSignals,
+                      browserSignals) {
+      if (browserSignals.bidCurrency !== 'USD') {
+        throw 'Wrong bidCurrency in scoreAd() for ' + suffix;
+      }
+      return {desirability: bid,
+              allowComponentAuction: true,
+              ad: adMetadata};
+    }
+
+    function reportResult(auctionConfig, browserSignals) {
+    }
+  )";
+
+  SetUpComponentAuctionAndResponses(/*bidder1_seller=*/kComponentSeller1,
+                                    /*bidder2_seller=*/kComponentSeller1,
+                                    /*bid_from_component_auction_wins=*/true,
+                                    /*report_post_auction_signals=*/true);
+  auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder1Url,
+                                         base::StringPrintf(kBidScript, 1));
+  auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder2Url,
+                                         base::StringPrintf(kBidScript, 2));
+  auction_worklet::AddJavascriptResponse(
+      &url_loader_factory_, kComponentSeller1Url,
+      base::StringPrintf(kDecisionScript, "component"));
+  auction_worklet::AddJavascriptResponse(
+      &url_loader_factory_, kSellerUrl,
+      base::StringPrintf(kDecisionScript, "top-level"));
+  ASSERT_EQ(component_auctions_.size(), 1u);
+
+  RunStandardAuction();
+  EXPECT_THAT(result_.errors, testing::ElementsAre());
+  EXPECT_EQ(GURL("https://ad2.com/"), result_.ad_descriptor->url);
+}
+
 // Test a component auction where the top level seller rejects all bids. This
 // should fail with kAllBidsRejected instead of kNoBids.
 TEST_F(AuctionRunnerTest, ComponentAuctionTopSellerRejectsBids) {
@@ -10985,6 +11428,10 @@
 
   const std::string kSellerScript = R"(
     function scoreAd(adMetadata, bid, auctionConfig, browserSignals) {
+      let convertedBid;
+      if (auctionConfig.sellerCurrency) {
+        convertedBid = 10*bid;
+      }
       privateAggregation.reportContributionForEvent('reserved.always', {
         bucket: {baseValue: 'winning-bid'},
         value: 21 + 100 * bid,
@@ -10997,8 +11444,12 @@
         bucket: {baseValue: 'bid-reject-reason'},
         value: 23 + 100 * bid,
       });
-      if (bid === 2) return {desirability: -1, rejectReason: 'invalid-bid'};
-      return bid;
+      if (bid === 2) return {
+        desirability: -1,
+        incomingBidInSellerCurrency: convertedBid,
+        rejectReason: 'invalid-bid'
+      };
+      return {desirability: bid, incomingBidInSellerCurrency: convertedBid};
     }
 
     function reportResult(auctionConfig, browserSignals) {
@@ -11023,58 +11474,83 @@
                                          base::StringPrintf(kBidScript, 2));
   auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl,
                                          kSellerScript);
+  for (bool use_seller_currency : {false, true}) {
+    SCOPED_TRACE(use_seller_currency);
+    if (use_seller_currency) {
+      seller_currency_ = blink::AdCurrency::From("CAD");
+    }
 
-  // kBidder2 was rejected by seller, so kBidder1 won the auction.
-  RunStandardAuction(/*request_trusted_bidding_signals=*/false);
-  EXPECT_THAT(result_.errors, testing::UnorderedElementsAre());
-  EXPECT_FALSE(result_.manually_aborted);
-  EXPECT_EQ(kBidder1Key, result_.winning_group_id);
-  EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_descriptor->url);
+    // kBidder2 was rejected by seller, so kBidder1 won the auction.
+    RunStandardAuction(/*request_trusted_bidding_signals=*/false);
+    EXPECT_THAT(result_.errors, testing::UnorderedElementsAre());
+    EXPECT_FALSE(result_.manually_aborted);
+    EXPECT_EQ(kBidder1Key, result_.winning_group_id);
+    EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_descriptor->url);
 
-  // Post auction signals of this auction:
-  // winning-bid is 1, highest-scoring-other-bid is 0, bid-reject-reason for
-  // kBidder1 is kNotAvailable (0), and bid-reject-reason for kBidder2 is
-  // kInvalidBid (1).
-  EXPECT_THAT(
-      private_aggregation_manager_.TakePrivateAggregationRequests(),
-      testing::UnorderedElementsAre(
-          testing::Pair(
-              kBidder1,
-              ElementsAreRequests(
-                  // generateBid().
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/101),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/102),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/103),
-                  // reportWin(). No request for 'bid-reject-reason' whose value
-                  // is 113, because it's not a supported base value in
-                  // reportWin().
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/111),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/112))),
-          testing::Pair(
-              kBidder2,
-              ElementsAreRequests(
-                  // generateBid().
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/201),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/202),
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/203))),
-          testing::Pair(
-              kSeller,
-              ElementsAreRequests(
-                  // scoreAd() for kBidder1.
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/121),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/122),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/123),
-                  // scoreAd() for kBidder2.
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/221),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/222),
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/223),
-                  // reportResult() for kBidder1. No request for
-                  // 'bid-reject-reason' whose value is 133, because it's not a
-                  // supported base value in reportResult().
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/131),
-                  BuildPrivateAggregationRequest(/*bucket=*/0,
-                                                 /*value=*/132)))));
-  EXPECT_TRUE(result_.private_aggregation_event_map.empty());
+    // Post auction signals of this auction:
+    // If sellerCurrency is off:
+    //   winning-bid is 1, highest-scoring-other-bid is 0, bid-reject-reason for
+    //   kBidder1 is kNotAvailable (0), and bid-reject-reason for kBidder2 is
+    //   kInvalidBid (1).
+    // If sellerCurrency is on:
+    //   winning-bid is 10, everything else is the same.
+    //
+    // Some things use 100 * browserSignals.bid in their
+    // reportResultcalculation, that's in seller currency, so also needs to be
+    // adjusted.
+    int winning_bid = use_seller_currency ? 10 : 1;
+
+    EXPECT_THAT(
+        private_aggregation_manager_.TakePrivateAggregationRequests(),
+        testing::UnorderedElementsAre(
+            testing::Pair(
+                kBidder1,
+                ElementsAreRequests(
+                    // generateBid().
+                    BuildPrivateAggregationRequest(/*bucket=*/winning_bid,
+                                                   /*value=*/101),
+                    BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/102),
+                    BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/103),
+                    // reportWin(). No request for 'bid-reject-reason' whose
+                    // value is 113, because it's not a supported base value in
+                    // reportWin().
+                    BuildPrivateAggregationRequest(/*bucket=*/winning_bid,
+                                                   /*value=*/111),
+                    BuildPrivateAggregationRequest(/*bucket=*/0,
+                                                   /*value=*/112))),
+            testing::Pair(
+                kBidder2,
+                ElementsAreRequests(
+                    // generateBid().
+                    BuildPrivateAggregationRequest(/*bucket=*/winning_bid,
+                                                   /*value=*/201),
+                    BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/202),
+                    BuildPrivateAggregationRequest(/*bucket=*/1,
+                                                   /*value=*/203))),
+            testing::Pair(
+                kSeller,
+                ElementsAreRequests(
+                    // scoreAd() for kBidder1.
+                    BuildPrivateAggregationRequest(/*bucket=*/winning_bid,
+                                                   /*value=*/121),
+                    BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/122),
+                    BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/123),
+                    // scoreAd() for kBidder2.
+                    BuildPrivateAggregationRequest(/*bucket=*/winning_bid,
+                                                   /*value=*/221),
+                    BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/222),
+                    BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/223),
+                    // reportResult() for kBidder1. No request for
+                    // 'bid-reject-reason' whose value is 133, because it's not
+                    // a supported base value in reportResult().
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/winning_bid,
+                        /*value=*/100 * winning_bid + 31),
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/0,
+                        /*value=*/100 * winning_bid + 32)))));
+    EXPECT_TRUE(result_.private_aggregation_event_map.empty());
+  }
 }
 
 // Similar to `PrivateAggregationRequestForEventContributionBucketBaseValue()`
@@ -11121,6 +11597,10 @@
 
   const std::string kSellerScript = R"(
     function scoreAd(adMetadata, bid, auctionConfig, browserSignals) {
+      let convertedBid;
+      if (auctionConfig.sellerCurrency) {
+        convertedBid = 10*bid;
+      }
       privateAggregation.reportContributionForEvent('reserved.always', {
         bucket: {baseValue: 'winning-bid'},
         value: 21 + 100 * bid,
@@ -11133,7 +11613,7 @@
         bucket: {baseValue: 'bid-reject-reason'},
         value: 23 + 100 * bid,
       });
-      return bid;
+      return {desirability: bid, incomingBidInSellerCurrency: convertedBid};
     }
 
     function reportResult(auctionConfig, browserSignals) {
@@ -11159,58 +11639,84 @@
   auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl,
                                          kSellerScript);
 
-  // kBidder2 won the auction.
-  RunStandardAuction(/*request_trusted_bidding_signals=*/false);
-  EXPECT_THAT(result_.errors, testing::UnorderedElementsAre());
-  EXPECT_FALSE(result_.manually_aborted);
-  EXPECT_EQ(kBidder2Key, result_.winning_group_id);
-  EXPECT_EQ(GURL("https://ad2.com/"), result_.ad_descriptor->url);
+  for (bool use_seller_currency : {false, true}) {
+    SCOPED_TRACE(use_seller_currency);
+    if (use_seller_currency) {
+      seller_currency_ = blink::AdCurrency::From("CAD");
+    }
 
-  // Post auction signals of this auction:
-  // winning-bid is 2, highest-scoring-other-bid is 1, bid-reject-reason for
-  // both bidders are kNotAvailable (0).
-  EXPECT_THAT(
-      private_aggregation_manager_.TakePrivateAggregationRequests(),
-      testing::UnorderedElementsAre(
-          testing::Pair(
-              kBidder1,
-              ElementsAreRequests(
-                  // generateBid().
-                  BuildPrivateAggregationRequest(/*bucket=*/2, /*value=*/101),
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/102),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/103))),
-          testing::Pair(
-              kBidder2,
-              ElementsAreRequests(
-                  // generateBid().
-                  BuildPrivateAggregationRequest(
-                      /*bucket=*/2, /*value=*/201),
-                  BuildPrivateAggregationRequest(
-                      /*bucket=*/1, /*value=*/202),
-                  BuildPrivateAggregationRequest(
-                      /*bucket=*/0, /*value=*/203),
-                  // reportWin(). No request for 'bid-reject-reason' whose value
-                  // is 213, because it's not a supported base value in
-                  // reportWin().
-                  BuildPrivateAggregationRequest(/*bucket=*/2, /*value=*/211),
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/212))),
-          testing::Pair(
-              kSeller,
-              ElementsAreRequests(
-                  // scoreAd() for kBidder1.
-                  BuildPrivateAggregationRequest(/*bucket=*/2, /*value=*/121),
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/122),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/123),
-                  // scoreAd() for kBidder2.
-                  BuildPrivateAggregationRequest(/*bucket=*/2, /*value=*/221),
-                  BuildPrivateAggregationRequest(/*bucket=*/1, /*value=*/222),
-                  BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/223),
-                  // reportResult() for kBidder2. No request for
-                  // 'bid-reject-reason' whose value is 233, because it's not a
-                  // supported base value in reportResult().
-                  BuildPrivateAggregationRequest(/*bucket=*/2, /*value=*/231),
-                  BuildPrivateAggregationRequest(/*bucket=*/1,
-                                                 /*value=*/232)))));
+    // kBidder2 won the auction.
+    RunStandardAuction(/*request_trusted_bidding_signals=*/false);
+    EXPECT_THAT(result_.errors, testing::UnorderedElementsAre());
+    EXPECT_FALSE(result_.manually_aborted);
+    EXPECT_EQ(kBidder2Key, result_.winning_group_id);
+    EXPECT_EQ(GURL("https://ad2.com/"), result_.ad_descriptor->url);
+
+    // Post auction signals of this auction:
+    // If sellerCurrency is off:
+    //   winning-bid is 2, highest-scoring-other-bid is 1, bid-reject-reason for
+    //   both bidders are kNotAvailable (0).
+    // If sellerCurrency is on:
+    //   winning-bid is 20, highest_scoring_other_bid is 10, everything else is
+    // same.
+    int winning_bid = use_seller_currency ? 20 : 2;
+    int highest_scoring_other_bid = use_seller_currency ? 10 : 1;
+
+    EXPECT_THAT(
+        private_aggregation_manager_.TakePrivateAggregationRequests(),
+        testing::UnorderedElementsAre(
+            testing::Pair(
+                kBidder1,
+                ElementsAreRequests(
+                    // generateBid().
+                    BuildPrivateAggregationRequest(/*bucket=*/winning_bid,
+                                                   /*value=*/101),
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/highest_scoring_other_bid, /*value=*/102),
+                    BuildPrivateAggregationRequest(/*bucket=*/0,
+                                                   /*value=*/103))),
+            testing::Pair(
+                kBidder2,
+                ElementsAreRequests(
+                    // generateBid().
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/winning_bid, /*value=*/201),
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/highest_scoring_other_bid, /*value=*/202),
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/0, /*value=*/203),
+                    // reportWin(). No request for 'bid-reject-reason' whose
+                    // value is 213, because it's not a supported base value in
+                    // reportWin().
+                    BuildPrivateAggregationRequest(/*bucket=*/winning_bid,
+                                                   /*value=*/211),
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/highest_scoring_other_bid, /*value=*/212))),
+            testing::Pair(
+                kSeller,
+                ElementsAreRequests(
+                    // scoreAd() for kBidder1.
+                    BuildPrivateAggregationRequest(/*bucket=*/winning_bid,
+                                                   /*value=*/121),
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/highest_scoring_other_bid, /*value=*/122),
+                    BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/123),
+                    // scoreAd() for kBidder2.
+                    BuildPrivateAggregationRequest(/*bucket=*/winning_bid,
+                                                   /*value=*/221),
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/highest_scoring_other_bid, /*value=*/222),
+                    BuildPrivateAggregationRequest(/*bucket=*/0, /*value=*/223),
+                    // reportResult() for kBidder2. No request for
+                    // 'bid-reject-reason' whose value is 233, because it's not
+                    // a supported base value in reportResult().
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/winning_bid,
+                        /*value=*/winning_bid * 100 + 31),
+                    BuildPrivateAggregationRequest(
+                        /*bucket=*/highest_scoring_other_bid,
+                        /*value=*/winning_bid * 100 + 32)))));
+  }
 }
 
 // Similar to PrivateAggregationRequestForEventContributionBucketBaseValue,
@@ -14156,9 +14662,13 @@
               /*bid=*/1),
           DebugReportUrl(
               "https://top-seller-loss-reporting.test/",
-              PostAuctionSignals(/*winning_bid=*/ModeBid(2),
-                                 /*winning_bid_currency=*/ModeCurrency(),
-                                 /*made_winning_bid=*/false),
+              PostAuctionSignals(
+                  /*winning_bid=*/ModeBid(2),
+                  /*winning_bid_currency=*/ModeCurrency(),
+                  /*made_winning_bid=*/false,
+                  /*highest_scoring_other_bid=*/0.0,
+                  /*highest_scoring_other_bid_currency=*/absl::nullopt,
+                  /*made_highest_scoring_other_bid=*/false),
               /*bid=*/1)));
 
   EXPECT_THAT(result_.debug_win_report_urls,
@@ -14188,11 +14698,15 @@
                           /*winning_bid_currency=*/ModeCurrency(),
                           /*made_winning_bid=*/true),
                       /*bid=*/2),
-                  DebugReportUrl("https://top-seller-win-reporting.test/",
-                                 PostAuctionSignals(/*winning_bid=*/ModeBid(2),
-                                                    ModeCurrency(),
-                                                    /*made_winning_bid=*/true),
-                                 /*bid=*/2)));
+                  DebugReportUrl(
+                      "https://top-seller-win-reporting.test/",
+                      PostAuctionSignals(
+                          /*winning_bid=*/ModeBid(2), ModeCurrency(),
+                          /*made_winning_bid=*/true,
+                          /*highest_scoring_other_bid=*/0.0,
+                          /*highest_scoring_other_bid_currency=*/absl::nullopt,
+                          /*made_highest_scoring_other_bid=*/false),
+                      /*bid=*/2)));
 }
 
 // Test debug loss reporting in an auction with no winner. Component bidder 1 is
@@ -14443,12 +14957,16 @@
                           /*winning_bid_currency=*/ModeCurrency(),
                           /*made_winning_bid=*/true),
                       /*bid=*/1),
-                  DebugReportUrl("https://top-seller-win-reporting.test/",
-                                 PostAuctionSignals(
-                                     /*winning_bid=*/ModeBid(1),
-                                     /*winning_bid_currency=*/ModeCurrency(),
-                                     /*made_winning_bid=*/true),
-                                 /*bid=*/1)));
+                  DebugReportUrl(
+                      "https://top-seller-win-reporting.test/",
+                      PostAuctionSignals(
+                          /*winning_bid=*/ModeBid(1),
+                          /*winning_bid_currency=*/ModeCurrency(),
+                          /*made_winning_bid=*/true,
+                          /*highest_scoring_other_bid=*/0.0,
+                          /*highest_scoring_other_bid_currency=*/absl::nullopt,
+                          /*made_highest_scoring_other_bid=*/false),
+                      /*bid=*/1)));
 }
 
 // Loss report URLs should be dropped when the seller worklet fails to load.
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc
index fca1172..d3ea5fc4 100644
--- a/content/browser/interest_group/interest_group_auction.cc
+++ b/content/browser/interest_group/interest_group_auction.cc
@@ -860,19 +860,37 @@
       const BidState* winner,
       const BidState* non_kanon_winner,
       const PostAuctionSignals& signals,
+      const absl::optional<PostAuctionSignals>& top_level_signals,
       std::map<url::Origin, PrivateAggregationRequests>&
           private_aggregation_requests_reserved,
       std::map<std::string, PrivateAggregationRequests>&
           private_aggregation_requests_non_reserved) {
     for (std::unique_ptr<BidState>& state : bid_states_) {
       bool is_winner = state.get() == winner;
-      for (auto& [origin, requests] : state->private_aggregation_requests) {
+      for (auto& [key, requests] : state->private_aggregation_requests) {
+        const url::Origin& origin = key.first;
+        bool is_top_level_seller = key.second;
+        double winning_bid_to_use = signals.winning_bid;
+        double highest_scoring_other_bid_to_use =
+            signals.highest_scoring_other_bid;
+        // When component auctions are in use, a BuyerHelper for a component
+        // auction calls here for the scoreAd() aggregation calls from the
+        // top-level; in that case the relevant signals are in
+        // `top_level_signals` and not `signals`. `highest_scoring_other_bid`
+        // is also not reported for top-levels.
+        if (is_top_level_seller && auction_->parent_) {
+          highest_scoring_other_bid_to_use = 0;
+          winning_bid_to_use = top_level_signals.has_value()
+                                   ? top_level_signals->winning_bid
+                                   : 0.0;
+        }
+
         for (auction_worklet::mojom::PrivateAggregationRequestPtr& request :
              requests) {
           absl::optional<PrivateAggregationRequestWithEventType>
               converted_request = FillInPrivateAggregationRequest(
-                  std::move(request), signals.winning_bid,
-                  signals.highest_scoring_other_bid, state->reject_reason,
+                  std::move(request), winning_bid_to_use,
+                  highest_scoring_other_bid_to_use, state->reject_reason,
                   is_winner);
           if (converted_request.has_value()) {
             PrivateAggregationRequestWithEventType converted_request_value =
@@ -1372,7 +1390,8 @@
     auction_->MaybeLogPrivateAggregationWebFeatures(pa_requests);
     if (!pa_requests.empty()) {
       PrivateAggregationRequests& pa_requests_for_bidder =
-          state->private_aggregation_requests[interest_group.owner];
+          state->private_aggregation_requests[std::make_pair(
+              interest_group.owner, false /*not a top-level seller*/)];
       pa_requests_for_bidder.insert(pa_requests_for_bidder.end(),
                                     std::move_iterator(pa_requests.begin()),
                                     std::move_iterator(pa_requests.end()));
@@ -2393,7 +2412,7 @@
     std::map<std::string, PrivateAggregationRequests>
         private_aggregation_requests_non_reserved;
     buyer_helper->TakePrivateAggregationRequests(
-        winner, non_kanon_winner, signals,
+        winner, non_kanon_winner, signals, top_level_signals,
         private_aggregation_requests_reserved,
         private_aggregation_requests_non_reserved);
 
@@ -3146,7 +3165,8 @@
     if (!pa_requests.empty()) {
       DCHECK(config_);
       PrivateAggregationRequests& pa_requests_for_seller =
-          bid->bid_state->private_aggregation_requests[config_->seller];
+          bid->bid_state->private_aggregation_requests[std::make_pair(
+              config_->seller, !parent_)];
       for (auction_worklet::mojom::PrivateAggregationRequestPtr& request :
            pa_requests) {
         // A for-event private aggregation request with non-reserved event type
diff --git a/content/browser/interest_group/interest_group_auction.h b/content/browser/interest_group/interest_group_auction.h
index 499c71fc..caefc53f 100644
--- a/content/browser/interest_group/interest_group_auction.h
+++ b/content/browser/interest_group/interest_group_auction.h
@@ -266,10 +266,13 @@
 
     // Requests made to Private aggregation API in generateBid() and scoreAd().
     // Keyed by reporting origin of the associated requests, i.e., buyer origin
-    // for generateBid() and seller origin for scoreAd().
+    // for generateBid() and seller origin for scoreAd(), plus a bool that's
+    // true for top-level seller requests only, which is used to make sure they
+    // get the top-level signals.
+    //
     // TODO(qingxinwu): Consider only saving the requests without saving Origin,
     // since copying Origin is expensive.
-    std::map<url::Origin, PrivateAggregationRequests>
+    std::map<std::pair<url::Origin, bool>, PrivateAggregationRequests>
         private_aggregation_requests;
 
     // Requests made to Private aggregation API in generateBid() for the
diff --git a/content/browser/interest_group/interest_group_auction_reporter.cc b/content/browser/interest_group/interest_group_auction_reporter.cc
index 0454748..f08e941 100644
--- a/content/browser/interest_group/interest_group_auction_reporter.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter.cc
@@ -288,6 +288,8 @@
   // On a seller load failure or crash, act as if the worklet returned no
   // results to advance to the next worklet.
   OnSellerReportResultComplete(seller_info,
+                               /*winning_bid=*/0.0,
+                               /*highest_scoring_other_bid=*/0.0,
                                /*signals_for_winner=*/absl::nullopt,
                                /*seller_report_url=*/absl::nullopt,
                                /*seller_ad_beacon_map=*/{},
@@ -303,9 +305,11 @@
   auction_worklet::mojom::ComponentAuctionOtherSellerPtr other_seller;
   auction_worklet::mojom::ComponentAuctionReportResultParamsPtr
       browser_signals_component_auction_report_result_params;
+  bool top_level_with_components = false;
   if (seller_info == &top_level_seller_winning_bid_info_) {
     DCHECK(!top_seller_signals);
     if (component_seller_winning_bid_info_) {
+      top_level_with_components = true;
       other_seller = auction_worklet::mojom::ComponentAuctionOtherSeller::
           NewComponentSeller(
               component_seller_winning_bid_info_->auction_config->seller);
@@ -340,6 +344,11 @@
         *seller_info->auction_config->non_shared_params.seller_currency;
   }
 
+  // top-level auctions with components don't report highest_scoring_other_bid.
+  if (top_level_with_components) {
+    highest_scoring_other_bid = 0.0;
+  }
+
   seller_worklet_handle_->AuthorizeSubresourceUrls(
       *seller_info->subresource_url_builder);
   seller_worklet_handle_->GetSellerWorklet()->ReportResult(
@@ -357,18 +366,22 @@
                                  kFledgeScoreReportingBits.Get()),
       RoundStochasticallyToKBits(highest_scoring_other_bid,
                                  kFledgeBidReportingBits.Get()),
-      bid_currency,
+      /*browser_signal_highest_scoring_other_bid_currency=*/
+      top_level_with_components ? absl::nullopt : bid_currency,
       std::move(browser_signals_component_auction_report_result_params),
       seller_info->scoring_signals_data_version.value_or(0),
       seller_info->scoring_signals_data_version.has_value(),
       seller_info->trace_id,
       base::BindOnce(
           &InterestGroupAuctionReporter::OnSellerReportResultComplete,
-          weak_ptr_factory_.GetWeakPtr(), base::Unretained(seller_info)));
+          weak_ptr_factory_.GetWeakPtr(), base::Unretained(seller_info), bid,
+          highest_scoring_other_bid));
 }
 
 void InterestGroupAuctionReporter::OnSellerReportResultComplete(
     const SellerWinningBidInfo* seller_info,
+    double winning_bid,
+    double highest_scoring_other_bid,
     const absl::optional<std::string>& signals_for_winner,
     const absl::optional<GURL>& seller_report_url,
     const base::flat_map<std::string, GURL>& seller_ad_beacon_map,
@@ -395,8 +408,8 @@
     // meaningful thus not supported in reportResult(), so it is set to
     // absl::nullopt.
     absl::optional<PrivateAggregationRequestWithEventType> converted_request =
-        FillInPrivateAggregationRequest(std::move(request), seller_info->bid,
-                                        seller_info->highest_scoring_other_bid,
+        FillInPrivateAggregationRequest(std::move(request), winning_bid,
+                                        highest_scoring_other_bid,
                                         /*reject_reason=*/absl::nullopt,
                                         /*is_winner=*/true);
 
@@ -570,6 +583,14 @@
           made_highest_scoring_other_bid, highest_scoring_other_bid,
           highest_scoring_other_bid_currency);
 
+  // While reportWin() itself always gets the bid back in its own currency,
+  // for private aggregation we want to do things in seller currency if
+  // it's enabled.
+  double winning_bid_for_aggregation =
+      auction_config->non_shared_params.seller_currency
+          ? seller_info.bid_in_seller_currency
+          : winning_bid_info_.bid;
+
   bidder_worklet_handle_->GetBidderWorklet()->ReportWin(
       group_name, auction_config->non_shared_params.auction_signals.value(),
       per_buyer_signals,
@@ -605,7 +626,8 @@
       winning_bid_info_.bidding_signals_data_version.has_value(),
       top_level_seller_winning_bid_info_.trace_id,
       base::BindOnce(&InterestGroupAuctionReporter::OnBidderReportWinComplete,
-                     weak_ptr_factory_.GetWeakPtr()));
+                     weak_ptr_factory_.GetWeakPtr(),
+                     winning_bid_for_aggregation, highest_scoring_other_bid));
 }
 
 void InterestGroupAuctionReporter::OnBidderWorkletFatalError(
@@ -613,12 +635,16 @@
     const std::vector<std::string>& errors) {
   // Nothing more to do. Act as if the worklet completed as normal, with no
   // results.
-  OnBidderReportWinComplete(/*bidder_report_url=*/absl::nullopt,
+  OnBidderReportWinComplete(/*winning_bid=*/0.0,
+                            /*highest_scoring_other_bid=*/0.0,
+                            /*bidder_report_url=*/absl::nullopt,
                             /*bidder_ad_beacon_map=*/{},
                             /*pa_requests=*/{}, errors);
 }
 
 void InterestGroupAuctionReporter::OnBidderReportWinComplete(
+    double winning_bid,
+    double highest_scoring_other_bid,
     const absl::optional<GURL>& bidder_report_url,
     const base::flat_map<std::string, GURL>& bidder_ad_beacon_map,
     PrivateAggregationRequests pa_requests,
@@ -640,7 +666,6 @@
 
   const url::Origin& bidder =
       winning_bid_info_.storage_interest_group->interest_group.owner;
-  const SellerWinningBidInfo& seller_info = GetBidderAuction();
   for (auction_worklet::mojom::PrivateAggregationRequestPtr& request :
        pa_requests) {
     // Only winner's reportWin() gets executed, so is_winner is true, which
@@ -649,8 +674,8 @@
     // absl::nullopt.
     absl::optional<PrivateAggregationRequestWithEventType> converted_request =
         FillInPrivateAggregationRequest(
-            std::move(request), winning_bid_info_.bid,
-            /*highest_scoring_other_bid=*/seller_info.highest_scoring_other_bid,
+            std::move(request), winning_bid,
+            /*highest_scoring_other_bid=*/highest_scoring_other_bid,
             /*reject_reason=*/absl::nullopt, /*is_winner=*/true);
 
     if (converted_request.has_value()) {
diff --git a/content/browser/interest_group/interest_group_auction_reporter.h b/content/browser/interest_group/interest_group_auction_reporter.h
index 25848f1..1886963c 100644
--- a/content/browser/interest_group/interest_group_auction_reporter.h
+++ b/content/browser/interest_group/interest_group_auction_reporter.h
@@ -307,9 +307,13 @@
   // Invoked once a seller's ReportResult() call has completed. Either starts
   // loading the component seller worklet, If the winning bid is from a
   // component seller and it was the top-level seller worklet that completed,
-  // or starts loading the bidder worklet, otherwise.
+  // or starts loading the bidder worklet, otherwise. `winning_bid` and
+  // `highest_scoring_other_bid` are in appropriate currency for private
+  // aggregation depending on the currency mode.
   void OnSellerReportResultComplete(
       const SellerWinningBidInfo* seller_info,
+      double winning_bid,
+      double highest_scoring_other_bid,
       const absl::optional<std::string>& signals_for_winner,
       const absl::optional<GURL>& seller_report_url,
       const base::flat_map<std::string, GURL>& seller_ad_beacon_map,
@@ -330,8 +334,12 @@
   void OnBidderWorkletReceived(const std::string& signals_for_winner);
 
   // Invoked the winning bidder's ReportWin() call has completed. Invokes
-  // OnReportingComplete().
+  // OnReportingComplete(). `winning_bid` and `highest_scoring_other_bid` are in
+  // appropriate currency for private aggregation depending on the currency
+  // mode.
   void OnBidderReportWinComplete(
+      double winning_bid,
+      double highest_scoring_other_bid,
       const absl::optional<GURL>& bidder_report_url,
       const base::flat_map<std::string, GURL>& bidder_ad_beacon_map,
       PrivateAggregationRequests pa_requests,
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc
index b5b4b2c..ec35abab 100644
--- a/content/browser/interest_group/interest_group_browsertest.cc
+++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -12608,6 +12608,42 @@
   EXPECT_TRUE(network_responder_->HasReceivedRequest());
 }
 
+// Call `setReportEventDataForAutomaticBeacons` without `eventData` field. The
+// beacon should be sent with empty event data.
+IN_PROC_BROWSER_TEST_F(
+    InterestGroupFencedFrameAdComponentAutomaticBeaconBrowserTest,
+    AdComponentFencedFrameNoEventData) {
+  GURL ad_component_url = https_server_->GetURL(
+      "a.test", "/set-header?Supports-Loading-Mode: fenced-frame");
+
+  ASSERT_NO_FATAL_FAILURE(RunAdAuctionAndLoadAdComponent(ad_component_url));
+
+  RenderFrameHostImpl* ad_frame = GetFencedFrameRenderFrameHost(shell());
+  RenderFrameHostImpl* ad_component_frame =
+      GetFencedFrameRenderFrameHost(ad_frame);
+
+  // Set automatic beacon data for ad component without the eventData field.
+  EXPECT_TRUE(ExecJs(ad_component_frame, (R"(
+                        window.fence.setReportEventDataForAutomaticBeacons(
+                          {
+                            eventType: 'reserved.top_navigation',
+                            destination: ['seller']
+                          }
+                        );
+                      )")));
+
+  // Perform a cross-origin `_unfencedTop` navigation.
+  GURL navigation_url = https_server_->GetURL(
+      "b.test", "/set-header?Supports-Loading-Mode: fenced-frame");
+  EXPECT_TRUE(
+      ExecJs(ad_component_frame,
+             JsReplace("window.open($1, '_unfencedTop');", navigation_url)));
+
+  // Expect automatic beacon being sent successfully with empty event data.
+  EXPECT_TRUE(network_responder_->GetRequest()->content.empty());
+  EXPECT_TRUE(network_responder_->HasReceivedRequest());
+}
+
 }  // namespace
 
 }  // namespace content
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index d838bac3..ddd5d5f 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -326,8 +326,7 @@
   new_request->has_storage_access =
       request_info.begin_params->has_storage_access;
 
-  new_request->attribution_reporting_os_support =
-      AttributionManager::GetOsSupport();
+  new_request->attribution_reporting_support = AttributionManager::GetSupport();
 
   return new_request;
 }
diff --git a/content/browser/presentation/presentation_service_impl.cc b/content/browser/presentation/presentation_service_impl.cc
index a130c82..8eed131 100644
--- a/content/browser/presentation/presentation_service_impl.cc
+++ b/content/browser/presentation/presentation_service_impl.cc
@@ -446,18 +446,12 @@
              : static_cast<PresentationServiceDelegate*>(controller_delegate_);
 }
 
-// TODO(btolsch): Convert to PresentationConnectionResultPtr.
 void PresentationServiceImpl::OnReceiverConnectionAvailable(
-    PresentationInfoPtr presentation_info,
-    mojo::PendingRemote<blink::mojom::PresentationConnection>
-        controller_connection_remote,
-    mojo::PendingReceiver<blink::mojom::PresentationConnection>
-        receiver_connection_receiver) {
+    blink::mojom::PresentationConnectionResultPtr result) {
   DVLOG(2) << "PresentationServiceImpl::OnReceiverConnectionAvailable";
 
   presentation_receiver_remote_->OnReceiverConnectionAvailable(
-      std::move(presentation_info), std::move(controller_connection_remote),
-      std::move(receiver_connection_receiver));
+      std::move(result));
 }
 
 void PresentationServiceImpl::DidFinishNavigation(
diff --git a/content/browser/presentation/presentation_service_impl.h b/content/browser/presentation/presentation_service_impl.h
index 0ef6e56..95e82fa 100644
--- a/content/browser/presentation/presentation_service_impl.h
+++ b/content/browser/presentation/presentation_service_impl.h
@@ -221,11 +221,7 @@
   // the PresentationServiceImpl for the presentation receiver is initialized.
   // Calls |receiver_| to create a new PresentationConnection on receiver page.
   void OnReceiverConnectionAvailable(
-      blink::mojom::PresentationInfoPtr presentation_info,
-      mojo::PendingRemote<blink::mojom::PresentationConnection>
-          controller_connection_remote,
-      mojo::PendingReceiver<blink::mojom::PresentationConnection>
-          receiver_connection_receiver);
+      blink::mojom::PresentationConnectionResultPtr result);
 
   // Associates a ReconnectPresentation |callback| with a unique request ID and
   // stores it in a map. Moves out |callback| object if |callback| is registered
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc
index bdc5d7c..c96a48f 100644
--- a/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -32,6 +32,9 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+using blink::mojom::PresentationConnectionResult;
+using blink::mojom::PresentationInfo;
+
 namespace content {
 
 namespace {
@@ -253,7 +256,7 @@
   mojo::Remote<PresentationConnection> controller_remote;
   std::ignore = presentation_connection_remote.InitWithNewPipeAndPassReceiver();
   std::move(callback).Run(PresentationConnectionResult::New(
-      blink::mojom::PresentationInfo::New(presentation_url2_, kPresentationId),
+      PresentationInfo::New(presentation_url2_, kPresentationId),
       std::move(presentation_connection_remote),
       controller_remote.BindNewPipeAndPassReceiver()));
   base::RunLoop().RunUntilIdle();
@@ -340,8 +343,7 @@
       .Times(1);
   std::move(saved_success_cb)
       .Run(PresentationConnectionResult::New(
-          blink::mojom::PresentationInfo::New(presentation_url1_,
-                                              kPresentationId),
+          PresentationInfo::New(presentation_url1_, kPresentationId),
           mojo::NullRemote(), mojo::NullReceiver()));
   ExpectPresentationCallbackWasRun();
 }
@@ -388,8 +390,7 @@
       .Times(1);
   std::move(saved_success_cb)
       .Run(PresentationConnectionResult::New(
-          blink::mojom::PresentationInfo::New(presentation_url1_,
-                                              kPresentationId),
+          PresentationInfo::New(presentation_url1_, kPresentationId),
           mojo::NullRemote(), mojo::NullReceiver()));
   ExpectPresentationCallbackWasRun();
 }
@@ -469,12 +470,10 @@
       controller_connection.InitWithNewPipeAndPassReceiver());
   mojo::Remote<PresentationConnection> receiver_connection;
 
-  EXPECT_CALL(mock_receiver,
-              OnReceiverConnectionAvailable(InfoPtrEquals(expected), _, _))
-      .Times(1);
-  callback.Run(PresentationInfo::New(expected),
-               std::move(controller_connection),
-               receiver_connection.BindNewPipeAndPassReceiver());
+  EXPECT_CALL(mock_receiver, OnReceiverConnectionAvailable(_)).Times(1);
+  callback.Run(PresentationConnectionResult::New(
+      PresentationInfo::New(expected), std::move(controller_connection),
+      receiver_connection.BindNewPipeAndPassReceiver()));
   base::RunLoop().RunUntilIdle();
 
   EXPECT_CALL(mock_receiver_delegate_, RemoveObserver(_, _)).Times(1);
diff --git a/content/browser/presentation/presentation_test_utils.h b/content/browser/presentation/presentation_test_utils.h
index 58a17cb..dcdb6a1 100644
--- a/content/browser/presentation/presentation_test_utils.h
+++ b/content/browser/presentation/presentation_test_utils.h
@@ -133,12 +133,8 @@
   MockPresentationReceiver();
   ~MockPresentationReceiver() override;
 
-  MOCK_METHOD3(
-      OnReceiverConnectionAvailable,
-      void(PresentationInfoPtr info,
-           mojo::PendingRemote<PresentationConnection> controller_connection,
-           mojo::PendingReceiver<PresentationConnection>
-               presentation_receiver_receiver));
+  MOCK_METHOD1(OnReceiverConnectionAvailable,
+               void(PresentationConnectionResultPtr result));
 };
 
 class MockReceiverPresentationServiceDelegate
diff --git a/content/browser/renderer_host/compositor_dependencies_android.cc b/content/browser/renderer_host/compositor_dependencies_android.cc
index b72c98f8..3fd2dd1 100644
--- a/content/browser/renderer_host/compositor_dependencies_android.cc
+++ b/content/browser/renderer_host/compositor_dependencies_android.cc
@@ -151,7 +151,7 @@
 }
 
 void CompositorDependenciesAndroid::EnqueueLowEndBackgroundCleanup() {
-  if (base::SysInfo::IsLowEndDevice()) {
+  if (base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled()) {
     low_end_background_cleanup_task_.Reset(base::BindOnce(
         &CompositorDependenciesAndroid::DoLowEndBackgroundCleanup,
         base::Unretained(this)));
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index aecb3505f..1bb280c 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -39,6 +39,7 @@
 #include "base/types/optional_util.h"
 #include "base/types/pass_key.h"
 #include "build/build_config.h"
+#include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/browsing_topics/header_util.h"
@@ -190,6 +191,8 @@
 #include "url/url_constants.h"
 
 #if BUILDFLAG(IS_ANDROID)
+#include "content/browser/attribution_reporting/attribution_manager.h"
+#include "services/network/public/cpp/attribution_utils.h"
 #include "ui/android/window_android.h"
 #include "ui/android/window_android_compositor.h"
 #endif
@@ -440,7 +443,11 @@
     headers->SetHeader("Purpose", "prefetch");
   }
 
-  if (has_attribution_src_token) {
+  if (has_attribution_src_token
+#if BUILDFLAG(IS_ANDROID)
+      && network::HasAttributionSupport(AttributionManager::GetSupport())
+#endif
+  ) {
     headers->SetHeader("Attribution-Reporting-Eligible", "navigation-source");
   }
 }
@@ -4558,7 +4565,6 @@
       policy_container_builder_->FinalPolicies().cross_origin_opener_policy,
       url::Origin(), net::NetworkAnonymizationKey::CreateTransient());
 
-  RenderFrameHostImpl* render_frame_host = nullptr;
   switch (ComputeErrorPageProcess()) {
     case ErrorPageProcess::kCurrentProcess:
       // There's no way to get here with a same-document navigation, it would
@@ -4566,7 +4572,6 @@
       // same document navigations don't go to the network so it wouldn't know
       // about the change.
       CHECK(!IsSameDocument());
-      render_frame_host = frame_tree_node_->current_frame_host();
       break;
     case ErrorPageProcess::kIsolatedProcess:
       // In this case we are isolating the error page from the source and
@@ -4585,30 +4590,33 @@
       // https://crbug.com/1125106.
       common_params_->navigation_type =
           ConvertToCrossDocumentType(common_params_->navigation_type);
-      if (auto result =
-              frame_tree_node_->render_manager()->GetFrameHostForNavigation(
-                  this, &browsing_context_group_swap_);
-          result.has_value()) {
-        render_frame_host = result.value();
-      } else {
-        switch (result.error()) {
-          case GetFrameHostForNavigationFailed::kCouldNotReinitializeMainFrame:
-            // TODO(https://crbug.com/1400535): This was unhandled
-            // before and remains explicitly unhandled. This branch may be
-            // removed in the future.
-            break;
-          case GetFrameHostForNavigationFailed::kBlockedByPendingCommit:
-            // TODO(https://crbug.com/1220337): Split OnRequestFailedInternal()
-            // so the process selection logic is at the top of its own method.
-            break;
-        }
-      }
       break;
     case ErrorPageProcess::kNotErrorPage:
     case ErrorPageProcess::kPostCommitErrorPage:
       NOTREACHED();
       break;
   }
+
+  RenderFrameHostImpl* render_frame_host = nullptr;
+  if (auto result =
+          frame_tree_node_->render_manager()->GetFrameHostForNavigation(
+              this, &browsing_context_group_swap_);
+      result.has_value()) {
+    render_frame_host = result.value();
+  } else {
+    switch (result.error()) {
+      case GetFrameHostForNavigationFailed::kCouldNotReinitializeMainFrame:
+        // TODO(https://crbug.com/1400535): This was unhandled
+        // before and remains explicitly unhandled. This branch may be
+        // removed in the future.
+        break;
+      case GetFrameHostForNavigationFailed::kBlockedByPendingCommit:
+        // TODO(https://crbug.com/1220337): Split OnRequestFailedInternal()
+        // so the process selection logic is at the top of its own method.
+        break;
+    }
+  }
+
   // Sanity check that we haven't changed the RenderFrameHost picked for the
   // error page in OnRequestFailedInternal when running the WillFailRequest
   // checks.
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index 488ebfe..b723da80 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -167,11 +167,21 @@
     SiteInstanceImpl* site_instance,
     const FrameTreeNode& frame_tree_node,
     NavigationRequest::ErrorPageProcess error_page_process) {
-  // With no error isolation all SiteInstances are compatible with any
-  // |error_page_process|.
+  if (error_page_process ==
+      NavigationRequest::ErrorPageProcess::kCurrentProcess) {
+    // If an error page must commit in the current process, the current
+    // SiteInstance must be reused.
+    return site_instance ==
+           frame_tree_node.current_frame_host()->GetSiteInstance();
+  }
+
   if (!frame_tree_node.IsErrorPageIsolationEnabled()) {
-    DCHECK_NE(error_page_process,
-              NavigationRequest::ErrorPageProcess::kIsolatedProcess);
+    // With no error isolation or current process requirement, all SiteInstances
+    // are compatible with any |error_page_process|.
+    CHECK(error_page_process ==
+              NavigationRequest::ErrorPageProcess::kNotErrorPage ||
+          error_page_process ==
+              NavigationRequest::ErrorPageProcess::kDestinationProcess);
     return true;
   }
 
@@ -1527,8 +1537,9 @@
     navigation_rfh->web_ui()->WebUIRenderFrameCreated(navigation_rfh);
   }
 
-  // If this function picked an incompatible process for the URL, capture a
-  // crash dump to diagnose why it is occurring.
+  // If this function picked an incompatible process for the URL, except for
+  // allowed cases such as navigating to an error page reusing the current
+  // process, capture a crash dump to diagnose why it is occurring.
   // TODO(creis): Remove this check after we've gathered enough information to
   // debug issues with browser-side security checks. https://crbug.com/931895.
   auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
@@ -1540,7 +1551,9 @@
       !policy->CanAccessDataForOrigin(
           navigation_rfh->GetProcess()->GetID(),
           url::Origin::Create(request->common_params().url)) &&
-      !request->IsForMhtmlSubframe()) {
+      !request->IsForMhtmlSubframe() &&
+      request->ComputeErrorPageProcess() !=
+          NavigationRequest::ErrorPageProcess::kCurrentProcess) {
     SCOPED_CRASH_KEY_STRING256("GetFrameHostForNav", "lock_url",
                                process_lock.ToString());
     SCOPED_CRASH_KEY_STRING64(
@@ -2580,6 +2593,20 @@
   // SiteInstanceRelation::RELATED_IN_COOP_GROUP relations to `current_instance`
   // iff `browsing_context_group_swap.ShouldSwap()` is true.
 
+  // If this is an error page that must reuse the current process, ensure that
+  // `current_instance` is used. Note that this must be the first check to
+  // avoid picking the destination instance or other instances, to preserve the
+  //  previous behavior where we didn't call this function (or even
+  // `GetFrameHostForNavigation()`) at all and immediately picked the current
+  // SiteInstance (through picking the current RenderFrameHost directly) in
+  // `NavigationRequest::OnRequestFailedInternal()`.
+  if (error_page_process ==
+      NavigationRequest::ErrorPageProcess::kCurrentProcess) {
+    AppendReason(reason,
+                 "DetermineSiteInstanceForURL => error-current-instance");
+    return SiteInstanceDescriptor(current_instance);
+  }
+
   // If the entry has an instance already we should usually use it, unless it is
   // no longer suitable.
 
@@ -2602,7 +2629,8 @@
     // reloads. In UrlInfo below we use kNone for OriginIsolationRequest since
     // error pages cannot request origin isolation: this is done implicitly in
     // the UrlInfoInit constructor.
-    AppendReason(reason, "DetermineSiteInstanceForURL => error-instance");
+    AppendReason(reason,
+                 "DetermineSiteInstanceForURL => error-isolated-instance");
 
     // Top level frames ending up as error pages should use COOP: unsafe-none.
     // They should therefore be non isolated. Note that it is possible for a
diff --git a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
index aceabcba..33189317 100644
--- a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
@@ -9,6 +9,7 @@
 #include <memory>
 #include <set>
 
+#include "base/cfi_buildflags.h"
 #include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
@@ -5758,9 +5759,11 @@
 // its unload handler is able to send a postMessage to the parent frame.
 // See https://crbug.com/857274.
 // TODO(https://crbug.com/989704): Fix flake on Linux TSAN and ASAN.
+// TODO(https://crbug.com/1439710): Fix flake on Linux CFI.
 #if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER)) || \
     (BUILDFLAG(IS_LINUX) &&                                                   \
-     (defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)))
+     (defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||              \
+      BUILDFLAG(CFI_ICALL_CHECK)))
 #define MAYBE_PostMessageToParentWhenSubframeNavigates \
   DISABLED_PostMessageToParentWhenSubframeNavigates
 #else
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 5ee1648..2e3678f 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1751,7 +1751,7 @@
       GetContentClient()->browser()->GetReducedUserAgent(),
       GetContentClient()->browser()->GetUserAgentMetadata(),
       storage_partition_impl_->cors_exempt_header_list(),
-      AttributionManager::GetOsSupport());
+      AttributionManager::GetSupport());
 
   if (run_renderer_in_process()) {
     DCHECK(g_renderer_main_thread_factory);
@@ -3135,10 +3135,9 @@
   // Spare renderer actually hurts performance on low-memory devices.  See
   // https://crbug.com/843775 for more details.
   //
-  // The comparison below is using 1077 rather than 1024 because 1) this helps
+  // The comparison below is using 1077 rather than 1024 because this helps
   // ensure that devices with exactly 1GB of RAM won't get included because of
-  // inaccuracies or off-by-one errors and 2) this is the bucket boundary in
-  // Memory.Stats.Win.TotalPhys2.
+  // inaccuracies or off-by-one errors.
   if (base::SysInfo::AmountOfPhysicalMemoryMB() <= 1077)
     return false;
 
@@ -5484,9 +5483,9 @@
   child_process_->OnMemoryPressure(level);
 }
 
-void RenderProcessHostImpl::SetOsSupportForAttributionReporting(
-    network::mojom::AttributionOsSupport os_support) {
-  GetRendererInterface()->SetOsSupportForAttributionReporting(os_support);
+void RenderProcessHostImpl::SetAttributionReportingSupport(
+    network::mojom::AttributionSupport attribution_support) {
+  GetRendererInterface()->SetAttributionReportingSupport(attribution_support);
 }
 
 #endif
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 200758b..589cfa7 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -328,8 +328,8 @@
       const GlobalRenderFrameHostId& render_frame_host_id) override;
 
 #if BUILDFLAG(IS_ANDROID)
-  void SetOsSupportForAttributionReporting(
-      network::mojom::AttributionOsSupport os_support) override;
+  void SetAttributionReportingSupport(
+      network::mojom::AttributionSupport) override;
 #endif
 
   // IPC::Sender via RenderProcessHost.
diff --git a/content/browser/resources/attribution_reporting/attribution_internals.html b/content/browser/resources/attribution_reporting/attribution_internals.html
index 056941c3..cc13d550 100644
--- a/content/browser/resources/attribution_reporting/attribution_internals.html
+++ b/content/browser/resources/attribution_reporting/attribution_internals.html
@@ -18,7 +18,7 @@
 <header>
 <h1>Attribution Reporting API Internals</h1>
 <p>Attribution Reporting is currently <span id="feature-status-content" class="disabled">disabled</span> in this browser.
-<p>OS support is <span id="os-support" class="disabled">disabled</span> in this browser.
+<p><code>Attribution-Reporting-Support</code> is <strong><span id="attribution-support">web</span></strong> in this browser.
 <p id="debug-mode-content"></p>
 <button id="refresh">Refresh all page data</button>
 <button id="clear-data">Clear all attribution data</button>
diff --git a/content/browser/resources/attribution_reporting/attribution_internals.ts b/content/browser/resources/attribution_reporting/attribution_internals.ts
index c94c3e9..f93e616 100644
--- a/content/browser/resources/attribution_reporting/attribution_internals.ts
+++ b/content/browser/resources/attribution_reporting/attribution_internals.ts
@@ -1180,9 +1180,8 @@
         debugModeContent.innerText = '';
       }
 
-      const osSupport = document.querySelector<HTMLElement>('#os-support')!;
-      osSupport.innerText = response.hasOsSupport ? 'enabled' : 'disabled';
-      osSupport.classList.toggle('disabled', !response.hasOsSupport);
+      const attributionSupport = document.querySelector<HTMLElement>('#attribution-support')!;
+      attributionSupport.innerText = response.attributionSupport;
     });
 
     this.updateSources();
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index d2bd22ce..475614d 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -69,6 +69,13 @@
 #include "media/capture/capture_switches.h"
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+#include "base/task/sequenced_task_runner.h"
+#include "components/viz/host/gpu_client.h"
+#include "media/capture/capture_switches.h"
+#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
+#endif  // BUILDFLAG(IS_LINUX)
+
 namespace content {
 
 namespace {
@@ -122,6 +129,9 @@
       started_(false),
       name_(u"utility process"),
       file_data_(std::make_unique<ChildProcessLauncherFileData>()),
+#if BUILDFLAG(IS_LINUX)
+      gpu_client_(nullptr, base::OnTaskRunnerDeleter(nullptr)),
+#endif
       client_(std::move(client)) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   process_ = std::make_unique<BrowserChildProcessHostImpl>(
@@ -410,6 +420,17 @@
     }
 #endif  // BUILDFLAG(IS_LINUX)
 
+#if BUILDFLAG(IS_LINUX)
+    if (metrics_name_ == video_capture::mojom::VideoCaptureService::Name_) {
+      if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+              switches::kDisableVideoCaptureUseGpuMemoryBuffer) &&
+          base::CommandLine::ForCurrentProcess()->HasSwitch(
+              switches::kVideoCaptureUseGpuMemoryBuffer)) {
+        cmd_line->AppendSwitch(switches::kVideoCaptureUseGpuMemoryBuffer);
+      }
+    }
+#endif  // BUILDFLAG(IS_LINUX)
+
     std::unique_ptr<UtilitySandboxedProcessLauncherDelegate> delegate =
         std::make_unique<UtilitySandboxedProcessLauncherDelegate>(
             sandbox_type_, env_, *cmd_line);
diff --git a/content/browser/utility_process_host.h b/content/browser/utility_process_host.h
index 64ca6bc..65e59b1 100644
--- a/content/browser/utility_process_host.h
+++ b/content/browser/utility_process_host.h
@@ -39,6 +39,12 @@
 class Thread;
 }  // namespace base
 
+#if BUILDFLAG(IS_LINUX)
+namespace viz {
+class GpuClient;
+}  // namespace viz
+#endif
+
 namespace content {
 class BrowserChildProcessHostImpl;
 class InProcessChildThreadParams;
@@ -204,6 +210,10 @@
   std::vector<RunServiceDeprecatedCallback> pending_run_service_callbacks_;
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+  std::unique_ptr<viz::GpuClient, base::OnTaskRunnerDeleter> gpu_client_;
+#endif
+
   std::unique_ptr<Client> client_;
 
   // Used to vend weak pointers, and should always be declared last.
diff --git a/content/browser/utility_process_host_receiver_bindings.cc b/content/browser/utility_process_host_receiver_bindings.cc
index 99feb3b..1094096 100644
--- a/content/browser/utility_process_host_receiver_bindings.cc
+++ b/content/browser/utility_process_host_receiver_bindings.cc
@@ -15,6 +15,11 @@
 #include "content/browser/font_service.h"  // nogncheck
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+#include "components/viz/host/gpu_client.h"
+#include "content/public/browser/gpu_client.h"
+#endif
+
 namespace content {
 
 void UtilityProcessHost::BindHostReceiver(
@@ -25,6 +30,13 @@
     return;
   }
 #endif
+#if BUILDFLAG(IS_LINUX)
+  if (auto gpu_receiver = receiver.As<viz::mojom::Gpu>()) {
+    gpu_client_ =
+        content::CreateGpuClient(std::move(gpu_receiver), base::DoNothing());
+    return;
+  }
+#endif
   GetContentClient()->browser()->BindUtilityHostReceiver(std::move(receiver));
 }
 
diff --git a/content/browser/utility_sandbox_delegate_win.cc b/content/browser/utility_sandbox_delegate_win.cc
index b3f4cc48..2f69073 100644
--- a/content/browser/utility_sandbox_delegate_win.cc
+++ b/content/browser/utility_sandbox_delegate_win.cc
@@ -32,7 +32,7 @@
 //
 //  integrity_level_(sandbox::INTEGRITY_LEVEL_LOW),
 //  delayed_integrity_level_(sandbox::INTEGRITY_LEVEL_UNTRUSTED),
-bool AudioPreSpawnTarget(sandbox::TargetConfig* config) {
+bool AudioInitializeConfig(sandbox::TargetConfig* config) {
   // Audio process privilege requirements:
   //  - Lockdown level of USER_NON_ADMIN
   //  - Delayed integrity level of INTEGRITY_LEVEL_LOW
@@ -79,7 +79,7 @@
 }
 
 // Sets the sandbox policy for the network service process.
-bool NetworkPreSpawnTarget(sandbox::TargetConfig* config) {
+bool NetworkInitializeConfig(sandbox::TargetConfig* config) {
   DCHECK(!config->IsConfigured());
   // LPAC sandbox is enabled, so do not use a restricted token.
   auto result = config->SetTokenLevel(sandbox::USER_UNPROTECTED,
@@ -113,7 +113,7 @@
 
 #if BUILDFLAG(ENABLE_OOP_PRINTING)
 // Sets the sandbox policy for the print backend service process.
-bool PrintBackendPreSpawnTarget(sandbox::TargetConfig* config) {
+bool PrintBackendInitializeConfig(sandbox::TargetConfig* config) {
   DCHECK(!config->IsConfigured());
   // Print Backend policy lockdown level must be at least USER_LIMITED and
   // delayed integrity level INTEGRITY_LEVEL_LOW, otherwise ::OpenPrinter()
@@ -131,7 +131,7 @@
   return base::WideToUTF8(cmd_line.GetProgram().value());
 }
 
-bool IconReaderPreSpawnTarget(sandbox::TargetConfig* config) {
+bool IconReaderInitializeConfig(sandbox::TargetConfig* config) {
   DCHECK(!config->IsConfigured());
 
   auto result = config->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
@@ -170,9 +170,9 @@
   return true;
 }
 
-bool XrCompositingPreSpawnTarget(sandbox::TargetConfig* config,
-                                 base::CommandLine& cmd_line,
-                                 sandbox::mojom::Sandbox sandbox_type) {
+bool XrCompositingInitializeConfig(sandbox::TargetConfig* config,
+                                   base::CommandLine& cmd_line,
+                                   sandbox::mojom::Sandbox sandbox_type) {
   DCHECK(!config->IsConfigured());
   // TODO(https://crbug.com/881919): Try to harden the XR Compositor
   // sandbox to use mitigations and restrict the token.
@@ -208,8 +208,8 @@
 }
 
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
-bool ScreenAIPreSpawnTarget(sandbox::TargetConfig* config,
-                            sandbox::mojom::Sandbox sandbox_type) {
+bool ScreenAIInitializeConfig(sandbox::TargetConfig* config,
+                              sandbox::mojom::Sandbox sandbox_type) {
   DCHECK(!config->IsConfigured());
 
   auto result = config->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
@@ -291,30 +291,30 @@
     sandbox::TargetConfig* config) {
   DCHECK(!config->IsConfigured());
   if (sandbox_type_ == sandbox::mojom::Sandbox::kAudio) {
-    if (!AudioPreSpawnTarget(config)) {
+    if (!AudioInitializeConfig(config)) {
       return false;
     }
   }
   if (sandbox_type_ == sandbox::mojom::Sandbox::kNetwork) {
-    if (!NetworkPreSpawnTarget(config)) {
+    if (!NetworkInitializeConfig(config)) {
       return false;
     }
   }
   if (sandbox_type_ == sandbox::mojom::Sandbox::kIconReader) {
-    if (!IconReaderPreSpawnTarget(config)) {
+    if (!IconReaderInitializeConfig(config)) {
       return false;
     }
   }
 
   if (sandbox_type_ == sandbox::mojom::Sandbox::kXrCompositing) {
-    if (!XrCompositingPreSpawnTarget(config, cmd_line_, sandbox_type_)) {
+    if (!XrCompositingInitializeConfig(config, cmd_line_, sandbox_type_)) {
       return false;
     }
   }
 
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
   if (sandbox_type_ == sandbox::mojom::Sandbox::kScreenAI) {
-    if (!ScreenAIPreSpawnTarget(config, sandbox_type_)) {
+    if (!ScreenAIInitializeConfig(config, sandbox_type_)) {
       return false;
     }
   }
@@ -362,7 +362,7 @@
   }
 #if BUILDFLAG(ENABLE_OOP_PRINTING)
   if (sandbox_type_ == sandbox::mojom::Sandbox::kPrintBackend) {
-    if (!PrintBackendPreSpawnTarget(config)) {
+    if (!PrintBackendInitializeConfig(config)) {
       return false;
     }
   }
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index 78531d44..6c6b515 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -280,10 +280,9 @@
 }
 
 void FilterAccountsWithLoginHint(
-    const blink::mojom::IdentityProviderLoginHintPtr& login_hint,
+    const std::string& login_hint,
     IdpNetworkRequestManager::AccountList& accounts) {
-  // Do not filter if both email and id are empty.
-  if (login_hint->email.empty() && login_hint->id.empty()) {
+  if (login_hint.empty()) {
     return;
   }
 
@@ -292,26 +291,11 @@
   // account afterwards, in which case the multiple account chooser would be
   // shown.
   auto Filter = [&login_hint](const IdentityRequestAccount& account) {
-    if (!login_hint->email.empty() && !login_hint->id.empty()) {
-      return account.id != login_hint->id && account.email != login_hint->email;
-    } else if (!login_hint->email.empty()) {
-      return account.email != login_hint->email;
-    } else {
-      return account.id != login_hint->id;
-    }
+    return std::find(account.hints.begin(), account.hints.end(), login_hint) ==
+           account.hints.end();
   };
-  bool should_filter = true;
-  if (!login_hint->is_required) {
-    // If |is_required| is false, do not use the filter if all elements would be
-    // removed.
-    size_t num_filtered_out =
-        std::count_if(accounts.begin(), accounts.end(), Filter);
-    should_filter = num_filtered_out != accounts.size();
-  }
-  if (should_filter) {
-    accounts.erase(std::remove_if(accounts.begin(), accounts.end(), Filter),
-                   accounts.end());
-  }
+  accounts.erase(std::remove_if(accounts.begin(), accounts.end(), Filter),
+                 accounts.end());
 }
 
 std::unique_ptr<FedCmMetrics> CreateFedCmMetrics(
diff --git a/content/browser/webid/federated_auth_request_impl_multiple_frames_unittest.cc b/content/browser/webid/federated_auth_request_impl_multiple_frames_unittest.cc
index 6a0da3ae..3cb2385 100644
--- a/content/browser/webid/federated_auth_request_impl_multiple_frames_unittest.cc
+++ b/content/browser/webid/federated_auth_request_impl_multiple_frames_unittest.cc
@@ -64,11 +64,12 @@
 constexpr char kToken[] = "[not a real token]";
 
 static const std::initializer_list<IdentityRequestAccount> kAccounts{{
-    kAccountId,         // id
-    "ken@idp.example",  // email
-    "Ken R. Example",   // name
-    "Ken",              // given_name
-    GURL()              // picture
+    kAccountId,                 // id
+    "ken@idp.example",          // email
+    "Ken R. Example",           // name
+    "Ken",                      // given_name
+    GURL(),                     // picture
+    std::vector<std::string>()  // hints
 }};
 
 // IdpNetworkRequestManager which returns valid data from IdP.
@@ -237,14 +238,10 @@
   void DoRequestToken(
       mojo::Remote<blink::mojom::FederatedAuthRequest>& request_remote,
       RequestTokenCallback callback) {
-    blink::mojom::IdentityProviderLoginHintPtr login_hint_ptr =
-        blink::mojom::IdentityProviderLoginHint::New(/*email=*/"", /*id=*/"",
-                                                     /*login_hint=*/false);
     auto config_ptr = blink::mojom::IdentityProviderConfig::New();
     config_ptr->config_url = GURL(kProviderUrlFull);
     config_ptr->client_id = kClientId;
     config_ptr->nonce = kNonce;
-    config_ptr->login_hint = std::move(login_hint_ptr);
     std::vector<blink::mojom::IdentityProviderPtr> idp_ptrs;
     blink::mojom::IdentityProviderPtr idp_ptr =
         blink::mojom::IdentityProvider::NewFederated(std::move(config_ptr));
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc
index 48aa453..fa2540e 100644
--- a/content/browser/webid/federated_auth_request_impl_unittest.cc
+++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -88,6 +88,9 @@
 constexpr char kTermsOfServiceUrl[] = "https://rp.example/tos";
 constexpr char kClientId[] = "client_id_123";
 constexpr char kNonce[] = "nonce123";
+constexpr char kAccountEmailNicolas[] = "nicolas@email.com";
+constexpr char kAccountEmailPeter[] = "peter@email.com";
+constexpr char kAccountEmailZach[] = "zach@email.com";
 constexpr char kAccountId[] = "1234";
 constexpr char kAccountIdNicolas[] = "nico_id";
 constexpr char kAccountIdPeter[] = "peter_id";
@@ -98,53 +101,91 @@
 constexpr char kToken[] = "[not a real token]";
 constexpr char kEmptyToken[] = "";
 
-static const std::initializer_list<IdentityRequestAccount> kAccounts{{
-    kAccountId,        // id
-    kEmail,            // email
-    "Ken R. Example",  // name
-    "Ken",             // given_name
-    GURL()             // picture
+static const std::initializer_list<IdentityRequestAccount> kSingleAccount{{
+    kAccountId,                 // id
+    kEmail,                     // email
+    "Ken R. Example",           // name
+    "Ken",                      // given_name
+    GURL(),                     // picture
+    std::vector<std::string>()  // hints
 }};
 
+static const std::initializer_list<IdentityRequestAccount>
+    kSingleAccountWithHint{{
+        kAccountId,           // id
+        kEmail,               // email
+        "Ken R. Example",     // name
+        "Ken",                // given_name
+        GURL(),               // picture
+        {kAccountId, kEmail}  // hints
+    }};
+
 static const std::initializer_list<IdentityRequestAccount> kMultipleAccounts{
     {
-        kAccountIdNicolas,    // id
-        "nicolas@email.com",  // email
-        "Nicolas P",          // name
-        "Nicolas",            // given_name
-        GURL(),               // picture
-        LoginState::kSignUp   // login_state
+        kAccountIdNicolas,           // id
+        kAccountEmailNicolas,        // email
+        "Nicolas P",                 // name
+        "Nicolas",                   // given_name
+        GURL(),                      // picture
+        std::vector<std::string>(),  // hints
+        LoginState::kSignUp          // login_state
     },
     {
-        kAccountIdPeter,     // id
-        "peter@email.com",   // email
-        "Peter K",           // name
-        "Peter",             // given_name
-        GURL(),              // picture
-        LoginState::kSignIn  // login_state
+        kAccountIdPeter,             // id
+        kAccountEmailPeter,          // email
+        "Peter K",                   // name
+        "Peter",                     // given_name
+        GURL(),                      // picture
+        std::vector<std::string>(),  // hints
+        LoginState::kSignIn          // login_state
     },
     {
-        kAccountIdZach,      // id
-        "zach@email.com",    // email
-        "Zachary T",         // name
-        "Zach",              // given_name
-        GURL(),              // picture
-        LoginState::kSignUp  // login_state
+        kAccountIdZach,              // id
+        "zach@email.com",            // email
+        "Zachary T",                 // name
+        "Zach",                      // given_name
+        GURL(),                      // picture
+        std::vector<std::string>(),  // hints
+        LoginState::kSignUp          // login_state
     }};
 
-static const std::set<std::string> kWellKnown{kProviderUrlFull};
+static const std::initializer_list<IdentityRequestAccount>
+    kMultipleAccountsWithHints{
+        {
+            kAccountIdNicolas,                          // id
+            kAccountEmailNicolas,                       // email
+            "Nicolas P",                                // name
+            "Nicolas",                                  // given_name
+            GURL(),                                     // picture
+            {kAccountIdNicolas, kAccountEmailNicolas},  // hints
+            LoginState::kSignUp                         // login_state
+        },
+        {
+            kAccountIdPeter,                        // id
+            kAccountEmailPeter,                     // email
+            "Peter K",                              // name
+            "Peter",                                // given_name
+            GURL(),                                 // picture
+            {kAccountIdPeter, kAccountEmailPeter},  // hints
+            LoginState::kSignIn                     // login_state
+        },
+        {
+            kAccountIdZach,                       // id
+            kAccountEmailZach,                    // email
+            "Zachary T",                          // name
+            "Zach",                               // given_name
+            GURL(),                               // picture
+            {kAccountIdZach, kAccountEmailZach},  // hints
+            LoginState::kSignUp                   // login_state
+        }};
 
-struct LoginHint {
-  const char* email = "";
-  const char* id = "";
-  bool is_required = false;
-};
+static const std::set<std::string> kWellKnown{kProviderUrlFull};
 
 struct IdentityProviderParameters {
   const char* provider;
   const char* client_id;
   const char* nonce;
-  LoginHint login_hint;
+  const char* login_hint;
 };
 
 // Parameters for a call to RequestToken.
@@ -229,7 +270,7 @@
     kTermsOfServiceUrl};
 
 static const IdentityProviderParameters kDefaultIdentityProviderConfig{
-    kProviderUrlFull, kClientId, kNonce};
+    kProviderUrlFull, kClientId, kNonce, /*login_hint=*/""};
 
 static const RequestParameters kDefaultRequestParameters{
     std::vector<IdentityProviderParameters>{kDefaultIdentityProviderConfig},
@@ -246,7 +287,7 @@
     },
     kDefaultClientMetadata,
     {ParseStatus::kSuccess, net::HTTP_OK},
-    kAccounts,
+    kSingleAccount,
 };
 
 static const base::flat_map<std::string, MockIdpInfo> kSingleProviderInfo{
@@ -281,8 +322,8 @@
 
 static const RequestParameters kDefaultMultiIdpRequestParameters{
     std::vector<IdentityProviderParameters>{
-        {kProviderUrlFull, kClientId, kNonce},
-        {kProviderTwoUrlFull, kClientId, kNonce}},
+        {kProviderUrlFull, kClientId, kNonce, /*login_hint=*/""},
+        {kProviderTwoUrlFull, kClientId, kNonce, /*login_hint=*/""}},
     /*auto_reauthn=*/false,
     /*rp_context=*/blink::mojom::RpContext::kSignIn};
 
@@ -729,17 +770,12 @@
     for (const auto& identity_provider :
          request_parameters.identity_providers) {
       std::vector<blink::mojom::IdentityProviderPtr> idp_ptrs;
-      blink::mojom::IdentityProviderLoginHintPtr login_hint_ptr =
-          blink::mojom::IdentityProviderLoginHint::New(
-              identity_provider.login_hint.email,
-              identity_provider.login_hint.id,
-              identity_provider.login_hint.is_required);
       blink::mojom::IdentityProviderConfigPtr config =
           blink::mojom::IdentityProviderConfig::New();
       config->config_url = GURL(identity_provider.provider);
       config->client_id = identity_provider.client_id;
       config->nonce = identity_provider.nonce;
-      config->login_hint = std::move(login_hint_ptr);
+      config->login_hint = identity_provider.login_hint;
       blink::mojom::IdentityProviderPtr idp_ptr =
           blink::mojom::IdentityProvider::NewFederated(std::move(config));
       idp_ptrs.push_back(std::move(idp_ptr));
@@ -1082,7 +1118,7 @@
 
   void ComputeLoginStateAndReorderAccounts(
       const blink::mojom::IdentityProviderConfigPtr& identity_provider,
-      IdpNetworkRequestManager::AccountList& accounts) {
+      AccountList& accounts) {
     federated_auth_request_impl_->ComputeLoginStateAndReorderAccounts(
         identity_provider, accounts);
   }
@@ -1249,8 +1285,8 @@
 
 // Test that request fails if the idp is not https.
 TEST_F(FederatedAuthRequestImplTest, ProviderNotTrustworthy) {
-  IdentityProviderParameters identity_provider{"http://idp.example/fedcm.json",
-                                               kClientId, kNonce};
+  IdentityProviderParameters identity_provider{
+      "http://idp.example/fedcm.json", kClientId, kNonce, /*login_hint=*/""};
   RequestParameters request{
       std::vector<IdentityProviderParameters>{identity_provider},
       /*auto_reauthn=*/false,
@@ -2081,7 +2117,7 @@
   // Set IDP claims user is signed in.
   MockConfiguration configuration = kConfigurationValid;
   AccountList displayed_accounts =
-      AccountList(kAccounts.begin(), kAccounts.end());
+      AccountList(kSingleAccount.begin(), kSingleAccount.end());
   displayed_accounts[0].login_state = LoginState::kSignIn;
   configuration.idp_info[kProviderUrlFull].accounts = displayed_accounts;
   RunAuthTest(kDefaultRequestParameters, kExpectationSuccess, configuration);
@@ -2138,7 +2174,7 @@
   // Set IDP claims user is signed in.
   MockConfiguration configuration = kConfigurationValid;
   AccountList displayed_accounts =
-      AccountList(kAccounts.begin(), kAccounts.end());
+      AccountList(kSingleAccount.begin(), kSingleAccount.end());
   displayed_accounts[0].login_state = LoginState::kSignIn;
   configuration.idp_info[kProviderUrlFull].accounts = displayed_accounts;
   RunAuthTest(kDefaultRequestParameters, kExpectationSuccess, configuration);
@@ -2505,15 +2541,11 @@
               kConfigurationValid);
 
   AccountList multiple_accounts = kMultipleAccounts;
-  blink::mojom::IdentityProviderLoginHintPtr login_hint_ptr =
-      blink::mojom::IdentityProviderLoginHint::New(/*email=*/"", /*id=*/"",
-                                                   /*login_hint=*/false);
   blink::mojom::IdentityProviderConfigPtr identity_provider =
       blink::mojom::IdentityProviderConfig::New();
   identity_provider->config_url = GURL(kProviderUrlFull);
   identity_provider->client_id = kClientId;
   identity_provider->nonce = kNonce;
-  identity_provider->login_hint = std::move(login_hint_ptr);
 
   ComputeLoginStateAndReorderAccounts(identity_provider, multiple_accounts);
 
@@ -3293,15 +3325,34 @@
               ElementsAre(kMetricsEndpoint, "https://idp2.example/metrics"));
 }
 
+TEST_F(FederatedAuthRequestImplTest, LoginHintDisabled) {
+  base::test::ScopedFeatureList list;
+  list.InitAndDisableFeature(features::kFedCmLoginHint);
+
+  RequestParameters parameters = kDefaultRequestParameters;
+  parameters.identity_providers[0].login_hint = "incorrect_login_hint";
+
+  MockConfiguration configuration = kConfigurationValid;
+  configuration.idp_info[kProviderUrlFull].accounts = kSingleAccountWithHint;
+
+  // The login hint should be disregarded when the flag is disabled. Therefore,
+  // the account should be shown.
+  RunAuthTest(parameters, kExpectationSuccess, configuration);
+  ASSERT_EQ(displayed_accounts().size(), 1u);
+}
+
 TEST_F(FederatedAuthRequestImplTest, LoginHintSingleAccountIdMatch) {
   base::test::ScopedFeatureList list;
   list.InitAndEnableFeature(features::kFedCmLoginHint);
 
   RequestParameters parameters = kDefaultRequestParameters;
-  parameters.identity_providers[0].login_hint.id = kAccountId;
+  parameters.identity_providers[0].login_hint = kAccountId;
 
-  RunAuthTest(parameters, kExpectationSuccess, kConfigurationValid);
-  EXPECT_EQ(displayed_accounts().size(), 1u);
+  MockConfiguration configuration = kConfigurationValid;
+  configuration.idp_info[kProviderUrlFull].accounts = kSingleAccountWithHint;
+
+  RunAuthTest(parameters, kExpectationSuccess, configuration);
+  ASSERT_EQ(displayed_accounts().size(), 1u);
   EXPECT_EQ(displayed_accounts()[0].id, kAccountId);
 }
 
@@ -3310,38 +3361,31 @@
   list.InitAndEnableFeature(features::kFedCmLoginHint);
 
   RequestParameters parameters = kDefaultRequestParameters;
-  parameters.identity_providers[0].login_hint.email = kEmail;
+  parameters.identity_providers[0].login_hint = kEmail;
 
-  RunAuthTest(parameters, kExpectationSuccess, kConfigurationValid);
-  EXPECT_EQ(displayed_accounts().size(), 1u);
+  MockConfiguration configuration = kConfigurationValid;
+  configuration.idp_info[kProviderUrlFull].accounts = kSingleAccountWithHint;
+
+  RunAuthTest(parameters, kExpectationSuccess, configuration);
+  ASSERT_EQ(displayed_accounts().size(), 1u);
   EXPECT_EQ(displayed_accounts()[0].email, kEmail);
 }
 
-TEST_F(FederatedAuthRequestImplTest, LoginHintSingleAccountNoMatchNotRequired) {
+TEST_F(FederatedAuthRequestImplTest, LoginHintSingleAccountNoMatch) {
   base::test::ScopedFeatureList list;
   list.InitAndEnableFeature(features::kFedCmLoginHint);
 
   RequestParameters parameters = kDefaultRequestParameters;
-  parameters.identity_providers[0].login_hint.id = "incorrect_login_hint";
-
-  RunAuthTest(parameters, kExpectationSuccess, kConfigurationValid);
-  EXPECT_TRUE(DidFetch(FetchedEndpoint::ACCOUNTS));
-  EXPECT_TRUE(did_show_accounts_dialog());
-}
-
-TEST_F(FederatedAuthRequestImplTest, LoginHintSingleAccountNoMatchRequired) {
-  base::test::ScopedFeatureList list;
-  list.InitAndEnableFeature(features::kFedCmLoginHint);
-
-  RequestParameters parameters = kDefaultRequestParameters;
-  parameters.identity_providers[0].login_hint.id = "incorrect_login_hint";
-  parameters.identity_providers[0].login_hint.is_required = true;
+  parameters.identity_providers[0].login_hint = "incorrect_login_hint";
   const RequestExpectations expectations = {
       RequestTokenStatus::kError,
       {FederatedAuthRequestResult::kErrorFetchingAccountsListEmpty},
       /*selected_idp_config_url=*/absl::nullopt};
 
-  RunAuthTest(parameters, expectations, kConfigurationValid);
+  MockConfiguration configuration = kConfigurationValid;
+  configuration.idp_info[kProviderUrlFull].accounts = kSingleAccountWithHint;
+
+  RunAuthTest(parameters, expectations, configuration);
   EXPECT_TRUE(DidFetch(FetchedEndpoint::ACCOUNTS));
   EXPECT_FALSE(did_show_accounts_dialog());
 }
@@ -3351,12 +3395,14 @@
   list.InitAndEnableFeature(features::kFedCmLoginHint);
 
   RequestParameters parameters = kDefaultRequestParameters;
-  parameters.identity_providers[0].login_hint.id = kAccountIdNicolas;
+  parameters.identity_providers[0].login_hint = kAccountIdNicolas;
+
   MockConfiguration configuration = kConfigurationValid;
-  configuration.idp_info[kProviderUrlFull].accounts = kMultipleAccounts;
+  configuration.idp_info[kProviderUrlFull].accounts =
+      kMultipleAccountsWithHints;
 
   RunAuthTest(parameters, kExpectationSuccess, configuration);
-  EXPECT_EQ(displayed_accounts().size(), 1u);
+  ASSERT_EQ(displayed_accounts().size(), 1u);
   EXPECT_EQ(displayed_accounts()[0].id, kAccountIdNicolas);
 }
 
@@ -3365,44 +3411,31 @@
   list.InitAndEnableFeature(features::kFedCmLoginHint);
 
   RequestParameters parameters = kDefaultRequestParameters;
-  parameters.identity_providers[0].login_hint.id = kAccountIdZach;
+  parameters.identity_providers[0].login_hint = kAccountIdZach;
+
   MockConfiguration configuration = kConfigurationValid;
-  configuration.idp_info[kProviderUrlFull].accounts = kMultipleAccounts;
+  configuration.idp_info[kProviderUrlFull].accounts =
+      kMultipleAccountsWithHints;
 
   RunAuthTest(parameters, kExpectationSuccess, configuration);
-  EXPECT_EQ(displayed_accounts().size(), 1u);
+  ASSERT_EQ(displayed_accounts().size(), 1u);
   EXPECT_EQ(displayed_accounts()[0].id, kAccountIdZach);
 }
 
-TEST_F(FederatedAuthRequestImplTest,
-       LoginHintMultipleAccountsNoMatchNotRequired) {
+TEST_F(FederatedAuthRequestImplTest, LoginHintMultipleAccountsNoMatch) {
   base::test::ScopedFeatureList list;
   list.InitAndEnableFeature(features::kFedCmLoginHint);
 
   RequestParameters parameters = kDefaultRequestParameters;
-  parameters.identity_providers[0].login_hint.email = "incorrect_login_hint";
-  MockConfiguration configuration = kConfigurationValid;
-  configuration.idp_info[kProviderUrlFull].accounts = kMultipleAccounts;
-
-  RunAuthTest(parameters, kExpectationSuccess, configuration);
-  EXPECT_TRUE(DidFetch(FetchedEndpoint::ACCOUNTS));
-  EXPECT_TRUE(did_show_accounts_dialog());
-  EXPECT_EQ(displayed_accounts().size(), 3u);
-}
-
-TEST_F(FederatedAuthRequestImplTest, LoginHintMultipleAccountsNoMatchRequired) {
-  base::test::ScopedFeatureList list;
-  list.InitAndEnableFeature(features::kFedCmLoginHint);
-
-  RequestParameters parameters = kDefaultRequestParameters;
-  parameters.identity_providers[0].login_hint.email = "incorrect_login_hint";
-  parameters.identity_providers[0].login_hint.is_required = true;
+  parameters.identity_providers[0].login_hint = "incorrect_login_hint";
   const RequestExpectations expectations = {
       RequestTokenStatus::kError,
       {FederatedAuthRequestResult::kErrorFetchingAccountsListEmpty},
       /*selected_idp_config_url=*/absl::nullopt};
+
   MockConfiguration configuration = kConfigurationValid;
-  configuration.idp_info[kProviderUrlFull].accounts = kMultipleAccounts;
+  configuration.idp_info[kProviderUrlFull].accounts =
+      kMultipleAccountsWithHints;
 
   RunAuthTest(parameters, expectations, configuration);
   EXPECT_TRUE(DidFetch(FetchedEndpoint::ACCOUNTS));
diff --git a/content/browser/webid/federated_auth_user_info_request_unittest.cc b/content/browser/webid/federated_auth_user_info_request_unittest.cc
index 9338ad9..8cbbfb1 100644
--- a/content/browser/webid/federated_auth_user_info_request_unittest.cc
+++ b/content/browser/webid/federated_auth_user_info_request_unittest.cc
@@ -162,10 +162,10 @@
 
     std::vector<IdentityRequestAccount> accounts;
     for (const AccountConfig& account_config : config_.accounts) {
-      accounts.emplace_back(account_config.id,
-                            GenerateEmailForUserId(account_config.id),
-                            kAccountName, kAccountGivenName,
-                            GURL(kAccountPicture), account_config.login_state);
+      accounts.emplace_back(
+          account_config.id, GenerateEmailForUserId(account_config.id),
+          kAccountName, kAccountGivenName, GURL(kAccountPicture),
+          std::vector<std::string>(), account_config.login_state);
     }
 
     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
diff --git a/content/browser/webid/idp_network_request_manager.cc b/content/browser/webid/idp_network_request_manager.cc
index 3fad1f89..0090b211 100644
--- a/content/browser/webid/idp_network_request_manager.cc
+++ b/content/browser/webid/idp_network_request_manager.cc
@@ -12,6 +12,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/webid/fedcm_metrics.h"
+#include "content/browser/webid/flags.h"
 #include "content/public/browser/identity_request_dialog_controller.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/storage_partition.h"
@@ -80,6 +81,7 @@
 constexpr char kAccountGivenNameKey[] = "given_name";
 constexpr char kAccountPictureKey[] = "picture";
 constexpr char kAccountApprovedClientsKey[] = "approved_clients";
+constexpr char kHintsKey[] = "hints";
 
 // Keys in 'branding' 'icons' dictionary in accounts endpoint.
 constexpr char kIdpBrandingIconUrl[] = "url";
@@ -149,6 +151,17 @@
   auto* given_name = account.FindString(kAccountGivenNameKey);
   auto* picture = account.FindString(kAccountPictureKey);
   auto* approved_clients = account.FindList(kAccountApprovedClientsKey);
+  std::vector<std::string> account_hints;
+  if (IsFedCmLoginHintEnabled()) {
+    auto* hints = account.FindList(kHintsKey);
+    if (hints) {
+      for (const base::Value& entry : *hints) {
+        if (entry.is_string()) {
+          account_hints.emplace_back(entry.GetString());
+        }
+      }
+    }
+  }
 
   // required fields
   if (!(id && email && name))
@@ -175,7 +188,8 @@
 
   return content::IdentityRequestAccount(
       *id, *email, *name, given_name ? *given_name : "",
-      picture ? GURL(*picture) : GURL(), approved_value);
+      picture ? GURL(*picture) : GURL(), std::move(account_hints),
+      approved_value);
 }
 
 // Parses accounts from given Value. Returns true if parse is successful and
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom
index 856cfaa..58c441d 100644
--- a/content/common/renderer.mojom
+++ b/content/common/renderer.mojom
@@ -180,17 +180,15 @@
   // |cors_exempt_header_list| sets the CORS exempt header list for sanity
   // checking (e.g. DCHECKs).
   //
-  // |attribution_os_support| sets the OS-level support for Attribution
-  // Reporting.
+  // |attribution_support| sets whether web or OS-level Attribution Reporting is supported.
   InitializeRenderer(string user_agent,
                      string full_user_agent,
                      string reduced_user_agent,
                      blink.mojom.UserAgentMetadata metadata,
                      array<string> cors_exempt_header_list,
-                     network.mojom.AttributionOsSupport attribution_os_support);
+                     network.mojom.AttributionSupport attribution_support);
 
-  // Set the OS-level support for Attribution Reporting indicating whether
-  // OS-level attribution is enabled.
+ // Set whether web or OS-level Attribution Reporting is supported.
   [EnableIf=is_android]
-  SetOsSupportForAttributionReporting(network.mojom.AttributionOsSupport os_support);
+  SetAttributionReportingSupport(network.mojom.AttributionSupport attribution_support);
 };
diff --git a/content/common/skia_utils.cc b/content/common/skia_utils.cc
index ebc1399..8a42c384 100644
--- a/content/common/skia_utils.cc
+++ b/content/common/skia_utils.cc
@@ -44,7 +44,8 @@
   const int kMB = 1024 * 1024;
   size_t font_cache_limit;
 #if BUILDFLAG(IS_ANDROID)
-  font_cache_limit = base::SysInfo::IsLowEndDevice() ? kMB : 8 * kMB;
+  font_cache_limit =
+      base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled() ? kMB : 8 * kMB;
   SkGraphics::SetFontCacheLimit(font_cache_limit);
 #else
   if (cmd.HasSwitch(switches::kSkiaFontCacheLimitMb)) {
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 6cb63ff..7d98052 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -17,6 +17,7 @@
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
 #include "content/browser/webid/mdocs/mdoc_provider.h"
 #include "content/public/browser/anchor_element_preconnect_delegate.h"
@@ -516,6 +517,12 @@
   return true;
 }
 
+#if BUILDFLAG(IS_ANDROID)
+bool ContentBrowserClient::IsWebAttributionReportingAllowed() {
+  return true;
+}
+#endif
+
 bool ContentBrowserClient::IsSharedStorageAllowed(
     content::BrowserContext* browser_context,
     content::RenderFrameHost* rfh,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index a60f331..b127b96 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -22,6 +22,7 @@
 #include "base/types/strong_alias.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
 #include "components/browsing_topics/common/common_types.h"
 #include "components/download/public/common/quarantine_connection.h"
@@ -892,6 +893,12 @@
       const url::Origin* destination_origin,
       const url::Origin* reporting_origin);
 
+#if BUILDFLAG(IS_ANDROID)
+  // Allows the embedder to control if web attribution reporting is allowed.
+  // This method must be idempotent.
+  virtual bool IsWebAttributionReportingAllowed();
+#endif
+
   // Allows the embedder to control if Shared Storage API operations can happen
   // in a given context.
   //
diff --git a/content/public/browser/identity_request_account.cc b/content/public/browser/identity_request_account.cc
index 4b6b765c..a53ede5e 100644
--- a/content/public/browser/identity_request_account.cc
+++ b/content/public/browser/identity_request_account.cc
@@ -12,12 +12,14 @@
     const std::string& name,
     const std::string& given_name,
     const GURL& picture,
+    std::vector<std::string> hints,
     absl::optional<LoginState> login_state)
     : id{id},
       email{email},
       name{name},
       given_name{given_name},
       picture{picture},
+      hints(std::move(hints)),
       login_state{login_state} {}
 
 IdentityRequestAccount::IdentityRequestAccount(const IdentityRequestAccount&) =
diff --git a/content/public/browser/identity_request_account.h b/content/public/browser/identity_request_account.h
index 001023df..4f24406 100644
--- a/content/public/browser/identity_request_account.h
+++ b/content/public/browser/identity_request_account.h
@@ -46,6 +46,7 @@
       const std::string& name,
       const std::string& given_name,
       const GURL& picture,
+      std::vector<std::string> hints,
       absl::optional<LoginState> login_state = absl::nullopt);
   IdentityRequestAccount(const IdentityRequestAccount&);
   ~IdentityRequestAccount();
@@ -55,6 +56,7 @@
   std::string name;
   std::string given_name;
   GURL picture;
+  std::vector<std::string> hints;
 
   // The account login state. Unlike the other fields this one can be populated
   // either by the IDP or by the browser based on its stored permission grants.
diff --git a/content/public/browser/presentation_service_delegate.h b/content/public/browser/presentation_service_delegate.h
index c9e428a..d4cf1123 100644
--- a/content/public/browser/presentation_service_delegate.h
+++ b/content/public/browser/presentation_service_delegate.h
@@ -49,9 +49,7 @@
     base::RepeatingCallback<void(const PresentationConnectionStateChangeInfo&)>;
 
 using ReceiverConnectionAvailableCallback = base::RepeatingCallback<void(
-    blink::mojom::PresentationInfoPtr,
-    mojo::PendingRemote<blink::mojom::PresentationConnection>,
-    mojo::PendingReceiver<blink::mojom::PresentationConnection>)>;
+    blink::mojom::PresentationConnectionResultPtr)>;
 
 // Base class for ControllerPresentationServiceDelegate and
 // ReceiverPresentationServiceDelegate.
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 72a1a6b..909d66d 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -701,11 +701,12 @@
 #endif
 
 #if BUILDFLAG(IS_ANDROID)
-  // Sets whether OS-level support is enabled for Attribution Reporting API.
-  // See
+  // Sets whether web or OS-level Attribution Reporting is supported. This may
+  // be called if the renderer process was created before the Measurement API
+  // state is returned from the underlying platform. See
   // https://github.com/WICG/attribution-reporting-api/blob/main/app_to_web.md.
-  virtual void SetOsSupportForAttributionReporting(
-      network::mojom::AttributionOsSupport os_support) = 0;
+  virtual void SetAttributionReportingSupport(
+      network::mojom::AttributionSupport) = 0;
 #endif
 
   // Static management functions -----------------------------------------------
diff --git a/content/public/common/network_service_util.cc b/content/public/common/network_service_util.cc
index 0c8c108..d9f60d5e 100644
--- a/content/public/common/network_service_util.cc
+++ b/content/public/common/network_service_util.cc
@@ -22,9 +22,9 @@
              "NetworkServiceOutOfProcessMemoryThreshold",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Using 1077 rather than 1024 because 1) it helps ensure that devices with
+// Using 1077 rather than 1024 because it helps ensure that devices with
 // exactly 1GB of RAM won't get included because of inaccuracies or off-by-one
-// errors and 2) this is the bucket boundary in Memory.Stats.Win.TotalPhys2.
+// errors.
 constexpr base::FeatureParam<int> kNetworkServiceOutOfProcessThresholdMb{
     &kNetworkServiceOutOfProcessMemoryThreshold,
     "network_service_oop_threshold_mb", 1077};
diff --git a/content/public/renderer/render_thread.h b/content/public/renderer/render_thread.h
index 7225bee..07dd7790 100644
--- a/content/public/renderer/render_thread.h
+++ b/content/public/renderer/render_thread.h
@@ -113,11 +113,11 @@
       perfetto::TracedProto<perfetto::protos::pbzero::RenderProcessHost>
           proto) = 0;
 
-  // Returns whether OS-level support is enabled for Attribution Reporting API.
+  // Returns whether web or OS-level Attribution Reporting is supported.
   // See
   // https://github.com/WICG/attribution-reporting-api/blob/main/app_to_web.md.
-  virtual network::mojom::AttributionOsSupport
-  GetOsSupportForAttributionReporting() = 0;
+  virtual network::mojom::AttributionSupport
+  GetAttributionReportingSupport() = 0;
 
  private:
   const base::AutoReset<RenderThread*> resetter_;
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 231cc33..0aa7544 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -288,8 +288,8 @@
   void WriteIntoTrace(perfetto::TracedProto<TraceProto> proto) const override;
 
 #if BUILDFLAG(IS_ANDROID)
-  void SetOsSupportForAttributionReporting(
-      network::mojom::AttributionOsSupport os_support) override {}
+  void SetAttributionReportingSupport(
+      network::mojom::AttributionSupport) override {}
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index 28cdf11d..729e45fbb 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -327,9 +327,9 @@
   page_broadcasts_.clear();
 }
 
-network::mojom::AttributionOsSupport
-MockRenderThread::GetOsSupportForAttributionReporting() {
-  return network::mojom::AttributionOsSupport::kDisabled;
+network::mojom::AttributionSupport
+MockRenderThread::GetAttributionReportingSupport() {
+  return network::mojom::AttributionSupport::kWeb;
 }
 
 }  // namespace content
diff --git a/content/public/test/mock_render_thread.h b/content/public/test/mock_render_thread.h
index b026a20..42cac47f 100644
--- a/content/public/test/mock_render_thread.h
+++ b/content/public/test/mock_render_thread.h
@@ -93,8 +93,7 @@
   void WriteIntoTrace(
       perfetto::TracedProto<perfetto::protos::pbzero::RenderProcessHost> proto)
       override;
-  network::mojom::AttributionOsSupport GetOsSupportForAttributionReporting()
-      override;
+  network::mojom::AttributionSupport GetAttributionReportingSupport() override;
 
   // Returns a new, unique routing ID that can be assigned to the next view,
   // widget, or frame.
diff --git a/content/renderer/accessibility/aom_content_ax_tree.cc b/content/renderer/accessibility/aom_content_ax_tree.cc
index e04f300..ef9414a 100644
--- a/content/renderer/accessibility/aom_content_ax_tree.cc
+++ b/content/renderer/accessibility/aom_content_ax_tree.cc
@@ -131,7 +131,11 @@
   AXTreeSnapshotterImpl snapshotter(render_frame_, ui::kAXModeComplete);
   snapshotter.Snapshot(/* max_node_count= */ 0,
                        /* timeout= */ {}, &tree_update);
+  // Computed AOM trees/updates do not use a tree id.
+  DCHECK(tree_.data().tree_id == ui::AXTreeIDUnknown());
+  tree_update.tree_data.tree_id = ui::AXTreeIDUnknown();
   CHECK(tree_.Unserialize(tree_update)) << tree_.error();
+  DCHECK(tree_.data().tree_id == ui::AXTreeIDUnknown());
   return true;
 }
 
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index 68713cc..07e74afd 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -753,7 +753,6 @@
   weak_factory_for_serialization_pipeline_.InvalidateWeakPtrs();
 
   last_serialization_timestamp_ = now;
-  serialization_in_flight_ = true;
 
   SendPendingAccessibilityEvents();
 }
@@ -1226,7 +1225,13 @@
                "RenderAccessibilityImpl::SendPendingAccessibilityEvents");
   base::ElapsedTimer timer;
 
+  // If serialize_post_lifecycle_ is false, then this method is scheduled
+  // asynchronously and serialization_in_flight_ is set at the point of
+  // scheduling. If serialize_post_lifecycle_ is true, then this method is
+  // called synchronously, but should never be called if there's a previous
+  // serialization still in flight.
   DCHECK(!serialize_post_lifecycle_ || !serialization_in_flight_);
+  serialization_in_flight_ = true;
 
   if (!serialize_post_lifecycle_) {
     // Clear status here in case we return early.
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index 20d07fa7..bd96be9 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -44,7 +44,8 @@
   idle_cleanup_interval_ = base::Seconds(5);
   idle_timeout_ = base::Seconds(15);
 
-  is_low_end_ = base::SysInfo::IsLowEndDevice();
+  is_low_end_ = base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled();
+
   idle_cleanup_timer_.SetTaskRunner(
       render_frame->GetTaskRunner(blink::TaskType::kInternalMedia));
 }
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 03cdd5c..a614d8e 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -926,7 +926,7 @@
     const std::string& reduced_user_agent,
     const blink::UserAgentMetadata& user_agent_metadata,
     const std::vector<std::string>& cors_exempt_header_list,
-    network::mojom::AttributionOsSupport attribution_os_support) {
+    network::mojom::AttributionSupport attribution_support) {
   DCHECK(user_agent_.IsNull());
   DCHECK(reduced_user_agent_.IsNull());
   DCHECK(full_user_agent_.IsNull());
@@ -937,7 +937,7 @@
   reduced_user_agent_ = WebString::FromUTF8(reduced_user_agent);
   user_agent_metadata_ = user_agent_metadata;
   cors_exempt_header_list_ = cors_exempt_header_list;
-  attribution_os_support_ = attribution_os_support;
+  attribution_support_ = attribution_support;
 
   blink::WebVector<blink::WebString> web_cors_exempt_header_list(
       cors_exempt_header_list.size());
@@ -1830,15 +1830,15 @@
   return rendering_color_space_;
 }
 
-network::mojom::AttributionOsSupport
-RenderThreadImpl::GetOsSupportForAttributionReporting() {
-  return attribution_os_support_;
+network::mojom::AttributionSupport
+RenderThreadImpl::GetAttributionReportingSupport() {
+  return attribution_support_;
 }
 
 #if BUILDFLAG(IS_ANDROID)
-void RenderThreadImpl::SetOsSupportForAttributionReporting(
-    network::mojom::AttributionOsSupport attribution_os_support) {
-  attribution_os_support_ = attribution_os_support;
+void RenderThreadImpl::SetAttributionReportingSupport(
+    network::mojom::AttributionSupport attribution_support) {
+  attribution_support_ = attribution_support;
 }
 #endif
 
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 765068e4..3116dcc 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -187,8 +187,7 @@
   void WriteIntoTrace(
       perfetto::TracedProto<perfetto::protos::pbzero::RenderProcessHost> proto)
       override;
-  network::mojom::AttributionOsSupport GetOsSupportForAttributionReporting()
-      override;
+  network::mojom::AttributionSupport GetAttributionReportingSupport() override;
 
   // IPC::Listener implementation via ChildThreadImpl:
   void OnAssociatedInterfaceRequest(
@@ -434,7 +433,7 @@
       const std::string& reduced_user_agent,
       const blink::UserAgentMetadata& user_agent_metadata,
       const std::vector<std::string>& cors_exempt_header_list,
-      network::mojom::AttributionOsSupport attribution_os_support) override;
+      network::mojom::AttributionSupport) override;
   void UpdateScrollbarTheme(
       mojom::UpdateScrollbarThemeParamsPtr params) override;
   void OnSystemColorsChanged(int32_t aqua_color_variant) override;
@@ -451,8 +450,8 @@
   void SetIsCrossOriginIsolated(bool value) override;
   void SetIsIsolatedContext(bool value) override;
 #if BUILDFLAG(IS_ANDROID)
-  void SetOsSupportForAttributionReporting(
-      network::mojom::AttributionOsSupport os_support) override;
+  void SetAttributionReportingSupport(
+      network::mojom::AttributionSupport) override;
 #endif
   void OnMemoryPressure(
       base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
@@ -503,7 +502,7 @@
   blink::WebString reduced_user_agent_;
   blink::UserAgentMetadata user_agent_metadata_;
 
-  network::mojom::AttributionOsSupport attribution_os_support_;
+  network::mojom::AttributionSupport attribution_support_;
 
   // Sticky once true, indicates that compositing is done without Gpu, so
   // resources given to the compositor or to the viz service should be
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 5fed17b1..f84c233c 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -998,13 +998,13 @@
   return io_thread_id_;
 }
 
-network::mojom::AttributionOsSupport
-RendererBlinkPlatformImpl::GetOsSupportForAttributionReporting() {
+network::mojom::AttributionSupport
+RendererBlinkPlatformImpl::GetAttributionReportingSupport() {
   auto* render_thread = RenderThreadImpl::current();
   // RenderThreadImpl is null in some tests.
   if (!render_thread)
-    return network::mojom::AttributionOsSupport::kDisabled;
-  return render_thread->GetOsSupportForAttributionReporting();
+    return network::mojom::AttributionSupport::kWeb;
+  return render_thread->GetAttributionReportingSupport();
 }
 
 scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 3f99988..9c66a331 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -218,8 +218,7 @@
       const blink::WebURL& url,
       blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) override;
   base::PlatformThreadId GetIOThreadId() const override;
-  network::mojom::AttributionOsSupport GetOsSupportForAttributionReporting()
-      override;
+  network::mojom::AttributionSupport GetAttributionReportingSupport() override;
   scoped_refptr<base::SingleThreadTaskRunner> VideoFrameCompositorTaskRunner()
       override;
 #if BUILDFLAG(IS_ANDROID)
diff --git a/content/renderer/skia_benchmarking_extension_unittest.cc b/content/renderer/skia_benchmarking_extension_unittest.cc
index c9030e8..5ac35359 100644
--- a/content/renderer/skia_benchmarking_extension_unittest.cc
+++ b/content/renderer/skia_benchmarking_extension_unittest.cc
@@ -17,13 +17,13 @@
 testing::AssertionResult HasArg(const base::Value::List& args,
                                 const char name[]) {
   for (size_t i = 0; i < args.size(); ++i) {
-    const base::Value& arg = args[i];
-    if (!arg.is_dict() || arg.DictSize() != 1) {
+    const base::Value::Dict* arg = args[i].GetIfDict();
+    if (!arg || arg->size() != 1) {
       return testing::AssertionFailure() << " malformed argument for index "
                                          << i;
     }
 
-    if (arg.GetDict().contains(name)) {
+    if (arg->contains(name)) {
       return testing::AssertionSuccess() << " argument '" << name
                                          << "' found at index " << i;
     }
diff --git a/content/renderer/v8_value_converter_impl_unittest.cc b/content/renderer/v8_value_converter_impl_unittest.cc
index 46287e8e..ad3b0256 100644
--- a/content/renderer/v8_value_converter_impl_unittest.cc
+++ b/content/renderer/v8_value_converter_impl_unittest.cc
@@ -300,7 +300,7 @@
       converter.ToV8Value(original_root, context).As<v8::Object>();
   ASSERT_FALSE(v8_object.IsEmpty());
 
-  EXPECT_EQ(original_root.DictSize(),
+  EXPECT_EQ(original_root.GetDict().size(),
             v8_object->GetPropertyNames(context).ToLocalChecked()->Length());
   EXPECT_TRUE(
       v8_object
diff --git a/content/test/content_unittests_bundle_data.filelist b/content/test/content_unittests_bundle_data.filelist
index eea93c03..a5f7b9b 100644
--- a/content/test/content_unittests_bundle_data.filelist
+++ b/content/test/content_unittests_bundle_data.filelist
@@ -807,6 +807,7 @@
 data/gpu/webgl2_conformance_tests_output.json
 data/gpu/webgl_conformance_tests_output.json
 data/gpu/webgl_extension_test.html
+data/gpu/webgl_test_page.html
 data/gpu/webgl_with_select_element.html
 data/gpu/webgpu-caching.html
 data/gpu/webgpu-context-lost.html
diff --git a/content/test/data/gpu/webgl_extension_test.html b/content/test/data/gpu/webgl_extension_test.html
index 87a6d6a9..9aba718 100644
--- a/content/test/data/gpu/webgl_extension_test.html
+++ b/content/test/data/gpu/webgl_extension_test.html
@@ -57,6 +57,9 @@
 
       webglTestHarness.notifyFinished(name);
     }
+
+    window.checkExtension = checkExtension;
+    window.checkSupportedExtensions = checkSupportedExtensions;
   </script>
   <body></body>
 </html>
diff --git a/content/test/data/gpu/webgl_test_page.html b/content/test/data/gpu/webgl_test_page.html
new file mode 100644
index 0000000..cc75cfd
--- /dev/null
+++ b/content/test/data/gpu/webgl_test_page.html
@@ -0,0 +1,21 @@
+<!--
+Test page used for running WebGL 1 and 2 conformance tests.
+
+Actual test pages are loaded into the iframe. This is so that we can guarantee
+that our asynchronous test setup is complete before the test starts.
+-->
+<div id="current_test">No test running.</div>
+<iframe id="test_iframe" style="width: 1024px; height: 768px; border: 0;"></iframe>
+<script>
+var currentTestDiv = document.getElementById('current_test');
+var testIframe = document.getElementById('test_iframe');
+var testIframeLoaded = false;
+function runTest(url) {
+  currentTestDiv.innerHTML = 'Current test: ' + url;
+  testIframeLoaded = false;
+  testHarness.reset();
+  wrapper.sendTestStarted();
+  testIframe.onload = (_) => { testIframeLoaded = true; };
+  testIframe.src = url;
+}
+</script>
\ No newline at end of file
diff --git a/content/test/gpu/gpu_tests/javascript/webgl_conformance_harness_script.js b/content/test/gpu/gpu_tests/javascript/webgl_conformance_harness_script.js
index 35d36e826..c8944b9e 100644
--- a/content/test/gpu/gpu_tests/javascript/webgl_conformance_harness_script.js
+++ b/content/test/gpu/gpu_tests/javascript/webgl_conformance_harness_script.js
@@ -10,18 +10,27 @@
     this.throttle_timer = null;
     this.last_heartbeat = null;
     this.socket = null;
+    this.eat_messages = false;
 
     this._sendDelayedHeartbeat = this._sendDelayedHeartbeat.bind(this);
   }
 
   setWebSocket(s) {
     this.socket = s;
+    s.send('{"type": "CONNECTION_ACK"}');
     for (let qm of this.queued_messages) {
       s.send(qm);
     }
   }
 
+  eatWebsocketMessages() {
+    this.eat_messages = true;
+  }
+
   _sendMessage(message) {
+    if (this.eat_messages) {
+      return;
+    }
     if (this.socket === null) {
       this.queued_messages.push(message);
     } else {
@@ -76,6 +85,10 @@
     }
   }
 
+  sendTestStarted() {
+    this._sendMessage('{"type": "TEST_STARTED"}');
+  }
+
   sendTestFinished() {
     this._clearPendingHeartbeat();
     this._sendMessage('{"type": "TEST_FINISHED"}');
@@ -83,9 +96,12 @@
 }
 
 if (window.parent.wrapper !== undefined) {
-  const wrapper = window.parent.wrapper;
+  var wrapper = window.parent.wrapper;
+  var inIframe = true;
+  window.wrapper = window.parent.wrapper;
 } else {
-  const wrapper = new WebSocketWrapper();
+  var wrapper = new WebSocketWrapper();
+  var inIframe = false;
   window.wrapper = wrapper;
 }
 
@@ -96,41 +112,75 @@
   });
 }
 
-var testHarness = {};
-testHarness._allTestSucceeded = true;
-testHarness._messages = '';
-testHarness._failures = 0;
-testHarness._finished = false;
-testHarness._originalLog = window.console.log;
-
-testHarness.log = function(msg) {
-  wrapper.sendHeartbeatThrottled();
-  testHarness._messages += msg + "\n";
-  testHarness._originalLog.apply(window.console, [msg]);
+// TODO(crbug.com/1432592): Remove this once Android is back to using the
+// heartbeat mechanism.
+function eatWebsocketMessages() {
+  wrapper.eatWebsocketMessages();
 }
 
-testHarness.reportResults = function(url, success, msg) {
-  wrapper.sendHeartbeatThrottled();
-  testHarness._allTestSucceeded = testHarness._allTestSucceeded && !!success;
-  if(!success) {
-    testHarness._failures++;
-    if(msg) {
-      testHarness.log(msg);
-    }
+function wrapFunctionInHeartbeat(prototype, key) {
+  const old = prototype[key];
+  prototype[key] = function (...args) {
+    wrapper.sendHeartbeatThrottled();
+    return old.call(this, ...args);
   }
-};
-testHarness.notifyFinished = function(url) {
-  wrapper.sendTestFinished();
-  testHarness._finished = true;
-};
-testHarness.navigateToPage = function(src) {
-  wrapper.sendHeartbeatThrottled();
-  var testFrame = document.getElementById("test-frame");
-  testFrame.src = src;
-};
+}
+
+if (inIframe) {
+  // getUniform* is to ensure we send heartbeats during the long-running
+  // conformance/uniforms/no-over-optimization-on-uniform-array-* tests.
+  wrapFunctionInHeartbeat(WebGLRenderingContext.prototype, 'getUniform');
+  wrapFunctionInHeartbeat(
+      WebGLRenderingContext.prototype, 'getUniformLocation');
+}
+
+if (!inIframe) {
+  var testHarness = {};
+
+  testHarness.reset = function() {
+    testHarness._allTestSucceeded = true;
+    testHarness._messages = '';
+    testHarness._failures = 0;
+    testHarness._totalTests = 0;
+    testHarness._finished = false;
+  }
+  testHarness.reset();
+
+  testHarness._originalLog = window.console.log;
+
+  testHarness.log = function(msg) {
+    wrapper.sendHeartbeatThrottled();
+    testHarness._messages += msg + "\n";
+    testHarness._originalLog.apply(window.console, [msg]);
+  }
+
+  testHarness.reportResults = function(url, success, msg) {
+    wrapper.sendHeartbeatThrottled();
+    testHarness._allTestSucceeded = testHarness._allTestSucceeded && !!success;
+    testHarness._totalTests++;
+    if(!success) {
+      testHarness._failures++;
+      if(msg) {
+        testHarness.log(msg);
+      }
+    }
+  };
+
+  testHarness.notifyFinished = function(url) {
+    wrapper.sendTestFinished();
+    testHarness._finished = true;
+  };
+
+  testHarness.navigateToPage = function(src) {
+    wrapper.sendHeartbeatThrottled();
+    var testFrame = document.getElementById("test-frame");
+    testFrame.src = src;
+  };
+} else {
+  var testHarness = window.parent.testHarness;
+}
 
 window.webglTestHarness = testHarness;
-window.parent.webglTestHarness = testHarness;
 window.console.log = testHarness.log;
 window.onerror = function(message, url, line) {
   testHarness.reportResults(null, false, message);
diff --git a/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py b/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py
index 7a3f34f..8b21c755 100644
--- a/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py
+++ b/content/test/gpu/gpu_tests/skia_gold_integration_test_base.py
@@ -380,19 +380,22 @@
     elif status == status_codes.INIT_FAILURE:
       logging.error('Gold initialization failed with output %s', error)
     elif status == status_codes.COMPARISON_FAILURE_REMOTE:
-      # We currently don't have an internal instance + public mirror like the
-      # general Chrome Gold instance, so just report the "internal" link, which
-      # points to the correct instance.
-      _, triage_link = gold_session.GetTriageLinks(image_name)
-      if not triage_link:
-        logging.error('Failed to get triage link for %s, raw output: %s',
+      public_triage_link, internal_triage_link = gold_session.GetTriageLinks(
+          image_name)
+      if not public_triage_link or not internal_triage_link:
+        logging.error('Failed to get triage links for %s, raw output: %s',
                       image_name, error)
-        logging.error('Reason for no triage link: %s',
+        logging.error('Reason for no triage links: %s',
                       gold_session.GetTriageLinkOmissionReason(image_name))
       elif gold_properties.IsTryjobRun():
-        self.artifacts.CreateLink('triage_link_for_entire_cl', triage_link)
+        self.artifacts.CreateLink('public_triage_link_for_entire_cl',
+                                  public_triage_link)
+        self.artifacts.CreateLink('internal_triage_link_for_entire_cl',
+                                  internal_triage_link)
       else:
-        self.artifacts.CreateLink('gold_triage_link', triage_link)
+        self.artifacts.CreateLink('public_gold_triage_link', public_triage_link)
+        self.artifacts.CreateLink('internal_gold_triage_link',
+                                  internal_triage_link)
     elif status == status_codes.COMPARISON_FAILURE_LOCAL:
       logging.error('Local comparison failed. Local diff files:')
       _OutputLocalDiffFiles(gold_session, image_name)
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 12f197bf..9eba073 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
@@ -333,19 +333,6 @@
 # The "Slow" expectations in this section are expected to stick around, i.e.
 # they are not attributed to some known issue that needs resolving.
 
-# Single tests doing large amounts of work (i.e. does not send heartbeats
-# throughout the test). This is fine with the passthrough decoder on non-debug
-# builds, but the validating decoder/debug builds slow them down significantly.
-# Also slow on Fuchsia smart displays due to their lower specs.
-crbug.com/1426593 [ no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
-crbug.com/1426593 [ debug angle-d3d9 passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
-crbug.com/1426593 [ debug angle-d3d11 passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
-crbug.com/1426593 [ debug angle-metal passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
-crbug.com/1426593 [ debug angle-opengl passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
-crbug.com/1426593 [ debug angle-opengles passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
-crbug.com/1426593 [ debug angle-swiftshader passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
-crbug.com/1426593 [ passthrough web-engine-shell ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
-
 # Seems to do enough JavaScript work that heartbeats are not reliably sent.
 crbug.com/1432580 [ android android-Pixel-2 ] conformance2/misc/uninitialized-test-2.html [ Slow ]
 crbug.com/1426916 [ chromeos chromeos-board-amd64-generic passthrough ] conformance2/misc/uninitialized-test-2.html [ Slow ]
@@ -541,6 +528,7 @@
 
 crbug.com/903903 [ android-nexus-5x android-nougat qualcomm target-cpu-64 ] conformance/glsl/bugs/sampler-array-struct-function-arg.html [ Failure ]
 crbug.com/478572 [ android-nexus-5x android-nougat qualcomm target-cpu-64 ] conformance/glsl/bugs/sequence-operator-evaluation-order.html [ Failure ]
+crbug.com/1439682 [ android android-nexus-5x passthrough ] conformance/textures/misc/tex-video-using-tex-unit-non-zero.html [ Failure ]
 
 # Need to investigate failure on basically all devices with passthrough on Android.
 crbug.com/angleproject/5038 [ android passthrough ] conformance/extensions/ext-color-buffer-half-float.html [ Failure ]
@@ -638,28 +626,6 @@
 crbug.com/1426793 [ android android-sm-a135m ] conformance/glsl/misc/shader-uniform-packing-restrictions.html [ Slow ]
 crbug.com/1426793 [ android android-sm-a135m ] conformance/textures/misc/tex-image-and-sub-image-2d-with-array-buffer-view.html [ Slow ]
 
-# Much slower (6x or worse) with the validating decoder than the passthrough
-# decoder. We list out all the tests so as to avoid a conflict with the wildcard
-# Slow expectation.
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-00.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-01.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-02.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-03.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-04.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-05.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-06.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-07.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-08.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-09.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-10.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-11.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-12.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-13.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-14.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-15.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-16.html [ Failure ]
-crbug.com/1426593 [ android android-sm-a135m no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-17.html [ Failure ]
-
 
 ############
 # ChromeOS #
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_integration_test_base.py b/content/test/gpu/gpu_tests/webgl_conformance_integration_test_base.py
index 551fdba..e19aaac 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_integration_test_base.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_integration_test_base.py
@@ -23,8 +23,10 @@
 from telemetry.internal.platform import gpu_info as telemetry_gpu_info
 
 JAVASCRIPT_DIR = os.path.join(gpu_path_util.GPU_DIR, 'gpu_tests', 'javascript')
+TEST_PAGE_RELPATH = os.path.join(webgl_test_util.extensions_relpath,
+                                 'webgl_test_page.html')
 
-WEBSOCKET_JAVASCRIPT_TIMEOUT_S = 30
+WEBSOCKET_JAVASCRIPT_TIMEOUT_S = 5
 HEARTBEAT_TIMEOUT_S = 15
 ASAN_MULTIPLIER = 2
 SLOW_MULTIPLIER = 4
@@ -73,6 +75,7 @@
   _command_decoder = ''
   _verified_flags = False
   _original_environ = None
+  page_loaded = False
 
   # Scripts read from file during process start up.
   _conformance_harness_script = None
@@ -124,6 +127,17 @@
                       help='Whether to enable Metal debug layers')
 
   @classmethod
+  def StartBrowser(cls) -> None:
+    cls.page_loaded = False
+    super().StartBrowser()
+
+  @classmethod
+  def StopBrowser(cls) -> None:
+    if cls.websocket_server:
+      cls.websocket_server.ClearCurrentConnection()
+    super().StopBrowser()
+
+  @classmethod
   def _SetClassVariablesFromOptions(cls, options: ct.ParsedCmdArgs) -> None:
     cls._webgl_version = int(options.webgl_conformance_version.split('.')[0])
     if not cls._conformance_harness_script:
@@ -269,6 +283,29 @@
     return True
 
   def _NavigateTo(self, test_path: str, harness_script: str) -> None:
+    if not self.__class__.page_loaded:
+      # If we haven't loaded the test page that we use to run tests within an
+      # iframe, load it and establish the websocket connection.
+      url = self.UrlOfStaticFilePath(TEST_PAGE_RELPATH)
+      self.tab.Navigate(url, script_to_evaluate_on_commit=harness_script)
+      self.tab.WaitForDocumentReadyStateToBeComplete(timeout=5)
+      # TODO(crbug.com/1432592): Remove this special casing once the flaky adb
+      # issues are investigated/resolved.
+      if self.browser.platform.GetOSName() != 'android':
+        self.tab.action_runner.EvaluateJavaScript(
+            'connectWebsocket("%d")' %
+            self.__class__.websocket_server.server_port,
+            timeout=WEBSOCKET_JAVASCRIPT_TIMEOUT_S)
+        self.__class__.websocket_server.WaitForConnection()
+        response = self.__class__.websocket_server.Receive(
+            WEBSOCKET_JAVASCRIPT_TIMEOUT_S)
+        response = json.loads(response)
+        assert response['type'] == 'CONNECTION_ACK'
+      else:
+        self.tab.action_runner.EvaluateJavaScript(
+            'eatWebsocketMessages()', timeout=WEBSOCKET_JAVASCRIPT_TIMEOUT_S)
+      self.__class__.page_loaded = True
+
     gpu_info = self.browser.GetSystemInfo().gpu
     self._crash_count = gpu_info.aux_attributes['process_crash_count']
     if not self._verified_flags:
@@ -278,15 +315,7 @@
           and self._VerifyCommandDecoder(gpu_info)):
         self._verified_flags = True
     url = self.UrlOfStaticFilePath(test_path)
-    self.tab.Navigate(url, script_to_evaluate_on_commit=harness_script)
-    # TODO(crbug.com/1432592): Remove this special casing once the flaky adb
-    # issues are investigated/resolved.
-    if self.browser.platform.GetOSName() != 'android':
-      self.tab.action_runner.EvaluateJavaScript(
-          'connectWebsocket("%d")' %
-          self.__class__.websocket_server.server_port,
-          timeout=self._GetWebsocketJavaScriptTimeout())
-      self.__class__.websocket_server.WaitForConnection()
+    self.tab.action_runner.EvaluateJavaScript('runTest("%s")' % url)
 
   def _HandleMessageLoop(self, test_timeout: float) -> None:
     # TODO(crbug.com/1432592): Remove this special casing once the flaky adb
@@ -296,6 +325,7 @@
           'webglTestHarness._finished', timeout=test_timeout)
       return
 
+    got_test_started = False
     start_time = time.time()
     try:
       while True:
@@ -310,6 +340,13 @@
               'messages over the websocket, i.e. was not due to a renderer '
               'crash.' % test_timeout)
 
+        if not got_test_started:
+          if response_type != 'TEST_STARTED':
+            raise RuntimeError('Got response %s when expected a test start.' %
+                               response_type)
+          got_test_started = True
+          continue
+
         if response_type == 'TEST_HEARTBEAT':
           continue
         if response_type == 'TEST_FINISHED':
@@ -334,17 +371,6 @@
       raise RuntimeError(
           'Detected closed websocket (%.3f seconds since test start) - likely '
           'caused by a renderer crash' % (time.time() - start_time)) from e
-    finally:
-      self.__class__.websocket_server.ClearCurrentConnection()
-
-  def _GetWebsocketJavaScriptTimeout(self) -> int:
-    # Most tests should be able to run JavaScript immediately after page load.
-    # However, some tests will do so much work that we're unable to actually
-    # run the JavaScript for quite a while.
-    return int(
-        NON_STANDARD_WEBSOCKET_JAVASCRIPT_TIMEOUTS.get(
-            self.shortName(), WEBSOCKET_JAVASCRIPT_TIMEOUT_S) *
-        self._GetTimeoutMultiplier())
 
   def _GetHeartbeatTimeout(self) -> int:
     return int(
@@ -386,13 +412,14 @@
                                 test_args: WebGLTestArgs) -> None:
     self._NavigateTo(test_path, self._GetExtensionHarnessScript())
     self.tab.action_runner.WaitForJavaScriptCondition(
-        'window._loaded', timeout=self._GetTestTimeout())
+        'testIframeLoaded', timeout=self._GetTestTimeout())
     context_type = 'webgl2' if test_args.webgl_version == 2 else 'webgl'
     extension_list_string = '['
     for extension in test_args.extension_list:
       extension_list_string = extension_list_string + extension + ', '
     extension_list_string = extension_list_string + ']'
     self.tab.action_runner.EvaluateJavaScript(
+        'testIframe.contentWindow.'
         'checkSupportedExtensions({{ extensions_string }}, {{context_type}})',
         extensions_string=extension_list_string,
         context_type=context_type)
@@ -401,9 +428,10 @@
   def _RunExtensionTest(self, test_path: str, test_args: WebGLTestArgs) -> None:
     self._NavigateTo(test_path, self._GetExtensionHarnessScript())
     self.tab.action_runner.WaitForJavaScriptCondition(
-        'window._loaded', timeout=self._GetTestTimeout())
+        'testIframeLoaded', timeout=self._GetTestTimeout())
     context_type = 'webgl2' if test_args.webgl_version == 2 else 'webgl'
     self.tab.action_runner.EvaluateJavaScript(
+        'testIframe.contentWindow.'
         'checkExtension({{ extension }}, {{ context_type }})',
         extension=test_args.extension,
         context_type=context_type)
@@ -499,7 +527,7 @@
         os.path.join(gpu_path_util.CHROMIUM_SRC_DIR,
                      webgl_test_util.conformance_relpath),
         os.path.join(gpu_path_util.CHROMIUM_SRC_DIR,
-                     webgl_test_util.extensions_relpath)
+                     webgl_test_util.extensions_relpath),
     ])
 
   @classmethod
@@ -512,7 +540,9 @@
 
   @staticmethod
   def _DidWebGLTestSucceed(tab: ct.Tab) -> bool:
-    return tab.EvaluateJavaScript('webglTestHarness._allTestSucceeded')
+    # Ensure that we actually ran tests and they all passed.
+    return tab.EvaluateJavaScript('webglTestHarness._allTestSucceeded '
+                                  '&& webglTestHarness._totalTests > 0')
 
   @staticmethod
   def _WebGLTestMessages(tab: ct.Tab) -> str:
diff --git a/content/utility/services.cc b/content/utility/services.cc
index e278440..87e42dc9 100644
--- a/content/utility/services.cc
+++ b/content/utility/services.cc
@@ -104,6 +104,10 @@
 #include "ui/accessibility/accessibility_features.h"
 #endif  // BUILDFLAG(ENABLE_ACCESSIBILITY_SERVICE)
 
+#if BUILDFLAG(IS_LINUX)
+#include "services/viz/public/cpp/gpu/gpu.h"
+#endif  // BUILDFLAG(IS_LINUX)
+
 namespace content {
 base::LazyInstance<NetworkBinderCreationCallback>::Leaky
     g_network_binder_creation_callback_for_testing = LAZY_INSTANCE_INITIALIZER;
@@ -298,8 +302,17 @@
 
 auto RunVideoCapture(
     mojo::PendingReceiver<video_capture::mojom::VideoCaptureService> receiver) {
-  return std::make_unique<UtilityThreadVideoCaptureServiceImpl>(
+  auto service = std::make_unique<UtilityThreadVideoCaptureServiceImpl>(
       std::move(receiver), base::SingleThreadTaskRunner::GetCurrentDefault());
+#if BUILDFLAG(IS_LINUX)
+  mojo::PendingRemote<viz::mojom::Gpu> remote_gpu;
+  content::UtilityThread::Get()->BindHostReceiver(
+      remote_gpu.InitWithNewPipeAndPassReceiver());
+  std::unique_ptr<viz::Gpu> viz_gpu = viz::Gpu::Create(
+      std::move(remote_gpu), content::UtilityThread::Get()->GetIOTaskRunner());
+  service->SetVizGpu(std::move(viz_gpu));
+#endif  // BUILDFLAG(IS_LINUX)
+  return service;
 }
 
 #if BUILDFLAG(ENABLE_VR) && !BUILDFLAG(IS_ANDROID)
diff --git a/device/gamepad/nintendo_controller.cc b/device/gamepad/nintendo_controller.cc
index beb0e62c..bd8ba133 100644
--- a/device/gamepad/nintendo_controller.cc
+++ b/device/gamepad/nintendo_controller.cc
@@ -4,9 +4,9 @@
 
 #include "device/gamepad/nintendo_controller.h"
 
+#include <algorithm>
 #include <utility>
 
-#include "base/cxx17_backports.h"
 #include "base/functional/bind.h"
 #include "base/ranges/algorithm.h"
 #include "base/task/single_thread_task_runner.h"
@@ -755,8 +755,8 @@
   int freq = static_cast<int>(frequency);
   int amp = static_cast<int>(amplitude * kVibrationAmplitudeMax);
   // Clamp the target frequency and amplitude to a safe range.
-  freq = base::clamp(freq, kVibrationFrequencyHzMin, kVibrationFrequencyHzMax);
-  amp = base::clamp(amp, 0, kVibrationAmplitudeMax);
+  freq = std::clamp(freq, kVibrationFrequencyHzMin, kVibrationFrequencyHzMax);
+  amp = std::clamp(amp, 0, kVibrationAmplitudeMax);
   const auto* best_vf = &kVibrationFrequency[0];
   for (size_t i = 1; i < kVibrationFrequencySize; ++i) {
     const auto* vf = &kVibrationFrequency[i];
@@ -1667,7 +1667,7 @@
 }
 
 void NintendoController::RequestSetHomeLightIntensity(double intensity) {
-  intensity = base::clamp(intensity, 0.0, 1.0);
+  intensity = std::clamp(intensity, 0.0, 1.0);
   uint8_t led_intensity = std::round(intensity * 0x0f);
   // Each pair of bytes in the minicycle data describes two minicyles.
   // The first byte holds two 4-bit values encoding minicycle intensities.
diff --git a/device/gamepad/xbox_controller_mac.mm b/device/gamepad/xbox_controller_mac.mm
index d2d9d840..5517314 100644
--- a/device/gamepad/xbox_controller_mac.mm
+++ b/device/gamepad/xbox_controller_mac.mm
@@ -4,10 +4,6 @@
 
 #include "device/gamepad/xbox_controller_mac.h"
 
-#include <algorithm>
-#include <cmath>
-#include <limits>
-
 #include <CoreFoundation/CoreFoundation.h>
 #include <IOKit/IOCFPlugIn.h>
 #include <IOKit/IOKitLib.h>
@@ -15,9 +11,12 @@
 #include <IOKit/usb/IOUSBLib.h>
 #include <IOKit/usb/USB.h>
 
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
 #include "base/check_op.h"
 #include "base/containers/fixed_flat_set.h"
-#include "base/cxx17_backports.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
@@ -338,8 +337,8 @@
 
   // Clamp magnitudes to [0,1]
   double strong_magnitude =
-      base::clamp<double>(params->strong_magnitude, 0.0, 1.0);
-  double weak_magnitude = base::clamp<double>(params->weak_magnitude, 0.0, 1.0);
+      std::clamp<double>(params->strong_magnitude, 0.0, 1.0);
+  double weak_magnitude = std::clamp<double>(params->weak_magnitude, 0.0, 1.0);
 
   if (xinput_type_ == kXInputTypeXbox360) {
     WriteXbox360Rumble(static_cast<uint8_t>(strong_magnitude * 255.0),
diff --git a/device/vr/android/arcore/arcore_gl.cc b/device/vr/android/arcore/arcore_gl.cc
index 28f3c205..f113afb 100644
--- a/device/vr/android/arcore/arcore_gl.cc
+++ b/device/vr/android/arcore/arcore_gl.cc
@@ -12,7 +12,6 @@
 #include "base/android/jni_android.h"
 #include "base/containers/contains.h"
 #include "base/containers/queue.h"
-#include "base/cxx17_backports.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ptr_util.h"
@@ -873,7 +872,7 @@
   // Ensure that the returned value is within ARCore's nominal frame time range.
   // This helps avoid underestimating the frame rate if the app is too slow
   // to reach the minimum target FPS value.
-  return base::clamp(frametime, min_frametime, max_frametime);
+  return std::clamp(frametime, min_frametime, max_frametime);
 }
 
 base::TimeDelta ArCoreGl::WaitTimeForArCoreUpdate() {
diff --git a/docs/security/research/README.md b/docs/security/research/README.md
new file mode 100644
index 0000000..89e9c8f2
--- /dev/null
+++ b/docs/security/research/README.md
@@ -0,0 +1,10 @@
+# Security Research Notes
+
+This directory contains security research notes about parts of Chromium of particular interest to attackers.
+
+The notes represent our understanding of a particular area of functionality at time of publishing, which we know is often incomplete, can become stale as code evolves, and may accidentally contain inaccuracies.
+
+We publish these notes to
+1. Preserve our understanding of areas of interest to security so we can refresh our memory of complex features after visiting other topics.
+2. Give new team members a learning resource.
+3. Boost productivity for external researchers making contributions to the [Chrome Vulnerability Rewards Program](https://www.chromium.org/Home/chromium-security/vulnerability-rewards-program/).
diff --git a/docs/security/research/graphics/README.md b/docs/security/research/graphics/README.md
new file mode 100644
index 0000000..61dd79c
--- /dev/null
+++ b/docs/security/research/graphics/README.md
@@ -0,0 +1,15 @@
+## Why Graphics?
+
+The GPU process is interesting from an attacker perspective for several reasons.
+
+1. Many of its features are reachable directly from web content by default,
+   which creates an opportunity for malicious websites to attack Chromium users.
+2. It processes complex data in (mostly) C++ native code, which is difficult to
+   do safely.
+3. It needs the privilege to interact with GPU drivers in the kernel, so our
+   ability to sandbox the process is limited.
+4. It loads third party native code into its address space to interact with
+   platform specific graphics features.
+
+Collectively these properties make the GPU process particularly attractive for
+both remote code execution and privilege escalation.
diff --git a/docs/security/research/graphics/gpu_command_buffer.md b/docs/security/research/graphics/gpu_command_buffer.md
new file mode 100644
index 0000000..35ba97d
--- /dev/null
+++ b/docs/security/research/graphics/gpu_command_buffer.md
@@ -0,0 +1,282 @@
+# GPU Command Buffer
+
+Authors: chrome-offsec-team@google.com<br/>
+Last updated: April 10, 2023<br/>
+
+## Overview
+The GPU Command Buffer is used to create and manage high throughput
+communication paths using a combination of Mojo IPC and shared memory regions.
+It is currently used by Chrome to support three distinct methods of
+GPU-accelerated graphics: WebGL2, Skia rasterization, and WebGPU. Mojo IPC
+messages are used to communicate the metadata necessary to establish new shared
+memory regions and coordinate state among endpoints producing and consuming from
+the memory region. Communication paths are between two endpoints: one client and
+one service. Typically the service endpoint resides in the GPU process and
+clients reside in the renderer process, but there is support for exceptions such
+as when GPU functionality is forced to run as a thread in the browser process,
+or unit tests where everything runs in a single process. A single renderer
+process may host multiple clients, such as when web content utilizes both WebGL
+and WebGPU features, where each context has an independent dedicated Command
+Buffer.
+
+The structure of Command Buffer data can be thought of as a layering of
+protocols. Common functionality is shared by all client-service types and
+specialized application-specific functionality is built on top. Core
+functionality provides the mechanisms to establish and manage the communication
+path, such as creating new shared memory regions and providing synchronization
+primitives. Specialized functionality pertains to application-specific features,
+such as shader configuration and execution.
+
+### Security Investment Rationale
+Isolating untrustworthy content within a sandboxed process is a cornerstone of
+the Chrome security model. Communication paths that bridge the sandbox to more
+trustworthy processes are a key part of the inter-process security boundary. The
+separation of the signaling mechanism (i.e. Mojo IPC) from the data transfer
+mechanism (i.e. shared memory) creates the potential for state inconsistencies.
+The layered nature of communication creates the potential for nuanced,
+cross-protocol dependencies. The use of shared memory creates the potential for
+time-of-check-time-of-use issues and other state inconsistencies.
+
+## Research Scope & Outcomes
+The Command Buffer investigation was part of a broader effort to identify areas
+of interest to attackers within the Chrome GPU acceleration stack. After
+narrowing our focus to code supporting the WebGPU subsystem, we still found the
+stack to be far larger and more complex than we could comprehensively audit in
+one pass. To further narrow scope we identified discrete components of
+functionality underpinning the WebGPU stack. The Command Buffer is one such
+component. Investigation of the Command Buffer proceeded in parallel to analysis
+of other GPU subsystems.
+
+Command Buffer communication is structured in layers. The foundational or common
+layer is shared by all higher layers. We chose to start analysis with the common
+features because of their applicability to all higher layers. The Command Buffer
+also supports application-specific features that behave like higher level
+protocols. Examples of higher level layers include support for WebGL and WebGPU.
+It is these higher level features - specifically the implications of
+cross-protocol interactions with the low level features - that we believe
+represent the bulk of complexity and attack surface. However, these are not yet
+explored and give motivation to revisit this subsystem.
+
+### Command Buffer Usage in Chrome
+The Command Buffer is used in four different scenarios:
+
+- [Proxy](https://source.chromium.org/chromium/chromium/src/+/main:gpu/ipc/client/command_buffer_proxy_impl.h;l=70;drc=93a273dd903e50a36011ea159fd9dc70c7000d87):
+  Used by sandboxed processes to communicate with the CommandBuffer service in
+  the GPU process.
+- [Direct](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/service/command_buffer_direct.h;l=19;drc=93a273dd903e50a36011ea159fd9dc70c7000d87):
+  Used by the CommandBuffer service within the GPU process.
+- [In-process](https://source.chromium.org/chromium/chromium/src/+/main:gpu/ipc/in_process_command_buffer.h;l=88;drc=b8743ff466a0d0208841a8c1bd906f481fc7f9ec):
+  Used when clients and services are all in the same process, such as unit tests
+  and when Chrome is run in single-process mode.
+- [Pepper](https://source.chromium.org/chromium/chromium/src/+/main:ppapi/proxy/ppapi_command_buffer_proxy.h;l=31;drc=821ca309ed94810aa52df2b31fc916806e207e0e)
+  (deprecated): Used by plugins - and possibly also extensions and apps - to
+  communicate with the CommandBuffer service in the GPU process.
+
+Each client type implements at least one of two additional classes that each
+provide a means of IPC signaling:
+
+1. CommandBufferClient: Used by the service to send messages to clients.
+   Implemented via
+   [Mojo](https://source.chromium.org/chromium/chromium/src/+/main:gpu/ipc/common/gpu_channel.mojom;l=282;drc=0a3ae731632f6d414e0460ab6bc0bb6e452adfda)
+   for multi-process use cases; the CommandBufferServiceClient is an equivalent
+   variation to support single-process operation via direct
+   [C++](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/service/command_buffer_service.h;l=50;drc=0a3ae731632f6d414e0460ab6bc0bb6e452adfda)
+   API calls.
+2. [GPUControl](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/client/gpu_control.h;l=37;drc=0a3ae731632f6d414e0460ab6bc0bb6e452adfda):
+   Used by clients to send messages to the service. Implemented via
+   [Mojo](https://source.chromium.org/chromium/chromium/src/+/main:gpu/ipc/common/gpu_channel.mojom;l=240;drc=0a3ae731632f6d414e0460ab6bc0bb6e452adfda)
+   for multi-process clients and C++ for in-process use cases.
+
+The Proxy use case is most interesting because it is the attack surface
+available from a sandboxed renderer process as deployed in real Chrome
+instances. However, we intended to pursue fuzzing and Chrome's primary fuzzer
+framework is based on single-process unit tests, so it was necessary to instead
+target the in-process implementation supported by unit tests even though it
+stubs-out or emulates interesting features.
+
+## Fuzzing
+Existing fuzzers for the Command Buffer were developed by the GPU team and
+predate our analysis. We studied these fuzzers - in particular how they
+bootstrap the graphics subsystem for testing - and developed new fuzzers with
+different generation strategies, finding one new high severity security
+[bug](https://crbug.com/1406115) in the same narrow feature set already covered
+by existing fuzzers. Much like our fuzzers from this first pass, the existing
+fuzzers targeted specific portions of functionality. An emerging theme for
+improving fuzzing Chrome at large applies here as well: layering and integration
+of fuzzers is expected to increase reachability of complex state and therefore
+increase aggregate fuzzer effectiveness.
+
+In other words, the coverage resulting from a combination of individual fuzzers
+is greater than the sum of its parts. Consequently, we intend to incrementally
+extend and integrate fuzzers in order to exercise cross-feature complexity
+during future work in the graphics subsystem. The next step is integration with
+new and complementary fuzzer targeting the WebGPU Dawn Wire protocol.
+
+We developed [one new fuzzer](https://crrev.com/c/4261996) tailored for the
+Command Buffer. Its design is similar to an [existing
+fuzzer](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/tests/fuzzer_main.cc;l=537;drc=c098bef2b9cb022ef1a037f28d3e3ee845c7a91a),
+but the new fuzzer differs in a few ways:
+- It uses [libprotobuf-mutator](https://github.com/google/libprotobuf-mutator)
+  (LPM) for generation.
+- The LPM
+  [grammar](https://source.chromium.org/chromium/chromium/src/+/main:testing/libfuzzer/fuzzers/command_buffer_fuzzer/cmd_buf_fuzz.proto)
+  targets
+  [CommandBuffer](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/common/command_buffer.h;l=18;drc=e20bf9387f49c3a0b208bad26dc8efc0dc214e96)
+  features that are common to all client-service types, making it suitable for
+  combination with other LPM fuzzers targeting higher level client-service
+  types, such as WebGPU.
+
+It so happens that most of the CommandBuffer features targeted by the new fuzzer
+also involve Mojo IPC.
+
+## Higher Layers
+Three types of CommandBuffer clients make direct use of its features: WebGL2,
+Skia Raster, and WebGPU. This section characterizes how each client type makes
+use of the CommandBuffer.
+
+One renderer may act as many clients. For example, if web content makes use of
+both WebGL2 and WebGPU, the renderer would have at least two separate
+CommandBuffer sessions.
+
+### CommandBuffer Protocol Structure
+CommandBuffer commands all start with a header containing two fields: an 11-bit
+command identifier and a 21-bit size. The header is followed by zero or more
+data fields.
+
+![](./resources/cmdbuf_command_structure.svg)
+
+The structure allows for 11 bits of unique commands, each with customizable data
+payloads. This is the mechanism used to implement the [common
+commands](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/common/cmd_buffer_common.h;l=171;drc=05dfbc82b07e06f610b8f2fecaa4d272430cc451).
+
+### WebGL2 and Skia Raster
+Just like the common commands, Skia [Raster
+commands](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/common/raster_cmd_ids_autogen.h)
+and [WebGL2/GLES2
+commands](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/common/gles2_cmd_ids_autogen.h;l=14;drc=4c9af88c669bd724a999193c8ffcff57f0cf6bbe)
+are also implemented as native CommandBuffer commands; each new command is
+assigned an identifier and their parameters are defined using CommandBuffer
+conventions. All native CommandBuffer commands are validated at the
+CommandBuffer level.
+
+### WebGPU
+WebGPU takes a different approach: a [few native CommandBuffer
+commands](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/common/webgpu_cmd_ids_autogen.h;l=14;drc=b4bc946c63b2b95e1f05dec4e84adcadd10499c6)
+support [many new Dawn
+APIs](https://source.chromium.org/chromium/chromium/src/+/main:out/Debug/gen/third_party/dawn/include/dawn/dawn_proc_table.h;l=8;drc=b4bc946c63b2b95e1f05dec4e84adcadd10499c6).
+In particular, a single CommandBuffer command called `DawnCommands` (code
+pointer:
+[client](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/client/webgpu_cmd_helper_autogen.h;l=14;drc=b4bc946c63b2b95e1f05dec4e84adcadd10499c6)
+/
+[service](https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/service/webgpu_decoder_impl.cc;l=1710;drc=48f518a9bb701c5ef7315b5affad8987517eb234))
+implements the bulk of the Dawn Wire protocol.
+
+Unlike native CommandBuffer commands, which each have a unique id at the
+CommandBuffer level, Dawn Wire commands are nested inside the data portion of
+the `DawnCommands` CommandBuffer command. In the GPU process, the CommandBuffer
+command handler reads the command data, which includes an identifier for the
+Dawn command, then uses a switch statement to determine which Dawn command to
+execute and how to further decode the data. Consequently, Dawn commands use an
+entirely discrete set of serialization, deserialization and validation logic.
+
+Notably, the [command
+handler](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/dawn/src/dawn/wire/ChunkedCommandHandler.h;l=59;drc=2dfb6431910db3004672ccb94df3ce09d13e8770)
+is platform specific,
+[auto-generated](https://source.chromium.org/chromium/chromium/src/+/main:third_party/dawn/src/dawn/wire/BUILD.gn;l=46;drc=0ebe86d1ca46dd203e7c55577df6115fa527c1c3),
+and its design allows individual handlers for Dawn commands (i.e. function
+pointers) to be overridden when the WebGPU session is established.
+
+Specific Dawn commands of interest are described in a dedicated document.
+
+## Features of Particular Interest
+
+This section describes high level feature operation to introduce the concepts.
+Later documents go into more detail about specific use cases.
+
+### `TransferBuffer`: Efficient Bulk Data Transfer
+
+Enabling efficient bulk data transfer is a core CommandBuffer feature. GPU
+clients - namely a renderer process - create a `gpu::TransferBuffer` that
+includes a pointer to a memory region the client intends to share with the GPU
+process. However, a pointer is only meaningful within a single process's address
+space and the goal is cross-process sharing, so `gpu::TransferBuffer` also
+contains a unique numeric identifier, `buffer_id_`, that will be consistent
+across processes.
+
+When a `gpu::TransferBuffer` is allocated and initialized, an important step is
+"registration" with the GPU process. Registration is a Mojo IPC message
+containing the `buffer_id_` of the newly created `gpu::TransferBuffer`, which
+allows the GPU process to record an association between the `buffer_id_` and a
+pointer to the shared buffer within its own address space. After registration
+both client and service can refer to the same memory by its ID rather than a
+pointer.
+
+The `gpu::TransferBuffer` includes data structures that allow the client and
+service to treat the shared memory region as a ring buffer. These data
+structures include alignments and offsets within the shared buffer, as well as
+features to let client and service indicate their respective positions of
+production and consumption within the buffer. These structures must be kept in
+sync across both the client and service to achieve intended operation, which
+requires cooperation of both client and service. Notably, since the client
+creates the shared memory it may also unilaterally reorganize or altogether
+de-allocate the memory; this means the service must guard against a compromised
+renderer that has many opportunities to manipulate state and shared resources.
+
+### `SyncToken`: Foundation for Synchronization
+
+The `SyncToken` is a CommandBuffer synchronization primitive. A token is
+inserted into the command stream as a shared point of reference for both
+producers and consumers. The shared point of reference allows building higher
+level synchronization features. For example, client and server can communicate
+expectations about the ordering of operations in the stream in relation to a
+token.
+
+Higher level several synchronization features such as `CHROMIUM_sync_point` and
+`CHROMIUM_ordering_barrier` build on the `SyncToken` and are implemented as
+[extensions](https://source.chromium.org/chromium/chromium/src/+/main:gpu/GLES2/extensions/CHROMIUM/)
+to the CommandBuffer protocol.
+
+Dedicated
+[documentation](https://source.chromium.org/chromium/chromium/src/+/main:docs/design/gpu_synchronization.md)
+goes into more detail about Chromium GPU synchronization features.
+
+### `Mailbox`: A cross-process identity for shared resources
+
+A `gpu::Mailbox` is a 16-byte random value that can be shared across GPU
+contexts and processes. The `gpu::Mailbox` name is a single shared identifier
+used to refer to the same object. Similar to a `gpu::TransferBuffer` ID, the
+common identifier gives GPU clients and services in different processes a name
+to refer to data across address spaces.
+
+The key feature of the `gpu::Mailbox` is allowing producers and consumers to
+associate *multiple* resources with a single name. After establishing a mailbox,
+communicating endpoints can reference a collection of related resources using a
+common name rather than managing many separate resources.
+
+### `SharedImage`: Allowing many endpoints to operate on shared binary data
+
+`SharedImage` is a complex collection of features to pass binary data between
+producers and consumers. It's key feature is allowing multiple contexts of
+potentially different types - e.g. Skia Raster, WebGL, and WebGPU - to operate
+on the same object.
+
+## Observations & Lessons Learned
+
+Layering and integration of fuzzers is expected to increase reachable state and
+therefore increase aggregate fuzzer effectiveness. Consequently, we intended to
+incrementally extend and integrate fuzzers in order to exercise cross-protocol
+complexity during future work in the graphics subsystem. Modest changes to
+existing fuzzers can yield new bugs.
+
+Layering Dawn on top of an independent communication mechanism has been a source
+of security bugs (e.g. [1](crbug.com/1314754), [2](crbug.com/1393177),
+[3](crbug.com/1373314), [4](crbug.com/1340654)) because operations at the lower
+CommandBuffer level can violate assumptions made at the higher level.
+
+### Prior Work
+- [2020 Q2 WebGPU Security design
+  doc](https://docs.google.com/document/d/1rrNBF8Ft8WZU3VzAgAUycrwlaesWWw6hvmIqJPiGRII)
+  (Google only)
+- [SwiftShader - A Chrome Security
+  Perspective](https://docs.google.com/presentation/d/1nVmbrJikT_qfhMls4rK0txtPXLuRhrhGs-TICLyU3Wc/)
+  (Google only)
diff --git a/docs/security/research/graphics/overview.md b/docs/security/research/graphics/overview.md
new file mode 100644
index 0000000..7d57e67
--- /dev/null
+++ b/docs/security/research/graphics/overview.md
@@ -0,0 +1,22 @@
+# Chromium Graphics
+
+Authors: chrome-offsec-team@google.com<br/>
+Last updated: April 7, 2023<br/>
+
+## Overview
+
+Chromium graphics features are among the most complex parts of the browser. This
+document is a snapshot of our evolving understanding of graphics features from
+an attacker perspective. Relevant and important pieces of the graphics stack are
+omitted, but the intent is to give VRP contributors a boost when getting started
+with unfamiliar graphics features.
+
+## In Pictures: WebGL and WebGPU
+
+The diagram below is a simplified view of WebGL and WebGPU with a focus on
+components of particular interest to attackers.
+
+![](resources/chrome_gfx_overview.svg)
+
+Note: Skia and Canvas APIs are omitted and may be incorporated in a future
+iteration.
diff --git a/docs/security/research/graphics/resources/chrome_gfx_overview.svg b/docs/security/research/graphics/resources/chrome_gfx_overview.svg
new file mode 100644
index 0000000..e22c2a0
--- /dev/null
+++ b/docs/security/research/graphics/resources/chrome_gfx_overview.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:lucid="lucid" width="1381.41" height="2579.8"><g transform="translate(-210.54687500000068 1260)" lucid:page-tab-id="HIvJzR.vuAat"><path d="M0-1296h1760v2656H0z" fill="#fff"/><path d="M230.55-1234a6 6 0 0 1 6-6h1329.4a6 6 0 0 1 6 6v2248a6 6 0 0 1-6 6H236.55a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#f2f3f5"/><use xlink:href="#a" transform="matrix(1,0,0,1,235.5468750000009,-1235) translate(1221.1358024691358 17.77777777777778)"/><path d="M251.25-354a6 6 0 0 1 6-6h1288a6 6 0 0 1 6 6V994a6 6 0 0 1-6 6h-1288a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#dfe3e8"/><use xlink:href="#b" transform="matrix(1,0,0,1,256.2500000000009,-355) translate(1059.4444444444443 17.77777777777778)"/><use xlink:href="#c" transform="matrix(1,0,0,1,256.2500000000009,-355) translate(1149.3827160493827 17.77777777777778)"/><use xlink:href="#d" transform="matrix(1,0,0,1,256.2500000000009,-355) translate(1203.6419753086418 17.77777777777778)"/><path d="M532.36-1174a6 6 0 0 1 6-6h258a6 6 0 0 1 6 6v738a6 6 0 0 1-6 6h-258a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#dfe3e8"/><use xlink:href="#b" transform="matrix(1,0,0,1,537.3561264558857,-1175) translate(72.71604938271605 17.77777777777778)"/><use xlink:href="#e" transform="matrix(1,0,0,1,537.3561264558857,-1175) translate(162.65432098765433 17.77777777777778)"/><use xlink:href="#d" transform="matrix(1,0,0,1,537.3561264558857,-1175) translate(173.64197530864197 44.44444444444444)"/><path d="M597.23-1034a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#c3f7c8"/><use xlink:href="#f" transform="matrix(1,0,0,1,609.2249788074035,-1028) translate(21.364197530864196 26.77777777777778)"/><use xlink:href="#g" transform="matrix(1,0,0,1,609.2249788074035,-1028) translate(16.209876543209873 53.44444444444445)"/><use xlink:href="#h" transform="matrix(1,0,0,1,609.2249788074035,-1028) translate(44.54320987654321 80.11111111111111)"/><path d="M597.23-876.5a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#c3f7c8"/><use xlink:href="#f" transform="matrix(1,0,0,1,609.2249788074035,-870.5) translate(21.364197530864196 26.77777777777778)"/><use xlink:href="#i" transform="matrix(1,0,0,1,609.2249788074035,-870.5) translate(43.98765432098766 53.44444444444445)"/><use xlink:href="#j" transform="matrix(1,0,0,1,609.2249788074035,-870.5) translate(25.46913580246914 80.11111111111111)"/><path d="M597.23-719a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#c3f7c8"/><use xlink:href="#k" transform="matrix(1,0,0,1,609.2249788074035,-713) translate(13.833333333333336 38.77777777777778)"/><use xlink:href="#l" transform="matrix(1,0,0,1,609.2249788074035,-713) translate(76.67283950617283 38.77777777777778)"/><use xlink:href="#m" transform="matrix(1,0,0,1,609.2249788074035,-713) translate(39.69753086419753 65.44444444444446)"/><path d="M677.23-916v8.76" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M679.23-915.95h-4V-918h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M677.23-890.97l-4.64-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M677.23-758.5v8.76" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M679.23-758.45h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M677.23-733.47l-4.64-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M597.23-566.5a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#cfe4ff"/><use xlink:href="#n" transform="matrix(1,0,0,1,609.2249788074035,-560.5000000000001) translate(16.85802469135802 26.77777777777778)"/><use xlink:href="#o" transform="matrix(1,0,0,1,609.2249788074035,-560.5000000000001) translate(38.617283950617285 53.44444444444445)"/><use xlink:href="#p" transform="matrix(1,0,0,1,609.2249788074035,-560.5000000000001) translate(39.69753086419753 80.11111111111111)"/><path d="M577.1-199.83a6 6 0 0 1 6-6h175a6 6 0 0 1 6 6V-106a6 6 0 0 1-6 6h-175a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#cfe4ff"/><use xlink:href="#q" transform="matrix(1,0,0,1,589.085456618486,-193.8333333333334) translate(27.80246913580247 33.15277777777778)"/><use xlink:href="#r" transform="matrix(1,0,0,1,589.085456618486,-193.8333333333334) translate(6.8148148148148096 59.81944444444445)"/><use xlink:href="#s" transform="matrix(1,0,0,1,589.085456618486,-193.8333333333334) translate(78.17283950617282 59.81944444444445)"/><path d="M300-14a6 6 0 0 1 6-6h493a6 6 0 0 1 6 6v488a6 6 0 0 1-6 6H306a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#c3f7c8"/><use xlink:href="#t" transform="matrix(1,0,0,1,312.0000000000001,-8.000000000000256) translate(0 17.77777777777778)"/><path d="M230.55 1037.05a6 6 0 0 1 6-6h1329.4a6 6 0 0 1 6 6v138.6a6 6 0 0 1-6 6H236.55a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ced4db"/><use xlink:href="#u" transform="matrix(1,0,0,1,235.54687500000068,1036.0494717741274) translate(0 17.77777777777778)"/><path d="M230.55 1198.7a6 6 0 0 1 6-6h1329.4a6 6 0 0 1 6 6v95.1a6 6 0 0 1-6 6H236.55a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#979ea8"/><use xlink:href="#v" transform="matrix(1,0,0,1,235.5468750000009,1197.704970165914) translate(0 17.77777777777778)"/><path d="M584.4 1066a6 6 0 0 1 6-6h588a6 6 0 0 1 6 6v95.58a6 6 0 0 1-6 6h-588a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ff8f8f"/><use xlink:href="#w" transform="matrix(1,0,0,1,596.3937394037023,1072) translate(222.62962962962962 17.77777777777778)"/><use xlink:href="#x" transform="matrix(1,0,0,1,596.3937394037023,1072) translate(276.88888888888886 17.77777777777778)"/><path d="M796.67 1234a6 6 0 0 1 6-6h164a6 6 0 0 1 6 6v52.55a6 6 0 0 1-6 6h-164a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#e08fff"/><use xlink:href="#y" transform="matrix(1,0,0,1,808.6683795395288,1240) translate(51.9567901234568 25.46527777777778)"/><path d="M372.5 358.5a6 6 0 0 1 6-6h348a6 6 0 0 1 6 6V454a6 6 0 0 1-6 6h-348a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd6f5"/><use xlink:href="#z" transform="matrix(1,0,0,1,384.5000000000002,364.5) translate(82.96913580246914 17.77777777777778)"/><use xlink:href="#A" transform="matrix(1,0,0,1,384.5000000000002,364.5) translate(148.27777777777777 17.77777777777778)"/><path d="M395 46a6 6 0 0 1 6-6h168a6 6 0 0 1 6 6v30.92a6 6 0 0 1-6 6H401a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#c3f7c8"/><use xlink:href="#B" transform="matrix(1,0,0,1,406.9999999999999,51.9999999999998) translate(30.160493827160494 17.77777777777778)"/><path d="M700 786a6 6 0 0 1 6-6h707.24a6 6 0 0 1 6 6v188a6 6 0 0 1-6 6H706a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd9d9"/><use xlink:href="#C" transform="matrix(1,0,0,1,712,792) translate(464.3333333333333 142.9861489777778)"/><use xlink:href="#D" transform="matrix(1,0,0,1,712,792) translate(525.8765432098766 142.9861489777778)"/><use xlink:href="#E" transform="matrix(1,0,0,1,712,792) translate(587.5432098765432 142.9861489777778)"/><use xlink:href="#F" transform="matrix(1,0,0,1,712,792) translate(499.95061728395063 169.65281564444444)"/><use xlink:href="#G" transform="matrix(1,0,0,1,712,792) translate(602.2962962962963 169.65281564444444)"/><path d="M715.26 806a6 6 0 0 1 6-6h678a6 6 0 0 1 6 6v97.08a6 6 0 0 1-6 6h-678a6 6 0 0 1-6-6z" fill="#ffd9d9"/><path d="M731.3 800h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h10.04m5.03 0h10.05m5.02 0h10.05m5.02 0h5.02l.94.07.92.22.87.35.8.5.7.6.62.72.5.8.35.88.22.9.06.95v5.4m0 5.4v10.77m0 5.4v10.78m0 5.4v10.78m0 5.4v10.8m0 5.38v10.8m0 5.4v5.38l-.07.94-.23.92-.36.87-.48.8-.6.73-.73.6-.8.5-.88.36-.92.2-.94.08h-5.02m-5.02 0h-10.05m-5.02 0h-10.04m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0h-10.04m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0h-10.04m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0h-10.04m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0h-10.04m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0h-10.04m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0h-10.04m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0h-10.04m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0h-10.04m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0H957.3m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0H912.1m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0H866.9m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0H821.7m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0H776.5m-5.02 0h-10.04m-5.02 0h-10.05m-5.02 0H731.3m-5.02 0h-5.02l-.94-.07-.9-.2-.88-.37-.8-.5-.72-.6-.6-.72-.5-.8-.36-.86-.22-.92-.08-.94v-5.4m0-5.38v-10.8m0-5.38v-10.8m0-5.4v-10.77m0-5.4v-10.78m0-5.4V816.8m0-5.4V806l.08-.94.22-.9.36-.88.5-.8.6-.72.72-.6.8-.5.87-.37.92-.23.94-.07h5.02" stroke="#000" fill="none"/><use xlink:href="#H" transform="matrix(1,0,0,1,727.2621295395286,812.0000000000002) translate(536.6172839506173 20.46527777777778)"/><use xlink:href="#I" transform="matrix(1,0,0,1,727.2621295395286,812.0000000000002) translate(479.8888888888889 47.13194444444444)"/><use xlink:href="#J" transform="matrix(1,0,0,1,727.2621295395286,812.0000000000002) translate(647.4814814814815 47.13194444444444)"/><use xlink:href="#K" transform="matrix(1,0,0,1,727.2621295395286,812.0000000000002) translate(409.51851851851853 73.79861111111111)"/><use xlink:href="#L" transform="matrix(1,0,0,1,727.2621295395286,812.0000000000002) translate(529.0864197530864 73.79861111111111)"/><use xlink:href="#M" transform="matrix(1,0,0,1,727.2621295395286,812.0000000000002) translate(619.0864197530864 73.79861111111111)"/><path d="M775 883.54V894a6 6 0 0 0 6 6h97.4a6 6 0 0 1 6 6v129.26" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M777 883.6h-4v-2.06h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M884.4 1051.53l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M725 835.54a6 6 0 0 1 6-6h88a6 6 0 0 1 6 6v38a6 6 0 0 1-6 6h-88a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd9d9"/><use xlink:href="#N" transform="matrix(1,0,0,1,737.0000000000003,841.5416666666681) translate(4.481481481481481 17.77777777777778)"/><path d="M884.4 1171.58v26.07a.14.14 0 0 0 .13.14.14.14 0 0 1 .14.13v5.33" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M886.4 1171.63h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M884.67 1219.53l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M680 586a6 6 0 0 1 6-6h368.95a6 6 0 0 1 6 6v88a6 6 0 0 1-6 6H686a6 6 0 0 1-6-6z" stroke="#000" stroke-width="4" fill="#00c2a8"/><use xlink:href="#O" transform="matrix(1,0,0,1,692,591.9999999999999) translate(114.42592592592592 17.77777777777778)"/><path d="M840 835.54a6 6 0 0 1 6-6h78a6 6 0 0 1 6 6v38a6 6 0 0 1-6 6h-78a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd9d9"/><use xlink:href="#P" transform="matrix(1,0,0,1,852.0000000000006,841.5416666666673) translate(10.839506172839506 17.77777777777778)"/><path d="M945 835.54a6 6 0 0 1 6-6h68a6 6 0 0 1 6 6v38a6 6 0 0 1-6 6h-68a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd9d9"/><use xlink:href="#Q" transform="matrix(1,0,0,1,957.0000000000006,841.5416666666673) translate(0.9012345679012341 17.77777777777778)"/><path d="M885 883.54v16.16a.3.3 0 0 1-.3.3.3.3 0 0 0-.3.3v134.96" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M887 883.6h-4v-2.06h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M884.4 1051.53l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M985 883.54V894a6 6 0 0 1-6 6h-88.6a6 6 0 0 0-6 6v129.26" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M987 883.6h-4v-2.06h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M884.4 1051.53l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M872.47 555.26h-4v-5.93h4zM444.5 513.92l.06.7.14.6.24.6.33.53.4.47.48.4.54.34.57.24.6.15.7.05h415.98l1.18.1 1.22.3 1.16.47 1.08.65.96.82.8.95.67 1.07.5 1.16.28 1.22.1 1.17V528h-4v-1.92l-.06-.7-.15-.6-.24-.6-.33-.53-.4-.47-.48-.4-.53-.34-.6-.24-.6-.15-.7-.05H448.4l-1.17-.1-1.22-.3-1.16-.47-1.08-.65-.96-.82-.82-.95-.65-1.07-.48-1.16-.3-1.22-.1-1.17V449h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M444.5 449.05h-4V447h4z" fill="#3a414a"/><path d="M444.52 449.08h-4.04v-2.1h4.04zm-4-2.06v2h3.96v-2z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M870.47 571.53l-4.63-14.27h9.27z" fill="#3a414a"/><path d="M870.47 578l-7.38-22.74h14.76zm-1.88-18.74l1.87 5.8 1.9-5.8z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><use xlink:href="#R" transform="matrix(1,0,0,1,816.2512126287031,528.0000000000006) translate(0 14.222222222222223)"/><use xlink:href="#S" transform="matrix(1,0,0,1,816.2512126287031,528.0000000000006) translate(33.53086419753087 14.222222222222223)"/><path d="M606.9 1109.03a6 6 0 0 1 6-6h108a6 6 0 0 1 6 6v41.8a6 6 0 0 1-6 6h-108a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ff8f8f"/><use xlink:href="#T" transform="matrix(1,0,0,1,618.8937394037025,1115.0302933193304) translate(17.228395061728396 17.77777777777778)"/><path d="M751.9 1109.03a6 6 0 0 1 6-6h108a6 6 0 0 1 6 6v41.8a6 6 0 0 1-6 6h-108a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ff8f8f"/><use xlink:href="#U" transform="matrix(1,0,0,1,763.8937394037022,1115.0302933193304) translate(27.72222222222222 17.77777777777778)"/><path d="M896.9 1109.03a6 6 0 0 1 6-6h108a6 6 0 0 1 6 6v41.8a6 6 0 0 1-6 6h-108a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ff8f8f"/><use xlink:href="#V" transform="matrix(1,0,0,1,908.8937394037022,1115.0302933193304) translate(12.2283950617284 17.77777777777778)"/><path d="M397.5 398.83a6 6 0 0 1 6-6h78a6 6 0 0 1 6 6V439a6 6 0 0 1-6 6h-78a6 6 0 0 1-6-6z" stroke="#000" stroke-width="4" fill="#ffd6f5"/><use xlink:href="#N" transform="matrix(1,0,0,1,409.4999999999999,404.8308823529405) translate(-0.518518518518519 18.944444444444443)"/><path d="M507.5 398.83a6 6 0 0 1 6-6h78a6 6 0 0 1 6 6V439a6 6 0 0 1-6 6h-78a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd6f5"/><use xlink:href="#P" transform="matrix(1,0,0,1,519.4999999999999,404.8308823529405) translate(10.839506172839506 19.59027777777778)"/><path d="M617.5 398.83a6 6 0 0 1 6-6h78a6 6 0 0 1 6 6V439a6 6 0 0 1-6 6h-78a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd6f5"/><use xlink:href="#Q" transform="matrix(1,0,0,1,629.4999999999999,404.8308823529405) translate(5.901234567901234 19.59027777777778)"/><path d="M554.5 723.92l.05.7.15.6.24.6.33.53.4.47.48.4.54.34.57.24.6.15.7.05h320.5l1.18.1 1.22.3 1.16.47 1.08.65.96.82.82.95.65 1.07.48 1.16.3 1.22.1 1.17v68.88h-4v-68.72l-.05-.7-.15-.6-.24-.6-.33-.53-.4-.47-.48-.4-.54-.34-.57-.24-.6-.15-.7-.05h-320.5l-1.18-.1-1.22-.3-1.16-.47-1.08-.65-.96-.82-.82-.95-.65-1.07-.48-1.16-.3-1.22-.1-1.17V449h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M554.5 449.05h-4V447h4z" fill="#3a414a"/><path d="M554.52 449.08h-4.04v-2.1h4.04zm-4-2.06v2h3.96v-2z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M885 821.07l-4.63-14.27h9.26z" fill="#3a414a"/><path d="M885 827.54l-7.4-22.74h14.8zm-1.88-18.74l1.88 5.8 1.88-5.8zM664.5 713.92l.05.7.15.6.24.6.33.53.4.47.48.4.54.34.57.24.6.15.7.05h310.5l1.18.1 1.22.3 1.16.47 1.08.65.96.82.82.95.65 1.07.48 1.16.3 1.22.1 1.17v78.88h-4v-78.72l-.05-.7-.15-.6-.24-.6-.33-.53-.4-.47-.48-.4-.54-.34-.57-.24-.6-.15-.7-.05h-310.5l-1.18-.1-1.22-.3-1.16-.47-1.08-.65-.96-.82-.82-.95-.65-1.07-.48-1.16-.3-1.22-.1-1.17V449h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M664.5 449.05h-4V447h4z" fill="#3a414a"/><path d="M664.52 449.08h-4.04v-2.1h4.04zm-4-2.06v2h3.96v-2z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M985 821.07l-4.63-14.27h9.26z" fill="#3a414a"/><path d="M985 827.54l-7.4-22.74h14.8zm-1.88-18.74l1.88 5.8 1.88-5.8z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1041.9 1109.03a6 6 0 0 1 6-6h108a6 6 0 0 1 6 6v41.8a6 6 0 0 1-6 6h-108a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ff8f8f"/><use xlink:href="#W" transform="matrix(1,0,0,1,1053.8937394037011,1115.0302933193304) translate(30.098765432098766 17.77777777777778)"/><path d="M366.25-1105l49.9 28.75-49.9 86.25c63.48 0 115-51.52 115-115 0-20.93-5.52-40.48-15.4-57.5h-99.6z" stroke="#ced4db" stroke-width="4" fill="url(#X)"/><path d="M366.25-1220c-42.55 0-79.8 23.23-99.6 57.5l49.7 86.25 49.9-28.75v-57.5h99.6c-20.02-34.27-57.05-57.5-99.6-57.5z" stroke="#ced4db" stroke-width="4" fill="url(#Y)"/><path d="M251.25-1105c0 63.48 51.52 115 115 115l49.9-86.25-49.9-28.75-49.9 28.75-49.7-86.25c-9.88 17.02-15.4 36.57-15.4 57.5" stroke="#ced4db" stroke-width="4" fill="url(#Z)"/><path d="M423.75-1105c0 31.74-25.76 57.5-57.5 57.5s-57.5-25.76-57.5-57.5 25.76-57.5 57.5-57.5 57.5 25.76 57.5 57.5" stroke="#ced4db" stroke-width="4" fill="#fff"/><path d="M412.94-1105c0 25.76-20.93 46.7-46.7 46.7-25.75 0-46.68-20.94-46.68-46.7s20.93-46.7 46.7-46.7c25.75 0 46.68 20.94 46.68 46.7" stroke="#ced4db" stroke-width="4" fill="url(#aa)"/><path d="M571-1077.83l-31-53.86h62.25L571-1077.8z" stroke="#979ea8" stroke-width="4" fill="#005a9c"/><path d="M602-1131.7l-15.75 26.9h31.25l-15.5-26.9z" stroke="#979ea8" stroke-width="4" fill="#0066b0"/><path d="M602-1077.93l-15.75-26.88h31.25l-15.5 26.87z" stroke="#979ea8" stroke-width="4" fill="#0076cc"/><path d="M617.5-1104.7l-8-13.44h15.75l-7.75 13.44z" stroke="#979ea8" stroke-width="4" fill="#0086e8"/><path d="M617.5-1131.58l-8 13.44h15.75l-7.75-13.44z" stroke="#979ea8" stroke-width="4" fill="#0093ff"/><path d="M648-1093.65c0-2.5-.5-4.93-1.75-7.15-1.25-2.06-3-3.8-5-4.93-2.25-1.25-4.75-1.9-7.25-1.84-2.75-.06-5.25.6-7.5 1.84-2.25 1.25-4 3.03-5 5.25-1.25 2.28-2 4.88-2 7.92 0 2.98.75 5.63 2 7.9 1 2.23 3 4.07 5 5.32 2.25 1.24 5 1.9 7.5 1.84 3.5 0 6.25-.87 8.75-2.65 2.25-1.68 3.75-4.07 4.5-6.78h-5c-.75 1.57-1.75 2.93-3 3.9-1.5.98-3.25 1.47-5.25 1.47-2.5.05-4.75-.82-6.5-2.44-1.75-1.63-2.75-3.85-3-6.72h23.25c.25-.98.25-1.95.25-2.93zm-5-1.03h-18.5c.25-2.7 1.25-4.87 3-6.45 1.75-1.57 4-2.38 6.25-2.33 1.5-.05 3.25.33 4.75 1.03 1.25.65 2.5 1.74 3.25 3.04.75 1.42 1.25 3.1 1.25 4.72zm16.25-7v-15.6h-5v39.3h5v-5.37c1 1.8 2.5 3.2 4.25 4.22 2 1.1 4.25 1.68 6.5 1.63 5 .05 9.75-2.76 12-7.26 1.25-2.44 1.75-5.15 1.75-7.86 0-2.98-.5-5.58-1.75-7.86-1-2.16-2.75-3.95-5-5.2-2-1.24-4.5-1.9-7-1.9-2.25 0-4.5.55-6.5 1.7-1.75.96-3.25 2.42-4.25 4.2zm19.75 9.06c0 2-.5 4-1.5 5.8-.75 1.57-2 2.87-3.5 3.8-1.5.86-3.25 1.3-5 1.3s-3.5-.44-5-1.3c-1.5-.93-2.75-2.23-3.5-3.8-1.75-3.63-1.75-7.86 0-11.5.75-1.56 2-2.86 3.5-3.73 1.5-.86 3.25-1.3 5-1.3s3.5.44 5 1.25c1.5.87 2.75 2.17 3.5 3.74 1 1.8 1.5 3.74 1.5 5.74zm45-11.65c-1.25-3.36-3.5-6.28-6.5-8.24-3.25-1.96-6.5-2.93-10.5-2.93-3.25 0-6.5.8-9.5 2.44-2.75 1.58-5 3.9-6.75 6.73-1.5 2.98-2.5 6.34-2.25 9.75-.25 3.4.75 6.77 2.25 9.7 1.75 2.82 4 5.15 6.75 6.72 3 1.63 6.25 2.5 9.5 2.44 3 .05 6-.7 8.75-2.22 2.75-1.4 5-3.47 6.5-5.96 1.75-2.55 2.5-5.42 2.75-8.4v-3.7h-19.75v3.9H720c-.5 3.7-1.75 6.62-4 8.8-2.5 2.16-5.5 3.24-9 3.24-2.5 0-5-.6-7-1.8-2-1.18-3.75-2.97-5-5.08-1-2.17-1.75-4.7-1.75-7.64 0-2.87.75-5.47 1.75-7.64 1.25-2.17 3-3.9 5-5.1 2-1.24 4.5-1.84 7-1.78 2.25-.06 4.75.54 6.75 1.8 2 1.18 3.5 2.9 4.5 4.97H724zm32.25.1c0-3.2-1-5.8-3.25-7.8s-5.5-3.03-9.5-3.03h-12v37h4.75v-15.43h7.25c4.25 0 7.5-1.03 9.5-3.04 2.25-2.06 3.25-4.6 3.25-7.7zm-12.75 6.78h-7.25v-13.6h7.25c5.25 0 7.75 2.3 7.75 6.84 0 2.17-.5 3.85-1.75 5-1.5 1.18-3.25 1.77-6 1.77zm18.75-17.6v23.36c0 3.1.5 5.7 1.75 7.8 1 2 2.75 3.68 5 4.7 4.5 2.02 9.75 2.02 14 0 2.25-1 4-2.7 5.25-4.7 1.25-2.1 1.75-4.7 1.75-7.8V-1115h-4.75v23.4c0 3.32-1 5.75-2.5 7.33-1.5 1.62-3.75 2.43-6.75 2.43-2.75 0-5-.8-6.75-2.43-1.5-1.58-2.25-4-2.25-7.32v-23.4h-4.75z" stroke="#979ea8" stroke-width="4" fill="#fff"/><path d="M325 206a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v68.8a6 6 0 0 1-6 6H331a6 6 0 0 1-6-6z" stroke="#000" stroke-width="4" fill="#ffdda6"/><use xlink:href="#ab" transform="matrix(1,0,0,1,337.0000000000001,211.99999999999997) translate(127.93827160493828 21.34027777777778)"/><use xlink:href="#ac" transform="matrix(1,0,0,1,337.0000000000001,211.99999999999997) translate(12.444444444444457 48.00694444444444)"/><use xlink:href="#ad" transform="matrix(1,0,0,1,337.0000000000001,211.99999999999997) translate(189.7901234567901 48.00694444444444)"/><use xlink:href="#ae" transform="matrix(1,0,0,1,337.0000000000001,211.99999999999997) translate(257.6296296296296 48.00694444444444)"/><path d="M487 175.26h-4v-34.13h4zm0-55.46h-4V86.92h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M487 86.97h-4v-2.05h4z" fill="#3a414a"/><path d="M487.02 87h-4.04v-2.1h4.04zm-4-2.06v2h3.96v-2z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M485 191.53l-4.63-14.27h9.26z" fill="#3a414a"/><path d="M485 198l-7.4-22.74h14.8zm-1.88-18.74l1.88 5.8 1.88-5.8z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><use xlink:href="#af" transform="matrix(1,0,0,1,425.8395061728396,119.79732632121356) translate(0 14.222222222222223)"/><path d="M597.5 106a6 6 0 0 1 6-6h175a6 6 0 0 1 6 6v68.8a6 6 0 0 1-6 6h-175a6 6 0 0 1-6-6z" stroke="#000" stroke-width="4" fill="#f2f3f5"/><use xlink:href="#ag" transform="matrix(1,0,0,1,602.4999999999999,104.99999999999997) translate(48.351851851851855 26.65277777777778)"/><use xlink:href="#ah" transform="matrix(1,0,0,1,602.4999999999999,104.99999999999997) translate(79.0925925925926 26.65277777777778)"/><use xlink:href="#ai" transform="matrix(1,0,0,1,602.4999999999999,104.99999999999997) translate(34.74074074074073 53.31944444444445)"/><path d="M485 284.8V314a6 6 0 0 0 6 6h56a6 6 0 0 1 6 6v1.76" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M487 284.86h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M553 344.03l-4.63-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M677.23-601v3.76" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M679.23-600.95h-4V-603h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M677.23-580.97l-4.64-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1020.5-1034a6 6 0 0 1 6-6h258a6 6 0 0 1 6 6v598a6 6 0 0 1-6 6h-258a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#dfe3e8"/><use xlink:href="#b" transform="matrix(1,0,0,1,1025.4874894037011,-1035) translate(72.71604938271605 17.77777777777778)"/><use xlink:href="#e" transform="matrix(1,0,0,1,1025.4874894037011,-1035) translate(162.65432098765433 17.77777777777778)"/><use xlink:href="#d" transform="matrix(1,0,0,1,1025.4874894037011,-1035) translate(173.64197530864197 44.44444444444444)"/><path d="M1075.5-877.75a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#c3f7c8"/><use xlink:href="#aj" transform="matrix(1,0,0,1,1087.4874894037011,-871.75) translate(30.592592592592595 26.77777777777778)"/><use xlink:href="#g" transform="matrix(1,0,0,1,1087.4874894037011,-871.75) translate(16.209876543209873 53.44444444444445)"/><use xlink:href="#h" transform="matrix(1,0,0,1,1087.4874894037011,-871.75) translate(44.54320987654321 80.11111111111111)"/><path d="M1075.5-720.25a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#c3f7c8"/><use xlink:href="#aj" transform="matrix(1,0,0,1,1087.4874894037011,-714.25) translate(30.592592592592595 26.77777777777778)"/><use xlink:href="#i" transform="matrix(1,0,0,1,1087.4874894037011,-714.25) translate(43.98765432098766 53.44444444444445)"/><use xlink:href="#j" transform="matrix(1,0,0,1,1087.4874894037011,-714.25) translate(25.46913580246914 80.11111111111111)"/><path d="M1075.5-566.5a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#cfe4ff"/><use xlink:href="#n" transform="matrix(1,0,0,1,1087.4874894037011,-560.5000000000001) translate(16.85802469135802 26.77777777777778)"/><use xlink:href="#o" transform="matrix(1,0,0,1,1087.4874894037011,-560.5000000000001) translate(38.617283950617285 53.44444444444445)"/><use xlink:href="#p" transform="matrix(1,0,0,1,1087.4874894037011,-560.5000000000001) translate(39.69753086419753 80.11111111111111)"/><path d="M1155.5-759.75v8.76" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1157.5-759.7h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1155.5-734.72l-4.65-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1155.5-602.25v5" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1157.5-602.2h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1155.5-580.97l-4.65-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1073-980h165v68.75h-165z" fill="url(#ak)"/><path d="M1062-199.83a6 6 0 0 1 6-6h175a6 6 0 0 1 6 6V-106a6 6 0 0 1-6 6h-175a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#cfe4ff"/><use xlink:href="#q" transform="matrix(1,0,0,1,1073.9874894037011,-193.8333333333334) translate(27.80246913580247 33.15277777777778)"/><use xlink:href="#r" transform="matrix(1,0,0,1,1073.9874894037011,-193.8333333333334) translate(6.8148148148148096 59.81944444444445)"/><use xlink:href="#s" transform="matrix(1,0,0,1,1073.9874894037011,-193.8333333333334) translate(78.17283950617282 59.81944444444445)"/><path d="M980-14a6 6 0 0 1 6-6h508a6 6 0 0 1 6 6v488a6 6 0 0 1-6 6H986a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#c3f7c8"/><use xlink:href="#al" transform="matrix(1,0,0,1,992,-8.000000000000256) translate(0 17.77777777777778)"/><path d="M1062 46a6 6 0 0 1 6-6h170.05a6 6 0 0 1 6 6v30.92a6 6 0 0 1-6 6H1068a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#c3f7c8"/><use xlink:href="#B" transform="matrix(1,0,0,1,1073.9874894037011,51.99999999999977) translate(31.660493827160494 17.77777777777778)"/><path d="M1004.24 358.5a6 6 0 0 1 6-6h463a6 6 0 0 1 6 6V454a6 6 0 0 1-6 6h-463a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd6f5"/><use xlink:href="#am" transform="matrix(1,0,0,1,1016.2374894037013,364.5) translate(131.24074074074076 17.77777777777778)"/><use xlink:href="#A" transform="matrix(1,0,0,1,1016.2374894037013,364.5) translate(215.00617283950618 17.77777777777778)"/><path d="M1033.26 399.92a6 6 0 0 1 6-6h78a6 6 0 0 1 6 6v40.16a6 6 0 0 1-6 6h-78a6 6 0 0 1-6-6z" stroke="#000" stroke-width="4" fill="#ffd6f5"/><use xlink:href="#N" transform="matrix(1,0,0,1,1045.254711758731,405.91544117647044) translate(-0.518518518518519 18.944444444444443)"/><path d="M1143.26 399.92a6 6 0 0 1 6-6h78a6 6 0 0 1 6 6v40.16a6 6 0 0 1-6 6h-78a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd6f5"/><use xlink:href="#P" transform="matrix(1,0,0,1,1155.254711758731,405.91544117647044) translate(10.839506172839506 19.59027777777778)"/><path d="M1253.26 399.92a6 6 0 0 1 6-6h78a6 6 0 0 1 6 6v40.16a6 6 0 0 1-6 6h-78a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd6f5"/><use xlink:href="#Q" transform="matrix(1,0,0,1,1265.254711758731,405.91544117647044) translate(5.901234567901234 19.59027777777778)"/><path d="M1080.26 734.08l-.1 1.17-.3 1.22-.47 1.16-.67 1.08-.8.96-.97.82-1.07.65-1.17.48-1.22.3-1.17.1H781.08l-.7.05-.6.15-.6.24-.53.33-.47.4-.4.48-.34.54-.24.57-.15.6-.05.7v58.73h-4v-58.88l.1-1.17.3-1.22.47-1.16.65-1.08.82-.96.95-.82 1.07-.65 1.16-.48 1.22-.3 1.17-.1h291.26l.7-.05.6-.15.6-.24.52-.33.48-.4.4-.48.33-.54.25-.57.15-.6.06-.7V450.08l4-.02z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1080.26 450.14h-4v-2.06h4z" fill="#3a414a"/><path d="M1080.28 450.16h-4.05v-2.1h4.05zm-4-2.05v2h3.95v-2z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M775 821.07l-4.63-14.27h9.26z" fill="#3a414a"/><path d="M775 827.54l-7.4-22.74h14.8zm-1.88-18.74l1.88 5.8 1.88-5.8zM1190.26 744.08l-.1 1.17-.3 1.22-.47 1.16-.67 1.08-.8.96-.97.82-1.07.65-1.17.48-1.22.3-1.17.1H891.08l-.7.05-.6.15-.6.24-.53.33-.47.4-.4.48-.34.54-.24.57-.15.6-.05.7v48.73h-4v-48.88l.1-1.17.3-1.22.47-1.16.65-1.08.82-.96.95-.82 1.07-.65 1.16-.48 1.22-.3 1.17-.1h291.26l.7-.05.6-.15.6-.24.52-.33.48-.4.4-.48.33-.54.25-.57.15-.6.06-.7V450.08l4-.02z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1190.26 450.14h-4v-2.06h4z" fill="#3a414a"/><path d="M1190.28 450.16h-4.05v-2.1h4.05zm-4-2.05v2h3.95v-2z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M885 821.07l-4.63-14.27h9.26z" fill="#3a414a"/><path d="M885 827.54l-7.4-22.74h14.8zm-1.88-18.74l1.88 5.8 1.88-5.8z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1298.26 450.08V754a6 6 0 0 1-6 6H991a6 6 0 0 0-6 6v38.8" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1300.26 450.14h-4v-2.06h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M985 821.07l-4.63-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1167.46 164.07h-4v-19.54h4zm-12.44-40.88h-4V86.9h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1155.02 86.97h-4v-2.05h4z" fill="#3a414a"/><path d="M1155.04 87H1151v-2.1h4.04zm-4-2.06v2h3.95v-2z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1165.46 180.34l-4.63-14.27h9.27z" fill="#3a414a"/><path d="M1165.46 186.8l-7.4-22.73h14.8zm-1.88-18.73l1.88 5.8 1.88-5.8z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><use xlink:href="#af" transform="matrix(1,0,0,1,1093.858126065002,123.19150315119516) translate(0 14.222222222222223)"/><path d="M1363.26 398.83a6 6 0 0 1 6-6h78a6 6 0 0 1 6 6V439a6 6 0 0 1-6 6h-78a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd6f5"/><use xlink:href="#an" transform="matrix(1,0,0,1,1375.254711758731,404.8308823529414) translate(3.370370370370374 19.59027777777778)"/><path d="M1010.92 194.8a6 6 0 0 1 6-6H1314a6 6 0 0 1 6 6v92a6 6 0 0 1-6 6h-297.08a6 6 0 0 1-6-6z" stroke="#4c535d" stroke-width="4" fill="#ffdda6"/><use xlink:href="#am" transform="matrix(1,0,0,1,1022.9247503806238,200.81240628211117) translate(47.53703703703704 30.27777777777778)"/><use xlink:href="#ao" transform="matrix(1,0,0,1,1022.9247503806238,200.81240628211117) translate(131.30246913580245 30.27777777777778)"/><use xlink:href="#ap" transform="matrix(1,0,0,1,1022.9247503806238,200.81240628211117) translate(11.086419753086432 56.94444444444445)"/><use xlink:href="#aq" transform="matrix(1,0,0,1,1022.9247503806238,200.81240628211117) translate(164.72839506172838 56.94444444444445)"/><use xlink:href="#ar" transform="matrix(1,0,0,1,1022.9247503806238,200.81240628211117) translate(248.98765432098762 56.94444444444445)"/><path d="M1154.45-96v65.28a.72.72 0 0 1-.7.72.72.72 0 0 0-.73.72v44.54" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1156.45-95.95h-4V-98h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1153.02 31.53l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1040 835.54a6 6 0 0 1 6-6h68a6 6 0 0 1 6 6v38a6 6 0 0 1-6 6h-68a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#ffd9d9"/><use xlink:href="#as" transform="matrix(1,0,0,1,1052.0000000000007,841.5416666666678) translate(-7.802469135802468 17.77777777777778)"/><path d="M1408.26 449v315a6 6 0 0 1-6 6h-315.22a6 6 0 0 0-6 6v28.8" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1410.26 449.05h-4V447h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1081.04 821.07l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1084.06 883.54V894a6 6 0 0 1-6 6H890.4a6 6 0 0 0-6 6v129.26" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1086.06 883.6h-4v-2.06h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M884.4 1051.53l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1165.46 296.8v7.2a6 6 0 0 0 6 6h64.28a6 6 0 0 1 6 6v11.76" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1167.46 296.86h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1241.74 344.03l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M677.23-448.5v217.93" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M679.23-448.45h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M677.23-214.3l-4.64-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M579 61.46h106a6 6 0 0 1 6 6v7.8" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M579.05 63.46H577v-4h2.05z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M691 91.53l-4.63-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M691 184.8V314a6 6 0 0 1-6 6H558.32a6 6 0 0 0-6 6v1.76" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M693 184.86h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M552.32 344.03l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M593.23-665H346a6 6 0 0 0-6 6v423a6 6 0 0 0 6 6h133a6 6 0 0 1 6 6V15.26" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M595.23-663h-2.06v-4h2.06z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M485 31.53l-4.63-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1155.5-448.5v217.93" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1157.5-448.45h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1155.5-214.3l-4.65-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M761.23-512.5H864a6 6 0 0 1 6 6v347.58a6 6 0 0 1-6 6h-75.18" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M761.28-510.5h-2.05v-4h2.05z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M772.56-152.92l14.26-4.63v9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1071.5-512.5H936a6 6 0 0 0-6 6v347.58a6 6 0 0 0 6 6h101.25" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1073.5-510.5h-2.06v-4h2.05z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1053.52-152.92l-14.27 4.64v-9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M977.5-275.83c0 8.05-34.14 14.58-76.25 14.58-42.1 0-76.25-6.53-76.25-14.58V-392.5c0-8.05 34.14-14.58 76.25-14.58 42.1 0 76.25 6.53 76.25 14.58z" stroke="#3a414a" stroke-width="4" fill="#fff7a1"/><path d="M977.5-392.5c0 8.05-34.14 14.58-76.25 14.58-42.1 0-76.25-6.53-76.25-14.58" stroke="#3a414a" stroke-width="4" fill="none"/><use xlink:href="#at" transform="matrix(1,0,0,1,830.0000000000005,-372.9166666666667) translate(5.635802469135797 44.52777777777778)"/><use xlink:href="#au" transform="matrix(1,0,0,1,830.0000000000005,-372.9166666666667) translate(25.913580246913583 71.19444444444446)"/><use xlink:href="#av" transform="matrix(1,0,0,1,830.0000000000005,-372.9166666666667) translate(80.11111111111111 71.19444444444446)"/><path d="M738.37-275.83c0 8.05-27.38 14.58-61.14 14.58-33.77 0-61.15-6.53-61.15-14.58V-392.5c0-8.05 27.38-14.58 61.14-14.58 33.77 0 61.15 6.53 61.15 14.58z" stroke="#3a414a" stroke-width="4" fill="#fff7a1"/><path d="M738.37-392.5c0 8.05-27.38 14.58-61.14 14.58-33.77 0-61.15-6.53-61.15-14.58" stroke="#3a414a" stroke-width="4" fill="none"/><g><use xlink:href="#aw" transform="matrix(1,0,0,1,621.0812129129546,-372.9166666666667) translate(2.3024691358024683 17.77777777777778)"/><use xlink:href="#ax" transform="matrix(1,0,0,1,621.0812129129546,-372.9166666666667) translate(23.907407407407412 44.44444444444444)"/><use xlink:href="#ay" transform="matrix(1,0,0,1,621.0812129129546,-372.9166666666667) translate(20.7283950617284 71.11111111111111)"/><use xlink:href="#az" transform="matrix(1,0,0,1,621.0812129129546,-372.9166666666667) translate(15.974135802469137 97.77777777777777)"/></g><path d="M402.3-276.58c0 8-27.4 14.5-61.16 14.5s-61.14-6.5-61.14-14.5v-116c0-8 27.38-14.5 61.14-14.5 33.77 0 61.15 6.5 61.15 14.5z" stroke="#3a414a" stroke-width="4" fill="#fff7a1"/><path d="M402.3-392.58c0 8-27.4 14.5-61.16 14.5s-61.14-6.5-61.14-14.5" stroke="#3a414a" stroke-width="4" fill="none"/><g><use xlink:href="#aA" transform="matrix(1,0,0,1,285,-373.08333333333337) translate(26.9320987654321 44.52777777777778)"/><use xlink:href="#aB" transform="matrix(1,0,0,1,285,-373.08333333333337) translate(32.54938271604939 71.19444444444446)"/></g><path d="M1231.74-276.67c0 8.06-34.14 14.6-76.25 14.6-42.12 0-76.26-6.54-76.26-14.6v-116.66c0-8.06 34.14-14.6 76.25-14.6 42.1 0 76.24 6.54 76.24 14.6z" stroke="#3a414a" stroke-width="4" fill="#fff7a1"/><path d="M1231.74-393.33c0 8.05-34.14 14.58-76.25 14.58-42.12 0-76.26-6.53-76.26-14.58" stroke="#3a414a" stroke-width="4" fill="none"/><g><use xlink:href="#aw" transform="matrix(1,0,0,1,1084.2374894037007,-373.74999999999994) translate(17.30246913580247 17.77777777777778)"/><use xlink:href="#ax" transform="matrix(1,0,0,1,1084.2374894037007,-373.74999999999994) translate(38.90740740740741 44.44444444444444)"/><use xlink:href="#ay" transform="matrix(1,0,0,1,1084.2374894037007,-373.74999999999994) translate(35.7283950617284 71.11111111111111)"/><use xlink:href="#az" transform="matrix(1,0,0,1,1084.2374894037007,-373.74999999999994) translate(30.974135802469135 97.77777777777777)"/></g><path d="M442.5 449v285a6 6 0 0 0 6 6H769a6 6 0 0 1 6 6v58.8" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M444.5 449.05h-4V447h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M775 821.07l-4.63-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1280 106a6 6 0 0 1 6-6h175a6 6 0 0 1 6 6v68.8a6 6 0 0 1-6 6h-175a6 6 0 0 1-6-6z" stroke="#000" stroke-width="4" fill="#f2f3f5"/><g><use xlink:href="#ag" transform="matrix(1,0,0,1,1285,104.99999999999997) translate(48.351851851851855 26.65277777777778)"/><use xlink:href="#ah" transform="matrix(1,0,0,1,1285,104.99999999999997) translate(79.0925925925926 26.65277777777778)"/><use xlink:href="#ai" transform="matrix(1,0,0,1,1285,104.99999999999997) translate(34.74074074074073 53.31944444444445)"/></g><path d="M1248.05 61.46h119.45a6 6 0 0 1 6 6v7.8" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1248.1 63.46h-2.05v-4h2.05z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1373.5 91.53l-4.63-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M1373.5 184.8V304a6 6 0 0 1-6 6h-119.76a6 6 0 0 0-6 6v11.76" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M1375.5 184.86h-4v-2.05h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1241.74 344.03l-4.64-14.27h9.27z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M890.95 631.16a6 6 0 0 1 6-6h144.25a6 6 0 0 1 6 6v33.17a6 6 0 0 1-6 6H896.95a6 6 0 0 1-6-6z" stroke="#000" stroke-width="4" fill="#b8f5ed"/><g><use xlink:href="#aC" transform="matrix(1,0,0,1,902.9468697018516,637.163935830689) translate(3.938271604938265 17.77777777777778)"/><use xlink:href="#aD" transform="matrix(1,0,0,1,902.9468697018516,637.163935830689) translate(40.481481481481474 17.77777777777778)"/></g><path d="M872.47 555.26h-4v-5.93h4zm207.8-41.18l-.1 1.17-.3 1.22-.48 1.16-.67 1.08-.8.96-.97.82-1.07.65-1.17.48-1.22.3-1.17.1H876.55l-.7.05-.6.15-.6.24-.52.33-.48.4-.4.48-.34.54-.23.57-.14.6-.06.7V528h-4v-2.08l.1-1.17.3-1.22.47-1.16.66-1.08.8-.96.97-.82 1.07-.65 1.16-.48 1.22-.3 1.17-.1h195.78l.7-.05.6-.15.6-.24.52-.33.48-.4.4-.48.33-.54.25-.57.15-.6.06-.7v-63.84l4-.02z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1080.26 450.14h-4v-2.06h4z" fill="#3a414a"/><path d="M1080.28 450.16h-4.05v-2.1h4.05zm-4-2.05v2h3.95v-2z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M870.47 571.53l-4.63-14.27h9.27z" fill="#3a414a"/><path d="M870.47 578l-7.38-22.74h14.76zm-1.88-18.74l1.87 5.8 1.9-5.8z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M980-56.92a6 6 0 0 1 6-6h508a6 6 0 0 1 6 6V-26a6 6 0 0 1-6 6H986a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#c3f7c8"/><g><use xlink:href="#aE" transform="matrix(1,0,0,1,992,-50.916666666666714) translate(53.740740740740705 17.77777777777778)"/><use xlink:href="#aF" transform="matrix(1,0,0,1,992,-50.916666666666714) translate(119.17283950617279 17.77777777777778)"/><use xlink:href="#aG" transform="matrix(1,0,0,1,992,-50.916666666666714) translate(249.9753086419753 17.77777777777778)"/><use xlink:href="#aH" transform="matrix(1,0,0,1,992,-50.916666666666714) translate(358.4320987654321 17.77777777777778)"/></g><path d="M670.6-96v10a6 6 0 0 1-6 6H491a6 6 0 0 0-6 6v89.26" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M672.6-95.95h-4V-98h4z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M485 31.53l-4.63-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M593.23-665H491a6 6 0 0 0-6 6V15.26" stroke="#3a414a" stroke-width="4" fill="none"/><path d="M595.23-663h-2.06v-4h2.06z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M485 31.53l-4.63-14.27h9.26z" stroke="#3a414a" stroke-width="4" fill="#3a414a"/><path d="M300-56.92a6 6 0 0 1 6-6h493a6 6 0 0 1 6 6V-26a6 6 0 0 1-6 6H306a6 6 0 0 1-6-6z" stroke="#3a414a" stroke-width="4" fill="#c3f7c8"/><g><use xlink:href="#z" transform="matrix(1,0,0,1,312.0000000000001,-50.916666666666714) translate(38.987654320987644 17.77777777777778)"/><use xlink:href="#aI" transform="matrix(1,0,0,1,312.0000000000001,-50.916666666666714) translate(104.29629629629628 17.77777777777778)"/><use xlink:href="#aJ" transform="matrix(1,0,0,1,312.0000000000001,-50.916666666666714) translate(158.37037037037035 17.77777777777778)"/><use xlink:href="#aG" transform="matrix(1,0,0,1,312.0000000000001,-50.916666666666714) translate(249.72839506172838 17.77777777777778)"/><use xlink:href="#aH" transform="matrix(1,0,0,1,312.0000000000001,-50.916666666666714) translate(358.18518518518516 17.77777777777778)"/></g><path d="M546.14-277.42c0 8-27.37 14.5-61.14 14.5-33.77 0-61.14-6.5-61.14-14.5v-116c0-8 27.37-14.5 61.14-14.5 33.77 0 61.14 6.5 61.14 14.5z" stroke="#3a414a" stroke-width="4" fill="#fff7a1"/><path d="M546.14-393.42c0 8-27.37 14.5-61.14 14.5-33.77 0-61.14-6.5-61.14-14.5" stroke="#3a414a" stroke-width="4" fill="none"/><g><use xlink:href="#aK" transform="matrix(1,0,0,1,428.85623410555115,-373.91666666666663) translate(13.969135802469133 31.15277777777778)"/><use xlink:href="#aL" transform="matrix(1,0,0,1,428.85623410555115,-373.91666666666663) translate(12.76543209876543 57.81944444444445)"/><use xlink:href="#s" transform="matrix(1,0,0,1,428.85623410555115,-373.91666666666663) translate(16.993827160493822 84.48611111111111)"/></g><path d="M696.88 631.16a6 6 0 0 1 6-6h144.25a6 6 0 0 1 6 6v33.17a6 6 0 0 1-6 6H702.88a6 6 0 0 1-6-6z" stroke="#000" stroke-width="4" fill="#b8f5ed"/><g><use xlink:href="#aM" transform="matrix(1,0,0,1,708.8750000000003,637.163935830689) translate(5.820987654320987 17.77777777777778)"/><use xlink:href="#aN" transform="matrix(1,0,0,1,708.8750000000003,637.163935830689) translate(79.03086419753086 17.77777777777778)"/></g><path d="M855.63 647.75h16.93" stroke="#3a414a" fill="none"/><path d="M855.64 648.25h-.5v-1h.5z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M887.33 647.75l-14.27 4.63v-9.27z" stroke="#3a414a" fill="#3a414a"/><defs><image width="1" height="1" id="cE" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAATUAAAE1CAYAAACGH3cEAAAAAXNSR0IArs4c6QAAIABJREFUeF7tnQeYHVX5/z8zt+xuGomAECAgTUJXFFBAwK6gYiNKC0m2JXThhyL+1YhSRAXp2ZINBAGl81OKFBUEpCtdeoCE0NOz2Vtm/s+7M8tvudxp997N3p15z/PwJOSeOee83/fMd055i4EWRUARUARihIARI1lUFEVAEVAEUFLTSaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUouVOlUYRUARUFLTOaAIKAKxQkBJLVbqVGEUAUVASU3ngCKgCMQKASW1WKlThVEEFAElNZ0DioAiECsElNRipU4VRhFQBJTUdA4oAopArBBQUhuh6uyAzGIYrL/CbLBGqDg6bEWgZggoqdUMyuCGZkN2U9gkDxtlYT0DmnIwpghj0tCUhUwBPmzBRBvWA9a34UPA2BQ0ZQDb7aaUvUSRA8qUP3P0M9xqA5YBb5vwtvyZgkXAu3koyO8mrMjAiiKsLsAbKXh1EbylBBmsT61RnwgoqdVOL8ZZ0JiGMU3QIKSUggkWfNKGr2Zhzyxk1wBFh3DqrpiAEGcDsBzeNuAvKbg5B4tMeCcLS3PQOwFWTnHE0KII1B0CSmoVqmQeNBZg8zRslYf9xsJOfTAhBxsCTTakgbQAPLC6qrCrYX3MHb9tQB4opOCdRni9D17Pw63Ag8AL7c5KUIsiMOwIKKkFq8C4ADZpgkkFmNwIm62B7xiwleUsbGSBk9higBBewYClJtwE3G/BSwa8NBEW7Ad9iQVHBR8WBJTUSmA/Fxo2hMY+GLUa2jNwQgHGjOTV1rDMLHcrW4DrGuGEt2HZaFjTDr0jfPE6XHBqvyERUFID5sPoPtg9BcfasHkRJgITgJSSWciZ5FFt4ALDguUGvDUKXl0J8wy4oc35N4W4Ooj16RIEEklqc2FsDrYdBbvn4CALtjdhXD0e3sdxxrqTLmfAC1n4Uw7uNeDhFliiq7g4anztypQIUpsN5ocgMx7WKcKlOfiMmFPoEmHtTraA3nJpeDQNh1rwysuQU7OSutLPiBlM7EntIvhWCo6QbWUKtlQ7hPqem2mwC7DQhBctuGExnDcbCvU9ah1dPSEQO1K7ErLL4AvAAcDXTNhI34h6mnLhxyLXyga8Y8PNFtychj83w4rwLWjNJCIQC1KzwbgQRqfg11k4uAjj9XwsftPZBLFd/lMaZk6DPr1kiJ+OayHRiCa12ZDeBGaKxb4N+wKj9JysFtOiftsYdJt6RwpuWQhn6dlb/eprOEY2IkmtAyan4Ms2HA1sqauy4Zg6w9+nbE9tx7/1VAtuaYdHhn9UOoLhRmBEkdpFsHEafpOCg8RnR0s0BETZA+4Pg//unl19oDFZ9Xr9V28fEnHtsOBWG2a2wkvRkNHacUJgRJBaN3zehNYCfMOGpjgpoBJZBghJnEulrIF35LYwBS8X4R1gmQ3LUrAUJwpHrheKFqxKORE5etOwxoDVOSikodAIufwgQ9iiw38SNSRtQsqERguaDGg0YbQNYxqhwQJDoowUYJwJ6wDrpBwPjI2KsKkBmzU5kUj6nUeHmgwNKKbhxjz8qR0urwRffWZkI1C3pCZhejaGPWw4SbaaSbvBFEZJOUSwzIRXi7DEhCUZWJaHtyy4JwcPHAMLR8IU7ISPArvb8OkMjM3DOkKCNqwLbJxyL3dqRXoysVNwZxFOt+Fv7Q6nakkAAnVJavPgIxZcX4Qd7YQ4jAuB2ZC34ZU0PJODKz4E17wO1rtutKKfO87jsbgLkRvrXzgh4MQwOrUhmEvh68BhKdjags1kdSgrvGoENsAyIVeE3drh8QS804kXsa5I7XzYfl34nxXwfRsa46gdWYGZYBfhFQP+m4W78rBA3ISWwSvLIZ90Y9MrIbUKMkXYoACfGAWbrIF9DdgW2MqAdFQjagmd1AC39cGpbXBvHOeWyuQgUBek1gWbAG02/D/5gsdJObICs+BdYFEGXs/BX4FudeauSMtGh3PGd0AaDsnDJGADw4kUHDb4gJ2CTuC3LfB8RaPQh+oagWEnkDnwXRMucQMrDvt4aqEt15YqZ8KDFrTm4NX1ITfFOdepZjdVi+HFpg3J0yCXGWNh1Er4len4jYqtYuA8EkPeFBz3CnSpnVtspsTwrtS6YFsDOorwmZEOqfsGrQb+k4XL83DfSnjhB87to5a1hIC4yC2BSRn4pOUYZO9nO3keyhY5CkjDI3n4+Wtwk5LbWlLUEHcT+EWrdf8S9seCo234VZgvaq37r1V7cgAtiUzGwjMroKsAfznCCZ2jpU4QuAka3oCPGnB6AbaThDZAYynJiS5TMK8AP22HxXUyfB1GhQisVVITQivAkzhnISOyyNfdcg72v5WBBdNgWVxuJEekQkIO+gInIc6EPByfgeNK7TvcF2G5DQe2O7kXtIxQBNYaqXXAKQb8yIbsSMNKbiuBhzNw3hp4aCY8rWdjI02L/zfe82HdUfBpG/YvQPvgC7MUFG24Woy9NSLIyNTxkJOa69p0uQF7R72GH2ZI5ZZM8mT+eQ2cPQueGObxaPdDgEAHrJeFQ2yYlYctnWO2/i/vS30wpR0e1pX4EAA/hE0OKal1wP4mzLechLwjpmTgVQtmFeF+Tf02YtRW1UCvhKZlsDVwqgFfcz/A8sev2+EnVTWuD69VBIaE1MTFaRM4yYKTbSc3bt0X+TwX4UrgL2vgymM0tVvd62yIBmjMgc+YsH8Gfui6512XhoOnO/HctNQ5AjUntQ7Hp++3NrSMBIOsFKy2nMQfx7Q6Z2VaFIF+BMREZCmcn4JvFR1n/l11jtT/5KgpqUnOzFFwXxE+Vu+iSyx8C/7YAD+ZqqFq6l1dwzq+LtggBUdloLUXjmyDa/WiaFhV4tt5zUjtPNg8C/fg2ALVbZFtpg1XFaBnJtxStwPVgdUdAh2wS9oJgfVyO5xRdwPUAfUjUBNS64KdmuDRVXUMqnuD9YwNre1wdx0PVYdW5wjIjX4G9ijC9RrSqP6UVTWpdcKuabglX8c3nBIM0YAfbgzd++kFQP3NwhE4IjlqaQBLSa3+lFcVqXXDngbcWHAintZdkXAzKbjSgpNaR0gwxboDUQekCIwwBComtXmwYwoe661fgd+2oG0WXFerIV4Mv0jBz4LaWwmbz4IFQfWi/j4HthvtuJn5FtlqW7DTVDUYDoJKf48hAhWRmphtZOG5HKxfj5gYcHsRDpkFb9ZyfD1wQx6+EdRmGo5qhguC6kX9vdOxfP9D0HNpJ8P5jtM1SkgQVPp7DBGITGodMNGAB2wnsGPdFYm4YMBWQ5BRyOh2kpaMDhK6AR6YBrsH1Yv6+8VwYR/MCnouBX9vgc8F1dPf1w4Cf4f0Q9Aw0Ynoa6SdEOP56c757kgw51w7QNWol0ikNs/JKHRXAXatUf81b8YV6Kdt8KtaNn4RfNkMaQKSdrI77TAdXq/lGHrgnjzsEdRmBn4+A04Jqqe/1x4BcbdaCWNSMHENzMzA/jaMLkLGhrSE23JDHcl5b18O7pdACUV43IIV7SAnOkp0VagmEql1QIcJbbXK+FPFuH0fHQNPHgI71LL9LrjcgoNCtlk0Ya9WuC9k/cBqs8HcGJZaMNavsoRAWQ0Tj6wxoQYOMOEVLoQtRkF3n2OnKdmxJG5gIDu5UZL7kzIDC+XooBeOOnIIvFuuhTuXh89S+J9p8IORqNawpGZ0wUwbLhgJgR1T8FYedqjVmdpZ0DQB3sgFEMrgCWDCD1rh97WaFJKVHufgX9IeeBYDnm6D7WrVb7XtyOrehBl4bNub4D9T4LZq+xmO52VejIFDgalp2KtWOfjkw5SHB9LQlYfL2x3Cq7r8EexlIVtJwW0t8KWQ1euqWihS64Adgfslj0Bdjd57ML1Z2GU6/LcW4xXTFQvulOQeEdpb1g7jI9T3rdoJRwPnBu1LTDi1Ff5frfqttp1ux37xiaKHp0kjXHg4HFltP2vzeVk1bwh7ZeHSPGw6lH2n4JUCfH+ms+oPUr/vUKKQmgm3t8IXh1K2oWo7kNQkuYUB/7Zh+6EaRK3bFZOGFOzZDP+qRdsd0AJ0RWnL/dp+vA3+E+U5r7rzYXEvbOjXlsz4BmieDj216LMWbcSN1CT+mpso6LOSsb4WGAW1kYJVFtxiw9RqVm1Kai7SXU7EjROq+kQEaS3C7ylYYkBTwScvqHtOcVErHBGhac+qXXCZBQdHbatWW1C5cW6ABX0BUYMlxlMRJjfDM1HHOlT140Rqc2EvG851AzYELghqial8qE34RxGOrTQps5Ka7HWgoRGW1kti4SwULZhRhO9JpiC/SSMv+OFgVhu1VLYam0ExV8EMNeD8NmfbWFXphH1s+JuTB9m3LG2HCVV1VuOH40Jqc2DnFPwz6KKmxvB9oDkTXkrDdpXEdks8qbmJKh7MOwfUw17kbTbg+BY4uwcOzcOlfoOS+vJFnQmPVjP4OTA9BT0V3vguboeNqulfnu2E7wOXB13SpGBmC3RU218tn48DqXXC1wy4xqqT/BopeC0Pe0b1Wkk8qXXD14uOi1GUw/Favg+lbfW0Q7P8o3g0GPCuHbByycDBM+CKagbVDXOKTnKOyEXCHOVgx2rzG3TBmRacGDAACdK6S6Vbk8jChXxgpJNaJ+wh/s1WDS99QkLnW00O8uV2MspOJNGkdiWklkGfVSeEloK7x8G+U/oXX06ZC/cVAqz2Dfh1G5xUzSTqhluL/rdAQib9yTrKlUY453A4rpoxdEGv5XOGKG2n4A1guxZ4t5q+av3sSCa1DhgFPAVsVi0uYnArWcnkIE7Opy0wg1beQX0aML+t/5QlXEk0qXXBcRacHQ6qoa1lwGtF2G0WLBrcUzecUYQf+fWehtubq7yWngurC963XL0GHGbA1V7b0ww8/gp8rNLs3+LEnoEn3Vj5nuKm4f4Z8OkoX+6h1ZzT+kglNbn1T8FdRfhUJTgN2Jpl4Oo8PGPAojwskXNhCQ1uwoaNsHEvfBfYH8fjIFIxYMnjMPG8kOG0EktqcjC+iWNXtG0khIegsux78/CVWfDX0ua7YKoFl/h1a0DhNWiaDUGcULaZLpiO/3naiynYteiEAx9XrpE0LLNh5xZ4uRKI5sLRhf47G/9iwrGtIeoFtVPr30cqqXXD4UW4OCoeRv+JA3c0wGGHwzthnp8H4004LwcHVHAR8cJimBxmjieW1MTQ1oDHon41wigvSh33vvyKNg9Tig7YMgPPB1lx27DrTHgoSt9SV7YGPXB3wcfXMgv3TYM9OuERPPIyuOYlX2qt0GpeXNOAtoDxy7Zmchs8G1XOoa4/EklNbv2bYLEV8SZZdJ2CzzXDPyoxlJ0DnzTgwSg6cfv8WHOIC7FEkpqkttsKnls1xFbSYZSWhlczsO1U8IwSPhdeKMAWfu2Z8OPWCuLJy+1vI7zlZQ8nq8giTGuHSy5xMrcf5TWOFJzfUqFpRw/8LQ+fDZBxUWudRk0ZiaQWpM9yujDgeQPk4yWr9orLPJhcdOzRNgjbSArOboHjg+onktR6YPe8kzxl2G88DTiuDc7xU9RcaC70H9t4FznTmgE7BSm89Pcu2Bf4m+Wdx6H3dhh7FRQ7nFuov3qtbuUQvyXAG8BrfJ2wwoYxfuPPwmnT6zTh7kgjtQthQhqetiOQSgZeWwW7Hg2vRZ1n5ep3wXdtuEKieoRpz4TXF8Fms52tr2dJJKldAoeuCbD/CgNyDeq82wbrBR16d8NuRSeJSsarzwZ4pw8mR8203gUnW3CqV7uyTWiD3eR3MTGxYbF4OpSr75p27DXL+WCELpLQxgqxrTDhwFa4OnTDgyq60T92kDNUAxqL8GYf/OsHNQowWQtSkwgYadjbhvEuzndE1WdYbLphb9fPN9Qjsv2z4MCZFeLv1UkXXGU5lwiBRVYgJmw5A15UUitZhcyDxbkKVxSByEeokIEDZ4SYJD0wyYLHij42RJKnIA2fmuGce4UuXXCnBXt7PTAKZh8Gv3B/lygm91kuyXkQ2xnN8OPQA5AbCvhZ/v/6KPuovFRp2H6GY3rgW1w/3pkmfM6Cj9iwedrNLzFweyvtieFyof+OhpdlW2XDXa/Bryu5wa2E1ObA3lnngkQuqz6agkyZ8Um29JdMeCYP82sRtl1MONLwRiFgZVwC8l1tsG/QBzhIN6W/d8GnDPjXezZMwQ2c2w7HKqkNIrUu+AxwV4WW88GQh6xhQrEPNjgqxM2RHOZfBk+vgm18mhefuSlRVjIyuU1Y6bX1lJfehq+0DbqV7YJv23CN1xbUgOva4NshYeiv1g3PFmFrv2eaYMVUj5vXgefECVsS8ebhBBPWjapjkdeCJWk4eSxcMsUJZBiqRCG1Htgi72RE/0oxQvpGWQkX4ck0nPAK3BHmJrDc4Htgn7xzyB+qGLDchvWGIqOUfIBMeMGCSWEGMxZuPBi+pqT2flL7qTXM0VLdVcKvWuCnYRQpdTrhxzac5lc/BWe2BNi0DX6+A35gwlleL7+s/hphwuBLDLmNxdkqeoX7fqM9wipYznbGwjurfV5u94Z4VhvM8ZJfwiaZTm6FdcNiGoDl0+PgY1MCzm8G2ghLat1wWAE6vLbwYcburpb+tw2+GaZ+aZ15cHQuglmMCVe3woGV9BXmmS44JQU/DWOJYMLDo2H3wQbqpX0k7kytB67Nw7fCgD2EdZYvhnWjfGndr7uYMnhebmThnemwXthxd8MNRZ8EKyY81AK7Dd5yyG1pBp6wPazP5dAvD59qd+LSBZZ58MU83Oo3ocUmKg9bHQmvlmuwCy5Mw6xKnPH9Bmg4QQ6+EkaWIFIbBefn4EkbflOMtu0rO0R3VSkfl33aIWxMxP62uuAhCz4RqBzXhaQIB7TB/4apX0kdCQ2+BLa1QsRRM6BvphMt13PKJI7UOmGhDRtXAn6tnjHgkddg14hnN3Ke9ZblsxIR6+4cbNseMmhkJzxqe9yYyktjwgHNZSZzN9xdhD298HA9HCSaaODHt9OJNHyRH7amY0slcr3v5XXdey4z4JuBHVWuPDlz+0SQr2kQqckWKwNbSgaSWhYh3j7YPuyNpGCWgpURtr3vttdo9VtLuf3aShSpzYbGjWG1j/nCWsE9DVc3V7Ccnw/ze+GwAAIIbXHfCQWfKLfLirD5EbCktD853E3Bv3wMghdmYeswYWO64FwrwLZtHNz9fdi79JB6DlxgwqxqfQuDlJ6FF8Vh3y9wYRCpBfVRze8Z+McMJ6tWILd3OLaAEt4pVDHgnLYqfXpDdVTDSokitYtgT4kVNdQvgZ9+ZO9YgH1mwl1R9dgNxxaD8wGc3R7CQLEDTpaQ2D6H6eKdsIfX4XAnvCWHx+VkMJxY8xINN9Dyfw68YvgcEruO0T9uLzEs7oQZaZgb5Gnhnl8usOF2w9m+rjEgnYcJKfgI8GUbxgaxQRqubIbveemsUlKTTEs23GTBi7LqkrsAycpkwIdt2CsN2wb5vrk3w6Eya3XDD4pwVti5Z8IRrQEr6bBtra16iSK1bmgv+hw2ryXQC4th7GyQq/pIpQd2ycPDfg+l4frmgDNDiU6yEl7P+5y/uS+xxDcr+753wZ8tj1so2bo2wtcOgxv9xnourD8e3vS7YjScW+JNB2+vzoIPjYVHrQDvAsPxQ730Nfi511bfvQE+23a2sB/2Gq97WeF5thSV1EQuA24GWlqdyCNlyxz4thyiAzsH7DCWZWFyULrCOXCNEeF2ugEOmDaE52mRXoCQlRNFaj1wXt7HzSckZlVVM+HFdeCjfrc3Xh3IgeoKWFnwia8mq6S2gETEXY4VuZxTlQ3VLIf9OfjCTLjDaywXw2l9PvZoBvy9LSDRcKeTOOWXfqukFCxeCJsMkJKssufBX/IBEYFNuGMlfDesca0bk18ivnoGCzXhz60eFytRSE1ulW2YMgH+HGYeSDandeA0y4kq41eubYfv+FW4Au5dDp8OM4llV2E5K+6a5J8I02ct6iSK1Drgn8BetQCu0jZMeLDVx3g1qN0uuN6GA3xclWQJ+ImjfIxw58JXC3CTV1+Seq/FZ9Uiz3U4W6N/em2NxLZpa1j3sz6RQ7rgUstJveZZSuO0iUmJCf+xPG4Q3e3qVTj+qpFSrl0EG6fhCa9AifKSG7BHuUQ3YUnNtTULdI0rB8hc6C64AUTL/e5+oXZogyfL/S4Z1F+DB1bCx4Pmmfw+Cuw+WK/S2HVig7Z4CFwRx4FxvI8NYaJIbQ4sNIb/5lPsiw4IM6nK1ZkPO/TBY35bERMuaPVZkc6DM3I+9mwmzGt1clh6FlkxdcJKZ+5/sAgB2PD5Vo9DaXm+G/5uwT5+/RhwUBv8caBON5xW9F8h3tvmczMbhLtsRyV+l+0R0tqEy1vhkNJ2wpKaARXrX1y9toDXe2F9LzlM+J9W+F2530W2LDyS8zfifu/RcWAfFJwvwhPSS+HCPMwKwjzq72Ig+T0fu8ZEkVqHw+6NUUGsZf0UdLdAa6VtdjiRRR73imvmtvufdtil3HmYG0fumSJs5TWGNBzTDOcFjXEuXFvwOb9rgvOmwjEeL5jschcTYC4gZhCDfP2MDngbJ8fmB4rrGxjKlcpPtovh5j74ikcf4lK1YzOsGPx7GFKTczQb9m13/HgrKnPgIAMucxaNZTH4d4uj+w+UuU6S6kcLsHmYzpvAnloFqV0MF/YNAalJ1INDlNScCdAFeStkRIAwSq+kTtAqKqhNmZi2E9zSM7lsA7y7HDY/BpaXtncRfDgNCy0P53hhmgLs1hYi3lUX7GfDjV5bYRPuafXY7s+BrTPwrN/NXhpWrYJ1j3EjnnbCV1Nwk9czGbhqBkwJwjDo906HqK8tJ5d7m7pLC/w7Kqk1wBMLYOeI9onvG64YYUvS5LxHUAEJGJqGjWbAW6VyngvjRsNjhZBhu1NgtyipBU2XYfu9n9Q6nDOWtZKY1UtSE+a2OkmDKy7z4F85n/DLMrFN2LMFHijtpAtOsuF0H9/N3jaPLWVpWxfApCw8brnO4qW/S9KYNo+VWIdzC+2Z6MVdhrzPRupiOL/PI8u5+NJmYOdpHudJUcCWaCQ4YdXLuoKVyw4fZqWWhh83VxDzrnTs3fCy10dNcMvAl6aXCdYZdaXWCLakX4yC3eC6ulKrFLlwzw2QmtgpbRLukaGpVc2ZysCILoRPZOEhv8gGJhzeCvMHSyHnWBfD7TmfW8k0dDUHR6DtbzYoq73rz/WFlpJbVNkCb+S4DHneNMpWLQ0TB684OpwX9QvlNJOGl9fADkc653zVFtnmSngbsWP7QBH3sVbYdfAPQaQmFwS9sF6YAAZBgw+yV/TKwyq356vhEQlRFdSH/F7tmZqSWhiUK6/TT2pz4C7DidIxbCUNDzZXcfspA5fIvRvBm7bHCknqmNDdWnJ255KQhNgpu3V1/QnFJShs+CK5LPijmCd4AWrCf1tgu8HeAO6KYbnf1lNszFbCtoNvuTrhKds7p4SYHexWq0gS3dBZ9Dj7lATSCyA1eBsZRGoGLG6rQW5UwVnS2QF3exmRN8Aj08r4dop9Yt65/Sx75laqQ7n9XAbrV0rESmpDSzMDZ2qBLjlDO4x+snlpHdg6jH2S31i64AGrZLVQUn9Be8mB8K9h7HgntVzZSKMmvGHBFlFMISQ6huHkOPAqS8UZffCLIa46phNt17MYcO942HswTnLbKtb25R4y4AUDLrJDuAoF6VjGlYE9Ch42X0JqBdi6BZ4faCuI1DJw3YwIRq9+Y3Qvi2QlWTa4wVh48lnYqdzZ3RVwz3KffBSD+3VDuUf5yL1v2EpqQTOtut8HSK3NGv7M3hV7FAyG4Ao4bbmPaYO8eCtg48GW+B1wqgEn+5yn3doKX4kaCLATXrNhooeKcjbsNjiDfA8clfe5XXUP489qgRMGt9kDtp9bVNnrwCrmjc8FiLS6f+sgW78gUkvBhS0e54FRh+h6QSz1uuwNSIivAAAcFElEQVRpguffhp3K2XJ1wh/sMiYpXmNIwbda4PqoY5T6SmqVoBb+mf75fgHskfFZtodvrvKabjq8z86KEKSvXG+d8A0DbvCJhSarwhNb4LfyvDjzT4Jevy2fCWe0RoxaK213wzxJzuKxgpJl4bQZg9L8dcEfLJ8XS27dhCQHuw9JyG/TMUeoi5KGtub+C3WnBJEacGZ7hFh3QULOhb6Chy1dI7y0EnYqd77YA235aB/249srzI07F35bCJmEWD6ktpPVKjBfgZp0OLOjn9SuhOwyWFMHUTquaQ4Zl91rcruJM8Sp3DO+2mAj2i4nXpVnKGyZSRbs3AqPBb1Qpb/3wA/z8Gufr/2zLc7hdP/ip8MJjeQZxdeAZ1th8uAVYydMMeFPEcI+RxUjUv0GOGpa/3cyNKn9rB1+GakTn8qVktocJxG05JAItbANY4hdK5k64BVCRMBVUhtEavLXLnglbOjgWimrtJ0K46m9rxk3kchLlo+9mgm3tYLENZNLku8aIO5DZUsKXmjxMcj1w0JelCzc67U1lCCPRZg0C96cD6MLsDzvYyqQgp6WEnegDjjShPOjhugeKh2m4QfNgyKmBK3UUvCjFjizVuPphr6ix0ptFDxXgJ3KhX5yP+x9YXFsgFXTahDUMoTccjMvwQsCyVZJrYTUeuCafI0ObEMoqmwV8Yt8LWLk23INdTnW+uf4TNA3290UaPPg3JxP3DITftHav0utrFwCb63xDkUkM/WbrXDDHPifFPzG76VqgoOmDnKNkhF1wrEG/D7sy1iZFOGfysCJM9ytvTwVRGp+7kvhe3Vqul4hvV6ktg488V8fI99uuF6i2Ybp181TcUJbhHBFYdotrdMBB6fgsjArcSW1ElKTyBB2DbcBlSjQdbqu+ozlAtgq7Wzlym5BJRLuUpiwDJZvAp4vgciQhu819+/QKytz4dQCnOz19DjoOQiae+CmPHzVq55sg8Xivd3ZirxXOuEwA+b7nCHKhYTc7AaFRqtMwJKnXAPc0NvPWpLaZTBhlWPSU/b8qQkenQof8xK0wzF69sz3UPqcAf9ohc9FvUCKALSs0q5dA98MXKbhLBvVTWrQklZMEGy4e7i/+GIBn4UNDg+RTcprcvwBxvU6zu2blasjEyTVfwnF7wuOW0/ZOVPORCHChOyvKrhaziVM2SL2alvBjs/BfbZPfHyx55L8B6X2ZhfBx8UZ2+eiQOLM7T3BJypIVJkC6hcHm5sErdQM+Gkb/KoWY5jj2P2J/29Za38DLm6D6V59SVy+Ajwclv1NKBRg36j5XMPKOg8aC07ehO3DPKOkVrJSk/+dB4tyNTKEDKMEn1VJVauj2ZDeBO4r+pBECsR5/Qbgh17jaIBXp/mczYWR8QLYMAtPWc4N1geKxHkrwCYp57JiQy8SFmft1jLhiNw4apbPud3T4yNkfwojU5Q6QaQG/K4d/idKm15158I3Co5Oy+EsTDe1JSBZ93x4qtfbkPkD7aZhkeSzqDQMkZ/c4kMM3Bh2oaGkVobULoaD+uDyWkywKttYIr6R1SzrO+B8A470ia+2ugmeXulDfA3wvWlVbD0HMJgPD/R6GATLkiINX7LgVq/Vluyl3oZxPyqJgDHQfocT7lr8Msu9dAsKsH0Uw+Eqdfe+x4NILQsXT/dZPUUZS4CtmSW32LPgCb82z4PNs/BC2FtQaSsLp02Hn0QZa1BdyU4mgUCNCJcRSmplSK0DdpdrbT9ziCBl1Or3FBzfUqEdkIxBTDskKkeA/ZZ8BL22KuIIvklQGOgw8s6FUwo+uUzlFtQrTpm0b8BLNmzj5erkl9rNhFUp2GlQmKIwQ/asMxc+XfTY1qcg2+yshN77lgSRmgFvtrmXNtUMTKLgrgeLej1WxCb0LoLxswPylUo74+HhfITVmuRPMOCUthrmzZVAoTYcGnYrLNgpqZUhNdm2bQXPrfJwWK5m0kV9NgWSeWny4ITBUdvodPJwhjqPKG07Dc+/CttGyUHqNT4598rAI2FusDzauLXNx6OhE662PVyXhLFTcOAMuDoqfuXqd8G9tkfY62wZM4cgUpPxGbBXi2MjVnGRTF6WE8G57CVBGq5rDnm7L7HZTLgsYiIiiQAzcwVc7hd9NkhANzO75Ibw3GV4taGkVobU5J8ugh1S8HiUL0SQoir53b0Jvaa9CmPcTrjEhqkV9n9dW8iXIEz7nc6tnGdkVr820jCv2SfibgecIgfuPlvtRxfCLtXEK5PxyQXMSljktSVKw2XNJed+QaTmyn13e5UBFebCzIJPdicDfDPZl+LfCfeLG1sY3ZbUeWgx7F4J1m504Ze9spEFjaWWpCY5ame4tpxB/Vb7ezXHTOX6/sCtn2vr82gRdqh2sNU+76bN++pMuKWStrrgRKtCw840HN5cEqKokjEMPDMXzizAiVHbkBvYlbDNUT5p9WSrnYG3Le+ttKyGvtMK10btf3D9y+EXK+FnXkEijTJhysOQWhpyJuw1PUQAznLjlw9xBh4sekRvdj+QoZNZSx+d8DHbicoSxprivWG5ld9qgH/2wkkzHed+zzWCrAYvhC1HwWk5J4S7Z+auIN3VktQMWGE7YaYiyR80xtLfbVg2E/aO+pxf/bID7oSjbTi3lh1V2paYMqyB3Y6BhVHbmAvbGPDfoByYpe3KlkhuJGc5ARFrUrrh8KJjRhKpSKihthDHAV3wJ8s/1NEjFnyq0hBEF8I2aWf1UvZCIgUv95WJ2xaG1AQQEx5PwefLRaYNAEzCPF3ltf2WZ2XV0QxfjAS8Y45zlA1neTnIB7Xn2hZK3tKnDXhKDv5NyFmO98gkE7YtwuQsbJwLaizE77UktRDd1arKO+0+KSkr6aQsqcnXQ0J818OFgTvh710E+1RwviVBDSV3ZKRtnwn/bg0ZWyss6PLll3YrOFc7vz0gU7uMocMZ7/1+js8mPNbrfCD6wo5b6s2DHS3HFq7seZUsQzJwVnNJ9BB5NiypuXq+vTUi+fTAGQX4kc9xSW8GtpnhJGyOVOQ9uARu64PPR3pwmCorqTnAey4txUbGcpK1ejqGr2XdXdLuEfHCbxzdML8Ih0UZq+kk0p0b5ZmgurKt3xTezAckVCltx4QZrf284l+k/YnOQbkESvQrd6Xg5DAH825mq58DR1o+X1MTns/DbkfAktKOI5KaBA8QY+hjgpKwuIE955swpejjL2vCvyQzV6UrVEmftwCuzoV0nwrSUzW/u9tozyZiQmqSTe10y/HUeF+x4IkU9NqueZQJra/C4xPhQtNNqNQEx3uS2m9g9Lpwf77C28NqlFfuWdfX7sS2QX6FYfrohH3EnSWsAaO0mYJ9WuCuMO1HqdMJR9iDIlgEPesmT95+pk8UkcFtiG2TJG3xieHWX929cexJwS298GIWXhoHy54CYwP4UCNsI47fFpxgwOZ+l0YygQw4sNXjdjUKqQ3I4uYA/aNEH8nD86azysrnYHwjbFmEXRvguFxA5AoDltrwkXZYFoR1wIdRsnRdZ8Hew3WBJltoA9bL+7h5xYXUOuGHNuxhOOY5e0mgUzeSzn+FvCwndL2dgtlFON1wkkpvY0FqFOzvewh4LjQ0wrt2yIQj1UycMM9mHHugtunQE6a+1OmB9QvwjBuTKvAx8QstwIaDY5YFPhSyguvGIwoQvgpTVrcHZJUvbaQHptvQEza+mrj6ZCGfdtLUGQVI5SBrh08s0r0Y2r1u+yohtcEypSAv45N/kxVZPuTYXLINtcoNowgxd5oINxrwpbVNbCm4ZyHsO9GJJvNNr/HGhNTeE+8CJzH4nY1w1uHuJVsX3G7BZ0x4txHueR0OHwfLJdl2HnYKJDVpvRvOsPzPLMLMiZrVSTvp7VrDOpm7dj/3WvDJMIMQP8rpPl4GYdrwqiMO12vgKSHNMO2k4PyWEOdppW11wE8M+GVEO6swQ3pfnTT8dRUc4HdGF0RqQVuqyIP6vwdOk8AdlW47vfrtguNMODvsR6OK8fc/asBfTWhvgZfnwZk5nxv0BJHabhm4yXL8qk/KwB+KcE4Bjg1Fau7ZxYM27Fytgmr1vJg5FMNHz5DbMbHO/kD28NLxmGCb8PFmeLRWYy1px7gU/rYa9g1q391u79BWWWo7Yw6clYKZ1hAlqU7BP4rwpSDS8CM1WfE0wi05+GKtLqXcSLFyHnpE0NiCdOD1+9nwkTGOuc9nohxrROlP5DDg5ixMHQjucBF8Pw1XePWZIFLbPQO7W04QCLlNXpOBU3LQEYrURBGybTJBiG1UFMUMZV3ZkhTgJ63wm6B+JAmvCdcG3TxKPLfxsP6UAFeaoP78fu+CNhs6grYwJrze6gQXCKrq1Z2Erfl2Hq6u5YvnGkrKR6IlDGkEkdpoaF0Fr6Xg+kpNJwYAcDPRH/8KnFOJ8WsUvcoFwvOwlwV/MuDDlSqpXJ/u1rl9EXQPlkNCz28Bvb0eA00SqVkwOQ23WLBDGlpsGFOA34cmNcGwG1qKTgz3ipO4Rpk0IesWDLjAhhODXrC5sLIQcD6Vhoea/TNRhRyWd7Uu5+D9uaCVSQpuaPE5Pwk7kC7YRLaiBnyvUEXCaiEMyzEZ+VUb/CVs/0Gk1gSth0N3D3yh4CSdmRyVIORiwYY7bCegp9wAr7UiZ4/djp6mWLBfCsYGfTzLDc61aXs15SSAOcfrTLcLFqTK+N4KZkJq3/OxaPiTk9qv3opnYu8L4TMNcGcWzj7MNReaC38Dds3B5NEwrQCnWPCllGN2dHbGyVESvnQ4V6ezavnlD9+7d80sXLUajjkSXveq1QW/tWFPv/5Gwe2H+jie12Ks7gfi737bQlkNpeDyGXB+rfoUcrPhctuxWN80BU2iRx/vgP7fbMcAWWK5nTUTrog6nnNh3FgnoUzZ0EtNcObB8OeBdrthThH2NeAjBjSUm2vuV9W2YLH4CFswuw1ujjq2oagvkWqz0JYDuTEdC4yXP1OQGvyyFfpPUPpNYN5OO6Y+58ys0uNjKOQZiW1GIjW5DR0FdxQDyGE4gDBgQR72PtLDyFLsuLYLcPk4EKxa+6GVw2IYxyLGyE0mjM3AVnmYZsM+DTB6gNz6YJnhrMiuK8LDJqz8KKz6bBVBJv0uLMrhLT6QWRhXcEIyTW10Vm+GjDEHz5hwTQFuNGHJBFhZba7YIZivxrmQHQ3ZAjTIbfI4MFJgyA1uExTfALsJ1oyD3qegb6i3y0MgY902GYnURIou2MCCB+RrX29SGbCsEY6bWoE7Ur3JouNRBBSByhCITGrSjfslfSlXhfNtZcMN95QBfzfgoKGwNQs3Aq2lCCgCw4VARaTmEttkiRzrdRMzXAIN9Gv0B4tlZhtcM9xj0f4VAUVg7SFQManJEC+B3Qrw14JzGFp3xQAJ3Hd1EX5UmoWp7garA1IEFIGaIFAVqckI5sDODXBHLqKjdk1GH74RWVCelIXOcolswzejNRUBBwGxU7sTLD3gr78ZUTWpiUg9sF0Gnlxdf/K9NyL3lu05oK0N7qzjoerQ6hwBCRyQhn3a4Ka1cVte53DU3fBqQmousU3KO3HmJ9WdlIMGJEaOluNdcPHMQfZR9TxmHVt9ICBJshudsOGL2qtIClQf0sR3FDUjNYFoNmQ3hbvzQ2yVXwt1pMG2nXA5EltMQi5rUQTKItAB69nQOgZm5uDIGXBjFe5rivIQI1BTUpOxSnKO1fBruXmM6u4yxLKWbT4Fq4vwoAnHtMJjwzEG7bM+EXAjvJxuwqFFJ1zUp9t8ckXUpxTJG1XNSU0gdCeDBHqTDEcSVKPuixuY8BoD/ncFXFVNmrO6F1YH6ItAN3zchm84m4/+cqUFhwb5Fyus9YHAkJDagGjd8BXb8ftbtz7EDTeKDLyeh1kZuKeCRCDhOtFadYXAlZBdClubcKzE6xPHTAPyFvx8JpxeV4PVwfgiMKSkJj3Pgw0LcJkBn6skesFw6c+NZ/VuBm5c4zhzD1WMteESUft1dhXrSLLnLMzqhZ0GEtdIMuscTJnlhIoeCScpqk8XgSEntQGk58DPDDiZEbIdHTxDXJAel4xJOXi4DZ7Qq/yR+w65RPZpyUWRh2MGxwlMgYSzurwAs9qhnq2URq4Chnjka43URA43McgTdpl4UEMsZ82al7A3FrxpwdfHwXPPwTI1wKwZvEPWkPgrS/gjAw5NwxmluwY3rPgyG74wEx4asoFow0OOwFoltf4TVxizBI4CJIb8Wu+/Voga/dzGu6PhmVVwSQ6uPQreqVX72k71CLgXVltZ8MsM7CAJhIFRpXtJ0WUazu+DU2fBm9X3rC0MJwLDRiqd8FETuiQzzFAnCBlqgN2v/Bo3y7gEUry3AZ49pEwezKEeS5LbvxJSq2BSAXYx4fMWfNvySXIjq27JOl9wbBUlsouencVgAg0bqQ1gdxF8S7LBWNA00sltQCaX5CTtnCRfbR0Fz0h8wwMhry9O7d4a8b98CzJLIGvAj1NwZNFZiQWGnDdAPkJtzfAH1UntdFIPLQ07qQkIc50EI81F+EVciG1AuRLbv+hEk12YgjeKTh7DOYfBW/oyRX4FjNmQmghfzjjx6TfDiem3sSy6wiyz3FvtC4HftcJLkUegD9Q9AnVBagModcDkcXDicjiIKpKE1DPqArgsI4rwmgHPpuEuC14swiNN8OIk6KsmdHY9yx52bO42MuMGId1lNEzqdbKjb2fAVgZko5oHic1Zk2NYffoR8HDYsWi9kYdAXZHaAHznw2ZNThy0XcJsJUYe7B8csazoJDm8kF3KIbmrJ0DPKrA/AgUJc/NzJxdkmAVJ3UMiK/JfOBdF5ocgtSGYS+HrcjtpwEct2CwFjUJe1QjsXugsy8GnjlIXp7qfF7UYYF2SmggmN1cZ2KMAJ6Zh/3wtpB1BbchqToiuAKtsWGjAWzYsy8LSHKySywgTHmiB/44EouuAHYHd0/AJya4kgUUlAYztOItvnIZ15Dq5VpnK3EO122w404Y71cVpBE3+Kodat6Q2WK4u2FcOdYtwQD0lVK4S+6oeF8KT/8TLerVDfC8Z8LLpnNstB5YCy7MgqR5X22DnnMNxIcTVJvSa0GdBbg3kM2AXIJcGowB2GrJ5MBohY0OmAI0mZOVCx4BRJoxpcLIjZYow1nIIarwB41Iw2oJNbZhkwKZN0FBwCLpmpOUFnmwzs3DDGrhCU85VNcVG7MMjgtQGnblNNOB3Gfh+bgTbuA3XbBFlD/5PxlHu3+Tf3Zyf7239Bv//wN+HS45y/boJja+XaCszPNIk1tN4dSxDh8CIIrUBGMTGLQVfLsLRBmxdqy3L0MGsLQ8FAq53x7IU/MqGWzV01FCgPPLaHJGkNgDzbEhvBG3Afgbsaw9KyjvyVKEjDoOAO2ElwOdtWfjLy3CBuqmFQS45dUY0qQ2oSW7SLoVRa+D0tBPQb4Ku3uI1id1tspwdXr4Gjj4aciPhgiReWhgZ0sSC1AZDLXGxlsPnbDgA+LoJG8sBtZaRh4BsLw14A7jZgpsb4capzkWHFkXAE4HYkVqppJ1OBNOjbNjChC11BVffb4PkjijCK8ACG66aAHOm9Nsqa1EEwiEQe1ITGGR7eh5kx8M6BZhfgM+Ui9YQDjKtVWsEXF/Zvgz8ew0c0gSvvQw5PSurNdLJaC8RpFaqyrkwtgiTm2D3NXCwBduZrvFnMtQ+vFK6t5Z9BjzfCFeuhnsseOQIjWoyvIqJSe+JJLVS3c2H0atg9wYnCuoWRZgITBD71mpcdGIyR6oSY8AOTrwhxCuiCRaugG4T/tIGy/Wwvyp49eEyCCiplYByLjRsCI1LYBTQnoETCjBGyS36+yPeDgW4uhF++DYsGw1r2qG3SnfO6APRJxKFgJJasLqNLtg4BZv2weTRsNka+I5Ei7AcL6XA2F3BXYzsGqYTJ26pCTcZcF8eXkrBglWw4BjoG9nS6ehHGgJKahVqbB40FmBzE7YuwlfHwk59MCHnRFqVgJfiuZN2D8Er7GX4H3PHL9FBJKZAIQXvNMLrffB6AW5LwwN5eKEd3h7+0eoIFAH1n6zlHDDOgsY0jBEHbok+kXKMgD9pw35Z2CMDWVm2iH1CPZqWyJJTlp6N9HvBLzHgzybcXISFwNtuhJDeCbBSzSxqOXW0rVoioCu1WqIZ0NZsyE6ESSZslHYSPI/Kw+gijElDU9aJhiGRXCdaTkie9W1Y14CxJjQK4Qyc7ZWS4sCBvAxB/i7LKstJ8bbCdqLsvpN2koosNuDtHBRtWJWGFWlYKXUL8IaEOVoMb6g5xVqcGNpVTRFQUqspnGuvMYk3t/j9K21rthPdR4sikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwJKavHTqUqkCCQaASW1RKtfhVcE4oeAklr8dKoSKQKJRkBJLdHqV+EVgfghoKQWP52qRIpAohFQUku0+lV4RSB+CCipxU+nKpEikGgElNQSrX4VXhGIHwL/H8ptWIHCTCOnAAAAAElFTkSuQmCC" preserveAspectRatio="none"/><path fill="#3a414a" d="M67-125c0 53 21 87 73 88 37 1 54-22 65-47l45 17C233-25 199 4 140 4 58 4 20-42 15-125 8-235 124-281 211-232c18 10 29 29 36 50l-46 12c-8-25-30-41-62-41-52 0-71 34-72 86" id="aO"/><path fill="#3a414a" d="M114-157C55-157 80-60 75 0H25v-261h50l-1 109c12-26 28-41 61-42 86-1 58 113 63 194h-50c-7-57 23-157-34-157" id="aP"/><path fill="#3a414a" d="M135-150c-39-12-60 13-60 57V0H25l-1-190h47c2 13-1 29 3 40 6-28 27-53 61-41v41" id="aQ"/><path fill="#3a414a" d="M110-194c64 0 96 36 96 99 0 64-35 99-97 99-61 0-95-36-95-99 0-62 34-99 96-99zm-1 164c35 0 45-28 45-65 0-40-10-65-43-65-34 0-45 26-45 65 0 36 10 65 43 65" id="aR"/><path fill="#3a414a" d="M220-157c-53 9-28 100-34 157h-49v-107c1-27-5-49-29-50C55-147 81-57 75 0H25l-1-190h47c2 12-1 28 3 38 10-53 101-56 108 0 13-22 24-43 59-42 82 1 51 116 57 194h-49v-107c-1-25-5-48-29-50" id="aS"/><path fill="#3a414a" d="M25-224v-37h50v37H25zM25 0v-190h50V0H25" id="aT"/><path fill="#3a414a" d="M85 4C-2 5 27-109 22-190h50c7 57-23 150 33 157 60-5 35-97 40-157h50l1 190h-47c-2-12 1-28-3-38-12 25-28 42-61 42" id="aU"/><g id="a"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aO"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#aP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.50617283950617,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.148148148148145,0)" xlink:href="#aR"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.666666666666664,0)" xlink:href="#aS"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,71.41975308641975,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,77.59259259259258,0)" xlink:href="#aU"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,91.1111111111111,0)" xlink:href="#aS"/></g><path fill="#3a414a" d="M185-48c-13 30-37 53-82 52C43 2 14-33 14-96s30-98 90-98c62 0 83 45 84 108H66c0 31 8 55 39 56 18 0 30-7 34-22zm-45-69c5-46-57-63-70-21-2 6-4 13-4 21h74" id="aV"/><g id="b"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aO"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#aP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.50617283950617,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.148148148148145,0)" xlink:href="#aR"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.666666666666664,0)" xlink:href="#aS"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,71.41975308641975,0)" xlink:href="#aV"/></g><path fill="#3a414a" d="M67-125c0 54 23 88 75 88 28 0 53-7 68-21v-34h-60v-39h108v91C232-14 192 4 140 4 58 4 20-42 15-125 8-236 126-280 215-234c19 10 29 26 37 47l-47 15c-11-23-29-39-63-39-53 1-75 33-75 86" id="aW"/><path fill="#3a414a" d="M24-248c93 1 206-16 204 79-1 75-69 88-152 82V0H24v-248zm52 121c47 0 100 7 100-41 0-47-54-39-100-39v80" id="aX"/><path fill="#3a414a" d="M238-95c0 69-44 99-111 99C63 4 22-25 22-93v-155h51v151c-1 38 19 59 55 60 90 1 49-130 58-211h52v153" id="aY"/><g id="c"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#aX"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.09876543209876,0)" xlink:href="#aY"/></g><path fill="#3a414a" d="M190-63c-7 42-38 67-86 67-59 0-84-38-90-98-12-110 154-137 174-36l-49 2c-2-19-15-32-35-32-30 0-35 28-38 64-6 74 65 87 74 30" id="aZ"/><path fill="#3a414a" d="M137-138c1-29-70-34-71-4 15 46 118 7 119 86 1 83-164 76-172 9l43-7c4 19 20 25 44 25 33 8 57-30 24-41C81-84 22-81 20-136c-2-80 154-74 161-7" id="ba"/><g id="d"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aX"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,23.456790123456788,0)" xlink:href="#aR"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.9753086419753,0)" xlink:href="#aZ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.32098765432098,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,61.66666666666666,0)" xlink:href="#ba"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,74.01234567901234,0)" xlink:href="#ba"/></g><path fill="#3a414a" d="M240-174c0 40-23 61-54 70L253 0h-59l-57-94H76V0H24v-248c93 4 217-23 216 74zM76-134c48-2 112 12 112-38 0-48-66-32-112-35v73" id="bb"/><path fill="#3a414a" d="M135-194c87-1 58 113 63 194h-50c-7-57 23-157-34-157-59 0-34 97-39 157H25l-1-190h47c2 12-1 28 3 38 12-26 28-41 61-42" id="bc"/><path fill="#3a414a" d="M88-194c31-1 46 15 58 34l-1-101h50l1 261h-48c-2-10 0-23-3-31C134-8 116 4 84 4 32 4 16-41 15-95c0-56 19-97 73-99zm17 164c33 0 40-30 41-66 1-37-9-64-41-64s-38 30-39 65c0 43 13 65 39 65" id="bd"/><g id="e"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bb"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,41.85185185185185,0)" xlink:href="#bd"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,55.37037037037037,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,67.71604938271605,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,76.35802469135803,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,88.70370370370371,0)" xlink:href="#aQ"/></g><path fill="#3a414a" d="M266 0h-40l-56-210L115 0H75L2-248h35L96-30l15-64 43-154h32l59 218 59-218h35" id="be"/><path fill="#3a414a" d="M100-194c63 0 86 42 84 106H49c0 40 14 67 53 68 26 1 43-12 49-29l28 8c-11 28-37 45-77 45C44 4 14-33 15-96c1-61 26-98 85-98zm52 81c6-60-76-77-97-28-3 7-6 17-6 28h103" id="bf"/><path fill="#3a414a" d="M115-194c53 0 69 39 70 98 0 66-23 100-70 100C84 3 66-7 56-30L54 0H23l1-261h32v101c10-23 28-34 59-34zm-8 174c40 0 45-34 45-75 0-40-5-75-45-74-42 0-51 32-51 76 0 43 10 73 51 73" id="bg"/><path fill="#3a414a" d="M143 4C61 4 22-44 18-125c-5-107 100-154 193-111 17 8 29 25 37 43l-32 9c-13-25-37-40-76-40-61 0-88 39-88 99 0 61 29 100 91 101 35 0 62-11 79-27v-45h-74v-28h105v86C228-13 192 4 143 4" id="bh"/><path fill="#3a414a" d="M30-248c87 1 191-15 191 75 0 78-77 80-158 76V0H30v-248zm33 125c57 0 124 11 124-50 0-59-68-47-124-48v98" id="bi"/><path fill="#3a414a" d="M232-93c-1 65-40 97-104 97C67 4 28-28 28-90v-158h33c8 89-33 224 67 224 102 0 64-133 71-224h33v155" id="bj"/><g id="f"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#be"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.493827160493826,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.839506172839506,0)" xlink:href="#bg"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,45.18518518518518,0)" xlink:href="#bh"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.46913580246913,0)" xlink:href="#bi"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,77.28395061728395,0)" xlink:href="#bj"/></g><path fill="#3a414a" d="M153-248C145-148 188 4 80 4 36 3 13-21 6-62l32-5c4 25 16 42 43 43 27 0 39-20 39-49v-147H72v-28h81" id="bk"/><path fill="#3a414a" d="M141-36C126-15 110 5 73 4 37 3 15-17 15-53c-1-64 63-63 125-63 3-35-9-54-41-54-24 1-41 7-42 31l-33-3c5-37 33-52 76-52 45 0 72 20 72 64v82c-1 20 7 32 28 27v20c-31 9-61-2-59-35zM48-53c0 20 12 33 32 33 41-3 63-29 60-74-43 2-92-5-92 41" id="bl"/><path fill="#3a414a" d="M108 0H70L1-190h34L89-25l56-165h34" id="bm"/><path fill="#3a414a" d="M185-189c-5-48-123-54-124 2 14 75 158 14 163 119 3 78-121 87-175 55-17-10-28-26-33-46l33-7c5 56 141 63 141-1 0-78-155-14-162-118-5-82 145-84 179-34 5 7 8 16 11 25" id="bn"/><path fill="#3a414a" d="M96-169c-40 0-48 33-48 73s9 75 48 75c24 0 41-14 43-38l32 2c-6 37-31 61-74 61-59 0-76-41-82-99-10-93 101-131 147-64 4 7 5 14 7 22l-32 3c-4-21-16-35-41-35" id="bo"/><path fill="#3a414a" d="M114-163C36-179 61-72 57 0H25l-1-190h30c1 12-1 29 2 39 6-27 23-49 58-41v29" id="bp"/><path fill="#3a414a" d="M24-231v-30h32v30H24zM24 0v-190h32V0H24" id="bq"/><path fill="#3a414a" d="M115-194c55 1 70 41 70 98S169 2 115 4C84 4 66-9 55-30l1 105H24l-1-265h31l2 30c10-21 28-34 59-34zm-8 174c40 0 45-34 45-75s-6-73-45-74c-42 0-51 32-51 76 0 43 10 73 51 73" id="br"/><path fill="#3a414a" d="M59-47c-2 24 18 29 38 22v24C64 9 27 4 27-40v-127H5v-23h24l9-43h21v43h35v23H59v120" id="bs"/><g id="g"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bk"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,11.11111111111111,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,23.45679012345679,0)" xlink:href="#bm"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,34.5679012345679,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.913580246913575,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,61.72839506172839,0)" xlink:href="#bo"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.8395061728395,0)" xlink:href="#bp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,80.18518518518519,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,85.06172839506173,0)" xlink:href="#br"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,97.40740740740742,0)" xlink:href="#bs"/></g><path fill="#3a414a" d="M205 0l-28-72H64L36 0H1l101-248h38L239 0h-34zm-38-99l-47-123c-12 45-31 82-46 123h93" id="bt"/><path fill="#3a414a" d="M33 0v-248h34V0H33" id="bu"/><path fill="#3a414a" d="M135-143c-3-34-86-38-87 0 15 53 115 12 119 90S17 21 10-45l28-5c4 36 97 45 98 0-10-56-113-15-118-90-4-57 82-63 122-42 12 7 21 19 24 35" id="bv"/><g id="h"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bt"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bi"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.629629629629626,0)" xlink:href="#bu"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.80246913580247,0)" xlink:href="#bv"/></g><path fill="#3a414a" d="M160-131c35 5 61 23 61 61C221 17 115-2 30 0v-248c76 3 177-17 177 60 0 33-19 50-47 57zm-97-11c50-1 110 9 110-42 0-47-63-36-110-37v79zm0 115c55-2 124 14 124-45 0-56-70-42-124-44v89" id="bw"/><path fill="#3a414a" d="M24 0v-261h32V0H24" id="bx"/><path fill="#3a414a" d="M117-194c89-4 53 116 60 194h-32v-121c0-31-8-49-39-48C34-167 62-67 57 0H25l-1-190h30c1 10-1 24 2 32 11-22 29-35 61-36" id="by"/><path fill="#3a414a" d="M143 0L79-87 56-68V0H24v-261h32v163l83-92h37l-77 82L181 0h-38" id="bz"/><g id="i"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bw"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.691358024691354,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.5679012345679,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.913580246913575,0)" xlink:href="#bz"/></g><path fill="#3a414a" d="M85-194c31 0 48 13 60 33l-1-100h32l1 261h-30c-2-10 0-23-3-31C134-8 116 4 85 4 32 4 16-35 15-94c0-66 23-100 70-100zm9 24c-40 0-46 34-46 75 0 40 6 74 45 74 42 0 51-32 51-76 0-42-9-74-50-73" id="bA"/><path fill="#3a414a" d="M177-190C167-65 218 103 67 71c-23-6-38-20-44-43l32-5c15 47 100 32 89-28v-30C133-14 115 1 83 1 29 1 15-40 15-95c0-56 16-97 71-98 29-1 48 16 59 35 1-10 0-23 2-32h30zM94-22c36 0 50-32 50-73 0-42-14-75-50-75-39 0-46 34-46 75s6 73 46 73" id="bB"/><g id="j"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bw"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.691358024691354,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.03703703703703,0)" xlink:href="#bA"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.38271604938271,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.25925925925925,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,61.60493827160493,0)" xlink:href="#bB"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,73.9506172839506,0)" xlink:href="#bv"/></g><path fill="#3a414a" d="M30-248c118-7 216 8 213 122C240-48 200 0 122 0H30v-248zM63-27c89 8 146-16 146-99s-60-101-146-95v194" id="bC"/><path fill="#3a414a" d="M206 0h-36l-40-164L89 0H53L-1-190h32L70-26l43-164h34l41 164 42-164h31" id="bD"/><g id="k"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bC"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bD"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.32098765432099,0)" xlink:href="#by"/></g><g id="l"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#be"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.925925925925924,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,25.80246913580247,0)" xlink:href="#bp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,33.148148148148145,0)" xlink:href="#bf"/></g><path fill="#3a414a" d="M212-179c-10-28-35-45-73-45-59 0-87 40-87 99 0 60 29 101 89 101 43 0 62-24 78-52l27 14C228-24 195 4 139 4 59 4 22-46 18-125c-6-104 99-153 187-111 19 9 31 26 39 46" id="bE"/><g id="m"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bE"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.864197530864196,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,25.74074074074074,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.08641975308642,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.432098765432094,0)" xlink:href="#bs"/></g><path fill="#3a414a" d="M100-194c62-1 85 37 85 99 1 63-27 99-86 99S16-35 15-95c0-66 28-99 85-99zM99-20c44 1 53-31 53-75 0-43-8-75-51-75s-53 32-53 75 10 74 51 75" id="bF"/><path fill="#3a414a" d="M210-169c-67 3-38 105-44 169h-31v-121c0-29-5-50-35-48C34-165 62-65 56 0H25l-1-190h30c1 10-1 24 2 32 10-44 99-50 107 0 11-21 27-35 58-36 85-2 47 119 55 194h-31v-121c0-29-5-49-35-48" id="bG"/><g id="n"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bE"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.79012345679012,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,65.24691358024691,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,77.5925925925926,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,89.93827160493828,0)" xlink:href="#bA"/></g><path fill="#3a414a" d="M84 4C-5 8 30-112 23-190h32v120c0 31 7 50 39 49 72-2 45-101 50-169h31l1 190h-30c-1-10 1-25-2-33-11 22-28 36-60 37" id="bH"/><path fill="#3a414a" d="M101-234c-31-9-42 10-38 44h38v23H63V0H32v-167H5v-23h27c-7-52 17-82 69-68v24" id="bI"/><g id="o"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bw"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bH"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#bI"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.901234567901234,0)" xlink:href="#bI"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.074074074074076,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.41975308641975,0)" xlink:href="#bp"/></g><g id="p"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bE"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.864197530864196,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,25.74074074074074,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.08641975308642,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.432098765432094,0)" xlink:href="#bs"/></g><path fill="#3a414a" d="M133-34C117-15 103 5 69 4 32 3 11-16 11-54c-1-60 55-63 116-61 1-26-3-47-28-47-18 1-26 9-28 27l-52-2c7-38 36-58 82-57s74 22 75 68l1 82c-1 14 12 18 25 15v27c-30 8-71 5-69-32zm-48 3c29 0 43-24 42-57-32 0-66-3-65 30 0 17 8 27 23 27" id="bJ"/><g id="q"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aO"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#aR"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.50617283950617,0)" xlink:href="#aS"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.25925925925925,0)" xlink:href="#aS"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,69.01234567901234,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,81.35802469135803,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,94.87654320987654,0)" xlink:href="#bd"/></g><path fill="#3a414a" d="M182-130c37 4 62 22 62 59C244 23 116-4 24 0v-248c84 5 203-23 205 63 0 31-19 50-47 55zM76-148c40-3 101 13 101-30 0-44-60-28-101-31v61zm0 110c48-3 116 14 116-37 0-48-69-32-116-35v72" id="bK"/><path fill="#3a414a" d="M121-226c-27-7-43 5-38 36h38v33H83V0H34v-157H6v-33h28c-9-59 32-81 87-68v32" id="bL"/><g id="r"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bK"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#aU"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.50617283950617,0)" xlink:href="#bL"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.85185185185185,0)" xlink:href="#bL"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.197530864197525,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,56.5432098765432,0)" xlink:href="#aQ"/></g><path fill="#3a414a" d="M169-182c-1-43-94-46-97-3 18 66 151 10 154 114 3 95-165 93-204 36-6-8-10-19-12-30l50-8c3 46 112 56 116 5-17-69-150-10-154-114-4-87 153-88 188-35 5 8 8 18 10 28" id="bM"/><path fill="#3a414a" d="M128 0H69L1-190h53L99-40l48-150h52" id="bN"/><g id="s"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bM"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.80246913580247,0)" xlink:href="#bN"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,48.148148148148145,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,54.32098765432099,0)" xlink:href="#aZ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,66.66666666666667,0)" xlink:href="#aV"/></g><path fill="#3a414a" d="M24-248c120-7 223 5 221 122C244-46 201 0 124 0H24v-248zM76-40c74 7 117-18 117-86 0-67-45-88-117-82v168" id="bO"/><path fill="#3a414a" d="M231 0h-52l-39-155L100 0H48L-1-190h46L77-45c9-52 24-97 36-145h53l37 145 32-145h46" id="bP"/><g id="t"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bO"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,45.61728395061728,0)" xlink:href="#bc"/></g><path fill="#3a414a" d="M195 0l-88-114-31 24V0H24v-248h52v113l112-113h60L142-143 257 0h-62" id="bQ"/><path fill="#3a414a" d="M25 0v-261h50V0H25" id="bR"/><g id="u"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.9753086419753,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.49382716049382,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.8395061728395,0)" xlink:href="#bR"/></g><path fill="#3a414a" d="M186 0v-106H76V0H24v-248h52v99h110v-99h50V0h-50" id="bS"/><g id="v"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bS"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.9753086419753,0)" xlink:href="#bd"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.49382716049382,0)" xlink:href="#bP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,67.77777777777777,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,80.12345679012346,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,88.76543209876543,0)" xlink:href="#aV"/></g><g id="w"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#aX"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.09876543209876,0)" xlink:href="#aY"/></g><g id="x"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bO"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.629629629629626,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.802469135802465,0)" xlink:href="#bN"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,43.148148148148145,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,55.49382716049382,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,64.1358024691358,0)" xlink:href="#ba"/></g><g id="y"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#aX"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.09876543209876,0)" xlink:href="#aY"/></g><g id="z"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bO"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,45.61728395061728,0)" xlink:href="#bc"/></g><path fill="#3a414a" d="M147 0L96-86 75-71V0H25v-261h50v150l67-79h53l-66 74L201 0h-54" id="bT"/><g id="A"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bK"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#aZ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.67901234567901,0)" xlink:href="#bT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,53.02469135802469,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,65.37037037037037,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,78.88888888888889,0)" xlink:href="#bd"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,92.4074074074074,0)" xlink:href="#ba"/></g><path fill="#3a414a" d="M137 0h-34L2-248h35l83 218 83-218h36" id="bU"/><g id="B"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bU"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,13.148148148148147,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,25.493827160493826,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.370370370370367,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.24691358024691,0)" xlink:href="#bA"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,47.59259259259259,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,59.938271604938265,0)" xlink:href="#bs"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,66.1111111111111,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,70.98765432098764,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,83.33333333333333,0)" xlink:href="#by"/></g><path fill="#3a414a" d="M136-208V0H84v-208H4v-40h212v40h-80" id="bV"/><g id="C"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,13.518518518518517,0)" xlink:href="#aP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.037037037037035,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,33.20987654320987,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,41.85185185185185,0)" xlink:href="#bd"/></g><path fill="#3a414a" d="M115-3C79 11 28 4 28-45v-112H4v-33h27l15-45h31v45h36v33H77v99c-1 23 16 31 38 25v30" id="bW"/><path fill="#3a414a" d="M123 10C108 53 80 86 19 72V37c35 8 53-11 59-39L3-190h52l48 148c12-52 28-100 44-148h51" id="bX"/><g id="D"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aX"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.80246913580247,0)" xlink:href="#bW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,43.148148148148145,0)" xlink:href="#bX"/></g><g id="E"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aY"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#ba"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.67901234567901,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.32098765432099,0)" xlink:href="#aS"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,69.07407407407408,0)" xlink:href="#aR"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,82.5925925925926,0)" xlink:href="#bd"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,96.11111111111111,0)" xlink:href="#aV"/></g><path fill="#3a414a" d="M135-194c53 0 70 44 70 98 0 56-19 98-73 100-31 1-45-17-59-34 3 33 2 69 2 105H25l-1-265h48c2 10 0 23 3 31 11-24 29-35 60-35zM114-30c33 0 39-31 40-66 0-38-9-64-40-64-56 0-55 130 0 130" id="bY"/><g id="F"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,25.925925925925924,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.2716049382716,0)" xlink:href="#bY"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.79012345679012,0)" xlink:href="#aP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,65.30864197530863,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,71.48148148148147,0)" xlink:href="#aZ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,83.82716049382715,0)" xlink:href="#ba"/></g><path fill="#3a414a" d="M24 0v-248h52v208h133V0H24" id="bZ"/><path fill="#3a414a" d="M135-194c52 0 70 43 70 98 0 56-19 99-73 100-30 1-46-15-58-35L72 0H24l1-261h50v104c11-23 29-37 60-37zM114-30c31 0 40-27 40-66 0-37-7-63-39-63s-41 28-41 65c0 36 8 64 40 64" id="ca"/><g id="G"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bZ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,13.518518518518517,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.691358024691358,0)" xlink:href="#ca"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,33.20987654320987,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,41.85185185185185,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,54.197530864197525,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.8395061728395,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,69.01234567901234,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,81.35802469135803,0)" xlink:href="#ba"/></g><path fill="#3a414a" d="M16-82v-28h88v28H16" id="cb"/><g id="H"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bh"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#bi"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.09876543209876,0)" xlink:href="#bj"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,48.08641975308641,0)" xlink:href="#cb"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,55.43209876543209,0)" xlink:href="#bv"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,66.5432098765432,0)" xlink:href="#br"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,78.88888888888889,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,91.23456790123457,0)" xlink:href="#bo"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,102.34567901234568,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,107.22222222222223,0)" xlink:href="#bI"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,113.39506172839506,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,118.27160493827161,0)" xlink:href="#bo"/></g><g id="I"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,4.876543209876543,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,23.33333333333333,0)" xlink:href="#br"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.679012345679006,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.55555555555555,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,52.90123456790123,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,71.35802469135801,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,83.7037037037037,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,96.04938271604938,0)" xlink:href="#bs"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,102.22222222222221,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,114.5679012345679,0)" xlink:href="#bs"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,120.74074074074073,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,125.61728395061728,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,137.96296296296296,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,150.30864197530863,0)" xlink:href="#bv"/></g><g id="J"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#bI"/></g><path fill="#3a414a" d="M140-251c81 0 123 46 123 126C263-46 219 4 140 4 59 4 17-45 17-125s42-126 123-126zm0 227c63 0 89-41 89-101s-29-99-89-99c-61 0-89 39-89 99S79-25 140-24" id="cc"/><g id="K"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.09876543209876,0)" xlink:href="#cb"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.444444444444436,0)" xlink:href="#bv"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.55555555555554,0)" xlink:href="#br"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.90123456790122,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,75.2469135802469,0)" xlink:href="#bo"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,86.35802469135801,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,91.23456790123456,0)" xlink:href="#bI"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,97.40740740740739,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,102.28395061728394,0)" xlink:href="#bo"/></g><path fill="#3a414a" d="M106-169C34-169 62-67 57 0H25v-261h32l-1 103c12-21 28-36 61-36 89 0 53 116 60 194h-32v-121c2-32-8-49-39-48" id="cd"/><g id="L"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bB"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#bp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.691358024691358,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.03703703703704,0)" xlink:href="#br"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.382716049382715,0)" xlink:href="#cd"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,56.72839506172839,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,61.60493827160494,0)" xlink:href="#bo"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.71604938271605,0)" xlink:href="#bv"/></g><g id="M"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bt"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bi"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.629629629629626,0)" xlink:href="#bu"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.80246913580247,0)" xlink:href="#bv"/></g><g id="N"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bU"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.012345679012345,0)" xlink:href="#bH"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,26.358024691358025,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,31.23456790123457,0)" xlink:href="#bz"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,42.345679012345684,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,54.69135802469136,0)" xlink:href="#by"/></g><g id="O"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bM"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.09876543209876,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.2716049382716,0)" xlink:href="#bL"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,45.61728395061728,0)" xlink:href="#bW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,52.962962962962955,0)" xlink:href="#bM"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,67.77777777777777,0)" xlink:href="#aP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,81.29629629629629,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,93.64197530864197,0)" xlink:href="#bd"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,107.1604938271605,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,119.50617283950618,0)" xlink:href="#aQ"/></g><path fill="#3a414a" d="M126-127c33 6 58 20 58 59 0 88-139 92-164 29-3-8-5-16-6-25l32-3c6 27 21 44 54 44 32 0 52-15 52-46 0-38-36-46-79-43v-28c39 1 72-4 72-42 0-27-17-43-46-43-28 0-47 15-49 41l-32-3c6-42 35-63 81-64 48-1 79 21 79 65 0 36-21 52-52 59" id="ce"/><g id="P"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bC"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#ce"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bC"/></g><path fill="#3a414a" d="M240 0l2-218c-23 76-54 145-80 218h-23L58-218 59 0H30v-248h44l77 211c21-75 51-140 76-211h43V0h-30" id="cf"/><g id="Q"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.456790123456788,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.80246913580247,0)" xlink:href="#bs"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.97530864197531,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.32098765432099,0)" xlink:href="#bx"/></g><path fill="#333" d="M185-189c-5-48-123-54-124 2 14 75 158 14 163 119 3 78-121 87-175 55-17-10-28-26-33-46l33-7c5 56 141 63 141-1 0-78-155-14-162-118-5-82 145-84 179-34 5 7 8 16 11 25" id="cg"/><path fill="#333" d="M266 0h-40l-56-210L115 0H75L2-248h35L96-30l15-64 43-154h32l59 218 59-218h35" id="ch"/><g id="R"><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,0,0)" xlink:href="#cg"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,11.851851851851853,0)" xlink:href="#ch"/></g><path fill="#333" d="M114-163C36-179 61-72 57 0H25l-1-190h30c1 12-1 29 2 39 6-27 23-49 58-41v29" id="ci"/><path fill="#333" d="M100-194c63 0 86 42 84 106H49c0 40 14 67 53 68 26 1 43-12 49-29l28 8c-11 28-37 45-77 45C44 4 14-33 15-96c1-61 26-98 85-98zm52 81c6-60-76-77-97-28-3 7-6 17-6 28h103" id="cj"/><path fill="#333" d="M117-194c89-4 53 116 60 194h-32v-121c0-31-8-49-39-48C34-167 62-67 57 0H25l-1-190h30c1 10-1 24 2 32 11-22 29-35 61-36" id="ck"/><path fill="#333" d="M85-194c31 0 48 13 60 33l-1-100h32l1 261h-30c-2-10 0-23-3-31C134-8 116 4 85 4 32 4 16-35 15-94c0-66 23-100 70-100zm9 24c-40 0-46 34-46 75 0 40 6 74 45 74 42 0 51-32 51-76 0-42-9-74-50-73" id="cl"/><path fill="#333" d="M24-231v-30h32v30H24zM24 0v-190h32V0H24" id="cm"/><path fill="#333" d="M177-190C167-65 218 103 67 71c-23-6-38-20-44-43l32-5c15 47 100 32 89-28v-30C133-14 115 1 83 1 29 1 15-40 15-95c0-56 16-97 71-98 29-1 48 16 59 35 1-10 0-23 2-32h30zM94-22c36 0 50-32 50-73 0-42-14-75-50-75-39 0-46 34-46 75s6 73 46 73" id="cn"/><g id="S"><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,0,0)" xlink:href="#ci"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,5.8765432098765435,0)" xlink:href="#cj"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,15.753086419753087,0)" xlink:href="#ck"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,25.629629629629633,0)" xlink:href="#cl"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,35.50617283950618,0)" xlink:href="#cj"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,45.38271604938272,0)" xlink:href="#ci"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,51.25925925925927,0)" xlink:href="#cm"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,55.1604938271605,0)" xlink:href="#ck"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,65.03703703703704,0)" xlink:href="#cn"/></g><path fill="#3a414a" d="M190 0L58-211 59 0H30v-248h39L202-35l-2-213h31V0h-41" id="co"/><g id="T"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#co"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bm"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.098765432098766,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,31.975308641975307,0)" xlink:href="#bA"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.32098765432099,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.19753086419753,0)" xlink:href="#bl"/></g><g id="U"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.456790123456788,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.80246913580247,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.67901234567901,0)" xlink:href="#bq"/></g><g id="V"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bt"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bA"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#bp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,34.50617283950617,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.85185185185185,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,59.197530864197525,0)" xlink:href="#bF"/></g><path fill="#3a414a" d="M33 0v-38h34V0H33" id="cp"/><g id="W"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#bs"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.51851851851852,0)" xlink:href="#bo"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.62962962962963,0)" xlink:href="#cp"/></g><linearGradient gradientUnits="userSpaceOnUse" id="X" x1="424" y1="-1162.74" x2="423.75" y2="-990"><stop offset="0%" stop-color="#afccfb"/><stop offset="100%" stop-color="#8bb5f8"/></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="Y" x1="349.57" y1="-1218.25" x2="359.08" y2="-1063.71"><stop offset="0%" stop-color="#1972e7"/><stop offset="100%" stop-color="#1969d5"/></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="Z" x1="333.71" y1="-1162.5" x2="333.7" y2="-990"><stop offset="0%" stop-color="#659cf6"/><stop offset="100%" stop-color="#4285f4"/></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="aa" x1="365.77" y1="-1151.51" x2="366.25" y2="-1058.31"><stop offset="0%" stop-color="#3680f0"/><stop offset="100%" stop-color="#2678ec"/></linearGradient><g id="ab"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,13.08641975308642,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.25925925925926,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.77777777777778,0)" xlink:href="#bW"/></g><path fill="#3a414a" d="M30 0v-248h33v221h125V0H30" id="cq"/><path fill="#3a414a" d="M18-27v-27l151-64-151-65v-27l175 74v36" id="cr"/><path fill="#3a414a" d="M39-94c74 12-11 154 75 146v23c-44 4-70-10-70-52C44-23 55-84 6-82v-22c81 4-7-162 84-157h24v23c-82-15-2 131-75 144" id="cs"/><path fill="#3a414a" d="M233-177c-1 41-23 64-60 70L243 0h-38l-65-103H63V0H30v-248c88 3 205-21 203 71zM63-129c60-2 137 13 137-47 0-61-80-42-137-45v92" id="ct"/><path fill="#3a414a" d="M68-38c1 34 0 65-14 84H32c9-13 17-26 17-46H33v-38h35" id="cu"/><g id="ac"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#be"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.925925925925924,0)" xlink:href="#bh"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.20987654320987,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,53.02469135802468,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,65.37037037037037,0)" xlink:href="#cb"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.71604938271605,0)" xlink:href="#cr"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,85.67901234567901,0)" xlink:href="#cs"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,93.08641975308642,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,107.90123456790123,0)" xlink:href="#bi"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,122.71604938271604,0)" xlink:href="#bu"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,128.88888888888889,0)" xlink:href="#ct"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,144.87654320987653,0)" xlink:href="#cb"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,152.2222222222222,0)" xlink:href="#bU"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,164.99999999999997,0)" xlink:href="#cu"/></g><path fill="#3a414a" d="M197 0v-115H63V0H30v-248h33v105h134v-105h34V0h-34" id="cv"/><g id="ad"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cv"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,43.148148148148145,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,55.49382716049382,0)" xlink:href="#cu"/></g><path fill="#3a414a" d="M76-40C78 24 84 88 6 75V52C86 64 9-79 80-94c-40-6-34-59-34-106 1-29-11-41-40-38v-23c44-4 70 10 70 52 0 47-12 108 38 105v22c-26 1-39 14-38 42" id="cw"/><g id="ae"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,6.172839506172839,0)" xlink:href="#cp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#cp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.51851851851852,0)" xlink:href="#cw"/></g><path fill="#333" d="M96-169c-40 0-48 33-48 73s9 75 48 75c24 0 41-14 43-38l32 2c-6 37-31 61-74 61-59 0-76-41-82-99-10-93 101-131 147-64 4 7 5 14 7 22l-32 3c-4-21-16-35-41-35" id="cx"/><path fill="#333" d="M100-194c62-1 85 37 85 99 1 63-27 99-86 99S16-35 15-95c0-66 28-99 85-99zM99-20c44 1 53-31 53-75 0-43-8-75-51-75s-53 32-53 75 10 74 51 75" id="cy"/><path fill="#333" d="M210-169c-67 3-38 105-44 169h-31v-121c0-29-5-50-35-48C34-165 62-65 56 0H25l-1-190h30c1 10-1 24 2 32 10-44 99-50 107 0 11-21 27-35 58-36 85-2 47 119 55 194h-31v-121c0-29-5-49-35-48" id="cz"/><path fill="#333" d="M115-194c55 1 70 41 70 98S169 2 115 4C84 4 66-9 55-30l1 105H24l-1-265h31l2 30c10-21 28-34 59-34zm-8 174c40 0 45-34 45-75s-6-73-45-74c-42 0-51 32-51 76 0 43 10 73 51 73" id="cA"/><path fill="#333" d="M24 0v-261h32V0H24" id="cB"/><path fill="#333" d="M106-169C34-169 62-67 57 0H25v-261h32l-1 103c12-21 28-36 61-36 89 0 53 116 60 194h-32v-121c2-32-8-49-39-48" id="cC"/><path fill="#333" d="M141-36C126-15 110 5 73 4 37 3 15-17 15-53c-1-64 63-63 125-63 3-35-9-54-41-54-24 1-41 7-42 31l-33-3c5-37 33-52 76-52 45 0 72 20 72 64v82c-1 20 7 32 28 27v20c-31 9-61-2-59-35zM48-53c0 20 12 33 32 33 41-3 63-29 60-74-43 2-92-5-92 41" id="cD"/><g id="af"><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,0,0)" xlink:href="#cx"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,8.88888888888889,0)" xlink:href="#cy"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,18.765432098765434,0)" xlink:href="#cz"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,33.53086419753087,0)" xlink:href="#cA"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,43.40740740740741,0)" xlink:href="#cm"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,47.308641975308646,0)" xlink:href="#cB"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,51.20987654320988,0)" xlink:href="#cj"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,61.086419753086425,0)" xlink:href="#cg"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,72.93827160493828,0)" xlink:href="#cC"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,82.81481481481482,0)" xlink:href="#cD"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,92.69135802469137,0)" xlink:href="#cl"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,102.56790123456791,0)" xlink:href="#cj"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,112.44444444444446,0)" xlink:href="#ci"/></g><g id="ag"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bt"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.691358024691354,0)" xlink:href="#bx"/></g><g id="ah"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#bs"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.51851851851852,0)" xlink:href="#cd"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.864197530864196,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,43.20987654320987,0)" xlink:href="#bp"/></g><g id="ai"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bo"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,11.11111111111111,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,23.45679012345679,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,41.91358024691358,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,60.37037037037037,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.71604938271605,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,85.06172839506173,0)" xlink:href="#bA"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,97.40740740740742,0)" xlink:href="#bv"/></g><g id="aj"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#be"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.493827160493826,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.839506172839506,0)" xlink:href="#bg"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,45.18518518518518,0)" xlink:href="#bh"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.46913580246913,0)" xlink:href="#cq"/></g><pattern id="ak" patternUnits="userSpaceOnUse" x="1072.99" y="-980" width="165" height="68.75"><use xlink:href="#cE" transform="translate(0, -48.125) scale(165,165)"/></pattern><path fill="#3a414a" d="M199 0l-22-63H83L61 0H9l90-248h61L250 0h-51zm-33-102l-36-108c-10 38-24 72-36 108h72" id="cF"/><path fill="#3a414a" d="M175 0L67-191c6 58 2 128 3 191H24v-248h59L193-55c-6-58-2-129-3-193h46V0h-61" id="cG"/><path fill="#3a414a" d="M24 0v-248h195v40H76v63h132v40H76v65h150V0H24" id="cH"/><g id="al"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#cG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,31.975308641975307,0)" xlink:href="#aW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.25925925925925,0)" xlink:href="#bZ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.77777777777777,0)" xlink:href="#cH"/></g><g id="am"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#cG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,31.975308641975307,0)" xlink:href="#aW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.25925925925925,0)" xlink:href="#bZ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.77777777777777,0)" xlink:href="#cH"/></g><path fill="#3a414a" d="M30 0v-248h187v28H63v79h144v27H63v87h162V0H30" id="cI"/><g id="an"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bh"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.629629629629626,0)" xlink:href="#cI"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.44444444444444,0)" xlink:href="#bn"/></g><g id="ao"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.28395061728395,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.925925925925924,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,33.2716049382716,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.79012345679012,0)" xlink:href="#ba"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,59.1358024691358,0)" xlink:href="#bR"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,65.30864197530863,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,77.65432098765432,0)" xlink:href="#bW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,85,0)" xlink:href="#aR"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,98.51851851851852,0)" xlink:href="#aQ"/></g><g id="ap"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bh"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.629629629629626,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.44444444444444,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,56.79012345679012,0)" xlink:href="#cb"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,64.1358024691358,0)" xlink:href="#cr"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,77.09876543209876,0)" xlink:href="#cs"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,84.50617283950616,0)" xlink:href="#bh"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,101.79012345679011,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,114.1358024691358,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,128.9506172839506,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,141.29629629629628,0)" xlink:href="#cu"/></g><g id="aq"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bi"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.629629629629626,0)" xlink:href="#bu"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.80246913580247,0)" xlink:href="#ct"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.79012345679012,0)" xlink:href="#cb"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,59.1358024691358,0)" xlink:href="#bU"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,71.91358024691357,0)" xlink:href="#cu"/></g><g id="ar"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,6.172839506172839,0)" xlink:href="#cp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#cp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.51851851851852,0)" xlink:href="#cw"/></g><path fill="#3a414a" d="M101-251c82-7 93 87 43 132L82-64C71-53 59-42 53-27h129V0H18c2-99 128-94 128-182 0-28-16-43-45-43s-46 15-49 41l-32-3c6-41 34-60 81-64" id="cJ"/><g id="as"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bh"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.629629629629626,0)" xlink:href="#cI"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.44444444444444,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,59.25925925925925,0)" xlink:href="#cJ"/></g><g id="at"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aW"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#bY"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.80246913580247,0)" xlink:href="#aU"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.32098765432099,0)" xlink:href="#aO"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,60.30864197530864,0)" xlink:href="#aP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,73.82716049382715,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,86.17283950617283,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,99.69135802469135,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,113.20987654320987,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,125.55555555555556,0)" xlink:href="#bR"/></g><path fill="#3a414a" d="M24-231v-30h32v30H24zM-9 49c24 4 33-6 33-30v-209h32V24c2 40-23 58-65 49V49" id="cK"/><g id="au"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.456790123456788,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.80246913580247,0)" xlink:href="#cK"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.67901234567901,0)" xlink:href="#bF"/></g><g id="av"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bu"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,6.172839506172839,0)" xlink:href="#bi"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.98765432098765,0)" xlink:href="#bE"/></g><g id="aw"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aO"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#aR"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.50617283950617,0)" xlink:href="#aS"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.25925925925925,0)" xlink:href="#aS"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,69.01234567901234,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,81.35802469135803,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,94.87654320987654,0)" xlink:href="#bd"/></g><g id="ax"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bK"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#aU"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.50617283950617,0)" xlink:href="#bL"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.85185185185185,0)" xlink:href="#bL"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.197530864197525,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,56.5432098765432,0)" xlink:href="#aQ"/></g><g id="ay"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bn"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#cd"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.50617283950617,0)" xlink:href="#bp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.85185185185185,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,59.197530864197525,0)" xlink:href="#bA"/></g><path fill="#3a414a" d="M179-190L93 31C79 59 56 82 12 73V49c39 6 53-20 64-50L1-190h34L92-34l54-156h33" id="cL"/><g id="az"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.456790123456788,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.80246913580247,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.25925925925925,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,61.60493827160493,0)" xlink:href="#bp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,68.9506172839506,0)" xlink:href="#cL"/></g><g id="aA"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bO"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,45.61728395061728,0)" xlink:href="#bc"/></g><path fill="#3a414a" d="M275 0h-61l-44-196L126 0H64L0-248h53L97-49l45-199h58l43 199 44-199h52" id="cM"/><g id="aB"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cM"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.740740740740737,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,26.913580246913575,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.55555555555555,0)" xlink:href="#aV"/></g><path fill="#3a414a" d="M127-220V0H93v-220H8v-28h204v28h-85" id="cN"/><g id="aC"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bk"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,11.11111111111111,0)" xlink:href="#bu"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#cN"/></g><g id="aD"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bE"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.79012345679012,0)" xlink:href="#br"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,59.1358024691358,0)" xlink:href="#bq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,64.01234567901234,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,68.88888888888889,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,81.23456790123457,0)" xlink:href="#bp"/></g><g id="aE"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bh"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.28395061728395,0)" xlink:href="#cq"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.629629629629626,0)" xlink:href="#cI"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.44444444444444,0)" xlink:href="#bn"/></g><g id="aF"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bi"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#bv"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.27160493827161,0)" xlink:href="#bv"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.38271604938272,0)" xlink:href="#bs"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,55.555555555555564,0)" xlink:href="#cd"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,67.90123456790124,0)" xlink:href="#bp"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,75.24691358024693,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,87.59259259259261,0)" xlink:href="#bH"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,99.9382716049383,0)" xlink:href="#bB"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,112.28395061728398,0)" xlink:href="#cd"/></g><g id="aG"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bE"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.79012345679012,0)" xlink:href="#bG"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,65.24691358024691,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,77.5925925925926,0)" xlink:href="#by"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,89.93827160493828,0)" xlink:href="#bA"/></g><g id="aH"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bC"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#bo"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.44444444444444,0)" xlink:href="#bF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.79012345679012,0)" xlink:href="#bA"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,64.1358024691358,0)" xlink:href="#bf"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,76.48148148148148,0)" xlink:href="#bp"/></g><g id="aI"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cM"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.740740740740737,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,26.913580246913575,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.55555555555555,0)" xlink:href="#aV"/></g><path fill="#3a414a" d="M33-154v-36h34v36H33zM33 0v-36h34V0H33" id="cO"/><g id="aJ"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bM"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.80246913580247,0)" xlink:href="#bN"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,48.148148148148145,0)" xlink:href="#aT"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,54.32098765432099,0)" xlink:href="#aZ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,66.66666666666667,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,79.01234567901236,0)" xlink:href="#cO"/></g><path fill="#3a414a" d="M230 0l2-204L168 0h-37L68-204 70 0H24v-248h70l56 185 57-185h69V0h-46" id="cP"/><g id="aK"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#cP"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.456790123456788,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.80246913580247,0)" xlink:href="#aS"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.55555555555556,0)" xlink:href="#aR"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,64.07407407407408,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.71604938271605,0)" xlink:href="#bX"/></g><g id="aL"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.28395061728395,0)" xlink:href="#aQ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.925925925925924,0)" xlink:href="#bJ"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,33.2716049382716,0)" xlink:href="#bc"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.79012345679012,0)" xlink:href="#ba"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,59.1358024691358,0)" xlink:href="#bL"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,66.48148148148148,0)" xlink:href="#aV"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,78.82716049382717,0)" xlink:href="#aQ"/></g><g id="aM"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bU"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.012345679012345,0)" xlink:href="#bH"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,26.358024691358025,0)" xlink:href="#bx"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,31.23456790123457,0)" xlink:href="#bz"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,42.345679012345684,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,54.69135802469136,0)" xlink:href="#by"/></g><g id="aN"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#bu"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,6.172839506172839,0)" xlink:href="#bI"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#bl"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.691358024691358,0)" xlink:href="#bo"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.80246913580247,0)" xlink:href="#bf"/></g></defs></g></svg>
\ No newline at end of file
diff --git a/docs/security/research/graphics/resources/cmdbuf_command_structure.svg b/docs/security/research/graphics/resources/cmdbuf_command_structure.svg
new file mode 100644
index 0000000..7a850478
--- /dev/null
+++ b/docs/security/research/graphics/resources/cmdbuf_command_structure.svg
@@ -0,0 +1 @@
+<svg version="1.1" viewBox="0.0 0.0 1152.0 864.0" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><clipPath id="p.0"><path d="m0 0l1152.0 0l0 864.0l-1152.0 0l0 -864.0z" clip-rule="nonzero"/></clipPath><g clip-path="url(#p.0)"><path fill="#000000" fill-opacity="0.0" d="m0 0l1152.0 0l0 864.0l-1152.0 0z" fill-rule="evenodd"/><path fill="#4a86e8" d="m72.727 199.73753l258.04724 0l0 98.3307l-258.04724 0z" fill-rule="evenodd"/><path fill="#000000" d="m147.84947 226.17879l-3.953125 0.71875q-0.203125 -1.1875 -0.921875 -1.78125q-0.703125 -0.609375 -1.828125 -0.609375q-1.515625 0 -2.40625 1.046875q-0.890625 1.03125 -0.890625 3.46875q0 2.703125 0.90625 3.828125q0.90625 1.109375 2.4375 1.109375q1.15625 0 1.875 -0.640625q0.734375 -0.65625 1.03125 -2.25l3.953125 0.671875q-0.609375 2.71875 -2.359375 4.109375q-1.75 1.390625 -4.6875 1.390625q-3.328125 0 -5.3125 -2.09375q-1.984375 -2.109375 -1.984375 -5.84375q0 -3.765625 1.984375 -5.859375q2.0 -2.09375 5.390625 -2.09375q2.78125 0 4.421875 1.203125q1.640625 1.1875 2.34375 3.625zm2.123413 2.90625q0 -2.015625 0.984375 -3.890625q1.0 -1.875 2.8125 -2.859375q1.8125 -0.984375 4.03125 -0.984375q3.453125 0 5.65625 2.25q2.21875 2.234375 2.21875 5.65625q0 3.4375 -2.234375 5.71875q-2.21875 2.265625 -5.609375 2.265625q-2.078125 0 -3.984375 -0.9375q-1.890625 -0.953125 -2.890625 -2.78125q-0.984375 -1.828125 -0.984375 -4.4375zm4.125 0.203125q0 2.265625 1.078125 3.46875q1.078125 1.203125 2.640625 1.203125q1.578125 0 2.640625 -1.203125q1.078125 -1.203125 1.078125 -3.484375q0 -2.234375 -1.078125 -3.4375q-1.0625 -1.203125 -2.640625 -1.203125q-1.5625 0 -2.640625 1.203125q-1.078125 1.203125 -1.078125 3.453125zm14.414795 -7.59375l3.71875 0l0 2.078125q1.984375 -2.421875 4.734375 -2.421875q1.46875 0 2.53125 0.609375q1.078125 0.59375 1.765625 1.8125q1.0 -1.21875 2.15625 -1.8125q1.171875 -0.609375 2.484375 -0.609375q1.671875 0 2.828125 0.6875q1.171875 0.671875 1.734375 1.984375q0.421875 0.96875 0.421875 3.15625l0 9.71875l-4.015625 0l0 -8.6875q0 -2.265625 -0.421875 -2.921875q-0.5625 -0.859375 -1.71875 -0.859375q-0.84375 0 -1.59375 0.515625q-0.734375 0.515625 -1.078125 1.515625q-0.328125 0.984375 -0.328125 3.140625l0 7.296875l-4.015625 0l0 -8.328125q0 -2.21875 -0.21875 -2.859375q-0.21875 -0.65625 -0.671875 -0.96875q-0.4375 -0.3125 -1.21875 -0.3125q-0.921875 0 -1.671875 0.5q-0.75 0.5 -1.078125 1.453125q-0.3125 0.9375 -0.3125 3.125l0 7.390625l-4.03125 0l0 -15.203125zm26.077408 0l3.71875 0l0 2.078125q1.984375 -2.421875 4.734375 -2.421875q1.46875 0 2.53125 0.609375q1.078125 0.59375 1.765625 1.8125q1.0 -1.21875 2.15625 -1.8125q1.171875 -0.609375 2.484375 -0.609375q1.671875 0 2.828125 0.6875q1.171875 0.671875 1.734375 1.984375q0.421875 0.96875 0.421875 3.15625l0 9.71875l-4.015625 0l0 -8.6875q0 -2.265625 -0.421875 -2.921875q-0.5625 -0.859375 -1.71875 -0.859375q-0.84375 0 -1.59375 0.515625q-0.734375 0.515625 -1.078125 1.515625q-0.328125 0.984375 -0.328125 3.140625l0 7.296875l-4.015625 0l0 -8.328125q0 -2.21875 -0.21875 -2.859375q-0.21875 -0.65625 -0.671875 -0.96875q-0.4375 -0.3125 -1.21875 -0.3125q-0.921875 0 -1.671875 0.5q-0.75 0.5 -1.078125 1.453125q-0.3125 0.9375 -0.3125 3.125l0 7.390625l-4.03125 0l0 -15.203125zm29.389908 4.640625l-3.65625 -0.671875q0.625 -2.203125 2.125 -3.25q1.5 -1.0625 4.46875 -1.0625q2.6875 0 4.0 0.640625q1.328125 0.625 1.859375 1.609375q0.546875 0.984375 0.546875 3.609375l-0.046875 4.6875q0 2.0 0.1875 2.953125q0.203125 0.953125 0.734375 2.046875l-3.984375 0q-0.15625 -0.40625 -0.390625 -1.1875q-0.09375 -0.359375 -0.140625 -0.46875q-1.03125 1.0 -2.203125 1.5q-1.171875 0.5 -2.515625 0.5q-2.34375 0 -3.703125 -1.265625q-1.34375 -1.28125 -1.34375 -3.234375q0 -1.28125 0.609375 -2.28125q0.625 -1.015625 1.734375 -1.546875q1.109375 -0.546875 3.203125 -0.953125q2.8125 -0.53125 3.90625 -0.984375l0 -0.40625q0 -1.15625 -0.578125 -1.640625q-0.578125 -0.5 -2.15625 -0.5q-1.078125 0 -1.6875 0.421875q-0.59375 0.421875 -0.96875 1.484375zm5.390625 3.265625q-0.78125 0.25 -2.453125 0.609375q-1.671875 0.359375 -2.1875 0.703125q-0.796875 0.5625 -0.796875 1.421875q0 0.84375 0.625 1.46875q0.640625 0.609375 1.609375 0.609375q1.09375 0 2.078125 -0.71875q0.734375 -0.546875 0.96875 -1.34375q0.15625 -0.515625 0.15625 -1.953125l0 -0.796875zm21.748413 7.296875l-4.015625 0l0 -7.765625q0 -2.453125 -0.265625 -3.171875q-0.25 -0.734375 -0.84375 -1.125q-0.578125 -0.40625 -1.390625 -0.40625q-1.046875 0 -1.875 0.578125q-0.828125 0.5625 -1.140625 1.515625q-0.3125 0.9375 -0.3125 3.484375l0 6.890625l-4.015625 0l0 -15.203125l3.734375 0l0 2.234375q1.984375 -2.578125 5.015625 -2.578125q1.328125 0 2.421875 0.484375q1.109375 0.46875 1.671875 1.21875q0.578125 0.734375 0.796875 1.6875q0.21875 0.9375 0.21875 2.703125l0 9.453125zm18.024185 0l-3.734375 0l0 -2.234375q-0.921875 1.296875 -2.203125 1.9375q-1.265625 0.640625 -2.546875 0.640625q-2.625 0 -4.5 -2.109375q-1.8593903 -2.109375 -1.8593903 -5.890625q0 -3.875 1.8125153 -5.875q1.828125 -2.015625 4.609375 -2.015625q2.546875 0 4.40625 2.109375l0 -7.5625l4.015625 0l0 21.0zm-10.734375 -7.9375q0 2.4375 0.671875 3.53125q0.96875 1.578125 2.71875 1.578125q1.390625 0 2.359375 -1.1875q0.984375 -1.1875 0.984375 -3.53125q0 -2.625 -0.953125 -3.765625q-0.9375 -1.15625 -2.421875 -1.15625q-1.421875 0 -2.390625 1.140625q-0.96875 1.125 -0.96875 3.390625z" fill-rule="nonzero"/><path fill="#ff9900" d="m328.52142 199.73753l536.9134 0l0 98.3307l-536.9134 0z" fill-rule="evenodd"/><path fill="#000000" d="m569.9485 232.55379l4.03125 -0.609375q0.265625 1.171875 1.046875 1.78125q0.796875 0.609375 2.203125 0.609375q1.5625 0 2.359375 -0.578125q0.53125 -0.390625 0.53125 -1.0625q0 -0.46875 -0.296875 -0.765625q-0.296875 -0.28125 -1.34375 -0.53125q-4.859375 -1.078125 -6.171875 -1.953125q-1.796875 -1.234375 -1.796875 -3.4375q0 -1.96875 1.5625 -3.3125q1.5625 -1.34375 4.828125 -1.34375q3.125 0 4.640625 1.015625q1.53125 1.015625 2.09375 3.0l-3.796875 0.703125q-0.234375 -0.890625 -0.921875 -1.359375q-0.671875 -0.46875 -1.9375 -0.46875q-1.59375 0 -2.28125 0.4375q-0.453125 0.3125 -0.453125 0.8125q0 0.4375 0.40625 0.734375q0.53125 0.40625 3.75 1.140625q3.21875 0.71875 4.5 1.78125q1.25 1.078125 1.25 3.0q0 2.09375 -1.75 3.59375q-1.734375 1.5 -5.171875 1.5q-3.09375 0 -4.90625 -1.25q-1.8125 -1.265625 -2.375 -3.4375zm17.732788 -12.921875l0 -3.734375l4.015625 0l0 3.734375l-4.015625 0zm0 17.265625l0 -15.203125l4.015625 0l0 15.203125l-4.015625 0zm6.5233154 0l0 -3.140625l5.703125 -6.546875q1.40625 -1.59375 2.078125 -2.265625q-0.703125 0.03125 -1.84375 0.046875l-5.375 0.03125l0 -3.328125l12.578125 0l0 2.84375l-5.828125 6.703125l-2.046875 2.21875q1.6875 -0.09375 2.078125 -0.09375l6.234375 0l0 3.53125l-13.578125 0zm25.085938 -4.84375l4.015625 0.671875q-0.765625 2.203125 -2.4375 3.359375q-1.671875 1.15625 -4.171875 1.15625q-3.96875 0 -5.875 -2.59375q-1.5 -2.078125 -1.5 -5.234375q0 -3.78125 1.96875 -5.921875q1.984375 -2.140625 5.0 -2.140625q3.390625 0 5.34375 2.25q1.96875 2.234375 1.890625 6.859375l-10.078125 0q0.03125 1.78125 0.953125 2.78125q0.9375 1.0 2.328125 1.0q0.953125 0 1.59375 -0.515625q0.640625 -0.515625 0.96875 -1.671875zm0.234375 -4.0625q-0.046875 -1.75 -0.90625 -2.65625q-0.859375 -0.90625 -2.09375 -0.90625q-1.3125 0 -2.171875 0.953125q-0.859375 0.96875 -0.84375 2.609375l6.015625 0z" fill-rule="nonzero"/><path fill="#d9d9d9" d="m72.727 157.72179l792.69293 0l0 42.015747l-792.69293 0z" fill-rule="evenodd"/><path fill="#000000" d="m441.85666 181.11053l1.640625 -0.21875q0.28125 1.40625 0.953125 2.015625q0.6875 0.609375 1.65625 0.609375q1.15625 0 1.953125 -0.796875q0.796875 -0.796875 0.796875 -1.984375q0 -1.125 -0.734375 -1.859375q-0.734375 -0.734375 -1.875 -0.734375q-0.46875 0 -1.15625 0.171875l0.1875 -1.4375q0.15625 0.015625 0.265625 0.015625q1.046875 0 1.875 -0.546875q0.84375 -0.546875 0.84375 -1.671875q0 -0.90625 -0.609375 -1.5q-0.609375 -0.59375 -1.578125 -0.59375q-0.953125 0 -1.59375 0.609375q-0.640625 0.59375 -0.8125 1.796875l-1.640625 -0.296875q0.296875 -1.640625 1.359375 -2.546875q1.0625 -0.90625 2.65625 -0.90625q1.09375 0 2.0 0.46875q0.921875 0.46875 1.40625 1.28125q0.5 0.8125 0.5 1.71875q0 0.859375 -0.46875 1.578125q-0.46875 0.703125 -1.375 1.125q1.1875 0.28125 1.84375 1.140625q0.65625 0.859375 0.65625 2.15625q0 1.734375 -1.28125 2.953125q-1.265625 1.21875 -3.21875 1.21875q-1.765625 0 -2.921875 -1.046875q-1.15625 -1.046875 -1.328125 -2.71875zm18.985077 1.953125l0 1.578125l-8.828125 0q-0.015625 -0.59375 0.1875 -1.140625q0.34375 -0.90625 1.078125 -1.78125q0.75 -0.875 2.15625 -2.015625q2.171875 -1.78125 2.9375 -2.828125q0.765625 -1.046875 0.765625 -1.96875q0 -0.984375 -0.703125 -1.640625q-0.6875 -0.671875 -1.8125 -0.671875q-1.1875 0 -1.90625 0.71875q-0.703125 0.703125 -0.703125 1.953125l-1.6875 -0.171875q0.171875 -1.890625 1.296875 -2.875q1.140625 -0.984375 3.03125 -0.984375q1.921875 0 3.046875 1.0625q1.125 1.0625 1.125 2.640625q0 0.796875 -0.328125 1.578125q-0.328125 0.78125 -1.09375 1.640625q-0.75 0.84375 -2.53125 2.34375q-1.46875 1.234375 -1.890625 1.6875q-0.421875 0.4375 -0.6875 0.875l6.546875 0zm1.5788574 -2.4375l0 -1.640625l5.03125 0l0 1.640625l-5.03125 0zm8.353302 4.015625l-1.515625 0l0 -13.359375l1.640625 0l0 4.765625q1.046875 -1.296875 2.65625 -1.296875q0.890625 0 1.6875 0.359375q0.796875 0.359375 1.3125 1.015625q0.515625 0.640625 0.796875 1.5625q0.296875 0.921875 0.296875 1.96875q0 2.484375 -1.234375 3.84375q-1.21875 1.359375 -2.953125 1.359375q-1.703125 0 -2.6875 -1.4375l0 1.21875zm-0.015625 -4.90625q0 1.734375 0.484375 2.515625q0.765625 1.265625 2.09375 1.265625q1.078125 0 1.859375 -0.9375q0.78125 -0.9375 0.78125 -2.78125q0 -1.890625 -0.75 -2.796875q-0.75 -0.90625 -1.828125 -0.90625q-1.0625 0 -1.859375 0.9375q-0.78125 0.9375 -0.78125 2.703125zm8.891327 -6.5625l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm7.7229614 -1.46875l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625zm0.9489136 -1.421875l1.625 -0.25q0.125 0.96875 0.75 1.5q0.625 0.515625 1.75 0.515625q1.125 0 1.671875 -0.453125q0.546875 -0.46875 0.546875 -1.09375q0 -0.546875 -0.484375 -0.875q-0.328125 -0.21875 -1.671875 -0.546875q-1.8125 -0.46875 -2.515625 -0.796875q-0.6875 -0.328125 -1.046875 -0.90625q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.640625 0.296875 -1.1875q0.296875 -0.5625 0.8125 -0.921875q0.375 -0.28125 1.03125 -0.46875q0.671875 -0.203125 1.421875 -0.203125q1.140625 0 2.0 0.328125q0.859375 0.328125 1.265625 0.890625q0.421875 0.5625 0.578125 1.5l-1.609375 0.21875q-0.109375 -0.75 -0.640625 -1.171875q-0.515625 -0.421875 -1.46875 -0.421875q-1.140625 0 -1.625 0.375q-0.46875 0.375 -0.46875 0.875q0 0.3125 0.1875 0.578125q0.203125 0.265625 0.640625 0.4375q0.234375 0.09375 1.4375 0.421875q1.75 0.453125 2.4375 0.75q0.6875 0.296875 1.078125 0.859375q0.390625 0.5625 0.390625 1.40625q0 0.828125 -0.484375 1.546875q-0.46875 0.71875 -1.375 1.125q-0.90625 0.390625 -2.046875 0.390625q-1.875 0 -2.875 -0.78125q-0.984375 -0.78125 -1.25 -2.328125z" fill-rule="nonzero"/><path fill="#b7b7b7" fill-opacity="0.506" d="m72.727 256.0525l258.04724 0l0 42.015747l-258.04724 0z" fill-rule="evenodd"/><path fill="#000000" d="m181.3984 282.9725l-1.640625 0l0 -10.453125q-0.59375 0.5625 -1.5625 1.140625q-0.953125 0.5625 -1.71875 0.84375l0 -1.59375q1.375 -0.640625 2.40625 -1.5625q1.03125 -0.921875 1.453125 -1.78125l1.0625 0l0 13.40625zm8.990295 0l-1.640625 0l0 -10.453125q-0.59375 0.5625 -1.5625 1.140625q-0.953125 0.5625 -1.71875 0.84375l0 -1.59375q1.375 -0.640625 2.40625 -1.5625q1.03125 -0.921875 1.453125 -1.78125l1.0625 0l0 13.40625zm4.016342 -4.015625l0 -1.640625l5.03125 0l0 1.640625l-5.03125 0zm8.353302 4.015625l-1.515625 0l0 -13.359375l1.640625 0l0 4.765625q1.046875 -1.296875 2.65625 -1.296875q0.890625 0 1.6875 0.359375q0.796875 0.359375 1.3125 1.015625q0.515625 0.640625 0.796875 1.5625q0.296875 0.921875 0.296875 1.96875q0 2.484375 -1.234375 3.84375q-1.21875 1.359375 -2.953125 1.359375q-1.703125 0 -2.6875 -1.4375l0 1.21875zm-0.015625 -4.90625q0 1.734375 0.484375 2.515625q0.765625 1.265625 2.09375 1.265625q1.078125 0 1.859375 -0.9375q0.78125 -0.9375 0.78125 -2.78125q0 -1.890625 -0.75 -2.796875q-0.75 -0.90625 -1.828125 -0.90625q-1.0625 0 -1.859375 0.9375q-0.78125 0.9375 -0.78125 2.703125zm8.891342 -6.5625l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm7.722946 -1.46875l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625zm0.94892883 -1.421875l1.625 -0.25q0.125 0.96875 0.75 1.5q0.625 0.515625 1.75 0.515625q1.125 0 1.671875 -0.453125q0.546875 -0.46875 0.546875 -1.09375q0 -0.546875 -0.484375 -0.875q-0.328125 -0.21875 -1.671875 -0.546875q-1.8125 -0.46875 -2.515625 -0.796875q-0.6875 -0.328125 -1.046875 -0.90625q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.640625 0.296875 -1.1875q0.296875 -0.5625 0.8125 -0.921875q0.375 -0.28125 1.03125 -0.46875q0.671875 -0.203125 1.421875 -0.203125q1.140625 0 2.0 0.328125q0.859375 0.328125 1.265625 0.890625q0.421875 0.5625 0.578125 1.5l-1.609375 0.21875q-0.109375 -0.75 -0.640625 -1.171875q-0.515625 -0.421875 -1.46875 -0.421875q-1.140625 0 -1.625 0.375q-0.46875 0.375 -0.46875 0.875q0 0.3125 0.1875 0.578125q0.203125 0.265625 0.640625 0.4375q0.234375 0.09375 1.4375 0.421875q1.75 0.453125 2.4375 0.75q0.6875 0.296875 1.078125 0.859375q0.390625 0.5625 0.390625 1.40625q0 0.828125 -0.484375 1.546875q-0.46875 0.71875 -1.375 1.125q-0.90625 0.390625 -2.046875 0.390625q-1.875 0 -2.875 -0.78125q-0.984375 -0.78125 -1.25 -2.328125z" fill-rule="nonzero"/><path fill="#b7b7b7" fill-opacity="0.506" d="m328.50876 256.0525l536.9133 0l0 42.015747l-536.9133 0z" fill-rule="evenodd"/><path fill="#000000" d="m578.35803 281.39438l0 1.578125l-8.828125 0q-0.015625 -0.59375 0.1875 -1.140625q0.34375 -0.90625 1.078125 -1.78125q0.75 -0.875 2.15625 -2.015625q2.171875 -1.78125 2.9375 -2.828125q0.765625 -1.046875 0.765625 -1.96875q0 -0.984375 -0.703125 -1.640625q-0.6875 -0.671875 -1.8125 -0.671875q-1.1875 0 -1.90625 0.71875q-0.703125 0.703125 -0.703125 1.953125l-1.6875 -0.171875q0.171875 -1.890625 1.296875 -2.875q1.140625 -0.984375 3.03125 -0.984375q1.921875 0 3.046875 1.0625q1.125 1.0625 1.125 2.640625q0 0.796875 -0.328125 1.578125q-0.328125 0.78125 -1.09375 1.640625q-0.75 0.84375 -2.53125 2.34375q-1.46875 1.234375 -1.890625 1.6875q-0.421875 0.4375 -0.6875 0.875l6.546875 0zm7.9382324 1.578125l-1.640625 0l0 -10.453125q-0.59375 0.5625 -1.5625 1.140625q-0.953125 0.5625 -1.71875 0.84375l0 -1.59375q1.375 -0.640625 2.40625 -1.5625q1.03125 -0.921875 1.453125 -1.78125l1.0625 0l0 13.40625zm4.0163574 -4.015625l0 -1.640625l5.03125 0l0 1.640625l-5.03125 0zm8.3532715 4.015625l-1.515625 0l0 -13.359375l1.640625 0l0 4.765625q1.046875 -1.296875 2.65625 -1.296875q0.890625 0 1.6875 0.359375q0.796875 0.359375 1.3125 1.015625q0.515625 0.640625 0.796875 1.5625q0.296875 0.921875 0.296875 1.96875q0 2.484375 -1.234375 3.84375q-1.21875 1.359375 -2.953125 1.359375q-1.703125 0 -2.6875 -1.4375l0 1.21875zm-0.015625 -4.90625q0 1.734375 0.484375 2.515625q0.765625 1.265625 2.09375 1.265625q1.078125 0 1.859375 -0.9375q0.78125 -0.9375 0.78125 -2.78125q0 -1.890625 -0.75 -2.796875q-0.75 -0.90625 -1.828125 -0.90625q-1.0625 0 -1.859375 0.9375q-0.78125 0.9375 -0.78125 2.703125zm8.891357 -6.5625l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm7.7229614 -1.46875l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625zm0.9489136 -1.421875l1.625 -0.25q0.125 0.96875 0.75 1.5q0.625 0.515625 1.75 0.515625q1.125 0 1.671875 -0.453125q0.546875 -0.46875 0.546875 -1.09375q0 -0.546875 -0.484375 -0.875q-0.328125 -0.21875 -1.671875 -0.546875q-1.8125 -0.46875 -2.515625 -0.796875q-0.6875 -0.328125 -1.046875 -0.90625q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.640625 0.296875 -1.1875q0.296875 -0.5625 0.8125 -0.921875q0.375 -0.28125 1.03125 -0.46875q0.671875 -0.203125 1.421875 -0.203125q1.140625 0 2.0 0.328125q0.859375 0.328125 1.265625 0.890625q0.421875 0.5625 0.578125 1.5l-1.609375 0.21875q-0.109375 -0.75 -0.640625 -1.171875q-0.515625 -0.421875 -1.46875 -0.421875q-1.140625 0 -1.625 0.375q-0.46875 0.375 -0.46875 0.875q0 0.3125 0.1875 0.578125q0.203125 0.265625 0.640625 0.4375q0.234375 0.09375 1.4375 0.421875q1.75 0.453125 2.4375 0.75q0.6875 0.296875 1.078125 0.859375q0.390625 0.5625 0.390625 1.40625q0 0.828125 -0.484375 1.546875q-0.46875 0.71875 -1.375 1.125q-0.90625 0.390625 -2.046875 0.390625q-1.875 0 -2.875 -0.78125q-0.984375 -0.78125 -1.25 -2.328125z" fill-rule="nonzero"/><path fill="#93c47d" d="m72.72711 298.06824l792.69293 0l0 98.33072l-792.69293 0z" fill-rule="evenodd"/><path fill="#000000" d="m380.94672 324.5095l-3.953125 0.71875q-0.203125 -1.1875 -0.921875 -1.78125q-0.703125 -0.609375 -1.828125 -0.609375q-1.515625 0 -2.40625 1.046875q-0.890625 1.03125 -0.890625 3.46875q0 2.703125 0.90625 3.828125q0.90625 1.109375 2.4375 1.109375q1.15625 0 1.875 -0.640625q0.734375 -0.65625 1.03125 -2.25l3.953125 0.671875q-0.609375 2.71875 -2.359375 4.109375q-1.75 1.390625 -4.6875 1.390625q-3.328125 0 -5.3125 -2.09375q-1.984375 -2.109375 -1.984375 -5.84375q0 -3.765625 1.984375 -5.859375q2.0 -2.09375 5.390625 -2.09375q2.78125 0 4.421875 1.203125q1.640625 1.1875 2.34375 3.625zm2.123413 2.90625q0 -2.015625 0.984375 -3.890625q1.0 -1.875 2.8125 -2.859375q1.8125 -0.984375 4.03125 -0.984375q3.453125 0 5.65625 2.25q2.21875 2.234375 2.21875 5.65625q0 3.4375 -2.234375 5.71875q-2.21875 2.265625 -5.609375 2.265625q-2.078125 0 -3.984375 -0.9375q-1.890625 -0.953125 -2.890625 -2.78125q-0.984375 -1.828125 -0.984375 -4.4375zm4.125 0.203125q0 2.265625 1.078125 3.46875q1.078125 1.203125 2.640625 1.203125q1.578125 0 2.640625 -1.203125q1.078125 -1.203125 1.078125 -3.484375q0 -2.234375 -1.078125 -3.4375q-1.0625 -1.203125 -2.640625 -1.203125q-1.5625 0 -2.640625 1.203125q-1.078125 1.203125 -1.078125 3.453125zm14.414795 -7.59375l3.71875 0l0 2.078125q1.984375 -2.421875 4.734375 -2.421875q1.46875 0 2.53125 0.609375q1.078125 0.59375 1.765625 1.8125q1.0 -1.21875 2.15625 -1.8125q1.171875 -0.609375 2.484375 -0.609375q1.671875 0 2.828125 0.6875q1.171875 0.671875 1.734375 1.984375q0.421875 0.96875 0.421875 3.15625l0 9.71875l-4.015625 0l0 -8.6875q0 -2.265625 -0.421875 -2.921875q-0.5625 -0.859375 -1.71875 -0.859375q-0.84375 0 -1.59375 0.515625q-0.734375 0.515625 -1.078125 1.515625q-0.328125 0.984375 -0.328125 3.140625l0 7.296875l-4.015625 0l0 -8.328125q0 -2.21875 -0.21875 -2.859375q-0.21875 -0.65625 -0.671875 -0.96875q-0.4375 -0.3125 -1.21875 -0.3125q-0.921875 0 -1.671875 0.5q-0.75 0.5 -1.078125 1.453125q-0.3125 0.9375 -0.3125 3.125l0 7.390625l-4.03125 0l0 -15.203125zm26.077393 0l3.71875 0l0 2.078125q1.984375 -2.421875 4.734375 -2.421875q1.46875 0 2.53125 0.609375q1.078125 0.59375 1.765625 1.8125q1.0 -1.21875 2.15625 -1.8125q1.171875 -0.609375 2.484375 -0.609375q1.671875 0 2.828125 0.6875q1.171875 0.671875 1.734375 1.984375q0.421875 0.96875 0.421875 3.15625l0 9.71875l-4.015625 0l0 -8.6875q0 -2.265625 -0.421875 -2.921875q-0.5625 -0.859375 -1.71875 -0.859375q-0.84375 0 -1.59375 0.515625q-0.734375 0.515625 -1.078125 1.515625q-0.328125 0.984375 -0.328125 3.140625l0 7.296875l-4.015625 0l0 -8.328125q0 -2.21875 -0.21875 -2.859375q-0.21875 -0.65625 -0.671875 -0.96875q-0.4375 -0.3125 -1.21875 -0.3125q-0.921875 0 -1.671875 0.5q-0.75 0.5 -1.078125 1.453125q-0.3125 0.9375 -0.3125 3.125l0 7.390625l-4.03125 0l0 -15.203125zm29.389923 4.640625l-3.65625 -0.671875q0.625 -2.203125 2.125 -3.25q1.5 -1.0625 4.46875 -1.0625q2.6875 0 4.0 0.640625q1.328125 0.625 1.859375 1.609375q0.546875 0.984375 0.546875 3.609375l-0.046875 4.6875q0 2.0 0.1875 2.953125q0.203125 0.953125 0.734375 2.046875l-3.984375 0q-0.15625 -0.40625 -0.390625 -1.1875q-0.09375 -0.359375 -0.140625 -0.46875q-1.03125 1.0 -2.203125 1.5q-1.171875 0.5 -2.515625 0.5q-2.34375 0 -3.703125 -1.265625q-1.34375 -1.28125 -1.34375 -3.234375q0 -1.28125 0.609375 -2.28125q0.625 -1.015625 1.734375 -1.546875q1.109375 -0.546875 3.203125 -0.953125q2.8125 -0.53125 3.90625 -0.984375l0 -0.40625q0 -1.15625 -0.578125 -1.640625q-0.578125 -0.5 -2.15625 -0.5q-1.078125 0 -1.6875 0.421875q-0.59375 0.421875 -0.96875 1.484375zm5.390625 3.265625q-0.78125 0.25 -2.453125 0.609375q-1.671875 0.359375 -2.1875 0.703125q-0.796875 0.5625 -0.796875 1.421875q0 0.84375 0.625 1.46875q0.640625 0.609375 1.609375 0.609375q1.09375 0 2.078125 -0.71875q0.734375 -0.546875 0.96875 -1.34375q0.15625 -0.515625 0.15625 -1.953125l0 -0.796875zm21.748413 7.296875l-4.015625 0l0 -7.765625q0 -2.453125 -0.265625 -3.171875q-0.25 -0.734375 -0.84375 -1.125q-0.578125 -0.40625 -1.390625 -0.40625q-1.046875 0 -1.875 0.578125q-0.828125 0.5625 -1.140625 1.515625q-0.3125 0.9375 -0.3125 3.484375l0 6.890625l-4.015625 0l0 -15.203125l3.734375 0l0 2.234375q1.984375 -2.578125 5.015625 -2.578125q1.328125 0 2.421875 0.484375q1.109375 0.46875 1.671875 1.21875q0.578125 0.734375 0.796875 1.6875q0.21875 0.9375 0.21875 2.703125l0 9.453125zm18.02417 0l-3.734375 0l0 -2.234375q-0.921875 1.296875 -2.203125 1.9375q-1.265625 0.640625 -2.546875 0.640625q-2.625 0 -4.5 -2.109375q-1.859375 -2.109375 -1.859375 -5.890625q0 -3.875 1.8125 -5.875q1.828125 -2.015625 4.609375 -2.015625q2.546875 0 4.40625 2.109375l0 -7.5625l4.015625 0l0 21.0zm-10.734375 -7.9375q0 2.4375 0.671875 3.53125q0.96875 1.578125 2.71875 1.578125q1.390625 0 2.359375 -1.1875q0.984375 -1.1875 0.984375 -3.53125q0 -2.625 -0.953125 -3.765625q-0.9375 -1.15625 -2.421875 -1.15625q-1.421875 0 -2.390625 1.140625q-0.96875 1.125 -0.96875 3.390625zm36.797455 7.9375l-3.734375 0l0 -2.234375q-0.921875 1.296875 -2.203125 1.9375q-1.265625 0.640625 -2.546875 0.640625q-2.625 0 -4.5 -2.109375q-1.859375 -2.109375 -1.859375 -5.890625q0 -3.875 1.8125 -5.875q1.828125 -2.015625 4.609375 -2.015625q2.546875 0 4.40625 2.109375l0 -7.5625l4.015625 0l0 21.0zm-10.734375 -7.9375q0 2.4375 0.671875 3.53125q0.96875 1.578125 2.71875 1.578125q1.390625 0 2.359375 -1.1875q0.984375 -1.1875 0.984375 -3.53125q0 -2.625 -0.953125 -3.765625q-0.9375 -1.15625 -2.421875 -1.15625q-1.421875 0 -2.390625 1.140625q-0.96875 1.125 -0.96875 3.390625zm17.71167 -2.625l-3.65625 -0.671875q0.625 -2.203125 2.125 -3.25q1.5 -1.0625 4.46875 -1.0625q2.6875 0 4.0 0.640625q1.328125 0.625 1.859375 1.609375q0.546875 0.984375 0.546875 3.609375l-0.046875 4.6875q0 2.0 0.1875 2.953125q0.203125 0.953125 0.734375 2.046875l-3.984375 0q-0.15625 -0.40625 -0.390625 -1.1875q-0.09375 -0.359375 -0.140625 -0.46875q-1.03125 1.0 -2.203125 1.5q-1.171875 0.5 -2.515625 0.5q-2.34375 0 -3.703125 -1.265625q-1.34375 -1.28125 -1.34375 -3.234375q0 -1.28125 0.609375 -2.28125q0.625 -1.015625 1.734375 -1.546875q1.109375 -0.546875 3.203125 -0.953125q2.8125 -0.53125 3.90625 -0.984375l0 -0.40625q0 -1.15625 -0.578125 -1.640625q-0.578125 -0.5 -2.15625 -0.5q-1.078125 0 -1.6875 0.421875q-0.59375 0.421875 -0.96875 1.484375zm5.390625 3.265625q-0.78125 0.25 -2.453125 0.609375q-1.671875 0.359375 -2.1875 0.703125q-0.796875 0.5625 -0.796875 1.421875q0 0.84375 0.625 1.46875q0.640625 0.609375 1.609375 0.609375q1.09375 0 2.078125 -0.71875q0.734375 -0.546875 0.96875 -1.34375q0.15625 -0.515625 0.15625 -1.953125l0 -0.796875zm14.889038 -7.90625l0 3.203125l-2.75 0l0 6.125q0 1.859375 0.078125 2.171875q0.078125 0.3125 0.359375 0.515625q0.28125 0.1875 0.6875 0.1875q0.546875 0 1.609375 -0.375l0.34375 3.125q-1.40625 0.59375 -3.171875 0.59375q-1.09375 0 -1.96875 -0.359375q-0.875 -0.375 -1.28125 -0.953125q-0.40625 -0.578125 -0.5625 -1.5625q-0.125 -0.703125 -0.125 -2.84375l0 -6.625l-1.859375 0l0 -3.203125l1.859375 0l0 -3.03125l4.03125 -2.34375l0 5.375l2.75 0zm5.7977905 4.640625l-3.65625 -0.671875q0.625 -2.203125 2.125 -3.25q1.5 -1.0625 4.46875 -1.0625q2.6875 0 4.0 0.640625q1.328125 0.625 1.859375 1.609375q0.546875 0.984375 0.546875 3.609375l-0.046875 4.6875q0 2.0 0.1875 2.953125q0.203125 0.953125 0.734375 2.046875l-3.984375 0q-0.15625 -0.40625 -0.390625 -1.1875q-0.09375 -0.359375 -0.140625 -0.46875q-1.03125 1.0 -2.203125 1.5q-1.171875 0.5 -2.515625 0.5q-2.34375 0 -3.703125 -1.265625q-1.34375 -1.28125 -1.34375 -3.234375q0 -1.28125 0.609375 -2.28125q0.625 -1.015625 1.734375 -1.546875q1.109375 -0.546875 3.203125 -0.953125q2.8125 -0.53125 3.90625 -0.984375l0 -0.40625q0 -1.15625 -0.578125 -1.640625q-0.578125 -0.5 -2.15625 -0.5q-1.078125 0 -1.6875 0.421875q-0.59375 0.421875 -0.96875 1.484375zm5.390625 3.265625q-0.78125 0.25 -2.453125 0.609375q-1.671875 0.359375 -2.1875 0.703125q-0.796875 0.5625 -0.796875 1.421875q0 0.84375 0.625 1.46875q0.640625 0.609375 1.609375 0.609375q1.09375 0 2.078125 -0.71875q0.734375 -0.546875 0.96875 -1.34375q0.15625 -0.515625 0.15625 -1.953125l0 -0.796875z" fill-rule="nonzero"/><path fill="#000000" d="m334.30743 376.15012l0 -26.921875l7.125 0l0 3.171875l-3.296875 0l0 20.578125l3.296875 0l0 3.171875l-7.125 0zm8.844635 -13.734375q0 -2.015625 0.984375 -3.890625q1.0 -1.875 2.8125 -2.859375q1.8125 -0.984375 4.03125 -0.984375q3.453125 0 5.65625 2.25q2.21875 2.234375 2.21875 5.65625q0 3.4375 -2.234375 5.71875q-2.21875 2.265625 -5.609375 2.265625q-2.078125 0 -3.984375 -0.9375q-1.890625 -0.953125 -2.890625 -2.78125q-0.984375 -1.828125 -0.984375 -4.4375zm4.125 0.203125q0 2.265625 1.078125 3.46875q1.078125 1.203125 2.640625 1.203125q1.578125 0 2.640625 -1.203125q1.078125 -1.203125 1.078125 -3.484375q0 -2.234375 -1.078125 -3.4375q-1.0625 -1.203125 -2.640625 -1.203125q-1.5625 0 -2.640625 1.203125q-1.078125 1.203125 -1.078125 3.453125zm14.602295 -7.59375l3.765625 0l0 2.234375q0.71875 -1.15625 1.96875 -1.859375q1.25 -0.71875 2.765625 -0.71875q2.640625 0 4.484375 2.078125q1.859375 2.0625 1.859375 5.78125q0 3.8125 -1.859375 5.921875q-1.859375 2.109375 -4.515625 2.109375q-1.265625 0 -2.296875 -0.5q-1.015625 -0.5 -2.140625 -1.71875l0 7.65625l-4.03125 0l0 -20.984375zm3.984375 7.34375q0 2.5625 1.015625 3.796875q1.015625 1.21875 2.484375 1.21875q1.40625 0 2.328125 -1.125q0.9375 -1.125 0.9375 -3.6875q0 -2.390625 -0.96875 -3.546875q-0.953125 -1.171875 -2.375 -1.171875q-1.46875 0 -2.453125 1.140625q-0.96875 1.140625 -0.96875 3.375zm21.02417 -7.34375l0 3.203125l-2.75 0l0 6.125q0 1.859375 0.078125 2.171875q0.078125 0.3125 0.359375 0.515625q0.28125 0.1875 0.6875 0.1875q0.546875 0 1.609375 -0.375l0.34375 3.125q-1.40625 0.59375 -3.171875 0.59375q-1.09375 0 -1.96875 -0.359375q-0.875 -0.375 -1.28125 -0.953125q-0.40625 -0.578125 -0.5625 -1.5625q-0.125 -0.703125 -0.125 -2.84375l0 -6.625l-1.859375 0l0 -3.203125l1.859375 0l0 -3.03125l4.03125 -2.34375l0 5.375l2.75 0zm2.79776 -2.0625l0 -3.734375l4.015625 0l0 3.734375l-4.015625 0zm0 17.265625l0 -15.203125l4.015625 0l0 15.203125l-4.015625 0zm7.210785 -7.8125q0 -2.015625 0.984375 -3.890625q1.0 -1.875 2.8125 -2.859375q1.8125 -0.984375 4.03125 -0.984375q3.453125 0 5.65625 2.25q2.21875 2.234375 2.21875 5.65625q0 3.4375 -2.234375 5.71875q-2.21875 2.265625 -5.609375 2.265625q-2.078125 0 -3.984375 -0.9375q-1.890625 -0.953125 -2.890625 -2.78125q-0.984375 -1.828125 -0.984375 -4.4375zm4.125 0.203125q0 2.265625 1.078125 3.46875q1.078125 1.203125 2.640625 1.203125q1.578125 0 2.640625 -1.203125q1.078125 -1.203125 1.078125 -3.484375q0 -2.234375 -1.078125 -3.4375q-1.0625 -1.203125 -2.640625 -1.203125q-1.5625 0 -2.640625 1.203125q-1.078125 1.203125 -1.078125 3.453125zm28.55542 7.609375l-4.015625 0l0 -7.765625q0 -2.453125 -0.265625 -3.171875q-0.25 -0.734375 -0.84375 -1.125q-0.578125 -0.40625 -1.390625 -0.40625q-1.046875 0 -1.875 0.578125q-0.828125 0.5625 -1.140625 1.515625q-0.3125 0.9375 -0.3125 3.484375l0 6.890625l-4.015625 0l0 -15.203125l3.734375 0l0 2.234375q1.984375 -2.578125 5.015625 -2.578125q1.328125 0 2.421875 0.484375q1.109375 0.46875 1.671875 1.21875q0.578125 0.734375 0.796875 1.6875q0.21875 0.9375 0.21875 2.703125l0 9.453125zm7.08667 -10.5625l-3.65625 -0.671875q0.625 -2.203125 2.125 -3.25q1.5 -1.0625 4.46875 -1.0625q2.6875 0 4.0 0.640625q1.328125 0.625 1.859375 1.609375q0.546875 0.984375 0.546875 3.609375l-0.046875 4.6875q0 2.0 0.1875 2.953125q0.203125 0.953125 0.734375 2.046875l-3.984375 0q-0.15625 -0.40625 -0.390625 -1.1875q-0.09375 -0.359375 -0.140625 -0.46875q-1.03125 1.0 -2.203125 1.5q-1.171875 0.5 -2.515625 0.5q-2.34375 0 -3.703125 -1.265625q-1.34375 -1.28125 -1.34375 -3.234375q0 -1.28125 0.609375 -2.28125q0.625 -1.015625 1.734375 -1.546875q1.109375 -0.546875 3.203125 -0.953125q2.8125 -0.53125 3.90625 -0.984375l0 -0.40625q0 -1.15625 -0.578125 -1.640625q-0.578125 -0.5 -2.15625 -0.5q-1.078125 0 -1.6875 0.421875q-0.59375 0.421875 -0.96875 1.484375zm5.390625 3.265625q-0.78125 0.25 -2.453125 0.609375q-1.671875 0.359375 -2.1875 0.703125q-0.796875 0.5625 -0.796875 1.421875q0 0.84375 0.625 1.46875q0.640625 0.609375 1.609375 0.609375q1.09375 0 2.078125 -0.71875q0.734375 -0.546875 0.96875 -1.34375q0.15625 -0.515625 0.15625 -1.953125l0 -0.796875zm7.920288 7.296875l0 -21.0l4.015625 0l0 21.0l-4.015625 0zm8.03891 -4.03125l4.03125 0l0 2.890625q0 1.734375 -0.3125 2.75q-0.296875 1.015625 -1.140625 1.8125q-0.828125 0.796875 -2.109375 1.265625l-0.796875 -1.671875q1.21875 -0.390625 1.734375 -1.09375q0.515625 -0.703125 0.546875 -1.921875l-1.953125 0l0 -4.03125zm20.249756 4.03125l-4.015625 0l0 -15.203125l3.734375 0l0 2.15625q0.953125 -1.53125 1.71875 -2.015625q0.765625 -0.484375 1.75 -0.484375q1.375 0 2.640625 0.75l-1.234375 3.515625q-1.03125 -0.65625 -1.890625 -0.65625q-0.859375 0 -1.453125 0.46875q-0.578125 0.453125 -0.921875 1.671875q-0.328125 1.21875 -0.328125 5.09375l0 4.703125zm16.366455 -4.84375l4.015625 0.671875q-0.765625 2.203125 -2.4375 3.359375q-1.671875 1.15625 -4.171875 1.15625q-3.96875 0 -5.875 -2.59375q-1.5 -2.078125 -1.5 -5.234375q0 -3.78125 1.96875 -5.921875q1.984375 -2.140625 5.0 -2.140625q3.390625 0 5.34375 2.25q1.96875 2.234375 1.890625 6.859375l-10.078125 0q0.03125 1.78125 0.953125 2.78125q0.9375 1.0 2.328125 1.0q0.953125 0 1.59375 -0.515625q0.640625 -0.515625 0.96875 -1.671875zm0.234375 -4.0625q-0.046875 -1.75 -0.90625 -2.65625q-0.859375 -0.90625 -2.09375 -0.90625q-1.3125 0 -2.171875 0.953125q-0.859375 0.96875 -0.84375 2.609375l6.015625 0zm7.154663 -6.296875l3.765625 0l0 2.234375q0.71875 -1.15625 1.96875 -1.859375q1.25 -0.71875 2.765625 -0.71875q2.640625 0 4.484375 2.078125q1.859375 2.0625 1.859375 5.78125q0 3.8125 -1.859375 5.921875q-1.859375 2.109375 -4.515625 2.109375q-1.265625 0 -2.296875 -0.5q-1.015625 -0.5 -2.140625 -1.71875l0 7.65625l-4.03125 0l0 -20.984375zm3.984375 7.34375q0 2.5625 1.015625 3.796875q1.015625 1.21875 2.484375 1.21875q1.40625 0 2.328125 -1.125q0.9375 -1.125 0.9375 -3.6875q0 -2.390625 -0.96875 -3.546875q-0.953125 -1.171875 -2.375 -1.171875q-1.46875 0 -2.453125 1.140625q-0.96875 1.140625 -0.96875 3.375zm22.852295 3.015625l4.015625 0.671875q-0.765625 2.203125 -2.4375 3.359375q-1.671875 1.15625 -4.171875 1.15625q-3.96875 0 -5.875 -2.59375q-1.5 -2.078125 -1.5 -5.234375q0 -3.78125 1.96875 -5.921875q1.984375 -2.140625 5.0 -2.140625q3.390625 0 5.34375 2.25q1.96875 2.234375 1.890625 6.859375l-10.078125 0q0.03125 1.78125 0.953125 2.78125q0.9375 1.0 2.328125 1.0q0.953125 0 1.59375 -0.515625q0.640625 -0.515625 0.96875 -1.671875zm0.234375 -4.0625q-0.046875 -1.75 -0.90625 -2.65625q-0.859375 -0.90625 -2.09375 -0.90625q-1.3125 0 -2.171875 0.953125q-0.859375 0.96875 -0.84375 2.609375l6.015625 0zm10.279663 -1.65625l-3.65625 -0.671875q0.625 -2.203125 2.125 -3.25q1.5 -1.0625 4.46875 -1.0625q2.6875 0 4.0 0.640625q1.328125 0.625 1.859375 1.609375q0.546875 0.984375 0.546875 3.609375l-0.046875 4.6875q0 2.0 0.1875 2.953125q0.203125 0.953125 0.734375 2.046875l-3.984375 0q-0.15625 -0.40625 -0.390625 -1.1875q-0.09375 -0.359375 -0.140625 -0.46875q-1.03125 1.0 -2.203125 1.5q-1.171875 0.5 -2.515625 0.5q-2.34375 0 -3.703125 -1.265625q-1.34375 -1.28125 -1.34375 -3.234375q0 -1.28125 0.609375 -2.28125q0.625 -1.015625 1.734375 -1.546875q1.109375 -0.546875 3.203125 -0.953125q2.8125 -0.53125 3.90625 -0.984375l0 -0.40625q0 -1.15625 -0.578125 -1.640625q-0.578125 -0.5 -2.15625 -0.5q-1.078125 0 -1.6875 0.421875q-0.59375 0.421875 -0.96875 1.484375zm5.390625 3.265625q-0.78125 0.25 -2.453125 0.609375q-1.671875 0.359375 -2.1875 0.703125q-0.796875 0.5625 -0.796875 1.421875q0 0.84375 0.625 1.46875q0.640625 0.609375 1.609375 0.609375q1.09375 0 2.078125 -0.71875q0.734375 -0.546875 0.96875 -1.34375q0.15625 -0.515625 0.15625 -1.953125l0 -0.796875zm14.889038 -7.90625l0 3.203125l-2.75 0l0 6.125q0 1.859375 0.078125 2.171875q0.078125 0.3125 0.359375 0.515625q0.28125 0.1875 0.6875 0.1875q0.546875 0 1.609375 -0.375l0.34375 3.125q-1.40625 0.59375 -3.171875 0.59375q-1.09375 0 -1.96875 -0.359375q-0.875 -0.375 -1.28125 -0.953125q-0.40625 -0.578125 -0.5625 -1.5625q-0.125 -0.703125 -0.125 -2.84375l0 -6.625l-1.859375 0l0 -3.203125l1.859375 0l0 -3.03125l4.03125 -2.34375l0 5.375l2.75 0zm2.7977295 -2.0625l0 -3.734375l4.015625 0l0 3.734375l-4.015625 0zm0 17.265625l0 -15.203125l4.015625 0l0 15.203125l-4.015625 0zm21.97644 0l-4.015625 0l0 -7.765625q0 -2.453125 -0.265625 -3.171875q-0.25 -0.734375 -0.84375 -1.125q-0.578125 -0.40625 -1.390625 -0.40625q-1.046875 0 -1.875 0.578125q-0.828125 0.5625 -1.140625 1.515625q-0.3125 0.9375 -0.3125 3.484375l0 6.890625l-4.015625 0l0 -15.203125l3.734375 0l0 2.234375q1.984375 -2.578125 5.015625 -2.578125q1.328125 0 2.421875 0.484375q1.109375 0.46875 1.671875 1.21875q0.578125 0.734375 0.796875 1.6875q0.21875 0.9375 0.21875 2.703125l0 9.453125zm3.71167 1.0l4.59375 0.5625q0.109375 0.796875 0.53125 1.09375q0.578125 0.4375 1.796875 0.4375q1.578125 0 2.375 -0.46875q0.53125 -0.3125 0.796875 -1.015625q0.1875 -0.5 0.1875 -1.859375l0 -2.21875q-1.8125 2.46875 -4.5625 2.46875q-3.0625 0 -4.84375 -2.59375q-1.40625 -2.046875 -1.40625 -5.09375q0 -3.828125 1.84375 -5.84375q1.84375 -2.015625 4.578125 -2.015625q2.8125 0 4.640625 2.46875l0 -2.125l3.765625 0l0 13.640625q0 2.6875 -0.4375 4.015625q-0.4375 1.34375 -1.25 2.09375q-0.796875 0.765625 -2.140625 1.1875q-1.328125 0.4375 -3.375 0.4375q-3.875 0 -5.5 -1.328125q-1.609375 -1.328125 -1.609375 -3.359375q0 -0.203125 0.015625 -0.484375zm3.59375 -8.921875q0 2.421875 0.9375 3.546875q0.9375 1.125 2.3125 1.125q1.46875 0 2.484375 -1.15625q1.03125 -1.15625 1.03125 -3.40625q0 -2.375 -0.984375 -3.515625q-0.96875 -1.140625 -2.453125 -1.140625q-1.453125 0 -2.390625 1.125q-0.9375 1.125 -0.9375 3.421875zm20.258545 -13.078125l0 26.921875l-7.125 0l0 -3.171875l3.3125 0l0 -20.609375l-3.3125 0l0 -3.140625l7.125 0z" fill-rule="nonzero"/><path fill="#4a86e8" d="m72.727 199.73753l258.04724 0l0 98.3307l-258.04724 0z" fill-rule="evenodd"/><path fill="#000000" d="m189.08655 236.89754l0 -21.0l4.25 0l0 21.0l-4.25 0zm8.2733 -21.0l7.7343597 0q2.625 0 4.0 0.40625q1.84375 0.546875 3.15625 1.9375q1.328125 1.390625 2.015625 3.40625q0.6875 2.0 0.6875 4.953125q0 2.59375 -0.640625 4.46875q-0.796875 2.296875 -2.25 3.703125q-1.109375 1.078125 -2.984375 1.6875q-1.40625 0.4375 -3.75 0.4375l-7.9687347 0l0 -21.0zm4.2343597 3.5625l0 13.90625l3.15625 0q1.78125 0 2.578125 -0.203125q1.03125 -0.265625 1.703125 -0.875q0.6875 -0.625 1.109375 -2.03125q0.4375 -1.40625 0.4375 -3.84375q0 -2.4375 -0.4375 -3.734375q-0.421875 -1.296875 -1.203125 -2.03125q-0.765625 -0.734375 -1.953125 -0.984375q-0.890625 -0.203125 -3.484375 -0.203125l-1.90625 0z" fill-rule="nonzero"/><path fill="#ff9900" d="m328.52142 199.73753l536.9134 0l0 98.3307l-536.9134 0z" fill-rule="evenodd"/><path fill="#000000" d="m568.6982 230.06941l4.125 -0.40625q0.375 2.078125 1.5 3.0625q1.140625 0.96875 3.078125 0.96875q2.046875 0 3.078125 -0.859375q1.046875 -0.875 1.046875 -2.03125q0 -0.75 -0.4375 -1.265625q-0.4375 -0.53125 -1.53125 -0.921875q-0.734375 -0.25 -3.390625 -0.90625q-3.40625 -0.84375 -4.78125 -2.078125q-1.9375 -1.734375 -1.9375 -4.234375q0 -1.59375 0.90625 -2.984375q0.921875 -1.40625 2.625 -2.140625q1.71875 -0.734375 4.140625 -0.734375q3.953125 0 5.9375 1.734375q2.0 1.734375 2.109375 4.625l-4.234375 0.1875q-0.28125 -1.609375 -1.171875 -2.3125q-0.890625 -0.71875 -2.6875 -0.71875q-1.84375 0 -2.890625 0.765625q-0.671875 0.484375 -0.671875 1.296875q0 0.75 0.625 1.28125q0.796875 0.671875 3.890625 1.40625q3.09375 0.71875 4.578125 1.5q1.484375 0.78125 2.3125 2.140625q0.84375 1.34375 0.84375 3.34375q0 1.796875 -1.0 3.375q-1.0 1.578125 -2.84375 2.34375q-1.828125 0.765625 -4.5625 0.765625q-3.96875 0 -6.109375 -1.84375q-2.140625 -1.84375 -2.546875 -5.359375zm20.60846 -10.4375l0 -3.734375l4.015625 0l0 3.734375l-4.015625 0zm0 17.265625l0 -15.203125l4.015625 0l0 15.203125l-4.015625 0zm6.5233154 0l0 -3.140625l5.703125 -6.546875q1.40625 -1.59375 2.078125 -2.265625q-0.703125 0.03125 -1.84375 0.046875l-5.375 0.03125l0 -3.328125l12.578125 0l0 2.84375l-5.828125 6.703125l-2.046875 2.21875q1.6875 -0.09375 2.078125 -0.09375l6.234375 0l0 3.53125l-13.578125 0zm25.085938 -4.84375l4.015625 0.671875q-0.765625 2.203125 -2.4375 3.359375q-1.671875 1.15625 -4.171875 1.15625q-3.96875 0 -5.875 -2.59375q-1.5 -2.078125 -1.5 -5.234375q0 -3.78125 1.96875 -5.921875q1.984375 -2.140625 5.0 -2.140625q3.390625 0 5.34375 2.25q1.96875 2.234375 1.890625 6.859375l-10.078125 0q0.03125 1.78125 0.953125 2.78125q0.9375 1.0 2.328125 1.0q0.953125 0 1.59375 -0.515625q0.640625 -0.515625 0.96875 -1.671875zm0.234375 -4.0625q-0.046875 -1.75 -0.90625 -2.65625q-0.859375 -0.90625 -2.09375 -0.90625q-1.3125 0 -2.171875 0.953125q-0.859375 0.96875 -0.84375 2.609375l6.015625 0z" fill-rule="nonzero"/><path fill="#d9d9d9" d="m72.727 157.72179l792.69293 0l0 42.015747l-792.69293 0z" fill-rule="evenodd"/><path fill="#000000" d="m441.85666 181.11053l1.640625 -0.21875q0.28125 1.40625 0.953125 2.015625q0.6875 0.609375 1.65625 0.609375q1.15625 0 1.953125 -0.796875q0.796875 -0.796875 0.796875 -1.984375q0 -1.125 -0.734375 -1.859375q-0.734375 -0.734375 -1.875 -0.734375q-0.46875 0 -1.15625 0.171875l0.1875 -1.4375q0.15625 0.015625 0.265625 0.015625q1.046875 0 1.875 -0.546875q0.84375 -0.546875 0.84375 -1.671875q0 -0.90625 -0.609375 -1.5q-0.609375 -0.59375 -1.578125 -0.59375q-0.953125 0 -1.59375 0.609375q-0.640625 0.59375 -0.8125 1.796875l-1.640625 -0.296875q0.296875 -1.640625 1.359375 -2.546875q1.0625 -0.90625 2.65625 -0.90625q1.09375 0 2.0 0.46875q0.921875 0.46875 1.40625 1.28125q0.5 0.8125 0.5 1.71875q0 0.859375 -0.46875 1.578125q-0.46875 0.703125 -1.375 1.125q1.1875 0.28125 1.84375 1.140625q0.65625 0.859375 0.65625 2.15625q0 1.734375 -1.28125 2.953125q-1.265625 1.21875 -3.21875 1.21875q-1.765625 0 -2.921875 -1.046875q-1.15625 -1.046875 -1.328125 -2.71875zm18.985077 1.953125l0 1.578125l-8.828125 0q-0.015625 -0.59375 0.1875 -1.140625q0.34375 -0.90625 1.078125 -1.78125q0.75 -0.875 2.15625 -2.015625q2.171875 -1.78125 2.9375 -2.828125q0.765625 -1.046875 0.765625 -1.96875q0 -0.984375 -0.703125 -1.640625q-0.6875 -0.671875 -1.8125 -0.671875q-1.1875 0 -1.90625 0.71875q-0.703125 0.703125 -0.703125 1.953125l-1.6875 -0.171875q0.171875 -1.890625 1.296875 -2.875q1.140625 -0.984375 3.03125 -0.984375q1.921875 0 3.046875 1.0625q1.125 1.0625 1.125 2.640625q0 0.796875 -0.328125 1.578125q-0.328125 0.78125 -1.09375 1.640625q-0.75 0.84375 -2.53125 2.34375q-1.46875 1.234375 -1.890625 1.6875q-0.421875 0.4375 -0.6875 0.875l6.546875 0zm1.5788574 -2.4375l0 -1.640625l5.03125 0l0 1.640625l-5.03125 0zm8.353302 4.015625l-1.515625 0l0 -13.359375l1.640625 0l0 4.765625q1.046875 -1.296875 2.65625 -1.296875q0.890625 0 1.6875 0.359375q0.796875 0.359375 1.3125 1.015625q0.515625 0.640625 0.796875 1.5625q0.296875 0.921875 0.296875 1.96875q0 2.484375 -1.234375 3.84375q-1.21875 1.359375 -2.953125 1.359375q-1.703125 0 -2.6875 -1.4375l0 1.21875zm-0.015625 -4.90625q0 1.734375 0.484375 2.515625q0.765625 1.265625 2.09375 1.265625q1.078125 0 1.859375 -0.9375q0.78125 -0.9375 0.78125 -2.78125q0 -1.890625 -0.75 -2.796875q-0.75 -0.90625 -1.828125 -0.90625q-1.0625 0 -1.859375 0.9375q-0.78125 0.9375 -0.78125 2.703125zm8.891327 -6.5625l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm7.7229614 -1.46875l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625zm0.9489136 -1.421875l1.625 -0.25q0.125 0.96875 0.75 1.5q0.625 0.515625 1.75 0.515625q1.125 0 1.671875 -0.453125q0.546875 -0.46875 0.546875 -1.09375q0 -0.546875 -0.484375 -0.875q-0.328125 -0.21875 -1.671875 -0.546875q-1.8125 -0.46875 -2.515625 -0.796875q-0.6875 -0.328125 -1.046875 -0.90625q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.640625 0.296875 -1.1875q0.296875 -0.5625 0.8125 -0.921875q0.375 -0.28125 1.03125 -0.46875q0.671875 -0.203125 1.421875 -0.203125q1.140625 0 2.0 0.328125q0.859375 0.328125 1.265625 0.890625q0.421875 0.5625 0.578125 1.5l-1.609375 0.21875q-0.109375 -0.75 -0.640625 -1.171875q-0.515625 -0.421875 -1.46875 -0.421875q-1.140625 0 -1.625 0.375q-0.46875 0.375 -0.46875 0.875q0 0.3125 0.1875 0.578125q0.203125 0.265625 0.640625 0.4375q0.234375 0.09375 1.4375 0.421875q1.75 0.453125 2.4375 0.75q0.6875 0.296875 1.078125 0.859375q0.390625 0.5625 0.390625 1.40625q0 0.828125 -0.484375 1.546875q-0.46875 0.71875 -1.375 1.125q-0.90625 0.390625 -2.046875 0.390625q-1.875 0 -2.875 -0.78125q-0.984375 -0.78125 -1.25 -2.328125z" fill-rule="nonzero"/><path fill="#b7b7b7" fill-opacity="0.506" d="m72.727 256.0525l258.04724 0l0 42.015747l-258.04724 0z" fill-rule="evenodd"/><path fill="#000000" d="m181.3984 282.9725l-1.640625 0l0 -10.453125q-0.59375 0.5625 -1.5625 1.140625q-0.953125 0.5625 -1.71875 0.84375l0 -1.59375q1.375 -0.640625 2.40625 -1.5625q1.03125 -0.921875 1.453125 -1.78125l1.0625 0l0 13.40625zm8.990295 0l-1.640625 0l0 -10.453125q-0.59375 0.5625 -1.5625 1.140625q-0.953125 0.5625 -1.71875 0.84375l0 -1.59375q1.375 -0.640625 2.40625 -1.5625q1.03125 -0.921875 1.453125 -1.78125l1.0625 0l0 13.40625zm4.016342 -4.015625l0 -1.640625l5.03125 0l0 1.640625l-5.03125 0zm8.353302 4.015625l-1.515625 0l0 -13.359375l1.640625 0l0 4.765625q1.046875 -1.296875 2.65625 -1.296875q0.890625 0 1.6875 0.359375q0.796875 0.359375 1.3125 1.015625q0.515625 0.640625 0.796875 1.5625q0.296875 0.921875 0.296875 1.96875q0 2.484375 -1.234375 3.84375q-1.21875 1.359375 -2.953125 1.359375q-1.703125 0 -2.6875 -1.4375l0 1.21875zm-0.015625 -4.90625q0 1.734375 0.484375 2.515625q0.765625 1.265625 2.09375 1.265625q1.078125 0 1.859375 -0.9375q0.78125 -0.9375 0.78125 -2.78125q0 -1.890625 -0.75 -2.796875q-0.75 -0.90625 -1.828125 -0.90625q-1.0625 0 -1.859375 0.9375q-0.78125 0.9375 -0.78125 2.703125zm8.891342 -6.5625l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm7.722946 -1.46875l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625zm0.94892883 -1.421875l1.625 -0.25q0.125 0.96875 0.75 1.5q0.625 0.515625 1.75 0.515625q1.125 0 1.671875 -0.453125q0.546875 -0.46875 0.546875 -1.09375q0 -0.546875 -0.484375 -0.875q-0.328125 -0.21875 -1.671875 -0.546875q-1.8125 -0.46875 -2.515625 -0.796875q-0.6875 -0.328125 -1.046875 -0.90625q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.640625 0.296875 -1.1875q0.296875 -0.5625 0.8125 -0.921875q0.375 -0.28125 1.03125 -0.46875q0.671875 -0.203125 1.421875 -0.203125q1.140625 0 2.0 0.328125q0.859375 0.328125 1.265625 0.890625q0.421875 0.5625 0.578125 1.5l-1.609375 0.21875q-0.109375 -0.75 -0.640625 -1.171875q-0.515625 -0.421875 -1.46875 -0.421875q-1.140625 0 -1.625 0.375q-0.46875 0.375 -0.46875 0.875q0 0.3125 0.1875 0.578125q0.203125 0.265625 0.640625 0.4375q0.234375 0.09375 1.4375 0.421875q1.75 0.453125 2.4375 0.75q0.6875 0.296875 1.078125 0.859375q0.390625 0.5625 0.390625 1.40625q0 0.828125 -0.484375 1.546875q-0.46875 0.71875 -1.375 1.125q-0.90625 0.390625 -2.046875 0.390625q-1.875 0 -2.875 -0.78125q-0.984375 -0.78125 -1.25 -2.328125z" fill-rule="nonzero"/><path fill="#b7b7b7" fill-opacity="0.506" d="m328.50876 256.0525l536.9133 0l0 42.015747l-536.9133 0z" fill-rule="evenodd"/><path fill="#000000" d="m578.35803 281.39438l0 1.578125l-8.828125 0q-0.015625 -0.59375 0.1875 -1.140625q0.34375 -0.90625 1.078125 -1.78125q0.75 -0.875 2.15625 -2.015625q2.171875 -1.78125 2.9375 -2.828125q0.765625 -1.046875 0.765625 -1.96875q0 -0.984375 -0.703125 -1.640625q-0.6875 -0.671875 -1.8125 -0.671875q-1.1875 0 -1.90625 0.71875q-0.703125 0.703125 -0.703125 1.953125l-1.6875 -0.171875q0.171875 -1.890625 1.296875 -2.875q1.140625 -0.984375 3.03125 -0.984375q1.921875 0 3.046875 1.0625q1.125 1.0625 1.125 2.640625q0 0.796875 -0.328125 1.578125q-0.328125 0.78125 -1.09375 1.640625q-0.75 0.84375 -2.53125 2.34375q-1.46875 1.234375 -1.890625 1.6875q-0.421875 0.4375 -0.6875 0.875l6.546875 0zm7.9382324 1.578125l-1.640625 0l0 -10.453125q-0.59375 0.5625 -1.5625 1.140625q-0.953125 0.5625 -1.71875 0.84375l0 -1.59375q1.375 -0.640625 2.40625 -1.5625q1.03125 -0.921875 1.453125 -1.78125l1.0625 0l0 13.40625zm4.0163574 -4.015625l0 -1.640625l5.03125 0l0 1.640625l-5.03125 0zm8.3532715 4.015625l-1.515625 0l0 -13.359375l1.640625 0l0 4.765625q1.046875 -1.296875 2.65625 -1.296875q0.890625 0 1.6875 0.359375q0.796875 0.359375 1.3125 1.015625q0.515625 0.640625 0.796875 1.5625q0.296875 0.921875 0.296875 1.96875q0 2.484375 -1.234375 3.84375q-1.21875 1.359375 -2.953125 1.359375q-1.703125 0 -2.6875 -1.4375l0 1.21875zm-0.015625 -4.90625q0 1.734375 0.484375 2.515625q0.765625 1.265625 2.09375 1.265625q1.078125 0 1.859375 -0.9375q0.78125 -0.9375 0.78125 -2.78125q0 -1.890625 -0.75 -2.796875q-0.75 -0.90625 -1.828125 -0.90625q-1.0625 0 -1.859375 0.9375q-0.78125 0.9375 -0.78125 2.703125zm8.891357 -6.5625l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm7.7229614 -1.46875l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625zm0.9489136 -1.421875l1.625 -0.25q0.125 0.96875 0.75 1.5q0.625 0.515625 1.75 0.515625q1.125 0 1.671875 -0.453125q0.546875 -0.46875 0.546875 -1.09375q0 -0.546875 -0.484375 -0.875q-0.328125 -0.21875 -1.671875 -0.546875q-1.8125 -0.46875 -2.515625 -0.796875q-0.6875 -0.328125 -1.046875 -0.90625q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.640625 0.296875 -1.1875q0.296875 -0.5625 0.8125 -0.921875q0.375 -0.28125 1.03125 -0.46875q0.671875 -0.203125 1.421875 -0.203125q1.140625 0 2.0 0.328125q0.859375 0.328125 1.265625 0.890625q0.421875 0.5625 0.578125 1.5l-1.609375 0.21875q-0.109375 -0.75 -0.640625 -1.171875q-0.515625 -0.421875 -1.46875 -0.421875q-1.140625 0 -1.625 0.375q-0.46875 0.375 -0.46875 0.875q0 0.3125 0.1875 0.578125q0.203125 0.265625 0.640625 0.4375q0.234375 0.09375 1.4375 0.421875q1.75 0.453125 2.4375 0.75q0.6875 0.296875 1.078125 0.859375q0.390625 0.5625 0.390625 1.40625q0 0.828125 -0.484375 1.546875q-0.46875 0.71875 -1.375 1.125q-0.90625 0.390625 -2.046875 0.390625q-1.875 0 -2.875 -0.78125q-0.984375 -0.78125 -1.25 -2.328125z" fill-rule="nonzero"/><path fill="#93c47d" d="m72.72711 298.06824l792.69293 0l0 98.33072l-792.69293 0z" fill-rule="evenodd"/><path fill="#000000" d="m439.4145 314.22824l7.734375 0q2.625 0 4.0 0.40625q1.84375 0.546875 3.15625 1.9375q1.328125 1.390625 2.015625 3.40625q0.6875 2.0 0.6875 4.953125q0 2.59375 -0.640625 4.46875q-0.796875 2.296875 -2.25 3.703125q-1.109375 1.078125 -2.984375 1.6875q-1.40625 0.4375 -3.75 0.4375l-7.96875 0l0 -21.0zm4.234375 3.5625l0 13.90625l3.15625 0q1.78125 0 2.578125 -0.203125q1.03125 -0.265625 1.703125 -0.875q0.6875 -0.625 1.109375 -2.03125q0.4375 -1.40625 0.4375 -3.84375q0 -2.4375 -0.4375 -3.734375q-0.421875 -1.296875 -1.203125 -2.03125q-0.765625 -0.734375 -1.953125 -0.984375q-0.890625 -0.203125 -3.484375 -0.203125l-1.90625 0zm19.92984 6.875l-3.65625 -0.671875q0.625 -2.203125 2.125 -3.25q1.5 -1.0625 4.46875 -1.0625q2.6875 0 4.0 0.640625q1.328125 0.625 1.859375 1.609375q0.546875 0.984375 0.546875 3.609375l-0.046875 4.6875q0 2.0 0.1875 2.953125q0.203125 0.953125 0.734375 2.046875l-3.984375 0q-0.15625 -0.40625 -0.390625 -1.1875q-0.09375 -0.359375 -0.140625 -0.46875q-1.03125 1.0 -2.203125 1.5q-1.171875 0.5 -2.515625 0.5q-2.34375 0 -3.703125 -1.265625q-1.34375 -1.28125 -1.34375 -3.234375q0 -1.28125 0.609375 -2.28125q0.625 -1.015625 1.734375 -1.546875q1.109375 -0.546875 3.203125 -0.953125q2.8125 -0.53125 3.90625 -0.984375l0 -0.40625q0 -1.15625 -0.578125 -1.640625q-0.578125 -0.5 -2.15625 -0.5q-1.078125 0 -1.6875 0.421875q-0.59375 0.421875 -0.96875 1.484375zm5.390625 3.265625q-0.78125 0.25 -2.453125 0.609375q-1.671875 0.359375 -2.1875 0.703125q-0.796875 0.5625 -0.796875 1.421875q0 0.84375 0.625 1.46875q0.640625 0.609375 1.609375 0.609375q1.09375 0 2.078125 -0.71875q0.734375 -0.546875 0.96875 -1.34375q0.15625 -0.515625 0.15625 -1.953125l0 -0.796875zm14.889038 -7.90625l0 3.203125l-2.75 0l0 6.125q0 1.859375 0.078125 2.171875q0.078125 0.3125 0.359375 0.515625q0.28125 0.1875 0.6875 0.1875q0.546875 0 1.609375 -0.375l0.34375 3.125q-1.40625 0.59375 -3.171875 0.59375q-1.09375 0 -1.96875 -0.359375q-0.875 -0.375 -1.28125 -0.953125q-0.40625 -0.578125 -0.5625 -1.5625q-0.125 -0.703125 -0.125 -2.84375l0 -6.625l-1.859375 0l0 -3.203125l1.859375 0l0 -3.03125l4.03125 -2.34375l0 5.375l2.75 0zm5.79776 4.640625l-3.65625 -0.671875q0.625 -2.203125 2.125 -3.25q1.5 -1.0625 4.46875 -1.0625q2.6875 0 4.0 0.640625q1.328125 0.625 1.859375 1.609375q0.546875 0.984375 0.546875 3.609375l-0.046875 4.6875q0 2.0 0.1875 2.953125q0.203125 0.953125 0.734375 2.046875l-3.984375 0q-0.15625 -0.40625 -0.390625 -1.1875q-0.09375 -0.359375 -0.140625 -0.46875q-1.03125 1.0 -2.203125 1.5q-1.171875 0.5 -2.515625 0.5q-2.34375 0 -3.703125 -1.265625q-1.34375 -1.28125 -1.34375 -3.234375q0 -1.28125 0.609375 -2.28125q0.625 -1.015625 1.734375 -1.546875q1.109375 -0.546875 3.203125 -0.953125q2.8125 -0.53125 3.90625 -0.984375l0 -0.40625q0 -1.15625 -0.578125 -1.640625q-0.578125 -0.5 -2.15625 -0.5q-1.078125 0 -1.6875 0.421875q-0.59375 0.421875 -0.96875 1.484375zm5.390625 3.265625q-0.78125 0.25 -2.453125 0.609375q-1.671875 0.359375 -2.1875 0.703125q-0.796875 0.5625 -0.796875 1.421875q0 0.84375 0.625 1.46875q0.640625 0.609375 1.609375 0.609375q1.09375 0 2.078125 -0.71875q0.734375 -0.546875 0.96875 -1.34375q0.15625 -0.515625 0.15625 -1.953125l0 -0.796875z" fill-rule="nonzero"/><path fill="#b7b7b7" fill-opacity="0.506" d="m77.25217 354.3832l788.1575 0l0 42.015747l-788.1575 0z" fill-rule="evenodd"/><path fill="#000000" d="m350.89865 374.8032q0 -3.328125 1.78125 -5.203125q1.78125 -1.890625 4.609375 -1.890625q1.84375 0 3.328125 0.890625q1.484375 0.875 2.265625 2.46875q0.78125 1.578125 0.78125 3.578125q0 2.03125 -0.828125 3.640625q-0.8125 1.59375 -2.3125 2.421875q-1.5 0.828125 -3.25 0.828125q-1.875 0 -3.359375 -0.90625q-1.484375 -0.921875 -2.25 -2.5q-0.765625 -1.578125 -0.765625 -3.328125zm1.8125 0.015625q0 2.421875 1.296875 3.8125q1.296875 1.390625 3.265625 1.390625q2.0 0 3.28125 -1.40625q1.28125 -1.40625 1.28125 -3.984375q0 -1.625 -0.546875 -2.84375q-0.546875 -1.21875 -1.609375 -1.875q-1.0625 -0.671875 -2.375 -0.671875q-1.890625 0 -3.25 1.296875q-1.34375 1.28125 -1.34375 4.28125zm13.027039 10.1875l0 -13.375l1.484375 0l0 1.25q0.53125 -0.734375 1.1875 -1.09375q0.671875 -0.375 1.625 -0.375q1.234375 0 2.171875 0.640625q0.953125 0.625 1.4375 1.796875q0.484375 1.15625 0.484375 2.546875q0 1.484375 -0.53125 2.671875q-0.53125 1.1875 -1.546875 1.828125q-1.015625 0.625 -2.140625 0.625q-0.8125 0 -1.46875 -0.34375q-0.65625 -0.34375 -1.0625 -0.875l0 4.703125l-1.640625 0zm1.484375 -8.484375q0 1.859375 0.75 2.765625q0.765625 0.890625 1.828125 0.890625q1.09375 0 1.875 -0.921875q0.78125 -0.9375 0.78125 -2.875q0 -1.84375 -0.765625 -2.765625q-0.75 -0.921875 -1.8125 -0.921875q-1.046875 0 -1.859375 0.984375q-0.796875 0.96875 -0.796875 2.84375zm12.469482 3.3125l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625zm1.6051636 -10.0l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm3.5354614 -4.84375q0 -2.6875 1.484375 -3.96875q1.25 -1.078125 3.046875 -1.078125q2.0 0 3.265625 1.3125q1.265625 1.296875 1.265625 3.609375q0 1.859375 -0.5625 2.9375q-0.5625 1.0625 -1.640625 1.65625q-1.0625 0.59375 -2.328125 0.59375q-2.03125 0 -3.28125 -1.296875q-1.25 -1.3125 -1.25 -3.765625zm1.6875 0q0 1.859375 0.796875 2.796875q0.8125 0.921875 2.046875 0.921875q1.21875 0 2.03125 -0.921875q0.8125 -0.9375 0.8125 -2.84375q0 -1.796875 -0.8125 -2.71875q-0.8125 -0.921875 -2.03125 -0.921875q-1.234375 0 -2.046875 0.921875q-0.796875 0.90625 -0.796875 2.765625zm9.297607 4.84375l0 -9.671875l1.46875 0l0 1.375q1.0625 -1.59375 3.078125 -1.59375q0.875 0 1.609375 0.3125q0.734375 0.3125 1.09375 0.828125q0.375 0.5 0.515625 1.203125q0.09375 0.453125 0.09375 1.59375l0 5.953125l-1.640625 0l0 -5.890625q0 -1.0 -0.203125 -1.484375q-0.1875 -0.5 -0.671875 -0.796875q-0.484375 -0.296875 -1.140625 -0.296875q-1.046875 0 -1.8125 0.671875q-0.75 0.65625 -0.75 2.515625l0 5.28125l-1.640625 0zm16.688202 -1.1875q-0.921875 0.765625 -1.765625 1.09375q-0.828125 0.3125 -1.796875 0.3125q-1.59375 0 -2.453125 -0.78125q-0.859375 -0.78125 -0.859375 -1.984375q0 -0.71875 0.328125 -1.296875q0.328125 -0.59375 0.84375 -0.9375q0.53125 -0.359375 1.1875 -0.546875q0.46875 -0.125 1.453125 -0.25q1.984375 -0.234375 2.921875 -0.5625q0.015625 -0.34375 0.015625 -0.421875q0 -1.0 -0.46875 -1.421875q-0.625 -0.546875 -1.875 -0.546875q-1.15625 0 -1.703125 0.40625q-0.546875 0.40625 -0.8125 1.421875l-1.609375 -0.21875q0.21875 -1.015625 0.71875 -1.640625q0.5 -0.640625 1.453125 -0.984375q0.953125 -0.34375 2.1875 -0.34375q1.25 0 2.015625 0.296875q0.78125 0.28125 1.140625 0.734375q0.375 0.4375 0.515625 1.109375q0.078125 0.421875 0.078125 1.515625l0 2.1875q0 2.28125 0.109375 2.890625q0.109375 0.59375 0.40625 1.15625l-1.703125 0q-0.265625 -0.515625 -0.328125 -1.1875zm-0.140625 -3.671875q-0.890625 0.375 -2.671875 0.625q-1.015625 0.140625 -1.4375 0.328125q-0.421875 0.1875 -0.65625 0.53125q-0.21875 0.34375 -0.21875 0.78125q0 0.65625 0.5 1.09375q0.5 0.4375 1.453125 0.4375q0.9375 0 1.671875 -0.40625q0.75 -0.421875 1.09375 -1.140625q0.265625 -0.5625 0.265625 -1.640625l0 -0.609375zm4.156952 4.859375l0 -13.359375l1.640625 0l0 13.359375l-1.640625 0zm17.0 -1.578125q-0.8125 0.90625 -1.765625 1.359375q-0.953125 0.453125 -2.0625 0.453125q-2.046875 0 -3.25 -1.390625q-0.984375 -1.125 -0.984375 -2.53125q0 -1.234375 0.796875 -2.234375q0.796875 -1.0 2.390625 -1.75q-0.90625 -1.03125 -1.203125 -1.671875q-0.296875 -0.65625 -0.296875 -1.265625q0 -1.203125 0.9375 -2.078125q0.9375 -0.890625 2.375 -0.890625q1.359375 0 2.234375 0.84375q0.875 0.828125 0.875 2.0q0 1.90625 -2.53125 3.25l2.390625 3.0625q0.421875 -0.8125 0.640625 -1.859375l1.703125 0.359375q-0.4375 1.75 -1.1875 2.875q0.921875 1.21875 2.09375 2.046875l-1.109375 1.3125q-0.984375 -0.640625 -2.046875 -1.890625zm-3.328125 -6.953125q1.0625 -0.640625 1.375 -1.109375q0.3125 -0.46875 0.3125 -1.046875q0 -0.6875 -0.4375 -1.109375q-0.421875 -0.4375 -1.0625 -0.4375q-0.671875 0 -1.125 0.4375q-0.4375 0.421875 -0.4375 1.03125q0 0.3125 0.15625 0.65625q0.171875 0.34375 0.484375 0.734375l0.734375 0.84375zm2.296875 5.65625l-3.0 -3.71875q-1.328125 0.796875 -1.796875 1.46875q-0.46875 0.671875 -0.46875 1.34375q0 0.8125 0.640625 1.6875q0.65625 0.875 1.84375 0.875q0.734375 0 1.515625 -0.453125q0.796875 -0.46875 1.265625 -1.203125zm11.033142 6.578125l0 -13.375l1.484375 0l0 1.25q0.53125 -0.734375 1.1875 -1.09375q0.671875 -0.375 1.625 -0.375q1.234375 0 2.171875 0.640625q0.953125 0.625 1.4375 1.796875q0.484375 1.15625 0.484375 2.546875q0 1.484375 -0.53125 2.671875q-0.53125 1.1875 -1.546875 1.828125q-1.015625 0.625 -2.140625 0.625q-0.8125 0 -1.46875 -0.34375q-0.65625 -0.34375 -1.0625 -0.875l0 4.703125l-1.640625 0zm1.484375 -8.484375q0 1.859375 0.75 2.765625q0.765625 0.890625 1.828125 0.890625q1.09375 0 1.875 -0.921875q0.78125 -0.9375 0.78125 -2.875q0 -1.84375 -0.765625 -2.765625q-0.75 -0.921875 -1.8125 -0.921875q-1.046875 0 -1.859375 0.984375q-0.796875 0.96875 -0.796875 2.84375zm8.281982 -0.0625q0 -2.6875 1.484375 -3.96875q1.25 -1.078125 3.046875 -1.078125q2.0 0 3.265625 1.3125q1.265625 1.296875 1.265625 3.609375q0 1.859375 -0.5625 2.9375q-0.5625 1.0625 -1.640625 1.65625q-1.0625 0.59375 -2.328125 0.59375q-2.03125 0 -3.28125 -1.296875q-1.25 -1.3125 -1.25 -3.765625zm1.6875 0q0 1.859375 0.796875 2.796875q0.8125 0.921875 2.046875 0.921875q1.21875 0 2.03125 -0.921875q0.8125 -0.9375 0.8125 -2.84375q0 -1.796875 -0.8125 -2.71875q-0.8125 -0.921875 -2.03125 -0.921875q-1.234375 0 -2.046875 0.921875q-0.796875 0.90625 -0.796875 2.765625zm8.641327 1.953125l1.625 -0.25q0.125 0.96875 0.75 1.5q0.625 0.515625 1.75 0.515625q1.125 0 1.671875 -0.453125q0.546875 -0.46875 0.546875 -1.09375q0 -0.546875 -0.484375 -0.875q-0.328125 -0.21875 -1.671875 -0.546875q-1.8125 -0.46875 -2.515625 -0.796875q-0.6875 -0.328125 -1.046875 -0.90625q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.640625 0.296875 -1.1875q0.296875 -0.5625 0.8125 -0.921875q0.375 -0.28125 1.03125 -0.46875q0.671875 -0.203125 1.421875 -0.203125q1.140625 0 2.0 0.328125q0.859375 0.328125 1.265625 0.890625q0.421875 0.5625 0.578125 1.5l-1.609375 0.21875q-0.109375 -0.75 -0.640625 -1.171875q-0.515625 -0.421875 -1.46875 -0.421875q-1.140625 0 -1.625 0.375q-0.46875 0.375 -0.46875 0.875q0 0.3125 0.1875 0.578125q0.203125 0.265625 0.640625 0.4375q0.234375 0.09375 1.4375 0.421875q1.75 0.453125 2.4375 0.75q0.6875 0.296875 1.078125 0.859375q0.390625 0.5625 0.390625 1.40625q0 0.828125 -0.484375 1.546875q-0.46875 0.71875 -1.375 1.125q-0.90625 0.390625 -2.046875 0.390625q-1.875 0 -2.875 -0.78125q-0.984375 -0.78125 -1.25 -2.328125zm9.328125 0l1.625 -0.25q0.125 0.96875 0.75 1.5q0.625 0.515625 1.75 0.515625q1.125 0 1.671875 -0.453125q0.546875 -0.46875 0.546875 -1.09375q0 -0.546875 -0.484375 -0.875q-0.328125 -0.21875 -1.671875 -0.546875q-1.8125 -0.46875 -2.515625 -0.796875q-0.6875 -0.328125 -1.046875 -0.90625q-0.359375 -0.59375 -0.359375 -1.3125q0 -0.640625 0.296875 -1.1875q0.296875 -0.5625 0.8125 -0.921875q0.375 -0.28125 1.03125 -0.46875q0.671875 -0.203125 1.421875 -0.203125q1.140625 0 2.0 0.328125q0.859375 0.328125 1.265625 0.890625q0.421875 0.5625 0.578125 1.5l-1.609375 0.21875q-0.109375 -0.75 -0.640625 -1.171875q-0.515625 -0.421875 -1.46875 -0.421875q-1.140625 0 -1.625 0.375q-0.46875 0.375 -0.46875 0.875q0 0.3125 0.1875 0.578125q0.203125 0.265625 0.640625 0.4375q0.234375 0.09375 1.4375 0.421875q1.75 0.453125 2.4375 0.75q0.6875 0.296875 1.078125 0.859375q0.390625 0.5625 0.390625 1.40625q0 0.828125 -0.484375 1.546875q-0.46875 0.71875 -1.375 1.125q-0.90625 0.390625 -2.046875 0.390625q-1.875 0 -2.875 -0.78125q-0.984375 -0.78125 -1.25 -2.328125zm9.984375 -8.578125l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm5.644806 0l-1.515625 0l0 -13.359375l1.640625 0l0 4.765625q1.046875 -1.296875 2.65625 -1.296875q0.890625 0 1.6875 0.359375q0.796875 0.359375 1.3125 1.015625q0.515625 0.640625 0.796875 1.5625q0.296875 0.921875 0.296875 1.96875q0 2.484375 -1.234375 3.84375q-1.21875 1.359375 -2.953125 1.359375q-1.703125 0 -2.6875 -1.4375l0 1.21875zm-0.015625 -4.90625q0 1.734375 0.484375 2.515625q0.765625 1.265625 2.09375 1.265625q1.078125 0 1.859375 -0.9375q0.78125 -0.9375 0.78125 -2.78125q0 -1.890625 -0.75 -2.796875q-0.75 -0.90625 -1.828125 -0.90625q-1.0625 0 -1.859375 0.9375q-0.78125 0.9375 -0.78125 2.703125zm8.844482 4.90625l0 -13.359375l1.640625 0l0 13.359375l-1.640625 0zm4.1135864 3.71875l-0.1875 -1.53125q0.546875 0.140625 0.9375 0.140625q0.546875 0 0.875 -0.1875q0.328125 -0.171875 0.546875 -0.5q0.15625 -0.25 0.5 -1.21875q0.046875 -0.140625 0.140625 -0.40625l-3.671875 -9.6875l1.765625 0l2.015625 5.59375q0.390625 1.078125 0.703125 2.25q0.28125 -1.125 0.671875 -2.203125l2.078125 -5.640625l1.640625 0l-3.6875 9.828125q-0.59375 1.609375 -0.921875 2.203125q-0.4375 0.8125 -1.0 1.1875q-0.5625 0.375 -1.34375 0.375q-0.484375 0 -1.0625 -0.203125zm14.573944 -3.71875l0 -9.671875l1.46875 0l0 1.46875q0.5625 -1.03125 1.03125 -1.359375q0.484375 -0.328125 1.0625 -0.328125q0.828125 0 1.6875 0.53125l-0.5625 1.515625q-0.609375 -0.359375 -1.203125 -0.359375q-0.546875 0 -0.96875 0.328125q-0.421875 0.328125 -0.609375 0.890625q-0.28125 0.875 -0.28125 1.921875l0 5.0625l-1.625 0zm12.8532715 -3.109375l1.6875 0.203125q-0.40625 1.484375 -1.484375 2.3125q-1.078125 0.8125 -2.765625 0.8125q-2.125 0 -3.375 -1.296875q-1.234375 -1.3125 -1.234375 -3.671875q0 -2.453125 1.25 -3.796875q1.265625 -1.34375 3.265625 -1.34375q1.9375 0 3.15625 1.328125q1.234375 1.3125 1.234375 3.703125q0 0.15625 0 0.4375l-7.21875 0q0.09375 1.59375 0.90625 2.453125q0.8125 0.84375 2.015625 0.84375q0.90625 0 1.546875 -0.46875q0.640625 -0.484375 1.015625 -1.515625zm-5.390625 -2.65625l5.40625 0q-0.109375 -1.21875 -0.625 -1.828125q-0.78125 -0.953125 -2.03125 -0.953125q-1.125 0 -1.90625 0.765625q-0.765625 0.75 -0.84375 2.015625zm9.141357 9.46875l0 -13.375l1.484375 0l0 1.25q0.53125 -0.734375 1.1875 -1.09375q0.671875 -0.375 1.625 -0.375q1.234375 0 2.171875 0.640625q0.953125 0.625 1.4375 1.796875q0.484375 1.15625 0.484375 2.546875q0 1.484375 -0.53125 2.671875q-0.53125 1.1875 -1.546875 1.828125q-1.015625 0.625 -2.140625 0.625q-0.8125 0 -1.46875 -0.34375q-0.65625 -0.34375 -1.0625 -0.875l0 4.703125l-1.640625 0zm1.484375 -8.484375q0 1.859375 0.75 2.765625q0.765625 0.890625 1.828125 0.890625q1.09375 0 1.875 -0.921875q0.78125 -0.9375 0.78125 -2.875q0 -1.84375 -0.765625 -2.765625q-0.75 -0.921875 -1.8125 -0.921875q-1.046875 0 -1.859375 0.984375q-0.796875 0.96875 -0.796875 2.84375zm15.516357 1.671875l1.6875 0.203125q-0.40625 1.484375 -1.484375 2.3125q-1.078125 0.8125 -2.765625 0.8125q-2.125 0 -3.375 -1.296875q-1.234375 -1.3125 -1.234375 -3.671875q0 -2.453125 1.25 -3.796875q1.265625 -1.34375 3.265625 -1.34375q1.9375 0 3.15625 1.328125q1.234375 1.3125 1.234375 3.703125q0 0.15625 0 0.4375l-7.21875 0q0.09375 1.59375 0.90625 2.453125q0.8125 0.84375 2.015625 0.84375q0.90625 0 1.546875 -0.46875q0.640625 -0.484375 1.015625 -1.515625zm-5.390625 -2.65625l5.40625 0q-0.109375 -1.21875 -0.625 -1.828125q-0.78125 -0.953125 -2.03125 -0.953125q-1.125 0 -1.90625 0.765625q-0.765625 0.75 -0.84375 2.015625zm15.453857 4.578125q-0.921875 0.765625 -1.765625 1.09375q-0.828125 0.3125 -1.796875 0.3125q-1.59375 0 -2.453125 -0.78125q-0.859375 -0.78125 -0.859375 -1.984375q0 -0.71875 0.328125 -1.296875q0.328125 -0.59375 0.84375 -0.9375q0.53125 -0.359375 1.1875 -0.546875q0.46875 -0.125 1.453125 -0.25q1.984375 -0.234375 2.921875 -0.5625q0.015625 -0.34375 0.015625 -0.421875q0 -1.0 -0.46875 -1.421875q-0.625 -0.546875 -1.875 -0.546875q-1.15625 0 -1.703125 0.40625q-0.546875 0.40625 -0.8125 1.421875l-1.609375 -0.21875q0.21875 -1.015625 0.71875 -1.640625q0.5 -0.640625 1.453125 -0.984375q0.953125 -0.34375 2.1875 -0.34375q1.25 0 2.015625 0.296875q0.78125 0.28125 1.140625 0.734375q0.375 0.4375 0.515625 1.109375q0.078125 0.421875 0.078125 1.515625l0 2.1875q0 2.28125 0.109375 2.890625q0.109375 0.59375 0.40625 1.15625l-1.703125 0q-0.265625 -0.515625 -0.328125 -1.1875zm-0.140625 -3.671875q-0.890625 0.375 -2.671875 0.625q-1.015625 0.140625 -1.4375 0.328125q-0.421875 0.1875 -0.65625 0.53125q-0.21875 0.34375 -0.21875 0.78125q0 0.65625 0.5 1.09375q0.5 0.4375 1.453125 0.4375q0.9375 0 1.671875 -0.40625q0.75 -0.421875 1.09375 -1.140625q0.265625 -0.5625 0.265625 -1.640625l0 -0.609375zm7.7819214 3.390625l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625zm1.6052246 -10.0l0 -1.890625l1.640625 0l0 1.890625l-1.640625 0zm0 11.46875l0 -9.671875l1.640625 0l0 9.671875l-1.640625 0zm4.1447754 0l0 -9.671875l1.46875 0l0 1.375q1.0625 -1.59375 3.078125 -1.59375q0.875 0 1.609375 0.3125q0.734375 0.3125 1.09375 0.828125q0.375 0.5 0.515625 1.203125q0.09375 0.453125 0.09375 1.59375l0 5.953125l-1.640625 0l0 -5.890625q0 -1.0 -0.203125 -1.484375q-0.1875 -0.5 -0.671875 -0.796875q-0.484375 -0.296875 -1.140625 -0.296875q-1.046875 0 -1.8125 0.671875q-0.75 0.65625 -0.75 2.515625l0 5.28125l-1.640625 0zm10.063232 0.796875l1.59375 0.234375q0.109375 0.75 0.5625 1.078125q0.609375 0.453125 1.671875 0.453125q1.140625 0 1.75 -0.453125q0.625 -0.453125 0.84375 -1.265625q0.125 -0.5 0.109375 -2.109375q-1.0625 1.265625 -2.671875 1.265625q-2.0 0 -3.09375 -1.4375q-1.09375 -1.4375 -1.09375 -3.453125q0 -1.390625 0.5 -2.5625q0.515625 -1.171875 1.453125 -1.796875q0.953125 -0.640625 2.25 -0.640625q1.703125 0 2.8125 1.375l0 -1.15625l1.515625 0l0 8.359375q0 2.265625 -0.46875 3.203125q-0.453125 0.9375 -1.453125 1.484375q-0.984375 0.546875 -2.453125 0.546875q-1.71875 0 -2.796875 -0.78125q-1.0625 -0.765625 -1.03125 -2.34375zm1.359375 -5.8125q0 1.90625 0.75 2.78125q0.765625 0.875 1.90625 0.875q1.125 0 1.890625 -0.859375q0.765625 -0.875 0.765625 -2.734375q0 -1.78125 -0.796875 -2.671875q-0.78125 -0.90625 -1.890625 -0.90625q-1.09375 0 -1.859375 0.890625q-0.765625 0.875 -0.765625 2.625z" fill-rule="nonzero"/></g></svg>
\ No newline at end of file
diff --git a/docs/security/research/graphics/vulnerabilities/README.md b/docs/security/research/graphics/vulnerabilities/README.md
new file mode 100644
index 0000000..a0d9ebd
--- /dev/null
+++ b/docs/security/research/graphics/vulnerabilities/README.md
@@ -0,0 +1,12 @@
+# Vulnerability Discovery: Chromium Graphics
+
+This directory contains notes on vulnerabilities found during the study of
+Chromium graphics subsystems.
+
+Notes about vulnerabilities are kept separate from general descriptions of
+features so we can publish general information without exposing sensitive
+details about vulnerabilities that may not yet be fixed.
+
+Aside from the issue of sensitivity, it's useful to talk about vulnerabilities
+separately so we can go into detail about the *process* of vulnerability
+discovery, including what worked and what didn't.
diff --git a/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc b/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc
index 52117c00a..383e6c5 100644
--- a/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc
+++ b/extensions/browser/api/feedback_private/feedback_private_api_chromeos_unittest.cc
@@ -280,7 +280,7 @@
   EXPECT_TRUE(
       RunReadLogSourceFunction(params, &result_reader_id, &result_string));
   EXPECT_EQ(*params.reader_id, result_reader_id);
-  EXPECT_EQ("[MAC OUI=11:22:33 IFACE=1]", result_string);
+  EXPECT_EQ("(MAC OUI=11:22:33 IFACE=1)", result_string);
 }
 
 TEST_F(FeedbackPrivateApiUnittest, ReadLogSourceMultipleSources) {
diff --git a/extensions/browser/api/messaging/extension_message_port.cc b/extensions/browser/api/messaging/extension_message_port.cc
index ac11c03..a1a19959 100644
--- a/extensions/browser/api/messaging/extension_message_port.cc
+++ b/extensions/browser/api/messaging/extension_message_port.cc
@@ -26,6 +26,7 @@
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/browser/process_manager_observer.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/api/messaging/message.h"
 #include "extensions/common/api/messaging/messaging_endpoint.h"
 #include "extensions/common/extension_messages.h"
@@ -285,6 +286,7 @@
 }
 
 void ExtensionMessagePort::DispatchOnConnect(
+    ChannelType channel_type,
     const std::string& channel_name,
     absl::optional<base::Value::Dict> source_tab,
     const ExtensionApiFrameIdMap::FrameData& source_frame,
@@ -297,9 +299,10 @@
   SendToPort(base::BindRepeating(
       &ExtensionMessagePort::BuildDispatchOnConnectIPC,
       // Called synchronously.
-      base::Unretained(this), channel_name, base::OptionalToPtr(source_tab),
-      source_frame, guest_process_id, guest_render_frame_routing_id,
-      source_endpoint, target_extension_id, source_url, source_origin));
+      base::Unretained(this), channel_type, channel_name,
+      base::OptionalToPtr(source_tab), source_frame, guest_process_id,
+      guest_render_frame_routing_id, source_endpoint, target_extension_id,
+      source_url, source_origin));
 }
 
 void ExtensionMessagePort::DispatchOnDisconnect(
@@ -555,6 +558,7 @@
 }
 
 std::unique_ptr<IPC::Message> ExtensionMessagePort::BuildDispatchOnConnectIPC(
+    ChannelType channel_type,
     const std::string& channel_name,
     const base::Value::Dict* source_tab,
     const ExtensionApiFrameIdMap::FrameData& source_frame,
@@ -584,9 +588,15 @@
   info.guest_process_id = guest_process_id;
   info.guest_render_frame_routing_id = guest_render_frame_routing_id;
 
+  ExtensionMsg_OnConnectData connect_data;
+  connect_data.target_port_id = port_id_;
+  connect_data.channel_type = channel_type;
+  connect_data.channel_name = channel_name;
+  connect_data.tab_source = std::move(source);
+  connect_data.external_connection_info = std::move(info);
+
   return std::make_unique<ExtensionMsg_DispatchOnConnect>(
-      MSG_ROUTING_NONE, target.worker_thread_id, port_id_, channel_name, source,
-      info);
+      MSG_ROUTING_NONE, target.worker_thread_id, connect_data);
 }
 
 std::unique_ptr<IPC::Message>
diff --git a/extensions/browser/api/messaging/extension_message_port.h b/extensions/browser/api/messaging/extension_message_port.h
index eafd977..fe80ae5 100644
--- a/extensions/browser/api/messaging/extension_message_port.h
+++ b/extensions/browser/api/messaging/extension_message_port.h
@@ -81,7 +81,8 @@
   bool HasFrame(content::RenderFrameHost* rfh) const override;
   bool IsValidPort() override;
   void RevalidatePort() override;
-  void DispatchOnConnect(const std::string& channel_name,
+  void DispatchOnConnect(ChannelType channel_type,
+                         const std::string& channel_name,
                          absl::optional<base::Value::Dict> source_tab,
                          const ExtensionApiFrameIdMap::FrameData& source_frame,
                          int guest_process_id,
@@ -132,6 +133,7 @@
 
   // Builds specific IPCs for a port, with correct frame or worker identifiers.
   std::unique_ptr<IPC::Message> BuildDispatchOnConnectIPC(
+      ChannelType channel_type,
       const std::string& channel_name,
       const base::Value::Dict* source_tab,
       const ExtensionApiFrameIdMap::FrameData& source_frame,
diff --git a/extensions/browser/api/messaging/message_port.cc b/extensions/browser/api/messaging/message_port.cc
index f8e0943..c99c4ea 100644
--- a/extensions/browser/api/messaging/message_port.cc
+++ b/extensions/browser/api/messaging/message_port.cc
@@ -18,6 +18,7 @@
 void MessagePort::RevalidatePort() {}
 
 void MessagePort::DispatchOnConnect(
+    ChannelType channel_type,
     const std::string& channel_name,
     absl::optional<base::Value::Dict> source_tab,
     const ExtensionApiFrameIdMap::FrameData& source_frame,
diff --git a/extensions/browser/api/messaging/message_port.h b/extensions/browser/api/messaging/message_port.h
index f64cc9f..0590fed8 100644
--- a/extensions/browser/api/messaging/message_port.h
+++ b/extensions/browser/api/messaging/message_port.h
@@ -20,6 +20,7 @@
 }
 
 namespace extensions {
+enum class ChannelType;
 struct Message;
 struct MessagingEndpoint;
 struct PortId;
@@ -65,6 +66,7 @@
 
   // Notifies the port that the channel has been opened.
   virtual void DispatchOnConnect(
+      ChannelType channel_type,
       const std::string& channel_name,
       absl::optional<base::Value::Dict> source_tab,
       const ExtensionApiFrameIdMap::FrameData& source_frame,
diff --git a/extensions/browser/api/messaging/message_service.cc b/extensions/browser/api/messaging/message_service.cc
index ab9a9563..4b6c21c 100644
--- a/extensions/browser/api/messaging/message_service.cc
+++ b/extensions/browser/api/messaging/message_service.cc
@@ -48,6 +48,7 @@
 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
 #include "extensions/browser/pref_names.h"
 #include "extensions/browser/process_manager.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/api/messaging/messaging_endpoint.h"
 #include "extensions/common/api/messaging/port_context.h"
 #include "extensions/common/extension.h"
@@ -206,6 +207,7 @@
   std::string target_extension_id;
   GURL source_url;
   absl::optional<url::Origin> source_origin;
+  ChannelType channel_type;
   std::string channel_name;
   bool include_guest_process_info;
 
@@ -220,6 +222,7 @@
                     const std::string& target_extension_id,
                     const GURL& source_url,
                     absl::optional<url::Origin> source_origin,
+                    ChannelType channel_type,
                     const std::string& channel_name,
                     bool include_guest_process_info)
       : source(source),
@@ -232,6 +235,7 @@
         target_extension_id(target_extension_id),
         source_url(source_url),
         source_origin(source_origin),
+        channel_type(channel_type),
         channel_name(channel_name),
         include_guest_process_info(include_guest_process_info) {}
 
@@ -239,7 +243,8 @@
   OpenChannelParams& operator=(const OpenChannelParams&) = delete;
 
   bool is_onetime_channel() const {
-    return channel_name == "chrome.runtime.sendMessage";
+    return channel_type == ChannelType::kSendMessage ||
+           channel_type == ChannelType::kSendRequest;
   }
 };
 
@@ -278,6 +283,7 @@
     std::unique_ptr<MessagePort> opener_port,
     const std::string& target_extension_id,
     const GURL& source_url,
+    ChannelType channel_type,
     const std::string& channel_name) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(source_port_id.is_opener);
@@ -407,7 +413,8 @@
           source, std::move(source_tab), source_frame, nullptr,
           source_port_id.GetOppositePortId(), source_endpoint,
           std::move(opener_port), target_extension_id, source_url,
-          std::move(source_origin), channel_name, include_guest_process_info);
+          std::move(source_origin), channel_type, channel_name,
+          include_guest_process_info);
   pending_incognito_channels_[params->receiver_port_id.GetChannelId()] =
       PendingMessagesQueue();
   if (context->IsOffTheRecord() &&
@@ -545,6 +552,7 @@
                                       int frame_id,
                                       const std::string& document_id,
                                       const std::string& extension_id,
+                                      ChannelType channel_type,
                                       const std::string& channel_name) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_GE(frame_id, -1);
@@ -606,7 +614,7 @@
           std::move(opener_port), extension_id,
           GURL(),         // Source URL doesn't make sense for opening to tabs.
           url::Origin(),  // Origin URL doesn't make sense for opening to tabs.
-          channel_name,
+          channel_type, channel_name,
           false);  // Connections to tabs aren't webview guests.
   OpenChannelImpl(receiver_context, std::move(params), extension,
                   false /* did_enqueue */);
@@ -687,9 +695,10 @@
   // Send the connect event to the receiver.  Give it the opener's port ID (the
   // opener has the opposite port ID).
   channel->receiver->DispatchOnConnect(
-      params->channel_name, std::move(params->source_tab), params->source_frame,
-      guest_process_id, guest_render_frame_routing_id, params->source_endpoint,
-      params->target_extension_id, params->source_url, params->source_origin);
+      params->channel_type, params->channel_name, std::move(params->source_tab),
+      params->source_frame, guest_process_id, guest_render_frame_routing_id,
+      params->source_endpoint, params->target_extension_id, params->source_url,
+      params->source_origin);
 
   // Report the event to the event router, if the target is an extension.
   //
diff --git a/extensions/browser/api/messaging/message_service.h b/extensions/browser/api/messaging/message_service.h
index 0daf928..06a5ea7 100644
--- a/extensions/browser/api/messaging/message_service.h
+++ b/extensions/browser/api/messaging/message_service.h
@@ -30,6 +30,7 @@
 }
 
 namespace extensions {
+enum class ChannelType;
 class ChannelEndpoint;
 class Extension;
 class ExtensionHost;
@@ -92,6 +93,7 @@
                               std::unique_ptr<MessagePort> opener_port,
                               const std::string& target_extension_id,
                               const GURL& source_url,
+                              ChannelType channel_type,
                               const std::string& channel_name);
 
   // Same as above, but opens a channel to the tab with the given ID.  Messages
@@ -103,6 +105,7 @@
                         int frame_id,
                         const std::string& document_id,
                         const std::string& extension_id,
+                        ChannelType channel_type,
                         const std::string& channel_name);
 
   void OpenChannelToNativeApp(const ChannelEndpoint& source,
diff --git a/extensions/browser/api/messaging/messaging_api_message_filter.cc b/extensions/browser/api/messaging/messaging_api_message_filter.cc
index 847cccb6..74477f48 100644
--- a/extensions/browser/api/messaging/messaging_api_message_filter.cc
+++ b/extensions/browser/api/messaging/messaging_api_message_filter.cc
@@ -18,6 +18,7 @@
 #include "extensions/browser/content_script_tracker.h"
 #include "extensions/browser/event_router_factory.h"
 #include "extensions/browser/extension_util.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/extension_features.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/trace_util.h"
@@ -408,6 +409,7 @@
 void MessagingAPIMessageFilter::OnOpenChannelToExtension(
     const PortContext& source_context,
     const ExtensionMsg_ExternalConnectionInfo& info,
+    ChannelType channel_type,
     const std::string& channel_name,
     const PortId& port_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -432,7 +434,7 @@
   MessageService::Get(browser_context_)
       ->OpenChannelToExtension(source_endpoint, port_id, info.source_endpoint,
                                nullptr /* opener_port */, info.target_id,
-                               info.source_url, channel_name);
+                               info.source_url, channel_type, channel_name);
 }
 
 void MessagingAPIMessageFilter::OnOpenChannelToNativeApp(
@@ -462,6 +464,7 @@
 void MessagingAPIMessageFilter::OnOpenChannelToTab(
     const PortContext& source_context,
     const ExtensionMsg_TabTargetConnectionInfo& info,
+    ChannelType channel_type,
     const std::string& channel_name,
     const PortId& port_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -483,7 +486,8 @@
                                   source_context);
   MessageService::Get(browser_context_)
       ->OpenChannelToTab(source_endpoint, port_id, info.tab_id, info.frame_id,
-                         info.document_id, *extension_id, channel_name);
+                         info.document_id, *extension_id, channel_type,
+                         channel_name);
 }
 
 void MessagingAPIMessageFilter::OnOpenMessagePort(const PortContext& source,
diff --git a/extensions/browser/api/messaging/messaging_api_message_filter.h b/extensions/browser/api/messaging/messaging_api_message_filter.h
index 55ee9f4..7567e14 100644
--- a/extensions/browser/api/messaging/messaging_api_message_filter.h
+++ b/extensions/browser/api/messaging/messaging_api_message_filter.h
@@ -18,6 +18,7 @@
 }
 
 namespace extensions {
+enum class ChannelType;
 struct Message;
 struct PortContext;
 struct PortId;
@@ -56,6 +57,7 @@
 
   void OnOpenChannelToExtension(const PortContext& source_context,
                                 const ExtensionMsg_ExternalConnectionInfo& info,
+                                ChannelType channel_type,
                                 const std::string& channel_name,
                                 const extensions::PortId& port_id);
   void OnOpenChannelToNativeApp(const PortContext& source_context,
@@ -63,6 +65,7 @@
                                 const extensions::PortId& port_id);
   void OnOpenChannelToTab(const PortContext& source_context,
                           const ExtensionMsg_TabTargetConnectionInfo& info,
+                          ChannelType channel_type,
                           const std::string& channel_name,
                           const extensions::PortId& port_id);
   void OnOpenMessagePort(const PortContext& port_context,
diff --git a/extensions/browser/extension_action.h b/extensions/browser/extension_action.h
index 5ffbd70..3cde22e 100644
--- a/extensions/browser/extension_action.h
+++ b/extensions/browser/extension_action.h
@@ -37,6 +37,7 @@
   enum ShowAction {
     ACTION_NONE,
     ACTION_SHOW_POPUP,
+    ACTION_TOGGLE_SIDE_PANEL,
     // We don't need a SHOW_CONTEXT_MENU because that's handled separately in
     // the UI.
   };
diff --git a/extensions/common/api/messaging/channel_type.h b/extensions/common/api/messaging/channel_type.h
index 8c45d04..28d1252 100644
--- a/extensions/common/api/messaging/channel_type.h
+++ b/extensions/common/api/messaging/channel_type.h
@@ -21,6 +21,8 @@
   // long-lived native message channels use the same type (because they don't
   // have associated channel names).
   kNative,
+
+  kLast = kNative,
 };
 
 }  // namespace extensions
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h
index bb9a4a1..3984439 100644
--- a/extensions/common/extension_messages.h
+++ b/extensions/common/extension_messages.h
@@ -20,6 +20,7 @@
 #include "base/values.h"
 #include "content/public/common/common_param_traits.h"
 #include "content/public/common/socket_permission_request.h"
+#include "extensions/common/api/messaging/channel_type.h"
 #include "extensions/common/api/messaging/message.h"
 #include "extensions/common/api/messaging/messaging_endpoint.h"
 #include "extensions/common/api/messaging/port_context.h"
@@ -68,6 +69,9 @@
 IPC_ENUM_TRAITS_MAX_VALUE(extensions::SerializationFormat,
                           extensions::SerializationFormat::kLast)
 
+IPC_ENUM_TRAITS_MAX_VALUE(extensions::ChannelType,
+                          extensions::ChannelType::kLast)
+
 // Parameters structure for ExtensionHostMsg_AddAPIActionToActivityLog and
 // ExtensionHostMsg_AddEventToActivityLog.
 IPC_STRUCT_BEGIN(ExtensionHostMsg_APIActionOrEvent_Params)
@@ -220,6 +224,15 @@
   IPC_STRUCT_MEMBER(extensions::mojom::ExtraResponseDataPtr, extra_data)
 IPC_STRUCT_END()
 
+IPC_STRUCT_BEGIN(ExtensionMsg_OnConnectData)
+  IPC_STRUCT_MEMBER(extensions::PortId, target_port_id)
+  IPC_STRUCT_MEMBER(extensions::ChannelType, channel_type)
+  IPC_STRUCT_MEMBER(std::string, channel_name)
+  IPC_STRUCT_MEMBER(ExtensionMsg_TabConnectionInfo, tab_source)
+  IPC_STRUCT_MEMBER(ExtensionMsg_ExternalConnectionInfo,
+                    external_connection_info)
+IPC_STRUCT_END()
+
 // Singly-included section for custom IPC traits.
 #ifndef INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
 #define INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
@@ -245,14 +258,11 @@
                     extensions::PortId /* port_id */)
 
 // Dispatch the Port.onConnect event for message channels.
-IPC_MESSAGE_ROUTED5(ExtensionMsg_DispatchOnConnect,
+IPC_MESSAGE_ROUTED2(ExtensionMsg_DispatchOnConnect,
                     // For main thread, this is kMainThreadId.
                     // TODO(lazyboy): Can this be absl::optional<int> instead?
                     int /* worker_thread_id */,
-                    extensions::PortId /* target_port_id */,
-                    std::string /* channel_name */,
-                    ExtensionMsg_TabConnectionInfo /* source */,
-                    ExtensionMsg_ExternalConnectionInfo)
+                    ExtensionMsg_OnConnectData /* connect_data */)
 
 // Deliver a message sent with ExtensionHostMsg_PostMessage.
 IPC_MESSAGE_ROUTED3(ExtensionMsg_DeliverMessage,
@@ -276,9 +286,10 @@
 // Open a channel to all listening contexts owned by the extension with
 // the given ID. This responds asynchronously with ExtensionMsg_AssignPortId.
 // If an error occurred, the opener will be notified asynchronously.
-IPC_MESSAGE_CONTROL4(ExtensionHostMsg_OpenChannelToExtension,
+IPC_MESSAGE_CONTROL5(ExtensionHostMsg_OpenChannelToExtension,
                      extensions::PortContext /* source_context */,
                      ExtensionMsg_ExternalConnectionInfo,
+                     extensions::ChannelType /* channel_type */,
                      std::string /* channel_name */,
                      extensions::PortId /* port_id */)
 
@@ -289,9 +300,10 @@
 
 // Get a port handle to the given tab.  The handle can be used for sending
 // messages to the extension.
-IPC_MESSAGE_CONTROL4(ExtensionHostMsg_OpenChannelToTab,
+IPC_MESSAGE_CONTROL5(ExtensionHostMsg_OpenChannelToTab,
                      extensions::PortContext /* source_context */,
                      ExtensionMsg_TabTargetConnectionInfo,
+                     extensions::ChannelType /* channel_type */,
                      std::string /* channel_name */,
                      extensions::PortId /* port_id */)
 
diff --git a/extensions/renderer/api/messaging/native_renderer_messaging_service.cc b/extensions/renderer/api/messaging/native_renderer_messaging_service.cc
index e4b566d66..4747ecf7 100644
--- a/extensions/renderer/api/messaging/native_renderer_messaging_service.cc
+++ b/extensions/renderer/api/messaging/native_renderer_messaging_service.cc
@@ -115,6 +115,7 @@
 void NativeRendererMessagingService::DispatchOnConnect(
     ScriptContextSetIterable* context_set,
     const PortId& target_port_id,
+    ChannelType channel_type,
     const std::string& channel_name,
     const ExtensionMsg_TabConnectionInfo& source,
     const ExtensionMsg_ExternalConnectionInfo& info,
@@ -128,8 +129,8 @@
       info.target_id, restrict_to_render_frame,
       base::BindRepeating(
           &NativeRendererMessagingService::DispatchOnConnectToScriptContext,
-          base::Unretained(this), target_port_id, channel_name, &source, info,
-          &port_created));
+          base::Unretained(this), target_port_id, channel_type, channel_name,
+          &source, info, &port_created));
   // Note: |restrict_to_render_frame| may have been deleted at this point!
 
   IPCMessageSender* ipc_sender = bindings_system_->GetIPCMessageSender();
@@ -289,6 +290,7 @@
 
 void NativeRendererMessagingService::DispatchOnConnectToScriptContext(
     const PortId& target_port_id,
+    ChannelType channel_type,
     const std::string& channel_name,
     const ExtensionMsg_TabConnectionInfo* source,
     const ExtensionMsg_ExternalConnectionInfo& info,
@@ -309,17 +311,22 @@
       relationship == MessagingEndpoint::Relationship::kExternalExtension ||
       relationship == MessagingEndpoint::Relationship::kExternalWebPage;
   std::string event_name;
-  if (info.source_endpoint.type == MessagingEndpoint::Type::kNativeApp) {
-    event_name = messaging_util::kOnConnectNativeEvent;
-  } else if (channel_name == messaging_util::kSendRequestChannel) {
-    event_name = is_external_event ? messaging_util::kOnRequestExternalEvent
-                                   : messaging_util::kOnRequestEvent;
-  } else if (channel_name == messaging_util::kSendMessageChannel) {
-    event_name = is_external_event ? messaging_util::kOnMessageExternalEvent
-                                   : messaging_util::kOnMessageEvent;
-  } else {
-    event_name = is_external_event ? messaging_util::kOnConnectExternalEvent
-                                   : messaging_util::kOnConnectEvent;
+  switch (channel_type) {
+    case ChannelType::kSendRequest:
+      event_name = is_external_event ? messaging_util::kOnRequestExternalEvent
+                                     : messaging_util::kOnRequestEvent;
+      break;
+    case ChannelType::kSendMessage:
+      event_name = is_external_event ? messaging_util::kOnMessageExternalEvent
+                                     : messaging_util::kOnMessageEvent;
+      break;
+    case ChannelType::kConnect:
+      event_name = is_external_event ? messaging_util::kOnConnectExternalEvent
+                                     : messaging_util::kOnConnectEvent;
+      break;
+    case ChannelType::kNative:
+      event_name = messaging_util::kOnConnectNativeEvent;
+      break;
   }
 
   // If there are no listeners for the given event, then we know the port won't
@@ -331,8 +338,8 @@
   *port_created = true;
 
   DispatchOnConnectToListeners(script_context, target_port_id,
-                               target_extension_id, channel_name, source, info,
-                               event_name);
+                               target_extension_id, channel_type, channel_name,
+                               source, info, event_name);
 }
 
 void NativeRendererMessagingService::DeliverMessageToScriptContext(
@@ -431,6 +438,7 @@
     ScriptContext* script_context,
     const PortId& target_port_id,
     const ExtensionId& target_extension_id,
+    ChannelType channel_type,
     const std::string& channel_name,
     const ExtensionMsg_TabConnectionInfo* source,
     const ExtensionMsg_ExternalConnectionInfo& info,
@@ -482,11 +490,13 @@
 
   v8::Local<v8::Object> sender = sender_builder.Build();
 
-  if (channel_name == "chrome.extension.sendRequest" ||
-      channel_name == "chrome.runtime.sendMessage") {
+  if (channel_type == ChannelType::kSendRequest ||
+      channel_type == ChannelType::kSendMessage) {
     one_time_message_handler_.AddReceiver(script_context, target_port_id,
                                           sender, event_name);
   } else {
+    CHECK(channel_type == ChannelType::kConnect ||
+          channel_type == ChannelType::kNative);
     gin::Handle<GinPort> port =
         CreatePort(script_context, channel_name, target_port_id);
     port->SetSender(v8_context, sender);
diff --git a/extensions/renderer/api/messaging/native_renderer_messaging_service.h b/extensions/renderer/api/messaging/native_renderer_messaging_service.h
index e0c3f33a..7fcef21 100644
--- a/extensions/renderer/api/messaging/native_renderer_messaging_service.h
+++ b/extensions/renderer/api/messaging/native_renderer_messaging_service.h
@@ -89,6 +89,7 @@
   // in that render frame will receive the message.
   void DispatchOnConnect(ScriptContextSetIterable* context_set,
                          const PortId& target_port_id,
+                         ChannelType channel_type,
                          const std::string& channel_name,
                          const ExtensionMsg_TabConnectionInfo& source,
                          const ExtensionMsg_ExternalConnectionInfo& info,
@@ -149,6 +150,7 @@
                                     ScriptContext* script_context);
   void DispatchOnConnectToScriptContext(
       const PortId& target_port_id,
+      ChannelType channel_type,
       const std::string& channel_name,
       const ExtensionMsg_TabConnectionInfo* source,
       const ExtensionMsg_ExternalConnectionInfo& info,
@@ -177,6 +179,7 @@
       ScriptContext* script_context,
       const PortId& target_port_id,
       const ExtensionId& target_extension_id,
+      ChannelType channel_type,
       const std::string& channel_name,
       const ExtensionMsg_TabConnectionInfo* source,
       const ExtensionMsg_ExternalConnectionInfo& info,
diff --git a/extensions/renderer/api/messaging/native_renderer_messaging_service_unittest.cc b/extensions/renderer/api/messaging/native_renderer_messaging_service_unittest.cc
index e6afb9ac..fce919a7 100644
--- a/extensions/renderer/api/messaging/native_renderer_messaging_service_unittest.cc
+++ b/extensions/renderer/api/messaging/native_renderer_messaging_service_unittest.cc
@@ -174,9 +174,9 @@
 
   EXPECT_CALL(*ipc_message_sender(),
               SendOpenMessagePort(MSG_ROUTING_NONE, port_id));
-  messaging_service()->DispatchOnConnect(script_context_set(), port_id,
-                                         channel_name, tab_connection_info,
-                                         external_connection_info, nullptr);
+  messaging_service()->DispatchOnConnect(
+      script_context_set(), port_id, ChannelType::kConnect, channel_name,
+      tab_connection_info, external_connection_info, nullptr);
   ::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
 
   ASSERT_TRUE(
@@ -509,9 +509,9 @@
   // Open a receiver for the message.
   EXPECT_CALL(*ipc_message_sender(),
               SendOpenMessagePort(MSG_ROUTING_NONE, port_id));
-  messaging_service()->DispatchOnConnect(script_context_set(), port_id,
-                                         kChannel, tab_connection_info,
-                                         external_connection_info, nullptr);
+  messaging_service()->DispatchOnConnect(
+      script_context_set(), port_id, ChannelType::kSendMessage, kChannel,
+      tab_connection_info, external_connection_info, nullptr);
   ::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
   EXPECT_TRUE(
       messaging_service()->HasPortForTesting(script_context(), port_id));
@@ -583,8 +583,9 @@
     EXPECT_CALL(*ipc_message_sender(),
                 SendOpenMessagePort(MSG_ROUTING_NONE, port_id));
     messaging_service()->DispatchOnConnect(
-        script_context_set(), port_id, messaging_util::kSendMessageChannel,
-        tab_connection_info, external_connection_info, nullptr);
+        script_context_set(), port_id, ChannelType::kSendMessage,
+        messaging_util::kSendMessageChannel, tab_connection_info,
+        external_connection_info, nullptr);
     ::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
     EXPECT_TRUE(
         messaging_service()->HasPortForTesting(script_context(), port_id));
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 70f96c75..65506920 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -1305,15 +1305,14 @@
 
 void Dispatcher::OnDispatchOnConnect(
     int worker_thread_id,
-    const PortId& target_port_id,
-    const std::string& channel_name,
-    const ExtensionMsg_TabConnectionInfo& source,
-    const ExtensionMsg_ExternalConnectionInfo& info) {
+    const ExtensionMsg_OnConnectData& connect_data) {
   DCHECK_EQ(kMainThreadId, worker_thread_id);
-  DCHECK(!target_port_id.is_opener);
+  DCHECK(!connect_data.target_port_id.is_opener);
 
   bindings_system_->messaging_service()->DispatchOnConnect(
-      script_context_set_.get(), target_port_id, channel_name, source, info,
+      script_context_set_.get(), connect_data.target_port_id,
+      connect_data.channel_type, connect_data.channel_name,
+      connect_data.tab_source, connect_data.external_connection_info,
       nullptr);  // All render frames.
 }
 
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h
index b3533c4e..757a2e1 100644
--- a/extensions/renderer/dispatcher.h
+++ b/extensions/renderer/dispatcher.h
@@ -40,8 +40,7 @@
 class ChromeRenderViewTest;
 class GURL;
 class ModuleSystem;
-struct ExtensionMsg_ExternalConnectionInfo;
-struct ExtensionMsg_TabConnectionInfo;
+struct ExtensionMsg_OnConnectData;
 
 namespace blink {
 class WebLocalFrame;
@@ -280,10 +279,7 @@
                         const PortId& target_port_id,
                         const Message& message);
   void OnDispatchOnConnect(int worker_thread_id,
-                           const PortId& target_port_id,
-                           const std::string& channel_name,
-                           const ExtensionMsg_TabConnectionInfo& source,
-                           const ExtensionMsg_ExternalConnectionInfo& info);
+                           const ExtensionMsg_OnConnectData& connect_data);
   void OnDispatchOnDisconnect(int worker_thread_id,
                               const PortId& port_id,
                               const std::string& error_message);
diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc
index 9c079090..a7d1a45 100644
--- a/extensions/renderer/extension_frame_helper.cc
+++ b/extensions/renderer/extension_frame_helper.cc
@@ -441,16 +441,15 @@
 
 void ExtensionFrameHelper::OnExtensionDispatchOnConnect(
     int worker_thread_id,
-    const PortId& target_port_id,
-    const std::string& channel_name,
-    const ExtensionMsg_TabConnectionInfo& source,
-    const ExtensionMsg_ExternalConnectionInfo& info) {
+    const ExtensionMsg_OnConnectData& connect_data) {
   DCHECK_EQ(kMainThreadId, worker_thread_id);
   extension_dispatcher_->bindings_system()
       ->messaging_service()
-      ->DispatchOnConnect(extension_dispatcher_->script_context_set_iterator(),
-                          target_port_id, channel_name, source, info,
-                          render_frame());
+      ->DispatchOnConnect(
+          extension_dispatcher_->script_context_set_iterator(),
+          connect_data.target_port_id, connect_data.channel_type,
+          connect_data.channel_name, connect_data.tab_source,
+          connect_data.external_connection_info, render_frame());
 }
 
 void ExtensionFrameHelper::OnExtensionDeliverMessage(int worker_thread_id,
diff --git a/extensions/renderer/extension_frame_helper.h b/extensions/renderer/extension_frame_helper.h
index ccf83a1..76f37c9 100644
--- a/extensions/renderer/extension_frame_helper.h
+++ b/extensions/renderer/extension_frame_helper.h
@@ -21,8 +21,7 @@
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
 #include "v8/include/v8-forward.h"
 
-struct ExtensionMsg_ExternalConnectionInfo;
-struct ExtensionMsg_TabConnectionInfo;
+struct ExtensionMsg_OnConnectData;
 
 namespace extensions {
 
@@ -173,10 +172,7 @@
   void OnExtensionValidateMessagePort(int worker_thread_id, const PortId& id);
   void OnExtensionDispatchOnConnect(
       int worker_thread_id,
-      const PortId& target_port_id,
-      const std::string& channel_name,
-      const ExtensionMsg_TabConnectionInfo& source,
-      const ExtensionMsg_ExternalConnectionInfo& info);
+      const ExtensionMsg_OnConnectData& connect_data);
   void OnExtensionDeliverMessage(int worker_thread_id,
                                  const PortId& target_port_id,
                                  const Message& message);
diff --git a/extensions/renderer/ipc_message_sender.cc b/extensions/renderer/ipc_message_sender.cc
index 673227f6..3f9317a 100644
--- a/extensions/renderer/ipc_message_sender.cc
+++ b/extensions/renderer/ipc_message_sender.cc
@@ -139,13 +139,17 @@
                               const MessageTarget& target,
                               ChannelType channel_type,
                               const std::string& channel_name) override {
-    // TODO(https://crbug.com/1430999): Use `channel_type` in the IPC message.
     content::RenderFrame* render_frame = script_context->GetRenderFrame();
     DCHECK(render_frame);
     PortContext frame_context =
         PortContext::ForFrame(render_frame->GetRoutingID());
     const Extension* extension = script_context->extension();
 
+    // TODO(https://crbug.com/1430999): We should just avoid passing a
+    // channel name in at all for non-connect messages; we no longer need to.
+    std::string channel_name_to_use =
+        channel_type == ChannelType::kConnect ? channel_name : std::string();
+
     switch (target.type) {
       case MessageTarget::EXTENSION: {
         ExtensionMsg_ExternalConnectionInfo info;
@@ -164,7 +168,7 @@
             "MainThreadIPCMessageSender::SendOpenMessageChannel/extension",
             *target.extension_id);
         render_thread_->Send(new ExtensionHostMsg_OpenChannelToExtension(
-            frame_context, info, channel_name, port_id));
+            frame_context, info, channel_type, channel_name_to_use, port_id));
         break;
       }
       case MessageTarget::TAB: {
@@ -177,10 +181,11 @@
         if (target.document_id)
           info.document_id = *target.document_id;
         render_frame->Send(new ExtensionHostMsg_OpenChannelToTab(
-            frame_context, info, channel_name, port_id));
+            frame_context, info, channel_type, channel_name_to_use, port_id));
         break;
       }
       case MessageTarget::NATIVE_APP:
+        CHECK_EQ(ChannelType::kNative, channel_type);
         render_frame->Send(new ExtensionHostMsg_OpenChannelToNativeApp(
             frame_context, *target.native_application_name, port_id));
         break;
@@ -388,11 +393,15 @@
                               const MessageTarget& target,
                               ChannelType channel_type,
                               const std::string& channel_name) override {
-    // TODO(https://crbug.com/1430999): Use `channel_type` in the IPC message.
     DCHECK(!script_context->GetRenderFrame());
     DCHECK(script_context->IsForServiceWorker());
     const Extension* extension = script_context->extension();
 
+    // TODO(https://crbug.com/1430999): We should just avoid passing a
+    // channel name in at all for non-connect messages; we no longer need to.
+    std::string channel_name_to_use =
+        channel_type == ChannelType::kConnect ? channel_name : std::string();
+
     switch (target.type) {
       case MessageTarget::EXTENSION: {
         ExtensionMsg_ExternalConnectionInfo info;
@@ -406,7 +415,8 @@
             "WorkerThreadIPCMessageSender::SendOpenMessageChannel/extension",
             *target.extension_id);
         dispatcher_->Send(new ExtensionHostMsg_OpenChannelToExtension(
-            PortContextForCurrentWorker(), info, channel_name, port_id));
+            PortContextForCurrentWorker(), info, channel_type,
+            channel_name_to_use, port_id));
         break;
       }
       case MessageTarget::TAB: {
@@ -415,10 +425,12 @@
         info.tab_id = *target.tab_id;
         info.frame_id = *target.frame_id;
         dispatcher_->Send(new ExtensionHostMsg_OpenChannelToTab(
-            PortContextForCurrentWorker(), info, channel_name, port_id));
+            PortContextForCurrentWorker(), info, channel_type,
+            channel_name_to_use, port_id));
         break;
       }
       case MessageTarget::NATIVE_APP:
+        CHECK_EQ(ChannelType::kNative, channel_type);
         dispatcher_->Send(new ExtensionHostMsg_OpenChannelToNativeApp(
             PortContextForCurrentWorker(), *target.native_application_name,
             port_id));
diff --git a/extensions/renderer/worker_thread_dispatcher.cc b/extensions/renderer/worker_thread_dispatcher.cc
index 29b16d1..6b381fd 100644
--- a/extensions/renderer/worker_thread_dispatcher.cc
+++ b/extensions/renderer/worker_thread_dispatcher.cc
@@ -434,17 +434,16 @@
 }
 void WorkerThreadDispatcher::OnDispatchOnConnect(
     int worker_thread_id,
-    const PortId& target_port_id,
-    const std::string& channel_name,
-    const ExtensionMsg_TabConnectionInfo& source,
-    const ExtensionMsg_ExternalConnectionInfo& info) {
+    const ExtensionMsg_OnConnectData& connect_data) {
   DCHECK_EQ(worker_thread_id, content::WorkerThread::GetCurrentId());
   WorkerThreadDispatcher::GetBindingsSystem()
       ->messaging_service()
-      ->DispatchOnConnect(Dispatcher::GetWorkerScriptContextSet(),
-                          target_port_id, channel_name, source, info,
-                          // Render frames do not matter.
-                          nullptr);
+      ->DispatchOnConnect(
+          Dispatcher::GetWorkerScriptContextSet(), connect_data.target_port_id,
+          connect_data.channel_type, connect_data.channel_name,
+          connect_data.tab_source, connect_data.external_connection_info,
+          // Render frames do not matter.
+          nullptr);
 }
 
 void WorkerThreadDispatcher::OnValidateMessagePort(int worker_thread_id,
diff --git a/extensions/renderer/worker_thread_dispatcher.h b/extensions/renderer/worker_thread_dispatcher.h
index 9f33e731..b1f8b60 100644
--- a/extensions/renderer/worker_thread_dispatcher.h
+++ b/extensions/renderer/worker_thread_dispatcher.h
@@ -32,8 +32,7 @@
 }
 
 class GURL;
-struct ExtensionMsg_TabConnectionInfo;
-struct ExtensionMsg_ExternalConnectionInfo;
+struct ExtensionMsg_OnConnectData;
 
 namespace extensions {
 class NativeExtensionBindingsSystem;
@@ -189,10 +188,7 @@
                         const std::string& error);
   void OnValidateMessagePort(int worker_thread_id, const PortId& id);
   void OnDispatchOnConnect(int worker_thread_id,
-                           const PortId& target_port_id,
-                           const std::string& channel_name,
-                           const ExtensionMsg_TabConnectionInfo& source,
-                           const ExtensionMsg_ExternalConnectionInfo& info);
+                           const ExtensionMsg_OnConnectData& connect_data);
   void OnDeliverMessage(int worker_thread_id,
                         const PortId& target_port_id,
                         const Message& message);
diff --git a/gpu/command_buffer/client/BUILD.gn b/gpu/command_buffer/client/BUILD.gn
index e12714a4..22bf9d6 100644
--- a/gpu/command_buffer/client/BUILD.gn
+++ b/gpu/command_buffer/client/BUILD.gn
@@ -264,7 +264,6 @@
     ":client",
     ":gles2_implementation",
     ":gles2_interface",
-    ":raster_interface",
     "//base",
     "//cc/paint",
     "//components/viz/common:resource_format_utils",
@@ -277,6 +276,8 @@
     "//ui/gfx/geometry",
     "//ui/gfx/ipc/color",
   ]
+  public_deps = [ ":raster_interface" ]
+
   sources = [
     "client_font_manager.cc",
     "client_font_manager.h",
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index 4a9e108..de76e1e 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -260,11 +260,11 @@
     DCHECK(!written_bytes_);
   }
 
-  size_t Serialize(const cc::PaintOp& op,
-                   const cc::PaintOp::SerializeOptions& options,
-                   const cc::PaintFlags* flags_to_serialize,
-                   const SkM44& current_ctm,
-                   const SkM44& original_ctm) {
+  size_t SerializeImpl(const cc::PaintOp& op,
+                       const cc::PaintOp::SerializeOptions& options,
+                       const cc::PaintFlags* flags_to_serialize,
+                       const SkM44& current_ctm,
+                       const SkM44& original_ctm) {
     if (!valid())
       return 0;
 
@@ -317,6 +317,16 @@
     return size;
   }
 
+  static size_t Serialize(void* instance,
+                          const cc::PaintOp& op,
+                          const cc::PaintOp::SerializeOptions& options,
+                          const cc::PaintFlags* flags_to_serialize,
+                          const SkM44& current_ctm,
+                          const SkM44& original_ctm) {
+    return reinterpret_cast<PaintOpSerializer*>(instance)->SerializeImpl(
+        op, options, flags_to_serialize, current_ctm, original_ctm);
+  }
+
   void SendSerializedData() {
     if (!valid())
       return;
@@ -1383,8 +1393,7 @@
                                   &font_manager_, max_op_size_hint);
 
   cc::PaintOpBufferSerializer serializer(
-      base::BindRepeating(&PaintOpSerializer::Serialize,
-                          base::Unretained(&op_serializer)),
+      PaintOpSerializer::Serialize, &op_serializer,
       cc::PaintOp::SerializeOptions(
           &stashing_image_provider, &transfer_cache_serialize_helper,
           GetOrCreatePaintCache(), font_manager_.strike_server(),
diff --git a/gpu/command_buffer/service/shared_image/shared_image_representation.cc b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
index 5a95f7a..86fb0df 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
@@ -170,8 +170,21 @@
     : ScopedAccessBase(representation),
       promise_image_textures_(std::move(promise_image_textures)) {
   DCHECK(!promise_image_textures_.empty());
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+  CHECK(graphite_textures_.empty());
+#endif
 }
 
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+SkiaImageRepresentation::ScopedWriteAccess::ScopedWriteAccess(
+    SkiaImageRepresentation* representation,
+    std::vector<skgpu::graphite::BackendTexture> graphite_textures)
+    : ScopedAccessBase(representation), graphite_textures_(graphite_textures) {
+  CHECK(!graphite_textures_.empty());
+  CHECK(promise_image_textures_.empty());
+}
+#endif
+
 SkiaImageRepresentation::ScopedWriteAccess::~ScopedWriteAccess() {
   // Ensure no one uses `surfaces_` by dropping the reference before calling
   // EndWriteAccess.
@@ -185,8 +198,21 @@
     : ScopedAccessBase(representation),
       promise_image_textures_(std::move(promise_image_textures)) {
   DCHECK(!promise_image_textures_.empty());
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+  CHECK(graphite_textures_.empty());
+#endif
 }
 
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+SkiaImageRepresentation::ScopedReadAccess::ScopedReadAccess(
+    SkiaImageRepresentation* representation,
+    std::vector<skgpu::graphite::BackendTexture> graphite_textures)
+    : ScopedAccessBase(representation), graphite_textures_(graphite_textures) {
+  CHECK(!graphite_textures_.empty());
+  CHECK(promise_image_textures_.empty());
+}
+#endif
+
 SkiaImageRepresentation::ScopedReadAccess::~ScopedReadAccess() {
   representation()->EndReadAccess();
 }
@@ -450,8 +476,10 @@
   std::unique_ptr<GrBackendSurfaceMutableState> end_state;
   std::vector<sk_sp<SkPromiseImageTexture>> promise_image_textures =
       BeginReadAccess(begin_semaphores, end_semaphores, &end_state);
-  if (promise_image_textures.empty())
+  if (promise_image_textures.empty()) {
+    LOG(ERROR) << "Unable to initialize SkPromiseImageTexture";
     return nullptr;
+  }
 
   backing()->OnReadSucceeded();
 
@@ -461,6 +489,160 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// SkiaGraphiteImageRepresentation
+
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+SkiaGraphiteImageRepresentation::SkiaGraphiteImageRepresentation(
+    SharedImageManager* manager,
+    SharedImageBacking* backing,
+    MemoryTypeTracker* tracker)
+    : SkiaImageRepresentation(manager, backing, tracker) {}
+
+SkiaGraphiteImageRepresentation::ScopedGraphiteWriteAccess::
+    ScopedGraphiteWriteAccess(
+        base::PassKey<SkiaGraphiteImageRepresentation> /* pass_key */,
+        SkiaImageRepresentation* representation,
+        std::vector<sk_sp<SkSurface>> surfaces)
+    : ScopedWriteAccess(representation, std::move(surfaces)) {
+  CHECK(!surfaces_.empty());
+}
+
+SkiaGraphiteImageRepresentation::ScopedGraphiteWriteAccess::
+    ScopedGraphiteWriteAccess(
+        base::PassKey<SkiaGraphiteImageRepresentation> /* pass_key */,
+        SkiaImageRepresentation* representation,
+        std::vector<skgpu::graphite::BackendTexture> backend_textures)
+    : ScopedWriteAccess(representation, backend_textures) {
+  CHECK(!graphite_textures_.empty());
+}
+
+SkiaGraphiteImageRepresentation::ScopedGraphiteWriteAccess::
+    ~ScopedGraphiteWriteAccess() = default;
+
+// Graphite-Dawn backend handles Vulkan transitions by itself, so nothing to do
+// here.
+void SkiaGraphiteImageRepresentation::ScopedGraphiteWriteAccess::
+    ApplyBackendSurfaceEndState() {}
+
+std::unique_ptr<SkiaImageRepresentation::ScopedWriteAccess>
+SkiaGraphiteImageRepresentation::BeginScopedWriteAccess(
+    int final_msaa_count,
+    const SkSurfaceProps& surface_props,
+    const gfx::Rect& update_rect,
+    std::vector<GrBackendSemaphore>* begin_semaphores,
+    std::vector<GrBackendSemaphore>* end_semaphores,
+    AllowUnclearedAccess allow_uncleared,
+    bool use_sk_surface) {
+  if (allow_uncleared != AllowUnclearedAccess::kYes && !IsCleared()) {
+    LOG(ERROR) << "Attempt to write to an uninitialized SharedImage";
+    return nullptr;
+  }
+
+  if (use_sk_surface) {
+    std::vector<sk_sp<SkSurface>> surfaces =
+        BeginWriteAccess(surface_props, update_rect);
+    if (surfaces.empty()) {
+      LOG(ERROR) << "Unable to initialize SkSurface";
+      return nullptr;
+    }
+
+    backing()->OnWriteSucceeded();
+
+    return std::make_unique<ScopedGraphiteWriteAccess>(
+        base::PassKey<SkiaGraphiteImageRepresentation>(), this,
+        std::move(surfaces));
+  }
+  std::vector<skgpu::graphite::BackendTexture> graphite_textures =
+      BeginWriteAccess();
+  if (graphite_textures.empty()) {
+    LOG(ERROR) << "Unable to initialize graphite::BackendTextures";
+    return nullptr;
+  }
+
+  backing()->OnWriteSucceeded();
+
+  return std::make_unique<ScopedGraphiteWriteAccess>(
+      base::PassKey<SkiaGraphiteImageRepresentation>(), this,
+      graphite_textures);
+}
+
+std::unique_ptr<SkiaImageRepresentation::ScopedWriteAccess>
+SkiaGraphiteImageRepresentation::BeginScopedWriteAccess(
+    int final_msaa_count,
+    const SkSurfaceProps& surface_props,
+    std::vector<GrBackendSemaphore>* begin_semaphores,
+    std::vector<GrBackendSemaphore>* end_semaphores,
+    AllowUnclearedAccess allow_uncleared,
+    bool use_sk_surface) {
+  return BeginScopedWriteAccess(
+      final_msaa_count, surface_props, gfx::Rect(size()), begin_semaphores,
+      end_semaphores, allow_uncleared, use_sk_surface);
+}
+
+std::unique_ptr<SkiaImageRepresentation::ScopedWriteAccess>
+SkiaGraphiteImageRepresentation::BeginScopedWriteAccess(
+    std::vector<GrBackendSemaphore>* begin_semaphores,
+    std::vector<GrBackendSemaphore>* end_semaphores,
+    AllowUnclearedAccess allow_uncleared,
+    bool use_sk_surface) {
+  return BeginScopedWriteAccess(
+      /*final_msaa_count=*/1,
+      SkSurfaceProps(/*flags=*/0, kUnknown_SkPixelGeometry), begin_semaphores,
+      end_semaphores, allow_uncleared, use_sk_surface);
+}
+
+SkiaGraphiteImageRepresentation::ScopedGraphiteReadAccess::
+    ScopedGraphiteReadAccess(
+        base::PassKey<SkiaGraphiteImageRepresentation> /* pass_key */,
+        SkiaImageRepresentation* representation,
+        std::vector<skgpu::graphite::BackendTexture> graphite_textures)
+    : ScopedReadAccess(representation, graphite_textures) {
+  CHECK(!graphite_textures_.empty());
+}
+
+SkiaGraphiteImageRepresentation::ScopedGraphiteReadAccess::
+    ~ScopedGraphiteReadAccess() = default;
+
+bool SkiaGraphiteImageRepresentation::ScopedGraphiteReadAccess::
+    HasBackendSurfaceEndState() {
+  return false;
+}
+
+// Graphite-Dawn backend handles Vulkan transitions by itself, so nothing to do
+// here.
+void SkiaGraphiteImageRepresentation::ScopedGraphiteReadAccess::
+    ApplyBackendSurfaceEndState() {}
+
+std::unique_ptr<SkiaImageRepresentation::ScopedReadAccess>
+SkiaGraphiteImageRepresentation::BeginScopedReadAccess(
+    std::vector<GrBackendSemaphore>* begin_semaphores,
+    std::vector<GrBackendSemaphore>* end_semaphores) {
+  if (!IsCleared()) {
+    auto cr = ClearedRect();
+    LOG(ERROR) << base::StringPrintf(
+        "Attempt to read from an uninitialized SharedImage. "
+        "Initialized region: (%d, %d, %d, %d) Size: (%d, %d)",
+        cr.x(), cr.y(), cr.width(), cr.height(), size().width(),
+        size().height());
+    return nullptr;
+  }
+
+  std::vector<skgpu::graphite::BackendTexture> graphite_textures =
+      BeginReadAccess();
+  if (graphite_textures.empty()) {
+    LOG(ERROR) << "Unable to initialize graphite::BackendTextures";
+    return nullptr;
+  }
+
+  backing()->OnReadSucceeded();
+
+  return std::make_unique<ScopedGraphiteReadAccess>(
+      base::PassKey<SkiaGraphiteImageRepresentation>(), this,
+      graphite_textures);
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
 // OverlayImageRepresentation
 
 #if BUILDFLAG(IS_ANDROID)
@@ -544,8 +726,10 @@
   }
 
   WGPUTexture texture = BeginAccess(usage);
-  if (!texture)
+  if (!texture) {
+    LOG(ERROR) << "Error creating WGPUTexture";
     return nullptr;
+  }
 
   if (usage & kWriteUsage) {
     backing()->OnWriteSucceeded();
diff --git a/gpu/command_buffer/service/shared_image/shared_image_representation.h b/gpu/command_buffer/service/shared_image/shared_image_representation.h
index 47baf714..13f6278 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_representation.h
+++ b/gpu/command_buffer/service/shared_image/shared_image_representation.h
@@ -17,6 +17,7 @@
 #include "gpu/command_buffer/service/shared_image/shared_image_backing.h"
 #include "gpu/command_buffer/service/shared_image/shared_image_manager.h"
 #include "gpu/gpu_gles2_export.h"
+#include "skia/buildflags.h"
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/gpu/GrDirectContext.h"
@@ -44,6 +45,10 @@
 #include <wrl/client.h>
 #endif
 
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+#include "third_party/skia/include/gpu/graphite/BackendTexture.h"
+#endif
+
 typedef unsigned int GLenum;
 class GrBackendSurfaceMutableState;
 class SkPromiseImageTexture;
@@ -319,6 +324,16 @@
       return promise_image_textures_[plane_index].get();
     }
 
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+    skgpu::graphite::BackendTexture graphite_texture() const {
+      DCHECK(representation()->format().is_single_plane());
+      return graphite_texture(0);
+    }
+    skgpu::graphite::BackendTexture graphite_texture(int plane_index) const {
+      return graphite_textures_[plane_index];
+    }
+#endif
+
     // NOTE: Implemented only for Ganesh.
     // Applies the GrBackendSurfaceMutableState for Vulkan layout and external
     // queue transitions needed for Vulkan/GL interop.
@@ -330,11 +345,21 @@
     ScopedWriteAccess(
         SkiaImageRepresentation* representation,
         std::vector<sk_sp<SkPromiseImageTexture>> promise_image_textures);
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+    ScopedWriteAccess(
+        SkiaImageRepresentation* representation,
+        std::vector<skgpu::graphite::BackendTexture> graphite_textures);
+#endif
 
-    // A vector of surfaces and promise textures corresponding to the number of
-    // planes in SharedImageFormat.
+    // A vector of surfaces, promise textures and graphite backend textures
+    // corresponding to the number of planes in SharedImageFormat.
     std::vector<sk_sp<SkSurface>> surfaces_;
+    // NOTE: Used only for Ganesh.
     std::vector<sk_sp<SkPromiseImageTexture>> promise_image_textures_;
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+    // NOTE: Used only for Graphite.
+    std::vector<skgpu::graphite::BackendTexture> graphite_textures_;
+#endif
   };
 
   class GPU_GLES2_EXPORT ScopedReadAccess
@@ -349,6 +374,17 @@
     SkPromiseImageTexture* promise_image_texture(int plane_index) const {
       return promise_image_textures_[plane_index].get();
     }
+
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+    skgpu::graphite::BackendTexture graphite_texture() const {
+      DCHECK(representation()->format().is_single_plane());
+      return graphite_texture(0);
+    }
+    skgpu::graphite::BackendTexture graphite_texture(int plane_index) const {
+      return graphite_textures_[plane_index];
+    }
+#endif
+
     // Creates an SkImage from GrBackendTexture for single planar formats or if
     // format prefers external sampler. Creates an SkImage from
     // GrYUVABackendTexture for multiplanar formats.
@@ -372,10 +408,19 @@
     ScopedReadAccess(
         SkiaImageRepresentation* representation,
         std::vector<sk_sp<SkPromiseImageTexture>> promise_image_textures);
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+    ScopedReadAccess(
+        SkiaImageRepresentation* representation,
+        std::vector<skgpu::graphite::BackendTexture> graphite_textures);
+#endif
 
-    // A vector of promise textures corresponding to the number of planes in
-    // SharedImageFormat.
+    // A vector of promise textures and graphite backend textures corresponding
+    // to the number of planes in SharedImageFormat. NOTE: Used only for Ganesh.
     std::vector<sk_sp<SkPromiseImageTexture>> promise_image_textures_;
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+    // NOTE: Used only for Graphite.
+    std::vector<skgpu::graphite::BackendTexture> graphite_textures_;
+#endif
   };
 
   SkiaImageRepresentation(SharedImageManager* manager,
@@ -565,6 +610,95 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
+// SkiaGraphiteImageRepresentation
+
+#if BUILDFLAG(ENABLE_SKIA_GRAPHITE)
+class GPU_GLES2_EXPORT SkiaGraphiteImageRepresentation
+    : public SkiaImageRepresentation {
+ public:
+  class GPU_GLES2_EXPORT ScopedGraphiteWriteAccess : public ScopedWriteAccess {
+   public:
+    ScopedGraphiteWriteAccess(
+        base::PassKey<SkiaGraphiteImageRepresentation> pass_key,
+        SkiaImageRepresentation* representation,
+        std::vector<sk_sp<SkSurface>> surfaces);
+    ScopedGraphiteWriteAccess(
+        base::PassKey<SkiaGraphiteImageRepresentation> pass_key,
+        SkiaImageRepresentation* representation,
+        std::vector<skgpu::graphite::BackendTexture> graphite_textures);
+    ~ScopedGraphiteWriteAccess() override;
+
+    // Graphite-Dawn backend handles Vulkan transitions by itself, so nothing to
+    // do here.
+    void ApplyBackendSurfaceEndState() override;
+  };
+
+  class GPU_GLES2_EXPORT ScopedGraphiteReadAccess : public ScopedReadAccess {
+   public:
+    ScopedGraphiteReadAccess(
+        base::PassKey<SkiaGraphiteImageRepresentation> pass_key,
+        SkiaImageRepresentation* representation,
+        std::vector<skgpu::graphite::BackendTexture> graphite_textures);
+    ~ScopedGraphiteReadAccess() override;
+
+    // Graphite-Dawn backend handles Vulkan transitions by itself, so nothing to
+    // do here.
+    bool HasBackendSurfaceEndState() override;
+    void ApplyBackendSurfaceEndState() override;
+  };
+
+  SkiaGraphiteImageRepresentation(SharedImageManager* manager,
+                                  SharedImageBacking* backing,
+                                  MemoryTypeTracker* tracker);
+
+  // Note: See BeginWriteAccess below for a description of the semaphore
+  // parameters.
+  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
+      int final_msaa_count,
+      const SkSurfaceProps& surface_props,
+      const gfx::Rect& update_rect,
+      std::vector<GrBackendSemaphore>* begin_semaphores,
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      AllowUnclearedAccess allow_uncleared,
+      bool use_sk_surface = true) override;
+
+  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
+      int final_msaa_count,
+      const SkSurfaceProps& surface_props,
+      std::vector<GrBackendSemaphore>* begin_semaphores,
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      AllowUnclearedAccess allow_uncleared,
+      bool use_sk_surface = true) override;
+
+  std::unique_ptr<ScopedWriteAccess> BeginScopedWriteAccess(
+      std::vector<GrBackendSemaphore>* begin_semaphores,
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      AllowUnclearedAccess allow_uncleared,
+      bool use_sk_surface = true) override;
+
+  // Note: See BeginReadAccess below for a description of the semaphore
+  // parameters.
+  std::unique_ptr<ScopedReadAccess> BeginScopedReadAccess(
+      std::vector<GrBackendSemaphore>* begin_semaphores,
+      std::vector<GrBackendSemaphore>* end_semaphores) override;
+
+ protected:
+  // Begin the write access. Returns an empty vector on failure.
+  //
+  // update_rect is a hint to the backend about the portion of the image that
+  // will be drawn to. Callers shouldn't draw outside of this area, but aren't
+  // required to overwrite every pixel inside it.
+  virtual std::vector<sk_sp<SkSurface>> BeginWriteAccess(
+      const SkSurfaceProps& surface_props,
+      const gfx::Rect& update_rect) = 0;
+  virtual std::vector<skgpu::graphite::BackendTexture> BeginWriteAccess() = 0;
+
+  // Returns an empty vector on failure.
+  virtual std::vector<skgpu::graphite::BackendTexture> BeginReadAccess() = 0;
+};
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
 // DawnImageRepresentation
 
 class GPU_GLES2_EXPORT DawnImageRepresentation
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index 65513068..65276b3 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -4200,6 +4200,22 @@
       "features": [
         "disable_accelerated_vp9_encode"
       ]
+    },
+    {
+      "id": 412,
+      "cr_bugs": [1217298, 1107331],
+      "description": "Disable VP9 HW encode on Intel GPUs preceding Ice Lake",
+      "os": {
+        "type": "win"
+      },
+      "vendor_id": "0x8086",
+      "intel_gpu_generation": {
+        "op": "<",
+        "value": "11"
+      },
+      "features": [
+        "disable_accelerated_vp9_encode"
+      ]
     }
   ]
 }
diff --git a/infra/config/generated/builders/ci/chromeos-js-code-coverage/properties.json b/infra/config/generated/builders/ci/chromeos-js-code-coverage/properties.json
new file mode 100644
index 0000000..b8e87de
--- /dev/null
+++ b/infra/config/generated/builders/ci/chromeos-js-code-coverage/properties.json
@@ -0,0 +1,68 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "chromeos-js-code-coverage",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-fyi-archive",
+              "builder_group": "chromium.coverage",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium",
+                "target_bits": 64,
+                "target_platform": "chromeos"
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "chromeos"
+                ],
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "chromeos-js-code-coverage",
+          "project": "chromium"
+        }
+      ],
+      "mirroring_builder_group_and_names": [
+        {
+          "builder": "chromeos-js-code-coverage",
+          "group": "tryserver.chromium.linux"
+        }
+      ]
+    }
+  },
+  "$build/code_coverage": {
+    "export_coverage_to_zoss": true,
+    "use_javascript_coverage": true
+  },
+  "$build/reclient": {
+    "instance": "rbe-chromium-trusted",
+    "jobs": 500,
+    "metrics_project": "chromium-reclient-metrics"
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "chromium.coverage",
+  "recipe": "chromium"
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/chromeos-js-code-coverage/properties.json b/infra/config/generated/builders/try/chromeos-js-code-coverage/properties.json
new file mode 100644
index 0000000..e107e28
--- /dev/null
+++ b/infra/config/generated/builders/try/chromeos-js-code-coverage/properties.json
@@ -0,0 +1,57 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "chromeos-js-code-coverage",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-fyi-archive",
+              "builder_group": "chromium.coverage",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium",
+                "target_bits": 64,
+                "target_platform": "chromeos"
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "chromeos"
+                ],
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "chromeos-js-code-coverage",
+          "project": "chromium"
+        }
+      ]
+    }
+  },
+  "$build/reclient": {
+    "instance": "rbe-chromium-untrusted",
+    "metrics_project": "chromium-reclient-metrics"
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "tryserver.chromium.linux",
+  "recipe": "chromium_trybot"
+}
\ No newline at end of file
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index a0f94c8..c7cef6b 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -1254,6 +1254,10 @@
         includable_only: true
       }
       builders {
+        name: "chromium/try/chromeos-js-code-coverage"
+        includable_only: true
+      }
+      builders {
         name: "chromium/try/chromeos-octopus-rel"
         includable_only: true
       }
diff --git a/infra/config/generated/luci/cr-buildbucket-dev.cfg b/infra/config/generated/luci/cr-buildbucket-dev.cfg
index 80f73ea9..5021b83 100644
--- a/infra/config/generated/luci/cr-buildbucket-dev.cfg
+++ b/infra/config/generated/luci/cr-buildbucket-dev.cfg
@@ -107,7 +107,7 @@
       swarming_host: "chromium-swarm-dev.appspot.com"
       dimensions: "builder:linux-local-ssd-rel-dev"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
         cipd_version: "refs/heads/main"
@@ -377,7 +377,7 @@
       swarming_host: "chromium-swarm-dev.appspot.com"
       dimensions: "builder:linux-remote-ssd-rel-dev"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "ssd:1"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index ad7fecf6..d687edd 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -25458,6 +25458,131 @@
       }
     }
     builders {
+      name: "android-build-perf-developer"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builder:android-build-perf-developer"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.ci"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$build/chromium_tests_builder_config": {'
+        '    "builder_config": {'
+        '      "builder_db": {'
+        '        "entries": ['
+        '          {'
+        '            "builder_id": {'
+        '              "bucket": "ci",'
+        '              "builder": "android-build-perf-developer",'
+        '              "project": "chromium"'
+        '            },'
+        '            "builder_spec": {'
+        '              "builder_group": "chromium.fyi",'
+        '              "execution_mode": "COMPILE_AND_TEST",'
+        '              "legacy_android_config": {'
+        '                "config": "main_builder"'
+        '              },'
+        '              "legacy_chromium_config": {'
+        '                "apply_configs": ['
+        '                  "mb"'
+        '                ],'
+        '                "build_config": "Debug",'
+        '                "config": "android",'
+        '                "target_bits": 64,'
+        '                "target_platform": "android"'
+        '              },'
+        '              "legacy_gclient_config": {'
+        '                "apply_configs": ['
+        '                  "android",'
+        '                  "checkout_siso"'
+        '                ],'
+        '                "config": "chromium"'
+        '              }'
+        '            }'
+        '          }'
+        '        ]'
+        '      },'
+        '      "builder_ids": ['
+        '        {'
+        '          "bucket": "ci",'
+        '          "builder": "android-build-perf-developer",'
+        '          "project": "chromium"'
+        '        }'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$build/reclient": {'
+        '    "instance": "rbe-chromium-untrusted",'
+        '    "jobs": 5120,'
+        '    "metrics_project": "chromium-reclient-metrics"'
+        '  },'
+        '  "$build/siso": {'
+        '    "enable_cloud_profiler": true,'
+        '    "enable_cloud_trace": true,'
+        '    "project": "rbe-chromium-untrusted"'
+        '  },'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "builder_group": "chromium.fyi",'
+        '  "recipe": "chrome_build/build_perf_developer"'
+        '}'
+      priority: 35
+      execution_timeout_secs: 36000
+      build_numbers: YES
+      service_account: "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "This builder measures build performance for Android developer builds, by simulating developer build scenarios on a high spec bot."
+    }
+    builders {
       name: "android-chrome-pie-x86-wpt-fyi-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -27046,6 +27171,78 @@
       }
     }
     builders {
+      name: "android-device-flasher"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "free_space:standard"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.ci"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "builder_group": "chromium.infra",'
+        '  "dry_run": true,'
+        '  "recipe": "android/device_flasher"'
+        '}'
+      execution_timeout_secs: 10800
+      build_numbers: YES
+      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
       name: "android-fieldtrial-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:android-fieldtrial-rel"
@@ -30478,6 +30675,91 @@
       }
     }
     builders {
+      name: "chromeos-js-code-coverage"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:32"
+      dimensions: "cpu:x86-64"
+      dimensions: "free_space:standard"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.ci"
+      dimensions: "ssd:1"
+      exe {
+        cipd_package: "infra/chromium/bootstrapper/${platform}"
+        cipd_version: "latest"
+        cmd: "bootstrapper"
+      }
+      properties:
+        '{'
+        '  "$bootstrap/exe": {'
+        '    "exe": {'
+        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
+        '      "cipd_version": "refs/heads/main",'
+        '      "cmd": ['
+        '        "luciexe"'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$bootstrap/properties": {'
+        '    "properties_file": "infra/config/generated/builders/ci/chromeos-js-code-coverage/properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "chromium.coverage",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium"'
+        '}'
+      priority: 35
+      execution_timeout_secs: 72000
+      build_numbers: YES
+      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
       name: "chromeos-octopus-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -36507,6 +36789,124 @@
       }
     }
     builders {
+      name: "linux-build-perf-developer"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builder:linux-build-perf-developer"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.ci"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$build/chromium_tests_builder_config": {'
+        '    "builder_config": {'
+        '      "builder_db": {'
+        '        "entries": ['
+        '          {'
+        '            "builder_id": {'
+        '              "bucket": "ci",'
+        '              "builder": "linux-build-perf-developer",'
+        '              "project": "chromium"'
+        '            },'
+        '            "builder_spec": {'
+        '              "builder_group": "chromium.fyi",'
+        '              "execution_mode": "COMPILE_AND_TEST",'
+        '              "legacy_chromium_config": {'
+        '                "apply_configs": ['
+        '                  "mb"'
+        '                ],'
+        '                "config": "chromium"'
+        '              },'
+        '              "legacy_gclient_config": {'
+        '                "apply_configs": ['
+        '                  "checkout_siso"'
+        '                ],'
+        '                "config": "chromium"'
+        '              }'
+        '            }'
+        '          }'
+        '        ]'
+        '      },'
+        '      "builder_ids": ['
+        '        {'
+        '          "bucket": "ci",'
+        '          "builder": "linux-build-perf-developer",'
+        '          "project": "chromium"'
+        '        }'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$build/reclient": {'
+        '    "instance": "rbe-chromium-untrusted",'
+        '    "jobs": 5120,'
+        '    "metrics_project": "chromium-reclient-metrics"'
+        '  },'
+        '  "$build/siso": {'
+        '    "enable_cloud_profiler": true,'
+        '    "enable_cloud_trace": true,'
+        '    "project": "rbe-chromium-untrusted"'
+        '  },'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "builder_group": "chromium.fyi",'
+        '  "recipe": "chrome_build/build_perf_developer"'
+        '}'
+      priority: 35
+      execution_timeout_secs: 36000
+      build_numbers: YES
+      service_account: "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "This builder measures build performance for Linux developer builds, by simulating developer build scenarios on a high spec bot."
+    }
+    builders {
       name: "linux-cfm-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -46060,6 +46460,124 @@
       }
     }
     builders {
+      name: "win-build-perf-developer"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builder:win-build-perf-developer"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.ci"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$build/chromium_tests_builder_config": {'
+        '    "builder_config": {'
+        '      "builder_db": {'
+        '        "entries": ['
+        '          {'
+        '            "builder_id": {'
+        '              "bucket": "ci",'
+        '              "builder": "win-build-perf-developer",'
+        '              "project": "chromium"'
+        '            },'
+        '            "builder_spec": {'
+        '              "builder_group": "chromium.fyi",'
+        '              "execution_mode": "COMPILE_AND_TEST",'
+        '              "legacy_chromium_config": {'
+        '                "apply_configs": ['
+        '                  "mb"'
+        '                ],'
+        '                "config": "chromium"'
+        '              },'
+        '              "legacy_gclient_config": {'
+        '                "apply_configs": ['
+        '                  "checkout_siso"'
+        '                ],'
+        '                "config": "chromium"'
+        '              }'
+        '            }'
+        '          }'
+        '        ]'
+        '      },'
+        '      "builder_ids": ['
+        '        {'
+        '          "bucket": "ci",'
+        '          "builder": "win-build-perf-developer",'
+        '          "project": "chromium"'
+        '        }'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$build/reclient": {'
+        '    "instance": "rbe-chromium-untrusted",'
+        '    "jobs": 1000,'
+        '    "metrics_project": "chromium-reclient-metrics"'
+        '  },'
+        '  "$build/siso": {'
+        '    "enable_cloud_profiler": true,'
+        '    "enable_cloud_trace": true,'
+        '    "project": "rbe-chromium-untrusted"'
+        '  },'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "builder_group": "chromium.fyi",'
+        '  "recipe": "chrome_build/build_perf_developer"'
+        '}'
+      priority: 35
+      execution_timeout_secs: 36000
+      build_numbers: YES
+      service_account: "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "This builder measures build performance for Windows developer builds, by simulating developer build scenarios on a high spec bot."
+    }
+    builders {
       name: "win-celab-builder-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:win-celab-builder-rel"
@@ -62143,7 +62661,7 @@
       dimensions: "builder:chromeos-amd64-generic-rel"
       dimensions: "cores:2"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.chromium.try"
       exe {
         cipd_package: "infra/chromium/bootstrapper/${platform}"
@@ -62238,7 +62756,7 @@
       dimensions: "builder:chromeos-amd64-generic-rel-compilator"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -62778,6 +63296,96 @@
       }
     }
     builders {
+      name: "chromeos-js-code-coverage"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/chromium/bootstrapper/${platform}"
+        cipd_version: "latest"
+        cmd: "bootstrapper"
+      }
+      properties:
+        '{'
+        '  "$bootstrap/exe": {'
+        '    "exe": {'
+        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
+        '      "cipd_version": "refs/heads/main",'
+        '      "cmd": ['
+        '        "luciexe"'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$bootstrap/properties": {'
+        '    "properties_file": "infra/config/generated/builders/try/chromeos-js-code-coverage/properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "tryserver.chromium.linux",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium_trybot"'
+        '}'
+      execution_timeout_secs: 72000
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
       name: "chromeos-octopus-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 225f4e8a..4dd4fd47 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -46,6 +46,11 @@
     short_name: "lnx"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/chromeos-js-code-coverage"
+    category: "linux"
+    short_name: "js"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/linux-js-code-coverage"
     category: "linux"
     short_name: "js"
@@ -9475,6 +9480,11 @@
     short_name: "and"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/android-build-perf-developer"
+    category: "buildperf"
+    short_name: "anddev"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/build-perf-android-siso"
     category: "buildperf"
     short_name: "andss"
@@ -9485,6 +9495,11 @@
     short_name: "lnx"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/linux-build-perf-developer"
+    category: "buildperf"
+    short_name: "lnxdev"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/build-perf-linux-siso"
     category: "buildperf"
     short_name: "lnxss"
@@ -9495,6 +9510,11 @@
     short_name: "win"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/win-build-perf-developer"
+    category: "buildperf"
+    short_name: "windev"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/build-perf-windows-siso"
     category: "buildperf"
     short_name: "winss"
@@ -11834,6 +11854,10 @@
   refs: "regexp:refs/heads/main"
   manifest_name: "REVISION"
   builders {
+    name: "buildbucket/luci.chromium.ci/android-device-flasher"
+    short_name: "flash"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/3pp-linux-amd64-packager"
     category: "packager|3pp|linux"
     short_name: "amd64"
@@ -17754,6 +17778,9 @@
     name: "buildbucket/luci.chromium.try/chromeos-jacuzzi-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/chromeos-js-code-coverage"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/chromeos-octopus-rel"
   }
   builders {
@@ -19230,6 +19257,9 @@
   id: "tryserver.chromium.linux"
   name: "tryserver.chromium.linux"
   builders {
+    name: "buildbucket/luci.chromium.try/chromeos-js-code-coverage"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/gpu-fyi-try-lacros-amd-rel"
   }
   builders {
diff --git a/infra/config/generated/luci/luci-notify.cfg b/infra/config/generated/luci/luci-notify.cfg
index 208cd3f9..9aa5e8e 100644
--- a/infra/config/generated/luci/luci-notify.cfg
+++ b/infra/config/generated/luci/luci-notify.cfg
@@ -2138,6 +2138,19 @@
 notifiers {
   notifications {
     on_new_status: FAILURE
+    email {
+      recipients: "chrome-buld-team+alert@google.com"
+    }
+  }
+  builders {
+    bucket: "ci"
+    name: "android-build-perf-developer"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+}
+notifiers {
+  notifications {
+    on_new_status: FAILURE
     on_new_status: INFRA_FAILURE
     on_new_status: SUCCESS
     email {
@@ -3271,6 +3284,19 @@
 }
 notifiers {
   notifications {
+    on_new_status: FAILURE
+    email {
+      recipients: "chrome-buld-team+alert@google.com"
+    }
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-build-perf-developer"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+}
+notifiers {
+  notifications {
     on_occurrence: FAILURE
     failed_step_regexp: "\\b(bot_update|compile|gclient runhooks|runhooks|update|\\w*nocompile_test)\\b"
     email {
@@ -3732,6 +3758,19 @@
 notifiers {
   notifications {
     on_new_status: FAILURE
+    email {
+      recipients: "chrome-buld-team+alert@google.com"
+    }
+  }
+  builders {
+    bucket: "ci"
+    name: "win-build-perf-developer"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+}
+notifiers {
+  notifications {
+    on_new_status: FAILURE
     on_new_status: INFRA_FAILURE
     email {
       recipients: "chrome-rust-experiments+bots@google.com"
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg
index a1d3c83..49916cd 100644
--- a/infra/config/generated/luci/luci-scheduler.cfg
+++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -3567,6 +3567,15 @@
   }
 }
 job {
+  id: "android-build-perf-developer"
+  realm: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "android-build-perf-developer"
+  }
+}
+job {
   id: "android-chrome-pie-x86-wpt-fyi-rel"
   realm: "ci"
   buildbucket {
@@ -3748,6 +3757,16 @@
   }
 }
 job {
+  id: "android-device-flasher"
+  realm: "ci"
+  schedule: "triggered"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "android-device-flasher"
+  }
+}
+job {
   id: "android-device-launcher"
   realm: "reviver"
   schedule: "0 5,8,11 * * *"
@@ -4136,6 +4155,20 @@
   }
 }
 job {
+  id: "chromeos-js-code-coverage"
+  realm: "ci"
+  schedule: "triggered"
+  triggering_policy {
+    kind: GREEDY_BATCHING
+    max_concurrent_invocations: 2
+  }
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "chromeos-js-code-coverage"
+  }
+}
+job {
   id: "chromeos-octopus-rel"
   realm: "ci"
   buildbucket {
@@ -4849,6 +4882,15 @@
   }
 }
 job {
+  id: "linux-build-perf-developer"
+  realm: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "linux-build-perf-developer"
+  }
+}
+job {
   id: "linux-cfm-rel"
   realm: "ci"
   buildbucket {
@@ -5936,6 +5978,15 @@
   }
 }
 job {
+  id: "win-build-perf-developer"
+  realm: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "win-build-perf-developer"
+  }
+}
+job {
   id: "win-celab-builder-rel"
   realm: "ci"
   schedule: "0 0,6,12,18 * * *"
@@ -6486,6 +6537,7 @@
   triggers: "android-backuprefptr-arm64-fyi-rel"
   triggers: "android-bfcache-rel"
   triggers: "android-binary-size-generator"
+  triggers: "android-build-perf-developer"
   triggers: "android-chrome-pie-x86-wpt-fyi-rel"
   triggers: "android-cronet-arm-dbg"
   triggers: "android-cronet-arm-rel"
@@ -6576,6 +6628,7 @@
   triggers: "linux-blink-heap-verification"
   triggers: "linux-blink-web-tests-force-accessibility-rel"
   triggers: "linux-blink-wpt-reset-rel"
+  triggers: "linux-build-perf-developer"
   triggers: "linux-cfm-rel"
   triggers: "linux-chromeos-annotator-rel"
   triggers: "linux-chromeos-dbg"
@@ -6645,6 +6698,7 @@
   triggers: "win-asan"
   triggers: "win-backuprefptr-x64-fyi-rel"
   triggers: "win-backuprefptr-x86-fyi-rel"
+  triggers: "win-build-perf-developer"
   triggers: "win-fieldtrial-rel"
   triggers: "win-official"
   triggers: "win-presubmit"
@@ -6762,6 +6816,7 @@
   triggers: "android-code-coverage"
   triggers: "android-code-coverage-native"
   triggers: "android-x86-code-coverage"
+  triggers: "chromeos-js-code-coverage"
   triggers: "fuchsia-code-coverage"
   triggers: "ios-simulator-code-coverage"
   triggers: "linux-chromeos-code-coverage"
diff --git a/infra/config/lib/linux-default.json b/infra/config/lib/linux-default.json
index fec0cee..b438ca17 100644
--- a/infra/config/lib/linux-default.json
+++ b/infra/config/lib/linux-default.json
@@ -1,7 +1,8 @@
 {
   "ci": {
+    "linux-local-ssd-rel-dev": "Ubuntu-22.04",
     "linux-rel-jammy-dev": "Ubuntu-22.04",
-    "linux-ssd-rel-dev": "Ubuntu-22.04",
+    "linux-remote-ssd-rel-dev": "Ubuntu-22.04",
     "build-perf-linux": "Ubuntu-22.04",
     "build-perf-linux-siso": "Ubuntu-22.04",
     "build-perf-android": "Ubuntu-22.04",
@@ -9,6 +10,8 @@
   },
   "try": {
     "android-12-x64-rel": "Ubuntu-22.04",
+    "chromeos-amd64-generic-rel": "Ubuntu-22.04",
+    "chromeos-amd64-generic-rel-compilator": "Ubuntu-22.04",
     "linux-chromeos-rel": "Ubuntu-22.04",
     "linux-lacros-rel": "Ubuntu-22.04",
     "linux-rel": "Ubuntu-22.04",
diff --git a/infra/config/recipes.star b/infra/config/recipes.star
index ba44590..cb39177 100644
--- a/infra/config/recipes.star
+++ b/infra/config/recipes.star
@@ -87,6 +87,10 @@
 )
 
 build_recipe(
+    name = "recipe:android/device_flasher",
+)
+
+build_recipe(
     name = "recipe:android/sdk_packager",
 )
 
@@ -124,6 +128,10 @@
 )
 
 build_recipe(
+    name = "recipe:chrome_build/build_perf_developer",
+)
+
+build_recipe(
     name = "recipe:celab",
 )
 
diff --git a/infra/config/subprojects/chromium/ci/chromium.coverage.star b/infra/config/subprojects/chromium/ci/chromium.coverage.star
index 27eeebb..ffbe2ce 100644
--- a/infra/config/subprojects/chromium/ci/chromium.coverage.star
+++ b/infra/config/subprojects/chromium/ci/chromium.coverage.star
@@ -284,6 +284,38 @@
     use_javascript_coverage = True,
 )
 
+coverage_builder(
+    name = "chromeos-js-code-coverage",
+    builder_spec = builder_config.builder_spec(
+        gclient_config = builder_config.gclient_config(
+            config = "chromium",
+            apply_configs = [
+                "chromeos",
+            ],
+        ),
+        chromium_config = builder_config.chromium_config(
+            config = "chromium",
+            apply_configs = [
+                "mb",
+            ],
+            build_config = builder_config.build_config.RELEASE,
+            target_bits = 64,
+            target_platform = builder_config.target_platform.CHROMEOS,
+        ),
+        build_gs_bucket = "chromium-fyi-archive",
+    ),
+    os = os.LINUX_DEFAULT,
+    console_view_entry = [
+        consoles.console_view_entry(
+            category = "linux",
+            short_name = "js",
+        ),
+    ],
+    export_coverage_to_zoss = True,
+    reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
+    use_javascript_coverage = True,
+)
+
 # Experimental builder. Does not export_coverage_to_zoss.
 coverage_builder(
     name = "linux-fuzz-coverage",
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index 06a0c2e0d..3d3283ff 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1511,9 +1511,10 @@
 
 def build_perf_builder(**kwargs):
     kwargs.setdefault("executable", "recipe:chrome_build/build_perf")
+    kwargs.setdefault("reclient_jobs", reclient.jobs.HIGH_JOBS_FOR_CQ)
+    kwargs.setdefault("use_clang_coverage", True)
     return ci.builder(
         reclient_instance = reclient.instance.DEFAULT_UNTRUSTED,
-        reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
         service_account = "chromium-build-perf-ci-builder@chops-service-accounts.iam.gserviceaccount.com",
         # rely on the builder dimension for the bot selection.
         builderless = False,
@@ -1521,7 +1522,6 @@
         siso_enable_cloud_profiler = True,
         siso_enable_cloud_trace = True,
         siso_project = siso.project.DEFAULT_UNTRUSTED,
-        use_clang_coverage = True,
         notifies = ["chrome-build-perf"],
         **kwargs
     )
@@ -1597,6 +1597,42 @@
 )
 
 build_perf_builder(
+    name = "android-build-perf-developer",
+    description_html = """\
+This builder measures build performance for Android developer builds, by simulating developer build scenarios on a high spec bot.\
+""",
+    executable = "recipe:chrome_build/build_perf_developer",
+    builder_spec = builder_config.builder_spec(
+        gclient_config = builder_config.gclient_config(
+            config = "chromium",
+            apply_configs = [
+                "android",
+                "checkout_siso",
+            ],
+        ),
+        chromium_config = builder_config.chromium_config(
+            config = "android",
+            apply_configs = [
+                "mb",
+            ],
+            build_config = builder_config.build_config.DEBUG,
+            target_bits = 64,
+            target_platform = builder_config.target_platform.ANDROID,
+        ),
+        android_config = builder_config.android_config(
+            config = "main_builder",
+        ),
+    ),
+    os = os.LINUX_DEFAULT,
+    console_view_entry = consoles.console_view_entry(
+        category = "buildperf",
+        short_name = "anddev",
+    ),
+    reclient_jobs = 5120,
+    use_clang_coverage = None,
+)
+
+build_perf_builder(
     name = "build-perf-linux",
     description_html = """\
 This builder measures Linux build performance with and without remote caches.<br/>\
@@ -1653,6 +1689,35 @@
 )
 
 build_perf_builder(
+    name = "linux-build-perf-developer",
+    description_html = """\
+This builder measures build performance for Linux developer builds, by simulating developer build scenarios on a high spec bot.\
+""",
+    executable = "recipe:chrome_build/build_perf_developer",
+    builder_spec = builder_config.builder_spec(
+        gclient_config = builder_config.gclient_config(
+            config = "chromium",
+            apply_configs = [
+                "checkout_siso",
+            ],
+        ),
+        chromium_config = builder_config.chromium_config(
+            config = "chromium",
+            apply_configs = [
+                "mb",
+            ],
+        ),
+    ),
+    os = os.LINUX_DEFAULT,
+    console_view_entry = consoles.console_view_entry(
+        category = "buildperf",
+        short_name = "lnxdev",
+    ),
+    reclient_jobs = 5120,
+    use_clang_coverage = None,
+)
+
+build_perf_builder(
     name = "build-perf-windows",
     description_html = """\
 This builder measures Windows build performance with and without remote caches.<br/>\
@@ -1708,6 +1773,35 @@
     ),
 )
 
+build_perf_builder(
+    name = "win-build-perf-developer",
+    description_html = """\
+This builder measures build performance for Windows developer builds, by simulating developer build scenarios on a high spec bot.\
+""",
+    executable = "recipe:chrome_build/build_perf_developer",
+    builder_spec = builder_config.builder_spec(
+        gclient_config = builder_config.gclient_config(
+            config = "chromium",
+            apply_configs = [
+                "checkout_siso",
+            ],
+        ),
+        chromium_config = builder_config.chromium_config(
+            config = "chromium",
+            apply_configs = [
+                "mb",
+            ],
+        ),
+    ),
+    os = os.LINUX_DEFAULT,
+    console_view_entry = consoles.console_view_entry(
+        category = "buildperf",
+        short_name = "windev",
+    ),
+    reclient_jobs = 1000,
+    use_clang_coverage = None,
+)
+
 ci.builder(
     name = "Linux Builder (j-500) (reclient)",
     schedule = "triggered",
diff --git a/infra/config/subprojects/chromium/ci/chromium.infra.star b/infra/config/subprojects/chromium/ci/chromium.infra.star
index f6aac23f..1a61383 100644
--- a/infra/config/subprojects/chromium/ci/chromium.infra.star
+++ b/infra/config/subprojects/chromium/ci/chromium.infra.star
@@ -297,3 +297,21 @@
         ),
     ],
 )
+
+ci.builder(
+    name = "android-device-flasher",
+    executable = "recipe:android/device_flasher",
+    # Triggered manually through the scheduler UI
+    # https://luci-scheduler.appspot.com/jobs/chromium/android-device-flasher
+    # TODO(crbug.com/1260195): Run the build regularly once recipe fully works
+    schedule = "triggered",
+    triggered_by = [],
+    console_view_entry = consoles.console_view_entry(
+        short_name = "flash",
+    ),
+    # TODO(crbug.com/1260195): Enable the notifies once recipe fully works
+    notifies = [],
+    properties = {
+        "dry_run": True,
+    },
+)
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
index 2e013fa..79e844eb 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -727,6 +727,12 @@
     execution_timeout = 20 * time.hour,
 )
 
+try_.builder(
+    name = "chromeos-js-code-coverage",
+    mirrors = ["ci/chromeos-js-code-coverage"],
+    execution_timeout = 20 * time.hour,
+)
+
 # ML experimental builder, modifies RTS itself to use a ml model
 try_.builder(
     name = "linux-rel-ml",
diff --git a/ios/chrome/browser/shared/ui/table_view/cells/table_view_multi_line_text_edit_item.mm b/ios/chrome/browser/shared/ui/table_view/cells/table_view_multi_line_text_edit_item.mm
index 0075632..bfd7602 100644
--- a/ios/chrome/browser/shared/ui/table_view/cells/table_view_multi_line_text_edit_item.mm
+++ b/ios/chrome/browser/shared/ui/table_view/cells/table_view_multi_line_text_edit_item.mm
@@ -92,7 +92,9 @@
               reuseIdentifier:(NSString*)reuseIdentifier {
   self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
   if (self) {
-    self.isAccessibilityElement = YES;
+    // The cell shouldn't be an a11y element to make the text view accessible to
+    // VoiceOver.
+    self.isAccessibilityElement = NO;
 
     UIView* contentView = self.contentView;
 
@@ -101,6 +103,7 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     _textLabel.font =
         [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
+    _textLabel.isAccessibilityElement = NO;
     [contentView addSubview:_textLabel];
 
     _textView = [[UITextView alloc] init];
@@ -110,10 +113,12 @@
     _textView.scrollEnabled = NO;
     _textView.textContainer.lineFragmentPadding = 0;
     _textView.textContainerInset = UIEdgeInsetsZero;
+    _textView.isAccessibilityElement = YES;
     [contentView addSubview:_textView];
 
     _iconView = [[UIImageView alloc] initWithImage:nil];
     _iconView.translatesAutoresizingMaskIntoConstraints = NO;
+    _iconView.isAccessibilityElement = NO;
     [contentView addSubview:_iconView];
 
     [NSLayoutConstraint activateConstraints:@[
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_coordinator.mm b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_coordinator.mm
index ea13e144..d96618e 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_coordinator.mm
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_coordinator.mm
@@ -51,7 +51,8 @@
     self.viewController = [[PasswordSuggestionBottomSheetViewController alloc]
         initWithHandler:self];
 
-    ChromeBrowserState* browserState = self.browser->GetBrowserState();
+    ChromeBrowserState* browserState =
+        browser->GetBrowserState()->GetOriginalChromeBrowserState();
     _savedPasswordsPresenter =
         std::make_unique<password_manager::SavedPasswordsPresenter>(
             IOSChromeAffiliationServiceFactory::GetForBrowserState(
@@ -64,9 +65,8 @@
     self.mediator = [[PasswordSuggestionBottomSheetMediator alloc]
            initWithWebStateList:browser->GetWebStateList()
                   faviconLoader:IOSChromeFaviconLoaderFactory::
-                                    GetForBrowserState(
-                                        browser->GetBrowserState())
-                    prefService:browser->GetBrowserState()->GetPrefs()
+                                    GetForBrowserState(browserState)
+                    prefService:browserState->GetPrefs()
                          params:params
         savedPasswordsPresenter:_savedPasswordsPresenter.get()];
     self.viewController.delegate = self.mediator;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
index ccd5ae1..34f0583d 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
@@ -628,8 +628,6 @@
     shouldHighlightRowAtIndexPath:(NSIndexPath*)indexPath {
   NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
   switch (itemType) {
-    case PasswordDetailsItemTypeNote:
-      return YES;
     case PasswordDetailsItemTypeWebsite:
     case PasswordDetailsItemTypeFederation:
     case PasswordDetailsItemTypeUsername:
@@ -638,6 +636,7 @@
     case PasswordDetailsItemTypeMoveToAccountButton:
       return !self.editing;
     case PasswordDetailsItemTypeDeleteButton:
+    case PasswordDetailsItemTypeNote:
       return self.editing;
     case PasswordDetailsItemTypeChangePasswordRecommendation:
     case PasswordDetailsItemTypeMoveToAccountRecommendation:
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
index 295f307..d66fbbfe 100644
--- a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
@@ -473,6 +473,15 @@
 - (GREYElementInteraction*)
     interactionForSinglePasswordEntryWithDomain:(NSString*)domain
                                        username:(NSString*)username {
+  // With notes enabled authentication is required before interacting with
+  // password details.
+  if ([self notesEnabled]) {
+    [PasswordSettingsAppInterface
+        setUpMockReauthenticationModuleForPasswordManager];
+    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
+                                      ReauthenticationResult::kSuccess];
+  }
+
   // With grouping enabled, discard the username; it's only shown on the details
   // page.
   // ID, not label because the latter might contain an extra label for the
@@ -584,13 +593,6 @@
       performAction:grey_tap()];
 
   // Inspect "password details" view.
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -662,13 +664,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -742,13 +737,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -775,13 +763,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -812,13 +793,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -883,13 +857,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -964,13 +931,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -1048,13 +1008,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -1219,13 +1172,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -1309,13 +1255,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -1368,13 +1307,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"federated username"]
       performAction:grey_tap()];
@@ -1423,13 +1355,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -1518,10 +1443,6 @@
   SaveExamplePasswordFormWithNote();
 
   OpenPasswordManager();
-  [PasswordSettingsAppInterface
-      setUpMockReauthenticationModuleForPasswordManager];
-  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                    ReauthenticationResult::kSuccess];
 
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
@@ -1567,10 +1488,6 @@
   SaveExamplePasswordFormWithNote();
 
   OpenPasswordManager();
-  [PasswordSettingsAppInterface
-      setUpMockReauthenticationModuleForPasswordManager];
-  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                    ReauthenticationResult::kSuccess];
 
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
@@ -1656,13 +1573,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"federated username"]
       performAction:grey_tap()];
@@ -2273,13 +2183,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -2334,13 +2237,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -2418,13 +2314,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username1"]
       performAction:grey_tap()];
@@ -2469,13 +2358,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
       performAction:grey_tap()];
@@ -2925,13 +2807,6 @@
   [[EarlGrey selectElementWithMatcher:AddPasswordSaveButton()]
       performAction:grey_tap()];
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"new username"]
       performAction:grey_tap()];
@@ -2987,9 +2862,9 @@
   }
 
   GREYAssert([PasswordSettingsAppInterface
-                 saveInsecurePassword:@"concrete password"
-                             userName:@"concrete username"
-                               origin:@"https://example.com"],
+                 saveCompromisedPassword:@"concrete password"
+                                userName:@"concrete username"
+                                  origin:@"https://example.com"],
              @"Stored form was not found in the PasswordStore results.");
 
   OpenPasswordManager();
@@ -3088,10 +2963,6 @@
   SaveExamplePasswordForm();
 
   OpenPasswordManager();
-  [PasswordSettingsAppInterface
-      setUpMockReauthenticationModuleForPasswordManager];
-  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                    ReauthenticationResult::kSuccess];
 
   [[self interactionForSinglePasswordEntryWithDomain:@"example.com"
                                             username:@"concrete username"]
@@ -3126,13 +2997,6 @@
 
   OpenPasswordManager();
 
-  if ([self notesEnabled]) {
-    [PasswordSettingsAppInterface
-        setUpMockReauthenticationModuleForPasswordManager];
-    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                      ReauthenticationResult::kSuccess];
-  }
-
   // Make sure the cell is loaded properly before tapping on it.
   ConditionBlock condition = ^{
     NSError* error = nil;
@@ -3608,6 +3472,15 @@
 - (GREYElementInteraction*)
     interactionForSinglePasswordEntryWithDomain:(NSString*)domain
                                        username:(NSString*)username {
+  // With notes enabled authentication is required before interacting with
+  // password details.
+  if ([self notesEnabled]) {
+    [PasswordSettingsAppInterface
+        setUpMockReauthenticationModuleForPasswordManager];
+    [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
+                                      ReauthenticationResult::kSuccess];
+  }
+
   NSString* label = [NSString stringWithFormat:@"%@, %@", domain, username];
   // ID, not label because the latter might contain an extra label for the
   // "local password icon" and most tests don't care about it.
diff --git a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h
index 26e86c7a..0e1485b 100644
--- a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h
+++ b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.h
@@ -48,10 +48,25 @@
                userName:(NSString*)userName
                  origin:(NSString*)origin;
 
-// Creates password form which is leaked.
-+ (BOOL)saveInsecurePassword:(NSString*)password
-                    userName:(NSString*)userName
-                      origin:(NSString*)origin;
+// Creates a compromised password form.
++ (BOOL)saveCompromisedPassword:(NSString*)password
+                       userName:(NSString*)userName
+                         origin:(NSString*)origin;
+
+// Creates a muted compromised password form.
++ (BOOL)saveMutedCompromisedPassword:(NSString*)password
+                            userName:(NSString*)userName
+                              origin:(NSString*)origin;
+
+// Creates a reused password form.
++ (BOOL)saveReusedPassword:(NSString*)password
+                  userName:(NSString*)userName
+                    origin:(NSString*)origin;
+
+// Creates a weak password form.
++ (BOOL)saveWeakPassword:(NSString*)password
+                userName:(NSString*)userName
+                  origin:(NSString*)origin;
 
 // Creates a blocked password form for given origin.
 + (BOOL)saveExampleBlockedOrigin:(NSString*)origin;
diff --git a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm
index 296f930..e3c312e 100644
--- a/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm
+++ b/ios/chrome/browser/ui/settings/password/password_settings_app_interface.mm
@@ -232,9 +232,9 @@
   return SaveToPasswordStore(example);
 }
 
-+ (BOOL)saveInsecurePassword:(NSString*)password
-                    userName:(NSString*)userName
-                      origin:(NSString*)origin {
++ (BOOL)saveCompromisedPassword:(NSString*)password
+                       userName:(NSString*)userName
+                         origin:(NSString*)origin {
   PasswordForm example;
   example.username_value = base::SysNSStringToUTF16(userName);
   example.password_value = base::SysNSStringToUTF16(password);
@@ -245,6 +245,47 @@
   return SaveToPasswordStore(example);
 }
 
++ (BOOL)saveMutedCompromisedPassword:(NSString*)password
+                            userName:(NSString*)userName
+                              origin:(NSString*)origin {
+  PasswordForm example;
+  example.username_value = base::SysNSStringToUTF16(userName);
+  example.password_value = base::SysNSStringToUTF16(password);
+  example.url = GURL(base::SysNSStringToUTF16(origin));
+  example.signon_realm = example.url.spec();
+  example.password_issues.insert(
+      {password_manager::InsecureType::kLeaked,
+       password_manager::InsecurityMetadata(base::Time::Now(),
+                                            password_manager::IsMuted(true))});
+  return SaveToPasswordStore(example);
+}
+
++ (BOOL)saveReusedPassword:(NSString*)password
+                  userName:(NSString*)userName
+                    origin:(NSString*)origin {
+  PasswordForm example;
+  example.username_value = base::SysNSStringToUTF16(userName);
+  example.password_value = base::SysNSStringToUTF16(password);
+  example.url = GURL(base::SysNSStringToUTF16(origin));
+  example.signon_realm = example.url.spec();
+  example.password_issues.insert({password_manager::InsecureType::kReused,
+                                  password_manager::InsecurityMetadata()});
+  return SaveToPasswordStore(example);
+}
+
++ (BOOL)saveWeakPassword:(NSString*)password
+                userName:(NSString*)userName
+                  origin:(NSString*)origin {
+  PasswordForm example;
+  example.username_value = base::SysNSStringToUTF16(userName);
+  example.password_value = base::SysNSStringToUTF16(password);
+  example.url = GURL(base::SysNSStringToUTF16(origin));
+  example.signon_realm = example.url.spec();
+  example.password_issues.insert({password_manager::InsecureType::kWeak,
+                                  password_manager::InsecurityMetadata()});
+  return SaveToPasswordStore(example);
+}
+
 + (BOOL)saveExampleBlockedOrigin:(NSString*)origin {
   PasswordForm example;
   example.url = GURL(base::SysNSStringToUTF16(origin));
diff --git a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm
index 3188ba11..60efebb 100644
--- a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm
+++ b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm
@@ -1175,7 +1175,7 @@
       self.passwordCheckItem.detailText =
           l10n_util::GetNSStringF(IDS_IOS_PASSWORD_CHECKUP_REUSED_COUNT,
                                   base::NumberToString16(reusedPasswordCount));
-      self.passwordCheckItem.warningState = WarningState::kWarning;
+      self.passwordCheckItem.trailingImage = nil;
       break;
     }
     case PasswordCheckRowStateWeakPasswords: {
@@ -1185,7 +1185,7 @@
       self.passwordCheckItem.detailText =
           base::SysUTF16ToNSString(l10n_util::GetPluralStringFUTF16(
               IDS_IOS_PASSWORD_CHECKUP_WEAK_COUNT, weakPasswordCount));
-      self.passwordCheckItem.warningState = WarningState::kWarning;
+      self.passwordCheckItem.trailingImage = nil;
       break;
     }
     case PasswordCheckRowStateDismissedWarnings: {
@@ -1195,7 +1195,7 @@
       self.passwordCheckItem.detailText =
           base::SysUTF16ToNSString(l10n_util::GetPluralStringFUTF16(
               IDS_IOS_PASSWORD_CHECKUP_DISMISSED_COUNT, dismissedWarningCount));
-      self.passwordCheckItem.warningState = WarningState::kWarning;
+      self.passwordCheckItem.trailingImage = nil;
       break;
     }
     case PasswordCheckRowStateDisabled:
diff --git a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm
index 2e9de1b..f3f4720 100644
--- a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator_unittest.mm
@@ -101,13 +101,6 @@
                                             kTrailingSymbolImagePointSize);
 }
 
-// The image when there are reused passwords, weak passwords or dismissed
-// compromised password warnings.
-UIImage* WarningImage() {
-  return DefaultSymbolTemplateWithPointSize(kErrorCircleFillSymbol,
-                                            kTrailingSymbolImagePointSize);
-}
-
 // The image when the state is unsafe.
 UIImage* UnsafeImage() {
   return DefaultSymbolTemplateWithPointSize(
@@ -121,12 +114,6 @@
       colorNamed:IsPasswordCheckupEnabled() ? kGreen500Color : kGreenColor];
 }
 
-// The color when there are reused passwords, weak passwords or dismissed
-// compromised password warnings.
-UIColor* YellowColor() {
-  return [UIColor colorNamed:kYellow500Color];
-}
-
 // The color when the state is unsafe.
 UIColor* RedColor() {
   return [UIColor
@@ -568,9 +555,7 @@
   EXPECT_NSEQ(
       mediator_.passwordCheckItem.detailText,
       l10n_util::GetNSStringF(IDS_IOS_PASSWORD_CHECKUP_REUSED_COUNT, u"2"));
-  EXPECT_EQ(mediator_.passwordCheckItem.trailingImage, WarningImage());
-  EXPECT_TRUE([mediator_.passwordCheckItem.trailingImageTintColor
-      isEqual:YellowColor()]);
+  EXPECT_EQ(mediator_.passwordCheckItem.trailingImage, nil);
   EXPECT_EQ(mediator_.passwordCheckItem.accessoryType,
             UITableViewCellAccessoryDisclosureIndicator);
 }
@@ -602,9 +587,7 @@
   EXPECT_NSEQ(mediator_.passwordCheckItem.detailText,
               base::SysUTF16ToNSString(l10n_util::GetPluralStringFUTF16(
                   IDS_IOS_PASSWORD_CHECKUP_WEAK_COUNT, 1)));
-  EXPECT_EQ(mediator_.passwordCheckItem.trailingImage, WarningImage());
-  EXPECT_TRUE([mediator_.passwordCheckItem.trailingImageTintColor
-      isEqual:YellowColor()]);
+  EXPECT_EQ(mediator_.passwordCheckItem.trailingImage, nil);
   EXPECT_EQ(mediator_.passwordCheckItem.accessoryType,
             UITableViewCellAccessoryDisclosureIndicator);
 }
@@ -638,9 +621,7 @@
   EXPECT_NSEQ(mediator_.passwordCheckItem.detailText,
               base::SysUTF16ToNSString(l10n_util::GetPluralStringFUTF16(
                   IDS_IOS_PASSWORD_CHECKUP_DISMISSED_COUNT, 1)));
-  EXPECT_EQ(mediator_.passwordCheckItem.trailingImage, WarningImage());
-  EXPECT_TRUE([mediator_.passwordCheckItem.trailingImageTintColor
-      isEqual:YellowColor()]);
+  EXPECT_EQ(mediator_.passwordCheckItem.trailingImage, nil);
   EXPECT_EQ(mediator_.passwordCheckItem.accessoryType,
             UITableViewCellAccessoryDisclosureIndicator);
 }
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
index c70cd88c..2862791 100644
--- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -1652,10 +1652,11 @@
         password_manager::WarningType::kCompromisedPasswordsWarning) {
       _safetyCheckItem.warningState = WarningState::kSevereWarning;
     } else {
-      // Severe warning is of higher priority than a regular warning. Only show
-      // the regular warning icon if there isn't any severe warning existing for
-      // another part of the Safety Check module.
-      _safetyCheckItem.warningState = WarningState::kWarning;
+      // Getting here means that there are reused, weak and/or muted passwords.
+      // In Safety Check, an icon is shown for passwords only when all passwords
+      // are safe or when there are unmuted compromised passwords. When there
+      // are reused, weak and/or muted passwords, no icon is shown.
+      _safetyCheckItem.trailingImage = nil;
     }
   }
   [self reconfigureCellsForItems:@[ _safetyCheckItem ]];
diff --git a/ios/third_party/earl_grey2/BUILD.gn b/ios/third_party/earl_grey2/BUILD.gn
index 37618d1..332e29d 100644
--- a/ios/third_party/earl_grey2/BUILD.gn
+++ b/ios/third_party/earl_grey2/BUILD.gn
@@ -183,6 +183,7 @@
     "src/UILib/GREYScreenshotter.h",
     "src/UILib/Provider/GREYUIWindowProvider.h",
     "src/UILib/Visibility/GREYVisibilityChecker.h",
+    "src/UILib/Visibility/GREYVisibilityCheckerCacheEntry.h",
   ]
 }
 
@@ -218,7 +219,6 @@
     "src/UILib/Visibility/GREYQuickVisibilityChecker.m",
     "src/UILib/Visibility/GREYThoroughVisibilityChecker.h",
     "src/UILib/Visibility/GREYThoroughVisibilityChecker.m",
-    "src/UILib/Visibility/GREYVisibilityChecker+Private.h",
     "src/UILib/Visibility/GREYVisibilityChecker.h",
     "src/UILib/Visibility/GREYVisibilityChecker.m",
     "src/UILib/Visibility/GREYVisibilityCheckerCacheEntry.h",
diff --git a/media/base/demuxer_memory_limit_android.cc b/media/base/demuxer_memory_limit_android.cc
index 26985636..4a7bdc5 100644
--- a/media/base/demuxer_memory_limit_android.cc
+++ b/media/base/demuxer_memory_limit_android.cc
@@ -14,7 +14,7 @@
 size_t SelectLimit(size_t default_limit,
                    size_t low_limit,
                    size_t very_low_limit) {
-  if (!base::SysInfo::IsLowEndDevice()) {
+  if (!base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled()) {
     return default_limit;
   }
   // Use very low limit on 512MiB Android Go devices only.
diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc
index 43b851c..483e621 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.cc
+++ b/media/gpu/chromeos/video_decoder_pipeline.cc
@@ -229,6 +229,33 @@
 }
 
 // static
+std::unique_ptr<VideoDecoder> VideoDecoderPipeline::CreateForTesting(
+    scoped_refptr<base::SequencedTaskRunner> client_task_runner,
+    std::unique_ptr<MediaLog> media_log,
+    bool ignore_resolution_changes_to_smaller_for_testing) {
+  CreateDecoderFunctionCB
+#if BUILDFLAG(USE_VAAPI)
+      create_decoder_function_cb = base::BindOnce(&VaapiVideoDecoder::Create);
+#elif BUILDFLAG(USE_V4L2_CODEC)
+      create_decoder_function_cb = base::BindOnce(&V4L2VideoDecoder::Create);
+#endif
+
+  auto* pipeline = new VideoDecoderPipeline(
+      gpu::GpuDriverBugWorkarounds(), std::move(client_task_runner),
+      std::make_unique<PlatformVideoFramePool>(),
+      /*frame_converter=*/nullptr,
+      VideoDecoderPipeline::DefaultPreferredRenderableFourccs(),
+      std::move(media_log), std::move(create_decoder_function_cb),
+      /*uses_oop_video_decoder=*/false);
+
+  if (ignore_resolution_changes_to_smaller_for_testing)
+    pipeline->ignore_resolution_changes_to_smaller_for_testing_ = true;
+
+  return std::make_unique<AsyncDestroyVideoDecoder<VideoDecoderPipeline>>(
+      base::WrapUnique(pipeline));
+}
+
+// static
 std::vector<Fourcc> VideoDecoderPipeline::DefaultPreferredRenderableFourccs() {
   // Preferred output formats in order of preference.
   // TODO(mcasas): query the platform for its preferred formats and modifiers.
@@ -520,6 +547,14 @@
   estimated_num_buffers_for_renderer_ =
       EstimateRequiredRendererPipelineBuffers(low_delay);
 
+#if BUILDFLAG(USE_VAAPI)
+  if (ignore_resolution_changes_to_smaller_for_testing_) {
+    static_cast<VaapiVideoDecoder*>(decoder_.get())
+        ->set_ignore_resolution_changes_to_smaller_vp9_for_testing(  // IN-TEST
+            true);
+  }
+#endif
+
   decoder_->Initialize(
       config, /* low_delay=*/false, cdm_context,
       base::BindOnce(&VideoDecoderPipeline::OnInitializeDone,
diff --git a/media/gpu/chromeos/video_decoder_pipeline.h b/media/gpu/chromeos/video_decoder_pipeline.h
index 35d31480..1243154 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.h
+++ b/media/gpu/chromeos/video_decoder_pipeline.h
@@ -160,6 +160,11 @@
       std::unique_ptr<MediaLog> media_log,
       mojo::PendingRemote<stable::mojom::StableVideoDecoder> oop_video_decoder);
 
+  static std::unique_ptr<VideoDecoder> CreateForTesting(
+      scoped_refptr<base::SequencedTaskRunner> client_task_runner,
+      std::unique_ptr<MediaLog> media_log,
+      bool ignore_resolution_changes_to_smaller_for_testing = false);
+
   static std::vector<Fourcc> DefaultPreferredRenderableFourccs();
 
   // Ensures that the video decoder supported configurations are known. When
@@ -414,6 +419,9 @@
   // Set to true to bypass checks for encrypted content support for testing.
   bool allow_encrypted_content_for_testing_ = false;
 
+  // See VP9Decoder for information on this.
+  bool ignore_resolution_changes_to_smaller_for_testing_ = false;
+
   base::WeakPtr<VideoDecoderPipeline> decoder_weak_this_;
   // The weak pointer of this, bound to |decoder_task_runner_|.
   base::WeakPtrFactory<VideoDecoderPipeline> decoder_weak_this_factory_{this};
diff --git a/media/gpu/test/video_decode_accelerator_tests.cc b/media/gpu/test/video_decode_accelerator_tests.cc
index 52cbf26b..232a0333 100644
--- a/media/gpu/test/video_decode_accelerator_tests.cc
+++ b/media/gpu/test/video_decode_accelerator_tests.cc
@@ -5,10 +5,12 @@
 #include <limits>
 
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/files/file_util.h"
 #include "base/functional/callback_helpers.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/encryption_scheme.h"
@@ -183,6 +185,16 @@
 
     config.implementation = g_env->GetDecoderImplementation();
     config.linear_output = g_env->ShouldOutputLinearBuffers();
+#if BUILDFLAG(USE_VAAPI)
+    // VP9 verification "frm_resize" and "sub8x8_sf" vectors utilize
+    // keyframeless resolution changes, see:
+    // https://www.webmproject.org/vp9/levels/#test-descriptions.
+    config.ignore_resolution_changes_to_smaller_vp9 =
+        base::Contains(base::ToLowerASCII(g_env->Video()->FilePath().value()),
+                       "frm_resize") ||
+        base::Contains(base::ToLowerASCII(g_env->Video()->FilePath().value()),
+                       "sub8x8_sf");
+#endif
 
     auto video_player = DecoderListener::Create(
         config, std::move(frame_renderer), std::move(frame_processors));
diff --git a/media/gpu/test/video_player/decoder_wrapper.cc b/media/gpu/test/video_player/decoder_wrapper.cc
index 3ac61a0..3d0403ee 100644
--- a/media/gpu/test/video_player/decoder_wrapper.cc
+++ b/media/gpu/test/video_player/decoder_wrapper.cc
@@ -162,14 +162,10 @@
   switch (decoder_wrapper_config_.implementation) {
     case DecoderImplementation::kVD:
 #if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
-      decoder_ = VideoDecoderPipeline::Create(
-          gpu::GpuDriverBugWorkarounds(),
+      decoder_ = VideoDecoderPipeline::CreateForTesting(
           base::SingleThreadTaskRunner::GetCurrentDefault(),
-          std::make_unique<PlatformVideoFramePool>(),
-          /*frame_converter=*/nullptr,
-          VideoDecoderPipeline::DefaultPreferredRenderableFourccs(),
           std::make_unique<NullMediaLog>(),
-          /*oop_video_decoder=*/{});
+          decoder_wrapper_config_.ignore_resolution_changes_to_smaller_vp9);
 #endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
       break;
     case DecoderImplementation::kVDA:
diff --git a/media/gpu/test/video_player/decoder_wrapper.h b/media/gpu/test/video_player/decoder_wrapper.h
index 37368eb..8ee2324 100644
--- a/media/gpu/test/video_player/decoder_wrapper.h
+++ b/media/gpu/test/video_player/decoder_wrapper.h
@@ -45,6 +45,8 @@
   size_t max_outstanding_decode_requests = 1;
   DecoderImplementation implementation = DecoderImplementation::kVDA;
   bool linear_output = false;
+  // See VP9Decoder for information on this.
+  bool ignore_resolution_changes_to_smaller_vp9 = false;
 };
 
 // This class wraps the VideoDecoder implementation and associated
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc
index 097c4784..47e5262 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.cc
+++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -608,6 +608,11 @@
   output_cb_.Run(std::move(video_frame));
 }
 
+void VaapiVideoDecoder::
+    set_ignore_resolution_changes_to_smaller_vp9_for_testing(bool value) {
+  ignore_resolution_changes_to_smaller_for_testing_ = value;
+}
+
 void VaapiVideoDecoder::ApplyResolutionChange() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(state_ == State::kChangingResolution ||
@@ -1139,6 +1144,12 @@
 
     decoder_ = std::make_unique<VP9Decoder>(std::move(accelerator), profile_,
                                             color_space_);
+
+    if (ignore_resolution_changes_to_smaller_for_testing_) {
+      static_cast<VP9Decoder*>(decoder_.get())
+          ->set_ignore_resolution_changes_to_smaller_for_testing(  // IN-TEST
+              true);
+    }
   }
 #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
   else if (profile_ >= HEVCPROFILE_MIN && profile_ <= HEVCPROFILE_MAX) {
diff --git a/media/gpu/vaapi/vaapi_video_decoder.h b/media/gpu/vaapi/vaapi_video_decoder.h
index 1bf7c9a..5084ad3 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.h
+++ b/media/gpu/vaapi/vaapi_video_decoder.h
@@ -85,6 +85,9 @@
                     const gfx::Rect& visible_rect,
                     const VideoColorSpace& color_space) override;
 
+  // Must be called before Initialize().
+  void set_ignore_resolution_changes_to_smaller_vp9_for_testing(bool value);
+
  private:
   // Decode task holding single decode request.
   struct DecodeTask {
@@ -276,6 +279,9 @@
   // DecoderBuffers we receive have been transcrypted and need special handling.
   bool transcryption_ = false;
 
+  // See VP9Decoder for information on this.
+  bool ignore_resolution_changes_to_smaller_for_testing_ = false;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtr<VaapiVideoDecoder> weak_this_;
diff --git a/media/gpu/vp9_decoder.cc b/media/gpu/vp9_decoder.cc
index 7d9fcbb..1e5bb2b3 100644
--- a/media/gpu/vp9_decoder.cc
+++ b/media/gpu/vp9_decoder.cc
@@ -291,11 +291,20 @@
     }
 
     DCHECK(!new_pic_size.IsEmpty());
-    if (new_pic_size != pic_size_ || new_profile != profile_ ||
-        curr_frame_hdr_->bit_depth != bit_depth_) {
+
+    const bool is_pic_size_different = new_pic_size != pic_size_;
+    const bool is_pic_size_larger = new_pic_size.width() > pic_size_.width() ||
+                                    new_pic_size.height() > pic_size_.height();
+    const bool is_new_configuration_different_enough =
+        (ignore_resolution_changes_to_smaller_for_testing_
+             ? is_pic_size_larger
+             : is_pic_size_different) ||
+        new_profile != profile_ || curr_frame_hdr_->bit_depth != bit_depth_;
+
+    if (is_new_configuration_different_enough) {
       DVLOG(1) << "New profile: " << GetProfileName(new_profile)
-               << ", New resolution: " << new_pic_size.ToString()
-               << ", New bit depth: "
+               << ", new resolution: " << new_pic_size.ToString()
+               << ", new bit depth: "
                << base::strict_cast<int>(curr_frame_hdr_->bit_depth);
 
       if (!curr_frame_hdr_->IsKeyframe() &&
diff --git a/media/gpu/vp9_decoder.h b/media/gpu/vp9_decoder.h
index d0c76c08e..fc3c313a 100644
--- a/media/gpu/vp9_decoder.h
+++ b/media/gpu/vp9_decoder.h
@@ -140,6 +140,10 @@
   size_t GetRequiredNumOfPictures() const override;
   size_t GetNumReferenceFrames() const override;
 
+  void set_ignore_resolution_changes_to_smaller_for_testing(bool value) {
+    ignore_resolution_changes_to_smaller_for_testing_ = value;
+  }
+
  private:
   // Decode and possibly output |pic| (if the picture is to be shown).
   // Return kOk on success, kTryAgain if this should be attempted again on the
@@ -178,6 +182,13 @@
   // Color space provided by the container.
   const VideoColorSpace container_color_space_;
 
+  // For VP9 validation purposes, this class can be indicated that it's OK to
+  // keep the decoding reference frames etc when the resolution decreases
+  // without a keyframe; this is an arcane feature of VP9, and are rare in the
+  // wild, but part of VP9 verification sets (see[1] "frm_resize" and
+  // "sub8x8_sf"). [1] https://www.webmproject.org/vp9/levels/#test-descriptions
+  bool ignore_resolution_changes_to_smaller_for_testing_ = false;
+
   // Reference frames currently in use.
   Vp9ReferenceFrameVector ref_frames_;
 
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
index d541b17..838c32a3 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -1208,7 +1208,7 @@
       // we encode.
       LONGLONG sample_ts = 0;
       auto hr = input_sample_->GetSampleTime(&sample_ts);
-      DCHECK_EQ(hr, S_OK);
+      DCHECK_EQ(hr, S_OK) << PrintHr(hr);
       int64_t frame_ts = input.frame->timestamp().InMicroseconds() *
                          kOneMicrosecondInMFSampleTimeUnits;
       DCHECK_EQ(frame_ts, sample_ts)
@@ -1272,6 +1272,25 @@
     return MF_E_INVALID_STREAM_DATA;
   }
 
+  auto hr = input_sample_->SetSampleTime(frame->timestamp().InMicroseconds() *
+                                         kOneMicrosecondInMFSampleTimeUnits);
+  RETURN_ON_HR_FAILURE(hr, "SetSampleTime() failed", hr);
+
+  UINT64 sample_duration = 0;
+  hr = MFFrameRateToAverageTimePerFrame(frame_rate_, 1, &sample_duration);
+  RETURN_ON_HR_FAILURE(hr, "Couldn't calculate sample duration", hr);
+
+  hr = input_sample_->SetSampleDuration(sample_duration);
+  RETURN_ON_HR_FAILURE(hr, "SetSampleDuration() failed", hr);
+
+  if (input.options.key_frame) {
+    VARIANT var;
+    var.vt = VT_UI4;
+    var.ulVal = 1;
+    hr = codec_api_->SetValue(&CODECAPI_AVEncVideoForceKeyFrame, &var);
+    RETURN_ON_HR_FAILURE(hr, "Set CODECAPI_AVEncVideoForceKeyFrame failed", hr);
+  }
+
   if (frame->storage_type() ==
       VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER) {
     gfx::GpuMemoryBuffer* gmb = frame->GetGpuMemoryBuffer();
@@ -1305,25 +1324,6 @@
     }
   }
 
-  auto hr = input_sample_->SetSampleTime(frame->timestamp().InMicroseconds() *
-                                         kOneMicrosecondInMFSampleTimeUnits);
-  RETURN_ON_HR_FAILURE(hr, "SetSampleTime() failed", hr);
-
-  UINT64 sample_duration = 0;
-  hr = MFFrameRateToAverageTimePerFrame(frame_rate_, 1, &sample_duration);
-  RETURN_ON_HR_FAILURE(hr, "Couldn't calculate sample duration", hr);
-
-  hr = input_sample_->SetSampleDuration(sample_duration);
-  RETURN_ON_HR_FAILURE(hr, "SetSampleDuration() failed", hr);
-
-  if (input.options.key_frame) {
-    VARIANT var;
-    var.vt = VT_UI4;
-    var.ulVal = 1;
-    hr = codec_api_->SetValue(&CODECAPI_AVEncVideoForceKeyFrame, &var);
-    RETURN_ON_HR_FAILURE(hr, "Set CODECAPI_AVEncVideoForceKeyFrame failed", hr);
-  }
-
   const auto kTargetPixelFormat = PIXEL_FORMAT_NV12;
   Microsoft::WRL::ComPtr<IMFMediaBuffer> input_buffer;
   hr = input_sample_->GetBufferByIndex(0, &input_buffer);
@@ -1657,32 +1657,43 @@
         base::Microseconds(sample_time / kOneMicrosecondInMFSampleTimeUnits);
   }
 
-  // For HMFT that continuously reports valid QP, update encoder info so that
-  // WebRTC will not use bandwidth quality scaler for resolution adaptation.
-  uint64_t frame_qp = 0xfffful;
+  // If `frame_qp` is set here, it will be plumbed down to WebRTC.
+  // If not set, the QP may be parsed by WebRTC from the bitstream but only if
+  // the QP is trusted (`encoder_info_.reports_average_qp` is true, which it is
+  // by default).
+  absl::optional<int32_t> frame_qp;
   bool should_notify_encoder_info_change = false;
-  hr = output_data_buffer.pSample->GetUINT64(MFSampleExtension_VideoEncodeQP,
-                                             &frame_qp);
-  if (vendor_ == DriverVendor::kIntel) {
-    if (codec_ == VideoCodec::kH264) {
-      if ((FAILED(hr) || !IsValidQp(codec_, frame_qp)) &&
-          encoder_info_.reports_average_qp) {
-        should_notify_encoder_info_change = true;
-        encoder_info_.reports_average_qp = false;
+  // In the case of VP9, `frame_qp_from_sample` is always 0 here
+  // (https://crbug.com/1434633) so we prefer WebRTC to parse the bitstream for
+  // us by leaving `frame_qp` unset.
+  if (codec_ != VideoCodec::kVP9) {
+    // For HMFT that continuously reports valid QP, update encoder info so that
+    // WebRTC will not use bandwidth quality scaler for resolution adaptation.
+    uint64_t frame_qp_from_sample = 0xfffful;
+    hr = output_data_buffer.pSample->GetUINT64(MFSampleExtension_VideoEncodeQP,
+                                               &frame_qp_from_sample);
+    if (vendor_ == DriverVendor::kIntel) {
+      if (codec_ == VideoCodec::kH264) {
+        if ((FAILED(hr) || !IsValidQp(codec_, frame_qp_from_sample)) &&
+            encoder_info_.reports_average_qp) {
+          should_notify_encoder_info_change = true;
+          encoder_info_.reports_average_qp = false;
+        }
+      } else if (codec_ == VideoCodec::kAV1) {
+        if (!rate_ctrl_) {
+          encoder_info_.reports_average_qp = false;
+        }
       }
-    } else if (codec_ == VideoCodec::kVP9 || codec_ == VideoCodec::kAV1) {
-      if (!rate_ctrl_)
-        encoder_info_.reports_average_qp = false;
+    }
+    // Bits 0-15: Default QP.
+    if (SUCCEEDED(hr)) {
+      frame_qp = frame_qp_from_sample & 0xfffful;
     }
   }
   if (!encoder_info_sent_ || should_notify_encoder_info_change) {
     client_->NotifyEncoderInfoChange(encoder_info_);
     encoder_info_sent_ = true;
   }
-  // Bits 0-15: Default QP.
-  if (SUCCEEDED(hr)) {
-    frame_qp = frame_qp & 0xfffful;
-  }
 
   const bool keyframe = MFGetAttributeUINT32(
       output_data_buffer.pSample, MFSampleExtension_CleanPoint, false);
@@ -1717,8 +1728,8 @@
     {
       MediaBufferScopedPointer scoped_buffer(output_buffer.Get());
       memcpy(encode_output->memory(), scoped_buffer.get(), size);
-      if (IsValidQp(codec_, frame_qp)) {
-        encode_output->SetQp(frame_qp);
+      if (frame_qp.has_value() && IsValidQp(codec_, *frame_qp)) {
+        encode_output->SetQp(*frame_qp);
       }
     }
     encoder_output_queue_.push_back(std::move(encode_output));
@@ -1745,8 +1756,8 @@
   output_data_buffer.pSample = nullptr;
 
   BitstreamBufferMetadata md(size, keyframe, timestamp);
-  if (IsValidQp(codec_, frame_qp)) {
-    md.qp = static_cast<int32_t>(frame_qp);
+  if (frame_qp.has_value() && IsValidQp(codec_, *frame_qp)) {
+    md.qp = *frame_qp;
   }
 
   if (temporal_scalable_coding()) {
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index add2a40..564d57dd 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -123,6 +123,7 @@
       "$mojom_generator_root/generators/mojom_webui_js_bridge_generator.py",
       "$mojom_generator_script",
       "//build/action_helpers.py",
+      "//build/gn_helpers.py",
       "//build/zip_helpers.py",
     ]
 
diff --git a/net/cert/internal/trust_store_nss.cc b/net/cert/internal/trust_store_nss.cc
index de8a1b2..c6cc4e45 100644
--- a/net/cert/internal/trust_store_nss.cc
+++ b/net/cert/internal/trust_store_nss.cc
@@ -85,6 +85,30 @@
   return r;
 }
 
+bool IsMozillaCaPolicyProvided(PK11SlotInfo* slot,
+                               CK_OBJECT_HANDLE cert_handle) {
+  return PK11_HasRootCerts(slot) &&
+         PK11_HasAttributeSet(slot, cert_handle, CKA_NSS_MOZILLA_CA_POLICY,
+                              /*haslock=*/PR_FALSE) == CK_TRUE;
+}
+
+bool IsCertOnlyInNSSRoots(CERTCertificate* cert) {
+  std::vector<std::pair<crypto::ScopedPK11Slot, CK_OBJECT_HANDLE>>
+      slots_and_handles_for_cert = GetAllSlotsAndHandlesForCert(cert);
+  for (const auto& [slot, handle] : slots_and_handles_for_cert) {
+    if (IsMozillaCaPolicyProvided(slot.get(), handle)) {
+      // Cert is an NSS root. Continue looking to see if it also is present in
+      // another slot.
+      continue;
+    }
+    // Found cert in a non-NSS roots slot.
+    return false;
+  }
+  // Cert was only found in NSS roots (or was not in any slots, but that
+  // shouldn't happen.)
+  return true;
+}
+
 }  // namespace
 
 TrustStoreNSS::ResultDebugData::ResultDebugData(
@@ -115,6 +139,16 @@
   return std::make_unique<ResultDebugData>(*this);
 }
 
+TrustStoreNSS::ListCertsResult::ListCertsResult(ScopedCERTCertificate cert,
+                                                CertificateTrust trust)
+    : cert(std::move(cert)), trust(trust) {}
+TrustStoreNSS::ListCertsResult::~ListCertsResult() = default;
+
+TrustStoreNSS::ListCertsResult::ListCertsResult(ListCertsResult&& other) =
+    default;
+TrustStoreNSS::ListCertsResult& TrustStoreNSS::ListCertsResult::operator=(
+    ListCertsResult&& other) = default;
+
 TrustStoreNSS::TrustStoreNSS(SystemTrustSetting system_trust_setting,
                              UserSlotTrustSetting user_slot_trust_setting)
     : ignore_system_trust_settings_(system_trust_setting == kIgnoreSystemTrust),
@@ -182,6 +216,46 @@
   }
 }
 
+std::vector<TrustStoreNSS::ListCertsResult>
+TrustStoreNSS::ListCertsIgnoringNSSRoots() {
+  std::vector<TrustStoreNSS::ListCertsResult> results;
+  crypto::ScopedCERTCertList cert_list;
+  if (absl::holds_alternative<crypto::ScopedPK11Slot>(
+          user_slot_trust_setting_)) {
+    if (absl::get<crypto::ScopedPK11Slot>(user_slot_trust_setting_) ==
+        nullptr) {
+      return results;
+    }
+    cert_list.reset(PK11_ListCertsInSlot(
+        absl::get<crypto::ScopedPK11Slot>(user_slot_trust_setting_).get()));
+  } else {
+    cert_list.reset(PK11_ListCerts(PK11CertListUnique, nullptr));
+  }
+  // PK11_ListCerts[InSlot] can return nullptr, e.g. because the PKCS#11 token
+  // that was backing the specified slot is not available anymore.
+  // Treat it as no certificates being present on the slot.
+  if (!cert_list) {
+    LOG(WARNING) << (absl::holds_alternative<crypto::ScopedPK11Slot>(
+                         user_slot_trust_setting_)
+                         ? "PK11_ListCertsInSlot"
+                         : "PK11_ListCerts")
+                 << " returned null";
+    return results;
+  }
+
+  CERTCertListNode* node;
+  for (node = CERT_LIST_HEAD(cert_list); !CERT_LIST_END(node, cert_list);
+       node = CERT_LIST_NEXT(node)) {
+    if (IsCertOnlyInNSSRoots(node->cert)) {
+      continue;
+    }
+    results.emplace_back(x509_util::DupCERTCertificate(node->cert),
+                         GetTrustIgnoringSystemTrust(node->cert, nullptr));
+  }
+
+  return results;
+}
+
 // TODO(https://crbug.com/1340420): add histograms? (how often hits fast vs
 // medium vs slow path, timing of fast/medium/slow path/all, etc?)
 
@@ -232,10 +306,16 @@
     return CertificateTrust::ForUnspecified();
   }
 
+  return GetTrustIgnoringSystemTrust(nss_cert.get(), debug_data);
+}
+
+CertificateTrust TrustStoreNSS::GetTrustIgnoringSystemTrust(
+    CERTCertificate* nss_cert,
+    base::SupportsUserData* debug_data) const {
   // See if NSS has any trust settings for the certificate at all. If not,
   // there is no point in doing further work.
   CERTCertTrust nss_cert_trust;
-  if (CERT_GetCertTrust(nss_cert.get(), &nss_cert_trust) != SECSuccess) {
+  if (CERT_GetCertTrust(nss_cert, &nss_cert_trust) != SECSuccess) {
     DVLOG(1) << "skipped cert that has no trust settings";
     return CertificateTrust::ForUnspecified();
   }
@@ -246,7 +326,7 @@
   // we care about.
 
   std::vector<std::pair<crypto::ScopedPK11Slot, CK_OBJECT_HANDLE>>
-      slots_and_handles_for_cert = GetAllSlotsAndHandlesForCert(nss_cert.get());
+      slots_and_handles_for_cert = GetAllSlotsAndHandlesForCert(nss_cert);
 
   // Generally this shouldn't happen, though it is possible (ex, a builtin
   // distrust record with no matching cert in the builtin trust store could
@@ -274,9 +354,7 @@
                << ", it's not user_slot_trust_setting_";
       continue;
     }
-    if (PK11_HasRootCerts(slot) &&
-        PK11_HasAttributeSet(slot, handle, CKA_NSS_MOZILLA_CA_POLICY,
-                             PR_FALSE) == CK_TRUE) {
+    if (IsMozillaCaPolicyProvided(slot, handle)) {
       DVLOG(1) << "skipping slot " << PK11_GetSlotName(slot)
                << ", this is mozilla ca policy provided";
       continue;
@@ -306,7 +384,8 @@
   // clear the cache. (There are multiple approaches possible, could cache the
   // hash->trust mappings on a per-slot basis, or just cache the end result for
   // each cert, etc.)
-  base::SHA1Digest cert_sha1 = base::SHA1HashSpan(cert->der_cert().AsSpan());
+  base::SHA1Digest cert_sha1 = base::SHA1HashSpan(
+      base::make_span(nss_cert->derCert.data, nss_cert->derCert.len));
 
   // Check the slots in trustOrder ordering. Lower trustOrder values are higher
   // priority, so we can return as soon as we find a matching trust object.
diff --git a/net/cert/internal/trust_store_nss.h b/net/cert/internal/trust_store_nss.h
index 082b94a..0582d8a 100644
--- a/net/cert/internal/trust_store_nss.h
+++ b/net/cert/internal/trust_store_nss.h
@@ -11,6 +11,7 @@
 #include "crypto/scoped_nss_types.h"
 #include "net/base/net_export.h"
 #include "net/cert/pki/trust_store.h"
+#include "net/cert/scoped_nss_types.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
 
 namespace net {
@@ -85,6 +86,17 @@
   CertificateTrust GetTrust(const ParsedCertificate* cert,
                             base::SupportsUserData* debug_data) override;
 
+  struct ListCertsResult {
+    ListCertsResult(ScopedCERTCertificate cert, CertificateTrust trust);
+    ~ListCertsResult();
+    ListCertsResult(ListCertsResult&& other);
+    ListCertsResult& operator=(ListCertsResult&& other);
+
+    ScopedCERTCertificate cert;
+    CertificateTrust trust;
+  };
+  std::vector<ListCertsResult> ListCertsIgnoringNSSRoots();
+
  private:
   bool IsCertAllowedForTrust(CERTCertificate* cert) const;
   CertificateTrust GetTrustForNSSTrust(const CERTCertTrust& trust) const;
@@ -92,6 +104,11 @@
   CertificateTrust GetTrustIgnoringSystemTrust(
       const ParsedCertificate* cert,
       base::SupportsUserData* debug_data) const;
+
+  CertificateTrust GetTrustIgnoringSystemTrust(
+      CERTCertificate* nss_cert,
+      base::SupportsUserData* debug_data) const;
+
   CertificateTrust GetTrustWithSystemTrust(
       const ParsedCertificate* cert,
       base::SupportsUserData* debug_data) const;
diff --git a/net/cert/nss_cert_database.cc b/net/cert/nss_cert_database.cc
index 91cdb07c..26a0bc8 100644
--- a/net/cert/nss_cert_database.cc
+++ b/net/cert/nss_cert_database.cc
@@ -6,6 +6,7 @@
 
 #include <cert.h>
 #include <certdb.h>
+#include <certt.h>
 #include <dlfcn.h>
 #include <keyhi.h>
 #include <pk11pub.h>
@@ -27,6 +28,7 @@
 #include "crypto/scoped_nss_types.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_database.h"
+#include "net/cert/internal/trust_store_nss.h"
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util_nss.h"
 #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
@@ -69,6 +71,26 @@
   raw_ptr<CertDatabase> cert_db_;
 };
 
+// TODO(https://crbug.com/1412591): once the other IsUntrusted impl is deleted,
+// rename this.
+bool IsUntrustedUsingTrustStore(const CERTCertificate* cert,
+                                CertificateTrust trust) {
+  if (trust.IsDistrusted()) {
+    return true;
+  }
+
+  // Self-signed certificates that don't have any trust bits set are untrusted.
+  // Other certificates that don't have any trust bits set may still be trusted
+  // if they chain up to a trust anchor.
+  // TODO(mattm): this is weird, but just match the behavior of the existing
+  // IsUntrusted function for now.
+  if (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject) == SECEqual) {
+    return !trust.IsTrustAnchor();
+  }
+
+  return false;
+}
+
 }  // namespace
 
 NSSCertDatabase::CertInfo::CertInfo() = default;
@@ -124,13 +146,14 @@
       std::move(callback));
 }
 
-void NSSCertDatabase::ListCertsInfo(ListCertsInfoCallback callback) {
+void NSSCertDatabase::ListCertsInfo(ListCertsInfoCallback callback,
+                                    NSSRootsHandling nss_roots_handling) {
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
       base::BindOnce(&NSSCertDatabase::ListCertsInfoImpl,
                      /*slot=*/nullptr,
-                     /*add_certs_info=*/true),
+                     /*add_certs_info=*/true, nss_roots_handling),
       std::move(callback));
 }
 
@@ -485,8 +508,8 @@
 // static
 ScopedCERTCertificateList NSSCertDatabase::ListCertsImpl(
     crypto::ScopedPK11Slot slot) {
-  CertInfoList certs_info =
-      ListCertsInfoImpl(std::move(slot), /*add_certs_info=*/false);
+  CertInfoList certs_info = ListCertsInfoImpl(
+      std::move(slot), /*add_certs_info=*/false, NSSRootsHandling::kInclude);
 
   return ExtractCertificates(std::move(certs_info));
 }
@@ -494,7 +517,8 @@
 // static
 NSSCertDatabase::CertInfoList NSSCertDatabase::ListCertsInfoImpl(
     crypto::ScopedPK11Slot slot,
-    bool add_certs_info) {
+    bool add_certs_info,
+    NSSRootsHandling nss_roots_handling) {
   // This method may acquire the NSS lock or reenter this code via extension
   // hooks (such as smart card UI). To ensure threads are not starved or
   // deadlocked, the base::ScopedBlockingCall below increments the thread pool
@@ -502,37 +526,67 @@
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
 
-  CertInfoList certs_info;
-  crypto::ScopedCERTCertList cert_list = nullptr;
-  if (slot)
-    cert_list.reset(PK11_ListCertsInSlot(slot.get()));
-  else
-    cert_list.reset(PK11_ListCerts(PK11CertListUnique, nullptr));
-  // PK11_ListCerts[InSlot] can return nullptr, e.g. because the PKCS#11 token
-  // that was backing the specified slot is not available anymore.
-  // Treat it as no certificates being present on the slot.
-  if (!cert_list) {
-    LOG(WARNING) << (slot ? "PK11_ListCertsInSlot" : "PK11_ListCerts")
-                 << " returned null";
+  if (nss_roots_handling == NSSRootsHandling::kExclude) {
+    // This assumes that using a new TrustStoreNSS instance on each
+    // ListCertsInfo call is not expensive. If that ever changes this might
+    // need to be rethought.
+    TrustStoreNSS trust_store_nss(
+        TrustStoreNSS::kIgnoreSystemTrust,
+        slot ? TrustStoreNSS::UserSlotTrustSetting(
+                   crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot.get())))
+             : TrustStoreNSS::UseTrustFromAllUserSlots());
+
+    std::vector<TrustStoreNSS::ListCertsResult> cert_list(
+        trust_store_nss.ListCertsIgnoringNSSRoots());
+
+    CertInfoList certs_info;
+    for (const auto& node : cert_list) {
+      CertInfo cert_info;
+      cert_info.cert = x509_util::DupCERTCertificate(node.cert.get());
+      if (add_certs_info) {
+        cert_info.untrusted =
+            IsUntrustedUsingTrustStore(cert_info.cert.get(), node.trust);
+        cert_info.web_trust_anchor = node.trust.IsTrustAnchor();
+        cert_info.on_read_only_slot = IsReadOnly(cert_info.cert.get());
+        cert_info.hardware_backed = IsHardwareBacked(cert_info.cert.get());
+      }
+      certs_info.push_back(std::move(cert_info));
+    }
     return certs_info;
-  }
-
-  CERTCertListNode* node;
-  for (node = CERT_LIST_HEAD(cert_list); !CERT_LIST_END(node, cert_list);
-       node = CERT_LIST_NEXT(node)) {
-    CertInfo cert_info;
-    cert_info.cert = x509_util::DupCERTCertificate(node->cert);
-
-    if (add_certs_info) {
-      cert_info.on_read_only_slot = IsReadOnly(cert_info.cert.get());
-      cert_info.untrusted = IsUntrusted(cert_info.cert.get());
-      cert_info.web_trust_anchor = IsWebTrustAnchor(cert_info.cert.get());
-      cert_info.hardware_backed = IsHardwareBacked(cert_info.cert.get());
+  } else {
+    CertInfoList certs_info;
+    crypto::ScopedCERTCertList cert_list = nullptr;
+    if (slot) {
+      cert_list.reset(PK11_ListCertsInSlot(slot.get()));
+    } else {
+      cert_list.reset(PK11_ListCerts(PK11CertListUnique, nullptr));
+    }
+    // PK11_ListCerts[InSlot] can return nullptr, e.g. because the PKCS#11 token
+    // that was backing the specified slot is not available anymore.
+    // Treat it as no certificates being present on the slot.
+    if (!cert_list) {
+      LOG(WARNING) << (slot ? "PK11_ListCertsInSlot" : "PK11_ListCerts")
+                   << " returned null";
+      return certs_info;
     }
 
-    certs_info.push_back(std::move(cert_info));
+    CERTCertListNode* node;
+    for (node = CERT_LIST_HEAD(cert_list); !CERT_LIST_END(node, cert_list);
+         node = CERT_LIST_NEXT(node)) {
+      CertInfo cert_info;
+      cert_info.cert = x509_util::DupCERTCertificate(node->cert);
+
+      if (add_certs_info) {
+        cert_info.on_read_only_slot = IsReadOnly(cert_info.cert.get());
+        cert_info.untrusted = IsUntrusted(cert_info.cert.get());
+        cert_info.web_trust_anchor = IsWebTrustAnchor(cert_info.cert.get());
+        cert_info.hardware_backed = IsHardwareBacked(cert_info.cert.get());
+      }
+
+      certs_info.push_back(std::move(cert_info));
+    }
+    return certs_info;
   }
-  return certs_info;
 }
 
 void NSSCertDatabase::NotifyCertRemovalAndCallBack(DeleteCertCallback callback,
diff --git a/net/cert/nss_cert_database.h b/net/cert/nss_cert_database.h
index 4884d9d..280ca59 100644
--- a/net/cert/nss_cert_database.h
+++ b/net/cert/nss_cert_database.h
@@ -154,10 +154,18 @@
   // asynchronously on a worker thread.
   virtual void ListCertsInSlot(ListCertsCallback callback, PK11SlotInfo* slot);
 
+  enum class NSSRootsHandling {
+    kInclude,
+    kExclude,
+  };
   // Asynchronously get a list of certificates along with additional
   // information. Note that the callback may be run even after the database is
   // deleted.
-  virtual void ListCertsInfo(ListCertsInfoCallback callback);
+  // The `nss_roots_handling` parameter controls whether to include or exclude
+  // NSS built-in roots from the returned list.
+  // TODO(https://crbug.com/1412591): remove the `nss_roots_handling` parameter.
+  virtual void ListCertsInfo(ListCertsInfoCallback callback,
+                             NSSRootsHandling nss_roots_handling);
 
 #if BUILDFLAG(IS_CHROMEOS)
   // Get the slot for system-wide key data. May be NULL if the system token was
@@ -260,6 +268,9 @@
   // IsUntrusted returns true if |cert| is specifically untrusted. These
   // certificates are stored in the database for the specific purpose of
   // rejecting them.
+  // TODO(mattm): that's not actually what this method does. (It also marks
+  // certs that are self-issued and don't have any specific trust as untrusted,
+  // which is wrong.)
   static bool IsUntrusted(const CERTCertificate* cert);
 
   // IsWebTrustAnchor returns true if |cert| is explicitly trusted for web
@@ -267,6 +278,8 @@
   static bool IsWebTrustAnchor(const CERTCertificate* cert);
 
   // Check whether cert is stored in a readonly slot.
+  // TODO(mattm): this is ill-defined if the cert exists on both readonly and
+  // non-readonly slots.
   static bool IsReadOnly(const CERTCertificate* cert);
 
   // Check whether cert is stored in a hardware slot.
@@ -303,8 +316,11 @@
   // default values.
   // Static so it may safely be used on the worker thread. If |slot| is nullptr,
   // obtains the certs of all slots, otherwise only of |slot|.
+  // The |nss_roots_handling| parameter controls whether to include or exclude
+  // NSS built-in roots from the resulting cert list.
   static CertInfoList ListCertsInfoImpl(crypto::ScopedPK11Slot slot,
-                                        bool add_certs_info);
+                                        bool add_certs_info,
+                                        NSSRootsHandling nss_roots_handling);
 
   // Broadcasts notifications to all registered observers.
   void NotifyObserversCertDBChanged();
diff --git a/net/cert/nss_cert_database_chromeos.cc b/net/cert/nss_cert_database_chromeos.cc
index 46e0df2..7c68834 100644
--- a/net/cert/nss_cert_database_chromeos.cc
+++ b/net/cert/nss_cert_database_chromeos.cc
@@ -49,13 +49,15 @@
       std::move(callback));
 }
 
-void NSSCertDatabaseChromeOS::ListCertsInfo(ListCertsInfoCallback callback) {
+void NSSCertDatabaseChromeOS::ListCertsInfo(
+    ListCertsInfoCallback callback,
+    NSSRootsHandling nss_roots_handling) {
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
       base::BindOnce(&NSSCertDatabaseChromeOS::ListCertsInfoImpl,
                      profile_filter_, /*slot=*/GetSystemSlot(),
-                     /*add_certs_info=*/true),
+                     /*add_certs_info=*/true, nss_roots_handling),
       std::move(callback));
 }
 
@@ -104,8 +106,9 @@
 // static
 ScopedCERTCertificateList NSSCertDatabaseChromeOS::ListCertsImpl(
     const NSSProfileFilterChromeOS& profile_filter) {
-  CertInfoList certs_info = ListCertsInfoImpl(
-      profile_filter, crypto::ScopedPK11Slot(), /*add_certs_info=*/false);
+  CertInfoList certs_info =
+      ListCertsInfoImpl(profile_filter, crypto::ScopedPK11Slot(),
+                        /*add_certs_info=*/false, NSSRootsHandling::kInclude);
 
   return ExtractCertificates(std::move(certs_info));
 }
@@ -114,7 +117,8 @@
 NSSCertDatabase::CertInfoList NSSCertDatabaseChromeOS::ListCertsInfoImpl(
     const NSSProfileFilterChromeOS& profile_filter,
     crypto::ScopedPK11Slot system_slot,
-    bool add_certs_info) {
+    bool add_certs_info,
+    NSSRootsHandling nss_roots_handling) {
   // This method may acquire the NSS lock or reenter this code via extension
   // hooks (such as smart card UI). To ensure threads are not starved or
   // deadlocked, the base::ScopedBlockingCall below increments the thread pool
@@ -123,7 +127,7 @@
                                                 base::BlockingType::MAY_BLOCK);
 
   CertInfoList certs_info(NSSCertDatabase::ListCertsInfoImpl(
-      crypto::ScopedPK11Slot(), add_certs_info));
+      crypto::ScopedPK11Slot(), add_certs_info, nss_roots_handling));
 
   // Filter certificate information according to user profile.
   base::EraseIf(certs_info, [&profile_filter](CertInfo& cert_info) {
diff --git a/net/cert/nss_cert_database_chromeos.h b/net/cert/nss_cert_database_chromeos.h
index f4acd4c..5377f8c 100644
--- a/net/cert/nss_cert_database_chromeos.h
+++ b/net/cert/nss_cert_database_chromeos.h
@@ -33,7 +33,8 @@
 
   // Uses NSSCertDatabase implementation and adds additional Chrome OS specific
   // certificate information.
-  void ListCertsInfo(ListCertsInfoCallback callback) override;
+  void ListCertsInfo(ListCertsInfoCallback callback,
+                     NSSRootsHandling nss_roots_handling) override;
 
   crypto::ScopedPK11Slot GetSystemSlot() const override;
 
@@ -63,7 +64,8 @@
   static CertInfoList ListCertsInfoImpl(
       const NSSProfileFilterChromeOS& profile_filter,
       crypto::ScopedPK11Slot system_slot,
-      bool add_certs_info);
+      bool add_certs_info,
+      NSSRootsHandling nss_roots_handling);
 
   NSSProfileFilterChromeOS profile_filter_;
   crypto::ScopedPK11Slot system_slot_;
diff --git a/net/cert/nss_cert_database_unittest.cc b/net/cert/nss_cert_database_unittest.cc
index bbb5299..f259e79 100644
--- a/net/cert/nss_cert_database_unittest.cc
+++ b/net/cert/nss_cert_database_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/test_future.h"
 #include "crypto/scoped_nss_types.h"
 #include "crypto/scoped_test_nss_db.h"
 #include "net/base/features.h"
@@ -49,12 +50,6 @@
 
 namespace {
 
-void SwapCertList(ScopedCERTCertificateList* destination,
-                  ScopedCERTCertificateList source) {
-  ASSERT_TRUE(destination);
-  destination->swap(source);
-}
-
 std::string GetSubjectCN(CERTCertificate* cert) {
   char* cn = CERT_GetCommonName(&cert->subject);
   std::string s = cn;
@@ -68,6 +63,17 @@
   return is_perm != PR_FALSE;
 }
 
+const NSSCertDatabase::CertInfo* FindCertInfoForCert(
+    const NSSCertDatabase::CertInfoList& cert_info_list,
+    CERTCertificate* target_cert) {
+  for (const auto& c : cert_info_list) {
+    if (x509_util::IsSameCertificate(c.cert.get(), target_cert)) {
+      return &c;
+    }
+  }
+  return nullptr;
+}
+
 }  // namespace
 
 class CertDatabaseNSSTest : public TestWithTaskEnvironment {
@@ -149,17 +155,166 @@
 TEST_F(CertDatabaseNSSTest, ListCerts) {
   // This test isn't terribly useful, though it might help with memory
   // leak tests.
-  ScopedCERTCertificateList certs;
-  cert_db_->ListCerts(base::BindOnce(&SwapCertList, base::Unretained(&certs)));
-  EXPECT_EQ(0U, certs.size());
+  base::test::TestFuture<ScopedCERTCertificateList> future;
+  cert_db_->ListCerts(future.GetCallback());
 
-  RunUntilIdle();
-
+  ScopedCERTCertificateList certs = future.Take();
   // The test DB is empty, but let's assume there will always be something in
   // the other slots.
   EXPECT_LT(0U, certs.size());
 }
 
+TEST_F(CertDatabaseNSSTest, ListCertsInfo) {
+  // Since ListCertsInfo queries all the "permanent" certs NSS knows about,
+  // including NSS builtin trust anchors and any locally installed certs of the
+  // user running the test, it's hard to do really precise testing here. Try to
+  // do some general testing as well as testing that a cert added through
+  // ScopedTestNSSDB is handled properly.
+
+  // Load a test certificate
+  ScopedCERTCertificateList test_root_certs = CreateCERTCertificateListFromFile(
+      GetTestCertsDirectory(), "root_ca_cert.pem",
+      X509Certificate::FORMAT_AUTO);
+  ASSERT_EQ(1U, test_root_certs.size());
+  // Should be only a temp certificate at this point, and thus not be returned
+  // in the listed certs.
+  EXPECT_FALSE(GetCertIsPerm(test_root_certs[0].get()));
+
+  // Get lists of all certs both including and excluding NSS roots.
+  NSSCertDatabase::CertInfoList certs_including_nss;
+  NSSCertDatabase::CertInfoList certs_excluding_nss;
+  {
+    base::test::TestFuture<NSSCertDatabase::CertInfoList> future;
+    cert_db_->ListCertsInfo(future.GetCallback(),
+                            NSSCertDatabase::NSSRootsHandling::kInclude);
+    certs_including_nss = future.Take();
+  }
+  {
+    base::test::TestFuture<NSSCertDatabase::CertInfoList> future;
+    cert_db_->ListCertsInfo(future.GetCallback(),
+                            NSSCertDatabase::NSSRootsHandling::kExclude);
+    certs_excluding_nss = future.Take();
+  }
+
+  // The tests based on GetAnNssSslTrustedBuiltinRoot could be flaky in obscure
+  // local configurations (if the user running the test has manually imported
+  // the same certificate into their user NSS DB.) Oh well.
+  ScopedCERTCertificate nss_root = GetAnNssBuiltinSslTrustedRoot();
+  // (Also this will fail if we ever do the "don't load libnssckbi.so" thing.)
+  ASSERT_TRUE(nss_root);
+  {
+    const NSSCertDatabase::CertInfo* nss_root_info =
+        FindCertInfoForCert(certs_including_nss, nss_root.get());
+    ASSERT_TRUE(nss_root_info);
+    EXPECT_TRUE(nss_root_info->web_trust_anchor);
+    EXPECT_FALSE(nss_root_info->untrusted);
+    EXPECT_FALSE(nss_root_info->device_wide);
+    EXPECT_FALSE(nss_root_info->hardware_backed);
+    EXPECT_TRUE(nss_root_info->on_read_only_slot);
+  }
+  EXPECT_FALSE(FindCertInfoForCert(certs_excluding_nss, nss_root.get()));
+
+  // Test root cert should not be in the lists retrieved before it was imported.
+  EXPECT_FALSE(
+      FindCertInfoForCert(certs_including_nss, test_root_certs[0].get()));
+  EXPECT_FALSE(
+      FindCertInfoForCert(certs_excluding_nss, test_root_certs[0].get()));
+
+  // Import the NSS root into the test DB.
+  SECStatus srv =
+      PK11_ImportCert(test_nssdb_.slot(), nss_root.get(), CK_INVALID_HANDLE,
+                      net::x509_util::GetDefaultUniqueNickname(
+                          nss_root.get(), net::CA_CERT, test_nssdb_.slot())
+                          .c_str(),
+                      PR_FALSE /* includeTrust (unused) */);
+  ASSERT_EQ(SECSuccess, srv);
+
+  // Import test certificate to the test DB.
+  NSSCertDatabase::ImportCertFailureList failed;
+  EXPECT_TRUE(cert_db_->ImportCACerts(test_root_certs,
+                                      NSSCertDatabase::TRUSTED_SSL, &failed));
+  EXPECT_EQ(0U, failed.size());
+
+  // Get new lists of all certs both including and excluding NSS roots, which
+  // should now also include the test db certificates.
+  NSSCertDatabase::CertInfoList certs_including_nss_with_local;
+  NSSCertDatabase::CertInfoList certs_excluding_nss_with_local;
+  {
+    base::test::TestFuture<NSSCertDatabase::CertInfoList> future;
+    cert_db_->ListCertsInfo(future.GetCallback(),
+                            NSSCertDatabase::NSSRootsHandling::kInclude);
+    certs_including_nss_with_local = future.Take();
+  }
+  {
+    base::test::TestFuture<NSSCertDatabase::CertInfoList> future;
+    cert_db_->ListCertsInfo(future.GetCallback(),
+                            NSSCertDatabase::NSSRootsHandling::kExclude);
+    certs_excluding_nss_with_local = future.Take();
+  }
+
+  // After adding the certs to the test db, the number certs returned should be
+  // 1 more than before in kInclude and and 2 more in kExclude cases.
+  EXPECT_EQ(certs_including_nss_with_local.size(),
+            1 + certs_including_nss.size());
+  EXPECT_EQ(certs_excluding_nss_with_local.size(),
+            2 + certs_excluding_nss.size());
+
+  // Using kExclude should give a smaller number of results than kInclude.
+  // (Although this would be wrong if we ever do the "don't load libnssckbi.so"
+  // thing.)
+  EXPECT_LT(certs_excluding_nss_with_local.size(),
+            certs_including_nss_with_local.size());
+
+  // The NSS root that was imported to the test db should be in both lists now.
+  {
+    const NSSCertDatabase::CertInfo* nss_root_info =
+        FindCertInfoForCert(certs_including_nss_with_local, nss_root.get());
+    ASSERT_TRUE(nss_root_info);
+    EXPECT_TRUE(nss_root_info->web_trust_anchor);
+    EXPECT_FALSE(nss_root_info->untrusted);
+    EXPECT_FALSE(nss_root_info->device_wide);
+    EXPECT_FALSE(nss_root_info->hardware_backed);
+    // `on_read_only_slot` is not tested here as the way it is calculated could
+    // be potentially flaky if the cert exists on both a readonly and
+    // non-readonly slot.
+  }
+  {
+    const NSSCertDatabase::CertInfo* nss_root_info =
+        FindCertInfoForCert(certs_excluding_nss_with_local, nss_root.get());
+    ASSERT_TRUE(nss_root_info);
+    EXPECT_FALSE(nss_root_info->web_trust_anchor);
+    EXPECT_TRUE(nss_root_info->untrusted);
+    EXPECT_FALSE(nss_root_info->device_wide);
+    EXPECT_FALSE(nss_root_info->hardware_backed);
+    // `on_read_only_slot` is not tested here as the way it is calculated could
+    // be potentially flaky if the cert exists on both a readonly and
+    // non-readonly slot.
+  }
+
+  // Ensure the test root cert is present in the lists retrieved after it was
+  // imported, and that the info returned is as expected.
+  {
+    const NSSCertDatabase::CertInfo* test_cert_info = FindCertInfoForCert(
+        certs_including_nss_with_local, test_root_certs[0].get());
+    ASSERT_TRUE(test_cert_info);
+    EXPECT_TRUE(test_cert_info->web_trust_anchor);
+    EXPECT_FALSE(test_cert_info->untrusted);
+    EXPECT_FALSE(test_cert_info->device_wide);
+    EXPECT_FALSE(test_cert_info->hardware_backed);
+    EXPECT_FALSE(test_cert_info->on_read_only_slot);
+  }
+  {
+    const NSSCertDatabase::CertInfo* test_cert_info = FindCertInfoForCert(
+        certs_excluding_nss_with_local, test_root_certs[0].get());
+    ASSERT_TRUE(test_cert_info);
+    EXPECT_TRUE(test_cert_info->web_trust_anchor);
+    EXPECT_FALSE(test_cert_info->untrusted);
+    EXPECT_FALSE(test_cert_info->device_wide);
+    EXPECT_FALSE(test_cert_info->hardware_backed);
+    EXPECT_FALSE(test_cert_info->on_read_only_slot);
+  }
+}
+
 TEST_F(CertDatabaseNSSTest, ImportFromPKCS12WrongPassword) {
   std::string pkcs12_data = ReadTestFile("client.p12");
 
diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h
index 59f5bb0d..e264192 100644
--- a/net/spdy/spdy_http_stream.h
+++ b/net/spdy/spdy_http_stream.h
@@ -168,9 +168,7 @@
   // After InitializeStream() is called but before OnClose() is called,
   //   |*stream_| is guaranteed to be valid.
   // After OnClose() is called, stream_ == nullptr.
-  // This field is not a raw_ptr<> because it was filtered by the rewriter for:
-  // #addr-of
-  RAW_PTR_EXCLUSION SpdyStream* stream_ = nullptr;
+  raw_ptr<SpdyStream> stream_ = nullptr;
 
   // False before OnClose() is called, true after.
   bool stream_closed_ = false;
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 7180f157..80a9fee 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -1002,7 +1002,7 @@
 int SpdySession::GetPushedStream(const GURL& url,
                                  spdy::SpdyStreamId pushed_stream_id,
                                  RequestPriority priority,
-                                 SpdyStream** stream) {
+                                 raw_ptr<SpdyStream>* stream) {
   CHECK(!in_io_loop_);
   // |pushed_stream_id| must be valid.
   DCHECK_NE(pushed_stream_id, kNoPushedStreamFound);
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 92d23b9..4c7e538 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -397,7 +397,7 @@
   int GetPushedStream(const GURL& url,
                       spdy::SpdyStreamId pushed_stream_id,
                       RequestPriority priority,
-                      SpdyStream** spdy_stream);
+                      raw_ptr<SpdyStream>* spdy_stream);
 
   // Called when the pushed stream should be cancelled. If the pushed stream is
   // not claimed and active, sends RST to the server to cancel the stream.
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
index d3f05db2..1abf1f5d 100644
--- a/pdf/pdf_view_web_plugin.cc
+++ b/pdf/pdf_view_web_plugin.cc
@@ -17,7 +17,6 @@
 #include "base/check_op.h"
 #include "base/containers/fixed_flat_map.h"
 #include "base/containers/queue.h"
-#include "base/cxx17_backports.h"
 #include "base/debug/crash_logging.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
@@ -503,8 +502,8 @@
                          0.0f);
 
   gfx::PointF scaled_scroll_position(
-      base::clamp(scroll_position.x(), 0.0f, max_x),
-      base::clamp(scroll_position.y(), 0.0f, max_y));
+      std::clamp(scroll_position.x(), 0.0f, max_x),
+      std::clamp(scroll_position.y(), 0.0f, max_y));
   scaled_scroll_position.Scale(device_scale_);
 
   engine_->ScrolledToXPosition(scaled_scroll_position.x());
diff --git a/pdf/pdfium/pdfium_font_linux.cc b/pdf/pdfium/pdfium_font_linux.cc
index bdc890f..15bd6293 100644
--- a/pdf/pdfium/pdfium_font_linux.cc
+++ b/pdf/pdfium/pdfium_font_linux.cc
@@ -4,11 +4,11 @@
 
 #include "pdf/pdfium/pdfium_font_linux.h"
 
+#include <algorithm>
 #include <memory>
 #include <string>
 
 #include "base/check_op.h"
-#include "base/cxx17_backports.h"
 #include "base/files/file.h"
 #include "base/i18n/encoding_detection.h"
 #include "base/i18n/icu_string_conversions.h"
@@ -115,7 +115,7 @@
   static_assert(blink::WebFontDescription::kWeight900 == 8, "Blink Weight max");
   constexpr int kMinimumWeight = 100;
   constexpr int kMaximumWeight = 900;
-  int normalized_weight = base::clamp(weight, kMinimumWeight, kMaximumWeight);
+  int normalized_weight = std::clamp(weight, kMinimumWeight, kMaximumWeight);
   normalized_weight = (normalized_weight / 100) - 1;
   return static_cast<blink::WebFontDescription::Weight>(normalized_weight);
 }
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc
index 99fe608..190366f 100644
--- a/pdf/pdfium/pdfium_page.cc
+++ b/pdf/pdfium/pdfium_page.cc
@@ -12,7 +12,6 @@
 #include <utility>
 
 #include "base/check_op.h"
-#include "base/cxx17_backports.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/metrics/histogram_functions.h"
@@ -1040,7 +1039,7 @@
   // If `x` < 0, scroll to the left side of the page.
   // If `x` > page width, scroll to the right side of the page.
   return TransformPageToScreenX(
-      base::clamp(x, 0.0f, FPDF_GetPageWidthF(GetPage())));
+      std::clamp(x, 0.0f, FPDF_GetPageWidthF(GetPage())));
 }
 
 float PDFiumPage::PreProcessAndTransformInPageCoordY(float y) {
diff --git a/pdf/ui/thumbnail.cc b/pdf/ui/thumbnail.cc
index ceacb89..716f678 100644
--- a/pdf/ui/thumbnail.cc
+++ b/pdf/ui/thumbnail.cc
@@ -12,7 +12,6 @@
 
 #include "base/check.h"
 #include "base/check_op.h"
-#include "base/cxx17_backports.h"
 #include "base/numerics/checked_math.h"
 #include "base/values.h"
 #include "ui/gfx/geometry/size.h"
@@ -109,9 +108,9 @@
 }  // namespace
 
 Thumbnail::Thumbnail(const gfx::Size& page_size, float device_pixel_ratio)
-    : device_pixel_ratio_(base::clamp(device_pixel_ratio,
-                                      kMinDevicePixelRatio,
-                                      kMaxDevicePixelRatio)),
+    : device_pixel_ratio_(std::clamp(device_pixel_ratio,
+                                     kMinDevicePixelRatio,
+                                     kMaxDevicePixelRatio)),
       image_size_(CalculateBestFitSize(page_size, device_pixel_ratio_)),
       stride_(CalculateStride(image_size_.width())),
       image_data_(CalculateImageDataSize(stride(), image_size().height())) {
diff --git a/services/network/attribution/attribution_request_helper.cc b/services/network/attribution/attribution_request_helper.cc
index f0f850e..ebc362b 100644
--- a/services/network/attribution/attribution_request_helper.cc
+++ b/services/network/attribution/attribution_request_helper.cc
@@ -27,12 +27,12 @@
 #include "services/network/attribution/attribution_attestation_mediator.h"
 #include "services/network/attribution/attribution_attestation_mediator_metrics_recorder.h"
 #include "services/network/attribution/boringssl_attestation_cryptographer.h"
+#include "services/network/public/cpp/attribution_utils.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/trigger_attestation.h"
 #include "services/network/public/cpp/trust_token_http_headers.h"
-#include "services/network/public/mojom/attribution.mojom.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/trust_tokens/trust_token_key_commitment_getter.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -70,15 +70,6 @@
   return is_trigger_ping;
 }
 
-base::StringPiece GetSupportHeader(mojom::AttributionOsSupport os_support) {
-  switch (os_support) {
-    case mojom::AttributionOsSupport::kDisabled:
-      return "web";
-    case mojom::AttributionOsSupport::kEnabled:
-      return "web, os";
-  }
-}
-
 }  // namespace
 
 struct AttributionRequestHelper::AttestationOperation {
@@ -294,7 +285,7 @@
       request.headers.HasHeader(kAttributionReportingEligibleHeader)) {
     url_request.SetExtraRequestHeaderByName(
         "Attribution-Reporting-Support",
-        GetSupportHeader(request.attribution_reporting_os_support),
+        GetAttributionSupportHeader(request.attribution_reporting_support),
         /*overwrite=*/true);
   }
 }
diff --git a/services/network/cors/cors_url_loader_shared_dictionary_unittest.cc b/services/network/cors/cors_url_loader_shared_dictionary_unittest.cc
index 527c67fb..d62ce11 100644
--- a/services/network/cors/cors_url_loader_shared_dictionary_unittest.cc
+++ b/services/network/cors/cors_url_loader_shared_dictionary_unittest.cc
@@ -74,7 +74,8 @@
   void NotifyLoaderClientOnReceiveResponseWithUseAsDictionaryHeader(
       std::vector<std::pair<std::string, std::string>> extra_headers = {}) {
     extra_headers.emplace_back(
-        network::shared_dictionary::kUseAsDictionaryHeaderName, "p=\"/path*\"");
+        network::shared_dictionary::kUseAsDictionaryHeaderName,
+        "match=\"/path*\"");
     NotifyLoaderClientOnReceiveResponse(extra_headers,
                                         std::move(consumer_handle_));
   }
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn
index e329f26..c1224fb 100644
--- a/services/network/public/cpp/BUILD.gn
+++ b/services/network/public/cpp/BUILD.gn
@@ -30,6 +30,8 @@
   output_name = "network_cpp"
 
   sources = [
+    "attribution_utils.cc",
+    "attribution_utils.h",
     "client_hints.cc",
     "client_hints.h",
     "constants.cc",
@@ -514,6 +516,7 @@
   testonly = true
 
   sources = [
+    "attribution_utils_unittest.cc",
     "client_hints_unittest.cc",
     "content_language_parser_unittest.cc",
     "content_security_policy/content_security_policy_unittest.cc",
diff --git a/services/network/public/cpp/OWNERS b/services/network/public/cpp/OWNERS
index c1e3e3e6..49bde052 100644
--- a/services/network/public/cpp/OWNERS
+++ b/services/network/public/cpp/OWNERS
@@ -17,3 +17,6 @@
 
 # Files related to Client Hints.
 per-file client_hints*=file://components/embedder_support/OWNERS
+
+# Files and features related to Attribution Reporting.
+per-file attribution*=file://content/browser/attribution_reporting/OWNERS
diff --git a/services/network/public/cpp/attribution_utils.cc b/services/network/public/cpp/attribution_utils.cc
new file mode 100644
index 0000000..a84894a
--- /dev/null
+++ b/services/network/public/cpp/attribution_utils.cc
@@ -0,0 +1,65 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/attribution_utils.h"
+
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+#include "services/network/public/mojom/attribution.mojom.h"
+
+namespace network {
+
+base::StringPiece GetAttributionSupportHeader(
+    mojom::AttributionSupport attribution_support) {
+  switch (attribution_support) {
+    case mojom::AttributionSupport::kWeb:
+      return "web";
+#if BUILDFLAG(IS_ANDROID)
+    case mojom::AttributionSupport::kWebAndOs:
+      return "os, web";
+    case mojom::AttributionSupport::kOs:
+      return "os";
+    case mojom::AttributionSupport::kNone:
+      return "";
+#endif
+  }
+}
+
+bool HasAttributionOsSupport(mojom::AttributionSupport attribution_support) {
+  switch (attribution_support) {
+#if BUILDFLAG(IS_ANDROID)
+    case mojom::AttributionSupport::kOs:
+    case mojom::AttributionSupport::kWebAndOs:
+      return true;
+#endif
+    case mojom::AttributionSupport::kWeb:
+#if BUILDFLAG(IS_ANDROID)
+    case mojom::AttributionSupport::kNone:
+#endif
+      return false;
+  }
+}
+
+#if BUILDFLAG(IS_ANDROID)
+
+bool HasAttributionWebSupport(mojom::AttributionSupport attribution_support) {
+  switch (attribution_support) {
+    case mojom::AttributionSupport::kWeb:
+    case mojom::AttributionSupport::kWebAndOs:
+      return true;
+    case mojom::AttributionSupport::kOs:
+    case mojom::AttributionSupport::kNone:
+      return false;
+  }
+}
+
+bool HasAttributionSupport(mojom::AttributionSupport attribution_support) {
+  return HasAttributionWebSupport(attribution_support) ||
+         HasAttributionOsSupport(attribution_support);
+}
+
+#endif
+
+}  // namespace network
diff --git a/services/network/public/cpp/attribution_utils.h b/services/network/public/cpp/attribution_utils.h
new file mode 100644
index 0000000..99e0b03b
--- /dev/null
+++ b/services/network/public/cpp/attribution_utils.h
@@ -0,0 +1,39 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_ATTRIBUTION_UTILS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_ATTRIBUTION_UTILS_H_
+
+#include "base/component_export.h"
+#include "base/strings/string_piece_forward.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+#include "services/network/public/mojom/attribution.mojom-forward.h"
+
+namespace network {
+
+// Returns the value to be set for `Attribution-Reporting-Support` request
+// header.
+COMPONENT_EXPORT(NETWORK_CPP)
+base::StringPiece GetAttributionSupportHeader(mojom::AttributionSupport);
+
+// Returns whether OS-level attribution is supported.
+COMPONENT_EXPORT(NETWORK_CPP)
+bool HasAttributionOsSupport(mojom::AttributionSupport);
+
+#if BUILDFLAG(IS_ANDROID)
+
+// Returns whether web attribution is supported.
+COMPONENT_EXPORT(NETWORK_CPP)
+bool HasAttributionWebSupport(mojom::AttributionSupport);
+
+// Returns whether either web or OS-level attribution is supported.
+COMPONENT_EXPORT(NETWORK_CPP)
+bool HasAttributionSupport(mojom::AttributionSupport);
+
+#endif
+
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_PUBLIC_CPP_ATTRIBUTION_UTILS_H_
diff --git a/services/network/public/cpp/attribution_utils_unittest.cc b/services/network/public/cpp/attribution_utils_unittest.cc
new file mode 100644
index 0000000..a6a857c0
--- /dev/null
+++ b/services/network/public/cpp/attribution_utils_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/attribution_utils.h"
+
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+#include "services/network/public/mojom/attribution.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+namespace {
+
+TEST(AttributionSupportTest, GetAttributionSupportHeader) {
+  const struct {
+    mojom::AttributionSupport attribution_support;
+    const char* expected;
+  } kTestCases[] = {
+    {mojom::AttributionSupport::kWeb, "web"},
+#if BUILDFLAG(IS_ANDROID)
+    {mojom::AttributionSupport::kWebAndOs, "os, web"},
+    {mojom::AttributionSupport::kOs, "os"},
+    {mojom::AttributionSupport::kNone, ""},
+#endif
+  };
+
+  for (const auto& test_case : kTestCases) {
+    EXPECT_EQ(GetAttributionSupportHeader(test_case.attribution_support),
+              test_case.expected);
+  }
+}
+
+TEST(AttributionSupportTest, HasAttributionOsSupport) {
+  const struct {
+    mojom::AttributionSupport attribution_support;
+    bool expected;
+  } kTestCases[] = {
+    {mojom::AttributionSupport::kWeb, false},
+#if BUILDFLAG(IS_ANDROID)
+    {mojom::AttributionSupport::kWebAndOs, true},
+    {mojom::AttributionSupport::kOs, true},
+    {mojom::AttributionSupport::kNone, false},
+#endif
+  };
+
+  for (const auto& test_case : kTestCases) {
+    EXPECT_EQ(HasAttributionOsSupport(test_case.attribution_support),
+              test_case.expected);
+  }
+}
+
+#if BUILDFLAG(IS_ANDROID)
+
+TEST(AttributionSupportTest, HasAttributionWebSupport) {
+  const struct {
+    mojom::AttributionSupport attribution_support;
+    bool expected;
+  } kTestCases[] = {
+      {mojom::AttributionSupport::kWeb, true},
+      {mojom::AttributionSupport::kWebAndOs, true},
+      {mojom::AttributionSupport::kOs, false},
+      {mojom::AttributionSupport::kNone, false},
+  };
+
+  for (const auto& test_case : kTestCases) {
+    EXPECT_EQ(HasAttributionWebSupport(test_case.attribution_support),
+              test_case.expected);
+  }
+}
+
+TEST(AttributionSupportTest, HasAttributionSupport) {
+  const struct {
+    mojom::AttributionSupport attribution_support;
+    bool expected;
+  } kTestCases[] = {
+      {mojom::AttributionSupport::kWeb, true},
+      {mojom::AttributionSupport::kWebAndOs, true},
+      {mojom::AttributionSupport::kOs, true},
+      {mojom::AttributionSupport::kNone, false},
+  };
+
+  for (const auto& test_case : kTestCases) {
+    EXPECT_EQ(HasAttributionSupport(test_case.attribution_support),
+              test_case.expected);
+  }
+}
+
+#endif
+
+}  // namespace
+}  // namespace network
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h
index 1f790022..a7d49b5 100644
--- a/services/network/public/cpp/resource_request.h
+++ b/services/network/public/cpp/resource_request.h
@@ -193,8 +193,8 @@
   mojom::IPAddressSpace target_ip_address_space =
       mojom::IPAddressSpace::kUnknown;
   bool has_storage_access = false;
-  network::mojom::AttributionOsSupport attribution_reporting_os_support =
-      network::mojom::AttributionOsSupport::kDisabled;
+  network::mojom::AttributionSupport attribution_reporting_support =
+      network::mojom::AttributionSupport::kWeb;
 };
 
 // This does not accept |kDefault| referrer policy.
diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc
index a92b276..76eaeb3 100644
--- a/services/network/public/cpp/url_request_mojom_traits.cc
+++ b/services/network/public/cpp/url_request_mojom_traits.cc
@@ -223,8 +223,7 @@
   out->original_destination = data.original_destination();
   out->target_ip_address_space = data.target_ip_address_space();
   out->has_storage_access = data.has_storage_access();
-  out->attribution_reporting_os_support =
-      data.attribution_reporting_os_support();
+  out->attribution_reporting_support = data.attribution_reporting_support();
   return true;
 }
 
diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h
index 8844283..40f1cba3 100644
--- a/services/network/public/cpp/url_request_mojom_traits.h
+++ b/services/network/public/cpp/url_request_mojom_traits.h
@@ -375,9 +375,9 @@
     return request.has_storage_access;
   }
 
-  static network::mojom::AttributionOsSupport attribution_reporting_os_support(
+  static network::mojom::AttributionSupport attribution_reporting_support(
       const network::ResourceRequest& request) {
-    return request.attribution_reporting_os_support;
+    return request.attribution_reporting_support;
   }
 
   static bool Read(network::mojom::URLRequestDataView data,
diff --git a/services/network/public/mojom/attribution.mojom b/services/network/public/mojom/attribution.mojom
index 59cf280..170b5e7 100644
--- a/services/network/public/mojom/attribution.mojom
+++ b/services/network/public/mojom/attribution.mojom
@@ -14,9 +14,14 @@
   string aggregatable_report_id;
 };
 
-// Indicates whether OS-level attribution is enabled.
+// Indicates whether web or OS-level Attribution Reporting is supported.
 // See https://github.com/WICG/attribution-reporting-api/blob/main/app_to_web.md.
-enum AttributionOsSupport {
-  kDisabled,
-  kEnabled,
+enum AttributionSupport {
+  kWeb,
+  [EnableIf=is_android]
+  kWebAndOs,
+  [EnableIf=is_android]
+  kOs,
+  [EnableIf=is_android]
+  kNone,
 };
diff --git a/services/network/public/mojom/url_request.mojom b/services/network/public/mojom/url_request.mojom
index cd347f0..bc36871 100644
--- a/services/network/public/mojom/url_request.mojom
+++ b/services/network/public/mojom/url_request.mojom
@@ -495,8 +495,8 @@
   // ok.
   bool has_storage_access;
 
- // Indicates whether the OS-level attribution is enabled.
-  AttributionOsSupport attribution_reporting_os_support;
+ // Indicates whether web or OS-level Attribution Reporting is supported.
+  AttributionSupport attribution_reporting_support;
 };
 
 // URLRequestBody represents body (i.e. upload data) of a HTTP request.
diff --git a/services/network/shared_dictionary/shared_dictionary_constants.cc b/services/network/shared_dictionary/shared_dictionary_constants.cc
index 7221799..8321904 100644
--- a/services/network/shared_dictionary/shared_dictionary_constants.cc
+++ b/services/network/shared_dictionary/shared_dictionary_constants.cc
@@ -8,4 +8,8 @@
 
 const char kUseAsDictionaryHeaderName[] = "use-as-dictionary";
 
+const char kOptionNameMatch[] = "match";
+const char kOptionNameExpires[] = "expires";
+const char kOptionNameAlgorithms[] = "algorithms";
+
 }  // namespace network::shared_dictionary
diff --git a/services/network/shared_dictionary/shared_dictionary_constants.h b/services/network/shared_dictionary/shared_dictionary_constants.h
index 6b10990..6ca4e1e 100644
--- a/services/network/shared_dictionary/shared_dictionary_constants.h
+++ b/services/network/shared_dictionary/shared_dictionary_constants.h
@@ -19,6 +19,15 @@
 COMPONENT_EXPORT(NETWORK_SERVICE)
 extern const char kUseAsDictionaryHeaderName[];
 
+// The dictionary option name of "match".
+COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kOptionNameMatch[];
+
+// The dictionary option name of "expires".
+COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kOptionNameExpires[];
+
+// The dictionary option name of "algorithms".
+COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kOptionNameAlgorithms[];
+
 }  // namespace network::shared_dictionary
 
 #endif  // SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_CONSTANTS_H_
diff --git a/services/network/shared_dictionary/shared_dictionary_disk_cache_unittest.cc b/services/network/shared_dictionary/shared_dictionary_disk_cache_unittest.cc
index f9a9a94..5e54590 100644
--- a/services/network/shared_dictionary/shared_dictionary_disk_cache_unittest.cc
+++ b/services/network/shared_dictionary/shared_dictionary_disk_cache_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_file_util.h"
+#include "build/build_config.h"
 #include "net/base/io_buffer.h"
 #include "net/base/test_completion_callback.h"
 #include "net/disk_cache/disk_cache_test_util.h"
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc b/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc
index fc259c6..19219491 100644
--- a/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc
+++ b/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc
@@ -148,40 +148,40 @@
       // Invalid dictionary.
       {"()", false},
 
-      // No `p` value.
+      // No `match` value.
       {"dummy", false},
 
-      // Valid `p` value.
-      {"p=\"/test\"", true},
-      {"p=\"test\"", true},
+      // Valid `match` value.
+      {"match=\"/test\"", true},
+      {"match=\"test\"", true},
 
-      // List `p` value is not supported.
-      {"p=(\"test1\" \"test2\")", false},
-      // Token `p` value is not supported.
-      {"p=test", false},
+      // List `match` value is not supported.
+      {"match=(\"test1\" \"test2\")", false},
+      // Token `match` value is not supported.
+      {"match=test", false},
 
-      // Valid `e` value.
-      {"p=\"test\", e=1000", true},
-      // List `e` value is not supported.
-      {"p=\"test\", e=(1000 2000)", false},
-      // String `e` value is not supported.
-      {"p=\"test\", e=PI", false},
+      // Valid `expires` value.
+      {"match=\"test\", expires=1000", true},
+      // List `expires` value is not supported.
+      {"match=\"test\", expires=(1000 2000)", false},
+      // String `expires` value is not supported.
+      {"match=\"test\", expires=PI", false},
 
-      // Valid `h` value.
-      {"p=\"test\", h=sha-256", true},
-      {"p=\"test\", h=(sha-256)", true},
-      {"p=\"test\", h=(sha-256 sha-512)", true},
+      // Valid `algorithms` value.
+      {"match=\"test\", algorithms=sha-256", true},
+      {"match=\"test\", algorithms=(sha-256)", true},
+      {"match=\"test\", algorithms=(sha-256 sha-512)", true},
 
       // The sha-256 token must be lowercase.
       // TODO(crbug.com/1413922): Investigate the spec and decide whether to
       // support it or not.
-      {"p=\"test\", h=SHA-256", false},
+      {"match=\"test\", algorithms=SHA-256", false},
 
-      // Each item in `h` value must be a token.
-      {"p=\"test\", h=(\"sha-256\")", false},
+      // Each item in `algorithms` value must be a token.
+      {"match=\"test\", algorithms=(\"sha-256\")", false},
 
-      // Unsupported `h` value. We only support sha-256.
-      {"p=\"test\", h=(sha-512)", false},
+      // Unsupported `algorithms` value. We only support sha-256.
+      {"match=\"test\", algorithms=(sha-512)", false},
   };
   for (const auto& testcase : kTestCases) {
     SCOPED_TRACE(base::StringPrintf("header_string: %s",
@@ -210,7 +210,7 @@
   scoped_refptr<net::HttpResponseHeaders> headers =
       net::HttpResponseHeaders::TryToCreate(base::StrCat(
           {"HTTP/1.1 200 OK\n", shared_dictionary::kUseAsDictionaryHeaderName,
-           ":  p=\"/testfile*\"\n\n"}));
+           ": match=\"/testfile*\"\n\n"}));
   ASSERT_TRUE(headers);
 
   // Write the test data to the dictionary.
@@ -241,7 +241,7 @@
   scoped_refptr<net::HttpResponseHeaders> headers =
       net::HttpResponseHeaders::TryToCreate(base::StrCat(
           {"HTTP/1.1 200 OK\n", shared_dictionary::kUseAsDictionaryHeaderName,
-           ":  p=\"/testfile*\"\n\n"}));
+           ": match=\"/testfile*\"\n\n"}));
   ASSERT_TRUE(headers);
   base::Time now_time = base::Time::Now();
 
@@ -308,7 +308,7 @@
   scoped_refptr<net::HttpResponseHeaders> headers =
       net::HttpResponseHeaders::TryToCreate(base::StrCat(
           {"HTTP/1.1 200 OK\n", shared_dictionary::kUseAsDictionaryHeaderName,
-           ":  p=\"/testfile*\"\n\n"}));
+           ": match=\"/testfile*\"\n\n"}));
   ASSERT_TRUE(headers);
   base::Time now_time = base::Time::Now();
 
diff --git a/services/network/shared_dictionary/shared_dictionary_storage.cc b/services/network/shared_dictionary/shared_dictionary_storage.cc
index 2320271..fb2f4ad 100644
--- a/services/network/shared_dictionary/shared_dictionary_storage.cc
+++ b/services/network/shared_dictionary/shared_dictionary_storage.cc
@@ -52,19 +52,19 @@
   absl::optional<int64_t> e_value;
   absl::optional<std::vector<std::string>> h_value;
   for (const auto& entry : dictionary.value()) {
-    if (entry.first == "p") {
+    if (entry.first == shared_dictionary::kOptionNameMatch) {
       if ((entry.second.member.size() != 1u) ||
           !entry.second.member.front().item.is_string()) {
         return absl::nullopt;
       }
       p_value = entry.second.member.front().item.GetString();
-    } else if (entry.first == "e") {
+    } else if (entry.first == shared_dictionary::kOptionNameExpires) {
       if ((entry.second.member.size() != 1u) ||
           !entry.second.member.front().item.is_integer()) {
         return absl::nullopt;
       }
       e_value = entry.second.member.front().item.GetInteger();
-    } else if (entry.first == "h") {
+    } else if (entry.first == shared_dictionary::kOptionNameAlgorithms) {
       std::vector<std::string> tmp_vec;
       for (const auto& h_item : entry.second.member) {
         if (!h_item.item.is_token()) {
diff --git a/services/network/shared_dictionary/shared_dictionary_writer_on_disk_unittest.cc b/services/network/shared_dictionary/shared_dictionary_writer_on_disk_unittest.cc
index 9bec699..b41d46a 100644
--- a/services/network/shared_dictionary/shared_dictionary_writer_on_disk_unittest.cc
+++ b/services/network/shared_dictionary/shared_dictionary_writer_on_disk_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/bind.h"
 #include "base/test/test_file_util.h"
+#include "build/build_config.h"
 #include "crypto/secure_hash.h"
 #include "net/base/hash_value.h"
 #include "net/base/io_buffer.h"
diff --git a/services/video_capture/video_capture_service_impl.cc b/services/video_capture/video_capture_service_impl.cc
index 9ba6f293..bf03041d 100644
--- a/services/video_capture/video_capture_service_impl.cc
+++ b/services/video_capture/video_capture_service_impl.cc
@@ -43,6 +43,11 @@
 #include "services/video_capture/lacros/device_factory_adapter_lacros.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
+#if BUILDFLAG(IS_LINUX)
+#include "media/capture/capture_switches.h"
+#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
+#endif  // BUILDFLAG(IS_LINUX)
+
 namespace video_capture {
 
 // Intended usage of this class is to instantiate on any sequence, and then
@@ -104,6 +109,88 @@
       this};
 };
 
+#if BUILDFLAG(IS_LINUX)
+// Intended usage of this class is to create viz::Gpu in utility process and
+// connect to viz::GpuClient of browser process, which will call to Gpu service.
+// Also, this class holds the viz::ContextProvider to listen and monitor Gpu
+// context lost event. The viz::Gpu and viz::ContextProvider need be created in
+// the main thread of utility process. The |main_task_runner_| is initialized as
+// the default single thread task runner of main thread. The
+// viz::ContextProvider will call BindToCurrentSequence on |main_task_runner_|
+// sequence of main thread. Then, the gpu context lost event will be called in
+// the |main_task_runner_| sequence, which will be notified to the
+// media::VideoCaptureGpuMemoryBufferManager.
+class VideoCaptureServiceImpl::VizGpuContextProvider
+    : public viz::ContextLostObserver {
+ public:
+  VizGpuContextProvider(std::unique_ptr<viz::Gpu> viz_gpu)
+      : main_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
+        viz_gpu_(std::move(viz_gpu)) {
+    StartContextProviderIfNeeded();
+  }
+  ~VizGpuContextProvider() override {
+    // Ensure destroy context provider and not receive callbacks before clear up
+    // |viz_gpu_|
+    if (context_provider_) {
+      context_provider_.reset();
+    }
+  }
+
+  // viz::ContextLostObserver implementation.
+  void OnContextLost() override {
+    context_provider_->RemoveObserver(this);
+    context_provider_.reset();
+
+    StartContextProviderIfNeeded();
+  }
+
+ private:
+  void StartContextProviderIfNeeded() {
+    DCHECK_EQ(context_provider_, nullptr);
+    DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+    if (!viz_gpu_) {
+      return;
+    }
+
+    if (!viz_gpu_->GetGpuChannel() || viz_gpu_->GetGpuChannel()->IsLost()) {
+      scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
+          viz_gpu_->EstablishGpuChannelSync();
+    }
+
+    scoped_refptr<viz::ContextProvider> context_provider =
+        base::MakeRefCounted<viz::ContextProviderCommandBuffer>(
+            viz_gpu_->GetGpuChannel(), viz_gpu_->GetGpuMemoryBufferManager(),
+            0 /* stream ID */, gpu::SchedulingPriority::kNormal,
+            gpu::kNullSurfaceHandle,
+            GURL(std::string("chrome://gpu/VideoCapture")),
+            false /* automatic flushes */, false /* support locking */,
+            false /* support grcontext */,
+            gpu::SharedMemoryLimits::ForMailboxContext(),
+            gpu::ContextCreationAttribs(),
+            viz::command_buffer_metrics::ContextType::VIDEO_CAPTURE);
+
+    const gpu::ContextResult context_result =
+        context_provider->BindToCurrentSequence();
+    if (context_result != gpu::ContextResult::kSuccess) {
+      LOG(ERROR) << "Bind context provider failed.";
+      return;
+    }
+
+    context_provider->AddObserver(this);
+    context_provider_ = std::move(context_provider);
+  }
+
+  // Task runner for operating |viz_gpu_| and
+  // |context_provider_| on. This must be the main service thread as the
+  // |viz_gpu_| required.
+  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+  std::unique_ptr<viz::Gpu> viz_gpu_;
+  scoped_refptr<viz::ContextProvider> context_provider_;
+  base::WeakPtrFactory<VizGpuContextProvider> weak_ptr_factory_{this};
+};
+#endif  // BUILDFLAG(IS_LINUX)
+
 VideoCaptureServiceImpl::VideoCaptureServiceImpl(
     mojo::PendingReceiver<mojom::VideoCaptureService> receiver,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
@@ -163,6 +250,13 @@
 void VideoCaptureServiceImpl::LazyInitializeGpuDependenciesContext() {
   if (!gpu_dependencies_context_)
     gpu_dependencies_context_ = std::make_unique<GpuDependenciesContext>();
+
+#if BUILDFLAG(IS_LINUX)
+  if (!viz_gpu_context_provider_) {
+    viz_gpu_context_provider_ =
+        std::make_unique<VizGpuContextProvider>(std::move(viz_gpu_));
+  }
+#endif  // BUILDFLAG(IS_LINUX)
 }
 
 void VideoCaptureServiceImpl::LazyInitializeDeviceFactory() {
@@ -243,4 +337,10 @@
 }
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+void VideoCaptureServiceImpl::SetVizGpu(std::unique_ptr<viz::Gpu> viz_gpu) {
+  viz_gpu_ = std::move(viz_gpu);
+}
+#endif
+
 }  // namespace video_capture
diff --git a/services/video_capture/video_capture_service_impl.h b/services/video_capture/video_capture_service_impl.h
index 406edc5..9726d58 100644
--- a/services/video_capture/video_capture_service_impl.h
+++ b/services/video_capture/video_capture_service_impl.h
@@ -24,6 +24,10 @@
 #include "services/video_capture/ash/video_capture_device_factory_ash.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+#if BUILDFLAG(IS_LINUX)
+#include "services/viz/public/cpp/gpu/gpu.h"
+#endif  // BUILDFLAG(IS_LINUX)
+
 namespace video_capture {
 
 class VirtualDeviceEnabledDeviceFactory;
@@ -58,6 +62,9 @@
 #if BUILDFLAG(IS_WIN)
   void OnGpuInfoUpdate(const CHROME_LUID& luid) override;
 #endif
+#if BUILDFLAG(IS_LINUX)
+  void SetVizGpu(std::unique_ptr<viz::Gpu> viz_gpu);
+#endif  // BUILDFLAG(IS_LINUX)
  private:
   class GpuDependenciesContext;
 
@@ -80,6 +87,12 @@
       factory_receivers_ash_;
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+  class VizGpuContextProvider;
+  std::unique_ptr<VizGpuContextProvider> viz_gpu_context_provider_;
+  std::unique_ptr<viz::Gpu> viz_gpu_;
+#endif  // BUILDFLAG(IS_LINUX)
+
   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
 };
 
diff --git a/sql/meta_table.cc b/sql/meta_table.cc
index e86ff5b..7464b97 100644
--- a/sql/meta_table.cc
+++ b/sql/meta_table.cc
@@ -94,21 +94,24 @@
 }
 
 // static
-void MetaTable::RazeIfIncompatible(Database* db,
+bool MetaTable::RazeIfIncompatible(Database* db,
                                    int lowest_supported_version,
                                    int current_version) {
   DCHECK(db);
 
-  if (!DoesTableExist(db))
-    return;
+  if (!DoesTableExist(db)) {
+    return true;
+  }
 
   sql::Statement select;
-  if (!PrepareGetStatement(kVersionKey, *db, select))
-    return;
+  if (!PrepareGetStatement(kVersionKey, *db, select)) {
+    return false;
+  }
   int64_t on_disk_schema_version = select.ColumnInt64(0);
 
-  if (!PrepareGetStatement(kCompatibleVersionKey, *db, select))
-    return;
+  if (!PrepareGetStatement(kCompatibleVersionKey, *db, select)) {
+    return false;
+  }
   int64_t on_disk_compatible_version = select.ColumnInt(0);
 
   select.Clear();  // Clear potential automatic transaction for Raze().
@@ -116,9 +119,9 @@
   if ((lowest_supported_version != kNoLowestSupportedVersion &&
        lowest_supported_version > on_disk_schema_version) ||
       (current_version < on_disk_compatible_version)) {
-    db->Raze();
-    return;
+    return db->Raze();
   }
+  return true;
 }
 
 bool MetaTable::Init(Database* db, int version, int compatible_version) {
@@ -144,7 +147,9 @@
 
     // Newly-created databases start out with mmap'ed I/O, but have no place to
     // store the setting.  Set here so that later opens don't need to validate.
-    SetMmapStatus(db_, kMmapSuccess);
+    if (!SetMmapStatus(db_, kMmapSuccess)) {
+      return false;
+    }
 
     // Note: there is no index over the meta table. We currently only have a
     // couple of keys, so it doesn't matter. If we start storing more stuff in
diff --git a/sql/meta_table.h b/sql/meta_table.h
index 51ccb5c3..f0cbb84 100644
--- a/sql/meta_table.h
+++ b/sql/meta_table.h
@@ -52,6 +52,9 @@
   // the latter, pass `kNoLowestSupportedVersion` for
   // `lowest_supported_version`.
   //
+  // Returns false if razing the database was necessary but failed or if
+  // determining the metadata version failed.
+  //
   // TODO(crbug.com/1228463): At this time the database is razed IFF meta exists
   // and contains a version row with the value not satisfying the constraints.
   // It may make sense to also raze if meta exists but has no version row, or if
@@ -60,7 +63,7 @@
   // TODO(crbug.com/1228463): Folding this into Init() would allow enforcing
   // the version constraint, but Init() is often called in a transaction.
   static constexpr int kNoLowestSupportedVersion = 0;
-  static void RazeIfIncompatible(Database* db,
+  static bool RazeIfIncompatible(Database* db,
                                  int lowest_supported_version,
                                  int current_version);
 
diff --git a/sql/statement.cc b/sql/statement.cc
index b35cdb63..90c39b52 100644
--- a/sql/statement.cc
+++ b/sql/statement.cc
@@ -578,6 +578,32 @@
   return true;
 }
 
+bool Statement::ColumnBlobAsString16(int column_index, std::u16string* result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(result);
+
+#if DCHECK_IS_ON()
+  DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
+  DCHECK(step_called_) << __func__ << " can only be used after Step()";
+#endif  // DCHECK_IS_ON()
+
+  if (!CheckValid()) {
+    return false;
+  }
+  DCHECK_GE(column_index, 0);
+  DCHECK_LT(column_index, sqlite3_data_count(ref_->stmt()))
+      << "Invalid column index";
+
+  const void* result_buffer = sqlite3_column_blob(ref_->stmt(), column_index);
+  int size = sqlite3_column_bytes(ref_->stmt(), column_index);
+  if (result_buffer && size > 0) {
+    result->assign(reinterpret_cast<const char16_t*>(result_buffer), size / 2);
+  } else {
+    result->clear();
+  }
+  return true;
+}
+
 bool Statement::ColumnBlobAsVector(int column_index,
                                    std::vector<char>* result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/sql/statement.h b/sql/statement.h
index a2e3f9b9..018c12a 100644
--- a/sql/statement.h
+++ b/sql/statement.h
@@ -132,6 +132,9 @@
   void BindDouble(int param_index, double val);
   void BindCString(int param_index, const char* val);
   void BindString(int param_index, base::StringPiece val);
+
+  // If you need to store (potentially invalid) UTF-16 strings losslessly,
+  // store them as BLOBs instead. `BindBlob()` has an overload for this purpose.
   void BindString16(int param_index, base::StringPiece16 value);
   void BindBlob(int param_index, base::span<const uint8_t> value);
 
@@ -140,6 +143,11 @@
     BindBlob(param_index, base::as_bytes(base::make_span(value)));
   }
 
+  // Overload that makes it easy to pass in std::u16string values.
+  void BindBlob(int param_index, base::span<const char16_t> value) {
+    BindBlob(param_index, base::as_bytes(base::make_span(value)));
+  }
+
   // Conforms with base::Time serialization recommendations.
   //
   // This is equivalent to the following snippets, which should be replaced.
@@ -183,6 +191,10 @@
   int64_t ColumnInt64(int column_index);
   double ColumnDouble(int column_index);
   std::string ColumnString(int column_index);
+
+  // If you need to store and retrieve (potentially invalid) UTF-16 strings
+  // losslessly, store them as BLOBs instead. They may be retrieved with
+  // `ColumnBlobAsString16()`.
   std::u16string ColumnString16(int column_index);
 
   // Conforms with base::Time serialization recommendations.
@@ -216,6 +228,7 @@
   base::span<const uint8_t> ColumnBlob(int column_index);
 
   bool ColumnBlobAsString(int column_index, std::string* result);
+  bool ColumnBlobAsString16(int column_index, std::u16string* result);
   bool ColumnBlobAsVector(int column_index, std::vector<char>* result);
   bool ColumnBlobAsVector(int column_index, std::vector<uint8_t>* result);
 
diff --git a/sql/statement_unittest.cc b/sql/statement_unittest.cc
index 8c346b8..093c4e6 100644
--- a/sql/statement_unittest.cc
+++ b/sql/statement_unittest.cc
@@ -258,6 +258,39 @@
   EXPECT_FALSE(select.Step());
 }
 
+TEST_F(StatementTest, BindBlob_String16Overload) {
+  // `id` makes SQLite's rowid mechanism explicit. We rely on it to retrieve
+  // the rows in the same order that they were inserted.
+  ASSERT_TRUE(db_.Execute(
+      "CREATE TABLE blobs(id INTEGER PRIMARY KEY NOT NULL, b BLOB NOT NULL)"));
+
+  const std::vector<std::u16string> values = {
+      std::u16string(), std::u16string(u"hello\n"), std::u16string(u"😀🍩🎉"),
+      std::u16string(u"\xd800\xdc00text"),  // surrogate pair with text
+      std::u16string(u"\xd8ff"),            // unpaired high surrogate
+      std::u16string(u"\xdddd"),            // unpaired low surrogate
+      std::u16string(u"\xdc00\xd800text"),  // lone low followed by lone high
+                                            // surrogate and text
+      std::u16string(1024, 0xdb23),         // long invalid UTF-16
+  };
+
+  Statement insert(db_.GetUniqueStatement("INSERT INTO blobs(b) VALUES(?)"));
+  for (const std::u16string& value : values) {
+    insert.BindBlob(0, value);
+    ASSERT_TRUE(insert.Run());
+    insert.Reset(/*clear_bound_vars=*/true);
+  }
+
+  Statement select(db_.GetUniqueStatement("SELECT b FROM blobs ORDER BY id"));
+  for (const std::u16string& value : values) {
+    ASSERT_TRUE(select.Step());
+    std::u16string column_value;
+    EXPECT_TRUE(select.ColumnBlobAsString16(0, &column_value));
+    EXPECT_EQ(value, column_value);
+  }
+  EXPECT_FALSE(select.Step());
+}
+
 TEST_F(StatementTest, BindString) {
   // `id` makes SQLite's rowid mechanism explicit. We rely on it to retrieve
   // the rows in the same order that they were inserted.
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 304d0fd..d665324 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -6716,7 +6716,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
+          "shards": 4
         },
         "test": "android_browsertests",
         "test_id_prefix": "ninja://chrome/test:android_browsertests/"
@@ -8006,7 +8006,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 25
+          "shards": 40
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
@@ -11292,7 +11292,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
+          "shards": 4
         },
         "test": "android_browsertests",
         "test_id_prefix": "ninja://chrome/test:android_browsertests/"
@@ -12489,7 +12489,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 25
+          "shards": 40
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
@@ -15402,7 +15402,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
+          "shards": 4
         },
         "test": "android_browsertests",
         "test_id_prefix": "ninja://chrome/test:android_browsertests/"
@@ -16599,7 +16599,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 25
+          "shards": 40
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 8f8a7485..b2405536 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5736,9 +5736,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5749,8 +5749,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -5901,9 +5901,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5914,8 +5914,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -6048,9 +6048,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -6061,8 +6061,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index ff37983..b91eea2a 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -8834,6 +8834,29 @@
       }
     ]
   },
+  "chromeos-js-code-coverage": {
+    "gtest_tests": [
+      {
+        "args": [],
+        "isolate_profile_data": true,
+        "merge": {
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "chromeos_js_code_coverage_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "browser_tests",
+        "test_id_prefix": "ninja://chrome/test:browser_tests/"
+      }
+    ]
+  },
   "fuchsia-code-coverage": {
     "additional_compile_targets": [
       "chrome_pkg"
@@ -25516,9 +25539,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25529,8 +25552,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -25681,9 +25704,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25694,8 +25717,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -25828,9 +25851,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25841,8 +25864,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -28432,7 +28455,8 @@
               "os": "Windows-10-19045"
             }
           ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 4
         },
         "test": "components_unittests",
         "test_id_prefix": "ninja://components:components_unittests/"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 245caf2..857f7b54 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -41560,9 +41560,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41572,8 +41572,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -41725,9 +41725,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41737,8 +41737,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -41872,9 +41872,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41884,8 +41884,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -43348,9 +43348,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43360,8 +43360,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -43513,9 +43513,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43525,8 +43525,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -43660,9 +43660,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43672,8 +43672,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -44407,9 +44407,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44419,8 +44419,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 03d195b..6a6394f 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -18114,12 +18114,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18130,8 +18130,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -18299,12 +18299,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18315,8 +18315,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
@@ -18461,12 +18461,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5731.0",
+        "description": "Run with ash-chrome version 114.0.5733.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18477,8 +18477,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5731.0",
-              "revision": "version:114.0.5731.0"
+              "location": "lacros_version_skew_tests_v114.0.5733.0",
+              "revision": "version:114.0.5733.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 7ed9ea4..6a07e75 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -2354,7 +2354,7 @@
           "hard_timeout": 21600,
           "io_timeout": 21600,
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 40
+          "shards": 20
         },
         "trigger_script": {
           "args": [
diff --git a/testing/buildbot/chromium.perf.pinpoint.json b/testing/buildbot/chromium.perf.pinpoint.json
index a29a2cb1..078daee 100644
--- a/testing/buildbot/chromium.perf.pinpoint.json
+++ b/testing/buildbot/chromium.perf.pinpoint.json
@@ -1951,7 +1951,7 @@
           "hard_timeout": 21600,
           "io_timeout": 21600,
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 40
+          "shards": 20
         },
         "trigger_script": {
           "args": [
diff --git a/testing/buildbot/filters/pixel_tests.filter b/testing/buildbot/filters/pixel_tests.filter
index fefc0605..d0d359d 100644
--- a/testing/buildbot/filters/pixel_tests.filter
+++ b/testing/buildbot/filters/pixel_tests.filter
@@ -65,7 +65,7 @@
 ProfilePickerUIPixelTest.*
 ProfileTypeChoiceUIPixelTest.*
 PromptForScanningModalDialogTest.*
-QRCodeGeneratorBubbleBrowserTest.*
+QrCodeGeneratorServicePixelTest.*
 RelaunchRecommendedBubbleViewDialogTest.*
 RelaunchRequiredDialogViewDialogTest.*
 ReopenTabPromoControllerDialogBrowserTest.*
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 3d198fc..f454bedd 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -40,18 +40,27 @@
           # https://crbug.com/1289764
           '--gtest_filter=-All/ChromeBrowsingDataLifetimeManagerScheduledRemovalTest.History/*',
         ],
+        'swarming': {
+          'shards': 4,
+        },
       },
       'android-12l-x64-dbg-tests': {
         'args': [
           # https://crbug.com/1289764
           '--gtest_filter=-All/ChromeBrowsingDataLifetimeManagerScheduledRemovalTest.History/*',
         ],
+        'swarming': {
+          'shards': 4,
+        },
       },
       'android-13-x64-rel': {
         'args': [
           # https://crbug.com/1414886
           '--gtest_filter=-OfferNotificationControllerAndroidBrowserTestForMessagesUi.MessageShown',
         ],
+        'swarming': {
+          'shards': 4,
+        },
       },
       # If you change this, make similar changes in android-x86-code-coverage below
       'android-nougat-x86-rel': {
@@ -1750,6 +1759,11 @@
           'inverse_quickrun_shards': 2,
         },
       },
+      'win10-code-coverage': {
+        'swarming': {
+          'shards': 4,
+        },
+      },
     },
   },
   'compositor_unittests': {
@@ -1874,7 +1888,7 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.content_browsertests.filter',
         ],
         'swarming': {
-          'shards': 25,
+          'shards': 40,
         },
       },
       'android-12l-x64-dbg-tests': {
@@ -1882,7 +1896,7 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12l_13.content_browsertests.filter',
         ],
         'swarming': {
-          'shards': 25,
+          'shards': 40,
         },
       },
       'android-13-x64-rel': {
@@ -1890,7 +1904,7 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12l_13.content_browsertests.filter',
         ],
         'swarming': {
-          'shards': 25,
+          'shards': 40,
         },
       },
       'android-arm64-proguard-rel': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 15fcc905..f472710 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -727,6 +727,13 @@
       },
     },
 
+    'chromeos_js_code_coverage_browser_tests' : {
+      'chromeos_js_code_coverage_browser_tests': {
+        'args': [],
+        'test': 'browser_tests',
+      }
+    },
+
     'chromeos_remote_device_isolated_tests': {
       'telemetry_perf_unittests': {
         'args': [
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 6063557..6f255f9d 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5731.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5733.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 114.0.5731.0',
+    'description': 'Run with ash-chrome version 114.0.5733.0',
     'identifier': 'Lacros version skew testing ash canary',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v114.0.5731.0',
-          'revision': 'version:114.0.5731.0',
+          'location': 'lacros_version_skew_tests_v114.0.5733.0',
+          'revision': 'version:114.0.5733.0',
         },
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index ccd76f6..5eb4f16a 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2187,6 +2187,15 @@
           'scripts': 'chromium_android_scripts',
         },
       },
+      'chromeos-js-code-coverage': {
+        'mixins': [
+          'isolate_profile_data',
+          'linux-bionic',
+        ],
+        'test_suites': {
+          'gtest_tests': 'chromeos_js_code_coverage_browser_tests'
+        },
+      },
       'fuchsia-code-coverage': {
         'additional_compile_targets': [
           'chrome_pkg',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 3df53c9..8fae7ac 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1266,7 +1266,6 @@
                 "android_weblayer",
                 "chromeos",
                 "chromeos_lacros",
-                "fuchsia",
                 "ios",
                 "linux",
                 "mac",
@@ -2148,6 +2147,21 @@
             ]
         }
     ],
+    "CCTRealTimeEngagementSignalsAlternativeImpl": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "CCTRealTimeEngagementSignalsAlternativeImpl"
+                    ]
+                }
+            ]
+        }
+    ],
     "CPSS": [
         {
             "platforms": [
@@ -2805,19 +2819,37 @@
             ]
         }
     ],
-    "ChromeOSMemoryPressureSignalStudy": [
+    "ChromeOSMemoryPressureSignalStudyArc": [
         {
             "platforms": [
                 "chromeos"
             ],
             "experiments": [
                 {
-                    "name": "Enabled12_20220512",
+                    "name": "Enabled8_20230420",
                     "params": {
-                        "critical_threshold_percentage": "1200"
+                        "critical_threshold_percentage": "800"
                     },
                     "enable_features": [
-                        "ChromeOSMemoryPressureSignalStudy"
+                        "ChromeOSMemoryPressureSignalStudyArc"
+                    ]
+                }
+            ]
+        }
+    ],
+    "ChromeOSMemoryPressureSignalStudyNonArc": [
+        {
+            "platforms": [
+                "chromeos"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled15_20230420",
+                    "params": {
+                        "critical_threshold_percentage": "1500"
+                    },
+                    "enable_features": [
+                        "ChromeOSMemoryPressureSignalStudyNonArc"
                     ]
                 }
             ]
@@ -8540,25 +8572,6 @@
             ]
         }
     ],
-    "NtpComprehensiveTheming": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_20221129",
-                    "enable_features": [
-                        "NtpComprehensiveTheming"
-                    ]
-                }
-            ]
-        }
-    ],
     "NtpHistoryClustersMetricsOnly112": [
         {
             "platforms": [
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index c7704c21..c753ca3e 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -716,6 +716,7 @@
       InvalidRegisterOsSourceHeader
       InvalidRegisterOsTriggerHeader
       WebAndOsHeaders
+      NoWebOrOsSupport
 
   # Details for issues around "Attribution Reporting API" usage.
   # Explainer: https://github.com/WICG/attribution-reporting-api
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom
index d46e64c..0181b4b9 100644
--- a/third_party/blink/public/mojom/frame/frame.mojom
+++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -597,9 +597,8 @@
   //
   // A document in a fenced frame can invoke the reportEvent API to request the
   // browser to send `eventData` in a beacon toward the URL registered against
-  // `eventType` by the worklet in registerAdBeacon. Depending on the declared
-  // `destination`, the beacon is sent to either the buyer's or the seller's
-  // registered URL.
+  // `eventType` by the worklet in registerAdBeacon. Please see enum
+  // `ReportingDestination` for egilible reporting entities.
   SendFencedFrameReportingBeacon(string event_data,
                                  string event_type,
                                  ReportingDestination destination);
diff --git a/third_party/blink/public/mojom/presentation/presentation.mojom b/third_party/blink/public/mojom/presentation/presentation.mojom
index 08c8e01..938acdab 100644
--- a/third_party/blink/public/mojom/presentation/presentation.mojom
+++ b/third_party/blink/public/mojom/presentation/presentation.mojom
@@ -193,13 +193,5 @@
 interface PresentationReceiver {
   // Notifies the PresentationReceiver that a receiver connection has become
   // available.
-  // |info|: URL and ID of the PresentationConnection.
-  // |controller_connection|: Remote to the corresponding controller connection.
-  // |receiver_connection_receiver|: PendingReceiver to be bound at the other
-  // endpoint of the controller connection.
-  // TODO(btolsch): Convert this to take a PresentationConnectionResult.
-  OnReceiverConnectionAvailable(
-      PresentationInfo info,
-      pending_remote<PresentationConnection> controller_connection,
-      pending_receiver<PresentationConnection> receiver_connection_receiver);
+  OnReceiverConnectionAvailable(PresentationConnectionResult result);
 };
diff --git a/third_party/blink/public/mojom/webid/federated_auth_request.mojom b/third_party/blink/public/mojom/webid/federated_auth_request.mojom
index 88f8e530..6335fe3a 100644
--- a/third_party/blink/public/mojom/webid/federated_auth_request.mojom
+++ b/third_party/blink/public/mojom/webid/federated_auth_request.mojom
@@ -63,21 +63,6 @@
   string account_id;
 };
 
-// The login hint for this identity provider. Used by the relying party to
-// specify some data about the user account they would like to show in the
-// FedCM dialog.
-struct IdentityProviderLoginHint {
-  // The strings can be empty when not provided.
-  string email;
-
-  string id;
-
-  // Whether the hint should be required or not. If required, the user agent can
-  // show other accounts if there is no account matching the hint. Otherwise,
-  // the user agent should not show other accounts in case no match is found.
-  bool is_required;
-};
-
 // The details of different mechanisms that allows the browser
 // to intermediate the exchange of the user's entities.
 // Currently, federated identities are supported, and mobile driver's license
@@ -116,8 +101,10 @@
   // Can be an empty string to be omitted in the request sent to the provider.
   string nonce;
 
+  // The login hint for this identity provider. Used by the relying party to
+  // specify which user account they would like to show in the FedCM dialog.
   // This field is not sent to the provider, but rather used by the user agent.
-  IdentityProviderLoginHint login_hint;
+  string login_hint;
 
   // The scope of the federated identity request: name/email/photo or
   // custom ones (e.g. "access to calendar", "access to social graph", etc).
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 82b369d..d7fc9c2 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -773,12 +773,11 @@
 
   // Attribution Reporting API ------------------------------------
 
-  // Returns whether OS-level support is enabled for Attribution Reporting API.
+  // Returns whether web or OS-level Attribution Reporting is supported.
   // See
   // https://github.com/WICG/attribution-reporting-api/blob/main/app_to_web.md.
-  virtual network::mojom::AttributionOsSupport
-  GetOsSupportForAttributionReporting() {
-    return network::mojom::AttributionOsSupport::kDisabled;
+  virtual network::mojom::AttributionSupport GetAttributionReportingSupport() {
+    return network::mojom::AttributionSupport::kWeb;
   }
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index 684e12c..a50072a3 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -136,6 +136,7 @@
                     "core/v8/use_counter_callback.h",
                     "core/v8/v8_binding_for_core.cc",
                     "core/v8/v8_binding_for_core.h",
+                    "core/v8/v8_custom_element_constructor_hash.h",
                     "core/v8/v8_code_cache.cc",
                     "core/v8/v8_code_cache.h",
                     "core/v8/v8_compile_hints.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc b/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
index 74f97cd..55a84d9e 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
@@ -31,7 +31,8 @@
 ScriptCustomElementDefinition::ScriptCustomElementDefinition(
     const ScriptCustomElementDefinitionData& data,
     const CustomElementDescriptor& descriptor)
-    : CustomElementDefinition(descriptor,
+    : CustomElementDefinition(*data.registry_,
+                              descriptor,
                               std::move(data.observed_attributes_),
                               data.disabled_features_,
                               data.is_form_associated_
@@ -46,7 +47,9 @@
       form_associated_callback_(data.form_associated_callback_),
       form_reset_callback_(data.form_reset_callback_),
       form_disabled_callback_(data.form_disabled_callback_),
-      form_state_restore_callback_(data.form_state_restore_callback_) {}
+      form_state_restore_callback_(data.form_state_restore_callback_) {
+  DCHECK(data.registry_);
+}
 
 void ScriptCustomElementDefinition::Trace(Visitor* visitor) const {
   visitor->Trace(script_state_);
diff --git a/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h b/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h
index e22aa6f..704b5bf 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h
+++ b/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.h
@@ -70,6 +70,9 @@
   // Implementations of |CustomElementDefinition|
   ScriptValue GetConstructorForScript() final;
   bool RunConstructor(Element&) override;
+  V8CustomElementConstructor* GetV8CustomElementConstructor() final {
+    return constructor_;
+  }
 
   // Calls the constructor. The script scope, etc. must already be set up.
   Element* CallConstructor();
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_custom_element_constructor_hash.h b/third_party/blink/renderer/bindings/core/v8/v8_custom_element_constructor_hash.h
new file mode 100644
index 0000000..54ede29d
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/v8_custom_element_constructor_hash.h
@@ -0,0 +1,45 @@
+// Copyright 2023 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_BINDINGS_CORE_V8_V8_CUSTOM_ELEMENT_CONSTRUCTOR_HASH_H_
+#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_CUSTOM_ELEMENT_CONSTRUCTOR_HASH_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_constructor.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+
+namespace blink {
+
+// Hashes V8CustomElementConstructor pointers by their v8 callback objects.
+struct V8CustomElementConstructorHashTraits
+    : WTF::MemberHashTraits<V8CustomElementConstructor> {
+  static unsigned GetHash(
+      const Member<V8CustomElementConstructor>& constructor) {
+    return constructor->CallbackObject()->GetIdentityHash();
+  }
+  static bool Equal(const Member<V8CustomElementConstructor>& a,
+                    const Member<V8CustomElementConstructor>& b) {
+    if (a->GetIsolate() != b->GetIsolate()) {
+      return false;
+    }
+    return a->CallbackObject() == b->CallbackObject();
+  }
+  static constexpr bool kSafeToCompareToEmptyOrDeleted = false;
+};
+
+// Hash translator for custom element constructors in two forms:
+// V8CustomElementConstructor or v8 object.
+struct V8CustomElementConstructorHashTranslator {
+  STATIC_ONLY(V8CustomElementConstructorHashTranslator);
+  static unsigned GetHash(const v8::Local<v8::Object>& constructor) {
+    return constructor->GetIdentityHash();
+  }
+  static bool Equal(const Member<V8CustomElementConstructor>& a,
+                    const v8::Local<v8::Object>& b) {
+    return a && a->CallbackObject() == b;
+  }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_CUSTOM_ELEMENT_CONSTRUCTOR_HASH_H_
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc b/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc
index 7a0a5e7..71a5872 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc
@@ -72,7 +72,8 @@
   // memory use and trigger a V8+Blink GC. However, on Android, if the frame
   // will not be reused, the process will likely to be killed soon so skip this.
   if (is_main_frame && frame_reuse_status == WindowProxy::kFrameWillBeReused &&
-      ((MemoryPressureListenerRegistry::IsLowEndDevice() &&
+      ((MemoryPressureListenerRegistry::
+            IsLowEndDeviceOrPartialLowEndModeEnabled() &&
         MemoryPressureListenerRegistry::IsCurrentlyLowMemory()) ||
        force_page_navigation_gc_)) {
     const size_t pre_gc_memory_usage = GetMemoryUsage();
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_html_constructor.cc b/third_party/blink/renderer/bindings/core/v8/v8_html_constructor.cc
index 686da8d..c880c03 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_html_constructor.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_html_constructor.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_construction_stack.h"
 #include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -59,8 +60,9 @@
   // NewTarget.
   // If there is no such definition, then throw a TypeError and abort these
   // steps.
+  v8::Local<v8::Object> constructor = new_target.As<v8::Object>();
   CustomElementDefinition* definition =
-      registry->DefinitionForConstructor(new_target.As<v8::Object>());
+      registry->DefinitionForConstructor(constructor);
   if (!definition) {
     V8ThrowException::ThrowTypeError(isolate, "Illegal constructor");
     return;
@@ -115,14 +117,16 @@
 
   // 8. If definition's construction stack is empty...
   Element* element;
-  if (definition->GetConstructionStack().empty()) {
+  CustomElementConstructionStack* construction_stack =
+      GetCustomElementConstructionStack(window, constructor);
+  if (!construction_stack || construction_stack->empty()) {
     // This is an element being created with 'new' from script
     element = definition->CreateElementForConstructor(*window->document());
   } else {
-    element = definition->GetConstructionStack().back();
+    element = construction_stack->back();
     if (element) {
       // This is an element being upgraded that has called super
-      definition->GetConstructionStack().back().Clear();
+      construction_stack->back().Clear();
     } else {
       // During upgrade an element has invoked the same constructor
       // before calling 'super' and that invocation has poached the
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 19a51c7..62f885d 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -611,8 +611,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_lock_manager_snapshot.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_lock_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_lock_options.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_login_hint.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_login_hint.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_long_range.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_long_range.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_m_doc_element.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index 3cfc0ad0..b6ba09f 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -169,7 +169,6 @@
           "//third_party/blink/renderer/modules/credentialmanagement/identity_credential_request_options.idl",
           "//third_party/blink/renderer/modules/credentialmanagement/identity_provider.idl",
           "//third_party/blink/renderer/modules/credentialmanagement/identity_provider_config.idl",
-          "//third_party/blink/renderer/modules/credentialmanagement/login_hint.idl",
           "//third_party/blink/renderer/modules/credentialmanagement/navigator_credentials.idl",
           "//third_party/blink/renderer/modules/credentialmanagement/otp_credential.idl",
           "//third_party/blink/renderer/modules/credentialmanagement/otp_credential_request_options.idl",
diff --git a/third_party/blink/renderer/core/css/css_selector.cc b/third_party/blink/renderer/core/css/css_selector.cc
index 0efa9cc..a27aa87 100644
--- a/third_party/blink/renderer/core/css/css_selector.cc
+++ b/third_party/blink/renderer/core/css/css_selector.cc
@@ -330,7 +330,6 @@
     case kPseudoInRange:
     case kPseudoIncrement:
     case kPseudoIndeterminate:
-    case kPseudoInitial:
     case kPseudoInvalid:
     case kPseudoIs:
     case kPseudoIsHtml:
@@ -487,7 +486,6 @@
     {"in-range", CSSSelector::kPseudoInRange},
     {"increment", CSSSelector::kPseudoIncrement},
     {"indeterminate", CSSSelector::kPseudoIndeterminate},
-    {"initial", CSSSelector::kPseudoInitial},
     {"invalid", CSSSelector::kPseudoInvalid},
     {"last-child", CSSSelector::kPseudoLastChild},
     {"last-of-type", CSSSelector::kPseudoLastOfType},
@@ -647,11 +645,6 @@
     return CSSSelector::kPseudoUnknown;
   }
 
-  if (match->type == CSSSelector::kPseudoInitial &&
-      !RuntimeEnabledFeatures::CSSInitialPseudoEnabled()) {
-    return CSSSelector::kPseudoUnknown;
-  }
-
   return static_cast<CSSSelector::PseudoType>(match->type);
 }
 
@@ -812,7 +805,6 @@
     case kPseudoInRange:
     case kPseudoIncrement:
     case kPseudoIndeterminate:
-    case kPseudoInitial:
     case kPseudoInvalid:
     case kPseudoIs:
     case kPseudoLang:
@@ -1288,7 +1280,6 @@
     case CSSSelector::kPseudoFirstChild:
     case CSSSelector::kPseudoLastChild:
     case CSSSelector::kPseudoFirstOfType:
-    case CSSSelector::kPseudoInitial:
     case CSSSelector::kPseudoLastOfType:
     case CSSSelector::kPseudoOnlyOfType:
     case CSSSelector::kPseudoHost:
diff --git a/third_party/blink/renderer/core/css/css_selector.h b/third_party/blink/renderer/core/css/css_selector.h
index f906e10..95d637cd 100644
--- a/third_party/blink/renderer/core/css/css_selector.h
+++ b/third_party/blink/renderer/core/css/css_selector.h
@@ -240,7 +240,6 @@
     kPseudoHover,
     kPseudoIncrement,
     kPseudoIndeterminate,
-    kPseudoInitial,
     kPseudoInvalid,
     kPseudoIs,
     kPseudoLang,
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc
index c06019b..7acded0 100644
--- a/third_party/blink/renderer/core/css/element_rule_collector.cc
+++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -412,8 +412,8 @@
   context.vtt_originating_element = match_request.VTTOriginatingElement();
   context.style_scope_frame =
       &style_scope_frame.GetParentFrameOrThis(context_.GetElement());
-  context.is_initial = !style_recalc_context_.is_ensuring_style &&
-                       !style_recalc_context_.old_style;
+  bool is_initial = !style_recalc_context_.is_ensuring_style &&
+                    !style_recalc_context_.old_style;
 
   CascadeLayerSeeker layer_seeker(
       context.scope, context.vtt_originating_element, style_sheet, rule_set);
@@ -434,7 +434,7 @@
       selector_statistics_collector.EndCollectionForCurrentRule();
       selector_statistics_collector.BeginCollectionForRule(&rule_data);
     }
-    if (!context.is_initial && rule_data.IsInitial()) {
+    if (!is_initial && rule_data.IsInitial()) {
       continue;
     }
     if (can_use_fast_reject_ &&
diff --git a/third_party/blink/renderer/core/css/parser/css_selector_parser.cc b/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
index a7e2734..f8d2bbad 100644
--- a/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/css_selector_parser.cc
@@ -1085,11 +1085,6 @@
     CSSSelector::PseudoType pseudo_class,
     CSSSelector::PseudoType compound_pseudo_element) {
   switch (compound_pseudo_element) {
-    case CSSSelector::kPseudoBefore:
-    case CSSSelector::kPseudoAfter:
-    case CSSSelector::kPseudoMarker:
-    case CSSSelector::kPseudoPlaceholder:
-      return pseudo_class == CSSSelector::kPseudoInitial;
     case CSSSelector::kPseudoResizer:
     case CSSSelector::kPseudoScrollbar:
     case CSSSelector::kPseudoScrollbarCorner:
@@ -1102,13 +1097,11 @@
       return pseudo_class == CSSSelector::kPseudoWindowInactive;
     case CSSSelector::kPseudoPart:
       return IsUserActionPseudoClass(pseudo_class) ||
-             pseudo_class == CSSSelector::kPseudoState ||
-             pseudo_class == CSSSelector::kPseudoInitial;
+             pseudo_class == CSSSelector::kPseudoState;
     case CSSSelector::kPseudoWebKitCustomElement:
     case CSSSelector::kPseudoBlinkInternalElement:
     case CSSSelector::kPseudoFileSelectorButton:
-      return IsUserActionPseudoClass(pseudo_class) ||
-             pseudo_class == CSSSelector::kPseudoInitial;
+      return IsUserActionPseudoClass(pseudo_class);
     case CSSSelector::kPseudoViewTransitionGroup:
     case CSSSelector::kPseudoViewTransitionImagePair:
     case CSSSelector::kPseudoViewTransitionOld:
diff --git a/third_party/blink/renderer/core/css/rule_feature_set.cc b/third_party/blink/renderer/core/css/rule_feature_set.cc
index 92273c4..8ca157a 100644
--- a/third_party/blink/renderer/core/css/rule_feature_set.cc
+++ b/third_party/blink/renderer/core/css/rule_feature_set.cc
@@ -195,7 +195,6 @@
     case CSSSelector::kPseudoViewTransitionNew:
     case CSSSelector::kPseudoViewTransitionOld:
     case CSSSelector::kPseudoToggle:
-    case CSSSelector::kPseudoInitial:
       return true;
     case CSSSelector::kPseudoUnknown:
     case CSSSelector::kPseudoLeftPage:
diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc
index a1029db..e7905d9 100644
--- a/third_party/blink/renderer/core/css/selector_checker.cc
+++ b/third_party/blink/renderer/core/css/selector_checker.cc
@@ -1873,14 +1873,6 @@
       // Only kept around for parsing; can never match anything
       // (because we don't know what it's supposed to mean).
       return false;
-    case CSSSelector::kPseudoInitial: {
-      if (!context.is_initial || !context.in_rightmost_compound ||
-          context.in_nested_complex_selector) {
-        return false;
-      }
-      result.SetFlag(MatchFlag::kAffectedByInitial);
-      return true;
-    }
     case CSSSelector::kPseudoTrue:
       return true;
     case CSSSelector::kPseudoUnknown:
diff --git a/third_party/blink/renderer/core/css/selector_checker.h b/third_party/blink/renderer/core/css/selector_checker.h
index 5d1196d4..ba4ebf8 100644
--- a/third_party/blink/renderer/core/css/selector_checker.h
+++ b/third_party/blink/renderer/core/css/selector_checker.h
@@ -145,8 +145,6 @@
     bool match_visited = false;
     bool pseudo_has_in_rightmost_compound = true;
     bool is_inside_has_pseudo_class = false;
-    // Set to true if :initial pseudo class should match.
-    bool is_initial = false;
   };
 
   struct MatchResult {
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index 2f1c11c6..fbc50f2 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -6016,8 +6016,10 @@
 TEST_F(StyleEngineTest, InitialStyle_Recalc) {
   GetDocument().body()->setInnerHTML(R"HTML(
     <style>
-      #target { background-color: green; }
-      #target:initial { background-color: red; }
+      #target {
+        background-color: green;
+        @initial { background-color: red; }
+      }
     </style>
     <div id="target"></div>
   )HTML");
@@ -6034,12 +6036,12 @@
   UpdateAllLifecyclePhasesForTest();
 
   EXPECT_EQ(GetStyleEngine().StyleForElementCount() - before_count, 1u)
-      << "The style recalc should not do a separate :initial pass since the "
+      << "The style recalc should not do a separate @initial pass since the "
          "element already has a style";
   EXPECT_EQ(target->ComputedStyleRef().VisitedDependentColor(
                 GetCSSPropertyBackgroundColor()),
             green)
-      << "Make sure :initial does not match for the second pass";
+      << "Make sure @initial rules do not apply for the second pass";
   EXPECT_EQ(
       target->ComputedStyleRef().VisitedDependentColor(GetCSSPropertyColor()),
       lime)
@@ -6049,8 +6051,10 @@
 TEST_F(StyleEngineTest, InitialStyle_FromDisplayNone) {
   GetDocument().body()->setInnerHTML(R"HTML(
     <style>
-      #target { background-color: green; }
-      #target:initial { background-color: red; }
+      #target {
+        background-color: green;
+        @initial { background-color: red; }
+      }
     </style>
     <div id="target" style="display:none"></div>
   )HTML");
@@ -6067,11 +6071,11 @@
 
   EXPECT_EQ(GetStyleEngine().StyleForElementCount() - before_count, 2u)
       << "The style recalc needs to do two passes because the element was "
-         "display:none and :initial styles are matching";
+         "display:none and @initial styles are matching";
   EXPECT_EQ(target->ComputedStyleRef().VisitedDependentColor(
                 GetCSSPropertyBackgroundColor()),
             green)
-      << "Make sure :initial does not match for the second pass";
+      << "Make sure @initial do not apply for the second pass";
 }
 
 TEST_F(StyleEngineTest, InitialStyleCount_EnsureComputedStyle) {
@@ -6080,8 +6084,8 @@
       #target {
         background-color: green;
         transition: background-color 100s step-end;
+        @initial { background-color: red; }
       }
-      #target:initial { background-color: red; }
     </style>
     <div id="target" style="display:none"></div>
   )HTML");
@@ -6100,12 +6104,12 @@
   ASSERT_TRUE(none_style);
 
   EXPECT_EQ(GetStyleEngine().StyleForElementCount() - before_count, 1u)
-      << "No :initial pass for EnsureComputedStyle";
+      << "No @initial pass for EnsureComputedStyle";
 
   EXPECT_EQ(target->ComputedStyleRef().VisitedDependentColor(
                 GetCSSPropertyBackgroundColor()),
             green)
-      << "Transitions are not started and :initial does not apply in "
+      << "Transitions are not started and @initial does not apply in "
          "display:none";
 }
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index cef6c858..d562b91 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3054,7 +3054,7 @@
     return nullptr;
   }
   if (style->IsPseudoInitialStyle()) {
-    // :initial pseudo styles matched. We need to compute the style a second
+    // @initial pseudo styles matched. We need to compute the style a second
     // time to compute the actual style and trigger transitions using the
     // starting from the :initial style.
     new_style_recalc_context.old_style =
diff --git a/third_party/blink/renderer/core/editing/local_caret_rect.cc b/third_party/blink/renderer/core/editing/local_caret_rect.cc
index 7b38aa2a..b1ea8a4 100644
--- a/third_party/blink/renderer/core/editing/local_caret_rect.cc
+++ b/third_party/blink/renderer/core/editing/local_caret_rect.cc
@@ -96,20 +96,35 @@
   if (!layout_object)
     return LocalCaretRect();
 
+  // If the `position` is for `LayoutText` or before/after inline boxes, let
+  // `ComputeLocalCaretRect` compute.
   const PositionWithAffinityTemplate<Strategy>& adjusted =
       ComputeInlineAdjustedPosition(position, rule);
-
   if (adjusted.IsNotNull()) {
     if (auto caret_position =
             ComputeNGCaretPosition(AdjustForNGCaretPosition(adjusted)))
       return ComputeLocalCaretRect(caret_position);
   }
 
-  // DeleteSelectionCommandTest.deleteListFromTable goes here.
+  // If the caret is in an empty `LayoutBlockFlow`, and if it is block-
+  // fragmented, set the first fragment to prevent rendering multiple carets in
+  // following fragments.
+  const NGPhysicalBoxFragment* root_box_fragment = nullptr;
+  if (position.GetPosition().IsOffsetInAnchor() &&
+      !position.GetPosition().OffsetInContainerNode()) {
+    if (const auto* block_flow = DynamicTo<LayoutBlockFlow>(layout_object)) {
+      if (!block_flow->FirstChild() &&
+          block_flow->PhysicalFragmentCount() >= 2) {
+        root_box_fragment = block_flow->GetPhysicalFragment(0);
+      }
+    }
+  }
+
   return LocalCaretRect(layout_object,
                         layout_object->PhysicalLocalCaretRect(
                             position.GetPosition().ComputeEditingOffset(),
-                            extra_width_to_end_of_line));
+                            extra_width_to_end_of_line),
+                        root_box_fragment);
 }
 
 // This function was added because the caret rect that is calculated by
diff --git a/third_party/blink/renderer/core/frame/DEPS b/third_party/blink/renderer/core/frame/DEPS
index 54219cef..5cd9234 100644
--- a/third_party/blink/renderer/core/frame/DEPS
+++ b/third_party/blink/renderer/core/frame/DEPS
@@ -4,6 +4,7 @@
   ],
   "attribution_src_loader(\.cc|\.h|_test\.cc)": [
     "+components/attribution_reporting",
+    "+services/network/public/cpp/attribution_utils.h",
     "+services/network/public/cpp/trigger_attestation.h",
   ],
   "child_frame_compositing_helper\.h": [
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 cb5be1e..454fcb9 100644
--- a/third_party/blink/renderer/core/frame/attribution_src_loader.cc
+++ b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
@@ -30,9 +30,10 @@
 #include "components/attribution_reporting/trigger_registration_error.mojom-shared.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/shared_remote.h"
+#include "services/network/public/cpp/attribution_utils.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/trigger_attestation.h"
-#include "services/network/public/mojom/attribution.mojom-blink.h"
+#include "services/network/public/mojom/attribution.mojom-forward.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/common/navigation/impression.h"
@@ -178,13 +179,26 @@
                   /*invalid_parameter=*/os_trigger);
   }
 
+  void LogSourceIgnored(ExecutionContext* execution_context) const {
+    DCHECK(!web_source.IsNull());
+    LogAuditIssue(execution_context,
+                  AttributionReportingIssueType::kSourceIgnored,
+                  /*element=*/nullptr, request_id,
+                  /*invalid_parameter=*/web_source);
+  }
+
+  void LogTriggerIgnored(ExecutionContext* execution_context) const {
+    DCHECK(!web_trigger.IsNull());
+    LogAuditIssue(execution_context,
+                  AttributionReportingIssueType::kTriggerIgnored,
+                  /*element=*/nullptr, request_id,
+                  /*invalid_parameter=*/web_trigger);
+  }
+
   void MaybeLogAllSourceHeadersIgnored(
       ExecutionContext* execution_context) const {
     if (!web_source.IsNull()) {
-      LogAuditIssue(execution_context,
-                    AttributionReportingIssueType::kSourceIgnored,
-                    /*element=*/nullptr, request_id,
-                    /*invalid_parameter=*/web_source);
+      LogSourceIgnored(execution_context);
     }
 
     if (!os_source.IsNull()) {
@@ -195,10 +209,7 @@
   void MaybeLogAllTriggerHeadersIgnored(
       ExecutionContext* execution_context) const {
     if (!web_trigger.IsNull()) {
-      LogAuditIssue(execution_context,
-                    AttributionReportingIssueType::kTriggerIgnored,
-                    /*element=*/nullptr, request_id,
-                    /*invalid_parameter=*/web_trigger);
+      LogTriggerIgnored(execution_context);
     }
 
     if (!os_trigger.IsNull()) {
@@ -501,16 +512,28 @@
                                        HTMLElement* element,
                                        absl::optional<uint64_t> request_id,
                                        bool log_issues) {
-  return !!ReportingOriginForUrlIfValid(url, element, request_id, log_issues);
+  if (!ReportingOriginForUrlIfValid(url, element, request_id, log_issues)) {
+    return false;
+  }
+
+// TODO(linnan): Consider introducing helper functions to reduce #ifdef's.
+#if BUILDFLAG(IS_ANDROID)
+  if (!network::HasAttributionSupport(GetSupport())) {
+    if (log_issues) {
+      LogAuditIssue(local_frame_->DomWindow(),
+                    AttributionReportingIssueType::kNoWebOrOsSupport, element,
+                    request_id,
+                    /*invalid_parameter=*/String());
+    }
+    return false;
+  }
+#endif
+
+  return true;
 }
 
-bool AttributionSrcLoader::HasOsSupport() const {
-  return GetOsSupport() == network::mojom::AttributionOsSupport::kEnabled;
-}
-
-network::mojom::AttributionOsSupport AttributionSrcLoader::GetOsSupport()
-    const {
-  return Platform::Current()->GetOsSupportForAttributionReporting();
+network::mojom::AttributionSupport AttributionSrcLoader::GetSupport() const {
+  return Platform::Current()->GetAttributionReportingSupport();
 }
 
 bool AttributionSrcLoader::MaybeRegisterAttributionHeaders(
@@ -747,6 +770,12 @@
   }
 
   if (!headers.web_source.IsNull()) {
+#if BUILDFLAG(IS_ANDROID)
+    if (!network::HasAttributionWebSupport(loader_->GetSupport())) {
+      headers.LogSourceIgnored(loader_->local_frame_->DomWindow());
+      return;
+    }
+#endif
     auto source_data = attribution_reporting::SourceRegistration::Parse(
         StringUTF8Adaptor(headers.web_source).AsStringPiece());
     if (!source_data.has_value()) {
@@ -764,7 +793,7 @@
   }
 
   DCHECK(!headers.os_source.IsNull());
-  if (!loader_->HasOsSupport()) {
+  if (!network::HasAttributionOsSupport(loader_->GetSupport())) {
     headers.LogOsSourceIgnored(loader_->local_frame_->DomWindow());
     return;
   }
@@ -799,6 +828,12 @@
   }
 
   if (!headers.web_trigger.IsNull()) {
+#if BUILDFLAG(IS_ANDROID)
+    if (!network::HasAttributionWebSupport(loader_->GetSupport())) {
+      headers.LogTriggerIgnored(loader_->local_frame_->DomWindow());
+      return;
+    }
+#endif
     auto trigger_data = attribution_reporting::TriggerRegistration::Parse(
         StringUTF8Adaptor(headers.web_trigger).AsStringPiece());
     if (!trigger_data.has_value()) {
@@ -818,7 +853,7 @@
   }
 
   DCHECK(!headers.os_trigger.IsNull());
-  if (!loader_->HasOsSupport()) {
+  if (!network::HasAttributionOsSupport(loader_->GetSupport())) {
     headers.LogOsTriggerIgnored(loader_->local_frame_->DomWindow());
     return;
   }
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.h b/third_party/blink/renderer/core/frame/attribution_src_loader.h
index bdc6bca..db6edb3 100644
--- a/third_party/blink/renderer/core/frame/attribution_src_loader.h
+++ b/third_party/blink/renderer/core/frame/attribution_src_loader.h
@@ -98,7 +98,7 @@
 
   void Trace(Visitor* visitor) const;
 
-  network::mojom::AttributionOsSupport GetOsSupport() const;
+  network::mojom::AttributionSupport GetSupport() const;
 
  private:
   class ResourceClient;
@@ -127,9 +127,6 @@
                              HTMLElement*,
                              absl::optional<AttributionSrcToken>);
 
-  // Returns whether OS-level attribution is supported.
-  bool HasOsSupport() const;
-
   struct AttributionHeaders;
 
   void RegisterAttributionHeaders(
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc b/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc
index 288489f7..9166b630 100644
--- a/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc
+++ b/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc
@@ -208,6 +208,16 @@
   std::unique_ptr<MockDataHost> mock_data_host_;
 };
 
+class AttributionTestingPlatformSupport : public TestingPlatformSupport {
+ public:
+  network::mojom::AttributionSupport GetAttributionReportingSupport() override {
+    return attribution_support;
+  }
+
+  network::mojom::AttributionSupport attribution_support =
+      network::mojom::AttributionSupport::kWeb;
+};
+
 class AttributionSrcLoaderTest : public PageTestBase {
  public:
   AttributionSrcLoaderTest() = default;
@@ -239,6 +249,7 @@
   }
 
  protected:
+  ScopedTestingPlatformSupport<AttributionTestingPlatformSupport> platform_;
   Persistent<AttributionSrcLocalFrameClient> client_;
   Persistent<AttributionSrcLoader> attribution_src_loader_;
 };
@@ -542,16 +553,48 @@
   EXPECT_EQ(mock_data_host->disconnects(), 1u);
 }
 
-class AttributionTestingPlatformSupport : public TestingPlatformSupport {
- public:
-  network::mojom::AttributionOsSupport GetOsSupportForAttributionReporting()
-      override {
-    return os_support;
-  }
+#if BUILDFLAG(IS_ANDROID)
 
-  network::mojom::AttributionOsSupport os_support =
-      network::mojom::AttributionOsSupport::kDisabled;
-};
+TEST_F(AttributionSrcLoaderTest, NoneSupported_CannotRegister) {
+  platform_->attribution_support = network::mojom::AttributionSupport::kNone;
+
+  KURL test_url = ToKURL("https://example1.com/foo.html");
+
+  EXPECT_FALSE(
+      attribution_src_loader_->CanRegister(test_url, /*element=*/nullptr,
+                                           /*request_id=*/absl::nullopt));
+}
+
+TEST_F(AttributionSrcLoaderTest, WebDisabled_TriggerNotRegistered) {
+  KURL test_url = ToKURL("https://example1.com/foo.html");
+
+  for (auto attribution_support : {network::mojom::AttributionSupport::kNone,
+                                   network::mojom::AttributionSupport::kOs}) {
+    platform_->attribution_support = attribution_support;
+
+    ResourceRequest request(test_url);
+    auto* resource = MakeGarbageCollected<MockResource>(test_url);
+    ResourceResponse response(test_url);
+    response.SetHttpStatusCode(200);
+    response.SetHttpHeaderField(
+        http_names::kAttributionReportingRegisterTrigger,
+        R"({"event_trigger_data":[{"trigger_data": "7"}]})");
+
+    MockAttributionHost host(
+        GetFrame().GetRemoteNavigationAssociatedInterfaces());
+    EXPECT_TRUE(attribution_src_loader_->MaybeRegisterAttributionHeaders(
+        request, response, resource));
+    host.WaitUntilBoundAndFlush();
+
+    auto* mock_data_host = host.mock_data_host();
+    ASSERT_TRUE(mock_data_host);
+
+    mock_data_host->Flush();
+    EXPECT_THAT(mock_data_host->trigger_data(), testing::IsEmpty());
+  }
+}
+
+#endif
 
 class AttributionSrcLoaderCrossAppWebEnabledTest
     : public AttributionSrcLoaderTest {
@@ -567,7 +610,13 @@
 };
 
 TEST_F(AttributionSrcLoaderCrossAppWebEnabledTest, SupportHeader_Register) {
-  platform_->os_support = network::mojom::AttributionOsSupport::kEnabled;
+#if BUILDFLAG(IS_ANDROID)
+  auto attribution_support = network::mojom::AttributionSupport::kWebAndOs;
+#else
+  auto attribution_support = network::mojom::AttributionSupport::kWeb;
+#endif
+
+  platform_->attribution_support = attribution_support;
 
   KURL url = ToKURL(kUrl);
   RegisterMockedURLLoad(url, test::CoreTestDataPath("foo.html"));
@@ -576,13 +625,19 @@
 
   url_test_helpers::ServeAsynchronousRequests();
 
-  EXPECT_EQ(client_->request_head().GetAttributionReportingOsSupport(),
-            network::mojom::AttributionOsSupport::kEnabled);
+  EXPECT_EQ(client_->request_head().GetAttributionReportingSupport(),
+            attribution_support);
 }
 
 TEST_F(AttributionSrcLoaderCrossAppWebEnabledTest,
        SupportHeader_RegisterNavigation) {
-  platform_->os_support = network::mojom::AttributionOsSupport::kEnabled;
+#if BUILDFLAG(IS_ANDROID)
+  auto attribution_support = network::mojom::AttributionSupport::kWebAndOs;
+#else
+  auto attribution_support = network::mojom::AttributionSupport::kWeb;
+#endif
+
+  platform_->attribution_support = attribution_support;
 
   KURL url = ToKURL(kUrl);
   RegisterMockedURLLoad(url, test::CoreTestDataPath("foo.html"));
@@ -593,13 +648,14 @@
 
   url_test_helpers::ServeAsynchronousRequests();
 
-  EXPECT_EQ(client_->request_head().GetAttributionReportingOsSupport(),
-            network::mojom::AttributionOsSupport::kEnabled);
+  EXPECT_EQ(client_->request_head().GetAttributionReportingSupport(),
+            attribution_support);
 }
 
 #if BUILDFLAG(IS_ANDROID)
 TEST_F(AttributionSrcLoaderCrossAppWebEnabledTest, RegisterOsTrigger) {
-  platform_->os_support = network::mojom::AttributionOsSupport::kEnabled;
+  platform_->attribution_support =
+      network::mojom::AttributionSupport::kWebAndOs;
 
   KURL test_url = ToKURL("https://example1.com/foo.html");
 
diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.cc b/third_party/blink/renderer/core/frame/remote_frame_view.cc
index 64c85d9..2816c04 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame_view.cc
@@ -4,7 +4,8 @@
 
 #include "third_party/blink/renderer/core/frame/remote_frame_view.h"
 
-#include "base/cxx17_backports.h"
+#include <algorithm>
+
 #include "components/paint_preview/common/paint_preview_tracker.h"
 #include "printing/buildflags/buildflags.h"
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
@@ -251,8 +252,8 @@
   constexpr float kMinCompositingScaleFactor = 0.25f;
   constexpr float kMaxCompositingScaleFactor = 5.0f;
   compositing_scale_factor_ =
-      base::clamp(compositing_scale_factor_, kMinCompositingScaleFactor,
-                  kMaxCompositingScaleFactor);
+      std::clamp(compositing_scale_factor_, kMinCompositingScaleFactor,
+                 kMaxCompositingScaleFactor);
 
   if (compositing_scale_factor_ != previous_scale_factor)
     remote_frame_->SynchronizeVisualProperties();
diff --git a/third_party/blink/renderer/core/html/build.gni b/third_party/blink/renderer/core/html/build.gni
index 9b5e84f..2afe354 100644
--- a/third_party/blink/renderer/core/html/build.gni
+++ b/third_party/blink/renderer/core/html/build.gni
@@ -51,6 +51,8 @@
   "cross_origin_attribute.h",
   "custom/ce_reactions_scope.cc",
   "custom/ce_reactions_scope.h",
+  "custom/custom_element_construction_stack.cc",
+  "custom/custom_element_construction_stack.h",
   "custom/custom_element_definition.cc",
   "custom/custom_element_definition.h",
   "custom/custom_element_definition_builder.h",
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
index b0e9ab5..d867623 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
@@ -49,16 +49,19 @@
 }
 
 unsigned CanvasFontCache::MaxFonts() {
-  return MemoryPressureListenerRegistry::IsLowEndDevice()
+  return MemoryPressureListenerRegistry::
+                 IsLowEndDeviceOrPartialLowEndModeEnabled()
              ? CanvasFontCacheMaxFontsLowEnd
              : CanvasFontCacheMaxFonts;
 }
 
 unsigned CanvasFontCache::HardMaxFonts() {
-  return document_->hidden() ? CanvasFontCacheHiddenMaxFonts
-                             : (MemoryPressureListenerRegistry::IsLowEndDevice()
-                                    ? CanvasFontCacheHardMaxFontsLowEnd
-                                    : CanvasFontCacheHardMaxFonts);
+  return document_->hidden()
+             ? CanvasFontCacheHiddenMaxFonts
+             : (MemoryPressureListenerRegistry::
+                        IsLowEndDeviceOrPartialLowEndModeEnabled()
+                    ? CanvasFontCacheHardMaxFontsLowEnd
+                    : CanvasFontCacheHardMaxFonts);
 }
 
 bool CanvasFontCache::GetFontUsingDefaultStyle(HTMLCanvasElement& element,
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_construction_stack.cc b/third_party/blink/renderer/core/html/custom/custom_element_construction_stack.cc
new file mode 100644
index 0000000..c8268031
--- /dev/null
+++ b/third_party/blink/renderer/core/html/custom/custom_element_construction_stack.cc
@@ -0,0 +1,124 @@
+// Copyright 2023 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/html/custom/custom_element_construction_stack.h"
+
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+
+namespace blink {
+
+namespace {
+
+// We manage the construction stacks in a map of maps, where the first map key
+// is a window, and the second map key is a constructor and value is a
+// construction stack.
+
+using ConstructorToStackMap =
+    HeapHashMap<Member<V8CustomElementConstructor>,
+                Member<CustomElementConstructionStack>,
+                V8CustomElementConstructorHashTraits>;
+
+using WindowMap =
+    HeapHashMap<Member<const LocalDOMWindow>, Member<ConstructorToStackMap>>;
+
+Persistent<WindowMap>& GetWindowMap() {
+  // This map is created only when upgrading custom elements and cleared when it
+  // finishes, so it never leaks. This is because construction stacks are
+  // populated only during custom element upgrading.
+  DEFINE_STATIC_LOCAL(Persistent<WindowMap>, map, ());
+  return map;
+}
+
+WindowMap& EnsureWindowMap() {
+  Persistent<WindowMap>& map = GetWindowMap();
+  if (!map) {
+    map = MakeGarbageCollected<WindowMap>();
+  }
+  return *map;
+}
+
+ConstructorToStackMap& EnsureConstructorToStackMap(
+    const LocalDOMWindow* window) {
+  WindowMap& window_map = EnsureWindowMap();
+  auto add_result = window_map.insert(window, nullptr);
+  if (add_result.is_new_entry) {
+    add_result.stored_value->value =
+        MakeGarbageCollected<ConstructorToStackMap>();
+  }
+  return *add_result.stored_value->value;
+}
+
+CustomElementConstructionStack& EnsureConstructionStack(
+    CustomElementDefinition& definition) {
+  const LocalDOMWindow* window = definition.GetRegistry().GetOwnerWindow();
+  ConstructorToStackMap& stack_map = EnsureConstructorToStackMap(window);
+
+  V8CustomElementConstructor* constructor =
+      definition.GetV8CustomElementConstructor();
+  v8::HandleScope handle_scope(constructor->GetIsolate());
+  auto add_result = stack_map.insert(constructor, nullptr);
+  if (add_result.is_new_entry) {
+    add_result.stored_value->value =
+        MakeGarbageCollected<CustomElementConstructionStack>();
+  }
+  return *add_result.stored_value->value;
+}
+
+}  // namespace
+
+CustomElementConstructionStack* GetCustomElementConstructionStack(
+    const LocalDOMWindow* window,
+    v8::Local<v8::Object> constructor) {
+  WindowMap* window_map = GetWindowMap();
+  if (!window_map) {
+    return nullptr;
+  }
+  auto constructor_stack_map_iter = window_map->find(window);
+  if (constructor_stack_map_iter == window_map->end()) {
+    return nullptr;
+  }
+  ConstructorToStackMap* constructor_stack_map =
+      constructor_stack_map_iter->value;
+  auto construction_stack_iter =
+      constructor_stack_map->Find<V8CustomElementConstructorHashTranslator>(
+          constructor);
+  if (construction_stack_iter == constructor_stack_map->end()) {
+    return nullptr;
+  }
+  return construction_stack_iter->value;
+}
+
+wtf_size_t CustomElementConstructionStackScope::nesting_level_ = 0;
+
+CustomElementConstructionStackScope::CustomElementConstructionStackScope(
+    CustomElementDefinition& definition,
+    Element& element)
+    : construction_stack_(EnsureConstructionStack(definition)) {
+  // Push the construction stack.
+  construction_stack_.push_back(&element);
+  ++nesting_level_;
+#if DCHECK_IS_ON()
+  element_ = &element;
+  depth_ = construction_stack_.size();
+#endif
+}
+
+CustomElementConstructionStackScope::~CustomElementConstructionStackScope() {
+#if DCHECK_IS_ON()
+  DCHECK(!construction_stack_.back() || construction_stack_.back() == element_);
+  DCHECK_EQ(construction_stack_.size(), depth_);  // It's a *stack*.
+#endif
+  // Pop the construction stack.
+  construction_stack_.pop_back();
+  // Clear the memory backing if all construction stacks are empty.
+  if (--nesting_level_ == 0) {
+    GetWindowMap().Clear();
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_construction_stack.h b/third_party/blink/renderer/core/html/custom/custom_element_construction_stack.h
new file mode 100644
index 0000000..8c996f9
--- /dev/null
+++ b/third_party/blink/renderer/core/html/custom/custom_element_construction_stack.h
@@ -0,0 +1,60 @@
+// Copyright 2023 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_HTML_CUSTOM_CUSTOM_ELEMENT_CONSTRUCTION_STACK_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_CONSTRUCTION_STACK_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_constructor_hash.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
+
+namespace blink {
+
+class CustomElementDefinition;
+class Element;
+class LocalDOMWindow;
+
+// https://html.spec.whatwg.org/multipage/custom-elements.html#concept-custom-element-definition-construction-stack
+// To support scoped custom element registries, we modify it such that there's a
+// stack corresponding to each (window, custom element constructor) pair. Since
+// this is 1:1 to definitions, there's no behavioral change. The benefit is that
+// when scoped registries are enabled, we can check the construction stack to
+// find out which definition to use, instead of always looking up the global
+// registry.
+
+using CustomElementConstructionStack = HeapVector<Member<Element>, 1>;
+
+// Returns the construction stack associated with the construction in the
+// window. Nullptr return value means the stack is empty (when the memory
+// backing isn't created yet).
+CORE_EXPORT CustomElementConstructionStack* GetCustomElementConstructionStack(
+    const LocalDOMWindow* window,
+    v8::Local<v8::Object> constructor);
+
+// Pushes the construction stack of the constructor of a definition when
+// entering the scope, and pops it when exiting. Helper class for manipulating
+// the construction stacks.
+class CORE_EXPORT CustomElementConstructionStackScope final {
+  STACK_ALLOCATED();
+
+ public:
+  CustomElementConstructionStackScope(CustomElementDefinition&, Element&);
+  CustomElementConstructionStackScope(
+      const CustomElementConstructionStackScope&) = delete;
+  CustomElementConstructionStackScope& operator=(
+      const CustomElementConstructionStackScope&) = delete;
+  ~CustomElementConstructionStackScope();
+
+ private:
+  CustomElementConstructionStack& construction_stack_;
+#if DCHECK_IS_ON()
+  Element* element_;
+  wtf_size_t depth_;
+#endif
+
+  static wtf_size_t nesting_level_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_CUSTOM_CUSTOM_ELEMENT_CONSTRUCTION_STACK_H_
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_definition.cc b/third_party/blink/renderer/core/html/custom/custom_element_definition.cc
index 40f0a754..74ee443 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_definition.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_definition.cc
@@ -6,9 +6,11 @@
 #include "third_party/blink/renderer/core/dom/attr.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/html/custom/custom_element.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_construction_stack.h"
 #include "third_party/blink/renderer/core/html/custom/custom_element_reaction.h"
 #include "third_party/blink/renderer/core/html/custom/custom_element_reaction_factory.h"
 #include "third_party/blink/renderer/core/html/custom/custom_element_reaction_stack.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
 #include "third_party/blink/renderer/core/html/custom/element_internals.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
 #include "third_party/blink/renderer/core/html_element_factory.h"
@@ -18,15 +20,18 @@
 namespace blink {
 
 CustomElementDefinition::CustomElementDefinition(
+    CustomElementRegistry& registry,
     const CustomElementDescriptor& descriptor)
-    : descriptor_(descriptor) {}
+    : registry_(registry), descriptor_(descriptor) {}
 
 CustomElementDefinition::CustomElementDefinition(
+    CustomElementRegistry& registry,
     const CustomElementDescriptor& descriptor,
     const HashSet<AtomicString>& observed_attributes,
     const Vector<String>& disabled_features,
     FormAssociationFlag form_association_flag)
-    : descriptor_(descriptor),
+    : registry_(registry),
+      descriptor_(descriptor),
       observed_attributes_(observed_attributes),
       has_style_attribute_changed_callback_(
           observed_attributes.Contains(html_names::kStyleAttr.LocalName())),
@@ -37,7 +42,7 @@
 CustomElementDefinition::~CustomElementDefinition() = default;
 
 void CustomElementDefinition::Trace(Visitor* visitor) const {
-  visitor->Trace(construction_stack_);
+  visitor->Trace(registry_);
   ElementRareDataField::Trace(visitor);
 }
 
@@ -174,22 +179,6 @@
   return element;
 }
 
-CustomElementDefinition::ConstructionStackScope::ConstructionStackScope(
-    CustomElementDefinition& definition,
-    Element& element)
-    : construction_stack_(definition.construction_stack_), element_(&element) {
-  // Push the construction stack.
-  construction_stack_.push_back(&element);
-  depth_ = construction_stack_.size();
-}
-
-CustomElementDefinition::ConstructionStackScope::~ConstructionStackScope() {
-  // Pop the construction stack.
-  DCHECK(!construction_stack_.back() || construction_stack_.back() == element_);
-  DCHECK_EQ(construction_stack_.size(), depth_);  // It's a *stack*.
-  construction_stack_.pop_back();
-}
-
 // https://html.spec.whatwg.org/C/#concept-upgrade-an-element
 void CustomElementDefinition::Upgrade(Element& element) {
   // 4.13.5.1 If element's custom element state is not "undefined" or
@@ -218,7 +207,8 @@
   bool succeeded = false;
   {
     // 4.13.5.6: Add element to the end of definition's construction stack.
-    ConstructionStackScope construction_stack_scope(*this, element);
+    CustomElementConstructionStackScope construction_stack_scope(*this,
+                                                                 element);
     // 4.13.5.8: Run the constructor, catching exceptions.
     succeeded = RunConstructor(element);
   }
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_definition.h b/third_party/blink/renderer/core/html/custom/custom_element_definition.h
index e4637d0..0749e399 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_definition.h
+++ b/third_party/blink/renderer/core/html/custom/custom_element_definition.h
@@ -25,6 +25,7 @@
 class HTMLElement;
 class HTMLFormElement;
 class QualifiedName;
+class V8CustomElementConstructor;
 
 enum class FormAssociationFlag {
   kNo,
@@ -45,6 +46,8 @@
     return "CustomElementDefinition";
   }
 
+  CustomElementRegistry& GetRegistry() { return *registry_; }
+
   const CustomElementDescriptor& Descriptor() { return descriptor_; }
 
   // TODO(yosin): To support Web Modules, introduce an abstract
@@ -55,8 +58,7 @@
   // CustomElementConstructor|.
   virtual ScriptValue GetConstructorForScript() = 0;
 
-  using ConstructionStack = HeapVector<Member<Element>, 1>;
-  ConstructionStack& GetConstructionStack() { return construction_stack_; }
+  virtual V8CustomElementConstructor* GetV8CustomElementConstructor() = 0;
 
   HTMLElement* CreateElementForConstructor(Document&);
   virtual HTMLElement* CreateAutonomousCustomElementSync(
@@ -110,25 +112,12 @@
   bool DisableInternals() const { return disable_internals_; }
   bool IsFormAssociated() const { return is_form_associated_; }
 
-  class CORE_EXPORT ConstructionStackScope final {
-    STACK_ALLOCATED();
-
-   public:
-    ConstructionStackScope(CustomElementDefinition&, Element&);
-    ConstructionStackScope(const ConstructionStackScope&) = delete;
-    ConstructionStackScope& operator=(const ConstructionStackScope&) = delete;
-    ~ConstructionStackScope();
-
-   private:
-    ConstructionStack& construction_stack_;
-    Element* element_;
-    size_t depth_;
-  };
-
  protected:
-  CustomElementDefinition(const CustomElementDescriptor&);
+  CustomElementDefinition(CustomElementRegistry&,
+                          const CustomElementDescriptor&);
 
-  CustomElementDefinition(const CustomElementDescriptor&,
+  CustomElementDefinition(CustomElementRegistry&,
+                          const CustomElementDescriptor&,
                           const HashSet<AtomicString>& observed_attributes,
                           const Vector<String>& disabled_features,
                           FormAssociationFlag form_association_flag);
@@ -141,8 +130,8 @@
                                      ExceptionState&);
 
  private:
+  Member<CustomElementRegistry> registry_;
   const CustomElementDescriptor descriptor_;
-  ConstructionStack construction_stack_;
   HashSet<AtomicString> observed_attributes_;
   bool has_style_attribute_changed_callback_;
   bool disable_shadow_ = false;
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc b/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc
index 1775c02..22ae47a6 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_definition_test.cc
@@ -31,6 +31,7 @@
 }  // namespace
 
 TEST_F(CustomElementDefinitionTest, upgrade_clearsReactionQueueOnFailure) {
+  CustomElementTestingScope testing_scope;
   Element& element = *CreateElement("a-a").InDocument(&GetDocument());
   EXPECT_EQ(CustomElementState::kUndefined, element.GetCustomElementState())
       << "sanity check: this element should be ready to upgrade";
@@ -53,6 +54,7 @@
 
 TEST_F(CustomElementDefinitionTest,
        upgrade_clearsReactionQueueOnFailure_backupStack) {
+  CustomElementTestingScope testing_scope;
   Element& element = *CreateElement("a-a").InDocument(&GetDocument());
   EXPECT_EQ(CustomElementState::kUndefined, element.GetCustomElementState())
       << "sanity check: this element should be ready to upgrade";
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc b/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
index 79679c9..a3001618 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_reaction_queue_test.cc
@@ -15,6 +15,7 @@
 namespace blink {
 
 TEST(CustomElementReactionQueueTest, invokeReactions_one) {
+  CustomElementTestingScope testing_scope;
   Vector<char> log;
   CustomElementReactionQueue* queue =
       MakeGarbageCollected<CustomElementReactionQueue>();
@@ -28,6 +29,7 @@
 }
 
 TEST(CustomElementReactionQueueTest, invokeReactions_many) {
+  CustomElementTestingScope testing_scope;
   Vector<char> log;
   CustomElementReactionQueue* queue =
       MakeGarbageCollected<CustomElementReactionQueue>();
@@ -53,6 +55,7 @@
 }
 
 TEST(CustomElementReactionQueueTest, invokeReactions_recursive) {
+  CustomElementTestingScope testing_scope;
   Vector<char> log;
   CustomElementReactionQueue* queue =
       MakeGarbageCollected<CustomElementReactionQueue>();
@@ -84,6 +87,7 @@
 }
 
 TEST(CustomElementReactionQueueTest, clear_duringInvoke) {
+  CustomElementTestingScope testing_scope;
   Vector<char> log;
   CustomElementReactionQueue* queue =
       MakeGarbageCollected<CustomElementReactionQueue>();
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc b/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
index 394d750..8b852f3 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_reaction_stack_test.cc
@@ -17,6 +17,7 @@
 
 TEST(CustomElementReactionStackTest, one) {
   Vector<char> log;
+  CustomElementTestingScope testing_scope;
   ScopedNullExecutionContext execution_context;
 
   CustomElementReactionStack* stack =
@@ -36,6 +37,7 @@
 
 TEST(CustomElementReactionStackTest, multipleElements) {
   Vector<char> log;
+  CustomElementTestingScope testing_scope;
   ScopedNullExecutionContext execution_context;
 
   CustomElementReactionStack* stack =
@@ -64,6 +66,7 @@
 
 TEST(CustomElementReactionStackTest, popTopEmpty) {
   Vector<char> log;
+  CustomElementTestingScope testing_scope;
   ScopedNullExecutionContext execution_context;
 
   CustomElementReactionStack* stack =
@@ -84,6 +87,7 @@
 
 TEST(CustomElementReactionStackTest, popTop) {
   Vector<char> log;
+  CustomElementTestingScope testing_scope;
   ScopedNullExecutionContext execution_context;
 
   CustomElementReactionStack* stack =
@@ -113,6 +117,7 @@
 
 TEST(CustomElementReactionStackTest, requeueingDoesNotReorderElements) {
   Vector<char> log;
+  CustomElementTestingScope testing_scope;
 
   Element& element = *CreateElement("a");
   ScopedNullExecutionContext execution_context;
@@ -148,6 +153,7 @@
 
 TEST(CustomElementReactionStackTest, oneReactionQueuePerElement) {
   Vector<char> log;
+  CustomElementTestingScope testing_scope;
 
   Element& element = *CreateElement("a");
 
@@ -221,6 +227,7 @@
 
 TEST(CustomElementReactionStackTest, enqueueFromReaction) {
   Vector<char> log;
+  CustomElementTestingScope testing_scope;
 
   Element& element = *CreateElement("a");
   ScopedNullExecutionContext execution_context;
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
index 0528d784..fba98e1 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
@@ -283,17 +283,9 @@
 
 CustomElementDefinition* CustomElementRegistry::DefinitionForConstructor(
     v8::Local<v8::Object> constructor) const {
-  struct HashTranslator {
-    STATIC_ONLY(HashTranslator);
-    static unsigned GetHash(const v8::Local<v8::Object>& constructor) {
-      return constructor->GetIdentityHash();
-    }
-    static bool Equal(const Member<V8CustomElementConstructor>& a,
-                      const v8::Local<v8::Object>& b) {
-      return a && a->CallbackObject() == b;
-    }
-  };
-  const auto it = constructor_map_.Find<HashTranslator>(constructor);
+  const auto it =
+      constructor_map_.Find<V8CustomElementConstructorHashTranslator>(
+          constructor);
   if (it == constructor_map_.end())
     return nullptr;
   return it->value;
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry.h b/third_party/blink/renderer/core/html/custom/custom_element_registry.h
index ae19553..d662c40 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_registry.h
+++ b/third_party/blink/renderer/core/html/custom/custom_element_registry.h
@@ -8,6 +8,7 @@
 #include "base/gtest_prod_util.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_constructor.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_constructor_hash.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -66,6 +67,8 @@
                             ExceptionState&);
   void upgrade(Node* root);
 
+  const LocalDOMWindow* GetOwnerWindow() const { return owner_; }
+
   void Trace(Visitor*) const override;
 
  private:
@@ -80,19 +83,6 @@
 
   bool element_definition_is_running_;
 
-  // Hashes Member<V8CustomElementConstructor> by their v8 callback objects.
-  struct V8CustomElementConstructorHashTraits
-      : WTF::MemberHashTraits<V8CustomElementConstructor> {
-    static unsigned GetHash(
-        const Member<V8CustomElementConstructor>& constructor) {
-      return constructor->CallbackObject()->GetIdentityHash();
-    }
-    static bool Equal(const Member<V8CustomElementConstructor>& a,
-                      const Member<V8CustomElementConstructor>& b) {
-      return a->CallbackObject() == b->CallbackObject();
-    }
-    static constexpr bool kSafeToCompareToEmptyOrDeleted = false;
-  };
   using ConstructorMap = HeapHashMap<Member<V8CustomElementConstructor>,
                                      Member<CustomElementDefinition>,
                                      V8CustomElementConstructorHashTraits>;
@@ -115,7 +105,7 @@
   FRIEND_TEST_ALL_PREFIXES(
       CustomElementTest,
       CreateElement_TagNameCaseHandlingCreatingCustomElement);
-  friend class CustomElementRegistryTestingScope;
+  friend class CustomElementRegistryTest;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc b/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc
index 1d30ec7..527cf94 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_registry_test.cc
@@ -7,7 +7,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/web/web_custom_element.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_css_style_sheet_init.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_element_definition_options.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_shadow_root_init.h"
@@ -32,12 +31,18 @@
 
 namespace blink {
 
-class CustomElementRegistryTestingScope : public V8TestingScope {
-  STACK_ALLOCATED();
-
+class CustomElementRegistryTest : public ::testing::Test {
  public:
   CustomElementRegistry& Registry() {
-    return *GetFrame().DomWindow()->customElements();
+    return CustomElementTestingScope::GetInstance().Registry();
+  }
+
+  ScriptState* GetScriptState() {
+    return CustomElementTestingScope::GetInstance().GetScriptState();
+  }
+
+  Document& GetDocument() {
+    return CustomElementTestingScope::GetInstance().GetDocument();
   }
 
   CustomElementDefinition* Define(const AtomicString& name,
@@ -54,16 +59,14 @@
   }
 };
 
-TEST(CustomElementRegistryTest,
-     collectCandidates_shouldNotIncludeElementsRemovedFromDocument) {
-  CustomElementRegistryTestingScope testing_scope;
-  Element& element =
-      *CreateElement("a-a").InDocument(&testing_scope.GetDocument());
-  testing_scope.Registry().AddCandidate(element);
+TEST_F(CustomElementRegistryTest,
+       collectCandidates_shouldNotIncludeElementsRemovedFromDocument) {
+  CustomElementTestingScope testing_scope;
+  Element& element = *CreateElement("a-a").InDocument(&GetDocument());
+  Registry().AddCandidate(element);
 
   HeapVector<Member<Element>> elements;
-  testing_scope.CollectCandidates(CustomElementDescriptor("a-a", "a-a"),
-                                  &elements);
+  CollectCandidates(CustomElementDescriptor("a-a", "a-a"), &elements);
 
   EXPECT_TRUE(elements.empty())
       << "no candidates should have been found, but we have "
@@ -72,12 +75,11 @@
       << "the out-of-document candidate should not have been found";
 }
 
-TEST(CustomElementRegistryTest,
-     collectCandidates_shouldNotIncludeElementsInDifferentDocument) {
-  CustomElementRegistryTestingScope testing_scope;
-  Element* element =
-      CreateElement("a-a").InDocument(&testing_scope.GetDocument());
-  testing_scope.Registry().AddCandidate(*element);
+TEST_F(CustomElementRegistryTest,
+       collectCandidates_shouldNotIncludeElementsInDifferentDocument) {
+  CustomElementTestingScope testing_scope;
+  Element* element = CreateElement("a-a").InDocument(&GetDocument());
+  Registry().AddCandidate(*element);
 
   ScopedNullExecutionContext execution_context;
   auto* other_document =
@@ -87,8 +89,7 @@
       << "sanity: another document should have adopted an element on append";
 
   HeapVector<Member<Element>> elements;
-  testing_scope.CollectCandidates(CustomElementDescriptor("a-a", "a-a"),
-                                  &elements);
+  CollectCandidates(CustomElementDescriptor("a-a", "a-a"), &elements);
 
   EXPECT_TRUE(elements.empty())
       << "no candidates should have been found, but we have "
@@ -97,32 +98,31 @@
       << "the adopted-away candidate should not have been found";
 }
 
-TEST(CustomElementRegistryTest,
-     collectCandidates_shouldOnlyIncludeCandidatesMatchingDescriptor) {
-  CustomElementRegistryTestingScope testing_scope;
+TEST_F(CustomElementRegistryTest,
+       collectCandidates_shouldOnlyIncludeCandidatesMatchingDescriptor) {
+  CustomElementTestingScope testing_scope;
   CustomElementDescriptor descriptor("hello-world", "hello-world");
 
   // Does not match: namespace is not HTML
   Element& element_a = *CreateElement("hello-world")
-                            .InDocument(&testing_scope.GetDocument())
+                            .InDocument(&GetDocument())
                             .InNamespace("data:text/date,1981-03-10");
   // Matches
-  Element& element_b =
-      *CreateElement("hello-world").InDocument(&testing_scope.GetDocument());
+  Element& element_b = *CreateElement("hello-world").InDocument(&GetDocument());
   // Does not match: local name is not hello-world
   Element& element_c = *CreateElement("button")
-                            .InDocument(&testing_scope.GetDocument())
+                            .InDocument(&GetDocument())
                             .WithIsValue("hello-world");
-  testing_scope.GetDocument().documentElement()->AppendChild(&element_a);
+  GetDocument().documentElement()->AppendChild(&element_a);
   element_a.AppendChild(&element_b);
   element_a.AppendChild(&element_c);
 
-  testing_scope.Registry().AddCandidate(element_a);
-  testing_scope.Registry().AddCandidate(element_b);
-  testing_scope.Registry().AddCandidate(element_c);
+  Registry().AddCandidate(element_a);
+  Registry().AddCandidate(element_b);
+  Registry().AddCandidate(element_c);
 
   HeapVector<Member<Element>> elements;
-  testing_scope.CollectCandidates(descriptor, &elements);
+  CollectCandidates(descriptor, &elements);
 
   EXPECT_EQ(1u, elements.size())
       << "only one candidates should have been found";
@@ -130,16 +130,14 @@
       << "the matching element should have been found";
 }
 
-TEST(CustomElementRegistryTest, collectCandidates_oneCandidate) {
-  CustomElementRegistryTestingScope testing_scope;
-  Element& element =
-      *CreateElement("a-a").InDocument(&testing_scope.GetDocument());
-  testing_scope.Registry().AddCandidate(element);
-  testing_scope.GetDocument().documentElement()->AppendChild(&element);
+TEST_F(CustomElementRegistryTest, collectCandidates_oneCandidate) {
+  CustomElementTestingScope testing_scope;
+  Element& element = *CreateElement("a-a").InDocument(&GetDocument());
+  Registry().AddCandidate(element);
+  GetDocument().documentElement()->AppendChild(&element);
 
   HeapVector<Member<Element>> elements;
-  testing_scope.CollectCandidates(CustomElementDescriptor("a-a", "a-a"),
-                                  &elements);
+  CollectCandidates(CustomElementDescriptor("a-a", "a-a"), &elements);
 
   EXPECT_EQ(1u, elements.size())
       << "exactly one candidate should have been found";
@@ -147,25 +145,24 @@
       << "the candidate should be the element that was added";
 }
 
-TEST(CustomElementRegistryTest, collectCandidates_shouldBeInDocumentOrder) {
-  CustomElementRegistryTestingScope testing_scope;
+TEST_F(CustomElementRegistryTest, collectCandidates_shouldBeInDocumentOrder) {
+  CustomElementTestingScope testing_scope;
   CreateElement factory = CreateElement("a-a");
-  factory.InDocument(&testing_scope.GetDocument());
+  factory.InDocument(&GetDocument());
   Element* element_a = factory.WithId("a");
   Element* element_b = factory.WithId("b");
   Element* element_c = factory.WithId("c");
 
-  testing_scope.Registry().AddCandidate(*element_b);
-  testing_scope.Registry().AddCandidate(*element_a);
-  testing_scope.Registry().AddCandidate(*element_c);
+  Registry().AddCandidate(*element_b);
+  Registry().AddCandidate(*element_a);
+  Registry().AddCandidate(*element_c);
 
-  testing_scope.GetDocument().documentElement()->AppendChild(element_a);
+  GetDocument().documentElement()->AppendChild(element_a);
   element_a->AppendChild(element_b);
-  testing_scope.GetDocument().documentElement()->AppendChild(element_c);
+  GetDocument().documentElement()->AppendChild(element_c);
 
   HeapVector<Member<Element>> elements;
-  testing_scope.CollectCandidates(CustomElementDescriptor("a-a", "a-a"),
-                                  &elements);
+  CollectCandidates(CustomElementDescriptor("a-a", "a-a"), &elements);
 
   EXPECT_EQ(element_a, elements[0].Get());
   EXPECT_EQ(element_b, elements[1].Get());
@@ -176,11 +173,15 @@
 // traceImpl template.
 class LogUpgradeDefinition : public TestCustomElementDefinition {
  public:
-  LogUpgradeDefinition(const CustomElementDescriptor& descriptor)
+  LogUpgradeDefinition(const CustomElementDescriptor& descriptor,
+                       V8CustomElementConstructor* constructor)
       : TestCustomElementDefinition(
             descriptor,
+            constructor,
             {
-                "attr1", "attr2", html_names::kContenteditableAttr.LocalName(),
+                "attr1",
+                "attr2",
+                html_names::kContenteditableAttr.LocalName(),
             },
             {}) {}
   LogUpgradeDefinition(const LogUpgradeDefinition&) = delete;
@@ -272,37 +273,36 @@
   STACK_ALLOCATED();
 
  public:
-  explicit LogUpgradeBuilder(ScriptState* script_state)
-      : TestCustomElementDefinitionBuilder(script_state) {}
+  LogUpgradeBuilder() = default;
   LogUpgradeBuilder(const LogUpgradeBuilder&) = delete;
   LogUpgradeBuilder& operator=(const LogUpgradeBuilder&) = delete;
 
   CustomElementDefinition* Build(
       const CustomElementDescriptor& descriptor) override {
-    return MakeGarbageCollected<LogUpgradeDefinition>(descriptor);
+    return MakeGarbageCollected<LogUpgradeDefinition>(descriptor,
+                                                      Constructor());
   }
 };
 
-TEST(CustomElementRegistryTest, define_upgradesInDocumentElements) {
-  CustomElementRegistryTestingScope testing_scope;
+TEST_F(CustomElementRegistryTest, define_upgradesInDocumentElements) {
+  CustomElementTestingScope testing_scope;
   ScriptForbiddenScope do_not_rely_on_script;
 
-  Element* element =
-      CreateElement("a-a").InDocument(&testing_scope.GetDocument());
+  Element* element = CreateElement("a-a").InDocument(&GetDocument());
   element->setAttribute(
       QualifiedName(g_null_atom, "attr1", html_names::xhtmlNamespaceURI), "v1");
   element->SetBooleanAttribute(html_names::kContenteditableAttr, true);
-  testing_scope.GetDocument().documentElement()->AppendChild(element);
+  GetDocument().documentElement()->AppendChild(element);
 
-  LogUpgradeBuilder builder(testing_scope.GetScriptState());
+  LogUpgradeBuilder builder;
   NonThrowableExceptionState should_not_throw;
   {
     CEReactionsScope reactions;
-    testing_scope.Define("a-a", builder, ElementDefinitionOptions::Create(),
-                         should_not_throw);
+    Define("a-a", builder, ElementDefinitionOptions::Create(),
+           should_not_throw);
   }
-  LogUpgradeDefinition* definition = static_cast<LogUpgradeDefinition*>(
-      testing_scope.Registry().DefinitionForName("a-a"));
+  LogUpgradeDefinition* definition =
+      static_cast<LogUpgradeDefinition*>(Registry().DefinitionForName("a-a"));
   EXPECT_EQ(LogUpgradeDefinition::kConstructor, definition->logs_[0])
       << "defining the element should have 'upgraded' the existing element";
   EXPECT_EQ(element, definition->element_)
@@ -331,23 +331,22 @@
       << "upgrade should not invoke other callbacks";
 }
 
-TEST(CustomElementRegistryTest, attributeChangedCallback) {
-  CustomElementRegistryTestingScope testing_scope;
+TEST_F(CustomElementRegistryTest, attributeChangedCallback) {
+  CustomElementTestingScope testing_scope;
   ScriptForbiddenScope do_not_rely_on_script;
 
-  Element* element =
-      CreateElement("a-a").InDocument(&testing_scope.GetDocument());
-  testing_scope.GetDocument().documentElement()->AppendChild(element);
+  Element* element = CreateElement("a-a").InDocument(&GetDocument());
+  GetDocument().documentElement()->AppendChild(element);
 
-  LogUpgradeBuilder builder(testing_scope.GetScriptState());
+  LogUpgradeBuilder builder;
   NonThrowableExceptionState should_not_throw;
   {
     CEReactionsScope reactions;
-    testing_scope.Define("a-a", builder, ElementDefinitionOptions::Create(),
-                         should_not_throw);
+    Define("a-a", builder, ElementDefinitionOptions::Create(),
+           should_not_throw);
   }
-  LogUpgradeDefinition* definition = static_cast<LogUpgradeDefinition*>(
-      testing_scope.Registry().DefinitionForName("a-a"));
+  LogUpgradeDefinition* definition =
+      static_cast<LogUpgradeDefinition*>(Registry().DefinitionForName("a-a"));
 
   definition->Clear();
   {
@@ -369,23 +368,22 @@
       << "upgrade should not invoke other callbacks";
 }
 
-TEST(CustomElementRegistryTest, disconnectedCallback) {
-  CustomElementRegistryTestingScope testing_scope;
+TEST_F(CustomElementRegistryTest, disconnectedCallback) {
+  CustomElementTestingScope testing_scope;
   ScriptForbiddenScope do_not_rely_on_script;
 
-  Element* element =
-      CreateElement("a-a").InDocument(&testing_scope.GetDocument());
-  testing_scope.GetDocument().documentElement()->AppendChild(element);
+  Element* element = CreateElement("a-a").InDocument(&GetDocument());
+  GetDocument().documentElement()->AppendChild(element);
 
-  LogUpgradeBuilder builder(testing_scope.GetScriptState());
+  LogUpgradeBuilder builder;
   NonThrowableExceptionState should_not_throw;
   {
     CEReactionsScope reactions;
-    testing_scope.Define("a-a", builder, ElementDefinitionOptions::Create(),
-                         should_not_throw);
+    Define("a-a", builder, ElementDefinitionOptions::Create(),
+           should_not_throw);
   }
-  LogUpgradeDefinition* definition = static_cast<LogUpgradeDefinition*>(
-      testing_scope.Registry().DefinitionForName("a-a"));
+  LogUpgradeDefinition* definition =
+      static_cast<LogUpgradeDefinition*>(Registry().DefinitionForName("a-a"));
 
   definition->Clear();
   {
@@ -399,27 +397,26 @@
       << "remove() should not invoke other callbacks";
 }
 
-TEST(CustomElementRegistryTest, adoptedCallback) {
-  CustomElementRegistryTestingScope testing_scope;
+TEST_F(CustomElementRegistryTest, adoptedCallback) {
+  CustomElementTestingScope testing_scope;
   ScriptForbiddenScope do_not_rely_on_script;
 
-  Element* element =
-      CreateElement("a-a").InDocument(&testing_scope.GetDocument());
-  testing_scope.GetDocument().documentElement()->AppendChild(element);
+  Element* element = CreateElement("a-a").InDocument(&GetDocument());
+  GetDocument().documentElement()->AppendChild(element);
 
-  LogUpgradeBuilder builder(testing_scope.GetScriptState());
+  LogUpgradeBuilder builder;
   NonThrowableExceptionState should_not_throw;
   {
     CEReactionsScope reactions;
-    testing_scope.Define("a-a", builder, ElementDefinitionOptions::Create(),
-                         should_not_throw);
+    Define("a-a", builder, ElementDefinitionOptions::Create(),
+           should_not_throw);
   }
-  LogUpgradeDefinition* definition = static_cast<LogUpgradeDefinition*>(
-      testing_scope.Registry().DefinitionForName("a-a"));
+  LogUpgradeDefinition* definition =
+      static_cast<LogUpgradeDefinition*>(Registry().DefinitionForName("a-a"));
 
   definition->Clear();
-  auto* other_document = HTMLDocument::CreateForTest(
-      *testing_scope.GetDocument().GetExecutionContext());
+  auto* other_document =
+      HTMLDocument::CreateForTest(*GetDocument().GetExecutionContext());
   {
     CEReactionsScope reactions;
     other_document->adoptNode(element, ASSERT_NO_EXCEPTION);
@@ -430,8 +427,7 @@
   EXPECT_EQ(LogUpgradeDefinition::kAdoptedCallback, definition->logs_[1])
       << "adoptNode() should invoke adoptedCallback";
 
-  EXPECT_EQ(&testing_scope.GetDocument(),
-            definition->adopted_[0]->old_owner_.Get())
+  EXPECT_EQ(GetDocument(), definition->adopted_[0]->old_owner_.Get())
       << "adoptedCallback should have been passed the old owner document";
   EXPECT_EQ(other_document, definition->adopted_[0]->new_owner_.Get())
       << "adoptedCallback should have been passed the new owner document";
@@ -440,53 +436,50 @@
       << "adoptNode() should not invoke other callbacks";
 }
 
-TEST(CustomElementRegistryTest, lookupCustomElementDefinition) {
-  CustomElementRegistryTestingScope testing_scope;
+TEST_F(CustomElementRegistryTest, lookupCustomElementDefinition) {
+  CustomElementTestingScope testing_scope;
   NonThrowableExceptionState should_not_throw;
-  TestCustomElementDefinitionBuilder builder_a(testing_scope.GetScriptState());
-  CustomElementDefinition* definition_a = testing_scope.Define(
+  TestCustomElementDefinitionBuilder builder_a;
+  CustomElementDefinition* definition_a = Define(
       "a-a", builder_a, ElementDefinitionOptions::Create(), should_not_throw);
-  TestCustomElementDefinitionBuilder builder_b(testing_scope.GetScriptState());
+  TestCustomElementDefinitionBuilder builder_b;
   ElementDefinitionOptions* options = ElementDefinitionOptions::Create();
   options->setExtends("div");
   CustomElementDefinition* definition_b =
-      testing_scope.Define("b-b", builder_b, options, should_not_throw);
+      Define("b-b", builder_b, options, should_not_throw);
   // look up defined autonomous custom element
-  CustomElementDefinition* definition = testing_scope.Registry().DefinitionFor(
+  CustomElementDefinition* definition = Registry().DefinitionFor(
       CustomElementDescriptor(CustomElementDescriptor("a-a", "a-a")));
   EXPECT_NE(nullptr, definition) << "a-a, a-a should be registered";
   EXPECT_EQ(definition_a, definition);
   // look up undefined autonomous custom element
-  definition = testing_scope.Registry().DefinitionFor(
-      CustomElementDescriptor("a-a", "div"));
+  definition = Registry().DefinitionFor(CustomElementDescriptor("a-a", "div"));
   EXPECT_EQ(nullptr, definition) << "a-a, div should not be registered";
   // look up defined customized built-in element
-  definition = testing_scope.Registry().DefinitionFor(
-      CustomElementDescriptor("b-b", "div"));
+  definition = Registry().DefinitionFor(CustomElementDescriptor("b-b", "div"));
   EXPECT_NE(nullptr, definition) << "b-b, div should be registered";
   EXPECT_EQ(definition_b, definition);
   // look up undefined customized built-in element
-  definition = testing_scope.Registry().DefinitionFor(
-      CustomElementDescriptor("a-a", "div"));
+  definition = Registry().DefinitionFor(CustomElementDescriptor("a-a", "div"));
   EXPECT_EQ(nullptr, definition) << "a-a, div should not be registered";
 }
 
 // The embedder may define its own elements via the CustomElementRegistry
 // whose names are not valid custom element names. Ensure that such a definition
 // may be done.
-TEST(CustomElementRegistryTest, DefineEmbedderCustomElements) {
-  CustomElementRegistryTestingScope testing_scope;
+TEST_F(CustomElementRegistryTest, DefineEmbedderCustomElements) {
+  CustomElementTestingScope testing_scope;
   CustomElement::AddEmbedderCustomElementName("embeddercustomelement");
 
   WebCustomElement::EmbedderNamesAllowedScope embedder_names_scope;
 
   NonThrowableExceptionState should_not_throw;
-  TestCustomElementDefinitionBuilder builder(testing_scope.GetScriptState());
-  CustomElementDefinition* definition_embedder = testing_scope.Define(
-      "embeddercustomelement", builder, ElementDefinitionOptions::Create(),
-      should_not_throw);
+  TestCustomElementDefinitionBuilder builder;
+  CustomElementDefinition* definition_embedder =
+      Define("embeddercustomelement", builder,
+             ElementDefinitionOptions::Create(), should_not_throw);
   CustomElementDefinition* definition =
-      testing_scope.Registry().DefinitionFor(CustomElementDescriptor(
+      Registry().DefinitionFor(CustomElementDescriptor(
           "embeddercustomelement", "embeddercustomelement"));
   EXPECT_NE(nullptr, definition)
       << "embeddercustomelement, embeddercustomelement should be registered";
@@ -497,19 +490,19 @@
 // be used for a custom element definition, the caller of |define| may disallow
 // the use of the invalid name (so that we don't expose the ability to use such
 // a name to the web).
-TEST(CustomElementRegistryTest, DisallowedEmbedderCustomElements) {
-  CustomElementRegistryTestingScope testing_scope;
+TEST_F(CustomElementRegistryTest, DisallowedEmbedderCustomElements) {
+  CustomElementTestingScope testing_scope;
   CustomElement::AddEmbedderCustomElementName("embeddercustomelement");
 
   // Without a WebCustomElement::EmbedderNamesAllowedScope, this registration
   // is disallowed.
 
-  TestCustomElementDefinitionBuilder builder(testing_scope.GetScriptState());
-  CustomElementDefinition* definition_embedder = testing_scope.Define(
-      "embeddercustomelement", builder, ElementDefinitionOptions::Create(),
-      IGNORE_EXCEPTION_FOR_TESTING);
+  TestCustomElementDefinitionBuilder builder;
+  CustomElementDefinition* definition_embedder =
+      Define("embeddercustomelement", builder,
+             ElementDefinitionOptions::Create(), IGNORE_EXCEPTION_FOR_TESTING);
   CustomElementDefinition* definition =
-      testing_scope.Registry().DefinitionFor(CustomElementDescriptor(
+      Registry().DefinitionFor(CustomElementDescriptor(
           "embeddercustomelement", "embeddercustomelement"));
   EXPECT_EQ(nullptr, definition) << "embeddercustomelement, "
                                     "embeddercustomelement should not be "
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_test.cc b/third_party/blink/renderer/core/html/custom/custom_element_test.cc
index d947d3a..9bf10635 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_test.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_test.cc
@@ -209,7 +209,7 @@
 
 TEST(CustomElementTest,
      CreateElement_TagNameCaseHandlingCreatingCustomElement) {
-  V8TestingScope scope;
+  CustomElementTestingScope scope;
   // register a definition
   ScriptState* script_state = scope.GetScriptState();
   CustomElementRegistry* registry =
@@ -217,7 +217,7 @@
   NonThrowableExceptionState should_not_throw;
   {
     CEReactionsScope reactions;
-    TestCustomElementDefinitionBuilder builder(script_state);
+    TestCustomElementDefinitionBuilder builder;
     registry->DefineInternal(script_state, "a-a", builder,
                              ElementDefinitionOptions::Create(),
                              should_not_throw);
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.cc b/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.cc
index 7c9387f6..7ec5916 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.cc
@@ -5,19 +5,76 @@
 #include "third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/v8_custom_element_constructor.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_construction_stack.h"
 
 namespace blink {
 
-TestCustomElementDefinitionBuilder::TestCustomElementDefinitionBuilder(
-    ScriptState* script_state) {
-  // Create a fake v8 constructor callback that should never be invoked.
-  constructor_ = V8CustomElementConstructor::Create(
+namespace {
+
+// Creates a mock custom element constructor that has a callback object to be
+// hashed, but should never be be invoked.
+V8CustomElementConstructor* CreateMockConstructor() {
+  ScriptState* script_state =
+      CustomElementTestingScope::GetInstance().GetScriptState();
+  return V8CustomElementConstructor::Create(
       v8::Object::New(script_state->GetIsolate()));
 }
 
+}  // namespace
+
+CustomElementTestingScope* CustomElementTestingScope::instance_ = nullptr;
+
+CustomElementRegistry& CustomElementTestingScope::Registry() {
+  return *GetFrame().DomWindow()->customElements();
+}
+
+TestCustomElementDefinitionBuilder::TestCustomElementDefinitionBuilder()
+    : constructor_(CreateMockConstructor()) {}
+
 CustomElementDefinition* TestCustomElementDefinitionBuilder::Build(
     const CustomElementDescriptor& descriptor) {
-  return MakeGarbageCollected<TestCustomElementDefinition>(descriptor);
+  DCHECK(constructor_);
+  return MakeGarbageCollected<TestCustomElementDefinition>(descriptor,
+                                                           constructor_);
+}
+
+TestCustomElementDefinition::TestCustomElementDefinition(
+    const CustomElementDescriptor& descriptor)
+    : TestCustomElementDefinition(descriptor, CreateMockConstructor()) {}
+
+TestCustomElementDefinition::TestCustomElementDefinition(
+    const CustomElementDescriptor& descriptor,
+    V8CustomElementConstructor* constructor)
+    : CustomElementDefinition(
+          CustomElementTestingScope::GetInstance().Registry(),
+          descriptor),
+      constructor_(constructor) {}
+
+TestCustomElementDefinition::TestCustomElementDefinition(
+    const CustomElementDescriptor& descriptor,
+    V8CustomElementConstructor* constructor,
+    HashSet<AtomicString>&& observed_attributes,
+    const Vector<String>& disabled_features)
+    : CustomElementDefinition(
+          CustomElementTestingScope::GetInstance().Registry(),
+          descriptor,
+          std::move(observed_attributes),
+          disabled_features,
+          FormAssociationFlag::kNo),
+      constructor_(constructor) {}
+
+bool TestCustomElementDefinition::RunConstructor(Element& element) {
+  CustomElementConstructionStack* construction_stack =
+      GetCustomElementConstructionStack(GetRegistry().GetOwnerWindow(),
+                                        constructor_->CallbackObject());
+  if (!construction_stack || construction_stack->empty() ||
+      construction_stack->back() != &element) {
+    return false;
+  }
+  construction_stack->back().Clear();
+  return true;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h b/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h
index cc75dea..9f24a48 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h
+++ b/third_party/blink/renderer/core/html/custom/custom_element_test_helpers.h
@@ -7,12 +7,14 @@
 
 #include <utility>
 
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/qualified_name.h"
 #include "third_party/blink/renderer/core/html/custom/ce_reactions_scope.h"
 #include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
 #include "third_party/blink/renderer/core/html/custom/custom_element_definition_builder.h"
+#include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
 #include "third_party/blink/renderer/core/html/html_document.h"
 #include "third_party/blink/renderer/core/testing/null_execution_context.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -20,14 +22,38 @@
 
 namespace blink {
 
-class CustomElementDescriptor;
+// Supports creating test custom element definitions to be added into the global
+// registry. Does not support scoped registries.
+class CustomElementTestingScope : public V8TestingScope {
+  STACK_ALLOCATED();
+
+ public:
+  static CustomElementTestingScope& GetInstance() {
+    DCHECK(instance_)
+        << "Custom element unit tests require CustomElementTestingScope";
+    return *instance_;
+  }
+
+  CustomElementTestingScope() {
+    // We should never create nested testing scopes.
+    DCHECK(!instance_);
+    instance_ = this;
+  }
+
+  ~CustomElementTestingScope() { instance_ = nullptr; }
+
+  CustomElementRegistry& Registry();
+
+ private:
+  static CustomElementTestingScope* instance_;
+};
 
 class TestCustomElementDefinitionBuilder
     : public CustomElementDefinitionBuilder {
   STACK_ALLOCATED();
 
  public:
-  explicit TestCustomElementDefinitionBuilder(ScriptState*);
+  TestCustomElementDefinitionBuilder();
   TestCustomElementDefinitionBuilder(
       const TestCustomElementDefinitionBuilder&) = delete;
   TestCustomElementDefinitionBuilder& operator=(
@@ -45,16 +71,16 @@
 
 class TestCustomElementDefinition : public CustomElementDefinition {
  public:
-  TestCustomElementDefinition(const CustomElementDescriptor& descriptor)
-      : CustomElementDefinition(descriptor) {}
+  explicit TestCustomElementDefinition(
+      const CustomElementDescriptor& descriptor);
 
   TestCustomElementDefinition(const CustomElementDescriptor& descriptor,
+                              V8CustomElementConstructor* constructor);
+
+  TestCustomElementDefinition(const CustomElementDescriptor& descriptor,
+                              V8CustomElementConstructor* constructor,
                               HashSet<AtomicString>&& observed_attributes,
-                              const Vector<String>& disabled_features)
-      : CustomElementDefinition(descriptor,
-                                std::move(observed_attributes),
-                                disabled_features,
-                                FormAssociationFlag::kNo) {}
+                              const Vector<String>& disabled_features);
 
   TestCustomElementDefinition(const TestCustomElementDefinition&) = delete;
   TestCustomElementDefinition& operator=(const TestCustomElementDefinition&) =
@@ -62,16 +88,19 @@
 
   ~TestCustomElementDefinition() override = default;
 
+  void Trace(Visitor* visitor) const override {
+    visitor->Trace(constructor_);
+    CustomElementDefinition::Trace(visitor);
+  }
+
   ScriptValue GetConstructorForScript() override { return ScriptValue(); }
 
-  bool RunConstructor(Element& element) override {
-    if (GetConstructionStack().empty() ||
-        GetConstructionStack().back() != &element)
-      return false;
-    GetConstructionStack().back().Clear();
-    return true;
+  V8CustomElementConstructor* GetV8CustomElementConstructor() override {
+    return constructor_;
   }
 
+  bool RunConstructor(Element& element) override;
+
   HTMLElement* CreateAutonomousCustomElementSync(
       Document& document,
       const QualifiedName&) override {
@@ -124,6 +153,9 @@
                                    const String& mode) override {
     NOTREACHED() << "definition does not have restoreValueCallback";
   }
+
+ private:
+  Member<V8CustomElementConstructor> constructor_;
 };
 
 class CreateElement {
diff --git a/third_party/blink/renderer/core/html/fenced_frame/fence.cc b/third_party/blink/renderer/core/html/fenced_frame/fence.cc
index 2b3245c..34dd5f0 100644
--- a/third_party/blink/renderer/core/html/fenced_frame/fence.cc
+++ b/third_party/blink/renderer/core/html/fenced_frame/fence.cc
@@ -77,7 +77,8 @@
         "fully active");
     return;
   }
-  if (event->eventData().length() > blink::kFencedFrameMaxBeaconLength) {
+  if (event->hasEventData() &&
+      event->eventData().length() > blink::kFencedFrameMaxBeaconLength) {
     exception_state.ThrowSecurityError(
         "The data provided to reportEvent() exceeds the maximum length, which "
         "is 64KB.");
@@ -100,7 +101,7 @@
   for (const V8FenceReportingDestination& web_destination :
        event->destination()) {
     frame->GetLocalFrameHostRemote().SendFencedFrameReportingBeacon(
-        event->eventData(), event->eventType(),
+        event->getEventDataOr(String{""}), event->eventType(),
         ToPublicDestination(web_destination));
   }
 }
@@ -120,7 +121,8 @@
                       " is not a valid automatic beacon event type.");
     return;
   }
-  if (event->eventData().length() > blink::kFencedFrameMaxBeaconLength) {
+  if (event->hasEventData() &&
+      event->eventData().length() > blink::kFencedFrameMaxBeaconLength) {
     exception_state.ThrowSecurityError(
         "The data provided to setReportEventDataForAutomaticBeacons() exceeds "
         "the maximum length, which is 64KB.");
@@ -144,7 +146,7 @@
     destination_vector.push_back(ToPublicDestination(web_destination));
   }
   frame->GetLocalFrameHostRemote().SetFencedFrameAutomaticBeaconReportEventData(
-      event->eventData(), destination_vector);
+      event->getEventDataOr(String{""}), destination_vector);
 }
 
 HeapVector<Member<FencedFrameConfig>> Fence::getNestedConfigs(
diff --git a/third_party/blink/renderer/core/html/fenced_frame/fence_event.idl b/third_party/blink/renderer/core/html/fenced_frame/fence_event.idl
index 0bd23147..5f29bd6 100644
--- a/third_party/blink/renderer/core/html/fenced_frame/fence_event.idl
+++ b/third_party/blink/renderer/core/html/fenced_frame/fence_event.idl
@@ -12,6 +12,6 @@
 
 dictionary FenceEvent {
   required DOMString eventType;
-  required DOMString eventData;
+  DOMString eventData;
   required sequence<FenceReportingDestination> destination;
 };
diff --git a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
index 264efd4..7b3619d3 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
@@ -362,8 +362,9 @@
   if (!IsDisabledFormControl()) {
     auto popover = popoverTargetElement();
     if (popover.popover) {
+      auto& document = GetDocument();
       DCHECK(RuntimeEnabledFeatures::HTMLPopoverAttributeEnabled(
-          GetDocument().GetExecutionContext()));
+          document.GetExecutionContext()));
       auto trigger_support = SupportsPopoverTriggering();
       DCHECK_NE(popover.action, PopoverTriggerAction::kNone);
       DCHECK_NE(trigger_support, PopoverTriggerSupport::kNone);
@@ -378,16 +379,18 @@
       // not a triggering element, then the light dismiss code will hide the
       // popover and set focus to the previously focused element, then the
       // normal focus management code will reset focus to the clicked control.
-      bool can_show =
-          popover.popover->IsPopoverReady(PopoverTriggerAction::kShow,
-                                          /*exception_state=*/nullptr) &&
-          (popover.action == PopoverTriggerAction::kToggle ||
-           popover.action == PopoverTriggerAction::kShow);
-      bool can_hide =
-          popover.popover->IsPopoverReady(PopoverTriggerAction::kHide,
-                                          /*exception_state=*/nullptr) &&
-          (popover.action == PopoverTriggerAction::kToggle ||
-           popover.action == PopoverTriggerAction::kHide);
+      bool can_show = popover.popover->IsPopoverReady(
+                          PopoverTriggerAction::kShow,
+                          /*exception_state=*/nullptr,
+                          /*include_event_handler_text=*/true, &document) &&
+                      (popover.action == PopoverTriggerAction::kToggle ||
+                       popover.action == PopoverTriggerAction::kShow);
+      bool can_hide = popover.popover->IsPopoverReady(
+                          PopoverTriggerAction::kHide,
+                          /*exception_state=*/nullptr,
+                          /*include_event_handler_text=*/true, &document) &&
+                      (popover.action == PopoverTriggerAction::kToggle ||
+                       popover.action == PopoverTriggerAction::kHide);
       if (event.type() == event_type_names::kDOMActivate &&
           (!Form() || !IsSuccessfulSubmitButton())) {
         if (can_hide) {
diff --git a/third_party/blink/renderer/core/html/html_dialog_element.cc b/third_party/blink/renderer/core/html/html_dialog_element.cc
index 84d6b4e..0161e2f 100644
--- a/third_party/blink/renderer/core/html/html_dialog_element.cc
+++ b/third_party/blink/renderer/core/html/html_dialog_element.cc
@@ -55,16 +55,7 @@
   if (!dialog->isConnected())
     return;
 
-  // Showing a <dialog> should hide all open popovers.
   auto& document = dialog->GetDocument();
-  if (RuntimeEnabledFeatures::HTMLPopoverAttributeEnabled(
-          document.GetExecutionContext())) {
-    HTMLElement::HideAllPopoversUntil(
-        nullptr, document, HidePopoverFocusBehavior::kNone,
-        HidePopoverTransitionBehavior::kFireEventsAndWaitForTransitions,
-        HidePopoverIndependence::kHideUnrelated);
-  }
-
   dialog->previously_focused_element_ = document.FocusedElement();
 
   // TODO(kochi): How to find focusable element inside Shadow DOM is not
@@ -215,8 +206,18 @@
   // Element::isFocusable, which requires an up-to-date layout.
   GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kJavaScript);
 
+  // Showing a <dialog> should hide all open popovers.
+  auto& document = GetDocument();
+  if (RuntimeEnabledFeatures::HTMLPopoverAttributeEnabled(
+          document.GetExecutionContext())) {
+    HTMLElement::HideAllPopoversUntil(
+        nullptr, document, HidePopoverFocusBehavior::kNone,
+        HidePopoverTransitionBehavior::kFireEventsAndWaitForTransitions,
+        HidePopoverIndependence::kHideUnrelated);
+  }
+
   if (RuntimeEnabledFeatures::DialogNewFocusBehaviorEnabled()) {
-    SetFocusForDialog();
+    SetFocusForDialog(is_modal_);
   } else {
     SetFocusForDialogLegacy(this);
   }
@@ -297,8 +298,17 @@
     }
   }
 
+  // Showing a <dialog> should hide all open popovers.
+  if (RuntimeEnabledFeatures::HTMLPopoverAttributeEnabled(
+          document.GetExecutionContext())) {
+    HTMLElement::HideAllPopoversUntil(
+        nullptr, document, HidePopoverFocusBehavior::kNone,
+        HidePopoverTransitionBehavior::kFireEventsAndWaitForTransitions,
+        HidePopoverIndependence::kHideUnrelated);
+  }
+
   if (RuntimeEnabledFeatures::DialogNewFocusBehaviorEnabled()) {
-    SetFocusForDialog();
+    SetFocusForDialog(is_modal_);
   } else {
     SetFocusForDialogLegacy(this);
   }
@@ -348,20 +358,11 @@
 }
 
 // https://html.spec.whatwg.org#dialog-focusing-steps
-void HTMLDialogElement::SetFocusForDialog() {
+void HTMLDialogElement::SetFocusForDialog(bool is_modal) {
   previously_focused_element_ = GetDocument().FocusedElement();
 
-  // Showing a <dialog> should hide all open popovers.
-  if (RuntimeEnabledFeatures::HTMLPopoverAttributeEnabled(
-          GetDocument().GetExecutionContext())) {
-    HTMLElement::HideAllPopoversUntil(
-        nullptr, GetDocument(), HidePopoverFocusBehavior::kNone,
-        HidePopoverTransitionBehavior::kFireEventsAndWaitForTransitions,
-        HidePopoverIndependence::kHideUnrelated);
-  }
-
   Element* control = GetFocusDelegate(/*autofocus_only=*/false);
-  if (is_modal_ && IsAutofocusable()) {
+  if (is_modal && IsAutofocusable()) {
     control = this;
   }
   if (!control)
@@ -369,8 +370,9 @@
 
   if (control->IsFocusable())
     control->Focus();
-  else if (is_modal_)
+  else if (is_modal) {
     control->GetDocument().ClearFocusedElement();
+  }
 
   // 4. Let topDocument be the active document of control's node document's
   // browsing context's top-level browsing context.
diff --git a/third_party/blink/renderer/core/html/html_dialog_element.h b/third_party/blink/renderer/core/html/html_dialog_element.h
index c0b6640f..1d5e3293 100644
--- a/third_party/blink/renderer/core/html/html_dialog_element.h
+++ b/third_party/blink/renderer/core/html/html_dialog_element.h
@@ -63,15 +63,9 @@
     return isConnected() && IsFocusableStyleAfterUpdate();
   }
 
- private:
-  void DefaultEventHandler(Event&) override;
-
-  void SetIsModal(bool is_modal);
-  void ScheduleCloseEvent();
-
   // https://html.spec.whatwg.org/C/#the-dialog-element
   // Chooses the focused element when show() or showModal() is invoked.
-  void SetFocusForDialog();
+  void SetFocusForDialog(bool is_modal);
 
   // This is the old dialog initial focus behavior which is currently being
   // replaced by SetFocusForDialog.
@@ -79,6 +73,12 @@
   // to stable with no issues.
   static void SetFocusForDialogLegacy(HTMLDialogElement* dialog);
 
+ private:
+  void DefaultEventHandler(Event&) override;
+
+  void SetIsModal(bool is_modal);
+  void ScheduleCloseEvent();
+
   bool is_modal_;
   String return_value_;
   WeakMember<Element> previously_focused_element_;
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index e771785f..2f70301 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -79,6 +79,7 @@
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/html/forms/labels_node_list.h"
 #include "third_party/blink/renderer/core/html/html_br_element.h"
+#include "third_party/blink/renderer/core/html/html_dialog_element.h"
 #include "third_party/blink/renderer/core/html/html_dimension.h"
 #include "third_party/blink/renderer/core/html/html_document.h"
 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
@@ -1428,7 +1429,9 @@
   if (GetPopoverData()) {
     GetPopoverData()->setInvoker(invoker);
   }
-  if (!IsPopoverReady(PopoverTriggerAction::kShow, exception_state)) {
+  if (!IsPopoverReady(PopoverTriggerAction::kShow, exception_state,
+                      /*include_event_handler_text=*/false,
+                      &original_document)) {
     DCHECK(exception_state)
         << " Callers which aren't supposed to throw exceptions should not call "
            "ShowPopoverInternal when the Popover isn't in a valid state to be "
@@ -1610,9 +1613,9 @@
             focus_behavior, transition_behavior, exception_state);
       }
       // Close all auto popovers.
-      for (auto popover : document.PopoverStack()) {
-        popover->HidePopoverInternal(focus_behavior, transition_behavior,
-                                     exception_state);
+      while (!document.PopoverStack().empty()) {
+        document.PopoverStack().back()->HidePopoverInternal(
+            focus_behavior, transition_behavior, exception_state);
       }
     }
   } else {
@@ -1683,11 +1686,12 @@
   DCHECK(RuntimeEnabledFeatures::HTMLPopoverAttributeEnabled(
       GetDocument().GetExecutionContext()));
 
-  if (!IsPopoverReady(PopoverTriggerAction::kHide, exception_state)) {
+  auto& document = GetDocument();
+  if (!IsPopoverReady(PopoverTriggerAction::kHide, exception_state,
+                      /*include_event_handler_text=*/true, &document)) {
     return;
   }
 
-  auto& document = GetDocument();
   if (PopoverType() == PopoverValueType::kAuto ||
       PopoverType() == PopoverValueType::kHint) {
     auto& stack = document.PopoverStack();
@@ -1698,29 +1702,13 @@
       // The 'beforetoggle' event handlers could have changed this popover, e.g.
       // by changing its type, removing it from the document, or calling
       // hidePopover().
-      if (!stack.Contains(this) && this != document.PopoverHintShowing()) {
-        if (exception_state) {
-          exception_state->ThrowDOMException(
-              DOMExceptionCode::kInvalidStateError,
-              "This popover's \"beforetoggle\" event handler caused it to be "
-              "hidden (e.g. by calling hidePopover()).");
-        }
+      if (!IsPopoverReady(PopoverTriggerAction::kHide, exception_state,
+                          /*include_event_handler_text=*/true, &document)) {
         return;
       }
     } while (PopoverType() == PopoverValueType::kAuto
                  ? (!stack.empty() && stack.back() != this)
                  : (document.TopmostPopoverOrHint() != this));
-
-    // Then remove this popover from the stack.
-    if (PopoverType() == PopoverValueType::kAuto) {
-      DCHECK(!stack.empty());
-      DCHECK_EQ(stack.back(), this);
-      stack.pop_back();
-    } else {
-      DCHECK(RuntimeEnabledFeatures::HTMLPopoverHintEnabled());
-      DCHECK_EQ(document.TopmostPopoverOrHint(), this);
-      document.SetPopoverHintShowing(nullptr);
-    }
   }
 
   MarkPopoverInvokersDirty(*this);
@@ -1745,7 +1733,7 @@
     // changing its type, removing it from the document, or calling
     // showPopover().
     if (!IsPopoverReady(PopoverTriggerAction::kHide, exception_state,
-                        /*include_event_handler_text=*/true)) {
+                        /*include_event_handler_text=*/true, &document)) {
       return;
     }
 
@@ -1770,7 +1758,7 @@
     DCHECK(!after_event->cancelable());
     after_event->SetTarget(this);
     GetPopoverData()->setPendingToggleEventTask(PostCancellableTask(
-        *GetDocument().GetTaskRunner(TaskType::kDOMManipulation), FROM_HERE,
+        *document.GetTaskRunner(TaskType::kDOMManipulation), FROM_HERE,
         WTF::BindOnce(
             [](HTMLElement* element, ToggleEvent* event) {
               DCHECK(element);
@@ -1779,9 +1767,21 @@
             },
             WrapPersistent(this), WrapPersistent(after_event))));
 
-    GetDocument().ScheduleForTopLayerRemoval(this);
+    document.ScheduleForTopLayerRemoval(this);
   } else {
-    GetDocument().RemoveFromTopLayerImmediately(this);
+    document.RemoveFromTopLayerImmediately(this);
+  }
+
+  // Remove this popover from the stack.
+  if (PopoverType() == PopoverValueType::kAuto) {
+    auto& stack = document.PopoverStack();
+    DCHECK(!stack.empty());
+    DCHECK_EQ(stack.back(), this);
+    stack.pop_back();
+  } else if (PopoverType() == PopoverValueType::kHint) {
+    DCHECK(RuntimeEnabledFeatures::HTMLPopoverHintEnabled());
+    DCHECK_EQ(document.TopmostPopoverOrHint(), this);
+    document.SetPopoverHintShowing(nullptr);
   }
 
   // Re-apply display:none, and stop matching `:popover-open`.
@@ -1793,7 +1793,7 @@
   if (previously_focused_element) {
     GetPopoverData()->setPreviouslyFocusedElement(nullptr);
     if (focus_behavior == HidePopoverFocusBehavior::kFocusPreviousElement &&
-        contains(GetDocument().AdjustedFocusedElement())) {
+        contains(document.AdjustedFocusedElement())) {
       FocusOptions* focus_options = FocusOptions::Create();
       focus_options->setPreventScroll(true);
       previously_focused_element->Focus(FocusParams(
@@ -1815,6 +1815,15 @@
   // which requires an up-to-date layout.
   GetDocument().UpdateStyleAndLayoutTreeForNode(this);
 
+  if (auto* dialog = DynamicTo<HTMLDialogElement>(this)) {
+    if (RuntimeEnabledFeatures::DialogNewFocusBehaviorEnabled()) {
+      dialog->SetFocusForDialog(/*is_modal=*/true);
+    } else {
+      HTMLDialogElement::SetFocusForDialogLegacy(dialog);
+    }
+    return;
+  }
+
   Element* control =
       IsAutofocusable() ? this : GetFocusDelegate(/*autofocus_only=*/true);
 
diff --git a/third_party/blink/renderer/core/html/html_element.h b/third_party/blink/renderer/core/html/html_element.h
index 83a04a77..9b1ceda 100644
--- a/third_party/blink/renderer/core/html/html_element.h
+++ b/third_party/blink/renderer/core/html/html_element.h
@@ -233,8 +233,8 @@
   // do not match.
   bool IsPopoverReady(PopoverTriggerAction action,
                       ExceptionState* exception_state,
-                      bool include_event_handler_text = false,
-                      Document* expected_document = nullptr) const;
+                      bool include_event_handler_text,
+                      Document* expected_document) const;
   void togglePopover(ExceptionState& exception_state);
   void togglePopover(bool force, ExceptionState& exception_state);
   void showPopover(ExceptionState& exception_state);
diff --git a/third_party/blink/renderer/core/html/lazy_load_image_observer.cc b/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
index a9ac4b91..9f48b59 100644
--- a/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
+++ b/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
@@ -343,28 +343,26 @@
 
 void LazyLoadImageObserver::CreateLazyLoadIntersectionObserver(
     Document* root_document) {
-  HeapVector<Member<Element>> existing_targets;
-  if (lazy_load_intersection_observer_) {
-    for (const IntersectionObservation* observation :
-         lazy_load_intersection_observer_->Observations()) {
-      existing_targets.push_back(observation->Target());
-    }
-  }
-
   int viewport_threshold =
       use_viewport_distance_threshold_
           ? GetLazyImageLoadingViewportDistanceThresholdPx(*root_document)
           : 0;
-  lazy_load_intersection_observer_ = IntersectionObserver::Create(
+  IntersectionObserver* new_observer = IntersectionObserver::Create(
       {Length::Fixed(viewport_threshold)}, {std::numeric_limits<float>::min()},
       root_document,
       WTF::BindRepeating(&LazyLoadImageObserver::LoadIfNearViewport,
                          WrapWeakPersistent(this)),
       LocalFrameUkmAggregator::kLazyLoadIntersectionObserver);
 
-  for (Element* element : existing_targets) {
-    lazy_load_intersection_observer_->observe(element);
+  if (lazy_load_intersection_observer_) {
+    for (const IntersectionObservation* observation :
+         lazy_load_intersection_observer_->Observations()) {
+      new_observer->observe(observation->Target());
+    }
+    lazy_load_intersection_observer_->disconnect();
   }
+
+  lazy_load_intersection_observer_ = new_observer;
 }
 
 void LazyLoadImageObserver::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
index 4091171..c07936cf 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
@@ -7,6 +7,8 @@
 #include <memory>
 
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
 #include "services/network/public/mojom/attribution.mojom-blink.h"
 #include "services/network/public/mojom/web_client_hints_types.mojom-blink.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -106,8 +108,8 @@
   const char* base_url;
   const char* input_html;
   const char* expected_eligible_header;
-  network::mojom::AttributionOsSupport os_support =
-      network::mojom::AttributionOsSupport::kDisabled;
+  network::mojom::AttributionSupport attribution_support =
+      network::mojom::AttributionSupport::kWeb;
 };
 
 class HTMLMockHTMLResourcePreloader : public ResourcePreloader {
@@ -252,7 +254,7 @@
   void AttributionSrcRequestVerification(
       Document* document,
       const char* expected_eligible_header,
-      network::mojom::AttributionOsSupport expected_os_support) {
+      network::mojom::AttributionSupport expected_support) {
     ASSERT_TRUE(preload_request_.get());
     Resource* resource = preload_request_->Start(document);
     ASSERT_TRUE(resource);
@@ -260,9 +262,8 @@
     EXPECT_EQ(expected_eligible_header,
               resource->GetResourceRequest().HttpHeaderField(
                   http_names::kAttributionReportingEligible));
-    EXPECT_EQ(
-        expected_os_support,
-        resource->GetResourceRequest().GetAttributionReportingOsSupport());
+    EXPECT_EQ(expected_support,
+              resource->GetResourceRequest().GetAttributionReportingSupport());
   }
 
  protected:
@@ -440,7 +441,7 @@
     SCOPED_TRACE(test_case.input_html);
 
     ScopedTestingPlatformSupport<AttributionTestingPlatformSupport> platform;
-    platform->os_support = test_case.os_support;
+    platform->attribution_support = test_case.attribution_support;
 
     HTMLMockHTMLResourcePreloader preloader(GetDocument().Url());
     KURL base_url(test_case.base_url);
@@ -449,19 +450,19 @@
     preloader.TakePreloadData(std::move(preload_data));
     preloader.AttributionSrcRequestVerification(
         &GetDocument(), test_case.expected_eligible_header,
-        test_case.os_support);
+        test_case.attribution_support);
   }
 
  private:
   class AttributionTestingPlatformSupport : public TestingPlatformSupport {
    public:
-    network::mojom::AttributionOsSupport GetOsSupportForAttributionReporting()
+    network::mojom::AttributionSupport GetAttributionReportingSupport()
         override {
-      return os_support;
+      return attribution_support;
     }
 
-    network::mojom::AttributionOsSupport os_support =
-        network::mojom::AttributionOsSupport::kDisabled;
+    network::mojom::AttributionSupport attribution_support =
+        network::mojom::AttributionSupport::kWeb;
   };
 
   std::unique_ptr<HTMLPreloadScanner> scanner_;
@@ -1124,33 +1125,35 @@
   static constexpr char kInsecureBaseURL[] = "http://example.test";
 
   AttributionSrcTestCase test_cases[] = {
-      // Insecure context
-      {kInsecureDocumentUrl, kSecureBaseURL,
-       "<img src='/image' attributionsrc>", nullptr},
-      {kInsecureDocumentUrl, kSecureBaseURL,
-       "<script src='/script' attributionsrc></script>", nullptr},
-      // No attributionsrc attribute
-      {kSecureDocumentUrl, kSecureBaseURL, "<img src='/image'>", nullptr},
-      {kSecureDocumentUrl, kSecureBaseURL, "<script src='/script'></script>",
-       nullptr},
-      // Irrelevant element type
-      {kSecureDocumentUrl, kSecureBaseURL,
-       "<video poster='/image' attributionsrc>", nullptr},
-      // Not potentially trustworthy reporting origin
-      {kSecureDocumentUrl, kInsecureBaseURL,
-       "<img src='/image' attributionsrc>", nullptr},
-      {kSecureDocumentUrl, kInsecureBaseURL,
-       "<script src='/script' attributionsrc></script>", nullptr},
-      // Secure context, potentially trustworthy reporting origin,
-      // attributionsrc attribute
-      {kSecureDocumentUrl, kSecureBaseURL, "<img src='/image' attributionsrc>",
-       kAttributionEligibleEventSourceAndTrigger},
-      {kSecureDocumentUrl, kSecureBaseURL,
-       "<script src='/script' attributionsrc></script>",
-       kAttributionEligibleEventSourceAndTrigger},
-      {kSecureDocumentUrl, kSecureBaseURL, "<img src='/image' attributionsrc>",
-       kAttributionEligibleEventSourceAndTrigger,
-       network::mojom::AttributionOsSupport::kEnabled},
+    // Insecure context
+    {kInsecureDocumentUrl, kSecureBaseURL, "<img src='/image' attributionsrc>",
+     nullptr},
+    {kInsecureDocumentUrl, kSecureBaseURL,
+     "<script src='/script' attributionsrc></script>", nullptr},
+    // No attributionsrc attribute
+    {kSecureDocumentUrl, kSecureBaseURL, "<img src='/image'>", nullptr},
+    {kSecureDocumentUrl, kSecureBaseURL, "<script src='/script'></script>",
+     nullptr},
+    // Irrelevant element type
+    {kSecureDocumentUrl, kSecureBaseURL,
+     "<video poster='/image' attributionsrc>", nullptr},
+    // Not potentially trustworthy reporting origin
+    {kSecureDocumentUrl, kInsecureBaseURL, "<img src='/image' attributionsrc>",
+     nullptr},
+    {kSecureDocumentUrl, kInsecureBaseURL,
+     "<script src='/script' attributionsrc></script>", nullptr},
+    // Secure context, potentially trustworthy reporting origin,
+    // attributionsrc attribute
+    {kSecureDocumentUrl, kSecureBaseURL, "<img src='/image' attributionsrc>",
+     kAttributionEligibleEventSourceAndTrigger},
+    {kSecureDocumentUrl, kSecureBaseURL,
+     "<script src='/script' attributionsrc></script>",
+     kAttributionEligibleEventSourceAndTrigger},
+#if BUILDFLAG(IS_ANDROID)
+    {kSecureDocumentUrl, kSecureBaseURL, "<img src='/image' attributionsrc>",
+     kAttributionEligibleEventSourceAndTrigger,
+     network::mojom::AttributionSupport::kWebAndOs},
+#endif
   };
 
   for (const auto& test_case : test_cases) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
index e2ef3fe..a9c1933 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
@@ -227,6 +227,9 @@
     case AttributionReportingIssueType::kWebAndOsHeaders:
       return protocol::Audits::AttributionReportingIssueTypeEnum::
           WebAndOsHeaders;
+    case AttributionReportingIssueType::kNoWebOrOsSupport:
+      return protocol::Audits::AttributionReportingIssueTypeEnum::
+          NoWebOrOsSupport;
   }
 }
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_issue.h b/third_party/blink/renderer/core/inspector/inspector_audits_issue.h
index 698477b0..2c91b82 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_issue.h
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_issue.h
@@ -58,6 +58,7 @@
   kInvalidRegisterOsSourceHeader,
   kInvalidRegisterOsTriggerHeader,
   kWebAndOsHeaders,
+  kNoWebOrOsSupport,
 };
 
 enum class SharedArrayBufferIssueType {
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
index 6196da7..672c477a 100644
--- a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -407,7 +407,6 @@
     DEFINE_STRING_MAPPING(PseudoViewTransitionOld);
     DEFINE_STRING_MAPPING(PseudoParent);
     DEFINE_STRING_MAPPING(PseudoUnparsed)
-    DEFINE_STRING_MAPPING(PseudoInitial)
 #undef DEFINE_STRING_MAPPING
   }
 
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index 6a80341..76e0f54 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -29,8 +29,6 @@
 blink_core_sources_layout = [
   "anchor_scroll_data.cc",
   "anchor_scroll_data.h",
-  "api/selection_state.cc",
-  "api/selection_state.h",
   "background_bleed_avoidance.h",
   "box_layout_extra_input.h",
   "content_change_type.h",
@@ -544,6 +542,8 @@
   "pointer_events_hit_rules.h",
   "scroll_anchor.cc",
   "scroll_anchor.h",
+  "selection_state.cc",
+  "selection_state.h",
   "shapes/box_shape.cc",
   "shapes/box_shape.h",
   "shapes/ellipse_shape.cc",
@@ -684,7 +684,6 @@
 
 blink_core_tests_layout = [
   "anchor_scroll_data_test.cc",
-  "api/selection_state_test.cc",
   "geometry/axis_test.cc",
   "geometry/logical_rect_test.cc",
   "geometry/physical_rect_test.cc",
@@ -776,6 +775,7 @@
   "paint_containment_test.cc",
   "scroll_anchor_test.cc",
   "scrollbars_test.cc",
+  "selection_state_test.cc",
   "shapes/box_shape_test.cc",
   "shapes/ellipse_shape_test.cc",
   "style_retain_scope_test.cc",
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 6420433..d849525 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -42,7 +42,6 @@
 #include "third_party/blink/renderer/core/editing/forward.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
-#include "third_party/blink/renderer/core/layout/api/selection_state.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
 #include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
 #include "third_party/blink/renderer/core/layout/hit_test_phase.h"
@@ -53,6 +52,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_outline_type.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
 #include "third_party/blink/renderer/core/layout/outline_rect_collector.h"
+#include "third_party/blink/renderer/core/layout/selection_state.h"
 #include "third_party/blink/renderer/core/loader/resource/image_resource_observer.h"
 #include "third_party/blink/renderer/core/paint/fragment_data.h"
 #include "third_party/blink/renderer/core/paint/paint_phase.h"
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index 7f252b9..e659175 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -484,8 +484,7 @@
                                MapCoordinatesFlags mode) const {
   NOT_DESTROYED();
   quads.push_back(LocalRectToAbsoluteQuad(
-      PhysicalRect(PhysicalOffset(), PhysicalSizeToBeNoop(Layer()->Size())),
-      mode));
+      PhysicalRect(PhysicalOffset(), GetScrollableArea()->Size()), mode));
 }
 
 void LayoutView::CommitPendingSelection() {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index 5d85c52..f7d4447 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -424,7 +424,11 @@
   }
 
   // Whether the current node is a table-cell.
-  bool IsTableCell() const { return bitfields_.is_table_cell; }
+  bool IsTableCell() const {
+    return HasRareData() &&
+           rare_data_->data_union_type ==
+               static_cast<unsigned>(RareData::DataUnionType::kTableCellData);
+  }
 
   // Whether the table-cell fragment should be hidden (not painted) if it has
   // no children.
@@ -1144,6 +1148,8 @@
       EnsureBlockData()->lines_until_clamp = value;
     }
 
+    void SetIsTableCell() { EnsureTableCellData(); }
+
     NGBoxStrut TableCellBorders() const {
       return GetDataUnionType() == DataUnionType::kTableCellData
                  ? table_cell_data_.table_cell_borders
@@ -1528,7 +1534,6 @@
           writing_mode(
               static_cast<unsigned>(writing_direction.GetWritingMode())),
           direction(static_cast<unsigned>(writing_direction.Direction())),
-          is_table_cell(false),
           is_anonymous(false),
           is_new_formatting_context(false),
           is_orthogonal_writing_mode_root(false),
@@ -1555,7 +1560,6 @@
       return adjoining_object_types == other.adjoining_object_types &&
              writing_mode == other.writing_mode &&
              direction == other.direction &&
-             is_table_cell == other.is_table_cell &&
              is_anonymous == other.is_anonymous &&
              is_new_formatting_context == other.is_new_formatting_context &&
              is_orthogonal_writing_mode_root ==
@@ -1586,8 +1590,6 @@
     unsigned writing_mode : 3;
     unsigned direction : 1;
 
-    unsigned is_table_cell : 1;
-
     unsigned is_anonymous : 1;
     unsigned is_new_formatting_context : 1;
     unsigned is_orthogonal_writing_mode_root : 1;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index a5ca105..3ad383d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -276,13 +276,14 @@
   }
 
   void SetIsTableCell(bool is_table_cell) {
-    space_.bitfields_.is_table_cell = is_table_cell;
+    space_.EnsureRareData()->SetIsTableCell();
   }
 
   void SetIsRestrictedBlockSizeTableCell(bool b) {
-    DCHECK(space_.bitfields_.is_table_cell);
-    if (!b && !space_.rare_data_)
+    DCHECK(space_.IsTableCell());
+    if (!b && !space_.rare_data_) {
       return;
+    }
     space_.EnsureRareData()->is_restricted_block_size_table_cell = b;
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
index 94fc0415..dbb74f17 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
@@ -67,18 +67,7 @@
         style_variant_(NGStyleVariant::kStandard) {
     DCHECK(style_);
   }
-  explicit NGFragmentBuilder(WritingDirectionMode writing_direction)
-      : writing_direction_(writing_direction) {}
 
-  NGFragmentBuilder(const NGPhysicalFragment& fragment)
-      : style_(&fragment.Style()),
-        writing_direction_(style_->GetWritingDirection()),
-        style_variant_(fragment.StyleVariant()),
-        size_(fragment.Size().ConvertToLogical(GetWritingMode())),
-        layout_object_(fragment.GetMutableLayoutObject()),
-        is_hidden_for_paint_(fragment.IsHiddenForPaint()) {}
-
- protected:
   scoped_refptr<const ComputedStyle> style_;
   WritingDirectionMode writing_direction_;
   NGStyleVariant style_variant_;
diff --git a/third_party/blink/renderer/core/layout/api/selection_state.cc b/third_party/blink/renderer/core/layout/selection_state.cc
similarity index 91%
rename from third_party/blink/renderer/core/layout/api/selection_state.cc
rename to third_party/blink/renderer/core/layout/selection_state.cc
index 193a00d..9bb9d67 100644
--- a/third_party/blink/renderer/core/layout/api/selection_state.cc
+++ b/third_party/blink/renderer/core/layout/selection_state.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 "third_party/blink/renderer/core/layout/api/selection_state.h"
+#include "third_party/blink/renderer/core/layout/selection_state.h"
 
 #include <ostream>
 
diff --git a/third_party/blink/renderer/core/layout/api/selection_state.h b/third_party/blink/renderer/core/layout/selection_state.h
similarity index 83%
rename from third_party/blink/renderer/core/layout/api/selection_state.h
rename to third_party/blink/renderer/core/layout/selection_state.h
index 0e6ffa1..f7c61fe 100644
--- a/third_party/blink/renderer/core/layout/api/selection_state.h
+++ b/third_party/blink/renderer/core/layout/selection_state.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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_API_SELECTION_STATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_API_SELECTION_STATE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SELECTION_STATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SELECTION_STATE_H_
 
 #include <iosfwd>
 #include "third_party/blink/renderer/core/core_export.h"
@@ -36,4 +36,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_API_SELECTION_STATE_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SELECTION_STATE_H_
diff --git a/third_party/blink/renderer/core/layout/api/selection_state_test.cc b/third_party/blink/renderer/core/layout/selection_state_test.cc
similarity index 89%
rename from third_party/blink/renderer/core/layout/api/selection_state_test.cc
rename to third_party/blink/renderer/core/layout/selection_state_test.cc
index ba51ce0..b9e583ad 100644
--- a/third_party/blink/renderer/core/layout/api/selection_state_test.cc
+++ b/third_party/blink/renderer/core/layout/selection_state_test.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 "third_party/blink/renderer/core/layout/api/selection_state.h"
+#include "third_party/blink/renderer/core/layout/selection_state.h"
 
 #include <sstream>
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index 88aa530..58937afc 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -364,8 +364,8 @@
 
   if (AttributionSrcLoader* attribution_src_loader =
           GetFrame()->GetAttributionSrcLoader()) {
-    request.SetAttributionReportingOsSupport(
-        attribution_src_loader->GetOsSupport());
+    request.SetAttributionReportingSupport(
+        attribution_src_loader->GetSupport());
   }
 
   GetLocalFrameClient()->DispatchWillSendRequest(request);
diff --git a/third_party/blink/renderer/core/loader/threaded_icon_loader.cc b/third_party/blink/renderer/core/loader/threaded_icon_loader.cc
index 7ecf388..043f597 100644
--- a/third_party/blink/renderer/core/loader/threaded_icon_loader.cc
+++ b/third_party/blink/renderer/core/loader/threaded_icon_loader.cc
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 
-#include "base/cxx17_backports.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task/single_thread_task_runner.h"
 #include "skia/ext/image_operations.h"
@@ -101,12 +100,11 @@
     return;
   }
 
-  int resized_width =
-      base::clamp(static_cast<int>(scale * decoded_icon.width()), 1,
-                  resize_dimensions.width());
+  int resized_width = std::clamp(static_cast<int>(scale * decoded_icon.width()),
+                                 1, resize_dimensions.width());
   int resized_height =
-      base::clamp(static_cast<int>(scale * decoded_icon.height()), 1,
-                  resize_dimensions.height());
+      std::clamp(static_cast<int>(scale * decoded_icon.height()), 1,
+                 resize_dimensions.height());
 
   // Use the RESIZE_GOOD quality allowing the implementation to pick an
   // appropriate method for the resize. Can be increased to RESIZE_BETTER
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
index d13967e..fe89dd8 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
@@ -9,8 +9,8 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker.h"
-#include "third_party/blink/renderer/core/layout/api/selection_state.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
+#include "third_party/blink/renderer/core/layout/selection_state.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_highlight_overlay.h"
 #include "third_party/blink/renderer/core/paint/text_decoration_info.h"
 #include "third_party/blink/renderer/core/paint/text_paint_style.h"
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 d5370a2..de8a2b2f 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
@@ -646,7 +646,7 @@
 PhysicalRect PaintLayerScrollableArea::LayoutContentRect(
     IncludeScrollbarsInRect scrollbar_inclusion) const {
   // LayoutContentRect is conceptually the same as the box's client rect.
-  LayoutSize layer_size(Layer()->Size());
+  LayoutSize layer_size = Size();
   LayoutUnit border_width = GetLayoutBox()->BorderWidth();
   LayoutUnit border_height = GetLayoutBox()->BorderHeight();
   NGPhysicalBoxStrut scrollbars;
@@ -884,6 +884,12 @@
   return layer_;
 }
 
+LayoutSize PaintLayerScrollableArea::Size() const {
+  return layer_->IsRootLayer()
+             ? LayoutSize(GetLayoutBox()->GetFrameView()->Size())
+             : GetLayoutBox()->Size();
+}
+
 LayoutUnit PaintLayerScrollableArea::ScrollWidth() const {
   return overflow_rect_.Width();
 }
@@ -3098,7 +3104,7 @@
         ctx.AddDebugAnnotation("early_exit", early_exit);
         ctx.AddDebugAnnotation("h_mode", static_cast<int>(h_mode));
         ctx.AddDebugAnnotation("v_mode", static_cast<int>(v_mode));
-        ctx.AddDebugAnnotation("layer_size", Layer()->Size().ToString());
+        ctx.AddDebugAnnotation("layer_size", Size().ToString());
         ctx.AddDebugAnnotation("overflow_rect", overflow_rect_.ToString());
         ctx.AddDebugAnnotation("is_root", Layer()->IsRootLayer());
         ctx.AddDebugAnnotation("is_main_frame",
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 cbfd9413..cfc5d5f 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
@@ -394,6 +394,7 @@
     in_resize_mode_ = in_resize_mode;
   }
 
+  LayoutSize Size() const;
   LayoutUnit ScrollWidth() const;
   LayoutUnit ScrollHeight() const;
 
diff --git a/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc b/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc
index 8bc760ad..f911351e 100644
--- a/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc
+++ b/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc
@@ -7,9 +7,9 @@
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/forms/text_control_element.h"
-#include "third_party/blink/renderer/core/layout/api/selection_state.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/selection_state.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
diff --git a/third_party/blink/renderer/core/paint/selection_bounds_recorder.h b/third_party/blink/renderer/core/paint/selection_bounds_recorder.h
index c2c85bf..247af41 100644
--- a/third_party/blink/renderer/core/paint/selection_bounds_recorder.h
+++ b/third_party/blink/renderer/core/paint/selection_bounds_recorder.h
@@ -5,8 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SELECTION_BOUNDS_RECORDER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SELECTION_BOUNDS_RECORDER_H_
 
-#include "third_party/blink/renderer/core/layout/api/selection_state.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
+#include "third_party/blink/renderer/core/layout/selection_state.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
diff --git a/third_party/blink/renderer/core/paint/theme_painter.cc b/third_party/blink/renderer/core/paint/theme_painter.cc
index 3546110..bf0fd45 100644
--- a/third_party/blink/renderer/core/paint/theme_painter.cc
+++ b/third_party/blink/renderer/core/paint/theme_painter.cc
@@ -42,6 +42,7 @@
 #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "third_party/blink/renderer/platform/text/writing_mode.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/native_theme/native_theme.h"
 
@@ -305,9 +306,17 @@
 
   ControlPart part = o.StyleRef().EffectiveAppearance();
   // We don't support ticks on alternate sliders like MediaVolumeSliders.
-  if (part != kSliderHorizontalPart && part != kSliderVerticalPart)
+  if (part != kSliderHorizontalPart &&
+      (part != kSliderVerticalPart ||
+       RuntimeEnabledFeatures::
+           RemoveNonStandardAppearanceValueSliderVerticalEnabled())) {
     return;
-  bool is_horizontal = part == kSliderHorizontalPart;
+  }
+  bool is_horizontal =
+      part == kSliderHorizontalPart &&
+      !(RuntimeEnabledFeatures::
+            FormControlsVerticalWritingModeSupportEnabled() &&
+        !IsHorizontalWritingMode(o.StyleRef().GetWritingMode()));
 
   gfx::Size thumb_size;
   LayoutObject* thumb_layout_object =
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index abbb041c..1692b7ff 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -27,7 +27,6 @@
 #include <memory>
 #include <utility>
 
-#include "base/cxx17_backports.h"
 #include "base/memory/values_equivalent.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/numerics/clamped_math.h"
@@ -2585,7 +2584,7 @@
   // real cost to our understanding of the zooms in use.
   base::UmaHistogramSparse(
       "Blink.EffectiveZoom",
-      base::clamp<float>(clamped_effective_zoom * 100, 0, 400));
+      std::clamp<float>(clamped_effective_zoom * 100, 0, 400));
   return true;
 }
 
diff --git a/third_party/blink/renderer/core/xml/xpath_functions.cc b/third_party/blink/renderer/core/xml/xpath_functions.cc
index 5a425f63..4ae6ec36 100644
--- a/third_party/blink/renderer/core/xml/xpath_functions.cc
+++ b/third_party/blink/renderer/core/xml/xpath_functions.cc
@@ -27,7 +27,8 @@
 
 #include "third_party/blink/renderer/core/xml/xpath_functions.h"
 
-#include "base/cxx17_backports.h"
+#include <algorithm>
+
 #include "third_party/blink/renderer/core/dom/attr.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/processing_instruction.h"
@@ -545,8 +546,8 @@
   if (std::isnan(start) || std::isnan(end))
     return std::make_pair(1, 1);
   // Neither start nor end are NaN, but may still be +/- Inf
-  const double clamped_start = base::clamp<double>(start, 1, max_len + 1);
-  const double clamped_end = base::clamp(end, clamped_start, max_len + 1);
+  const double clamped_start = std::clamp<double>(start, 1, max_len + 1);
+  const double clamped_end = std::clamp(end, clamped_start, max_len + 1);
   return std::make_pair(static_cast<unsigned>(clamped_start),
                         static_cast<unsigned>(clamped_end));
 }
diff --git a/third_party/blink/renderer/modules/accessibility/BUILD.gn b/third_party/blink/renderer/modules/accessibility/BUILD.gn
index cb09148..5413ec2 100644
--- a/third_party/blink/renderer/modules/accessibility/BUILD.gn
+++ b/third_party/blink/renderer/modules/accessibility/BUILD.gn
@@ -77,4 +77,11 @@
   # The modules/accessibility/ depends closely on core/ --
   # include the core pch for faster Windows compilation times.
   configs += [ "//third_party/blink/renderer/core:blink_core_pch" ]
+
+  if (is_debug || dcheck_always_on) {
+    sources += [
+      "ax_debug_utils.cc",
+      "ax_debug_utils.h",
+    ]
+  }
 }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_debug_utils.cc b/third_party/blink/renderer/modules/accessibility/ax_debug_utils.cc
new file mode 100644
index 0000000..c55726d
--- /dev/null
+++ b/third_party/blink/renderer/modules/accessibility/ax_debug_utils.cc
@@ -0,0 +1,38 @@
+// Copyright 2023 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/modules/accessibility/ax_debug_utils.h"
+
+#include <memory>
+#include <numeric>
+#include <string>
+#include <utility>
+
+namespace blink {
+
+namespace {
+
+std::string NewlineToSpaceReplacer(std::string str) {
+  std::replace(str.begin(), str.end(), '\n', ' ');
+  return str;
+}
+
+}  // namespace
+
+std::string TreeToStringHelper(const AXObject* obj, int indent, bool verbose) {
+  if (!obj) {
+    return "";
+  }
+
+  return std::accumulate(
+      obj->CachedChildrenIncludingIgnored().begin(),
+      obj->CachedChildrenIncludingIgnored().end(),
+      std::string(2 * indent, ' ') +
+          NewlineToSpaceReplacer(obj->ToString(verbose).Utf8()) + "\n",
+      [indent, verbose](const std::string& str, const AXObject* child) {
+        return str + TreeToStringHelper(child, indent + 1, verbose);
+      });
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_debug_utils.h b/third_party/blink/renderer/modules/accessibility/ax_debug_utils.h
new file mode 100644
index 0000000..5b65d15
--- /dev/null
+++ b/third_party/blink/renderer/modules/accessibility/ax_debug_utils.h
@@ -0,0 +1,21 @@
+// Copyright 2023 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_MODULES_ACCESSIBILITY_AX_DEBUG_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_DEBUG_UTILS_H_
+
+#include "third_party/blink/renderer/modules/accessibility/ax_object.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
+#include "ui/accessibility/ax_tree_serializer.h"
+
+namespace blink {
+
+class AXObject;
+
+// Friendly output of a subtree, useful for debugging.
+std::string TreeToStringHelper(const AXObject* obj, int indent, bool verbose);
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_DEBUG_UTILS_H_
diff --git a/third_party/blink/renderer/modules/cache_storage/cache.cc b/third_party/blink/renderer/modules/cache_storage/cache.cc
index f375870..cae786e6 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache.cc
@@ -888,14 +888,18 @@
              CacheStorageBlobClientList* blob_client_list,
              mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache>
                  cache_pending_remote,
-             scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : scoped_fetcher_(fetcher), blob_client_list_(blob_client_list) {
+             scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+             ContextLifecycleNotifier* context)
+    : scoped_fetcher_(fetcher),
+      blob_client_list_(blob_client_list),
+      cache_remote_(context) {
   cache_remote_.Bind(std::move(cache_pending_remote), std::move(task_runner));
 }
 
 void Cache::Trace(Visitor* visitor) const {
   visitor->Trace(scoped_fetcher_);
   visitor->Trace(blob_client_list_);
+  visitor->Trace(cache_remote_);
   ScriptWrappable::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/modules/cache_storage/cache.h b/third_party/blink/renderer/modules/cache_storage/cache.h
index dd6888e..1962d143 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache.h
+++ b/third_party/blink/renderer/modules/cache_storage/cache.h
@@ -7,7 +7,6 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/task/single_thread_task_runner.h"
-#include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -16,6 +15,7 @@
 #include "third_party/blink/renderer/core/fetch/global_fetch.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/gc_plugin.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -56,7 +56,8 @@
   Cache(GlobalFetch::ScopedFetcher*,
         CacheStorageBlobClientList* blob_client_list,
         mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache>,
-        scoped_refptr<base::SingleThreadTaskRunner>);
+        scoped_refptr<base::SingleThreadTaskRunner>,
+        ContextLifecycleNotifier*);
 
   Cache(const Cache&) = delete;
   Cache& operator=(const Cache&) = delete;
@@ -135,8 +136,8 @@
   Member<GlobalFetch::ScopedFetcher> scoped_fetcher_;
   Member<CacheStorageBlobClientList> blob_client_list_;
 
-  GC_PLUGIN_IGNORE("https://crbug.com/1381979")
-  mojo::AssociatedRemote<mojom::blink::CacheStorageCache> cache_remote_;
+  blink::HeapMojoAssociatedRemote<mojom::blink::CacheStorageCache>
+      cache_remote_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
index 7f88eb3..1dcb3aa 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
@@ -187,7 +187,8 @@
               resolver->Resolve(MakeGarbageCollected<Cache>(
                   fetcher, blob_client_list, std::move(result->get_cache()),
                   resolver->GetExecutionContext()->GetTaskRunner(
-                      blink::TaskType::kMiscPlatformAPI)));
+                      blink::TaskType::kMiscPlatformAPI),
+                  resolver->GetExecutionContext()));
             }
           },
           WrapPersistent(scoped_fetcher_.Get()),
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_test.cc b/third_party/blink/renderer/modules/cache_storage/cache_test.cc
index 35c0f26..f50b3be 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_test.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache_test.cc
@@ -40,6 +40,8 @@
 #include "third_party/blink/renderer/core/fetch/request.h"
 #include "third_party/blink/renderer/core/fetch/response.h"
 #include "third_party/blink/renderer/core/frame/frame.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
 #include "third_party/blink/renderer/modules/cache_storage/cache_storage_blob_client_list.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -277,11 +279,13 @@
   TestCache(
       GlobalFetch::ScopedFetcher* fetcher,
       mojo::PendingAssociatedRemote<mojom::blink::CacheStorageCache> remote,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      ContextLifecycleNotifier* context)
       : Cache(fetcher,
               MakeGarbageCollected<CacheStorageBlobClientList>(),
               std::move(remote),
-              std::move(task_runner)) {}
+              std::move(task_runner),
+              context) {}
 
   bool IsAborted() const {
     return abort_controller_ && abort_controller_->signal()->aborted();
@@ -316,7 +320,8 @@
         cache_.get(), cache_remote.BindNewEndpointAndPassDedicatedReceiver());
     return MakeGarbageCollected<TestCache>(
         fetcher, cache_remote.Unbind(),
-        blink::scheduler::GetSingleThreadTaskRunnerForTesting());
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
+        GetFrame().DomWindow());
   }
 
   ErrorCacheForTests* test_cache() { return cache_.get(); }
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
index f444485..5060875b 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
@@ -25,7 +25,6 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_identity_credential_request_options_context.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_identity_provider_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_identity_user_info.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_login_hint.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_m_doc_element.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_m_doc_provider.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_creation_options.h"
@@ -62,7 +61,6 @@
 using blink::mojom::blink::IdentityProvider;
 using blink::mojom::blink::IdentityProviderConfig;
 using blink::mojom::blink::IdentityProviderConfigPtr;
-using blink::mojom::blink::IdentityProviderLoginHint;
 using blink::mojom::blink::IdentityProviderPtr;
 using blink::mojom::blink::IdentityUserInfo;
 using blink::mojom::blink::IdentityUserInfoPtr;
@@ -737,16 +735,10 @@
   mojo_provider->config_url = blink::KURL(provider.configURL());
   mojo_provider->client_id = provider.clientId();
   mojo_provider->nonce = provider.getNonceOr("");
-  auto login_hint = IdentityProviderLoginHint::New();
-  if (blink::RuntimeEnabledFeatures::FedCmLoginHintEnabled() &&
-      provider.hasLoginHint()) {
-    login_hint->email = provider.loginHint()->getEmailOr("");
-    login_hint->id = provider.loginHint()->getIdOr("");
-    login_hint->is_required = provider.loginHint()->getIsRequiredOr(false);
+  if (blink::RuntimeEnabledFeatures::FedCmLoginHintEnabled()) {
+    mojo_provider->login_hint = provider.getLoginHintOr("");
   } else {
-    login_hint->email = "";
-    login_hint->id = "";
-    login_hint->is_required = false;
+    mojo_provider->login_hint = "";
   }
 
   if (blink::RuntimeEnabledFeatures::FedCmAuthzEnabled()) {
@@ -765,7 +757,6 @@
     }
   }
 
-  mojo_provider->login_hint = std::move(login_hint);
   return mojo_provider;
 }
 
diff --git a/third_party/blink/renderer/modules/credentialmanagement/identity_provider_config.idl b/third_party/blink/renderer/modules/credentialmanagement/identity_provider_config.idl
index 5c9c1fbf..cd0ed1c9 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/identity_provider_config.idl
+++ b/third_party/blink/renderer/modules/credentialmanagement/identity_provider_config.idl
@@ -12,7 +12,7 @@
   [RuntimeEnabled=FedCmAuthz] sequence<USVString> scope;
   [RuntimeEnabled=FedCmAuthz] sequence<USVString> responseType;
   [RuntimeEnabled=FedCmAuthz] record<USVString, USVString> params;
-  [RuntimeEnabled=FedCmLoginHint] LoginHint loginHint;
+  [RuntimeEnabled=FedCmLoginHint] DOMString loginHint;
 };
 
 // extends the IdentityProviderConfig with mDoc-specific attributes
diff --git a/third_party/blink/renderer/modules/credentialmanagement/login_hint.idl b/third_party/blink/renderer/modules/credentialmanagement/login_hint.idl
deleted file mode 100644
index 8c0de95..0000000
--- a/third_party/blink/renderer/modules/credentialmanagement/login_hint.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://fedidcg.github.io/FedCM/
-
-dictionary LoginHint {
-  // Normally only one of |email| or |id| is provided.
-  USVString email;
-  USVString id;
-  boolean isRequired;
-};
diff --git a/third_party/blink/renderer/modules/presentation/presentation_receiver.cc b/third_party/blink/renderer/modules/presentation/presentation_receiver.cc
index dfabf30..4c8db51 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_receiver.cc
+++ b/third_party/blink/renderer/modules/presentation/presentation_receiver.cc
@@ -58,16 +58,12 @@
 }
 
 void PresentationReceiver::OnReceiverConnectionAvailable(
-    mojom::blink::PresentationInfoPtr info,
-    mojo::PendingRemote<mojom::blink::PresentationConnection>
-        controller_connection,
-    mojo::PendingReceiver<mojom::blink::PresentationConnection>
-        receiver_connection_receiver) {
+    mojom::blink::PresentationConnectionResultPtr result) {
   // Take() will call PresentationReceiver::registerConnection()
   // and register the connection.
   auto* connection = ReceiverPresentationConnection::Take(
-      this, *info, std::move(controller_connection),
-      std::move(receiver_connection_receiver));
+      this, *result->presentation_info, std::move(result->connection_remote),
+      std::move(result->connection_receiver));
 
   // Only notify receiver.connectionList property if it has been acccessed
   // previously.
diff --git a/third_party/blink/renderer/modules/presentation/presentation_receiver.h b/third_party/blink/renderer/modules/presentation/presentation_receiver.h
index e4372ee0..37f921a 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_receiver.h
+++ b/third_party/blink/renderer/modules/presentation/presentation_receiver.h
@@ -43,9 +43,7 @@
 
   // mojom::blink::PresentationReceiver
   void OnReceiverConnectionAvailable(
-      mojom::blink::PresentationInfoPtr,
-      mojo::PendingRemote<mojom::blink::PresentationConnection>,
-      mojo::PendingReceiver<mojom::blink::PresentationConnection>) override;
+      mojom::blink::PresentationConnectionResultPtr result) override;
 
   void RegisterConnection(ReceiverPresentationConnection*);
   void RemoveConnection(ReceiverPresentationConnection*);
diff --git a/third_party/blink/renderer/modules/presentation/presentation_receiver_test.cc b/third_party/blink/renderer/modules/presentation/presentation_receiver_test.cc
index f7a41e5..3739b239 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_receiver_test.cc
+++ b/third_party/blink/renderer/modules/presentation/presentation_receiver_test.cc
@@ -109,8 +109,9 @@
 
   // Receive first connection.
   receiver->OnReceiverConnectionAvailable(
-      connection_info_.Clone(), std::move(controller_connection_),
-      std::move(receiver_connection_receiver_));
+      mojom::blink::PresentationConnectionResult::New(
+          connection_info_.Clone(), std::move(controller_connection_),
+          std::move(receiver_connection_receiver_)));
 
   VerifyConnectionListPropertyState(ConnectionListProperty::kResolved,
                                     receiver);
@@ -132,8 +133,9 @@
 
   // Receive first connection.
   receiver->OnReceiverConnectionAvailable(
-      connection_info_.Clone(), std::move(controller_connection_),
-      std::move(receiver_connection_receiver_));
+      mojom::blink::PresentationConnectionResult::New(
+          connection_info_.Clone(), std::move(controller_connection_),
+          std::move(receiver_connection_receiver_)));
 
   mojo::PendingRemote<mojom::blink::PresentationConnection>
       controller_connection_2_;
@@ -148,8 +150,9 @@
 
   // Receive second connection.
   receiver->OnReceiverConnectionAvailable(
-      connection_info_.Clone(), std::move(controller_connection_2_),
-      std::move(receiver_connection_receiver_2));
+      mojom::blink::PresentationConnectionResult::New(
+          connection_info_.Clone(), std::move(controller_connection_2_),
+          std::move(receiver_connection_receiver_2)));
 
   VerifyConnectionListSize(2, receiver);
 }
@@ -167,8 +170,9 @@
 
   // Receive first connection.
   receiver->OnReceiverConnectionAvailable(
-      connection_info_.Clone(), std::move(controller_connection_),
-      std::move(receiver_connection_receiver_));
+      mojom::blink::PresentationConnectionResult::New(
+          connection_info_.Clone(), std::move(controller_connection_),
+          std::move(receiver_connection_receiver_)));
 
   mojo::PendingRemote<mojom::blink::PresentationConnection>
       controller_connection_2_;
@@ -183,8 +187,9 @@
 
   // Receive second connection.
   receiver->OnReceiverConnectionAvailable(
-      connection_info_.Clone(), std::move(controller_connection_2_),
-      std::move(receiver_connection_receiver_2));
+      mojom::blink::PresentationConnectionResult::New(
+          connection_info_.Clone(), std::move(controller_connection_2_),
+          std::move(receiver_connection_receiver_2)));
 
   receiver->connectionList(scope.GetScriptState());
   VerifyConnectionListPropertyState(ConnectionListProperty::kResolved,
diff --git a/third_party/blink/renderer/modules/storage/storage_controller.cc b/third_party/blink/renderer/modules/storage/storage_controller.cc
index 97f31f9..17d34788 100644
--- a/third_party/blink/renderer/modules/storage/storage_controller.cc
+++ b/third_party/blink/renderer/modules/storage/storage_controller.cc
@@ -44,7 +44,7 @@
 StorageController* StorageController::GetInstance() {
   DEFINE_STATIC_LOCAL(StorageController, gCachedStorageAreaController,
                       (GetDomStorageConnection(),
-                       base::SysInfo::IsLowEndDevice()
+                       base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled()
                            ? kStorageControllerTotalCacheLimitInBytesLowEnd
                            : kStorageControllerTotalCacheLimitInBytes));
   return &gCachedStorageAreaController;
diff --git a/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc b/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc
index fb91e00..01dd0c1 100644
--- a/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc
+++ b/third_party/blink/renderer/modules/xr/xr_cpu_depth_information.cc
@@ -4,10 +4,10 @@
 
 #include "third_party/blink/renderer/modules/xr/xr_cpu_depth_information.h"
 
+#include <algorithm>
 #include <cmath>
 #include <cstdlib>
 
-#include "base/cxx17_backports.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/ostream_operators.h"
 #include "device/vr/public/mojom/vr_service.mojom-blink.h"
@@ -100,9 +100,9 @@
   gfx::PointF depth_coordinates =
       gfx::ScalePoint(norm_depth_coordinates, size_.width(), size_.height());
 
-  uint32_t column = base::clamp<uint32_t>(
+  uint32_t column = std::clamp<uint32_t>(
       static_cast<uint32_t>(depth_coordinates.x()), 0, size_.width() - 1);
-  uint32_t row = base::clamp<uint32_t>(
+  uint32_t row = std::clamp<uint32_t>(
       static_cast<uint32_t>(depth_coordinates.y()), 0, size_.height() - 1);
 
   auto checked_index =
diff --git a/third_party/blink/renderer/modules/xr/xr_cube_map.cc b/third_party/blink/renderer/modules/xr/xr_cube_map.cc
index 3db91023..20e8cc88 100644
--- a/third_party/blink/renderer/modules/xr/xr_cube_map.cc
+++ b/third_party/blink/renderer/modules/xr/xr_cube_map.cc
@@ -4,9 +4,9 @@
 
 #include "third_party/blink/renderer/modules/xr/xr_cube_map.h"
 
+#include <algorithm>
 #include <cstring>
 
-#include "base/cxx17_backports.h"
 #include "device/vr/public/mojom/vr_service.mojom-blink.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_texture.h"
@@ -29,7 +29,7 @@
 // Linear to sRGB converstion as given in
 // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_framebuffer_sRGB.txt
 uint8_t LinearToSrgb(float cl) {
-  float cs = base::clamp(
+  float cs = std::clamp(
       cl < 0.0031308f ? 12.92f * cl : 1.055f * std::pow(cl, 0.41666f) - 0.055f,
       0.0f, 1.0f);
   return static_cast<uint8_t>(255.0f * cs + 0.5f);
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc
index a2ba506..b657789 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -11,7 +11,6 @@
 
 #include "base/auto_reset.h"
 #include "base/containers/contains.h"
-#include "base/cxx17_backports.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
 #include "base/types/pass_key.h"
@@ -369,8 +368,8 @@
 
   // Clamp to a reasonable min/max size for the default framebuffer scale.
   recommended_framebuffer_scale_ =
-      base::clamp(device_config->default_framebuffer_scale,
-                  kMinDefaultFramebufferScale, kMaxDefaultFramebufferScale);
+      std::clamp(device_config->default_framebuffer_scale,
+                 kMinDefaultFramebufferScale, kMaxDefaultFramebufferScale);
 
   UpdateViews(device_config->views);
 
diff --git a/third_party/blink/renderer/modules/xr/xr_session_viewport_scaler.cc b/third_party/blink/renderer/modules/xr/xr_session_viewport_scaler.cc
index 20d3d76..b75c2bc 100644
--- a/third_party/blink/renderer/modules/xr/xr_session_viewport_scaler.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session_viewport_scaler.cc
@@ -7,8 +7,6 @@
 #include <algorithm>
 #include <cmath>
 
-#include "base/cxx17_backports.h"
-
 namespace blink {
 
 namespace {
@@ -49,8 +47,8 @@
 }
 
 void XRSessionViewportScaler::UpdateRenderingTimeRatio(float new_value) {
-  gpu_load_ += base::clamp(kLoadDecay * (new_value - gpu_load_), -kMaxChange,
-                           kMaxChange);
+  gpu_load_ +=
+      std::clamp(kLoadDecay * (new_value - gpu_load_), -kMaxChange, kMaxChange);
   float old_scale = scale_;
   if (gpu_load_ > kLoadHigh && scale_ > kMinScale) {
     scale_ *= kScaleStep;
@@ -59,7 +57,7 @@
     scale_ /= kScaleStep;
     scale_ = round(scale_ * kRound) / kRound;
   }
-  scale_ = base::clamp(scale_, kMinScale, kMaxScale);
+  scale_ = std::clamp(scale_, kMinScale, kMaxScale);
   if (scale_ != old_scale) {
     ResetLoad();
   }
diff --git a/third_party/blink/renderer/modules/xr/xr_view.cc b/third_party/blink/renderer/modules/xr/xr_view.cc
index 83b1172..1f04625a 100644
--- a/third_party/blink/renderer/modules/xr/xr_view.cc
+++ b/third_party/blink/renderer/modules/xr/xr_view.cc
@@ -6,9 +6,9 @@
 
 #include "third_party/blink/renderer/modules/xr/xr_view.h"
 
+#include <algorithm>
 #include <cmath>
 
-#include "base/cxx17_backports.h"
 #include "third_party/blink/renderer/modules/xr/xr_camera.h"
 #include "third_party/blink/renderer/modules/xr/xr_frame.h"
 #include "third_party/blink/renderer/modules/xr/xr_session.h"
@@ -250,7 +250,7 @@
   if (!scale)
     return;
 
-  requested_viewport_scale_ = base::clamp(*scale, kMinViewportScale, 1.0);
+  requested_viewport_scale_ = std::clamp(*scale, kMinViewportScale, 1.0);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
index c12557d3..e76aa25 100644
--- a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
+++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <utility>
 
-#include "base/cxx17_backports.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
@@ -117,8 +116,8 @@
     // small to see or unreasonably large.
     // TODO(bajones): Would be best to have the max value communicated from the
     // service rather than limited to the native res.
-    framebuffer_scale = base::clamp(initializer->framebufferScaleFactor(),
-                                    kFramebufferMinScale, max_scale);
+    framebuffer_scale = std::clamp(initializer->framebufferScaleFactor(),
+                                   kFramebufferMinScale, max_scale);
   }
 
   gfx::SizeF framebuffers_size = session->RecommendedFramebufferSize();
diff --git a/third_party/blink/renderer/platform/fonts/font_selection_types.h b/third_party/blink/renderer/platform/fonts/font_selection_types.h
index 406101a..cccdd8d 100644
--- a/third_party/blink/renderer/platform/fonts/font_selection_types.h
+++ b/third_party/blink/renderer/platform/fonts/font_selection_types.h
@@ -26,7 +26,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_SELECTION_TYPES_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_SELECTION_TYPES_H_
 
-#include "base/cxx17_backports.h"
+#include <algorithm>
+
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -355,7 +356,7 @@
   }
 
   FontSelectionValue clampToRange(FontSelectionValue selection_value) const {
-    return base::clamp(selection_value, minimum, maximum);
+    return std::clamp(selection_value, minimum, maximum);
   }
 
   FontSelectionValue minimum{FontSelectionValue(1)};
diff --git a/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc b/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc
index 379a333..7c66482 100644
--- a/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc
+++ b/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/platform/graphics/image_decoder_wrapper.h"
 
+#include "base/system/sys_info.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/graphics/image_decoding_store.h"
@@ -83,6 +84,21 @@
 
 ImageDecoderWrapper::~ImageDecoderWrapper() = default;
 
+namespace {
+
+bool IsLowEndDeviceOrPartialLowEndModeEnabled() {
+#if BUILDFLAG(IS_ANDROID)
+  // Since ImageFrameGeneratorTest depends on Platform::Current(), use
+  // Platform::Current()->IsLowEndDevice() here.
+  return Platform::Current()->IsLowEndDevice() ||
+         base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled();
+#else
+  return Platform::Current()->IsLowEndDevice();
+#endif
+}
+
+}  // namespace
+
 bool ImageDecoderWrapper::Decode(ImageDecoderFactory* factory,
                                  wtf_size_t* frame_count,
                                  bool* has_alpha) {
@@ -210,7 +226,7 @@
   // On low-end devices, always use the external allocator, to avoid storing
   // duplicate copies of the data for partial decodes in the ImageDecoder's
   // cache.
-  if (Platform::Current()->IsLowEndDevice()) {
+  if (IsLowEndDeviceOrPartialLowEndModeEnabled()) {
     DCHECK(!resume_decoding);
     return true;
   }
diff --git a/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.cc b/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.cc
index 3094064..2355fe7 100644
--- a/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.cc
+++ b/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.cc
@@ -43,6 +43,12 @@
   return is_low_end_device_;
 }
 
+bool MemoryPressureListenerRegistry::
+    IsLowEndDeviceOrPartialLowEndModeEnabled() {
+  return is_low_end_device_ ||
+         base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled();
+}
+
 // static
 bool MemoryPressureListenerRegistry::IsCurrentlyLowMemory() {
 #if BUILDFLAG(IS_ANDROID)
diff --git a/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h b/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
index f58db6f..806dc494 100644
--- a/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
+++ b/third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h
@@ -40,6 +40,10 @@
   // Can be overridden in web tests via internals.
   static bool IsLowEndDevice();
 
+  // Returns true when IsLowEndDevice() returns true or when the feature
+  // PartialLowEndModeOnMidEndDevices is enabled on Android devices.
+  static bool IsLowEndDeviceOrPartialLowEndModeEnabled();
+
   // Returns true when available memory is low.
   // This is not cheap and should not be called repeatedly.
   static bool IsCurrentlyLowMemory();
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc b/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
index 9d48914..0e848c5 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
@@ -478,7 +478,8 @@
 void MemoryCache::OnMemoryPressure(
     base::MemoryPressureListener::MemoryPressureLevel level) {
   saved_page_resources_.clear();
-  if (MemoryPressureListenerRegistry::IsLowEndDevice()) {
+  if (MemoryPressureListenerRegistry::
+          IsLowEndDeviceOrPartialLowEndModeEnabled()) {
     PruneAll();
   }
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
index 671d7fb..61e7ebbeb 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
@@ -222,7 +222,7 @@
   request->SetRecursivePrefetchToken(RecursivePrefetchToken());
   request->SetFetchLikeAPI(IsFetchLikeAPI());
   request->SetFavicon(IsFavicon());
-  request->SetAttributionReportingOsSupport(GetAttributionReportingOsSupport());
+  request->SetAttributionReportingSupport(GetAttributionReportingSupport());
 
   return request;
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_request.h b/third_party/blink/renderer/platform/loader/fetch/resource_request.h
index 73eda7d..dd069a1 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_request.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_request.h
@@ -552,14 +552,13 @@
   }
   bool GetHasStorageAccess() const { return has_storage_access_; }
 
-  network::mojom::AttributionOsSupport GetAttributionReportingOsSupport()
-      const {
-    return attribution_reporting_os_support_;
+  network::mojom::AttributionSupport GetAttributionReportingSupport() const {
+    return attribution_reporting_support_;
   }
 
-  void SetAttributionReportingOsSupport(
-      network::mojom::AttributionOsSupport os_support) {
-    attribution_reporting_os_support_ = os_support;
+  void SetAttributionReportingSupport(
+      network::mojom::AttributionSupport attribution_support) {
+    attribution_reporting_support_ = attribution_support;
   }
 
  private:
@@ -682,8 +681,8 @@
 
   bool has_storage_access_ = false;
 
-  network::mojom::AttributionOsSupport attribution_reporting_os_support_ =
-      network::mojom::AttributionOsSupport::kDisabled;
+  network::mojom::AttributionSupport attribution_reporting_support_ =
+      network::mojom::AttributionSupport::kWeb;
 };
 
 class PLATFORM_EXPORT ResourceRequestBody {
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
index 7fffc8e6..2013663 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/request_conversion.cc
@@ -403,8 +403,7 @@
 
   dest->has_storage_access = src.GetHasStorageAccess();
 
-  dest->attribution_reporting_os_support =
-      src.GetAttributionReportingOsSupport();
+  dest->attribution_reporting_support = src.GetAttributionReportingSupport();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc b/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc
index f1b47787..2b5c5f0 100644
--- a/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc
+++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc
@@ -4,10 +4,10 @@
 
 #include "third_party/blink/renderer/platform/media/multi_buffer_data_source.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/containers/adapters.h"
-#include "base/cxx17_backports.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
@@ -721,7 +721,7 @@
   buffer_size_update_counter_ = kUpdateBufferSizeFrequency;
 
   // Use a default bit rate if unknown and clamp to prevent overflow.
-  int64_t bitrate = base::clamp<int64_t>(bitrate_, 0, kMaxBitrate);
+  int64_t bitrate = std::clamp<int64_t>(bitrate_, 0, kMaxBitrate);
   if (bitrate == 0)
     bitrate = kDefaultBitrate;
 
@@ -735,8 +735,8 @@
   int64_t bytes_per_second = (bitrate / 8.0) * playback_rate;
 
   // Preload 10 seconds of data, clamped to some min/max value.
-  int64_t preload = base::clamp(preload_seconds_.value() * bytes_per_second,
-                                kMinBufferPreload, kMaxBufferPreload);
+  int64_t preload = std::clamp(preload_seconds_.value() * bytes_per_second,
+                               kMinBufferPreload, kMaxBufferPreload);
 
   // Increase buffering slowly at a rate of 10% of data downloaded so
   // far, maxing out at the preload size.
@@ -751,8 +751,8 @@
 
   // We pin a few seconds of data behind the current reading position.
   int64_t pin_backward =
-      base::clamp(keep_after_playback_seconds_.value() * bytes_per_second,
-                  kMinBufferPreload, kMaxBufferPreload);
+      std::clamp(keep_after_playback_seconds_.value() * bytes_per_second,
+                 kMinBufferPreload, kMaxBufferPreload);
 
   // We always pin at least kDefaultPinSize ahead of the read position.
   // Normally, the extra space between preload_high and kDefaultPinSize will
diff --git a/third_party/blink/tools/blinkpy/common/wpt_results_diff.py b/third_party/blink/tools/blinkpy/common/wpt_results_diff.py
new file mode 100644
index 0000000..94fa6f6
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/common/wpt_results_diff.py
@@ -0,0 +1,144 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from blinkpy.common import path_finder
+
+path_finder.bootstrap_wpt_imports()
+from wptrunner import manifestexpected
+from wptrunner.wptmanifest import node as wptnode
+from wptrunner.wptmanifest.backends import static
+
+_TEMPLATE = """<html>
+<head>
+<style>
+table { white-space: pre-wrap; font-family: monospace; border-collapse: collapse; }
+div {white-space: pre-wrap; font-family: monospace;}
+th { color: #444; background: #eed; text-align: right; vertical-align: baseline; padding: 1px 4px 1px 4px; }
+.del { background: #faa; }
+.add { background: #afa; }
+.miss { background: #f5e642; }
+</style>
+</head>
+<body><table>%s</table></body>
+</html>
+"""
+
+
+def create_top_level_node(node):
+    top_level = wptnode.DataNode()
+    top_level.append(node)
+    return top_level
+
+
+# TODO(nihardamar): right now we're on the fly comparing subtests which may be empty and assuming a positive
+# result. A potential refactor could be to simply build the trees earlier so they are the same structure,
+# that way we can also write an expected_results file for the error.
+def wpt_results_diff(expected_node, actual_node, file_path):
+    """
+        assumption for .ini files is that first arg is expected text and second is actual text
+    """
+
+    expected = None
+    if expected_node:
+        expected_top_level = create_top_level_node(expected_node)
+        expected = static.compile_ast(expected_top_level, {},
+                                      manifestexpected.data_cls_getter,
+                                      test_path=file_path).get_test(
+                                          actual_node.data)
+
+    actual_top_level = create_top_level_node(actual_node)
+    actual = static.compile_ast(actual_top_level, {},
+                                manifestexpected.data_cls_getter,
+                                test_path=file_path).get_test(actual_node.data)
+
+    return _TEMPLATE % WPTResultsDiffGenerator().generate_tbody(
+        expected, actual)
+
+
+class WPTResultsDiffGenerator:
+    def __init__(self):
+        self.tbody = ""
+
+    def generate_tbody(self, expected_node, actual_node):
+
+        self.compare_trees(expected_node, actual_node)
+        return self.tbody
+
+    def get_spaces(self, space_count):
+        return "&nbsp;" * space_count
+
+    def build_tbody_expected(self, spaces, name, result):
+        self.tbody += f"<div>{self.get_spaces(spaces)}[{name}]</div>"
+        self.tbody += f"<div>{self.get_spaces(spaces + 2)}expected: {result}</div>"
+        self.tbody += f"<div>\n</div>"
+
+    def build_tbody_diff(self, spaces, name, expected_result, actual_result):
+        self.tbody += f"<div>{self.get_spaces(spaces)}[{name}]</div>"
+        self.tbody += f"<div class=add>{self.get_spaces(spaces + 2)}expected: {expected_result}</div>"
+        self.tbody += f"<div class=del>{self.get_spaces(spaces + 2)}actual: {actual_result}</div>"
+        self.tbody += f"<div>\n</div>"
+
+    def build_tbody_miss(self, spaces, name, expected_result):
+        self.tbody += f"<div>{self.get_spaces(spaces)}[{name}]</div>"
+        self.tbody += f"<div class=miss>{self.get_spaces(spaces + 2)}expected: {expected_result}</div>"
+        self.tbody += f"<div>\n</div>"
+
+    def compare_single_results(self, actual_result, expected_result, spaces,
+                               name):
+        if actual_result == expected_result:
+            self.build_tbody_expected(spaces, name, expected_result)
+        else:
+            self.build_tbody_diff(spaces, name, expected_result, actual_result)
+
+    def compare_trees(self, expected_node, actual_node):
+        # important difference between expected and actual
+        # is that expected will omit PASS results
+
+        if expected_node:
+            # Test comparison
+            if expected_node.has_key("expected"):
+                self.compare_single_results(actual_node.expected,
+                                            expected_node.expected, 0,
+                                            actual_node.id)
+            else:
+                self.compare_single_results(actual_node.expected, "OK", 0,
+                                            actual_node.id)
+
+            # Subtest comparison
+            for actual_subtest in actual_node.subtests:
+                expected_result = "PASS"
+
+                if expected_node.get_subtest(
+                        actual_subtest) and expected_node.get_subtest(
+                            actual_subtest).has_key("expected"):
+                    expected_result = expected_node.get_subtest(
+                        actual_subtest).expected
+
+                self.compare_single_results(
+                    actual_node.get_subtest(actual_subtest).expected,
+                    expected_result, 2, actual_subtest)
+
+            # Case where a subtest is not run, but it exists in expected subtests
+            for expected_subtest in expected_node.subtests:
+                if actual_node.get_subtest(expected_subtest):
+                    continue
+                expected_result = "PASS"
+                if expected_node.get_subtest(
+                        expected_subtest) and expected_node.get_subtest(
+                            expected_subtest).expected:
+                    expected_result = expected_node.get_subtest(
+                        expected_subtest).expected
+                self.build_tbody_miss(2, expected_subtest, expected_result)
+        else:
+            # expected node is None, so no .ini file, assume all passes
+
+            # Test comparison
+            self.compare_single_results(actual_node.expected, "OK", 0,
+                                        actual_node.id)
+
+            # Subtest comparison
+            for actual_subtest in actual_node.subtests:
+                self.compare_single_results(
+                    actual_node.get_subtest(actual_subtest).expected, "PASS",
+                    2, actual_subtest)
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 0afc185..569a2e9 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -259,9 +259,6 @@
             'base::ClampSub',
             'base::MakeClampedNum',
 
-            # //base/cxx17_backports.h.
-            "base::clamp",
-
             # //base/strings/strcat.h.
             'base::StrCat',
 
diff --git a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py
index e0b0e812..f951bcb 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt.py
@@ -19,16 +19,20 @@
 from blinkpy.common.host import Host
 from blinkpy.common.system.filesystem import FileSystem
 from blinkpy.tool.commands.command import Command
+from blinkpy.tool.commands.update_metadata import (
+    BUG_PATTERN,
+    TestConfigurations,
+)
 from blinkpy.w3c.wpt_manifest import WPTManifest
-from blinkpy.tool.commands.update_metadata import BUG_PATTERN, generate_configs
+from blinkpy.web_tests.port.base import Port
 
 path_finder.bootstrap_wpt_imports()
 from tools.lint import lint as wptlint
 from tools.lint import rules
-from wptrunner import metadata, wptmanifest
+from wptrunner import manifestupdate, metadata, wptmanifest
 from wptrunner.manifestexpected import fuzzy_prop
 from wptrunner.wptmanifest import node as wptnode
-from wptrunner.wptmanifest.backends.static import Compiler
+from wptrunner.wptmanifest.backends import conditional, static
 
 _log = logging.getLogger(__name__)
 
@@ -222,6 +226,19 @@
     """
 
 
+class MetadataLongTimeout(MetadataRule):
+    name = 'META-LONG-TIMEOUT'
+    description = ('%(test)r should be disabled when it consistently times '
+                   "out even with 'timeout=long'")
+    to_fix = """
+    To reduce resource waste, add a `disabled: ...` key that disables the test
+    for configurations where there are consistent timeouts.
+
+    Splitting a `testharness.js` test with many subtests may also help them run
+    to completion.
+    """
+
+
 LintError = Tuple[str, str, str, Optional[int]]
 ValueNode = Union[wptnode.ValueNode, wptnode.AtomNode, wptnode.ListNode]
 Condition = Optional[wptnode.Node]
@@ -249,13 +266,13 @@
 
     def __init__(self,
                  tool: Host,
-                 configs: Optional[Collection[metadata.RunInfo]] = None):
+                 configs: Optional[TestConfigurations] = None):
         super().__init__()
         self._tool = tool
         self._fs = self._tool.filesystem
         self._default_port = self._tool.port_factory.get()
         self._finder = path_finder.PathFinder(self._fs)
-        self._configs = configs or generate_configs(self._tool)
+        self._configs = configs or TestConfigurations.generate(self._tool)
 
     def parse_args(self, args: List[str]) -> Tuple[optparse.Values, List[str]]:
         # TODO(crbug.com/1431070): Migrate `blink_tool.py` to stdlib's
@@ -359,7 +376,8 @@
             return [MetadataBadSyntax.error(path, context, error.line)]
 
         test_type = manifest.get_test_type(test_path) if test_path else None
-        linter = MetadataLinter(path, test_type, manifest, self._configs)
+        linter = MetadataLinter(path, test_path, test_type, manifest,
+                                repo_root, self._configs)
         return linter.find_errors(ast)
 
     def _manifest(self, repo_root: str) -> WPTManifest:
@@ -379,12 +397,20 @@
         return None
 
 
-class MetadataLinter(Compiler):
-    def __init__(self, path: str, test_type: str, manifest: WPTManifest,
-                 configs: Collection[metadata.RunInfo]):
+class MetadataLinter(static.Compiler):
+    def __init__(
+        self,
+        path: str,
+        test_path: Optional[str],
+        test_type: Optional[str],
+        manifest: WPTManifest,
+        metadata_root: str,
+        configs: TestConfigurations,
+    ):
+        super().__init__()
         self.path = path
-        self.test_type = test_type
-        self.manifest = manifest
+        self.test_path, self.test_type = test_path, test_type
+        self.manifest, self.metadata_root = manifest, metadata_root
         self.configs = configs
         # `context` contains information about the current section type,
         # heading, and key as it becomes available during the traversal. It's
@@ -392,7 +418,7 @@
         self.context = {}
         self.errors = set()
         # Check that all configurations have the same keys.
-        assert len(set({frozenset(config.data) for config in configs})) == 1
+        assert len({frozenset(config.data) for config in configs}) == 1
 
     @contextlib.contextmanager
     def using_context(self, **context):
@@ -408,12 +434,36 @@
         self.errors.clear()
         if self.test_type:
             initial_type = SectionType.ROOT
+            url_base = Port.WPT_DIRS[self.manifest.wpt_dir]
+            # Since the long timeout check requires examining both `disabled`
+            # and `expected` at the same time, use the high-level expectations
+            # API instead of checking during the syntax tree traversal.
+            expected = conditional.compile_ast(ast,
+                                               manifestupdate.data_cls_getter,
+                                               test_path=self.test_path,
+                                               run_info_properties=([], {}),
+                                               url_base=url_base)
+            self._check_for_long_timeouts(expected)
         else:
             initial_type = SectionType.DIRECTORY
         with self.using_context(next_type=initial_type):
             self.visit(ast)
         return sorted(self.errors, key=lambda error: error[:3])
 
+    def _check_for_long_timeouts(self,
+                                 expected: manifestupdate.ExpectedManifest):
+        for test_id in sorted(expected.child_map):
+            test = expected.get_test(test_id)
+            if test_id.startswith('/'):
+                test_id = test_id[1:]
+            if not self.manifest.is_slow_test(test_id):
+                continue
+            configs = self.configs.enabled_configs(test, self.metadata_root)
+            for config in configs:
+                with contextlib.suppress(KeyError):
+                    if test.get('expected', config) == 'TIMEOUT':
+                        self._error(MetadataLongTimeout, test=test_id)
+
     def visit(self, node: wptnode.Node):
         try:
             return super().visit(node)
diff --git a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py
index f804c58..bc1a45c 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/lint_wpt_unittest.py
@@ -11,9 +11,10 @@
 from typing import List
 
 from blinkpy.common import path_finder
+from blinkpy.common.system.log_testing import LoggingTestCase
 from blinkpy.tool.mock_tool import MockBlinkTool
 from blinkpy.tool.commands.lint_wpt import LintError, LintWPT
-from blinkpy.common.system.log_testing import LoggingTestCase
+from blinkpy.tool.commands.update_metadata import TestConfigurations
 
 path_finder.bootstrap_wpt_imports()
 from wptrunner import metadata
@@ -47,7 +48,12 @@
             'flag_specific': 'fake-flag',
             'product': 'content_shell',
         }]
-        self.command = LintWPT(self.tool, set(map(metadata.RunInfo, configs)))
+        configs = {
+            metadata.RunInfo(config):
+            self.tool.port_factory.get('test-linux-trusty')
+            for config in configs
+        }
+        self.command = LintWPT(self.tool, TestConfigurations(self.fs, configs))
         self.fs.write_text_file(self.finder.path_from_wpt_tests('lint.ignore'),
                                 '')
         self.fs.write_text_file(
@@ -71,8 +77,12 @@
                         },
                         'variant.html': [
                             'b8db5972284d1ac6bbda0da81621d9bca5d04ee7',
-                            ['variant.html?foo=bar/abc', {}],
-                            ['variant.html?foo=baz', {}],
+                            ['variant.html?foo=bar/abc', {
+                                'timeout': 'long'
+                            }],
+                            ['variant.html?foo=baz', {
+                                'timeout': 'long'
+                            }],
                         ],
                     },
                 },
@@ -210,14 +220,14 @@
         out_of_order_subtests, out_of_order_tests = self._check_metadata(
             """\
             [variant.html?foo=baz]
-              expected: TIMEOUT
+              expected: PRECONDITION_FAILED
               [subtest 2]
                 expected: NOTRUN
               [subtest 1]
-                expected: TIMEOUT
+                expected: PRECONDITION_FAILED
 
             [variant.html?foo=bar/abc]
-              expected: TIMEOUT
+              expected: PRECONDITION_FAILED
             """, 'variant.html.ini')
         name, description, path, _ = out_of_order_tests
         self.assertEqual(name, 'META-UNSORTED-SECTION')
@@ -626,3 +636,36 @@
         self.assertEqual(
             description, "Test '[reftest.html]' key 'expected' has "
             "a single-element list that should be unwrapped to 'FAIL'")
+
+    def test_metadata_long_timeout(self):
+        (error, ) = self._check_metadata(
+            """\
+            [variant.html?foo=bar/abc]
+              disabled:
+                if os == "mac": slow
+              expected:
+                # Already disabled
+                if os == "mac": TIMEOUT
+                # Does not need to be disabled because the test sometimes runs OK.
+                [TIMEOUT, OK]
+            [variant.html?foo=baz]
+              expected:
+                if os == "mac": TIMEOUT
+            """, 'variant.html.ini')
+        name, description, path, _ = error
+        self.assertEqual(name, 'META-LONG-TIMEOUT')
+        self.assertEqual(path, 'variant.html.ini')
+        self.assertEqual(
+            description, "'variant.html?foo=baz' should be disabled when "
+            "it consistently times out even with 'timeout=long'")
+
+    def test_metadata_long_timeout_already_disabled(self):
+        self.fs.write_text_file(
+            self.finder.path_from_wpt_tests('__dir__.ini'),
+            'disabled: bulk disable of slow tests that timeout\n')
+        with self._patch_builtins():
+            errors = self._check_metadata("""\
+                [variant.html?foo=baz]
+                  expected: TIMEOUT
+                """)
+        self.assertEqual(errors, [])
diff --git a/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py b/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py
index 2d42d35..5b19dc7f 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py
@@ -169,7 +169,7 @@
         manifests = load_and_update_manifests(self._path_finder)
         updater = MetadataUpdater.from_manifests(
             manifests,
-            generate_configs(self._tool),
+            TestConfigurations.generate(self._tool),
             self._tool.filesystem,
             self._explicit_include_patterns(options, args),
             options.exclude,
@@ -468,46 +468,121 @@
         setattr(parser.values, option.dest, reports)
 
 
-def generate_configs(host: Host) -> Dict[metadata.RunInfo, Port]:
-    """Construct run info representing all Chromium test environments.
+class TestConfigurations(collections.abc.Mapping):
+    def __init__(self, fs: FileSystem, configs):
+        self._fs = fs
+        self._finder = path_finder.PathFinder(self._fs)
+        self._configs = configs
+        self._get_dir_manifest = memoized(manifestexpected.get_dir_manifest)
 
-    Each property in a config represents a value that metadata keys can be
-    conditioned on (e.g., 'os').
-    """
-    configs = {}
-    wptrunner_builders = {
-        builder
-        for builder in host.builders.all_builder_names()
-        if host.builders.uses_wptrunner(builder)
-    }
+    def __getitem__(self, config: metadata.RunInfo) -> Port:
+        return self._configs[config]
 
-    for builder in wptrunner_builders:
-        port_name = host.builders.port_name_for_builder_name(builder)
-        _, build_config, *_ = host.builders.specifiers_for_builder(builder)
+    def __len__(self) -> int:
+        return len(self._configs)
 
-        for step in host.builders.step_names_for_builder(builder):
-            flag_specific = host.builders.flag_specific_option(builder, step)
-            port = host.port_factory.get(
-                port_name,
-                optparse.Values({
-                    'configuration': build_config,
-                    'flag_specific': flag_specific,
-                }))
-            product = host.builders.product_for_build_step(builder, step)
-            config = metadata.RunInfo({
-                'product':
-                product,
-                'os':
-                port.operating_system(),
-                'port':
-                port.version(),
-                'debug':
-                port.get_option('configuration') == 'Debug',
-                'flag_specific':
-                flag_specific or '',
-            })
-            configs[config] = port
-    return configs
+    def __iter__(self) -> Iterator[metadata.RunInfo]:
+        return iter(self._configs)
+
+    @classmethod
+    def generate(cls, host: Host) -> 'TestConfigurations':
+        """Construct run info representing all Chromium test environments.
+
+        Each property in a config represents a value that metadata keys can be
+        conditioned on (e.g., 'os').
+        """
+        configs = {}
+        wptrunner_builders = {
+            builder
+            for builder in host.builders.all_builder_names()
+            if host.builders.uses_wptrunner(builder)
+        }
+
+        for builder in wptrunner_builders:
+            port_name = host.builders.port_name_for_builder_name(builder)
+            _, build_config, *_ = host.builders.specifiers_for_builder(builder)
+
+            for step in host.builders.step_names_for_builder(builder):
+                flag_specific = host.builders.flag_specific_option(
+                    builder, step)
+                port = host.port_factory.get(
+                    port_name,
+                    optparse.Values({
+                        'configuration': build_config,
+                        'flag_specific': flag_specific,
+                    }))
+                product = host.builders.product_for_build_step(builder, step)
+                debug = port.get_option('configuration') == 'Debug'
+                config = metadata.RunInfo({
+                    'product': product,
+                    'os': port.operating_system(),
+                    'port': port.version(),
+                    'debug': debug,
+                    'flag_specific': flag_specific or '',
+                })
+                configs[config] = port
+        return cls(host.filesystem, configs)
+
+    def enabled_configs(self, test: manifestupdate.TestNode,
+                        metadata_root: str) -> Set[metadata.RunInfo]:
+        """Find configurations where the given test is enabled.
+
+        This method also checks parent `__dir__.ini` to give a definitive
+        answer.
+
+        Arguments:
+            test: Test node holding expectations in conditional form.
+            test_path: Path to the test file (relative to the test root).
+            metadata_root: Absolute path to where the `.ini` files are stored.
+        """
+        return {
+            config
+            for config in self._configs
+            if not self._config_disabled(config, test, metadata_root)
+        }
+
+    def _config_disabled(
+        self,
+        config: metadata.RunInfo,
+        test: manifestupdate.TestNode,
+        metadata_root: str,
+    ) -> bool:
+        with contextlib.suppress(KeyError):
+            port = self._configs[config]
+            if port.default_smoke_test_only():
+                test_id = test.id
+                if test_id.startswith('/'):
+                    test_id = test_id[1:]
+                if (not self._finder.is_wpt_internal_path(test_id)
+                        and not self._finder.is_wpt_path(test_id)):
+                    test_id = self._finder.wpt_prefix() + test_id
+                if port.skipped_due_to_smoke_tests(test_id):
+                    return True
+        with contextlib.suppress(KeyError):
+            return test.get('disabled', config)
+        test_dir = test.parent.test_path
+        while test_dir:
+            test_dir = self._fs.dirname(test_dir)
+            abs_test_dir = self._fs.join(metadata_root, test_dir)
+            disabled = self._directory_disabled(abs_test_dir, config)
+            if disabled is not None:
+                return disabled
+        return False
+
+    def _directory_disabled(self, dir_path: str,
+                            config: metadata.RunInfo) -> Optional[bool]:
+        """Check if a `__dir__.ini` in the given directory disables tests.
+
+        Returns:
+            * True if the directory disables tests.
+            * False if the directory explicitly enables tests.
+            * None if the key is not present (e.g., `__dir__.ini` doesn't
+              exist). We may need to search other `__dir__.ini` to get a
+              conclusive answer.
+        """
+        metadata_path = self._fs.join(dir_path, '__dir__.ini')
+        manifest = self._get_dir_manifest(metadata_path, config)
+        return manifest.disabled if manifest else None
 
 
 class UpdateAbortError(Exception):
@@ -527,8 +602,7 @@
         self,
         test_files: TestFileMap,
         slow_tests: Set[str],
-        configs: Dict[metadata.RunInfo, Port],
-        fs: FileSystem,
+        configs: TestConfigurations,
         primary_properties: Optional[List[str]] = None,
         dependent_properties: Optional[Mapping[str, str]] = None,
         overwrite_conditions: Literal['yes', 'no', 'fill'] = 'fill',
@@ -539,7 +613,6 @@
     ):
         self._configs = configs
         self._slow_tests = slow_tests
-        self._fs = fs
         self._default_expected = _default_expected_by_type()
         self._primary_properties = primary_properties or [
             'debug',
@@ -595,7 +668,7 @@
                                   if getattr(test, 'timeout', None) == 'long')
             finally:
                 manifest.itertypes = itertypes
-        return cls(test_files, slow_tests, configs, fs, **options)
+        return cls(test_files, slow_tests, configs, **options)
 
     def collect_results(self, reports: Iterable[io.TextIOBase]) -> Set[str]:
         """Parse and record test results."""
@@ -660,11 +733,8 @@
             # instead of replaying every result.
             if not updated_configs:
                 continue
-            enabled_configs = {
-                config
-                for config in self._configs
-                if not self._config_disabled(test_file, test, config)
-            }
+            enabled_configs = self._configs.enabled_configs(
+                test, test_file.metadata_path)
             missing_configs = enabled_configs - updated_configs
             for config in missing_configs:
                 self._updater.suite_start({'run_info': config.data})
@@ -750,53 +820,6 @@
         subtest_data = subtests.get(subtest_id, [])
         return frozenset(run_info for _, run_info, _ in subtest_data)
 
-    def _config_disabled(
-        self,
-        test_file: metadata.TestFileData,
-        test: manifestupdate.TestNode,
-        config: metadata.RunInfo,
-    ) -> bool:
-        """Check if a test is disabled for a given configuration."""
-        with contextlib.suppress(KeyError):
-            port = self._configs[config]
-            if port.default_smoke_test_only():
-                finder = path_finder.PathFinder(self._fs)
-                test_id = test.id
-                if test_id.startswith('/'):
-                    test_id = test_id[1:]
-                if (not finder.is_wpt_internal_path(test_id)
-                        and not finder.is_wpt_path(test_id)):
-                    test_id = finder.wpt_prefix() + test_id
-                if port.skipped_due_to_smoke_tests(test_id):
-                    return True
-        with contextlib.suppress(KeyError):
-            return test.get('disabled', config)
-        test_dir = test_file.test_path
-        while test_dir:
-            test_dir = self._fs.dirname(test_dir)
-            abs_test_dir = self._fs.join(test_file.metadata_path, test_dir)
-            disabled = self._directory_disabled(abs_test_dir, config)
-            if disabled is not None:
-                return disabled
-        return False
-
-    @memoized
-    def _directory_disabled(self, dir_path: str,
-                            config: metadata.RunInfo) -> Optional[bool]:
-        """Check if a `__dir__.ini` in the given directory disables tests.
-
-        Returns:
-            * True if the directory disables tests.
-            * False if the directory explicitly enables tests.
-            * None if the key is not present (e.g., `__dir__.ini` doesn't
-              exist). We may need to search other `__dir__.ini` to get a
-              conclusive answer.
-        """
-        metadata_path = self._fs.join(dir_path, '__dir__.ini')
-        manifest = manifestexpected.get_dir_manifest(metadata_path,
-                                                     config.data)
-        return manifest.disabled if manifest else None
-
     def update(self, test_file: metadata.TestFileData) -> bool:
         """Update and serialize the AST of a metadata file.
 
diff --git a/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py
index 0c132da..1dfdffd5 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py
@@ -18,7 +18,7 @@
 from blinkpy.tool.commands.update_metadata import (
     UpdateMetadata,
     MetadataUpdater,
-    generate_configs,
+    TestConfigurations,
     load_and_update_manifests,
     sort_metadata_ast,
 )
@@ -578,7 +578,7 @@
 
     def test_generate_configs(self):
         linux, linux_highdpi, mac = sorted(
-            generate_configs(self.tool),
+            TestConfigurations.generate(self.tool),
             key=lambda config: (config['os'], config['flag_specific']))
 
         self.assertEqual(linux['os'], 'linux')
@@ -627,11 +627,12 @@
                     **result
                 } for result in report['results']]
 
-            configs = {
-                metadata.RunInfo(report['run_info']):
-                report.pop('test_port', self.tool.port_factory.get())
-                for report in reports
-            }
+            configs = TestConfigurations(
+                self.tool.filesystem, {
+                    metadata.RunInfo(report['run_info']): report.pop(
+                        'test_port', self.tool.port_factory.get())
+                    for report in reports
+                })
             updater = MetadataUpdater.from_manifests(manifests, configs,
                                                      self.tool.filesystem,
                                                      **options)
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py
index 33b7c9b1..4cb05cf4 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py
@@ -25,7 +25,7 @@
 import mozinfo
 
 from blinkpy.common import path_finder
-from blinkpy.common.html_diff import html_diff
+from blinkpy.common.wpt_results_diff import wpt_results_diff
 from blinkpy.common.memoized import memoized
 from blinkpy.common.system.filesystem import FileSystem
 from blinkpy.common.unified_diff import unified_diff
@@ -166,6 +166,9 @@
     def actual_metadata(self):
         return wptmanifest.serialize(self._test_section)
 
+    def test_section(self):
+        return self._test_section
+
 
 def _test_basename(test_id: str) -> str:
     # The test "basename" is test path + query string + fragment
@@ -597,14 +600,15 @@
         if not test_manifest:
             raise ValueError('test ID does not exist')
         update_with_static_expectations(test_manifest)
-        return wptmanifest.serialize(test_manifest.node)
+        return test_manifest
 
     def _write_text_results(self, test_name: str, artifacts: Artifacts,
-                            actual_text: str, file_path: str):
+                            actual_text: str, file_path: str,
+                            actual_node: Any):
         """Write actual, expected, and diff text outputs to disk, if possible.
 
         If the expected output (WPT metadata) is missing, this method will not
-        produce diffs.
+        produce diff, but will still produce pretty diff.
 
         Arguments:
             test_name: Web test name (a path).
@@ -617,33 +621,42 @@
             test_name, test_failures.FILENAME_SUFFIX_ACTUAL, '.txt')
         artifacts.CreateArtifact('actual_text', actual_subpath,
                                  actual_text.encode())
+        expected_file_exists = True
 
         try:
-            expected_text = self._read_expected_metadata(test_name, file_path)
+            expected_manifest = self._read_expected_metadata(
+                test_name, file_path)
         except FileNotFoundError:
             _log.debug('".ini" file for "%s" does not exist.', file_path)
-            return
+            expected_file_exists = False
         except (ValueError, KeyError, wptmanifest.parser.ParseError) as error:
             _log.warning('Unable to parse metadata for %s: %s', test_name,
                          error)
-            return
-        expected_subpath = self.port.output_filename(
-            test_name, test_failures.FILENAME_SUFFIX_EXPECTED, '.txt')
-        artifacts.CreateArtifact('expected_text', expected_subpath,
-                                 expected_text.encode())
+            expected_file_exists = False
 
-        diff_content = unified_diff(
-            expected_text,
-            actual_text,
-            expected_subpath,
-            actual_subpath,
-        )
-        diff_subpath = self.port.output_filename(
-            test_name, test_failures.FILENAME_SUFFIX_DIFF, '.txt')
-        artifacts.CreateArtifact('text_diff', diff_subpath,
-                                 diff_content.encode())
+        if expected_file_exists:
+            expected_text = wptmanifest.serialize(expected_manifest.node)
+            expected_subpath = self.port.output_filename(
+                test_name, test_failures.FILENAME_SUFFIX_EXPECTED, '.txt')
+            artifacts.CreateArtifact('expected_text', expected_subpath,
+                                     expected_text.encode())
 
-        html_diff_content = html_diff(expected_text, actual_text)
+            diff_content = unified_diff(
+                expected_text,
+                actual_text,
+                expected_subpath,
+                actual_subpath,
+            )
+            diff_subpath = self.port.output_filename(
+                test_name, test_failures.FILENAME_SUFFIX_DIFF, '.txt')
+            artifacts.CreateArtifact('text_diff', diff_subpath,
+                                     diff_content.encode())
+
+        expected_node = None
+        if expected_file_exists:
+            expected_node = expected_manifest.node
+        html_diff_content = wpt_results_diff(expected_node, actual_node,
+                                             file_path)
         html_diff_subpath = self.port.output_filename(
             test_name, test_failures.FILENAME_SUFFIX_HTML_DIFF, '.html')
         artifacts.CreateArtifact('pretty_text_diff', html_diff_subpath,
@@ -725,7 +738,8 @@
         leaf = self._leaves[result.name]
         if result.actual not in [ResultType.Pass, ResultType.Skip]:
             self._write_text_results(result.name, artifacts,
-                                     result.actual_metadata, result.file_path)
+                                     result.actual_metadata, result.file_path,
+                                     result.test_section())
             screenshots = (extra or {}).get('reftest_screenshots') or []
             if screenshots:
                 diff_stats = self._write_screenshots(result.name, artifacts,
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py
index 3afe7b3..807f351d 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py
@@ -195,6 +195,10 @@
                     self.fs.join('layout-test-results', 'wpt_internal',
                                  'reftest-actual.txt'),
                 ],
+                'pretty_text_diff': [
+                    self.fs.join('layout-test-results', 'wpt_internal',
+                                 'reftest-pretty-diff.html'),
+                ]
             })
         self.assertTrue(self.processor.has_regressions)
 
@@ -496,8 +500,9 @@
             self.fs.join('/mock-checkout', 'out', 'Default',
                          'layout-test-results',
                          'variant_foo=baz-pretty-diff.html'))
+
         self.assertIn('expected: FAIL', pretty_diff)
-        self.assertIn('expected: CRASH', pretty_diff)
+        self.assertIn('actual: CRASH', pretty_diff)
 
     def test_extract_text_multiglobal(self):
         # Similar to a test with variants, the processor should extract the
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_data_types.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_data_types.py
new file mode 100644
index 0000000..57e03dd3
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_data_types.py
@@ -0,0 +1,63 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Module for all data type definitions."""
+
+from typing import Any, Dict, List, Tuple
+from collections import namedtuple
+
+TypTagTupleType = Tuple[str, ...]
+# Image diff data, first item is color difference,
+# second item is pixel difference, third is build url, example: [2, 30, 'url']
+ImageDiffTagTupleType = namedtuple(
+    'ImageDiffTagTupleType',
+    ['color_difference', 'pixel_difference', 'build_url'])
+
+# Sample:
+# {
+#   'test_name': {
+#     ('typ', 'tags', 'as', 'tuple'): [ (0, 200, 'url_1'), (3, 400, 'url_2'),],
+#   },
+# }
+TestToTypTagsType = Dict[TypTagTupleType, List[ImageDiffTagTupleType]]
+AggregatedResultsType = Dict[str, TestToTypTagsType]
+
+
+class Result:
+    """Container for an image diff test result.
+
+    Contains all the relevant information we get back from BigQuery for a result
+    for the purposes of the fuzzy diff analyzer.
+    """
+    def __init__(self, test: str, typ_tags: TypTagTupleType,
+                 image_diff_tag: Tuple[int, int], build_id: str):
+        """Class for store an image diff web tests data.
+
+        Args:
+          test: The test name.
+          typ_tags: A tuple of typ tags such as ('linux', 'x86')
+          image_diff_tag: A tuple containing image diff data, first is color
+          difference, second is the pixel difference.
+          build_id: The build id for this test.
+        """
+        assert isinstance(typ_tags, tuple), \
+          'Typ tags must be in tuple form to be hashable'
+        assert isinstance(image_diff_tag, tuple), \
+          'Image diff tag must be in tuple form to be hashable'
+        assert len(image_diff_tag) == 2, 'Image diff tag must be 2 length'
+        # Results should not have any globs.
+        assert '*' not in test
+        self.test = test
+        self.typ_tags = typ_tags
+        self.image_diff_tag = image_diff_tag
+        self.build_id = build_id
+
+    def __eq__(self, other: Any) -> bool:
+        return (isinstance(other, Result) and self.test == other.test
+                and self.typ_tags == other.typ_tags
+                and self.image_diff_tag == other.image_diff_tag
+                and self.build_id == other.build_id)
+
+    def __hash__(self) -> int:
+        return hash(
+            (self.test, self.typ_tags, self.image_diff_tag, self.build_id))
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_data_types_unittest.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_data_types_unittest.py
new file mode 100644
index 0000000..98d4f4d4d
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_data_types_unittest.py
@@ -0,0 +1,65 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import typing
+import unittest
+
+from blinkpy.web_tests.fuzzy_diff_analyzer import fuzzy_diff_analyzer_data_types as data_types
+
+
+class FuzzyDiffAnalyzerDataTypesUnittest(unittest.TestCase):
+    def testTypTagsTupleEnforced(self) -> None:
+        """Tests that typ tags must be in a tuple."""
+        fake_typ_tuple = typing.cast(tuple, ['win', 'x86'])
+        with self.assertRaises(AssertionError):
+            _ = data_types.Result('test', fake_typ_tuple, (1, 10), 'build_id')
+
+    def testImageDiffTupleEnforced(self) -> None:
+        """Tests that image diff tag must be in a tuple."""
+        fake_image_diff_tuple = typing.cast(tuple, [1, 10])
+        with self.assertRaises(AssertionError):
+            _ = data_types.Result('test', ('win', 'x86'),
+                                  fake_image_diff_tuple, 'build_id')
+
+    def testImageDiffLengthEnforced(self) -> None:
+        """Tests that image diff tag must be 2 length."""
+        with self.assertRaises(AssertionError):
+            _ = data_types.Result('test', ('win', 'x86'), (1, 2, 3),
+                                  'build_id')
+
+    def testWildcardsDisallowed(self) -> None:
+        with self.assertRaises(AssertionError):
+            _ = data_types.Result('t*', ('win', 'x86'), (1, 10), 'id')
+
+    def testHashability(self) -> None:
+        """Tests that Result objects are hashable."""
+        r = data_types.Result('test_1', ('win', 'x86'), (1, 10), 'id')
+        test_set = set([r])
+        test_set.add(r)
+        self.assertEqual(1, len(test_set))
+
+        r = data_types.Result('test_2', ('win', 'x86'), (2, 30), 'id')
+        test_set.add(r)
+        self.assertEqual(2, len(test_set))
+
+    def testEquality(self) -> None:
+        """Tests that equality is properly calculated."""
+        r = data_types.Result('test_1', ('win', 'x86'), (1, 10), 'id')
+        other = data_types.Result('test_1', ('win', 'x86'), (1, 10), 'id')
+        self.assertEqual(r, other)
+
+        other = data_types.Result('test_2', ('win', 'x86'), (1, 10), 'id')
+        self.assertNotEqual(r, other)
+
+        other = data_types.Result('test_1', ('win', 'arm64'), (1, 10), 'id')
+        self.assertNotEqual(r, other)
+
+        other = data_types.Result('test_1', ('win', 'x86'), (2, 11), 'id')
+        self.assertNotEqual(r, other)
+
+        other = data_types.Result('test_1', ('win', 'x86'), (1, 10), 'id_2')
+        self.assertNotEqual(r, other)
+
+        other = None
+        self.assertNotEqual(r, other)
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_results.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_results.py
new file mode 100644
index 0000000..a70b9ea
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_results.py
@@ -0,0 +1,58 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Module for working with BigQuery results."""
+
+from collections import defaultdict
+from typing import List, Tuple
+
+from flake_suppressor_common import common_typing as ct
+from flake_suppressor_common import tag_utils
+from blinkpy.web_tests.fuzzy_diff_analyzer import fuzzy_diff_analyzer_data_types as dt
+
+
+class ResultProcessor:
+    def aggregate_results(
+            self, results: ct.QueryJsonType) -> dt.AggregatedResultsType:
+        """Aggregates BigQuery results for all image comparison tests.
+
+        Args:
+          results: Parsed JSON test results from a BigQuery query.
+
+        Returns:
+          A map in the following format:
+          {
+            'test_name': {
+              'typ_tags_as_tuple': [ (0, 200, 'url_1'), (3, 400, 'url_2'),],
+            },
+          }
+        """
+        results = self._convert_json_results_to_result_objects(results)
+        aggregated_results = defaultdict(lambda: defaultdict(list))
+        for r in results:
+            build_url = 'http://ci.chromium.org/b/%s' % r.build_id
+            aggregated_results[r.test][r.typ_tags].append(
+                dt.ImageDiffTagTupleType(r.image_diff_tag[0],
+                                         r.image_diff_tag[1], build_url))
+        return aggregated_results
+
+    def _convert_json_results_to_result_objects(
+            self, results: ct.QueryJsonType) -> List[dt.Result]:
+        """Converts JSON BigQuery results to data_types.Result objects.
+
+        Args:
+          results: Parsed JSON results from a BigQuery query
+
+        Returns:
+          The contents of |results| as a list of data_types.Result objects.
+        """
+        object_results = []
+        for r in results:
+            build_id = r['id'].split('-')[-1]
+            typ_tags = tuple(
+                tag_utils.TagUtils.RemoveIgnoredTags(r['typ_tags']))
+            image_diff_tag = (int(r['image_diff_max_difference']),
+                              int(r['image_diff_total_pixels']))
+            object_results.append(
+                dt.Result(r['name'], typ_tags, image_diff_tag, build_id))
+        return object_results
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_results_unittest.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_results_unittest.py
new file mode 100644
index 0000000..28151c14
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer_results_unittest.py
@@ -0,0 +1,95 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+
+from blinkpy.web_tests.fuzzy_diff_analyzer import fuzzy_diff_analyzer_data_types as data_types
+from blinkpy.web_tests.fuzzy_diff_analyzer import fuzzy_diff_analyzer_results as results_processor
+from flake_suppressor_common import tag_utils as common_tag_utils
+from flake_suppressor_common import unittest_utils as uu
+
+
+class BaseResultsUnittest(unittest.TestCase):
+    def setUp(self) -> None:
+        common_tag_utils.SetTagUtilsImplementation(uu.UnitTestTagUtils)
+        self._result_processor = results_processor.ResultProcessor()
+
+
+class AggregateResultsUnittest(BaseResultsUnittest):
+    def testBasic(self) -> None:
+        """Basic functionality test."""
+        query_results = [
+            {
+                'name': ('conformance/textures/misc/video-rotation.html'),
+                'id': 'build-1111',
+                'typ_tags': ['win'],
+                'image_diff_max_difference': '10',
+                'image_diff_total_pixels': '40',
+            },
+            {
+                'name': ('conformance/textures/misc/video-rotation.html'),
+                'id': 'build-2222',
+                'typ_tags': ['win'],
+                'image_diff_max_difference': '15',
+                'image_diff_total_pixels': '42',
+            },
+            {
+                'name': ('conformance/textures/misc/video-rotation.html'),
+                'id': 'build-3333',
+                'typ_tags': ['linux'],
+                'image_diff_max_difference': '10',
+                'image_diff_total_pixels': '40',
+            },
+            {
+                'name': ('conformance/textures/misc/texture-npot-video.html'),
+                'id': 'build-4444',
+                'typ_tags': ['win'],
+                'image_diff_max_difference': '10',
+                'image_diff_total_pixels': '40',
+            },
+        ]
+        expected_output = {
+            'conformance/textures/misc/video-rotation.html': {
+                tuple(['win']): [(10, 40, 'http://ci.chromium.org/b/1111'),
+                                 (15, 42, 'http://ci.chromium.org/b/2222')],
+                tuple(['linux']): [(10, 40, 'http://ci.chromium.org/b/3333')],
+            },
+            'conformance/textures/misc/texture-npot-video.html': {
+                tuple(['win']): [(10, 40, 'http://ci.chromium.org/b/4444')],
+            },
+        }
+        self.assertEqual(
+            self._result_processor.aggregate_results(query_results),
+            expected_output)
+
+
+class ConvertJsonResultsToResultObjectsUnittest(BaseResultsUnittest):
+    def testBasic(self) -> None:
+        """Basic functionality test."""
+        r = [
+            {
+                'name': 'conformance/textures/misc/video-rotation.html',
+                'id': 'build-1111',
+                'typ_tags': ['win', 'x86'],
+                'image_diff_max_difference': '10',
+                'image_diff_total_pixels': '40',
+            },
+            {
+                'name': 'conformance/textures/misc/video-rotation.html',
+                'id': 'build-1111',
+                'typ_tags': ['win', 'x86'],
+                'image_diff_max_difference': '12',
+                'image_diff_total_pixels': '45',
+            },
+        ]
+        expected_results = [
+            data_types.Result('conformance/textures/misc/video-rotation.html',
+                              ('win', 'x86'), (10, 40), '1111'),
+            data_types.Result('conformance/textures/misc/video-rotation.html',
+                              ('win', 'x86'), (12, 45), '1111'),
+        ]
+
+        self.assertEqual(
+            self._result_processor._convert_json_results_to_result_objects(r),
+            expected_results)
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 d8b25104..7d614f0 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
+++ b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
@@ -84,6 +84,7 @@
 crbug.com/1209223 external/wpt/html/browsers/browsing-the-web/navigating-across-documents/javascript-url-security-check-same-origin-domain.sub.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 virtual/fenced-frame-mparch/wpt_internal/fenced_frame/unfenced-top.https.html [ Timeout ]
 crbug.com/626703 virtual/fenced-frame-mparch/wpt_internal/fenced_frame/can-load-api.https.html [ Timeout ]
 crbug.com/626703 virtual/threaded/external/wpt/long-animation-frame/tentative/loaf-script-block.html [ Timeout ]
 crbug.com/626703 external/wpt/png/cicp-chunk.html [ Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 819f3f81..789dabcf 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2932,7 +2932,8 @@
 crbug.com/626703 external/wpt/css/css-multicol/file-control-crash.html [ Crash ]
 
 # ====== New tests from wpt-importer added here ======
-crbug.com/626703 [ Win11 ] external/wpt/fetch/api/body/mime-type.any.worker.html [ Timeout Failure ]
+crbug.com/626703 virtual/fenced-frame-mparch/wpt_internal/fenced_frame/unfenced-top.https.html [ Skip Timeout ]
+crbug.com/626703 [ Win11 ] external/wpt/fetch/api/body/mime-type.any.worker.html [ Failure Timeout ]
 crbug.com/626703 [ Linux ] virtual/fenced-frame-mparch/external/wpt/html/anonymous-iframe/web-lock.tentative.https.window.html [ Timeout ]
 crbug.com/626703 [ Linux ] virtual/isolate-sandboxed-iframes/external/wpt/html/infrastructure/urls/terminology-0/document-base-url-initiated-grand-parent.https.window.html [ Timeout ]
 crbug.com/626703 [ Linux ] virtual/keepalive-in-browser-migration/external/wpt/fetch/metadata/generated/element-frame.https.sub.html [ Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index d38433a..8973baf 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1684,7 +1684,7 @@
     ],
     "exclusive_tests": "ALL",
     "args": [
-      "--enable-blink-features=SpeculationRulesPrefetchProxy,SpeculationRulesFetchFromHeader,SpeculationRulesDocumentRules,NoVarySearchPrefetch,SpeculationRulesEagerness",
+      "--enable-blink-features=SpeculationRulesPrefetchProxy,SpeculationRulesFetchFromHeader,SpeculationRulesDocumentRules,NoVarySearchPrefetch,SpeculationRulesEagerness,SpeculationRulesDocumentRulesSelectorMatches",
       "--enable-features=SpeculationRulesPrefetchProxy,PrefetchUseContentRefactor",
       "--bypass-prefetch-proxy-for-host=not-web-platform.test"
     ],
diff --git a/third_party/blink/web_tests/editing/caret/caret-in-empty-block-in-multicol-rtl.html b/third_party/blink/web_tests/editing/caret/caret-in-empty-block-in-multicol-rtl.html
new file mode 100644
index 0000000..c3ccdae
--- /dev/null
+++ b/third_party/blink/web_tests/editing/caret/caret-in-empty-block-in-multicol-rtl.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<style>
+#parent {
+  columns: 2;
+}
+#editor {
+  height: 100px;
+  padding: 10px;
+}
+</style>
+<div id="parent" dir="rtl">
+  <div id="editor" contenteditable></div>
+</div>
+<script>
+editor.focus();
+</script>
diff --git a/third_party/blink/web_tests/editing/caret/caret-in-empty-block-in-multicol.html b/third_party/blink/web_tests/editing/caret/caret-in-empty-block-in-multicol.html
new file mode 100644
index 0000000..37542c02
--- /dev/null
+++ b/third_party/blink/web_tests/editing/caret/caret-in-empty-block-in-multicol.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<style>
+#parent {
+  columns: 2;
+}
+#editor {
+  height: 100px;
+  padding: 10px;
+}
+</style>
+<div id="parent">
+  <div id="editor" contenteditable></div>
+</div>
+<script>
+editor.focus();
+</script>
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 b66c141..fa72d43e 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
@@ -5464,6 +5464,13 @@
         {}
        ]
       ],
+      "popover-hint-crash.tentative.html": [
+       "82f83538e93e364dc90b45aa41515a586ea2089b",
+       [
+        null,
+        {}
+       ]
+      ],
       "popover-manual-crash.html": [
        "535eb4c7d120186f620c376a149158900721fe12",
        [
@@ -85108,6 +85115,19 @@
        {}
       ]
      ],
+     "background-attachment-fixed.html": [
+      "003873228d65166a7aadea0f5dec0702b94fab51",
+      [
+       null,
+       [
+        [
+         "/css/css-break/background-attachment-fixed-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "background-image-000.html": [
       "27e78dc21cf932b9fea8a10ce1c677ce5dad6be5",
       [
@@ -105846,6 +105866,58 @@
        ],
        {}
       ]
+     ],
+     "quote-scoping-invalidation-001.html": [
+      "61ec4a481ffd20af97be0620334edfad6cef1954",
+      [
+       null,
+       [
+        [
+         "/css/css-contain/reference/quote-scoping-invalidation-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "quote-scoping-invalidation-002.html": [
+      "727ee9a58128bbb4eaeff87f2f3df988e8547da9",
+      [
+       null,
+       [
+        [
+         "/css/css-contain/reference/quote-scoping-invalidation-002-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "quote-scoping-invalidation-003.html": [
+      "24e69eb38fe7d18fd5e2359fdfb5d64440343192",
+      [
+       null,
+       [
+        [
+         "/css/css-contain/reference/quote-scoping-invalidation-003-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "quote-scoping-invalidation-004.html": [
+      "11b0d24f6680879aafd21853ea7abb07a55072c4",
+      [
+       null,
+       [
+        [
+         "/css/css-contain/reference/quote-scoping-invalidation-004-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
      ]
     },
     "css-content": {
@@ -106691,6 +106763,71 @@
        {}
       ]
      ],
+     "quotes-first-letter-001.html": [
+      "651615f5259d0cf4b972552e6e6a454c1127b7e3",
+      [
+       null,
+       [
+        [
+         "/css/css-content/reference/quotes-first-letter-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "quotes-first-letter-002.html": [
+      "8c40b1418a3ca0e3074ce6130ad372f8bb03c263",
+      [
+       null,
+       [
+        [
+         "/css/css-content/reference/quotes-first-letter-002-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "quotes-first-letter-003.html": [
+      "fd556d2ab12b704491c3ab36bbb4d1d045247d6a",
+      [
+       null,
+       [
+        [
+         "/css/css-content/reference/quotes-first-letter-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "quotes-first-letter-004.html": [
+      "932ea8516e12a9cd8d53de56fbea7d6317d2cbe6",
+      [
+       null,
+       [
+        [
+         "/css/css-content/reference/quotes-first-letter-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "quotes-first-letter-005.html": [
+      "a22589a661b5a043c7b1b5eb291e6aac20b0f688",
+      [
+       null,
+       [
+        [
+         "/css/css-content/reference/quotes-first-letter-002-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "quotes-slot-scoping.html": [
       "3caeabef4eccc76d8703825bf5db09e129186987",
       [
@@ -145604,45 +145741,6 @@
          {}
         ]
        ],
-       "clip-path-path-interpolation-001.html": [
-        "0c988e090e6b5775242208909b51e7dc83876664",
-        [
-         null,
-         [
-          [
-           "/css/css-masking/clip-path/animations/clip-path-path-interpolation-001-ref.html",
-           "=="
-          ]
-         ],
-         {}
-        ]
-       ],
-       "clip-path-path-interpolation-002.html": [
-        "4c1c485f7f814d6849b3dc41b0a1d2f0295068e3",
-        [
-         null,
-         [
-          [
-           "/css/css-masking/clip-path/animations/clip-path-path-interpolation-002-ref.html",
-           "=="
-          ]
-         ],
-         {}
-        ]
-       ],
-       "clip-path-path-interpolation-with-zoom.html": [
-        "50dc5e6f4e75cf8a1abfb5a972d94e6db23fa8c9",
-        [
-         null,
-         [
-          [
-           "/css/css-masking/clip-path/animations/clip-path-path-interpolation-with-zoom-ref.html",
-           "=="
-          ]
-         ],
-         {}
-        ]
-       ],
        "clip-path-transition-custom-timing-function.html": [
         "47b0cd6e751fe8c2282ce8c44746fa01d0340b30",
         [
@@ -146833,6 +146931,45 @@
         {}
        ]
       ],
+      "clip-path-path-interpolation-001.html": [
+       "9b12621b9d6bbd2575ce50ddd121faf69d436423",
+       [
+        null,
+        [
+         [
+          "/css/css-masking/clip-path/reference/clip-path-path-interpolation-001-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "clip-path-path-interpolation-002.html": [
+       "4cf6fb4a07d36891dd4785df5a742c6611f9dd0a",
+       [
+        null,
+        [
+         [
+          "/css/css-masking/clip-path/reference/clip-path-path-interpolation-002-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "clip-path-path-interpolation-with-zoom.html": [
+       "4d54708da198d2c35bc5980857a8248b9159d3d4",
+       [
+        null,
+        [
+         [
+          "/css/css-masking/clip-path/reference/clip-path-path-interpolation-with-zoom-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "clip-path-path-with-zoom.html": [
        "5879917f36e7efb74db4b1aaeb8a05bee96f39cd",
        [
@@ -269944,11 +270081,11 @@
   "support": {
    ".cache": {
     "gitignore2.json": [
-     "4525961c018afb980806d02ec8d507e564b42809",
+     "2ad079ea1bbedfaa41e9d38a31e6e06cbc59b0b3",
      []
     ],
     "mtime.json": [
-     "b45a80b6c172e1597c11c442d42ed4a1cd893828",
+     "511d51003e6d595a1b207d02e8897149734895a4",
      []
     ]
    },
@@ -271268,7 +271405,7 @@
      []
     ],
     "worklet-animation-local-time-null-2.https.html.ini": [
-     "c5c79208424782f15542cfeeb81c92e4f76affed",
+     "c8e4379a5730fba22b182832c3699d413910dd76",
      []
     ],
     "worklet-animation-pause-immediately.https.html.ini": [
@@ -288440,6 +288577,10 @@
       "b7013a90ab3834935522850a8cf5e02bf04fe7ef",
       []
      ],
+     "background-attachment-fixed-ref.html": [
+      "344c9d31643350f6e816804a3ad9cf30aad27a65",
+      []
+     ],
      "background-image-000-ref.html": [
       "bb63020d69d46460e994bcecf0aeffdb96f65b52",
       []
@@ -290726,22 +290867,6 @@
        []
       ]
      },
-     "quote-scoping-001.html.ini": [
-      "4ed5c3a5a026430868e153999d6c108743a422c9",
-      []
-     ],
-     "quote-scoping-002.html.ini": [
-      "754329ba6e88d83b912ca3b54da1ed8b67ef666a",
-      []
-     ],
-     "quote-scoping-003.html.ini": [
-      "37abc561465ac854979d5412185feae990945a0a",
-      []
-     ],
-     "quote-scoping-004.html.ini": [
-      "e12db6452eff25054307d32bc8a8ec9277c7dd9a",
-      []
-     ],
      "reference": {
       "contain-baseline-ref.html": [
        "1fdecb1c33149af52c48c105bce8ad91904bad44",
@@ -291067,6 +291192,22 @@
        "6437e08eb1a336d7ae9d69b1c1a47b67a3fd1a3f",
        []
       ],
+      "quote-scoping-invalidation-001-ref.html": [
+       "5c1a6203e62a8a57a450b33e09461856b5e3a6ab",
+       []
+      ],
+      "quote-scoping-invalidation-002-ref.html": [
+       "e48a080e9216ac6d0594588b6b531324501b57a2",
+       []
+      ],
+      "quote-scoping-invalidation-003-ref.html": [
+       "766ad6cbe9632388b0978a079d38154abf8f253b",
+       []
+      ],
+      "quote-scoping-invalidation-004-ref.html": [
+       "8280075f004a82682a07856242a8a6854c0eac82",
+       []
+      ],
       "ref-if-there-is-no-red.xht": [
        "a5b4e9f47a8e60ad0bede1ac81e02b3542c80f3b",
        []
@@ -291452,6 +291593,14 @@
       "quotes-034-ref.html": [
        "bfe7163f13276f181c2aeb765f20dad74c0cf204",
        []
+      ],
+      "quotes-first-letter-001-ref.html": [
+       "c68334b8da72b7d72a9c4539fb06dad06530f82f",
+       []
+      ],
+      "quotes-first-letter-002-ref.html": [
+       "094be48cd8c90b569b82ce26d9083daecca7ae44",
+       []
       ]
      },
      "resources": {
@@ -308400,18 +308549,6 @@
         "99126195a13b6e09a9e6080277a454d19c8576bf",
         []
        ],
-       "clip-path-path-interpolation-001-ref.html": [
-        "4e26ac61f62a61c3edb91d91acbd1aa1d5b35655",
-        []
-       ],
-       "clip-path-path-interpolation-002-ref.html": [
-        "567764a30124c2bc8821a508e2a7f8b6f0787c7e",
-        []
-       ],
-       "clip-path-path-interpolation-with-zoom-ref.html": [
-        "7e0d2a54266f3855dbc8e8e87167a06ea0cc323b",
-        []
-       ],
        "clip-path-transition-ref.html": [
         "af164c30f06808c3394cf3210ca13bc41792d53c",
         []
@@ -308666,7 +308803,7 @@
        []
       ],
       "clip-path-scaled-video.html.ini": [
-       "d83f400618c1ff40af94692f10746cfd962e3fc2",
+       "3ba1844a01451f1093076848d022ccd0d7e3e564",
        []
       ],
       "clip-path-scroll.html.ini": [
@@ -308721,6 +308858,10 @@
        "194c4734828bfd9ff496cbbc31cf2abcf4a57a67",
        []
       ],
+      "clip-path-svg-text-backdrop-filter.html.ini": [
+       "f181a1c6b467fe537f5a8ef866679f16bf4ff355",
+       []
+      ],
       "clip-path-viewBox-1a.html.ini": [
        "4b709fc4a168890f6b1ca5493b6bc6b281de29bd",
        []
@@ -308778,6 +308919,18 @@
         "d9ea5183fb1e6aa745c01f02e702df065d4945e6",
         []
        ],
+       "clip-path-path-interpolation-001-ref.html": [
+        "4e26ac61f62a61c3edb91d91acbd1aa1d5b35655",
+        []
+       ],
+       "clip-path-path-interpolation-002-ref.html": [
+        "567764a30124c2bc8821a508e2a7f8b6f0787c7e",
+        []
+       ],
+       "clip-path-path-interpolation-with-zoom-ref.html": [
+        "7e0d2a54266f3855dbc8e8e87167a06ea0cc323b",
+        []
+       ],
        "clip-path-path-with-zoom-ref.html": [
         "ef91c619c40615f633c64d59bfe302fcfbd8c5fb",
         []
@@ -309596,7 +309749,7 @@
        []
       ],
       "mask-with-rotation.svg.ini": [
-       "d0c6d887233de55df637594a2c52d50906d3cea9",
+       "80078da1f57382345acc2fc5895e34549a1fa9ff",
        []
       ],
       "reference": {
@@ -326727,6 +326880,10 @@
        "d8d05f85cdcff1cf718a9af855602ffd89e8b878",
        []
       ],
+      "kind-of-widget-fallback-input-reset-background-clip-001.html.ini": [
+       "35fd610ca98a59ca67e85a4a229c2604a0ff47e9",
+       []
+      ],
       "kind-of-widget-fallback-input-reset-background-size-001.html.ini": [
        "84b2aa611163625a43a4f6dddf833d523ef30051",
        []
@@ -326791,6 +326948,10 @@
        "14b26723f548de962341d22594eefaf841cec560",
        []
       ],
+      "kind-of-widget-fallback-input-search-background-clip-001.html.ini": [
+       "8d12dfe5143a2da958d4ef1d9fe09a2b9578e11a",
+       []
+      ],
       "kind-of-widget-fallback-input-search-background-image-001.html.ini": [
        "e78f02c6c1b94086e440f4a775baebd8ca017c53",
        []
@@ -326988,7 +327149,7 @@
        []
       ],
       "kind-of-widget-fallback-input-submit-border-block-end-width-001.html.ini": [
-       "0d819011f7f7df4cc05590aaa06da099f39e6597",
+       "8016a814a0f605f95889ebb0373f54f7779e02f5",
        []
       ],
       "kind-of-widget-fallback-input-submit-border-block-start-style-001.html.ini": [
@@ -327059,6 +327220,10 @@
        "7e86e3dde9c51af132c681e6c1b829bcefefbc34",
        []
       ],
+      "kind-of-widget-fallback-input-submit-border-right-style-001.html.ini": [
+       "92aa3cd1b0a5a00b7c008cabc4b74c39a8dc747e",
+       []
+      ],
       "kind-of-widget-fallback-input-submit-border-right-width-001.html.ini": [
        "1e55e271c6c6f134ac658bcefa5369580ea553da",
        []
@@ -334061,7 +334226,7 @@
       []
      ],
      "backdrop-filters-brightness.html.ini": [
-      "a95d0fb793c07b57e380d0d72eafdc6a502b81f4",
+      "3fb8d11144d59cc6c49d68d17a101d7dd7931582",
       []
      ],
      "backdrop-filters-contrast-ref.html": [
@@ -334072,6 +334237,10 @@
       "d90d0039fd8d209222414b66ba983ca3265cd9f1",
       []
      ],
+     "backdrop-filters-grayscale-002.html.ini": [
+      "ae3f41c16cc8093e8772c2da3ac54b9f0cebd0d8",
+      []
+     ],
      "backdrop-filters-grayscale-003.html.ini": [
       "7e2330ecc855ac7e6b03f56fe92a2f802d8b25a8",
       []
@@ -334089,7 +334258,7 @@
       []
      ],
      "backdrop-filters-invert.html.ini": [
-      "932dff64aa7e5694f2f063ce81506bfca0e006e6",
+      "5b3348f93919cedfcfb07f28b0900a32edf7cbbd",
       []
      ],
      "backdrop-filters-opacity-ref.html": [
@@ -336592,7 +336761,7 @@
    },
    "density-size-correction": {
     "density-corrected-image-in-canvas.html.ini": [
-     "bcf5c9bfd960d18be62a49b8b50de898a77453c1",
+     "7740502e869430ff2e403cac2e7e4a27c653a4ac",
      []
     ],
     "density-corrected-image-svg-aspect-ratio-cross-origin.sub.html.ini": [
@@ -341562,7 +341731,7 @@
      []
     ],
     "event-click-visibilitychange.html.ini": [
-     "89fce3af5f45a24479e5d44a20acf97bb5d594b2",
+     "0e015ebba321a525b88dfd96fff416c8cf80a461",
      []
     ],
     "first-input-interactionid-tap.html.ini": [
@@ -342113,10 +342282,22 @@
     }
    },
    "fenced-frame": {
+    "DIR_METADATA": [
+     "8c8f7d738ac69e05d9d64833808488b8074eb238",
+     []
+    ],
+    "README.md": [
+     "6055d17e978fec1d740b2cea1b6ef7723fe245f5",
+     []
+    ],
     "__dir__.ini": [
      "8f1e84e28c10c1aa66945d52ceac7792ebcd4a0f",
      []
     ],
+    "client-hints.https.html.headers": [
+     "56ce6114188741f4cc980575aa4467ae8d648023",
+     []
+    ],
     "default-enabled-features-allow-all.https.html.headers": [
      "d39cf98dd5c71f5777e73544886fccf9f664a01d",
      []
@@ -342145,7 +342326,51 @@
      "8df98474b589d070992677cb0134bd47bd0509c4",
      []
     ],
+    "input-on-coop-fenced-frame.https.html.headers": [
+     "073ce7adfbd81cb7c0b2f91f96c8349b6677f26c",
+     []
+    ],
+    "load-ad-with-size.https.html.ini": [
+     "3db75d1a4b8e6f24c13556fa58b0a16bff7abaa7",
+     []
+    ],
+    "prerender.https-expected.txt": [
+     "a00576dc4df64ccbf3010093b19bcbb5e838bf0e",
+     []
+    ],
     "resources": {
+     "ancestor-throttle-iframe-csp.https.html": [
+      "28fadb296cc430a9ef357d4a95ac40dd3615de3d",
+      []
+     ],
+     "ancestor-throttle-iframe-csp.https.html.headers": [
+      "bb76329b1dcc16c205081ddaf21b4b7dade1c291",
+      []
+     ],
+     "ancestor-throttle-iframe-xfo.https.html": [
+      "267aa076c0bf8810448d5163d066a80bd0361aee",
+      []
+     ],
+     "ancestor-throttle-iframe-xfo.https.html.headers": [
+      "63d5019c35ce98ab36ea5742d084b247872cc8de",
+      []
+     ],
+     "ancestor-throttle-inner.https.html": [
+      "e0977c73f0739cfef3b8e548733aadd3598714f1",
+      []
+     ],
+     "ancestor-throttle-inner.https.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "ancestor-throttle-nested.https.html": [
+      "a26b7bfdc200858d43c42b7ebcc0cff133daaafc",
+      []
+     ],
+     "ancestor-throttle-nested.https.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
      "background-fetch-inner.https.html": [
       "1bca25a957a3fe4069df838a5b7cbaa42e813f9b",
       []
@@ -342210,6 +342435,38 @@
       "98231079b33c62d75ef27b8604669197a9a6dc35",
       []
      ],
+     "client-hints-iframe-inner.sub.https.html": [
+      "d02abd6957e33895be8e4b1458b24bc38159ce71",
+      []
+     ],
+     "client-hints-iframe-inner.sub.https.html.headers": [
+      "f500a60ae889c308d0ba71c9d9244522c71b95ba",
+      []
+     ],
+     "client-hints-inner.sub.https.html": [
+      "0271d0290d553f98c5dd35711a11237431195122",
+      []
+     ],
+     "client-hints-inner.sub.https.html.headers": [
+      "ea4cf59d16a6816ca4c4dd9bef8f4ebe3e319fee",
+      []
+     ],
+     "client-hints-meta-iframe-inner.sub.https.html": [
+      "9afb5c6a8597c6dcc214984289b6cac8800181e6",
+      []
+     ],
+     "client-hints-meta-iframe-inner.sub.https.html.headers": [
+      "b7952e5d05993668ac3260f562a56eaa16776c55",
+      []
+     ],
+     "client-hints-meta-inner.sub.https.html": [
+      "b84f16ffd06e65828bbfaff7e6ab644f43ed7c02",
+      []
+     ],
+     "client-hints-meta-inner.sub.https.html.headers": [
+      "afe7b4f317dfacad8c25661dbe4dd2bf07b5b86e",
+      []
+     ],
      "content-index-sw.js": [
       "c2759d9630ea309b7ab2df65691df339a75c2d62",
       []
@@ -342298,6 +342555,22 @@
       "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
       []
      ],
+     "download-helper.js": [
+      "011d5c867f86f5a839de6d9ded45e498f5b589e8",
+      []
+     ],
+     "download-inner.html": [
+      "9bc816cbf3a2ec193b5b472342c1d76abd4d6af7",
+      []
+     ],
+     "download-inner.html.headers": [
+      "6247f6d63211cd39dffca9fc507aefcdee586eba",
+      []
+     ],
+     "download-stash.py": [
+      "497f7cb0187dd4a6382bb25a20a8f76ed3a285f1",
+      []
+     ],
      "dummy.html": [
       "a0cf50713ecd2e116a045a968c33446f03264aba",
       []
@@ -342374,6 +342647,102 @@
       "776bf2987b402ebe53f8b6af69992cd641dc5e0f",
       []
      ],
+     "frame-navigation-inner-create-nested.https.html": [
+      "9a56a3d9fbcf8d182522510ab6e39abd5aa34670",
+      []
+     ],
+     "frame-navigation-inner-create-nested.https.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "frame-navigation-inner-simple.https.html": [
+      "643ea48a7630b0f2ba61bc4383207901e1d67be0",
+      []
+     ],
+     "frame-navigation-inner-simple.https.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "frame-with-intersection-observer.html": [
+      "dd36b203995303f3eebb536e8cc3015c1043deca",
+      []
+     ],
+     "frame-with-intersection-observer.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "gamepad-inner.html": [
+      "3e253e4915f700dc8f985485ff0ac0defacc6138",
+      []
+     ],
+     "gamepad-inner.html.headers": [
+      "6247f6d63211cd39dffca9fc507aefcdee586eba",
+      []
+     ],
+     "get-nested-configs-inner.html": [
+      "a83ba93aa6d14dd9d03a77f9097c376810d25c3c",
+      []
+     ],
+     "get-nested-configs-inner.html.headers": [
+      "6247f6d63211cd39dffca9fc507aefcdee586eba",
+      []
+     ],
+     "get-nested-configs-nested-iframe.html": [
+      "9bd5d9f492ad4b48feabbfad249c842e533bf1d8",
+      []
+     ],
+     "get-nested-configs-nested-iframe.html.headers": [
+      "6247f6d63211cd39dffca9fc507aefcdee586eba",
+      []
+     ],
+     "get_battery.html": [
+      "0532deca4ba7184e3ce8752891368a27f3a4d549",
+      []
+     ],
+     "get_battery.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "header-referrer-inner.html": [
+      "2940dbac8e8a9015ae3cb62b72f673494cbfbcb7",
+      []
+     ],
+     "header-referrer-inner.html.headers": [
+      "6247f6d63211cd39dffca9fc507aefcdee586eba",
+      []
+     ],
+     "header-secFetchDest-inner.html": [
+      "aa3fe9e34cc678811cbbcea251a8ea94558122e9",
+      []
+     ],
+     "header-secFetchDest-inner.html.headers": [
+      "6247f6d63211cd39dffca9fc507aefcdee586eba",
+      []
+     ],
+     "history-back-and-forward-should-not-work-in-fenced-tree-inner.html": [
+      "9620249d76486c10197d923aa61be71e971e4d07",
+      []
+     ],
+     "history-back-and-forward-should-not-work-in-fenced-tree-inner.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "history-length-fenced-navigations-replace-do-not-contribute-to-joint-inner.html": [
+      "726fafd65bf829a7caa04d85a5dc6832cc3665f1",
+      []
+     ],
+     "history-length-fenced-navigations-replace-do-not-contribute-to-joint-inner.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "history-length-outer-page-navigation-not-reflected-in-fenced-inner.html": [
+      "2bdb90ab64c6fd61c9e9b5d0c718b05a5e778edb",
+      []
+     ],
+     "history-length-outer-page-navigation-not-reflected-in-fenced-inner.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
      "ignore-child-fenced-frame-onload-event-inner.html": [
       "4fe496f29c84806d0fa41c4d23851cd4878214c6",
       []
@@ -342386,6 +342755,14 @@
       "c9fd81b2a3d26978500ef9c025cb961eba875b92",
       []
      ],
+     "location-ancestorOrigins-inner.https.html": [
+      "3c9411c520988687f47d6ed01975e0206c9210cc",
+      []
+     ],
+     "location-ancestorOrigins-inner.https.html.headers": [
+      "6247f6d63211cd39dffca9fc507aefcdee586eba",
+      []
+     ],
      "navigate-ancestor-destination.https.html": [
       "f12849c8ec625f96ae8fd404d00e2a7bbbcefdaa",
       []
@@ -342442,6 +342819,14 @@
       "6247f6d63211cd39dffca9fc507aefcdee586eba",
       []
      ],
+     "navigate-nested-config.html": [
+      "85c5194c6c7746aedc9d78db8e1a222aa59e37ea",
+      []
+     ],
+     "navigate-nested-config.html.headers": [
+      "6247f6d63211cd39dffca9fc507aefcdee586eba",
+      []
+     ],
      "navigator-keyboard-layout-map-inner.html": [
       "59170c7512062a8195529210b41b9c0eabdeb2ab",
       []
@@ -342470,6 +342855,54 @@
       "8b5e83cddf0e2db994ae5527f8d7d4a6e057ddac",
       []
      ],
+     "permission-api-denied-inner.html": [
+      "06724ac0615d9a21991f88c9cf0941ce9ae4b1ed",
+      []
+     ],
+     "permission-api-denied-inner.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "permission-geolocation-inner.html": [
+      "07c3e662bf824c905649bef3df846736a2efb610",
+      []
+     ],
+     "permission-geolocation-inner.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "permission-geolocation-test-runner.html": [
+      "724a35ce9a568b7c8bd00d9042271b920e23698f",
+      []
+     ],
+     "permission-notification-inner.html": [
+      "d01d10034c1aa59910ae66d1c38ecb27ee7c96f8",
+      []
+     ],
+     "permission-notification-inner.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "popup-noopener-destination.html": [
+      "30cc21f22ca4a97fa22b54c5ee84c4a6ff966293",
+      []
+     ],
+     "popup-noopener-inner.html": [
+      "6a79fd21b297c626db6e032ec9f4efd9d1a957aa",
+      []
+     ],
+     "popup-noopener-inner.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "prerender-inner.html": [
+      "a523ef31c1a3423c3c11b607c7f497209e10054f",
+      []
+     ],
+     "prerender-inner.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
      "presentation-receiver-inner.html": [
       "2e170dd91bb32b896f72d20e5e064347c6558491",
       []
@@ -342490,6 +342923,22 @@
       "6247f6d63211cd39dffca9fc507aefcdee586eba",
       []
      ],
+     "resize-lock-inner-input.html": [
+      "cb17789b45055c280ff3a5f6be515a39758e34cc",
+      []
+     ],
+     "resize-lock-inner-input.html.headers": [
+      "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
+      []
+     ],
+     "resize-lock-inner.html": [
+      "fbaf436330f5e6fe466110d4e0b0795f95b9a618",
+      []
+     ],
+     "resize-lock-inner.html.headers": [
+      "6247f6d63211cd39dffca9fc507aefcdee586eba",
+      []
+     ],
      "response-204.py": [
       "e6cf8d4ac9100aac67831686ff105fbc242aa06b",
       []
@@ -350294,7 +350743,7 @@
        []
       ],
       "clear-window-name.https.html.ini": [
-       "e7d16638a317dd20f4fe996ea5c07e9537e9c893",
+       "5bcd71c98ebefc4d6bfa1a475e731f108ec7136e",
        []
       ],
       "document-domain-removed-iframe-expected.txt": [
@@ -353685,7 +354134,7 @@
         []
        ],
        "reporting-observer.html.ini": [
-        "7965b2c9212999599e1236adee1133ab8f5c88c2",
+        "2b82b238a310c2e7b61e452b8d9160e42f643109",
         []
        ]
       },
@@ -361544,7 +361993,7 @@
        ],
        "decode": {
         "image-decode-iframe.html.ini": [
-         "e93e004c661d52ccd15729be3a409737a343c315",
+         "ad8883e85a158e04a4cd82edd9353c025dc7c735",
          []
         ]
        },
@@ -361859,7 +362308,7 @@
         []
        ],
        "object-events.html.ini": [
-        "ce15add966c29a2f17bc6d9552d8c0929eab780b",
+        "055c09e0a3b41bb850ba3bd68afbae4fad4dff11",
         []
        ],
        "object-fallback-failed-cross-origin-navigation.sub-expected.txt": [
@@ -369534,7 +369983,7 @@
      []
     ],
     "cross-origin-iframe.sub.html.ini": [
-     "89dc46716c2b8e0f4685c83e4dba22ece1bcc6c3",
+     "0543237396f7c6faaa4042963ca3eeb9de224d0d",
      []
     ],
     "idlharness.window-expected.txt": [
@@ -369965,7 +370414,7 @@
     ]
    },
    "lint.ignore": [
-    "862a2ba050bb0a9fbbc06ddcd71bc9af8d4b6a87",
+    "cda77f4df8c7bec58570fcee614f393fffe60a03",
     []
    ],
    "loading": {
@@ -371348,7 +371797,7 @@
        []
       ],
       "tabindex-002.html.ini": [
-       "5dcce868229beef768e8ab19329f07ae2c2ed748",
+       "b35f85201bf65981b91626b2ee45b7c539802fb9",
        []
       ],
       "unique-identifier-1-iframe-1.html": [
@@ -372024,11 +372473,11 @@
      []
     ],
     "mediasource-correct-frames-after-reappend.html.ini": [
-     "924c37ee9b53a1c14c95c990b0e0e1ef06619310",
+     "743e81a72e476e7cc34397de0fe532e344f7d5b4",
      []
     ],
     "mediasource-correct-frames.html.ini": [
-     "ddf4760f6601067839989cb18238f7d84b22a0ab",
+     "2d071fe67e06ed495538cd2383b0c036741ff15b",
      []
     ],
     "mediasource-duration-expected.txt": [
@@ -372424,7 +372873,7 @@
      []
     ],
     "MediaRecorder-peerconnection-no-sink.https.html.ini": [
-     "d7186be95ff23a95179185d71ced951b88263c89",
+     "d1f792e6bf97f7ec2ba2bbdf4f1ed2e196f3253d",
      []
     ],
     "MediaRecorder-peerconnection.https.html.ini": [
@@ -372615,10 +373064,6 @@
      "79737eaeca9fab57a3811f99c05cfd882f9662d5",
      []
     ],
-    "idlharness.https.window-expected.txt": [
-     "144a7fa0cce98d5783bc29353eede5a23056d864",
-     []
-    ],
     "idlharness.https.window.js.ini": [
      "6498a7cf2d7e89c685fbfa4bce5d45bec949a1d7",
      []
@@ -374718,7 +375163,7 @@
      []
     ],
     "navigation-id-resource-timing.tentative.html.ini": [
-     "f2408ea2c085f8bb46302e703b1f8da0f015b0e3",
+     "303699b750f25587fd908f3f63d33c1eda57eaba",
      []
     ],
     "navigation-id.helper.js": [
@@ -374916,6 +375361,14 @@
       "387cc8e3bcc66e0b71bfbaf51f29622278537502",
       []
      ],
+     "private-state-token-redemption-default-permissions-policy.tentative.https.sub.html.ini": [
+      "9f4614a19526af696c44120bd6b9617882820401",
+      []
+     ],
+     "private-state-token-redemption-supported-by-permissions-policy.tentative.html.ini": [
+      "5e44491d4d8c0f58aa863eb4b47660e9a1c1b8a2",
+      []
+     ],
      "resources": {
       "common.js": [
        "308f787da63d147b00356cf4817f8c33b162c6cb",
@@ -374933,8 +375386,8 @@
        "fd3da53a29c3e7f55f950611d34694867b0ff0a4",
        []
       ],
-      "permissions-policy-trust-token-redemption.html": [
-       "db24b04824c235027095205ac9cc051066e921ed",
+      "permissions-policy-private-state-token-redemption.html": [
+       "7a055f0e7bfb8740b20afc1e43df0e0d66a5ef93",
        []
       ],
       "unload-helper.js": [
@@ -374970,14 +375423,6 @@
        []
       ]
      },
-     "trust-token-redemption-default-permissions-policy.tentative.https.sub.html.ini": [
-      "95f36f7071600858605e8bbbd9ff26c769a60b9f",
-      []
-     ],
-     "trust-token-redemption-supported-by-permissions-policy.tentative.html.ini": [
-      "a54ad04c8585af431bd123c07479959332908ee2",
-      []
-     ],
      "vertical-scroll-main-frame-manual.tentative.html.headers": [
       "8d9c01e14835acbc0af74b5b9157a4a8b95243f8",
       []
@@ -383027,7 +383472,7 @@
       []
      ],
      "unregister-immediately-during-extendable-events.https.html.ini": [
-      "4507f109d4a7c9681a8acaa819e15213d5906200",
+      "099411deb66fa0fed34a5258192b037681df15b1",
       []
      ],
      "unregister-then-register-new-script.https-expected.txt": [
@@ -383871,39 +384316,39 @@
     },
     "prerender": {
      "about-blank-iframes.html.ini": [
-      "eee27e12168717219be8c3f2830df40141ed67bf",
+      "15f2a68eeddb7e095a7488af3efae8b91ad4004a",
       []
      ],
      "accept-clint-hint-cache.https.html.ini": [
-      "e35a01fd7fd92b8334123d4f81fb2ac70f81ce70",
+      "a89648017d86b1f126d04587ac2302fafa40ade1",
       []
      ],
      "activation-start.html.ini": [
-      "ca5a9c78961f4100945e566b4467d38e1fb7e9cf",
+      "e116e0db3d3d2f2721cffd8506d4ec40994c8e2b",
       []
      ],
      "cache-storage.https.html.ini": [
-      "a0b6f6990bdc7e10dfa6d0f89f6952516c7bf8d8",
+      "70bdc22bd2c416ee39a5cdb3abf9e7b7c15afb47",
       []
      ],
      "clients-matchall.https.html.ini": [
-      "6837e4c4817134ed915cad8cdb1d84a03930349f",
+      "d158edd74cd9232b9f824d65b86ccab07dcfb88c",
       []
      ],
      "cookies.https.html.ini": [
-      "251b3471d47bc9f15c9901ee97908abcc2947bf6",
+      "cfca822abfbcb74e7d8aae0a6f79c9e61723bc72",
       []
      ],
      "credentialed-prerender-opt-in.html.ini": [
-      "9beef48da5e5559f7dbc7b678fc0fc09774eae7a",
+      "8801d5b51fb9c8bc92b5efb682eb5b8ff3c1493d",
       []
      ],
      "cross-origin-iframe.html.ini": [
-      "6baae604fb44eea872de39aae7b176cff2cd1b35",
+      "a16b689afb4577ac50a4d877b5bd5fda011918f2",
       []
      ],
      "cross-origin-isolated.https.html.ini": [
-      "a2c4df468947ee68b7304e4e4f12f7fe16f0b6f1",
+      "f9732f4a1224652cbebf55c5ef4837f9eafca310",
       []
      ],
      "csp-script-src-elem-inline-speculation-rules.tentative.html.ini": [
@@ -383919,35 +384364,35 @@
       []
      ],
      "csp-script-src-strict-dynamic.html.ini": [
-      "6563cff979a6a2b6a097280b64097676ec223e8c",
+      "5cb3798c82a672a0aa44fe3704f09ba6e2320e38",
       []
      ],
      "csp-script-src-unsafe-inline.html.ini": [
-      "191ed7f745ff643f911ba24b76cda823a9fdace0",
+      "3021c8872299a642a5c9c322fc0bc351dac7ce9d",
       []
      ],
      "fetch-blob.html.ini": [
-      "7d9696ef4468e9f26c33da54722c54c9d51805c9",
+      "d37fa6a479b034bbae96d1e6716948eeecc81816",
       []
      ],
      "fetch-intercepted-by-service-worker.https.html.ini": [
-      "e2ca52f23b59ab36fdc8428d018f67613574f6cf",
+      "65a50baa3ea15187f65298afe498ee6a733d5852",
       []
      ],
      "iframe-added-post-activation.html.ini": [
-      "7d679b0e1cadbf51933a625a1fdbe73380cc5faa",
+      "43c2772eeb0d3e81f415c9558ef3f60b5d1d198b",
       []
      ],
      "indexeddb.html.ini": [
-      "8f43c365e676ea9d979e094958a65eb8c47c5ce5",
+      "2a080fb802f136b03920319f09a5f4b52d8b2501",
       []
      ],
      "local-storage.html.ini": [
-      "2b5676071995f3d381de824ae711dffe6278b8c3",
+      "20709c81d4adc07ae90e79c36011420f75101509",
       []
      ],
      "main-frame-navigation.https.html.ini": [
-      "742da7108a833ad200ed7feb5d93e430e6704a0c",
+      "155ce16ff7508bed23b2a138ac6f4fcea0cea822",
       []
      ],
      "media-autoplay-expected.txt": [
@@ -383955,19 +384400,19 @@
       []
      ],
      "media-autoplay.html.ini": [
-      "aeb045e766ab18857817dae07562768e6f84f696",
+      "4375eb5474c5500d6d9975ecc8fe8f4291d84b60",
       []
      ],
      "navigation-intercepted-by-service-worker.https.html.ini": [
-      "4efbbff04dba9fc52ecf9c05efc274d684cda92d",
+      "d3cae063b95407abb8255cd8c28f07633b142d6f",
       []
      ],
      "navigator-plugins.tentative.html.ini": [
-      "be80e7407dc508b5c3d41fffd0385c159aa890c0",
+      "31b9a7f734b756c6d6fcff3edc3f02189cbfc927",
       []
      ],
      "navigator-subapp.https.tentative.html.ini": [
-      "b59f8528347ebeaa2cd36507b9528f95ea206806",
+      "a220b7b72f1467d05a18fc9961a5b21e09b8b852",
       []
      ],
      "prefetch.https.html.ini": [
@@ -383979,27 +384424,27 @@
       []
      ],
      "referrer-policy-mismatch.html.ini": [
-      "7dce1222075e1621bea7b284e397dd798ce762fd",
+      "7b9c5b65f313683e3495405dc1ce86a0f7f2083e",
       []
      ],
      "referrer-policy-no-referrer.html.ini": [
-      "4ce7c0767407f551c3037c1d563bfb41b54eb6ac",
+      "cdb0a5cbdc0cbce87e2510011473eb94a657234d",
       []
      ],
      "referrer-policy-origin.html.ini": [
-      "8451be50733f07bff66a07c4e5c74504cdc1e89e",
+      "67b549445614dd61ffeef87ccc761b1f7162b916",
       []
      ],
      "referrer-policy-strict-origin.html.ini": [
-      "4b21fd4e3ccbb00c6d217a4aeefe25ff23227d6d",
+      "73b1bfb248fbaccdb0750c7a6b41205358206f25",
       []
      ],
      "referrer.html.ini": [
-      "a32534cf8d671a4f6003b7618758c3819805876e",
+      "00518007a7982191090ee065d1e46cbf26e6ed01",
       []
      ],
      "register-service-worker.https.html.ini": [
-      "db713f6a715f97dc1577c34811c85ad8a50ac876",
+      "b3ba96844cfff12dd6f5c9f9d0774a30d0a6d01b",
       []
      ],
      "resources": {
@@ -384421,199 +384866,199 @@
       []
      ],
      "restriction-audio-setSinkId-with-invalid-sinkId.https.tentative.html.ini": [
-      "5dd34491d1b84c5efd98d0e3766d19509aa0d052",
+      "f3c5e33c2981750ca07bba697a5ec64c693f273b",
       []
      ],
      "restriction-audio-setSinkId.https.tentative.html.ini": [
-      "0ff6e76f112c55de24e811c3700b90d5b2a51f0d",
+      "2635df52e4ea5979e274614bbb4ecfbc8866278c",
       []
      ],
      "restriction-background-fetch.https.html.ini": [
-      "1ac295b334d2b0181d434ad896e7d9e0469372b4",
+      "66fd117289a5fc2bedf99ce4634217d852561619",
       []
      ],
      "restriction-background-sync.tentative.https.html.ini": [
-      "893f72f908bc206f384871e0d4aeac5946b59531",
+      "fb0a21fd22f180119a1d935fa73fcd782223e4f0",
       []
      ],
      "restriction-battery-status.https.html.ini": [
-      "90dee5cce9835a5c1e5529d76859ce8b3171ccd4",
+      "4cdf4ace04cded6446bcf63a9fb69293326d7e48",
       []
      ],
      "restriction-bluetooth.tentative.https.html.ini": [
-      "1018a2fc7b9588c66c60843c45b30f5647013135",
+      "78e6d0e563950fa90f3e0a6c6839bc283fe0189c",
       []
      ],
      "restriction-broadcast-channel.html.ini": [
-      "d174790e1f16087aeb063113cbb50f2740f28697",
+      "6064b01418fc29d3733b03f2c4b626b9d9f947bd",
       []
      ],
      "restriction-dedicated-worker.https.html.ini": [
-      "a8944b78a2e662243ee17f80267bcdeb61c83499",
+      "748cf85221eb66fbd844e12f29e2b7efb83faeb4",
       []
      ],
      "restriction-encrypted-media-unsupported-config.https.html.ini": [
-      "9d332b176cb56fc612c20f6a863282c7b03e1aaa",
+      "e6e00f8b3b6c5572139c70e83a73956a39fba681",
       []
      ],
      "restriction-encrypted-media.https.html.ini": [
-      "e87ab013b8a7a2eaabd247ff4ca8a77c463d00b6",
+      "463706028c21ead17ab84cfaec1b882baccd0297",
       []
      ],
      "restriction-focus.html.ini": [
-      "c68dd60d1a75da7cf736a43571f95d4efef3883c",
+      "9538fafb46603ddb9b065b9e026f53c1c012d8bd",
       []
      ],
      "restriction-idle-detection.https.html.ini": [
-      "53b068270a81e4b8efcff96a90a143f5f36fb4a6",
+      "da69b36f75bab779615212d47b600110f6dc8df9",
       []
      ],
      "restriction-local-file-system-access.https.html.ini": [
-      "1ba40e694d06fdb6540fdd06c95a5fc413bac8e5",
+      "45bbe74988ab48f00946a81adf744c3ed50eb859",
       []
      ],
      "restriction-media-auto-play-attribute.html.ini": [
-      "66742d368ccc70a5dd063f28bf578ad6ab1cc43d",
+      "924ea8ade34ad476a72999ac8374cd342c016e6c",
       []
      ],
      "restriction-media-camera.https.html.ini": [
-      "6c294d0667b55bb94d67171dd5a56fa6e8cdaa47",
+      "738d253980c8189cb27b8fbf0866202b1a633805",
       []
      ],
      "restriction-media-device-info.https.html.ini": [
-      "a23bb17d22c89c43d4e2a73f009c13de0238f591",
+      "61d296a68e0c55b2583ddb13538efd99857afd6e",
       []
      ],
      "restriction-media-microphone.https.html.ini": [
-      "6e30e4dbe254c538c9ba457ca42750b94a0029b6",
+      "e85411a4b7eca6c894822bdb5af772c60f89e21b",
       []
      ],
      "restriction-media-play.html.ini": [
-      "813502fd866e6774091b6e51c4b957e74fef29c4",
+      "9f5436f149bb483f8526b5e6eff3545845de3448",
       []
      ],
      "restriction-message-boxes.html.ini": [
-      "5ca869cb703f21fc0d13f73395f8143dc0cf42c7",
+      "ab996156ee607066516475c6a1a46e8a3a50b73b",
       []
      ],
      "restriction-midi-sysex.https.html.ini": [
-      "f97d8b4d9146ab40eab5ddc560ad07576af41973",
+      "556ea50bdf38e212282451feb353b8351fe8e77e",
       []
      ],
      "restriction-midi.https.html.ini": [
-      "1ba11ff3269140b99e0563420d2f308a4c5e7e22",
+      "12865807d1e5c6fbe576d0adc5fd2aea0e8b5aaf",
       []
      ],
      "restriction-notification.https.html.ini": [
-      "00e171547a6cb114f8a31c0101be65e4dbc9df1b",
+      "3805cbf625445dedad811060493e178128a47c91",
       []
      ],
      "restriction-presentation-request.https.html.ini": [
-      "014edcaea08187b72dc82def14525b5fd1c194e8",
+      "58f8e8f7eb968b170db9bbc91f9a72f99eb8c610",
       []
      ],
      "restriction-prompt-by-before-unload.html.ini": [
-      "8943a52da46ce93ced4da72a74623c8105c8b180",
+      "0400a720606c36aa54705a5bd280f8743e79df1f",
       []
      ],
      "restriction-push.https.html.ini": [
-      "4779329d3032b90f0bcd3456f67bd95131a65b79",
+      "bdcef470fe54a8bf136f51bb1bb22f6a0a4d2d35",
       []
      ],
      "restriction-request-picture-in-picture.html.ini": [
-      "b276b792edb362704558b73b6e369f13fcfb9a59",
+      "74a349ba8bbdddba3342fdc15042d0900b4112c6",
       []
      ],
      "restriction-screen-capture.https.html.ini": [
-      "b24d1f2de37566a23c719551bac25d775cfa52f9",
+      "f6720a34067e74eeb727d8a2fab2b5b3c9a0716f",
       []
      ],
      "restriction-screen-orientation-lock.https.html.ini": [
-      "3b750165910a0c556064959906b89ccd8f130375",
+      "9680a561a93eabbc46aad70cf25c05dfd3451f72",
       []
      ],
      "restriction-sensor-accelerometer.https.html.ini": [
-      "7923b1f54580eb1ccadbfe89010c59f5b2a60b5c",
+      "d389e7703a4d6786dc65917c317d25780a7e4fd1",
       []
      ],
      "restriction-sensor-ambient-light-sensor.https.html.ini": [
-      "7604105a1cffd21a42bff0dddff4e4b35d575c86",
+      "64ee876aba53b0135cb96fc1ee5aa8ecc11ced05",
       []
      ],
      "restriction-sensor-gyroscope.https.html.ini": [
-      "a418c2f7afde34a23a514216b93cd2f0c217d92e",
+      "75954a142c03e57c20683e45ae056ea4ca606a5e",
       []
      ],
      "restriction-sensor-magnetometer.https.html.ini": [
-      "2fb9a9f54be08972874a8e618302d09b79d3070a",
+      "fc3e540904aa6ee0305d051a354d10d1030dd370",
       []
      ],
      "restriction-service-worker-postmessage.https.html.ini": [
-      "95868e1603180eb28b798a8b21ab9fa519894626",
+      "edf451f1138f9a63ecd13f176557057dd3e18049",
       []
      ],
      "restriction-service-worker-unregister.https.html.ini": [
-      "39994bdbf6fdad26308a59cd149f252bf24cdca5",
+      "e337ae3e9fe3c4d993533bc6cd5bc110fb15cc60",
       []
      ],
      "restriction-service-worker-update.https.html.ini": [
-      "9b17e751ff5c8a454f0fb1434ef7c0f8ffcb15b4",
+      "d9490c75ac13dc269bdbec813cd0d62d712ac525",
       []
      ],
      "restriction-speech-synthesis.html.ini": [
-      "f4624323a4a185e5c4cea6eea3461fbb64cf3805",
+      "279143cbea1f951faaced8562b5f780caacebefa",
       []
      ],
      "restriction-storage-persist.https.html.ini": [
-      "b182a0a9f64a36cb4dca820b2e9ca4a18d736b7a",
+      "f77b4fd99a05d022edb151f8fef3e75f40bd3ccb",
       []
      ],
      "restriction-wake-lock.https.html.ini": [
-      "8968bd90c98be03771200a5d930cc4d4db5fba29",
+      "716464b10e454e7eeb4a672fefcb390af774508c",
       []
      ],
      "restriction-web-hid.https.html.ini": [
-      "b65a55c49fd1db358ace6714d6f170e82898fdef",
+      "fc0e2947bee867a78132832c61ca7737f03e845d",
       []
      ],
      "restriction-web-locks.https.html.ini": [
-      "6cd318469cd4b61032a08cd3c100193f23078afa",
+      "fd27659940e63deea7ba34bbf2bf829668b782c2",
       []
      ],
      "restriction-web-nfc.https.html.ini": [
-      "8b504495fc3aae225a25e88c8c80fec62e451475",
+      "dffcae9805c1a334a22dfd42c239d186659bccb3",
       []
      ],
      "restriction-web-serial.tentative.https.html.ini": [
-      "cb21c440a07915e5c697add346a4dd689e794eac",
+      "2b1973274ecfb2e1158f61078ad1344971c0490c",
       []
      ],
      "restriction-web-share.https.html.ini": [
-      "a9c0545b40f3b19f06a8e2afdda969723c5485fc",
+      "9d5cb42c707c59470507c9b005b223eadc38bfef",
       []
      ],
      "restriction-web-usb.https.html.ini": [
-      "1481c56063eddea648966b6d1c8d59dba77ee9fb",
+      "5b7d5df13ac65a69d49b0c22fe9956d46d354255",
       []
      ],
      "restriction-web-xr-immersive-vr-session.https.html.ini": [
-      "6c113b2ec5450f2da088788846cb15ec42de043e",
+      "76115e12e5b6f1e8794a7dc8a8314c1bdb6c3a94",
       []
      ],
      "restriction-web-xr-inline-session.https.html.ini": [
-      "20922ee2ac9a3853ff8e8841b97690cfbdd5544e",
+      "522e3feecb5bc9ddc527c95aad2b3a1d1339d520",
       []
      ],
      "restriction-window-move.html.ini": [
-      "6b2a50d8dad8b42743ccca391611b626b41624c8",
+      "f70c295c91ce121752951c0694c79ae4e6f4e7b8",
       []
      ],
      "restriction-window-open.html.ini": [
-      "245368db503c115f17c749ad84583d784d50557d",
+      "8657f83495bb8fb0cb7d5502e1dfa717c6b8e527",
       []
      ],
      "restriction-window-resize.html.ini": [
-      "5e2909edb818508ad6395035d54c67cbff555f9e",
+      "4275a6e35f1ecd36ba12752ebbe777e2f2de5086",
       []
      ],
      "restrictions.html.ini": [
@@ -384621,7 +385066,7 @@
       []
      ],
      "sandbox-iframe.html.ini": [
-      "ed62e078766229bf1d93dfb334695080d46171d1",
+      "37f386bfc93885e96d238ea0729373d5cf94602d",
       []
      ],
      "service-workers.https.html.ini": [
@@ -384629,59 +385074,59 @@
       []
      ],
      "session-history-activation.https.html.ini": [
-      "08c85686db357339adf5220d13bfe182c6851fbe",
+      "d839cd0a9232d97ce31da6132f85dd0afdc489c7",
       []
      ],
      "session-history-location.https.html.ini": [
-      "44e4e48072b0872ffcb054c3abbf2348391f1210",
+      "3a6c36c9874c5a0567262fef7ffb3fcfa375adde",
       []
      ],
      "session-history-navigation.https.html.ini": [
-      "8194d4ebc445a30241d62a652212f8305eafbf23",
+      "dc642f5ce2e337222ffcdf47a03529f72828f963",
       []
      ],
      "session-history-pushstate.https.html.ini": [
-      "2e4711c7104ba208966b57fca58c586403372a3a",
+      "15c9b501222df3d74dcb79a33904c033d1804dc6",
       []
      ],
      "session-history-subframe-navigation.https.html.ini": [
-      "4141fe17f04861e1257fa143f211d68793b42519",
+      "727a7fc8ebb58131f14e6736fca23212452f3fa1",
       []
      ],
      "session-history-subframe-reload.https.html.ini": [
-      "ab5c561b898149fcb7871ac0130f87c6accfdf3a",
+      "3192ed037b602260df99ba4d736f0ff9548de32c",
       []
      ],
      "state-and-event.html.ini": [
-      "2f570890348cf3d96cb3e583045e7c5fb8703cb2",
+      "93c7a36616dd1b18f9fb6269803fd13ed84fa0c2",
       []
      ],
      "visibility-state.html.ini": [
-      "bffcc56ac0e34675615b02dcc6b964669d789249",
+      "8960e0be34d75092aa8d9526cd31feaf38770d36",
       []
      ],
      "web-database.https.html.ini": [
-      "9558e9783421aeb525e5f39f5e02ffed86a385dc",
+      "ab8ae616fc6f440687ad68ef7e7edd37d4521555",
       []
      ],
      "windowclient-navigate-to-cross-origin-url-on-iframe.https.html.ini": [
-      "92b0e5e9a11986f7fcacd38e71ea4aa6695cce11",
+      "3324bfb8fa300e06fd1beec5d3a6f3088afe6633",
       []
      ],
      "windowclient-navigate-to-same-origin-url-on-iframe.https.html.ini": [
-      "4235b8b0ef81babc44168f69ec5607ddd8db9789",
+      "d5abf2543bb4b05eb79d09ad5e67eda60af23bea",
       []
      ],
      "windowclient-navigate.https.html.ini": [
-      "c934bee68c7f3ef5408991957053874d901ea069",
+      "3c1da9e271f08775bec30956b2265a7e26ed6d64",
       []
      ],
      "workers-in-cross-origin-iframe.html.ini": [
-      "bc3a810dec604a50946197aaccc1f91cab5433dd",
+      "cde9c659499580197ccbaf9011ce4d649d0664cf",
       []
      ],
      "workers.html.ini": [
-      "794e82acc208449aaa25319963ec1447f48ed42d",
+      "01d27284333b0c618f0b515997040ed9dde80cba",
       []
      ]
     }
@@ -387996,7 +388441,7 @@
      []
     ],
     "failure.html.ini": [
-     "aec09b98e86c829dff0a7ca9fdf18c9b269fd285",
+     "74bd7a8a5eeeeabb6c0dcc25caa573079cd987b2",
      []
     ],
     "idlharness-shadowrealm.window-expected.txt": [
@@ -391541,6 +391986,10 @@
       ]
      }
     },
+    "postMessage_cross_domain_image_transfer_webgl.sub.htm.ini": [
+     "7676117d453f6e6115ebf6dc4b4bb6b77ca425e3",
+     []
+    ],
     "resources": {
      "post-cryptokey-to-opener.html": [
       "91c70165f03ec63615ac286dc9ae3555706f49ad",
@@ -391563,6 +392012,10 @@
      "compare.js": [
       "5341b374381ffeb44fcd7b8bc92c33cdc9826bd4",
       []
+     ],
+     "cross-domain-image-receive.htm": [
+      "253b34bd769734b8a096647a0afb3b69c98bb4af",
+      []
      ]
     },
     "with-options": {
@@ -391679,6 +392132,10 @@
      "b33ebb8f2bfa17e8cc33a6ec75d8d358b01e2b9f",
      []
     ],
+    "hard_sigmoid.https.any.js.ini": [
+     "72fe9565a99c5e5975ac518f919fad3543b91d09",
+     []
+    ],
     "hard_swish.https.any.js.ini": [
      "1d4d2d09471f27b2286b7dd04b2572bafe20b8ff",
      []
@@ -391691,6 +392148,10 @@
      "7b3310be72b46a3b99c5fea423dd8cbeda2cdfcd",
      []
     ],
+    "linear.https.any.js.ini": [
+     "b3bb1d888bd1a2392a2ea1b219e30afaacfe089a",
+     []
+    ],
     "matmul.https.any-expected.txt": [
      "d6271b0ce53393981b49d9e7ea211131b67a0705",
      []
@@ -391797,6 +392258,10 @@
        "3738e19f7c641020309de975b4474fd652fbcb35",
        []
       ],
+      "hard_sigmoid.json": [
+       "22fe7c6da0c2135ab663eec54d7bf3661c3d1e20",
+       []
+      ],
       "hard_swish.json": [
        "8d7812d21e23a1e9aef93dfd14bf2872d556550e",
        []
@@ -391805,6 +392270,10 @@
        "a95a9a0cfcee9bd549f2e1aed40429592b2049ba",
        []
       ],
+      "linear.json": [
+       "ded1d2d7e3537492497453b29c8dbaded5c6a3f3",
+       []
+      ],
       "log.json": [
        "c48406e707554630e93b074eafc34d3c4cb5d07b",
        []
@@ -391919,7 +392388,7 @@
       ]
      },
      "utils.js": [
-      "d24562eba1fe70f3c46b36c88426015c774505db",
+      "49f1762a3bb3716b7e4fcb89c988c9e6dc450a32",
       []
      ]
     },
@@ -392330,7 +392799,7 @@
      []
     ],
     "RTCRtpReceiver-getSynchronizationSources.https.html.ini": [
-     "e5eb21199da99d385eeb92b6dd5fa024652d1509",
+     "fb1b72fcf96a3417cfba194764c74d9c4b626e08",
      []
     ],
     "RTCRtpSender-getStats.https-expected.txt": [
@@ -392511,7 +392980,7 @@
       []
      ],
      "vp9-scalability-mode.https.html.ini": [
-      "86234908e66031ed4fdaaf66266580c859697a6f",
+      "ab351810151d9e0b50621f5d184e9f8b459bad9b",
       []
      ],
      "vp9.https.html.ini": [
@@ -392848,7 +393317,7 @@
      []
     ],
     "hardware-capability-stats.https.html.ini": [
-     "629a492ba0e16aa30d84570d405f7e28748fbaaa",
+     "ae8b422c7817afcd494136867230777558ef42c3",
      []
     ],
     "outbound-rtp.https-expected.txt": [
@@ -393466,7 +393935,7 @@
        []
       ],
       "backpressure-send.any.js.ini": [
-       "79fa753a59180878bbb109028d3fdce69a899ba7",
+       "84f0c69d11a32f30ddbc246644d93225349f8153",
        []
       ],
       "backpressure-send.any.sharedworker_wpt_flags=h2-expected.txt": [
@@ -425014,6 +425483,13 @@
    },
    "content-security-policy": {
     "base-uri": {
+     "base-uri-allow-leading-zero-port.sub.html": [
+      "614d7dd50eb464779fa10cee6603676c08ebb3b6",
+      [
+       null,
+       {}
+      ]
+     ],
      "base-uri-allow.sub.html": [
       "cda0c2db44faa685679152ddfd9f85fb0450dad6",
       [
@@ -425021,6 +425497,13 @@
        {}
       ]
      ],
+     "base-uri-deny-url-encoded-host.sub.html": [
+      "5e7fad9d9e367bfd5e6f156a31618416d5e83109",
+      [
+       null,
+       {}
+      ]
+     ],
      "base-uri-deny.sub.html": [
       "a5a78ae1a347930b759afbc1ec1ceac953eb9df7",
       [
@@ -468719,7 +469202,7 @@
        ]
       ],
       "modal-pseudo-class-in-has.html": [
-       "1bff896d49e97a289adafcd9580533ca3ede3ead",
+       "140f7cc4f83688a5a2bd7d666e110466157975ca",
        [
         null,
         {
@@ -492594,6 +493077,176 @@
     }
    },
    "fenced-frame": {
+    "add-fencedframe-to-detached-iframe.https.html": [
+     "37c0cd6cba832d73183b7c898d7c4319b47e111d",
+     [
+      null,
+      {}
+     ]
+    ],
+    "ancestor-throttle.https.html": [
+     "9b6dfb0d3051e3bd17c3886008ef3f2b085549b7",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
+    "anchor-focus.https.html": [
+     "262781f571ae8104012acaff183fb99462deb1eb",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "autofocus-denied.https.html": [
+     "ff6955a3b25370ee48e8c44e277ed70d836d2042",
+     [
+      null,
+      {}
+     ]
+    ],
+    "background-fetch.https.html": [
+     "7036f2bb5f3bb5e42b5af1b5f970141c0884b5ef",
+     [
+      null,
+      {}
+     ]
+    ],
+    "background-sync.https.html": [
+     "72eb44750b4f818d97f65af773d381b333966fb5",
+     [
+      null,
+      {}
+     ]
+    ],
+    "badging.https.html": [
+     "93683e096c7226bed6eb25066a535e2409283d01",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "battery_status.https.html": [
+     "d7e1dc028434d45f9ac4f4d512d3ef6a0bb25c23",
+     [
+      null,
+      {}
+     ]
+    ],
+    "before-unload.https.html": [
+     "d924b1d1a4db33aa4086d518d62c8e0d0c57ad70",
+     [
+      null,
+      {}
+     ]
+    ],
+    "can-load-api.https.html": [
+     "f9996dd5e9a7628b1ec61abe80bc47db3a632f52",
+     [
+      null,
+      {}
+     ]
+    ],
+    "change-src-attribute-after-config-installation-does-not-trigger-navigation.https.html": [
+     "7ad73d3a4b26bc831461b6991c27bd167715d289",
+     [
+      null,
+      {}
+     ]
+    ],
+    "client-hints-meta.https.html": [
+     "3a4acf1b261d687304b197b52183786d2f009747",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "client-hints.https.html": [
+     "fc7b8db08de58a2d0c5a024e8438b10dbbcde59f",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "compute-pressure.https.html": [
+     "81091afc8e374dbbe61570bdcbe6eb0d7a121543",
+     [
+      null,
+      {}
+     ]
+    ],
+    "config-installation-triggers-navigation-of-navigated-fenced-frame.https.html": [
+     "74f810f6d2faa381ef89e3933864ab8dfb4437c6",
+     [
+      null,
+      {}
+     ]
+    ],
+    "config-installation-triggers-navigation.https.html": [
+     "6a7238da0530598ff974d360ef8b9eaf92766390",
+     [
+      null,
+      {}
+     ]
+    ],
+    "config-with-empty-url-installation-unloads-navigated-fenced-frame.https.html": [
+     "13e6904cf9c59a98866f8f551ab3b4f9114e2973",
+     [
+      null,
+      {}
+     ]
+    ],
+    "consume-user-activation.https.html": [
+     "e4ad20d17b7fdcec69f25e652dab967f9b52cf65",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "content-index.https.html": [
+     "99af848492b04dbaae378b62b377888beef4f3b9",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "coop-bcg-swap.https.html": [
+     "5a414fdfa168ca3aef0eeef67199e8d71c47fdc4",
+     [
+      null,
+      {}
+     ]
+    ],
+    "create-credential.https.html": [
+     "15f0558e521d83b49891b326458d0cb04b1e4b4b",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
+    "create-in-sandbox-and-adopt-outside-sandbox.https.html": [
+     "4b4817b863ba4cefcec3842b71c6005b8b6e6aed",
+     [
+      null,
+      {}
+     ]
+    ],
     "csp-allowed.https.html": [
      "8c002bc8a9d03955d8ac7ff021fd1b326a16ad18",
      [
@@ -492713,6 +493366,13 @@
       {}
      ]
     ],
+    "deprecated-config-apis.https.html": [
+     "11cd247f23dc79a35025c21d96f000d216f93d1a",
+     [
+      null,
+      {}
+     ]
+    ],
     "disallowed-navigation-to-blob.https.html": [
      "9b299cd5e1e03641586004eb0b53ab14ce3bfd1b",
      [
@@ -492767,6 +493427,29 @@
       }
      ]
     ],
+    "document-picture-in-picture-denied.https.html": [
+     "3838fd683a87a4cf04e15098ff66a213c187e545",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "document-referrer.https.html": [
+     "2bbc319c7b174216be67b9c2a1f375e1232dc27b",
+     [
+      null,
+      {}
+     ]
+    ],
+    "download.https.html": [
+     "ae9cebbe05b2720f6f20582f8d2923115210c59e",
+     [
+      null,
+      {}
+     ]
+    ],
     "embedder-coop-coep-blocked.https.html": [
      "e0e418577dc97fc424a4e55e2a809bad5ce63e48",
      [
@@ -492797,6 +493480,15 @@
       }
      ]
     ],
+    "fedcm-get-credential.https.html": [
+     "396da5946b0a8026a0a158c5c1a2b2b0c49572f6",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
     "fence-api.https.html": [
      "7d350ff75f0367e495ed222b60aa0f952a080dd7",
      [
@@ -492818,6 +493510,101 @@
       {}
      ]
     ],
+    "fragment-navigation.https.html": [
+     "1d548e35da94e4848d1b0c649daacc9e5711bea1",
+     [
+      null,
+      {}
+     ]
+    ],
+    "frame-navigation.https.html": [
+     "f3464c94e9e434172fbc96bff10eaefc1c0bc7bf",
+     [
+      null,
+      {}
+     ]
+    ],
+    "gamepad.https.html": [
+     "ef6b91e9211f58f53f22d0a7f13d30b9601eb953",
+     [
+      null,
+      {}
+     ]
+    ],
+    "get-mode-in-nested-frame.https.html": [
+     "d0888ce2e52732d47597c0865057c25c4b812f1d",
+     [
+      null,
+      {}
+     ]
+    ],
+    "get-nested-configs.https.html": [
+     "ed9f953e74a304f4b99e3a8e688866cb3a0365c3",
+     [
+      null,
+      {}
+     ]
+    ],
+    "header-referrer.https.html": [
+     "b6323962d898f8e29f7e5517133249759767d121",
+     [
+      null,
+      {}
+     ]
+    ],
+    "header-secFetchDest.https.html": [
+     "70b8c32749d93e1223309aac252ea06d52f27f7a",
+     [
+      null,
+      {}
+     ]
+    ],
+    "hid.https.html": [
+     "762ed6715a6a132d40fac5720f2e12e0b0cd6487",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "history-back-and-forward-should-not-work-in-fenced-tree.https.html": [
+     "910b2ba792169b0222742484eb5185b423f65357",
+     [
+      null,
+      {}
+     ]
+    ],
+    "history-length-fenced-navigations-replace-do-not-contribute-to-joint.https.html": [
+     "bd1d5f7309d1cf6c010b44ab4a3004c952255601",
+     [
+      null,
+      {}
+     ]
+    ],
+    "history-length-outer-page-navigation-not-reflected-in-fenced.https.html": [
+     "da643040316e93407d7b9edc333c6227ae6015ce",
+     [
+      null,
+      {}
+     ]
+    ],
+    "ignore-child-fenced-frame-onload-event.https.html": [
+     "a542c25909102e7b3ad8daf5837efb59f467f86e",
+     [
+      null,
+      {}
+     ]
+    ],
+    "input-on-coop-fenced-frame.https.html": [
+     "e7b44a0784d2708b313efb7075a1c50c8dcff46d",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "insecure-context.html": [
      "44db6432a45674a8f0842df1ce8042149635ea4f",
      [
@@ -492825,6 +493612,64 @@
       {}
      ]
     ],
+    "intersection-observer.https.html": [
+     "592e7c127f803b69d3ee2162164cfa06ab1b3766",
+     [
+      null,
+      {}
+     ]
+    ],
+    "invalid-url.https.html": [
+     "4e17185d8177729714b95b74af8ed2f86a3a1b92",
+     [
+      null,
+      {}
+     ]
+    ],
+    "key-scrolling.https.html": [
+     "7a23a72cb00b3863a8203298ca5b542103c311c2",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "key-value-store.https.html": [
+     "ba6b1c0a4f582a9de8ce91f6699c2c9cb7ac7245",
+     [
+      null,
+      {}
+     ]
+    ],
+    "load-ad-with-size.https.html": [
+     "c06205f056e7666e0dc8dfb11cdc611aa5e23c5f",
+     [
+      null,
+      {}
+     ]
+    ],
+    "loading.https.html": [
+     "2f39af0395c91b996e12f4621c157b27b19624f0",
+     [
+      null,
+      {}
+     ]
+    ],
+    "location-ancestorOrigins.https.html": [
+     "f72a668bdca49f63da17e8944f0c87119729879c",
+     [
+      null,
+      {}
+     ]
+    ],
+    "mediaDevices-setCaptureHandle.https.html": [
+     "fcc95a401fa3b1a5aa5db06e156650ddf07de45c",
+     [
+      null,
+      {}
+     ]
+    ],
     "navigate-ancestor-by-name.https.html": [
      "a5df1e99424e3d4561b977cc45c4df946102557d",
      [
@@ -492911,6 +493756,158 @@
       {}
      ]
     ],
+    "nested-opaque-ad-sizes.https.html": [
+     "2ac8ff003f9f37db50dd5b350cb31da68dd6af5d",
+     [
+      null,
+      {}
+     ]
+    ],
+    "notification.https.html": [
+     "636d218e10dd8a78dfd65c0e11301b243f0f9692",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "opaque-ad-sizes-exact-size.https.html": [
+     "b23d3ab0d7165d3b6aefccdfa7ba53971262717e",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
+    "opaque-ad-sizes-special-cases.https.html": [
+     "55cadaeec000be294d9cee791a9b03c2f27a674c",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
+    "payment-handler.https.html": [
+     "36e5e50726ea285438a7ce5f965bcc7ad474d820",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "payment-request.https.html": [
+     "0d1bbb01130b227c7b23e7e3b80e6001728cb424",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "permission-api-denied-non-standard.https.html": [
+     "ffc06781f6075ef95285af5f0d6bb91439eb9b95",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "permission-api-denied.https.html": [
+     "0d193e73cc5f708f615ef50dd64d50bdd46d42f7",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "permission-geolocation.https.html": [
+     "98b5a72b3c60ba1f988b43a98d3caf654f6a96ec",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "permission-notification.https.html": [
+     "79341252941c129cf1969a64d288e906f99dc837",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "picture-in-picture.https.html": [
+     "9665f88b9c045ffac8a6ca49280d3bceb5efea5a",
+     [
+      null,
+      {}
+     ]
+    ],
+    "popup-noopener.https.html": [
+     "9e7e8ce262eb20d5abe9f726429b613f1c5c9421",
+     [
+      null,
+      {}
+     ]
+    ],
+    "prerender.https.html": [
+     "45a39989d24e41704c6fdfe1906c4e349b6d75fc",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "presentation-receiver.https.html": [
+     "c33c72abf0ba3fbe569b5f948e868b733d569787",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "reinsert.https.html": [
+     "b88ff83d007b2cb7911dc5b7b8a3d58a5ffd861d",
+     [
+      null,
+      {}
+     ]
+    ],
+    "resize-lock-input.https.html": [
+     "261c9a737eff4b85723214b7f4735b8fe9423a65",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "resize-lock-zoom.https.html": [
+     "783f51d84eb6803bca38544e3ad6d665cbaa7461",
+     [
+      null,
+      {}
+     ]
+    ],
+    "resize-lock.https.html": [
+     "b7c39f6f3a0a083bf13c7e0324b7baaf6ec5e851",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
     "sandbox-attribute.https.html": [
      "1458145e4377e573f8aa13f5cb4d0dfdc7e09182",
      [
@@ -492985,6 +493982,15 @@
       {}
      ]
     ],
+    "script-focus.https.html": [
+     "4b5fe758b48d12d2a16bb47ff0d50d3fc4c21b47",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "selecturl-flexible-size.https.html": [
      "6b1a07e73a70744b493fea221fd12f94761242e6",
      [
@@ -493061,6 +494067,31 @@
       {}
      ]
     ],
+    "unique-cookie-partition.https.html": [
+     "8ecd56ffc3a9dda769ba62b6d0918d1cde2e5445",
+     [
+      null,
+      {}
+     ]
+    ],
+    "user-activation.https.html": [
+     "3ca0dca49bbdc684235b469b4b84d3c732a32428",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "visual-viewport.https.html": [
+     "7870f11e8c73282a6831f0e9e1ac3ce634f2b4ca",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "web-bluetooth.https.html": [
      "88bbd6ec3750cd2a7cecb7ddeee223d14b075982",
      [
@@ -551417,7 +552448,7 @@
        ]
       ],
       "popover-light-dismiss.html": [
-       "0ac73ec4549c6f91aa6e0c1f40508a2ba328dbdf",
+       "5800b7bc4d4426ae15c8790dc83a83b06575a6e6",
        [
         null,
         {
@@ -551427,7 +552458,7 @@
        ]
       ],
       "popover-move-documents.html": [
-       "2ead18a2b73956e8821cd61490c4f25861e33ed8",
+       "9feaa4b2bf8756aa1774cfa973327912d534ffac",
        [
         null,
         {}
@@ -569337,7 +570368,7 @@
      ]
     ],
     "idlharness.https.window.js": [
-     "e8e3cdab2180292ce0ca088a7f261ca51944a5d1",
+     "d8b7bc8d7a2a471ebaef2214706e0c26cba707bd",
      [
       "mediacapture-streams/idlharness.https.window.html",
       {
@@ -577374,15 +578405,15 @@
        {}
       ]
      ],
-     "trust-token-redemption-default-permissions-policy.tentative.https.sub.html": [
-      "20736879105b72053e48b16fbd5528743f9199a0",
+     "private-state-token-redemption-default-permissions-policy.tentative.https.sub.html": [
+      "4962b42721dfdefafcc1674c5e64d178be841a1a",
       [
        null,
        {}
       ]
      ],
-     "trust-token-redemption-supported-by-permissions-policy.tentative.html": [
-      "e349eadc5d1f79b4423052bee9b1903ae6c5e437",
+     "private-state-token-redemption-supported-by-permissions-policy.tentative.html": [
+      "0399f167fb045b967114db33c9461b0355c8a9ff",
       [
        null,
        {}
@@ -604945,7 +605976,7 @@
       ]
      ],
      "document-rules.https.html": [
-      "b0b07a878494da33145347e5995d76425fc775c7",
+      "eb8170923dc74e17c30f9b688cba524a229f4118",
       [
        "speculation-rules/prefetch/document-rules.https.html?include=and",
        {}
@@ -604981,6 +606012,30 @@
       [
        "speculation-rules/prefetch/document-rules.https.html?include=or",
        {}
+      ],
+      [
+       "speculation-rules/prefetch/document-rules.https.html?include=selectorMatches",
+       {}
+      ],
+      [
+       "speculation-rules/prefetch/document-rules.https.html?include=selectorMatchesDisplayLocked",
+       {}
+      ],
+      [
+       "speculation-rules/prefetch/document-rules.https.html?include=selectorMatchesDisplayNone",
+       {}
+      ],
+      [
+       "speculation-rules/prefetch/document-rules.https.html?include=selectorMatchesInShadowTree",
+       {}
+      ],
+      [
+       "speculation-rules/prefetch/document-rules.https.html?include=selectorMatchesScopingRoot",
+       {}
+      ],
+      [
+       "speculation-rules/prefetch/document-rules.https.html?include=unslottedLink",
+       {}
       ]
      ],
      "duplicate-urls.https.html": [
@@ -632964,6 +634019,20 @@
       {}
      ]
     ],
+    "postMessage_cross_domain_image_transfer_2d.sub.htm": [
+     "4faf979274b292c69dd1a212f9e10de87a22c509",
+     [
+      null,
+      {}
+     ]
+    ],
+    "postMessage_cross_domain_image_transfer_webgl.sub.htm": [
+     "0c5458953f87f73f471a14a18e5c24a733fd0575",
+     [
+      null,
+      {}
+     ]
+    ],
     "postMessage_crosssite.sub.htm": [
      "25bccd9df27a6688ae823bc15e9badcf7534825e",
      [
@@ -633939,6 +635008,57 @@
       }
      ]
     ],
+    "hard_sigmoid.https.any.js": [
+     "81bd5124ce90f09da63b292def464701101e9b15",
+     [
+      "webnn/hard_sigmoid.https.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "test WebNN API hardSigmoid operation"
+        ],
+        [
+         "global",
+         "window,dedicatedworker"
+        ],
+        [
+         "script",
+         "./resources/utils.js"
+        ],
+        [
+         "timeout",
+         "long"
+        ]
+       ],
+       "timeout": "long"
+      }
+     ],
+     [
+      "webnn/hard_sigmoid.https.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "test WebNN API hardSigmoid operation"
+        ],
+        [
+         "global",
+         "window,dedicatedworker"
+        ],
+        [
+         "script",
+         "./resources/utils.js"
+        ],
+        [
+         "timeout",
+         "long"
+        ]
+       ],
+       "timeout": "long"
+      }
+     ]
+    ],
     "hard_swish.https.any.js": [
      "052c7f2a208013ffca4d5c4ddb09404cd69d17d5",
      [
@@ -634100,6 +635220,57 @@
       }
      ]
     ],
+    "linear.https.any.js": [
+     "4b2c05540b7fec01a6142af2351204213d436259",
+     [
+      "webnn/linear.https.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "test WebNN API linear operation"
+        ],
+        [
+         "global",
+         "window,dedicatedworker"
+        ],
+        [
+         "script",
+         "./resources/utils.js"
+        ],
+        [
+         "timeout",
+         "long"
+        ]
+       ],
+       "timeout": "long"
+      }
+     ],
+     [
+      "webnn/linear.https.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "test WebNN API linear operation"
+        ],
+        [
+         "global",
+         "window,dedicatedworker"
+        ],
+        [
+         "script",
+         "./resources/utils.js"
+        ],
+        [
+         "timeout",
+         "long"
+        ]
+       ],
+       "timeout": "long"
+      }
+     ]
+    ],
     "matmul.https.any.js": [
      "8a9882afe613c68fb1fd948c2310f91eb9cb8009",
      [
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-local-time-null-2.https.html.ini b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-local-time-null-2.https.html.ini
index c5c79208..c8e4379 100644
--- a/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-local-time-null-2.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/animation-worklet/worklet-animation-local-time-null-2.https.html.ini
@@ -1,2 +1,3 @@
 [worklet-animation-local-time-null-2.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/base-uri/base-uri-allow-leading-zero-port.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/base-uri/base-uri-allow-leading-zero-port.sub.html
new file mode 100644
index 0000000..614d7dd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/base-uri/base-uri-allow-leading-zero-port.sub.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Security-Policy" content="base-uri {{location[scheme]}}://{{domains[www1]}}:0{{ports[http][0]}}/">
+    <script src='/resources/testharness.js'></script>
+    <script src='/resources/testharnessreport.js'></script>
+
+    <script>
+      var t = async_test("Check that base URIs can be set if they do not violate the page's policy because leading 0s are stripped from the port.");
+      window.addEventListener('securitypolicyviolation', t.step_func(function(t) {
+        assert_unreached('No CSP violation report should have been fired.');
+      }));
+    </script>
+
+    <base href="{{location[scheme]}}://{{domains[www1]}}:{{ports[http][0]}}/">
+    <script>
+    t.step(function() {
+      assert_equals(document.baseURI, "{{location[scheme]}}://{{domains[www1]}}:{{ports[http][0]}}/");
+      t.done();
+    });
+    </script>
+</head>
+<body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/base-uri/base-uri-deny-url-encoded-host.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/base-uri/base-uri-deny-url-encoded-host.sub.html
new file mode 100644
index 0000000..5e7fad9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/base-uri/base-uri-deny-url-encoded-host.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Security-Policy" content="base-uri {{location[scheme]}}://www1%2E{{domains[]}}:{{ports[http][0]}}/">
+    <script src='/resources/testharness.js'></script>
+    <script src='/resources/testharnessreport.js'></script>
+
+    <script>
+      var t = async_test("Check that baseURI fires a securitypolicyviolation event when it does not match the csp directive due to a url encoded host character.");
+      window.addEventListener('securitypolicyviolation', t.step_func_done(function(e) {
+        assert_equals(e.blockedURI, "{{location[scheme]}}://{{domains[www2]}}:{{ports[http][0]}}/")
+        assert_equals(e.violatedDirective, "base-uri");
+      }));
+    </script>
+
+    <base href="{{location[scheme]}}://{{domains[www2]}}:{{ports[http][0]}}/">
+    <script>
+    test(function() {
+      assert_equals(document.baseURI, window.location.href);
+      t.done();
+    }, "Check that the baseURI is not set when it does not match the csp directive");
+    </script>
+</head>
+<body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-scaled-video.html.ini b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-scaled-video.html.ini
index d83f4006..3ba1844a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-scaled-video.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-scaled-video.html.ini
@@ -1,3 +1,4 @@
 [clip-path-scaled-video.html]
   expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-svg-text-backdrop-filter.html.ini b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-svg-text-backdrop-filter.html.ini
new file mode 100644
index 0000000..f181a1c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-svg-text-backdrop-filter.html.ini
@@ -0,0 +1,3 @@
+[clip-path-svg-text-backdrop-filter.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/mask-svg-content/mask-with-rotation.svg.ini b/third_party/blink/web_tests/external/wpt/css/css-masking/mask-svg-content/mask-with-rotation.svg.ini
index d0c6d88..80078da1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/mask-svg-content/mask-with-rotation.svg.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/mask-svg-content/mask-with-rotation.svg.ini
@@ -1,5 +1,6 @@
 [mask-with-rotation.svg]
   expected:
-    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
-    if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-background-clip-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-background-clip-001.html.ini
new file mode 100644
index 0000000..35fd610
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-background-clip-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-input-reset-background-clip-001.html]
+  expected:
+    if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-clip-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-clip-001.html.ini
new file mode 100644
index 0000000..8d12dfe5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-clip-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-input-search-background-clip-001.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-block-end-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-block-end-width-001.html.ini
index 0d81901..8016a81 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-block-end-width-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-block-end-width-001.html.ini
@@ -1,3 +1,5 @@
 [kind-of-widget-fallback-input-submit-border-block-end-width-001.html]
   expected:
-    if (product == "content_shell") and (os == "mac"): FAIL
+    if (product == "content_shell") and (os == "win"): PASS
+    if product == "chrome": PASS
+    FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-right-style-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-right-style-001.html.ini
new file mode 100644
index 0000000..92aa3cd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-submit-border-right-style-001.html.ini
@@ -0,0 +1,3 @@
+[kind-of-widget-fallback-input-submit-border-right-style-001.html]
+  expected:
+    if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-brightness.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-brightness.html.ini
index a95d0fb..3fb8d11 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-brightness.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-brightness.html.ini
@@ -1,3 +1,4 @@
 [backdrop-filters-brightness.html]
   expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
     if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-grayscale-002.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-grayscale-002.html.ini
new file mode 100644
index 0000000..ae3f41c1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-grayscale-002.html.ini
@@ -0,0 +1,3 @@
+[backdrop-filters-grayscale-002.html]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-invert.html.ini b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-invert.html.ini
index 932dff64..5b3348f 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-invert.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filters-invert.html.ini
@@ -1,3 +1,4 @@
 [backdrop-filters-invert.html]
   expected:
     if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): FAIL
+    if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/modal-pseudo-class-in-has.html b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/modal-pseudo-class-in-has.html
index 1bff896..140f7cc4 100644
--- a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/modal-pseudo-class-in-has.html
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/modal-pseudo-class-in-has.html
@@ -3,6 +3,7 @@
 <title>CSS Selectors Invalidation: :modal pseudo class in :has()</title>
 <link rel="author" title="Tim Nguyen" href="https://github.com/nt1m">
 <link rel="help" href="https://drafts.csswg.org/selectors/#relational">
+<link rel="help" href="https://drafts.csswg.org/selectors/#modal-state">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/testdriver.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/event-click-visibilitychange.html.ini b/third_party/blink/web_tests/external/wpt/event-timing/event-click-visibilitychange.html.ini
index 89fce3af..0e015eb 100644
--- a/third_party/blink/web_tests/external/wpt/event-timing/event-click-visibilitychange.html.ini
+++ b/third_party/blink/web_tests/external/wpt/event-timing/event-click-visibilitychange.html.ini
@@ -1,4 +1,5 @@
 [event-click-visibilitychange.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Event handlers which change visibility should not measure next paint.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/windows/clear-window-name.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/windows/clear-window-name.https.html.ini
index e7d1663..5bcd71c 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/windows/clear-window-name.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/windows/clear-window-name.https.html.ini
@@ -1,4 +1,5 @@
 [clear-window-name.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Window.name is not reset if the document.domain is set to the parent domain]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html.ini b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html.ini
index 7965b2c..2b82b23 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html.ini
@@ -1,4 +1,5 @@
 [reporting-observer.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Access from cross-site iframe]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/decode/image-decode-iframe.html.ini b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/decode/image-decode-iframe.html.ini
index e93e004..ad8883e 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/decode/image-decode-iframe.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/decode/image-decode-iframe.html.ini
@@ -1,4 +1,5 @@
 [image-decode-iframe.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [HTMLImageElement.prototype.decode(), iframe tests. Decode from iframe, later removed, fails (img not loaded)]
     expected: [TIMEOUT, NOTRUN]
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-events.html.ini b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-events.html.ini
index ce15add96..055c09e 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-events.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-object-element/object-events.html.ini
@@ -1,4 +1,5 @@
 [object-events.html]
+  disabled: times out even with extended deadline
   expected:
     if (product == "content_shell") and (os == "win"): OK
     TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-dialog-initial-focus.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-dialog-initial-focus.html
new file mode 100644
index 0000000..47b2252b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-dialog-initial-focus.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="http://crbug.com/1430405">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<dialog id=dialog popover=auto>
+  <button id=button>button</button>
+</dialog>
+
+<dialog id=dialog2 popover=auto autofocus>
+  <button>button</button>
+</dialog>
+
+<script>
+test(() => {
+  dialog.showPopover();
+  assert_equals(document.activeElement, button);
+}, 'Opening dialogs as popovers should use dialog initial focus algorithm.');
+
+test(() => {
+  dialog2.showPopover();
+  assert_equals(document.activeElement, dialog2);
+}, 'Opening dialogs as popovers which have autofocus should focus the dialog.');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hint-crash.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hint-crash.tentative.html
new file mode 100644
index 0000000..82f8353
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hint-crash.tentative.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8" />
+<title>Popover=hint crash test</title>
+<link rel="author" href="mailto:masonf@chromium.org">
+<link rel=help href="https://open-ui.org/components/popover.research.explainer">
+<link rel=help href="https://html.spec.whatwg.org/multipage/popover.html">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/popover-utils.js"></script>
+
+<p>This test passes if it does not crash.</p>
+
+<div popover id=popover1>Popover 1
+  <div popover id=popover2 style="top:100px">Popover 2</div>
+</div>
+<div popover=manual id=popover3 style="top:200px">Popover 3</div>
+<div popover=hint id=popover4 anchor=popover3 style="inset:0;top:300px">Popover 4 - Click me</div>
+<script>
+popover1.showPopover();
+popover2.showPopover();
+popover3.showPopover();
+popover4.showPopover();
+clickOn(popover4)
+  .then(() => {
+    document.documentElement.classList.remove("reftest-wait");
+  });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss.html
index 0ac73ec..5800b7bc 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss.html
@@ -568,7 +568,10 @@
     if (e.newState === "closed")
       p20.showPopover();
   },{once:true});
-  p19.hidePopover();
+  // Because the `beforetoggle` handler shows a different popover,
+  // and that action closes the p19 popover, the call to hidePopover()
+  // will result in an exception.
+  assert_throws_dom('InvalidStateError',() => p19.hidePopover());
   assert_false(p19.matches(':popover-open'));
   assert_true(p20.matches(':popover-open'));
 },'Show an unrelated popover during "hide popover"');
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-move-documents.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-move-documents.html
index 2ead18a..9feaa4b 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-move-documents.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-move-documents.html
@@ -27,7 +27,10 @@
   assert_true(p2.matches(':popover-open'),
     'The popover should be open after calling showPopover()');
 
-  p2.hidePopover();
+  // Because the `beforetoggle` handler changes the document,
+  // and that action closes the popover, the call to hidePopover()
+  // will result in an exception.
+  assert_throws_dom('InvalidStateError',() => p2.hidePopover());
   assert_false(p2.matches(':popover-open'),
     'The popover should be closed after moving it between documents.');
 }, 'Moving popovers between documents while hiding should not throw an exception.');
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/cross-origin-iframe.sub.html.ini b/third_party/blink/web_tests/external/wpt/intersection-observer/cross-origin-iframe.sub.html.ini
index 89dc467..0543237 100644
--- a/third_party/blink/web_tests/external/wpt/intersection-observer/cross-origin-iframe.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/cross-origin-iframe.sub.html.ini
@@ -1,25 +1,27 @@
 [cross-origin-iframe.sub.html]
   [First rAF]
     expected:
+      if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): [FAIL, PASS]
       if (product == "content_shell") and (os == "linux"): PASS
       if product == "chrome": PASS
       FAIL
 
   [iframeDocument.scrollingElement.scrollTop = 250]
     expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-      if (product == "content_shell") and (os == "mac"): FAIL
+      if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): [FAIL, PASS]
+      if (product == "content_shell") and (os == "linux"): PASS
+      if product == "chrome": PASS
+      FAIL
 
   [topDocument.scrollingElement.scrollTop = 100]
     expected:
-      if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): PASS
+      if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): [FAIL, PASS]
       if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): PASS
-      if (product == "content_shell") and (os == "linux") and (flag_specific == ""): [FAIL, PASS]
       if product == "chrome": PASS
       FAIL
 
   [topDocument.scrollingElement.scrollTop = 200]
     expected:
-      if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): PASS
       if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS
+      if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): [FAIL, PASS]
       FAIL
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/tabindex-002.html.ini b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/tabindex-002.html.ini
index 5dcce86..b35f852 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/tabindex-002.html.ini
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/html5-tree/tabindex-002.html.ini
@@ -1,4 +1,5 @@
 [tabindex-002.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Elements with different tabindex must be focused sequentially when pressing 'Tab' keys]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames-after-reappend.html.ini b/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames-after-reappend.html.ini
index 924c37ee..743e81a7 100644
--- a/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames-after-reappend.html.ini
+++ b/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames-after-reappend.html.ini
@@ -1,4 +1,5 @@
 [mediasource-correct-frames-after-reappend.html]
+  disabled: times out even with extended deadline
   expected:
     if product == "chrome": ERROR
     TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames.html.ini b/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames.html.ini
index ddf4760..2d071fe67 100644
--- a/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames.html.ini
+++ b/third_party/blink/web_tests/external/wpt/media-source/mediasource-correct-frames.html.ini
@@ -1,4 +1,5 @@
 [mediasource-correct-frames.html]
+  disabled: times out even with extended deadline
   expected:
     if product == "chrome": ERROR
     TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-peerconnection-no-sink.https.html.ini b/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-peerconnection-no-sink.https.html.ini
index d7186be9..d1f792e6 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-peerconnection-no-sink.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-peerconnection-no-sink.https.html.ini
@@ -1,4 +1,5 @@
 [MediaRecorder-peerconnection-no-sink.https.html]
+  disabled: times out even with extended deadline
   expected:
     if product == "chrome": OK
     TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt
deleted file mode 100644
index 144a7fa..0000000
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-This is a testharness.js-based test.
-FAIL idl_test setup promise_test: Unhandled rejection with value: object "DevicePermissionDescriptor inherits PermissionDescriptor, but PermissionDescriptor is undefined."
-PASS idl_test validation
-PASS Partial interface Navigator: original interface defined
-PASS Partial interface Navigator: member names are unique
-PASS Partial interface MediaDevices: original interface defined
-PASS Partial interface MediaDevices: member names are unique
-PASS Partial interface Navigator[2]: original interface defined
-PASS Partial interface Navigator[2]: member names are unique
-PASS Partial interface Navigator[3]: member names are unique
-PASS Partial interface mixin NavigatorID: member names are unique
-PASS Navigator includes NavigatorID: member names are unique
-PASS Navigator includes NavigatorLanguage: member names are unique
-PASS Navigator includes NavigatorOnLine: member names are unique
-PASS Navigator includes NavigatorContentUtils: member names are unique
-PASS Navigator includes NavigatorCookies: member names are unique
-PASS Navigator includes NavigatorPlugins: member names are unique
-PASS Navigator includes NavigatorConcurrentHardware: member names are unique
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js
index e8e3cda..d8b7bc8d 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js
@@ -8,7 +8,7 @@
 
 idl_test(
   ['mediacapture-streams'],
-  ['webidl', 'dom', 'html'],
+  ['webidl', 'dom', 'html', 'permissions'],
   async idl_array => {
     const inputDevices = [];
     const outputDevices = [];
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id-resource-timing.tentative.html.ini b/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id-resource-timing.tentative.html.ini
index f2408ea2..303699b7 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id-resource-timing.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id-resource-timing.tentative.html.ini
@@ -1,4 +1,5 @@
 [navigation-id-resource-timing.tentative.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Resource Timing navigation id test]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-default-permissions-policy.tentative.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-default-permissions-policy.tentative.https.sub.html.ini
new file mode 100644
index 0000000..9f4614a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-default-permissions-policy.tentative.https.sub.html.ini
@@ -0,0 +1,9 @@
+[private-state-token-redemption-default-permissions-policy.tentative.https.sub.html]
+  [Default "private-state-token-redemption" permissions policy ["self"\] allows same-origin iframes.]
+    expected: FAIL
+
+  [Default "private-state-token-redemption" permissions policy ["self"\] allows the top-level document.]
+    expected: FAIL
+
+  [Default "private-state-token-redemption" permissions policy ["self"\] disallows cross-origin iframes.]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative.html.ini b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative.html.ini
new file mode 100644
index 0000000..5e44491
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/private-state-token-redemption-supported-by-permissions-policy.tentative.html.ini
@@ -0,0 +1,3 @@
+[private-state-token-redemption-supported-by-permissions-policy.tentative.html]
+  [document.featurePolicy.features should advertise private-state-token-redemption.]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-immediately-during-extendable-events.https.html.ini b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-immediately-during-extendable-events.https.html.ini
index 4507f10..099411d 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-immediately-during-extendable-events.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/unregister-immediately-during-extendable-events.https.html.ini
@@ -1,4 +1,8 @@
 [unregister-immediately-during-extendable-events.https.html]
-  expected: TIMEOUT
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac11"): [OK, TIMEOUT]
+    TIMEOUT
   [Clear-Site-Data must fail pending subresource fetch events.]
-    expected: TIMEOUT
+    expected:
+      if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
+      TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html
index b0b07a8..eb817092 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html
@@ -15,6 +15,12 @@
 <meta name="variant" content="?include=linkInShadowTree">
 <meta name="variant" content="?include=linkHrefChanged">
 <meta name="variant" content="?include=newRuleSetAdded">
+<meta name="variant" content="?include=selectorMatches">
+<meta name="variant" content="?include=selectorMatchesScopingRoot">
+<meta name="variant" content="?include=selectorMatchesInShadowTree">
+<meta name="variant" content="?include=selectorMatchesDisplayNone">
+<meta name="variant" content="?include=selectorMatchesDisplayLocked">
+<meta name="variant" content="?include=unslottedLink">
 
 <body>
 <script>
@@ -166,5 +172,127 @@
     assert_equals(await isUrlPrefetched(url), 1);
   }, 'test that adding a second rule set triggers prefetch');
 
+  subsetTestByKey('selectorMatches', promise_test, async t => {
+    assert_implements(HTMLScriptElement.supports('speculationrules'),
+      'Speculation Rules not supported');
+
+    insertDocumentRule({ selector_matches: 'a.important-link' });
+
+    const url_1 = getPrefetchUrl({foo: 'bar'});
+    const importantLink = addLink(url_1);
+    importantLink.className = 'important-link';
+    const url_2 = getPrefetchUrl({foo: 'buzz'});
+    addLink(url_2)
+    await new Promise(resolve => t.step_timeout(resolve, 2000));
+
+    assert_equals(await isUrlPrefetched(url_1), 1);
+    assert_equals(await isUrlPrefetched(url_2), 0);
+  }, 'test selector_matches document rule');
+
+  subsetTestByKey('selectorMatchesScopingRoot', promise_test, async t => {
+    assert_implements(HTMLScriptElement.supports('speculationrules'),
+      'Speculation Rules not supported');
+
+    insertDocumentRule({ selector_matches: ':root > body > a' });
+
+    const url_1 = getPrefetchUrl({ foo: 'bar' });
+    addLink(url_1);
+
+    const url_2 = getPrefetchUrl({ foo: 'buzz' });
+    const extraContainer = document.createElement('div');
+    document.body.appendChild(extraContainer);
+    addLink(url_2, extraContainer);
+
+    await new Promise(resolve => t.step_timeout(resolve, 2000));
+
+    assert_equals(await isUrlPrefetched(url_1), 1);
+    assert_equals(await isUrlPrefetched(url_2), 0);
+  }, 'test selector_matches with :root');
+
+  // 'selector_matches' should never match with a link inside a shadow tree
+  // because the scoping root used when matching is always the document.
+  subsetTestByKey('selectorMatchesInShadowTree', promise_test, async t => {
+    assert_implements(HTMLScriptElement.supports('speculationrules'),
+      'Speculation Rules not supported');
+
+    insertDocumentRule({ selector_matches: 'a.important-link' });
+
+    // Create shadow root.
+    const shadowHost = document.createElement('div');
+    document.body.appendChild(shadowHost);
+    const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
+
+    const url = getPrefetchUrl();
+    const link = addLink(url, shadowRoot);
+    link.className = 'important-link';
+    await new Promise(resolve => t.step_timeout(resolve, 2000));
+
+    assert_equals(await isUrlPrefetched(url), 0);
+  }, 'test selector_matches with link inside shadow tree');
+
+  subsetTestByKey('selectorMatchesDisplayNone', promise_test, async t => {
+    assert_implements(HTMLScriptElement.supports('speculationrules'),
+      'Speculation Rules not supported');
+
+    const style = document.createElement('style');
+    style.innerText = ".important-section { display: none; }";
+    document.head.appendChild(style);
+    insertDocumentRule();
+
+    const importantSection = document.createElement('div');
+    importantSection.className = 'important-section';
+    document.body.appendChild(importantSection);
+    const url = getPrefetchUrl();
+    addLink(url, importantSection);
+
+    await new Promise(resolve => t.step_timeout(resolve, 2000));
+    assert_equals(await isUrlPrefetched(url), 0);
+
+    style.remove();
+    await new Promise(resolve => t.step_timeout(resolve, 2000));
+    assert_equals(await isUrlPrefetched(url), 1);
+  }, 'test selector_matches with link inside display:none container');
+
+  subsetTestByKey('selectorMatchesDisplayLocked', promise_test, async t => {
+    assert_implements(HTMLScriptElement.supports('speculationrules'),
+      'Speculation Rules not supported');
+
+    const style = document.createElement('style');
+    style.innerText = ".important-section { content-visibility: hidden; }";
+    document.head.appendChild(style);
+    insertDocumentRule({ selector_matches: '.important-section a' });
+
+    const importantSection = document.createElement('div');
+    importantSection.className = 'important-section';
+    document.body.appendChild(importantSection);
+    const url = getPrefetchUrl();
+    addLink(url, importantSection);
+
+    await new Promise(resolve => t.step_timeout(resolve, 2000));
+    assert_equals(await isUrlPrefetched(url), 0);
+
+    style.remove();
+    await new Promise(resolve => t.step_timeout(resolve, 2000));
+    assert_equals(await isUrlPrefetched(url), 1);
+  }, 'test selector_matches with link inside display locked container');
+
+  subsetTestByKey('unslottedLink', promise_test, async t => {
+    assert_implements(HTMLScriptElement.supports('speculationrules'),
+      'Speculation Rules not supported');
+
+    insertDocumentRule();
+
+    // Create shadow root.
+    const shadowHost = document.createElement('div');
+    document.body.appendChild(shadowHost);
+    const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
+
+    // Add unslotted link.
+    const url = getPrefetchUrl();
+    addLink(url, shadowHost);
+
+    await new Promise(resolve => t.step_timeout(resolve, 2000));
+    assert_equals(await isUrlPrefetched(url), 0);
+  }, 'test that unslotted link never matches document rule');
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/about-blank-iframes.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/about-blank-iframes.html.ini
index eee27e12..15f2a68 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/about-blank-iframes.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/about-blank-iframes.html.ini
@@ -1,4 +1,5 @@
 [about-blank-iframes.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [about:blank iframes]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/accept-clint-hint-cache.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/accept-clint-hint-cache.https.html.ini
index e35a01f..a8964801 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/accept-clint-hint-cache.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/accept-clint-hint-cache.https.html.ini
@@ -1,4 +1,5 @@
 [accept-clint-hint-cache.https.html]
+  disabled: times out even with extended deadline
   expected:
     if product == "chrome": TIMEOUT
   [Prerender page should maintain their own client hints cache and do not propagate it tothe global cache until activation]
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/activation-start.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/activation-start.html.ini
index ca5a9c7..e116e0db 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/activation-start.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/activation-start.html.ini
@@ -1,4 +1,5 @@
 [activation-start.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [PerformanceNavigationTiming's activationStart in prerendered page]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cache-storage.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cache-storage.https.html.ini
index a0b6f699..70bdc22 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cache-storage.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cache-storage.https.html.ini
@@ -1,4 +1,5 @@
 [cache-storage.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering page should be able to access cache storage]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/clients-matchall.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/clients-matchall.https.html.ini
index 6837e4c..d158edd 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/clients-matchall.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/clients-matchall.https.html.ini
@@ -1,4 +1,5 @@
 [clients-matchall.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [The client urls (including a prerender page) are exposed by Clients#matchAll()]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cookies.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cookies.https.html.ini
index 251b347..cfca822 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cookies.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cookies.https.html.ini
@@ -1,4 +1,5 @@
 [cookies.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering page should be able to access cookies]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/credentialed-prerender-opt-in.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/credentialed-prerender-opt-in.html.ini
index 9beef48..8801d5b 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/credentialed-prerender-opt-in.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/credentialed-prerender-opt-in.html.ini
@@ -1,4 +1,5 @@
 [credentialed-prerender-opt-in.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [same-site cross-origin prerendering opt in]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cross-origin-iframe.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cross-origin-iframe.html.ini
index 6baae60..a16b689 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cross-origin-iframe.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cross-origin-iframe.html.ini
@@ -1,4 +1,5 @@
 [cross-origin-iframe.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [cross-origin iframes should not load until activation]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cross-origin-isolated.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cross-origin-isolated.https.html.ini
index a2c4df4..f9732f4 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cross-origin-isolated.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/cross-origin-isolated.https.html.ini
@@ -1,4 +1,5 @@
 [cross-origin-isolated.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Allow crossOriginIsolated in prerendered page]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-strict-dynamic.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-strict-dynamic.html.ini
index 6563cff9..5cb3798 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-strict-dynamic.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-strict-dynamic.html.ini
@@ -1,4 +1,5 @@
 [csp-script-src-strict-dynamic.html]
+  disabled: times out even with extended deadline
   expected:
     if product == "chrome": TIMEOUT
   [Test if CSP script-src strict-dynamic allows inline speculationrules injected from the permitted scripts.]
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-unsafe-inline.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-unsafe-inline.html.ini
index 191ed7f7..3021c887 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-unsafe-inline.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-unsafe-inline.html.ini
@@ -1,4 +1,5 @@
 [csp-script-src-unsafe-inline.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Test if CSP script-src unsafe-inline permits inline speculationrules.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/fetch-blob.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/fetch-blob.html.ini
index 7d9696ef..d37fa6a4 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/fetch-blob.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/fetch-blob.html.ini
@@ -1,4 +1,5 @@
 [fetch-blob.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering page should be able to access blobs]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/fetch-intercepted-by-service-worker.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/fetch-intercepted-by-service-worker.https.html.ini
index e2ca52f2..65a50ba 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/fetch-intercepted-by-service-worker.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/fetch-intercepted-by-service-worker.https.html.ini
@@ -1,4 +1,5 @@
 [fetch-intercepted-by-service-worker.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [fetch() in a prerendering page should go through a service worker]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/iframe-added-post-activation.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/iframe-added-post-activation.html.ini
index 7d679b0e..43c2772 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/iframe-added-post-activation.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/iframe-added-post-activation.html.ini
@@ -1,4 +1,5 @@
 [iframe-added-post-activation.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [iframe added after activation has false document.prerendering]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/indexeddb.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/indexeddb.html.ini
index 8f43c36..2a080fb 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/indexeddb.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/indexeddb.html.ini
@@ -1,4 +1,5 @@
 [indexeddb.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering page should be able to access Indexed DataBase]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/local-storage.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/local-storage.html.ini
index 2b567607..20709c8 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/local-storage.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/local-storage.html.ini
@@ -1,4 +1,5 @@
 [local-storage.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering page should be able to access local storage]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/main-frame-navigation.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/main-frame-navigation.https.html.ini
index 742da71..155ce16 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/main-frame-navigation.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/main-frame-navigation.https.html.ini
@@ -1,4 +1,5 @@
 [main-frame-navigation.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Test document.prerendering and prerenderingchange event in the navigated page]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/media-autoplay.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/media-autoplay.html.ini
index aeb045e..4375eb5 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/media-autoplay.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/media-autoplay.html.ini
@@ -1,4 +1,5 @@
 [media-autoplay.html]
+  disabled: times out even with extended deadline
   expected:
     if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): [OK, TIMEOUT]
     if product == "chrome": TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigation-intercepted-by-service-worker.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigation-intercepted-by-service-worker.https.html.ini
index 4efbbff..d3cae06 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigation-intercepted-by-service-worker.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigation-intercepted-by-service-worker.https.html.ini
@@ -1,4 +1,5 @@
 [navigation-intercepted-by-service-worker.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [navigation should be intercepted by a service worker]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigator-plugins.tentative.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigator-plugins.tentative.html.ini
index be80e74..31b9a7f 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigator-plugins.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigator-plugins.tentative.html.ini
@@ -1,4 +1,5 @@
 [navigator-plugins.tentative.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering page should be able to access the navigator.plugins]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigator-subapp.https.tentative.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigator-subapp.https.tentative.html.ini
index b59f852..a220b7b7 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigator-subapp.https.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/navigator-subapp.https.tentative.html.ini
@@ -1,4 +1,5 @@
 [navigator-subapp.https.tentative.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering pages should not be able to access subapp API.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-mismatch.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-mismatch.html.ini
index 7dce122..7b9c5b65 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-mismatch.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-mismatch.html.ini
@@ -1,4 +1,5 @@
 [referrer-policy-mismatch.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendered with "strict-origin", activated with "unsafe-url"]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-no-referrer.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-no-referrer.html.ini
index 4ce7c07..cdb0a5c 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-no-referrer.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-no-referrer.html.ini
@@ -1,4 +1,5 @@
 [referrer-policy-no-referrer.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [no referrer]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-origin.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-origin.html.ini
index 8451be50..67b54944 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-origin.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-origin.html.ini
@@ -1,4 +1,5 @@
 [referrer-policy-origin.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [origin referrer]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-strict-origin.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-strict-origin.html.ini
index 4b21fd4e..73b1bfb24 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-strict-origin.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-strict-origin.html.ini
@@ -1,4 +1,5 @@
 [referrer-policy-strict-origin.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [strict-origin referrer]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer.html.ini
index a32534cf..00518007 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer.html.ini
@@ -1,4 +1,5 @@
 [referrer.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [default referrer]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/register-service-worker.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/register-service-worker.https.html.ini
index db713f6..b3ba968 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/register-service-worker.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/register-service-worker.https.html.ini
@@ -1,4 +1,5 @@
 [register-service-worker.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [New service worker should be registered in a prerendered page]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-audio-setSinkId-with-invalid-sinkId.https.tentative.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-audio-setSinkId-with-invalid-sinkId.https.tentative.html.ini
index 5dd3449..f3c5e33 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-audio-setSinkId-with-invalid-sinkId.https.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-audio-setSinkId-with-invalid-sinkId.https.tentative.html.ini
@@ -1,4 +1,5 @@
 [restriction-audio-setSinkId-with-invalid-sinkId.https.tentative.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the setSinkId of Audio API with the invalid sinkId should be\n    deferred until the prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-audio-setSinkId.https.tentative.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-audio-setSinkId.https.tentative.html.ini
index 0ff6e76..2635df5 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-audio-setSinkId.https.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-audio-setSinkId.https.tentative.html.ini
@@ -1,4 +1,5 @@
 [restriction-audio-setSinkId.https.tentative.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the setSinkId of Audio API should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-background-fetch.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-background-fetch.https.html.ini
index 1ac295b..66fd117 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-background-fetch.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-background-fetch.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-background-fetch.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [The access to the Background Fetch API should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-background-sync.tentative.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-background-sync.tentative.https.html.ini
index 893f72f..fb0a21f 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-background-sync.tentative.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-background-sync.tentative.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-background-sync.tentative.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [The access to the Background Sync API should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-battery-status.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-battery-status.https.html.ini
index 90dee5cc..4cdf4ac 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-battery-status.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-battery-status.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-battery-status.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Battery Status API should be deferred until the\n   prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-bluetooth.tentative.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-bluetooth.tentative.https.html.ini
index 1018a2fc..78e6d0e 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-bluetooth.tentative.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-bluetooth.tentative.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-bluetooth.tentative.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Bluetooth API should be deferred until the\n   prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-broadcast-channel.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-broadcast-channel.html.ini
index d174790..6064b01 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-broadcast-channel.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-broadcast-channel.html.ini
@@ -1,4 +1,5 @@
 [restriction-broadcast-channel.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [BroadcastChannel#postMessage should be deferred until the prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-dedicated-worker.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-dedicated-worker.https.html.ini
index a8944b7..748cf85 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-dedicated-worker.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-dedicated-worker.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-dedicated-worker.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [The access to the Dedicated Worker API should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-encrypted-media-unsupported-config.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-encrypted-media-unsupported-config.https.html.ini
index 9d332b1..e6e00f8 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-encrypted-media-unsupported-config.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-encrypted-media-unsupported-config.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-encrypted-media-unsupported-config.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Encrypted Media API should be deferred with the\n    unsupported configurations until the prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-encrypted-media.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-encrypted-media.https.html.ini
index e87ab01..4637060 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-encrypted-media.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-encrypted-media.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-encrypted-media.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Encrypted Media API should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-focus.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-focus.html.ini
index c68dd60..9538fafb 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-focus.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-focus.html.ini
@@ -1,4 +1,5 @@
 [restriction-focus.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Prerendering document should update the active element but not have focus]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-idle-detection.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-idle-detection.https.html.ini
index 53b06827..da69b36 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-idle-detection.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-idle-detection.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-idle-detection.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering pages should not be able to invoke the Idle Detection API]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-local-file-system-access.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-local-file-system-access.https.html.ini
index 1ba40e69..45bbe749 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-local-file-system-access.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-local-file-system-access.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-local-file-system-access.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering pages should not be able to access the local file system via the File System Access API]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-auto-play-attribute.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-auto-play-attribute.html.ini
index 66742d3..924ea8a 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-auto-play-attribute.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-auto-play-attribute.html.ini
@@ -1,4 +1,5 @@
 [restriction-media-auto-play-attribute.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [autoplay of the audio media should be deferred until the prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-camera.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-camera.https.html.ini
index 6c294d0..738d253 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-camera.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-camera.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-media-camera.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the camera of the user media should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-device-info.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-device-info.https.html.ini
index a23bb17..61d296a 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-device-info.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-device-info.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-media-device-info.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Media Device Info should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-microphone.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-microphone.https.html.ini
index 6e30e4d..e85411a4 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-microphone.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-microphone.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-media-microphone.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Microphone of the user media should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-play.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-play.html.ini
index 813502fd..9f5436f1 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-play.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-media-play.html.ini
@@ -1,4 +1,5 @@
 [restriction-media-play.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [play of the audio media should be deferred until the prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-message-boxes.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-message-boxes.html.ini
index 5ca869c..ab99615 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-message-boxes.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-message-boxes.html.ini
@@ -1,4 +1,5 @@
 [restriction-message-boxes.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [alert() does not display the modal and returns immediately]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-midi-sysex.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-midi-sysex.https.html.ini
index f97d8b4..556ea50b 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-midi-sysex.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-midi-sysex.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-midi-sysex.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Midi API should be deferred until the prerendered page is\n  activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-midi.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-midi.https.html.ini
index 1ba11ff..12865807 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-midi.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-midi.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-midi.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Midi API should be deferred until the prerendered page is\n  activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-notification.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-notification.https.html.ini
index 00e1715..3805cbf6 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-notification.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-notification.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-notification.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Displaying Notification should be deferred until the prerendered page is\n activated]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-presentation-request.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-presentation-request.https.html.ini
index 014edcae..58f8e8f 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-presentation-request.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-presentation-request.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-presentation-request.https.html]
+  disabled: times out even with extended deadline
   expected:
     if product == "chrome": TIMEOUT
     ERROR
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-prompt-by-before-unload.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-prompt-by-before-unload.html.ini
index 8943a52d..0400a72 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-prompt-by-before-unload.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-prompt-by-before-unload.html.ini
@@ -1,4 +1,5 @@
 [restriction-prompt-by-before-unload.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Prerendering cannot invoke the prompt by the beforeunload event.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-push.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-push.https.html.ini
index 4779329..bdcef47 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-push.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-push.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-push.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [The access to the Push API should be deferred until the prerendered page is\n    activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-request-picture-in-picture.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-request-picture-in-picture.html.ini
index b276b79..74a349b 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-request-picture-in-picture.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-request-picture-in-picture.html.ini
@@ -1,4 +1,5 @@
 [restriction-request-picture-in-picture.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering page cannot invokeHTMLVideoElement.requestPictureInPicture]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-screen-capture.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-screen-capture.https.html.ini
index b24d1f2d..f6720a3 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-screen-capture.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-screen-capture.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-screen-capture.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering pages should not be able to invoke the Screen Capture API]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-screen-orientation-lock.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-screen-orientation-lock.https.html.ini
index 3b750165..9680a56 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-screen-orientation-lock.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-screen-orientation-lock.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-screen-orientation-lock.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [The access to the Screen Orienation Lock API should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-accelerometer.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-accelerometer.https.html.ini
index 7923b1f..d389e770 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-accelerometer.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-accelerometer.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-sensor-accelerometer.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Accelerometer API should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-ambient-light-sensor.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-ambient-light-sensor.https.html.ini
index 7604105..64ee876 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-ambient-light-sensor.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-ambient-light-sensor.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-sensor-ambient-light-sensor.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Ambient Light Sensor API should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-gyroscope.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-gyroscope.https.html.ini
index a418c2f7..75954a1 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-gyroscope.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-gyroscope.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-sensor-gyroscope.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Gyroscope API should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-magnetometer.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-magnetometer.https.html.ini
index 2fb9a9f5..fc3e540 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-magnetometer.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-sensor-magnetometer.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-sensor-magnetometer.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Magnetometer API should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-postmessage.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-postmessage.https.html.ini
index 95868e16..edf451f1 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-postmessage.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-postmessage.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-service-worker-postmessage.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [ServiceWorker#postMessage() from a prerendered page should be deferred until page activation.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-unregister.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-unregister.https.html.ini
index 39994bd..e337ae3e 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-unregister.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-unregister.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-service-worker-unregister.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [ServiceWorkerRegistration.unregister() should be deferred in a prerendered page]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-update.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-update.https.html.ini
index 9b17e751..d9490c7 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-update.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-service-worker-update.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-service-worker-update.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [ServiceWorkerRegistration.update() should be deferred in a prerendered page]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-speech-synthesis.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-speech-synthesis.html.ini
index f4624323..279143c 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-speech-synthesis.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-speech-synthesis.html.ini
@@ -1,4 +1,5 @@
 [restriction-speech-synthesis.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [speechSynthesis.cancel() should be deferred until the prerendered page is activated]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-storage-persist.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-storage-persist.https.html.ini
index b182a0a..f77b4fd 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-storage-persist.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-storage-persist.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-storage-persist.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the storage.persist() should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-wake-lock.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-wake-lock.https.html.ini
index 8968bd9..716464b1 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-wake-lock.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-wake-lock.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-wake-lock.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Wake Lock API should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-hid.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-hid.https.html.ini
index b65a55c..fc0e2947 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-hid.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-hid.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-web-hid.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Web HID API should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-locks.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-locks.https.html.ini
index 6cd3184..fd276599 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-locks.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-locks.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-web-locks.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [navigator.locks.query should be deferred until the prerendered page is activated]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-nfc.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-nfc.https.html.ini
index 8b504495..dffcae98 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-nfc.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-nfc.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-web-nfc.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [The access to the Web NFC API should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-serial.tentative.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-serial.tentative.https.html.ini
index cb21c440..2b197327 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-serial.tentative.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-serial.tentative.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-web-serial.tentative.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Web Serial API should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-share.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-share.https.html.ini
index a9c0545..9d5cb42 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-share.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-share.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-web-share.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering pages should not be able to invoke the Web Share API]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-usb.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-usb.https.html.ini
index 1481c560..5b7d5df 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-usb.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-usb.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-web-usb.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [the access to the Web USB API should be deferred until the prerendered\n    page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-xr-immersive-vr-session.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-xr-immersive-vr-session.https.html.ini
index 6c113b2..76115e1 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-xr-immersive-vr-session.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-xr-immersive-vr-session.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-web-xr-immersive-vr-session.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [The access to the WebXR immersive-vr session API should be deferred until\n    the prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-xr-inline-session.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-xr-inline-session.https.html.ini
index 20922ee..522e3fe 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-xr-inline-session.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-web-xr-inline-session.https.html.ini
@@ -1,4 +1,5 @@
 [restriction-web-xr-inline-session.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [The access to the WebXR inline session API should be deferred until the\n    prerendered page is activated]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-move.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-move.html.ini
index 6b2a50d..f70c295 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-move.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-move.html.ini
@@ -1,4 +1,5 @@
 [restriction-window-move.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [a prerendering page cannot move its window by executing moveBy.]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-open.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-open.html.ini
index 245368d..8657f83 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-open.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-open.html.ini
@@ -1,4 +1,5 @@
 [restriction-window-open.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [window.open() should fail during prerendering]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-resize.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-resize.html.ini
index 5e2909e..4275a6e3 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-resize.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restriction-window-resize.html.ini
@@ -1,4 +1,5 @@
 [restriction-window-resize.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [a prerendering page cannot resize its window by executing resizeBy.]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/sandbox-iframe.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/sandbox-iframe.html.ini
index ed62e078..37f386bf 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/sandbox-iframe.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/sandbox-iframe.html.ini
@@ -1,4 +1,5 @@
 [sandbox-iframe.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [same-origin sandbox iframes should not load until activation]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-activation.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-activation.https.html.ini
index 08c8568..d839cd0 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-activation.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-activation.https.html.ini
@@ -1,4 +1,5 @@
 [session-history-activation.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [history.length should be updated after activation]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-location.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-location.https.html.ini
index 44e4e48..3a6c36c 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-location.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-location.https.html.ini
@@ -1,4 +1,5 @@
 [session-history-location.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Setting location.href navigates independently with replacement in a prerender]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-navigation.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-navigation.https.html.ini
index 8194d4eb..dc642f5c 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-navigation.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-navigation.https.html.ini
@@ -1,4 +1,5 @@
 [session-history-navigation.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Synthetic anchor click navigates independently with replacement in a prerender]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-pushstate.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-pushstate.https.html.ini
index 2e4711c..15c9b50 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-pushstate.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-pushstate.https.html.ini
@@ -1,4 +1,5 @@
 [session-history-pushstate.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [history.pushState navigates independently with replacement in a prerender]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-subframe-navigation.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-subframe-navigation.https.html.ini
index 4141fe1..727a7fc8 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-subframe-navigation.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-subframe-navigation.https.html.ini
@@ -1,4 +1,5 @@
 [session-history-subframe-navigation.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Subframe navigation in prerender replaces the session entry]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-subframe-reload.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-subframe-reload.https.html.ini
index ab5c561b..3192ed0 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-subframe-reload.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/session-history-subframe-reload.https.html.ini
@@ -1,4 +1,5 @@
 [session-history-subframe-reload.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Subframe reload works in prerendered page]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/state-and-event.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/state-and-event.html.ini
index 2f57089..93c7a36 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/state-and-event.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/state-and-event.html.ini
@@ -1,4 +1,5 @@
 [state-and-event.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [Test document.prerendering and its change event.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/visibility-state.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/visibility-state.html.ini
index bffcc56ac..8960e0b 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/visibility-state.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/visibility-state.html.ini
@@ -1,4 +1,5 @@
 [visibility-state.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [visibilityState must be updated after prerendering]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/web-database.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/web-database.https.html.ini
index 9558e97..ab8ae61 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/web-database.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/web-database.https.html.ini
@@ -1,4 +1,5 @@
 [web-database.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [prerendering page should be able to access Web Database]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate-to-cross-origin-url-on-iframe.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate-to-cross-origin-url-on-iframe.https.html.ini
index 92b0e5e..3324bfb8 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate-to-cross-origin-url-on-iframe.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate-to-cross-origin-url-on-iframe.https.html.ini
@@ -1,4 +1,5 @@
 [windowclient-navigate-to-cross-origin-url-on-iframe.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [WindowClient.navigate() to a cross-origin URL on a prerendered iframe should be deferred]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate-to-same-origin-url-on-iframe.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate-to-same-origin-url-on-iframe.https.html.ini
index 4235b8b..d5abf25 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate-to-same-origin-url-on-iframe.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate-to-same-origin-url-on-iframe.https.html.ini
@@ -1,4 +1,5 @@
 [windowclient-navigate-to-same-origin-url-on-iframe.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [WindowClient.navigate() to a same-origin URL on a prerendered iframe should succeed]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate.https.html.ini
index c934bee6..3c1da9e 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/windowclient-navigate.https.html.ini
@@ -1,4 +1,5 @@
 [windowclient-navigate.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [WindowClient.navigate() for a prerendered main page should throw aTypeError]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/workers-in-cross-origin-iframe.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/workers-in-cross-origin-iframe.html.ini
index bc3a810d..cde9c659 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/workers-in-cross-origin-iframe.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/workers-in-cross-origin-iframe.html.ini
@@ -1,4 +1,5 @@
 [workers-in-cross-origin-iframe.html]
+  disabled: times out even with extended deadline
   expected:
     if product == "chrome": TIMEOUT
   [Dedicated workers in cross-origin iframe should be loaded after activation]
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/workers.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/workers.html.ini
index 794e82a..01d27284 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/workers.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/workers.html.ini
@@ -1,4 +1,5 @@
 [workers.html]
+  disabled: times out even with extended deadline
   expected:
     if (product == "content_shell") and (os == "win") and (port == "win11"): [TIMEOUT, OK]
     if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): [OK, TIMEOUT]
diff --git a/third_party/blink/web_tests/external/wpt/url/failure.html.ini b/third_party/blink/web_tests/external/wpt/url/failure.html.ini
index aec09b9..74bd7a8 100644
--- a/third_party/blink/web_tests/external/wpt/url/failure.html.ini
+++ b/third_party/blink/web_tests/external/wpt/url/failure.html.ini
@@ -1,4 +1,5 @@
 [failure.html]
+  disabled: times out even with extended deadline
   expected:
     if product == "chrome": TIMEOUT
   [Location's href:  should throw]
diff --git a/third_party/blink/web_tests/external/wpt/webmessaging/postMessage_cross_domain_image_transfer_webgl.sub.htm.ini b/third_party/blink/web_tests/external/wpt/webmessaging/postMessage_cross_domain_image_transfer_webgl.sub.htm.ini
new file mode 100644
index 0000000..7676117
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webmessaging/postMessage_cross_domain_image_transfer_webgl.sub.htm.ini
@@ -0,0 +1,4 @@
+[postMessage_cross_domain_image_transfer_webgl.sub.htm]
+  expected:
+    if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): ERROR
+    if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): ERROR
diff --git a/third_party/blink/web_tests/external/wpt/webnn/hard_sigmoid.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/hard_sigmoid.https.any.js
new file mode 100644
index 0000000..81bd512
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webnn/hard_sigmoid.https.any.js
@@ -0,0 +1,10 @@
+// META: title=test WebNN API hardSigmoid operation
+// META: global=window,dedicatedworker
+// META: script=./resources/utils.js
+// META: timeout=long
+
+'use strict';
+
+// https://webmachinelearning.github.io/webnn/#api-mlgraphbuilder-hard-sigmoid
+
+testWebNNOperation('hardSigmoid', buildOperationWithSingleInput);
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webnn/hard_sigmoid.https.any.js.ini b/third_party/blink/web_tests/external/wpt/webnn/hard_sigmoid.https.any.js.ini
new file mode 100644
index 0000000..72fe9565
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webnn/hard_sigmoid.https.any.js.ini
@@ -0,0 +1,119 @@
+[hard_sigmoid.https.any.html]
+  [hardSigmoid float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / async]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor specified all options (negative options.alpha and positive options.beta) / async]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor specified negative options.alpha default options.beta / async]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor specified negative options.beta default options.alpha / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 1D tensor default options / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 2D tensor default options / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 3D tensor default options / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor default options / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified all options (negative options.alpha and negative options.beta) / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified all options (positive options.alpha and positive options.beta) / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified positive options.alpha default options.beta / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified positive options.beta default options.alpha / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 5D tensor default options / async]
+    expected: FAIL
+
+
+[hard_sigmoid.https.any.worker.html]
+  [hardSigmoid float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / async]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor specified all options (negative options.alpha and positive options.beta) / async]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor specified all options (negative options.alpha and positive options.beta) / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor specified negative options.alpha default options.beta / async]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor specified negative options.alpha default options.beta / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor specified negative options.beta default options.alpha / async]
+    expected: FAIL
+
+  [hardSigmoid float32 negative 4D tensor specified negative options.beta default options.alpha / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 1D tensor default options / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 1D tensor default options / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 2D tensor default options / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 2D tensor default options / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 3D tensor default options / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 3D tensor default options / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor default options / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor default options / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified all options (negative options.alpha and negative options.beta) / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified all options (negative options.alpha and negative options.beta) / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified all options (positive options.alpha and positive options.beta) / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified all options (positive options.alpha and positive options.beta) / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified positive options.alpha default options.beta / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified positive options.alpha default options.beta / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified positive options.beta default options.alpha / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 4D tensor specified positive options.beta default options.alpha / sync]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 5D tensor default options / async]
+    expected: FAIL
+
+  [hardSigmoid float32 positive 5D tensor default options / sync]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/webnn/linear.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/linear.https.any.js
new file mode 100644
index 0000000..4b2c055
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webnn/linear.https.any.js
@@ -0,0 +1,10 @@
+// META: title=test WebNN API linear operation
+// META: global=window,dedicatedworker
+// META: script=./resources/utils.js
+// META: timeout=long
+
+'use strict';
+
+// https://webmachinelearning.github.io/webnn/#api-mlgraphbuilder-linear
+
+testWebNNOperation('linear', buildOperationWithSingleInput);
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webnn/linear.https.any.js.ini b/third_party/blink/web_tests/external/wpt/webnn/linear.https.any.js.ini
new file mode 100644
index 0000000..b3bb1d8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webnn/linear.https.any.js.ini
@@ -0,0 +1,101 @@
+[linear.https.any.html]
+  [linear float32 1D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 2D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 3D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 4D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 4D tensor specified options.alpha and default options.beta / async]
+    expected: FAIL
+
+  [linear float32 5D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / async]
+    expected: FAIL
+
+  [linear float32 negative 4D tensor specified negative options.beta and default options.alpha / async]
+    expected: FAIL
+
+  [linear float32 positive 4D tensor all options (negative options.alpha and negative options.beta) / async]
+    expected: FAIL
+
+  [linear float32 positive 4D tensor all options (positive options.alpha and positive options.beta) / async]
+    expected: FAIL
+
+  [linear float32 positive 4D tensor specified positive options.beta and default options.alpha / async]
+    expected: FAIL
+
+
+[linear.https.any.worker.html]
+  [linear float32 1D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 1D tensor default options / sync]
+    expected: FAIL
+
+  [linear float32 2D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 2D tensor default options / sync]
+    expected: FAIL
+
+  [linear float32 3D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 3D tensor default options / sync]
+    expected: FAIL
+
+  [linear float32 4D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 4D tensor default options / sync]
+    expected: FAIL
+
+  [linear float32 4D tensor specified options.alpha and default options.beta / async]
+    expected: FAIL
+
+  [linear float32 4D tensor specified options.alpha and default options.beta / sync]
+    expected: FAIL
+
+  [linear float32 5D tensor default options / async]
+    expected: FAIL
+
+  [linear float32 5D tensor default options / sync]
+    expected: FAIL
+
+  [linear float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / async]
+    expected: FAIL
+
+  [linear float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / sync]
+    expected: FAIL
+
+  [linear float32 negative 4D tensor specified negative options.beta and default options.alpha / async]
+    expected: FAIL
+
+  [linear float32 negative 4D tensor specified negative options.beta and default options.alpha / sync]
+    expected: FAIL
+
+  [linear float32 positive 4D tensor all options (negative options.alpha and negative options.beta) / async]
+    expected: FAIL
+
+  [linear float32 positive 4D tensor all options (negative options.alpha and negative options.beta) / sync]
+    expected: FAIL
+
+  [linear float32 positive 4D tensor all options (positive options.alpha and positive options.beta) / async]
+    expected: FAIL
+
+  [linear float32 positive 4D tensor all options (positive options.alpha and positive options.beta) / sync]
+    expected: FAIL
+
+  [linear float32 positive 4D tensor specified positive options.beta and default options.alpha / async]
+    expected: FAIL
+
+  [linear float32 positive 4D tensor specified positive options.beta and default options.alpha / sync]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/hard_sigmoid.json b/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/hard_sigmoid.json
new file mode 100644
index 0000000..22fe7c6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/hard_sigmoid.json
@@ -0,0 +1,890 @@
+{ // hardSigmoid: Calculate the non-smooth function used in place of a sigmoid function on the input tensor.
+  "tests": [
+    {
+      "name": "hardSigmoid float32 positive 1D tensor default options", // default options: {alpha: 0.2, beta: 0.5}
+      "inputs": {
+        "x": {
+          "shape": [24],
+          "data": [
+            0.05907066981577147,
+            0.7076089198897,
+            0.5228405296259637,
+            0.42310158753617455,
+            0.6643692569867639,
+            0.9502940424761401,
+            0.10918906453593258,
+            0.012977113903015258,
+            0.4755297159390164,
+            0.5322551665299613,
+            0.684307857800798,
+            0.4662107602754757,
+            0.3048996433987061,
+            0.8025872652109942,
+            0.2485963985673023,
+            0.6636898942337357,
+            0.554761182646025,
+            0.5542584257213008,
+            0.7311381962152534,
+            0.48809603333206986,
+            0.7766845231174959,
+            0.8455570201933926,
+            0.5553020911955322,
+            0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [24],
+        "data": [
+          0.5118141174316406,
+          0.6415218114852905,
+          0.6045681238174438,
+          0.5846202969551086,
+          0.6328738331794739,
+          0.6900588274002075,
+          0.5218378305435181,
+          0.5025954246520996,
+          0.5951059460639954,
+          0.6064510345458984,
+          0.6368615627288818,
+          0.5932421684265137,
+          0.5609799027442932,
+          0.6605174541473389,
+          0.5497192740440369,
+          0.6327379941940308,
+          0.6109522581100464,
+          0.6108517050743103,
+          0.6462276577949524,
+          0.5976191759109497,
+          0.6553369164466858,
+          0.669111430644989,
+          0.6110604405403137,
+          0.6120688915252686
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 positive 2D tensor default options",
+      "inputs": {
+        "x": {
+          "shape": [4, 6],
+          "data": [
+            0.05907066981577147,
+            0.7076089198897,
+            0.5228405296259637,
+            0.42310158753617455,
+            0.6643692569867639,
+            0.9502940424761401,
+            0.10918906453593258,
+            0.012977113903015258,
+            0.4755297159390164,
+            0.5322551665299613,
+            0.684307857800798,
+            0.4662107602754757,
+            0.3048996433987061,
+            0.8025872652109942,
+            0.2485963985673023,
+            0.6636898942337357,
+            0.554761182646025,
+            0.5542584257213008,
+            0.7311381962152534,
+            0.48809603333206986,
+            0.7766845231174959,
+            0.8455570201933926,
+            0.5553020911955322,
+            0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [4, 6],
+        "data": [
+          0.5118141174316406,
+          0.6415218114852905,
+          0.6045681238174438,
+          0.5846202969551086,
+          0.6328738331794739,
+          0.6900588274002075,
+          0.5218378305435181,
+          0.5025954246520996,
+          0.5951059460639954,
+          0.6064510345458984,
+          0.6368615627288818,
+          0.5932421684265137,
+          0.5609799027442932,
+          0.6605174541473389,
+          0.5497192740440369,
+          0.6327379941940308,
+          0.6109522581100464,
+          0.6108517050743103,
+          0.6462276577949524,
+          0.5976191759109497,
+          0.6553369164466858,
+          0.669111430644989,
+          0.6110604405403137,
+          0.6120688915252686
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 positive 3D tensor default options",
+      "inputs": {
+        "x": {
+          "shape": [2, 3, 4],
+          "data": [
+            0.05907066981577147,
+            0.7076089198897,
+            0.5228405296259637,
+            0.42310158753617455,
+            0.6643692569867639,
+            0.9502940424761401,
+            0.10918906453593258,
+            0.012977113903015258,
+            0.4755297159390164,
+            0.5322551665299613,
+            0.684307857800798,
+            0.4662107602754757,
+            0.3048996433987061,
+            0.8025872652109942,
+            0.2485963985673023,
+            0.6636898942337357,
+            0.554761182646025,
+            0.5542584257213008,
+            0.7311381962152534,
+            0.48809603333206986,
+            0.7766845231174959,
+            0.8455570201933926,
+            0.5553020911955322,
+            0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 3, 4],
+        "data": [
+          0.5118141174316406,
+          0.6415218114852905,
+          0.6045681238174438,
+          0.5846202969551086,
+          0.6328738331794739,
+          0.6900588274002075,
+          0.5218378305435181,
+          0.5025954246520996,
+          0.5951059460639954,
+          0.6064510345458984,
+          0.6368615627288818,
+          0.5932421684265137,
+          0.5609799027442932,
+          0.6605174541473389,
+          0.5497192740440369,
+          0.6327379941940308,
+          0.6109522581100464,
+          0.6108517050743103,
+          0.6462276577949524,
+          0.5976191759109497,
+          0.6553369164466858,
+          0.669111430644989,
+          0.6110604405403137,
+          0.6120688915252686
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 positive 4D tensor default options",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 3, 4],
+          "data": [
+            0.05907066981577147,
+            0.7076089198897,
+            0.5228405296259637,
+            0.42310158753617455,
+            0.6643692569867639,
+            0.9502940424761401,
+            0.10918906453593258,
+            0.012977113903015258,
+            0.4755297159390164,
+            0.5322551665299613,
+            0.684307857800798,
+            0.4662107602754757,
+            0.3048996433987061,
+            0.8025872652109942,
+            0.2485963985673023,
+            0.6636898942337357,
+            0.554761182646025,
+            0.5542584257213008,
+            0.7311381962152534,
+            0.48809603333206986,
+            0.7766845231174959,
+            0.8455570201933926,
+            0.5553020911955322,
+            0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 3, 4],
+        "data": [
+          0.5118141174316406,
+          0.6415218114852905,
+          0.6045681238174438,
+          0.5846202969551086,
+          0.6328738331794739,
+          0.6900588274002075,
+          0.5218378305435181,
+          0.5025954246520996,
+          0.5951059460639954,
+          0.6064510345458984,
+          0.6368615627288818,
+          0.5932421684265137,
+          0.5609799027442932,
+          0.6605174541473389,
+          0.5497192740440369,
+          0.6327379941940308,
+          0.6109522581100464,
+          0.6108517050743103,
+          0.6462276577949524,
+          0.5976191759109497,
+          0.6553369164466858,
+          0.669111430644989,
+          0.6110604405403137,
+          0.6120688915252686
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 positive 5D tensor default options",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 1, 3, 4],
+          "data": [
+            0.05907066981577147,
+            0.7076089198897,
+            0.5228405296259637,
+            0.42310158753617455,
+            0.6643692569867639,
+            0.9502940424761401,
+            0.10918906453593258,
+            0.012977113903015258,
+            0.4755297159390164,
+            0.5322551665299613,
+            0.684307857800798,
+            0.4662107602754757,
+            0.3048996433987061,
+            0.8025872652109942,
+            0.2485963985673023,
+            0.6636898942337357,
+            0.554761182646025,
+            0.5542584257213008,
+            0.7311381962152534,
+            0.48809603333206986,
+            0.7766845231174959,
+            0.8455570201933926,
+            0.5553020911955322,
+            0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 1, 3, 4],
+        "data": [
+          0.5118141174316406,
+          0.6415218114852905,
+          0.6045681238174438,
+          0.5846202969551086,
+          0.6328738331794739,
+          0.6900588274002075,
+          0.5218378305435181,
+          0.5025954246520996,
+          0.5951059460639954,
+          0.6064510345458984,
+          0.6368615627288818,
+          0.5932421684265137,
+          0.5609799027442932,
+          0.6605174541473389,
+          0.5497192740440369,
+          0.6327379941940308,
+          0.6109522581100464,
+          0.6108517050743103,
+          0.6462276577949524,
+          0.5976191759109497,
+          0.6553369164466858,
+          0.669111430644989,
+          0.6110604405403137,
+          0.6120688915252686
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 positive 4D tensor specified positive options.alpha default options.beta",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 3, 4],
+          "data": [
+            0.05907066981577147,
+            0.7076089198897,
+            0.5228405296259637,
+            0.42310158753617455,
+            0.6643692569867639,
+            0.9502940424761401,
+            0.10918906453593258,
+            0.012977113903015258,
+            0.4755297159390164,
+            0.5322551665299613,
+            0.684307857800798,
+            0.4662107602754757,
+            0.3048996433987061,
+            0.8025872652109942,
+            0.2485963985673023,
+            0.6636898942337357,
+            0.554761182646025,
+            0.5542584257213008,
+            0.7311381962152534,
+            0.48809603333206986,
+            0.7766845231174959,
+            0.8455570201933926,
+            0.5553020911955322,
+            0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": 0.7854232544278235
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 3, 4],
+        "data": [
+          0.546395480632782,
+          1,
+          0.9106510877609253,
+          0.8323138356208801,
+          1,
+          1,
+          0.5857596397399902,
+          0.5101925134658813,
+          0.8734921216964722,
+          0.9180455803871155,
+          1,
+          0.8661727905273438,
+          0.7394752502441406,
+          1,
+          0.6952533721923828,
+          1,
+          0.9357223510742188,
+          0.9353274703025818,
+          1,
+          0.8833619952201843,
+          1,
+          1,
+          0.936147153377533,
+          0.9401075839996338
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 negative 4D tensor specified negative options.alpha default options.beta",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 3, 4],
+          "data": [
+            -0.05907066981577147,
+            -0.7076089198897,
+            -0.5228405296259637,
+            -0.42310158753617455,
+            -0.6643692569867639,
+            -0.9502940424761401,
+            -0.10918906453593258,
+            -0.012977113903015258,
+            -0.4755297159390164,
+            -0.5322551665299613,
+            -0.684307857800798,
+            -0.4662107602754757,
+            -0.3048996433987061,
+            -0.8025872652109942,
+            -0.2485963985673023,
+            -0.6636898942337357,
+            -0.554761182646025,
+            -0.5542584257213008,
+            -0.7311381962152534,
+            -0.48809603333206986,
+            -0.7766845231174959,
+            -0.8455570201933926,
+            -0.5553020911955322,
+            -0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": -0.7854232544278235
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 3, 4],
+        "data": [
+          0.546395480632782,
+          1,
+          0.9106510877609253,
+          0.8323138356208801,
+          1,
+          1,
+          0.5857596397399902,
+          0.5101925134658813,
+          0.8734921216964722,
+          0.9180455803871155,
+          1,
+          0.8661727905273438,
+          0.7394752502441406,
+          1,
+          0.6952533721923828,
+          1,
+          0.9357223510742188,
+          0.9353274703025818,
+          1,
+          0.8833619952201843,
+          1,
+          1,
+          0.936147153377533,
+          0.9401075839996338
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 positive 4D tensor specified positive options.beta default options.alpha",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 3, 4],
+          "data": [
+            0.05907066981577147,
+            0.7076089198897,
+            0.5228405296259637,
+            0.42310158753617455,
+            0.6643692569867639,
+            0.9502940424761401,
+            0.10918906453593258,
+            0.012977113903015258,
+            0.4755297159390164,
+            0.5322551665299613,
+            0.684307857800798,
+            0.4662107602754757,
+            0.3048996433987061,
+            0.8025872652109942,
+            0.2485963985673023,
+            0.6636898942337357,
+            0.554761182646025,
+            0.5542584257213008,
+            0.7311381962152534,
+            0.48809603333206986,
+            0.7766845231174959,
+            0.8455570201933926,
+            0.5553020911955322,
+            0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "beta": 0.4361860418530341
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 3, 4],
+        "data": [
+          0.4480001926422119,
+          0.577707827091217,
+          0.5407541394233704,
+          0.5208063721656799,
+          0.5690599083900452,
+          0.626244843006134,
+          0.4580238461494446,
+          0.4387814700603485,
+          0.5312919616699219,
+          0.5426371097564697,
+          0.5730476379394531,
+          0.5294281840324402,
+          0.4971659779548645,
+          0.5967035293579102,
+          0.48590531945228577,
+          0.5689240097999573,
+          0.5471382737159729,
+          0.5470377206802368,
+          0.5824136734008789,
+          0.533805251121521,
+          0.5915229320526123,
+          0.6052974462509155,
+          0.5472464561462402,
+          0.5482549667358398
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 negative 4D tensor specified negative options.beta default options.alpha",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 3, 4],
+          "data": [
+            -0.05907066981577147,
+            -0.7076089198897,
+            -0.5228405296259637,
+            -0.42310158753617455,
+            -0.6643692569867639,
+            -0.9502940424761401,
+            -0.10918906453593258,
+            -0.012977113903015258,
+            -0.4755297159390164,
+            -0.5322551665299613,
+            -0.684307857800798,
+            -0.4662107602754757,
+            -0.3048996433987061,
+            -0.8025872652109942,
+            -0.2485963985673023,
+            -0.6636898942337357,
+            -0.554761182646025,
+            -0.5542584257213008,
+            -0.7311381962152534,
+            -0.48809603333206986,
+            -0.7766845231174959,
+            -0.8455570201933926,
+            -0.5553020911955322,
+            -0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "beta": -0.436186041853034
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 3, 4],
+        "data": [
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 positive 4D tensor specified all options (positive options.alpha and positive options.beta)",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 3, 4],
+          "data": [
+            0.05907066981577147,
+            0.7076089198897,
+            0.5228405296259637,
+            0.42310158753617455,
+            0.6643692569867639,
+            0.9502940424761401,
+            0.10918906453593258,
+            0.012977113903015258,
+            0.4755297159390164,
+            0.5322551665299613,
+            0.684307857800798,
+            0.4662107602754757,
+            0.3048996433987061,
+            0.8025872652109942,
+            0.2485963985673023,
+            0.6636898942337357,
+            0.554761182646025,
+            0.5542584257213008,
+            0.7311381962152534,
+            0.48809603333206986,
+            0.7766845231174959,
+            0.8455570201933926,
+            0.5553020911955322,
+            0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": 0.7854232544278235,
+        "beta": 0.4361860418530341
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 3, 4],
+        "data": [
+          0.4825815260410309,
+          0.9919585585594177,
+          0.8468371629714966,
+          0.7684998512268066,
+          0.9579971432685852,
+          1,
+          0.5219456553459167,
+          0.44637855887413025,
+          0.8096781373023987,
+          0.8542316555976868,
+          0.9736573696136475,
+          0.8023588061332703,
+          0.6756613254547119,
+          1,
+          0.6314394474029541,
+          0.9574635624885559,
+          0.8719083666801453,
+          0.8715134859085083,
+          1,
+          0.8195480108261108,
+          1,
+          1,
+          0.8723332285881042,
+          0.8762935996055603
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 positive 4D tensor specified all options (negative options.alpha and negative options.beta)",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 3, 4],
+          "data": [
+            0.05907066981577147,
+            0.7076089198897,
+            0.5228405296259637,
+            0.42310158753617455,
+            0.6643692569867639,
+            0.9502940424761401,
+            0.10918906453593258,
+            0.012977113903015258,
+            0.4755297159390164,
+            0.5322551665299613,
+            0.684307857800798,
+            0.4662107602754757,
+            0.3048996433987061,
+            0.8025872652109942,
+            0.2485963985673023,
+            0.6636898942337357,
+            0.554761182646025,
+            0.5542584257213008,
+            0.7311381962152534,
+            0.48809603333206986,
+            0.7766845231174959,
+            0.8455570201933926,
+            0.5553020911955322,
+            0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": -0.7854232544278235,
+        "beta": -0.4361860418530341
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 3, 4],
+        "data": [
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 negative 4D tensor all options (positive options.alpha and negative options.beta)",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 3, 4],
+          "data": [
+            -0.05907066981577147,
+            -0.7076089198897,
+            -0.5228405296259637,
+            -0.42310158753617455,
+            -0.6643692569867639,
+            -0.9502940424761401,
+            -0.10918906453593258,
+            -0.012977113903015258,
+            -0.4755297159390164,
+            -0.5322551665299613,
+            -0.684307857800798,
+            -0.4662107602754757,
+            -0.3048996433987061,
+            -0.8025872652109942,
+            -0.2485963985673023,
+            -0.6636898942337357,
+            -0.554761182646025,
+            -0.5542584257213008,
+            -0.7311381962152534,
+            -0.48809603333206986,
+            -0.7766845231174959,
+            -0.8455570201933926,
+            -0.5553020911955322,
+            -0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": 0.7854232544278235,
+        "beta": -0.4361860418530341
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 3, 4],
+        "data": [
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "hardSigmoid float32 negative 4D tensor specified all options (negative options.alpha and positive options.beta)",
+      "inputs": {
+        "x": {
+          "shape": [1, 2, 3, 4],
+          "data": [
+            -0.05907066981577147,
+            -0.7076089198897,
+            -0.5228405296259637,
+            -0.42310158753617455,
+            -0.6643692569867639,
+            -0.9502940424761401,
+            -0.10918906453593258,
+            -0.012977113903015258,
+            -0.4755297159390164,
+            -0.5322551665299613,
+            -0.684307857800798,
+            -0.4662107602754757,
+            -0.3048996433987061,
+            -0.8025872652109942,
+            -0.2485963985673023,
+            -0.6636898942337357,
+            -0.554761182646025,
+            -0.5542584257213008,
+            -0.7311381962152534,
+            -0.48809603333206986,
+            -0.7766845231174959,
+            -0.8455570201933926,
+            -0.5553020911955322,
+            -0.5603444395469193
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": -0.7854232544278235,
+        "beta": 0.4361860418530341
+      },
+      "expected": {
+        "name": "output",
+        "shape": [1, 2, 3, 4],
+        "data": [
+          0.4825815260410309,
+          0.9919585585594177,
+          0.8468371629714966,
+          0.7684998512268066,
+          0.9579971432685852,
+          1,
+          0.5219456553459167,
+          0.44637855887413025,
+          0.8096781373023987,
+          0.8542316555976868,
+          0.9736573696136475,
+          0.8023588061332703,
+          0.6756613254547119,
+          1,
+          0.6314394474029541,
+          0.9574635624885559,
+          0.8719083666801453,
+          0.8715134859085083,
+          1,
+          0.8195480108261108,
+          1,
+          1,
+          0.8723332285881042,
+          0.8762935996055603
+        ],
+        "type": "float32"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/linear.json b/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/linear.json
new file mode 100644
index 0000000..ded1d2d7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webnn/resources/test_data/linear.json
@@ -0,0 +1,751 @@
+{ // linear: Calculate a linear function y = alpha * x + beta on the input tensor.
+  "tests": [
+    {
+      "name": "linear float32 1D tensor default options", // default options: {alpha: 1, beta: 0}
+      "inputs": {
+        "x": {
+          "shape": [24],
+          "data": [
+            -1.1225161816883542,
+            -6.605223195131225,
+            -1.9555539248683687,
+            -4.598548331438281,
+            4.234208072658522,
+            3.097542121236385,
+            3.7465923873418348,
+            -4.487029772637743,
+            6.407402114982858,
+            -4.354544013606705,
+            -5.8190925441357955,
+            3.7214346452179328,
+            -6.330114110872294,
+            8.580595073862398,
+            -6.764922344398516,
+            6.433565829855674,
+            -9.708685944356201,
+            2.6431380232113746,
+            5.214088864824586,
+            9.658617012096975,
+            -8.72174939837989,
+            -0.4533396492565025,
+            9.992619953447026,
+            -6.469674921617137
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [24],
+        "data": [
+          -1.12251615524292,
+          -6.605223178863525,
+          -1.9555538892745972,
+          -4.598548412322998,
+          4.234208106994629,
+          3.0975420475006104,
+          3.7465922832489014,
+          -4.487029552459717,
+          6.407402038574219,
+          -4.354544162750244,
+          -5.819092750549316,
+          3.7214345932006836,
+          -6.330113887786865,
+          8.580595016479492,
+          -6.764922142028809,
+          6.433565616607666,
+          -9.708685874938965,
+          2.6431379318237305,
+          5.2140889167785645,
+          9.65861701965332,
+          -8.721749305725098,
+          -0.4533396363258362,
+          9.992619514465332,
+          -6.469675064086914
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 2D tensor default options",
+      "inputs": {
+        "x": {
+          "shape": [4, 6],
+          "data": [
+            -1.1225161816883542,
+            -6.605223195131225,
+            -1.9555539248683687,
+            -4.598548331438281,
+            4.234208072658522,
+            3.097542121236385,
+            3.7465923873418348,
+            -4.487029772637743,
+            6.407402114982858,
+            -4.354544013606705,
+            -5.8190925441357955,
+            3.7214346452179328,
+            -6.330114110872294,
+            8.580595073862398,
+            -6.764922344398516,
+            6.433565829855674,
+            -9.708685944356201,
+            2.6431380232113746,
+            5.214088864824586,
+            9.658617012096975,
+            -8.72174939837989,
+            -0.4533396492565025,
+            9.992619953447026,
+            -6.469674921617137
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [4, 6],
+        "data": [
+          -1.12251615524292,
+          -6.605223178863525,
+          -1.9555538892745972,
+          -4.598548412322998,
+          4.234208106994629,
+          3.0975420475006104,
+          3.7465922832489014,
+          -4.487029552459717,
+          6.407402038574219,
+          -4.354544162750244,
+          -5.819092750549316,
+          3.7214345932006836,
+          -6.330113887786865,
+          8.580595016479492,
+          -6.764922142028809,
+          6.433565616607666,
+          -9.708685874938965,
+          2.6431379318237305,
+          5.2140889167785645,
+          9.65861701965332,
+          -8.721749305725098,
+          -0.4533396363258362,
+          9.992619514465332,
+          -6.469675064086914
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 3D tensor default options",
+      "inputs": {
+        "x": {
+          "shape": [2, 3, 4],
+          "data": [
+            -1.1225161816883542,
+            -6.605223195131225,
+            -1.9555539248683687,
+            -4.598548331438281,
+            4.234208072658522,
+            3.097542121236385,
+            3.7465923873418348,
+            -4.487029772637743,
+            6.407402114982858,
+            -4.354544013606705,
+            -5.8190925441357955,
+            3.7214346452179328,
+            -6.330114110872294,
+            8.580595073862398,
+            -6.764922344398516,
+            6.433565829855674,
+            -9.708685944356201,
+            2.6431380232113746,
+            5.214088864824586,
+            9.658617012096975,
+            -8.72174939837989,
+            -0.4533396492565025,
+            9.992619953447026,
+            -6.469674921617137
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 3, 4],
+        "data": [
+          -1.12251615524292,
+          -6.605223178863525,
+          -1.9555538892745972,
+          -4.598548412322998,
+          4.234208106994629,
+          3.0975420475006104,
+          3.7465922832489014,
+          -4.487029552459717,
+          6.407402038574219,
+          -4.354544162750244,
+          -5.819092750549316,
+          3.7214345932006836,
+          -6.330113887786865,
+          8.580595016479492,
+          -6.764922142028809,
+          6.433565616607666,
+          -9.708685874938965,
+          2.6431379318237305,
+          5.2140889167785645,
+          9.65861701965332,
+          -8.721749305725098,
+          -0.4533396363258362,
+          9.992619514465332,
+          -6.469675064086914
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 4D tensor default options",
+      "inputs": {
+        "x": {
+          "shape": [2, 2, 2, 3],
+          "data": [
+            -1.1225161816883542,
+            -6.605223195131225,
+            -1.9555539248683687,
+            -4.598548331438281,
+            4.234208072658522,
+            3.097542121236385,
+            3.7465923873418348,
+            -4.487029772637743,
+            6.407402114982858,
+            -4.354544013606705,
+            -5.8190925441357955,
+            3.7214346452179328,
+            -6.330114110872294,
+            8.580595073862398,
+            -6.764922344398516,
+            6.433565829855674,
+            -9.708685944356201,
+            2.6431380232113746,
+            5.214088864824586,
+            9.658617012096975,
+            -8.72174939837989,
+            -0.4533396492565025,
+            9.992619953447026,
+            -6.469674921617137
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 2, 2, 3],
+        "data": [
+          -1.12251615524292,
+          -6.605223178863525,
+          -1.9555538892745972,
+          -4.598548412322998,
+          4.234208106994629,
+          3.0975420475006104,
+          3.7465922832489014,
+          -4.487029552459717,
+          6.407402038574219,
+          -4.354544162750244,
+          -5.819092750549316,
+          3.7214345932006836,
+          -6.330113887786865,
+          8.580595016479492,
+          -6.764922142028809,
+          6.433565616607666,
+          -9.708685874938965,
+          2.6431379318237305,
+          5.2140889167785645,
+          9.65861701965332,
+          -8.721749305725098,
+          -0.4533396363258362,
+          9.992619514465332,
+          -6.469675064086914
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 5D tensor default options",
+      "inputs": {
+        "x": {
+          "shape": [2, 1, 4, 1, 3],
+          "data": [
+            -1.1225161816883542,
+            -6.605223195131225,
+            -1.9555539248683687,
+            -4.598548331438281,
+            4.234208072658522,
+            3.097542121236385,
+            3.7465923873418348,
+            -4.487029772637743,
+            6.407402114982858,
+            -4.354544013606705,
+            -5.8190925441357955,
+            3.7214346452179328,
+            -6.330114110872294,
+            8.580595073862398,
+            -6.764922344398516,
+            6.433565829855674,
+            -9.708685944356201,
+            2.6431380232113746,
+            5.214088864824586,
+            9.658617012096975,
+            -8.72174939837989,
+            -0.4533396492565025,
+            9.992619953447026,
+            -6.469674921617137
+          ],
+          "type": "float32"
+        }
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 1, 4, 1, 3],
+        "data": [
+          -1.12251615524292,
+          -6.605223178863525,
+          -1.9555538892745972,
+          -4.598548412322998,
+          4.234208106994629,
+          3.0975420475006104,
+          3.7465922832489014,
+          -4.487029552459717,
+          6.407402038574219,
+          -4.354544162750244,
+          -5.819092750549316,
+          3.7214345932006836,
+          -6.330113887786865,
+          8.580595016479492,
+          -6.764922142028809,
+          6.433565616607666,
+          -9.708685874938965,
+          2.6431379318237305,
+          5.2140889167785645,
+          9.65861701965332,
+          -8.721749305725098,
+          -0.4533396363258362,
+          9.992619514465332,
+          -6.469675064086914
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 4D tensor specified options.alpha and default options.beta",
+      "inputs": {
+        "x": {
+         "shape": [2, 2, 2, 3],
+          "data": [
+            -1.1225161816883542,
+            -6.605223195131225,
+            -1.9555539248683687,
+            -4.598548331438281,
+            4.234208072658522,
+            3.097542121236385,
+            3.7465923873418348,
+            -4.487029772637743,
+            6.407402114982858,
+            -4.354544013606705,
+            -5.8190925441357955,
+            3.7214346452179328,
+            -6.330114110872294,
+            8.580595073862398,
+            -6.764922344398516,
+            6.433565829855674,
+            -9.708685944356201,
+            2.6431380232113746,
+            5.214088864824586,
+            9.658617012096975,
+            -8.72174939837989,
+            -0.4533396492565025,
+            9.992619953447026,
+            -6.469674921617137
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": 7.398793812746618
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 2, 2, 3],
+        "data": [
+          -8.305265426635742,
+          -48.87068176269531,
+          -14.46873950958252,
+          -34.023712158203125,
+          31.328031539916992,
+          22.918073654174805,
+          27.72026252746582,
+          -33.198604583740234,
+          47.407047271728516,
+          -32.2183723449707,
+          -43.05426788330078,
+          27.53412628173828,
+          -46.835205078125,
+          63.486053466796875,
+          -50.05226516723633,
+          47.600624084472656,
+          -71.83256530761719,
+          19.556032180786133,
+          38.57796859741211,
+          71.46211242675781,
+          -64.53042602539062,
+          -3.3541665077209473,
+          73.9333267211914,
+          -47.86779022216797
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 positive 4D tensor specified positive options.beta and default options.alpha",
+      "inputs": {
+        "x": {
+         "shape": [2, 2, 2, 3],
+          "data": [
+            5.098545948694657,
+            3.381463063963137,
+            8.054763200467299,
+            8.074773950900846,
+            0.47079092139064027,
+            5.243823847381135,
+            3.8273059380736973,
+            5.369768658136882,
+            6.103317088913478,
+            3.75057871122652,
+            0.7479738402058334,
+            1.8931976115227744,
+            1.9056464154414843,
+            7.8633162842491355,
+            4.580754697122725,
+            9.373635444757738,
+            6.584214206038917,
+            9.344809838863029,
+            5.16057820830762,
+            0.8060914255567009,
+            9.13053330505177,
+            3.193740457592318,
+            5.748293601645558,
+            4.113487804502045
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "beta": 5.919095653700928
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 2, 2, 3],
+        "data": [
+          11.017641067504883,
+          9.300558090209961,
+          13.973857879638672,
+          13.99386978149414,
+          6.389886379241943,
+          11.162919998168945,
+          9.7464017868042,
+          11.288864135742188,
+          12.02241325378418,
+          9.669673919677734,
+          6.667069435119629,
+          7.81229305267334,
+          7.824741840362549,
+          13.782411575317383,
+          10.499850273132324,
+          15.292730331420898,
+          12.50330924987793,
+          15.263904571533203,
+          11.079673767089844,
+          6.725186824798584,
+          15.049629211425781,
+          9.112835884094238,
+          11.667388916015625,
+          10.032583236694336
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 negative 4D tensor specified negative options.beta and default options.alpha",
+      "inputs": {
+        "x": {
+         "shape": [2, 2, 2, 3],
+          "data": [
+            -5.098545948694657,
+            -3.381463063963137,
+            -8.054763200467299,
+            -8.074773950900846,
+            -0.47079092139064027,
+            -5.243823847381135,
+            -3.8273059380736973,
+            -5.369768658136882,
+            -6.103317088913478,
+            -3.75057871122652,
+            -0.7479738402058334,
+            -1.8931976115227744,
+            -1.9056464154414843,
+            -7.8633162842491355,
+            -4.580754697122725,
+            -9.373635444757738,
+            -6.584214206038917,
+            -9.344809838863029,
+            -5.16057820830762,
+            -0.8060914255567009,
+            -9.13053330505177,
+            -3.193740457592318,
+            -5.748293601645558,
+            -4.113487804502045
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "beta": -5.919095653700928
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 2, 2, 3],
+        "data": [
+          -11.017641067504883,
+          -9.300558090209961,
+          -13.973857879638672,
+          -13.99386978149414,
+          -6.389886379241943,
+          -11.162919998168945,
+          -9.7464017868042,
+          -11.288864135742188,
+          -12.02241325378418,
+          -9.669673919677734,
+          -6.667069435119629,
+          -7.81229305267334,
+          -7.824741840362549,
+          -13.782411575317383,
+          -10.499850273132324,
+          -15.292730331420898,
+          -12.50330924987793,
+          -15.263904571533203,
+          -11.079673767089844,
+          -6.725186824798584,
+          -15.049629211425781,
+          -9.112835884094238,
+          -11.667388916015625,
+          -10.032583236694336
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 positive 4D tensor all options (positive options.alpha and positive options.beta)",
+      "inputs": {
+        "x": {
+         "shape": [2, 2, 2, 3],
+          "data": [
+            5.098545948694657,
+            3.381463063963137,
+            8.054763200467299,
+            8.074773950900846,
+            0.47079092139064027,
+            5.243823847381135,
+            3.8273059380736973,
+            5.369768658136882,
+            6.103317088913478,
+            3.75057871122652,
+            0.7479738402058334,
+            1.8931976115227744,
+            1.9056464154414843,
+            7.8633162842491355,
+            4.580754697122725,
+            9.373635444757738,
+            6.584214206038917,
+            9.344809838863029,
+            5.16057820830762,
+            0.8060914255567009,
+            9.13053330505177,
+            3.193740457592318,
+            5.748293601645558,
+            4.113487804502045
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": 7.398793812746618,
+        "beta": 5.919095653700928
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 2, 2, 3],
+        "data": [
+          43.64218521118164,
+          30.937843322753906,
+          65.5146255493164,
+          65.66268157958984,
+          9.402379989624023,
+          44.71706771850586,
+          34.236541748046875,
+          45.64890670776367,
+          51.0762825012207,
+          33.668853759765625,
+          11.45319938659668,
+          19.92647361755371,
+          20.018579483032227,
+          64.09815216064453,
+          39.811153411865234,
+          75.27268981933594,
+          54.63433837890625,
+          75.05941009521484,
+          44.10115051269531,
+          11.883199691772461,
+          73.47402954101562,
+          29.548921585083008,
+          48.44953155517578,
+          36.35394287109375
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 positive 4D tensor all options (negative options.alpha and negative options.beta)",
+      "inputs": {
+        "x": {
+         "shape": [2, 2, 2, 3],
+          "data": [
+            5.098545948694657,
+            3.381463063963137,
+            8.054763200467299,
+            8.074773950900846,
+            0.47079092139064027,
+            5.243823847381135,
+            3.8273059380736973,
+            5.369768658136882,
+            6.103317088913478,
+            3.75057871122652,
+            0.7479738402058334,
+            1.8931976115227744,
+            1.9056464154414843,
+            7.8633162842491355,
+            4.580754697122725,
+            9.373635444757738,
+            6.584214206038917,
+            9.344809838863029,
+            5.16057820830762,
+            0.8060914255567009,
+            9.13053330505177,
+            3.193740457592318,
+            5.748293601645558,
+            4.113487804502045
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": -7.398793812746618,
+        "beta": -5.919095653700928
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 2, 2, 3],
+        "data": [
+          -43.64218521118164,
+          -30.937843322753906,
+          -65.5146255493164,
+          -65.66268157958984,
+          -9.402379989624023,
+          -44.71706771850586,
+          -34.236541748046875,
+          -45.64890670776367,
+          -51.0762825012207,
+          -33.668853759765625,
+          -11.45319938659668,
+          -19.92647361755371,
+          -20.018579483032227,
+          -64.09815216064453,
+          -39.811153411865234,
+          -75.27268981933594,
+          -54.63433837890625,
+          -75.05941009521484,
+          -44.10115051269531,
+          -11.883199691772461,
+          -73.47402954101562,
+          -29.548921585083008,
+          -48.44953155517578,
+          -36.35394287109375
+        ],
+        "type": "float32"
+      }
+    },
+    {
+      "name": "linear float32 negative 4D tensor all options (positive options.alpha and negative options.beta)",
+      "inputs": {
+        "x": {
+         "shape": [2, 2, 2, 3],
+          "data": [
+            -5.098545948694657,
+            -3.381463063963137,
+            -8.054763200467299,
+            -8.074773950900846,
+            -0.47079092139064027,
+            -5.243823847381135,
+            -3.8273059380736973,
+            -5.369768658136882,
+            -6.103317088913478,
+            -3.75057871122652,
+            -0.7479738402058334,
+            -1.8931976115227744,
+            -1.9056464154414843,
+            -7.8633162842491355,
+            -4.580754697122725,
+            -9.373635444757738,
+            -6.584214206038917,
+            -9.344809838863029,
+            -5.16057820830762,
+            -0.8060914255567009,
+            -9.13053330505177,
+            -3.193740457592318,
+            -5.748293601645558,
+            -4.113487804502045
+          ],
+          "type": "float32"
+        }
+      },
+      "options": {
+        "alpha": 7.398793812746618,
+        "beta": -5.919095653700928
+      },
+      "expected": {
+        "name": "output",
+        "shape": [2, 2, 2, 3],
+        "data": [
+          -43.64218521118164,
+          -30.937843322753906,
+          -65.5146255493164,
+          -65.66268157958984,
+          -9.402379989624023,
+          -44.71706771850586,
+          -34.236541748046875,
+          -45.64890670776367,
+          -51.0762825012207,
+          -33.668853759765625,
+          -11.45319938659668,
+          -19.92647361755371,
+          -20.018579483032227,
+          -64.09815216064453,
+          -39.811153411865234,
+          -75.27268981933594,
+          -54.63433837890625,
+          -75.05941009521484,
+          -44.10115051269531,
+          -11.883199691772461,
+          -73.47402954101562,
+          -29.548921585083008,
+          -48.44953155517578,
+          -36.35394287109375
+        ],
+        "type": "float32"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js b/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
index d24562e..49f1762 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
@@ -267,8 +267,10 @@
   // End Element-wise unary operations
   elu: {ULP: {float32: 18, float16: 18}},
   gemm: {ULP: {float32: getGemmPrecisionTolerance, float16: getGemmPrecisionTolerance}},
+  hardSigmoid: {ULP: {float32: 2, float16: 2}},
   hardSwish: {ULP: {float32: 4, float16: 4}},
   leakyRelu: {ULP: {float32: 1, float16: 1}},
+  linear: {ULP: {float32: 2, float16: 2}},
   matmul: {ULP: {float32: getMatmulPrecisionTolerance, float16: getMatmulPrecisionTolerance}},
   pad: {ULP: {float32: 0, float16: 0}},
   // Begin Pooling operations
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/hardware-capability-stats.https.html.ini b/third_party/blink/web_tests/external/wpt/webrtc-stats/hardware-capability-stats.https.html.ini
index 629a492..ae8b422c 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-stats/hardware-capability-stats.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/webrtc-stats/hardware-capability-stats.https.html.ini
@@ -1,4 +1,5 @@
 [hardware-capability-stats.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [decoderImplementation exposed when capturing.]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getSynchronizationSources.https.html.ini b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getSynchronizationSources.https.html.ini
index e5eb211..fb1b72f 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getSynchronizationSources.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getSynchronizationSources.https.html.ini
@@ -1,4 +1,5 @@
 [RTCRtpReceiver-getSynchronizationSources.https.html]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [[audio-only\] RTCRtpSynchronizationSource.audioLevel is a number [0, 1\]]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/simulcast/vp9-scalability-mode.https.html.ini b/third_party/blink/web_tests/external/wpt/webrtc/simulcast/vp9-scalability-mode.https.html.ini
index 86234908..ab35181 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/simulcast/vp9-scalability-mode.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/webrtc/simulcast/vp9-scalability-mode.https.html.ini
@@ -1,4 +1,5 @@
 [vp9-scalability-mode.https.html]
+  disabled: times out even with extended deadline
   expected:
     if product == "chrome": TIMEOUT
   [VP9 simulcast setup with two streams and L1T2 set]
diff --git a/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/backpressure-send.any.js.ini b/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/backpressure-send.any.js.ini
index 79fa753..84f0c69 100644
--- a/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/backpressure-send.any.js.ini
+++ b/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/backpressure-send.any.js.ini
@@ -1,22 +1,26 @@
 [backpressure-send.any.html?wpt_flags=h2]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [backpressure should be applied to sent messages]
     expected: TIMEOUT
 
 
 [backpressure-send.any.serviceworker.html?wpt_flags=h2]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [backpressure should be applied to sent messages]
     expected: TIMEOUT
 
 
 [backpressure-send.any.sharedworker.html?wpt_flags=h2]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [backpressure should be applied to sent messages]
     expected: TIMEOUT
 
 
 [backpressure-send.any.worker.html?wpt_flags=h2]
+  disabled: times out even with extended deadline
   expected: TIMEOUT
   [backpressure should be applied to sent messages]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/fast/events/touch/script-tests/touch-slider.js b/third_party/blink/web_tests/fast/events/touch/script-tests/touch-slider.js
index 8df08725..180f927 100644
--- a/third_party/blink/web_tests/fast/events/touch/script-tests/touch-slider.js
+++ b/third_party/blink/web_tests/fast/events/touch/script-tests/touch-slider.js
@@ -10,7 +10,7 @@
 slider2.setAttribute("type", "range");
 slider2.style.width = "30px";
 slider2.style.height = "200px";
-slider2.style.setProperty("-webkit-appearance", "slider-vertical");
+slider2.style.setProperty("writing-mode", "vertical-lr");
 var slider3 = document.createElement("input");
 slider3.id = "slider3";
 slider3.setAttribute("type", "range");
diff --git a/third_party/blink/web_tests/fast/events/touch/touch-action-range-input-crash.html b/third_party/blink/web_tests/fast/events/touch/touch-action-range-input-crash.html
index d6f3fc5e..800ab2bc 100644
--- a/third_party/blink/web_tests/fast/events/touch/touch-action-range-input-crash.html
+++ b/third_party/blink/web_tests/fast/events/touch/touch-action-range-input-crash.html
@@ -3,7 +3,7 @@
 <script src='../../../resources/testharnessreport.js'></script>
 
 <style type='text/css'>
-*:before{-webkit-appearance:slider-vertical;}
+*:before{writing-mode: vertical-lr;}
 </style>
 
 <select  multiple='multiple'>
diff --git a/third_party/blink/web_tests/fast/events/touch/touch-action-range-input.html b/third_party/blink/web_tests/fast/events/touch/touch-action-range-input.html
index 07584eb1..00b749ff 100644
--- a/third_party/blink/web_tests/fast/events/touch/touch-action-range-input.html
+++ b/third_party/blink/web_tests/fast/events/touch/touch-action-range-input.html
@@ -21,7 +21,7 @@
 </table>
 <div><input type='range' id='slider1' min = '0' max = '100' step = '10'></input></div>
 <div><input type='range' id='slider2' min = '0' max = '100' step = '10' style='touch-action:none;'></div>
-<div><input type='range' id='slider3' min = '0' max = '100' step = '10' style='-webkit-appearance: slider-vertical;'></div>
+<div><input type='range' id='slider3' min='0' max='100' step='10' style='writing-mode:vertical-lr;'></div>
 <table id = 'table2'><tbody /></table>
 
 <script>
diff --git a/third_party/blink/web_tests/fast/forms/color-scheme/range/range-appearance-basic.html b/third_party/blink/web_tests/fast/forms/color-scheme/range/range-appearance-basic.html
index 61b3040..df46ea7 100644
--- a/third_party/blink/web_tests/fast/forms/color-scheme/range/range-appearance-basic.html
+++ b/third_party/blink/web_tests/fast/forms/color-scheme/range/range-appearance-basic.html
@@ -5,7 +5,8 @@
 <body>
 <style>
   #vertical {
-    -webkit-appearance: slider-vertical;
+    writing-mode: vertical-lr;
+    -webkit-appearance: auto;
   }
 
   #no-appearance {
diff --git a/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-datalist-zoomed.html b/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-datalist-zoomed.html
index dbd3f9c..1a0961dd 100644
--- a/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-datalist-zoomed.html
+++ b/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-datalist-zoomed.html
@@ -1,16 +1,16 @@
 <div style="zoom: 0.7;">
     <input type=range list=foo style="width: 100px;" />
-    <input type=range list=foo style="-webkit-appearance:slider-vertical; height: 100px; width: 30px" />
+    <input type=range list=foo style="writing-mode: vertical-lr; height: 100px; width: 30px" />
 </div>
 
 <div style="zoom: 1.5;">
     <input type=range list=foo style="width: 100px;" />
-    <input type=range list=foo style="-webkit-appearance:slider-vertical; height: 100px; width: 30px" />
+    <input type=range list=foo style="writing-mode: vertical-lr; height: 100px; width: 30px" />
 </div>
 
 <div style="zoom: 2;">
     <input type=range list=foo style="width: 100px;" />
-    <input type=range list=foo style="-webkit-appearance:slider-vertical; height: 100px; width: 30px" />
+    <input type=range list=foo style="writing-mode: vertical-lr; height: 100px; width: 30px" />
 </div>
 
 <datalist id=foo>
diff --git a/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-datalist.html b/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-datalist.html
index 737d34d..0cda815 100644
--- a/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-datalist.html
+++ b/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-datalist.html
@@ -1,7 +1,7 @@
 <input type=range list=foo value=10 />
 <input type=range list=foo style="width: 50px;" value=20 />
-<input type=range list=foo style="-webkit-appearance:slider-vertical;" value=40 />
-<input type=range list=foo style="-webkit-appearance:slider-vertical; height: 50px;" value=80 />
+<input type=range list=foo style="writing-mode: vertical-lr;" value=40 />
+<input type=range list=foo style="writing-mode: vertical-lr; height: 50px;" value=80 />
 <datalist id=foo>
     <option>0</option>
     <option>10</option>
diff --git a/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-padding-with-datalist.html b/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-padding-with-datalist.html
index c90d152..f2479df 100644
--- a/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-padding-with-datalist.html
+++ b/third_party/blink/web_tests/fast/forms/datalist/input-appearance-range-with-padding-with-datalist.html
@@ -5,8 +5,8 @@
 <p id="description">Tests if tick marks are drawn in the correct positions even when the element has padding. <a href="https://bugs.webkit.org/show_bug.cgi?id=93791">Bug 93791</a></p>
 <input type=range list=foo style="width: 200px; padding: 0 40px;" value=20 />
 <input type=range list=foo dir=rtl style="width: 200px; padding: 0 40px;" value=20 />
-<input type=range list=foo style="-webkit-appearance:slider-vertical; width: 20px; height: 200px; padding: 40px 0;" value=20 />
-<input type=range list=foo dir=rtl style="-webkit-appearance:slider-vertical; width: 20px; height: 200px; padding: 40px 0;" value=20 />
+<input type=range list=foo style="writing-mode: vertical-lr; width: 20px; height: 200px; padding: 40px 0;" value=20 />
+<input type=range list=foo dir=rtl style="writing-mode: vertical-lr; width: 20px; height: 200px; padding: 40px 0;" value=20 />
 <datalist id=foo>
     <option>0</option>
     <option>10</option>
diff --git a/third_party/blink/web_tests/fast/forms/datalist/slider-appearance-with-ticks-crash.html b/third_party/blink/web_tests/fast/forms/datalist/slider-appearance-with-ticks-crash.html
index e0154a5..ca164120 100644
--- a/third_party/blink/web_tests/fast/forms/datalist/slider-appearance-with-ticks-crash.html
+++ b/third_party/blink/web_tests/fast/forms/datalist/slider-appearance-with-ticks-crash.html
@@ -6,8 +6,8 @@
     testRunner.dumpAsText();
 </script>
 <p>No crash means test PASS.</p>
-<input type="text" list="foo" style="-webkit-appearance: slider-vertical">
-<input type="text" list="foo" style="-webkit-appearance: slider-horizontal">
+<input type="text" list="foo" style="writing-mode: vertical-lr">
+<input type="text" list="foo" style="writing-mode: horizontal-tb">
 <datalist id="foo">
     <option>1</option>
 </datalist>
diff --git a/third_party/blink/web_tests/fast/forms/range/input-appearance-range-rtl.html b/third_party/blink/web_tests/fast/forms/range/input-appearance-range-rtl.html
index 71f0f014..f26d4dd 100644
--- a/third_party/blink/web_tests/fast/forms/range/input-appearance-range-rtl.html
+++ b/third_party/blink/web_tests/fast/forms/range/input-appearance-range-rtl.html
@@ -9,7 +9,7 @@
 <div><input type=range value=100 id=r2></div>
 <div><input type=range value=0 id=r3 dir=rtl></div>
 <div><input type=range value=0 id=r4 style="direction:rtl"></div>
-<div><input type=range style="-webkit-appearance:slider-vertical; height:140px;" value=80 dir=rtl></div>
+<div><input type=range style="writing-mode:vertical-lr; height:140px;" value=80 dir=rtl></div>
 <script>
 document.getElementById('r1').dir = 'rtl';
 document.getElementById('r2').style.direction = 'rtl';
diff --git a/third_party/blink/web_tests/fast/forms/range/input-appearance-range.html b/third_party/blink/web_tests/fast/forms/range/input-appearance-range.html
index ef774e2..1a08946 100644
--- a/third_party/blink/web_tests/fast/forms/range/input-appearance-range.html
+++ b/third_party/blink/web_tests/fast/forms/range/input-appearance-range.html
@@ -12,7 +12,7 @@
 <div><input type=range value=0 min=0 max=100></div>
 <div><input type=range value=110 min=0 max=100></div>
 
-<div><input type=range style="-webkit-appearance:slider-vertical; height:140px; margin-left:64px"></div>
+<div><input type=range style="writing-mode:vertical-lr; height:140px; margin-left:64px"></div>
 
 <div><input type=range value=75 style="transform: rotate(30deg)"></div>
 
diff --git a/third_party/blink/web_tests/fast/forms/range/range-appearance-border-padding.html b/third_party/blink/web_tests/fast/forms/range/range-appearance-border-padding.html
index 51c300c..d401244f 100644
--- a/third_party/blink/web_tests/fast/forms/range/range-appearance-border-padding.html
+++ b/third_party/blink/web_tests/fast/forms/range/range-appearance-border-padding.html
@@ -6,7 +6,7 @@
   <li>Range value=50 with padding: <input type="range" min="0" max="100" value="50" style="padding:20px" /> </li>
   <li>Range value=30 with padding-left: <input type="range" min="0" max="100" value="30" style="padding-left:20px" /> </li>
   <li>Range value=50 with border and padding: <input type="range" min="0" max="100" value="50" style="border: 15px solid blue; padding:20px" /> </li>
-  <li>Range vertical value=50 with border and padding: <input type="range" min="0" max="100" value="50" style="border: 15px solid blue; padding:20px; -webkit-appearance: slider-vertical" /> </li>
+  <li>Range vertical value=50 with border and padding: <input type="range" min="0" max="100" value="50" style="border: 15px solid blue; padding:20px; writing-mode: vertical-lr" /> </li>
   <li>Range RTL value=30: <input type="range" min="0" max="100" value="30" style="direction: rtl" /> </li>
   <li>Range RTL value=80 with border and padding: <input type="range" min="0" max="100" value="80" style="border: 15px solid blue; padding:20px; direction: rtl" /> </li>
 </ul>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/range/range-hit-test-with-padding.html b/third_party/blink/web_tests/fast/forms/range/range-hit-test-with-padding.html
index 62f914d..be5bf4b4c 100644
--- a/third_party/blink/web_tests/fast/forms/range/range-hit-test-with-padding.html
+++ b/third_party/blink/web_tests/fast/forms/range/range-hit-test-with-padding.html
@@ -8,8 +8,8 @@
 <div id="console"></div>
 <input id="ltr" type=range min=0 max=50 step=1 value="0" style="width: 100px; padding: 0 40px;">
 <input id="rtl" dir="rtl" type=range min=0 max=50 step=1 value="0" style="width: 100px; padding: 0 40px;">
-<input id="vertical_ltr" type=range min=0 max=50 step=1 value="0" style="-webkit-appearance:slider-vertical; width: 20px; height: 100px; padding: 40px 0;">
-<input id="vertical_rtl" dir="rtl" type=range min=0 max=50 step=1 value="0" style="-webkit-appearance:slider-vertical; width: 20px; height: 100px; padding: 40px 0;">
+<input id="vertical_ltr" type=range min=0 max=50 step=1 value="0" style="writing-mode: vertical-lr; width: 20px; height: 100px; padding: 40px 0;">
+<input id="vertical_rtl" dir="rtl" type=range min=0 max=50 step=1 value="0" style="writing-mode: vertical-lr; width: 20px; height: 100px; padding: 40px 0;">
 <script>
 function clickHorizontalSlider(input, offsetLeft) {
     var centerY = input.offsetTop + input.offsetHeight / 2;
diff --git a/third_party/blink/web_tests/fast/forms/range/range-keyoperation.html b/third_party/blink/web_tests/fast/forms/range/range-keyoperation.html
index d528254..8aa27aa 100644
--- a/third_party/blink/web_tests/fast/forms/range/range-keyoperation.html
+++ b/third_party/blink/web_tests/fast/forms/range/range-keyoperation.html
@@ -9,11 +9,11 @@
 
 <input type=range id=horiz-range min=0 max=100 value=50 onchange='handleChange()'>
 <input type=range id=horiz-range-rtl dir=rtl min=0 max=100 value=50 onchange='handleChange()'>
-<input type=range id=vert-range min=0 max=100 value=50 onchange='handleChange()' style='-webkit-appearance:slider-vertical;'>
-<input type=range id=vert-range-rtl dir=rtl min=0 max=100 value=50 onchange='handleChange()' style='-webkit-appearance:slider-vertical;'>
-<input type=range id=step-any min=0 max=200 value=100 step='any' onchange='handleChange()' style='-webkit-appearance:slider-vertical;'>
-<input type=range id=small-range min=0 max=10 value=6 step=3 onchange='handleChange()' style='-webkit-appearance:slider-vertical;'>
-<input type=range id=disabled disabled min=0 max=100 value=1 step=1 onchange='handleChange()' style='-webkit-appearance:slider-vertical;'>
+<input type=range id=vert-range min=0 max=100 value=50 onchange='handleChange()' style='writing-mode: vertical-lr;'>
+<input type=range id=vert-range-rtl dir=rtl min=0 max=100 value=50 onchange='handleChange()' style='writing-mode: vertical-lr;'>
+<input type=range id=step-any min=0 max=200 value=100 step='any' onchange='handleChange()' style='writing-mode: vertical-lr;'>
+<input type=range id=small-range min=0 max=10 value=6 step=3 onchange='handleChange()' style='writing-mode: vertical-lr;'>
+<input type=range id=disabled disabled min=0 max=100 value=1 step=1 onchange='handleChange()' style='writing-mode: vertical-lr;'>
 
 <script>
 
diff --git a/third_party/blink/web_tests/fast/forms/range/slider-vertical-no-shadow-root.html b/third_party/blink/web_tests/fast/forms/range/slider-horizontal-no-shadow-root.html
similarity index 100%
rename from third_party/blink/web_tests/fast/forms/range/slider-vertical-no-shadow-root.html
rename to third_party/blink/web_tests/fast/forms/range/slider-horizontal-no-shadow-root.html
diff --git a/third_party/blink/web_tests/fast/forms/range/slider-horizontal-to-vertical-expected.html b/third_party/blink/web_tests/fast/forms/range/slider-horizontal-to-vertical-expected.html
index 9aa155b..e212bbd1 100644
--- a/third_party/blink/web_tests/fast/forms/range/slider-horizontal-to-vertical-expected.html
+++ b/third_party/blink/web_tests/fast/forms/range/slider-horizontal-to-vertical-expected.html
@@ -1,3 +1,3 @@
 <!DOCTYPE html>
 <p>You should see a vertical slider with a matching thumb below.</p>
-<input type="range" style="-webkit-appearance:slider-vertical">
+<input type="range" style="writing-mode: vertical-lr">
diff --git a/third_party/blink/web_tests/fast/forms/range/slider-horizontal-to-vertical.html b/third_party/blink/web_tests/fast/forms/range/slider-horizontal-to-vertical.html
index ec626faa..53124de 100644
--- a/third_party/blink/web_tests/fast/forms/range/slider-horizontal-to-vertical.html
+++ b/third_party/blink/web_tests/fast/forms/range/slider-horizontal-to-vertical.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <style>
-  .horizontal { -webkit-appearance: slider-horizontal }
-  .vertical { -webkit-appearance: slider-vertical }
+  .horizontal { writing-mode: horizontal-tb }
+  .vertical { writing-mode: vertical-lr }
 </style>
 <p>You should see a vertical slider with a matching thumb below.</p>
 <input id="range" type="range" class="horizontal">
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/datalist/input-appearance-range-with-datalist-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
index 16ca306..73363f7 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
+++ b/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/range/input-appearance-range-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/range/input-appearance-range-expected.png
index 5c6ab69..39187af 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/range/input-appearance-range-expected.png
+++ b/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/range/input-appearance-range-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/editing/caret/caret-in-empty-block-in-multicol-expected.png b/third_party/blink/web_tests/platform/linux/editing/caret/caret-in-empty-block-in-multicol-expected.png
new file mode 100644
index 0000000..abb88655
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/editing/caret/caret-in-empty-block-in-multicol-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/editing/caret/caret-in-empty-block-in-multicol-rtl-expected.png b/third_party/blink/web_tests/platform/linux/editing/caret/caret-in-empty-block-in-multicol-rtl-expected.png
new file mode 100644
index 0000000..4c0206c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/editing/caret/caret-in-empty-block-in-multicol-rtl-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/range/range-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/range/range-appearance-basic-expected.png
index 1f91d60..ea869129 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/range/range-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
index e9cc46db..af70901 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
index 187b874..c14d9fb 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
index 8db7595..1403adab 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/range/range-appearance-border-padding-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/range/range-appearance-border-padding-expected.png
index 5c6d273..652ef2c 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/range/range-appearance-border-padding-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/range/range-appearance-border-padding-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png
index 6a38e35..5e83105 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png
index f2debfb..852b99f 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/editing/caret/caret-in-empty-block-in-multicol-expected.png b/third_party/blink/web_tests/platform/mac/editing/caret/caret-in-empty-block-in-multicol-expected.png
new file mode 100644
index 0000000..c19d5e8
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/editing/caret/caret-in-empty-block-in-multicol-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/editing/caret/caret-in-empty-block-in-multicol-rtl-expected.png b/third_party/blink/web_tests/platform/mac/editing/caret/caret-in-empty-block-in-multicol-rtl-expected.png
new file mode 100644
index 0000000..67f3f78b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/editing/caret/caret-in-empty-block-in-multicol-rtl-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/range/range-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/range/range-appearance-basic-expected.png
index 37f4feb..19e0511 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/range/range-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
index e362364f..5be75b2a 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
index 740262b..ad2dab9 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
index 346ee04..4d957e2 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/range/input-appearance-range-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/range/input-appearance-range-expected.png
index 441b8fd..3d504ba 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/range/input-appearance-range-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/range/input-appearance-range-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/range/input-appearance-range-rtl-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/range/input-appearance-range-rtl-expected.png
index bb5daddc..c59fbda5 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/range/input-appearance-range-rtl-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/range/input-appearance-range-rtl-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/range/range-appearance-border-padding-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/range/range-appearance-border-padding-expected.png
index a528e87f..c4d32cd 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/range/range-appearance-border-padding-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/range/range-appearance-border-padding-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png
index 97bb461..8fee0b3e 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png
index 1ce30873..261b68e64 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/editing/caret/caret-in-empty-block-in-multicol-expected.png b/third_party/blink/web_tests/platform/win/editing/caret/caret-in-empty-block-in-multicol-expected.png
new file mode 100644
index 0000000..abb88655
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/editing/caret/caret-in-empty-block-in-multicol-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/editing/caret/caret-in-empty-block-in-multicol-rtl-expected.png b/third_party/blink/web_tests/platform/win/editing/caret/caret-in-empty-block-in-multicol-rtl-expected.png
new file mode 100644
index 0000000..4c0206c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/editing/caret/caret-in-empty-block-in-multicol-rtl-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/range/range-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/range/range-appearance-basic-expected.png
index b7f21a8..a2448b11 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/range/range-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
index ca57c63..03d75a3 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
index 31a00a7d..3b7a67ce 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
index d675af3..5eb11b4ae 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-padding-with-datalist-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/range/input-appearance-range-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/range/input-appearance-range-expected.png
index f883d41..cc12546 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/range/input-appearance-range-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/range/input-appearance-range-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/range/input-appearance-range-rtl-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/range/input-appearance-range-rtl-expected.png
index 14c04bb..8eb94a7 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/range/input-appearance-range-rtl-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/range/input-appearance-range-rtl-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/range/range-appearance-border-padding-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/range/range-appearance-border-padding-expected.png
index ced5190..bb2227d 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/range/range-appearance-border-padding-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/range/range-appearance-border-padding-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png
index 3808097..73847c7 100644
--- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/fast/forms/color-scheme/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png
index 8ecab594..3e95692d 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-none.html b/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-none.html
deleted file mode 100644
index 6742c7ad..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-none.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/8174#issuecomment-1379258184">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/css/css-transitions/support/helper.js"></script>
-<div id="target"></div>
-<style>
-  #target {
-    transition-property: background-color;
-    transition-duration: 100s;
-    transition-timing-function: steps(2, start);
-    background-color: green;
-  }
-  #target:initial {
-    display: none;
-    background-color: red;
-  }
-</style>
-<script>
-  promise_test(async t => {
-    await waitForAnimationFrames(2);
-    assert_equals(getComputedStyle(target).backgroundColor, "rgb(0, 128, 0)",
-                  "No transition of background-color when :initial display is 'none'");
-  }, ":initial with display:none");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-basic.html b/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-basic.html
deleted file mode 100644
index c7ce813..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-basic.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/8174">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/css/css-transitions/support/helper.js"></script>
-<div id="target" class="trans"></div>
-<style>
-  #target {
-    transition-property: background-color, color;
-    transition-duration: 100s;
-    transition-timing-function: steps(2, start);
-    color: green;
-    background-color: white;
-  }
-  #target:initial {
-    background-color: black;
-  }
-  #target.red {
-    background-color: red;
-  }
-</style>
-<script>
-  promise_test(async t => {
-    await waitForAnimationFrames(2);
-    assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)",
-                  "No transition of color");
-    assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from :initial value black to white");
-  }, "Triggered transition from first style update");
-
-  promise_test(async t => {
-    target.style.display = "none";
-    target.className = "red";
-    assert_equals(getComputedStyle(target).backgroundColor, "rgb(255, 0, 0)",
-                  "Overridden with red. No transition while display:none");
-    target.className = "";
-    assert_equals(getComputedStyle(target).backgroundColor, "rgb(255, 255, 255)",
-                  "Removing class while display:none. Still no transition");
-    await waitForAnimationFrames(2);
-    target.style.display = "block";
-    await waitForAnimationFrames(2);
-    assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from :initial value black to white");
-  }, "Triggered transition from display:none to display:block");
-
-  promise_test(async t => {
-    let removed = target;
-    removed.remove();
-    await waitForAnimationFrames(2);
-    document.body.appendChild(removed);
-    await waitForAnimationFrames(2);
-    assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from :initial value black to white");
-  }, "Triggered transition on DOM insertion");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-elements.html b/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-elements.html
deleted file mode 100644
index e6d873b0..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-elements.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/8174">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/css/css-transitions/support/helper.js"></script>
-<div id="target" class="trans"></div>
-<style>
-  #target::before {
-    transition-property: background-color, color;
-    transition-duration: 100s;
-    transition-timing-function: steps(2, start);
-    color: green;
-    background-color: white;
-    content: "";
-  }
-  #target::before:initial {
-    background-color: black;
-  }
-  #target.red::before {
-    background-color: red;
-  }
-</style>
-<script>
-  promise_test(async t => {
-    await waitForAnimationFrames(2);
-    assert_equals(getComputedStyle(target, "::before").color, "rgb(0, 128, 0)",
-                  "No transition of color");
-    assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from :initial value black to white");
-  }, "Triggered transition from first style update");
-
-  promise_test(async t => {
-    target.style.display = "none";
-    target.className = "red";
-    assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(255, 0, 0)",
-                  "Overridden with red. No transition while display:none");
-    target.className = "";
-    assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(255, 255, 255)",
-                  "Removing class while display:none. Still no transition");
-    await waitForAnimationFrames(2);
-    target.style.display = "block";
-    await waitForAnimationFrames(2);
-    assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from :initial value black to white");
-  }, "Triggered transition from display:none to display:block");
-
-  promise_test(async t => {
-    let removed = target;
-    removed.remove();
-    await waitForAnimationFrames(2);
-    document.body.appendChild(removed);
-    await waitForAnimationFrames(2);
-    assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(128, 128, 128)",
-                  "Background transition from :initial value black to white");
-  }, "Triggered transition on DOM insertion");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-non-matching.html b/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-non-matching.html
deleted file mode 100644
index 59ca87a..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-non-matching.html
+++ /dev/null
@@ -1,66 +0,0 @@
-<!DOCTYPE html>
-<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/8174">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<style>
-  #t1:not(:initial) { color: green; }
-  :not(:initial) > #t1 { background-color: green; }
-
-  .none { display: none; }
-
-  .none:not(:initial) + #t2 { color: green; }
-  :not(:initial) + div + #t2 { background-color: green; }
-
-  #t3 { color: green; transition: color 100s step-end; }
-  #t3:is(:initial) { color: red; }
-  #t3:where(:initial) { color: red; }
-  #t3:not(:not(:initial)) { color: red; }
-
-  #t4 { color: green; transition: color 100s step-end; }
-  :initial #t4 { color: red; }
-
-  #t5 { color: green; transition: color 100s step-end; }
-  .none:initial + #t5 { color: red; }
-</style>
-<div id="t1"></div>
-<div>
-  <div></div>
-  <div class="none"></div>
-  <div id="t2"></div>
-</div>
-<div id="t3"></div>
-<div id="t4"></div>
-<div>
-  <div class="none"></div>
-  <div id="t5"></div>
-</div>
-<script>
-  const green = "rgb(0, 128, 0)";
-
-  test(() => {
-    const t1_style = getComputedStyle(t1);
-    assert_equals(t1_style.color, green);
-    assert_equals(t1_style.backgroundColor, green);
-  }, ":not(:initial) matching");
-
-  test(() => {
-    const t2_style = getComputedStyle(t2);
-    assert_equals(t2_style.color, green);
-    assert_equals(t2_style.backgroundColor, green);
-  }, ":initial not matching on previous siblings");
-
-  test(() => {
-    const t3_style = getComputedStyle(t3);
-    assert_equals(t3_style.color, green);
-  }, ":initial not matching inside :is/:where/:not");
-
-  test(() => {
-    const t4_style = getComputedStyle(t4);
-    assert_equals(t4_style.color, green);
-  }, ":initial not matching ancestor");
-
-  test(() => {
-    const t5_style = getComputedStyle(t5);
-    assert_equals(t5_style.color, green);
-  }, ":initial not matching sibling");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-parsing.html b/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-parsing.html
deleted file mode 100644
index 28ced41..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-transitions/initial-pseudo-parsing.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<title>CSS Transitions: Parsing tests for :initial pseudo class</title>
-<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/8174">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/css/support/parsing-testcommon.js"></script>
-<script>
-  // Valid selectors that will match.
-  test_valid_selector(":initial");
-  test_valid_selector("div:initial#id");
-  test_valid_selector("div + :initial");
-
-  // Valid selectors that parse, but will never match.
-  test_valid_selector("div:initial span");
-  test_valid_selector(":is(:initial)");
-  test_valid_selector(":where(:hover, :initial)");
-  test_valid_selector(":is(:is(div, :initial), :has(:initial))");
-  test_valid_selector(":nth-child(2n+1 of :initial)");
-
-  // Typographic pseudo elements.
-  test_invalid_selector("::first-line:initial");
-  test_invalid_selector("::first-letter:initial");
-  test_invalid_selector("::prefix:initial");
-  test_invalid_selector("::postfix:initial");
-
-  // Highlight pseudo elements.
-  test_invalid_selector("::selection:initial");
-  test_invalid_selector("::target-text:initial");
-  test_invalid_selector("::spelling-error:initial");
-  test_invalid_selector("::grammar-error:initial");
-
-  // Tree-abiding pseudo elements
-  test_valid_selector("::before:initial");
-  test_valid_selector("::after:initial");
-  test_valid_selector("::marker:initial");
-  test_valid_selector("::placeholder:initial");
-  test_valid_selector("::file-selector-button:initial");
-
-  // Shadow pseudo elements.
-  test_valid_selector("::part(part):initial");
-  test_valid_selector("::slotted(:initial)");
-  test_invalid_selector("::slotted(*):initial");
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/autoplay.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/autoplay.https.html.ini
new file mode 100644
index 0000000..5b23c2b3
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/autoplay.https.html.ini
@@ -0,0 +1,3 @@
+[autoplay.https.html]
+  [If Autoplay plocy is set to 'user-gesture-required', autoplaying  should be blocked in a fenced frame as it's treated like a cross-origin subframe.]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/maxframes.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/maxframes.https.html.ini
new file mode 100644
index 0000000..160624d8
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/maxframes.https.html.ini
@@ -0,0 +1,3 @@
+[maxframes.https.html]
+  [Max Subframes Test]
+    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus-last-element.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus-last-element.https.html.ini
new file mode 100644
index 0000000..0ab8edb
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus-last-element.https.html.ini
@@ -0,0 +1,4 @@
+[tab-focus-last-element.https.html]
+  [Tab focus last element]
+    expected:
+      if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus.https.html.ini
new file mode 100644
index 0000000..9b55cc6
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus.https.html.ini
@@ -0,0 +1,4 @@
+[tab-focus.https.html]
+  [Tab focus]
+    expected:
+      if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/unfenced-top.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/unfenced-top.https.html.ini
new file mode 100644
index 0000000..b5efb09
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/unfenced-top.https.html.ini
@@ -0,0 +1,32 @@
+[unfenced-top.https.html]
+  [_unfencedTop :blob URL failure]
+    expected:
+      if product == "chrome": FAIL
+
+  [_unfencedTop :javascript URL failure]
+    expected:
+      if product == "chrome": FAIL
+
+  [_unfencedTop fragment navigation]
+    expected:
+      if product == "chrome": FAIL
+
+  [_unfencedTop in default fenced frame]
+    expected:
+      if product == "chrome": FAIL
+
+  [_unfencedTop in opaque-ads -> default fenced frame]
+    expected:
+      if product == "chrome": FAIL
+
+  [_unfencedTop opaque-ads nested iframe success case]
+    expected:
+      if product == "chrome": FAIL
+
+  [_unfencedTop opaque-ads non-refresh success case]
+    expected:
+      if product == "chrome": FAIL
+
+  [_unfencedTop opaque-ads refresh success case]
+    expected:
+      if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/presentation/resources/presentation-service-mock.js b/third_party/blink/web_tests/wpt_internal/presentation/resources/presentation-service-mock.js
index a75cd77..4950756 100644
--- a/third_party/blink/web_tests/wpt_internal/presentation/resources/presentation-service-mock.js
+++ b/third_party/blink/web_tests/wpt_internal/presentation/resources/presentation-service-mock.js
@@ -106,9 +106,11 @@
     }
 
     console.log('onReceiverConnectionAvailable: ' + mojoUrl + ',' + id);
-    this.receiver_.onReceiverConnectionAvailable(
-        { url: mojoUrl, id: id },
-        controllerConnectionPtr, receiverConnectionRequest);
+    this.receiver_.onReceiverConnectionAvailable({
+      presentationInfo: {url: mojoUrl, id: id},
+      connectionRemote: controllerConnectionPtr,
+      connectionReceiver: receiverConnectionRequest,
+    });
     console.log('after onReceiverConnectionAvailable');
   }
 
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium
index 8605145a..0c9ea83f 100644
--- a/third_party/nearby/README.chromium
+++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@
 Name: Nearby Connections Library
 Short Name: Nearby
 URL: https://github.com/google/nearby
-Version: e4c1f9aa240fb016c08964af11f7232d9cbce62d
+Version: db308775d2dfb6e1bf49d666acbf92b516effe52
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/opus/BUILD.gn b/third_party/opus/BUILD.gn
index 11287cc..6c517fa 100644
--- a/third_party/opus/BUILD.gn
+++ b/third_party/opus/BUILD.gn
@@ -11,7 +11,7 @@
 # If ARM optimizations shall be used to accelerate performance.
 # TODO(scottmg): Disabled on Fuchsia for now, see https://crbug.com/775272.
 use_opus_arm_optimization =
-    current_cpu == "arm" || (current_cpu == "arm64" && is_ios)
+    current_cpu == "arm" || (current_cpu == "arm64" && (is_ios || is_win))
 
 # NaCl, unlike Chrome, doesn't target SSE2 minimum, so skip optimizations for
 # the sake of simplicity.
diff --git a/third_party/snappy/README.chromium b/third_party/snappy/README.chromium
index 896f2aaa..3bb5d9fd 100644
--- a/third_party/snappy/README.chromium
+++ b/third_party/snappy/README.chromium
@@ -1,8 +1,8 @@
 Name: Snappy: A fast compressor/decompressor
 Short Name: snappy
 URL: http://google.github.io/snappy/
-Version: 1.1.7.git.3f194acb57e0487531c96b97af61dcbd025a78a3
-CPEPrefix: cpe:/a:google:snappy:1.1.7
+Version: 1.1.10.git.c9f9edf6d75bb065fa47468bf035e051a57bec7c
+CPEPrefix: cpe:/a:google:snappy:1.1.10
 License: New BSD
 License File: src/COPYING
 Security Critical: yes
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index 2dc9323..62cde967 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -682,7 +682,7 @@
   cxxflags = []
   ldflags = []
 
-  targets = 'AArch64;ARM;Mips;PowerPC;RISCV;SystemZ;WebAssembly;X86'
+  targets = 'AArch64;ARM;LoongArch;Mips;PowerPC;RISCV;SystemZ;WebAssembly;X86'
   projects = 'clang;lld;clang-tools-extra'
   if args.bolt:
     projects += ';bolt'
@@ -1048,6 +1048,9 @@
     elif platform.machine() == 'riscv64':
       cmake_args.append(
           '-DLLVM_DEFAULT_TARGET_TRIPLE=riscv64-unknown-linux-gnu')
+    elif platform.machine() == 'loongarch64':
+      cmake_args.append(
+          '-DLLVM_DEFAULT_TARGET_TRIPLE=loongarch64-unknown-linux-gnu')
     else:
       cmake_args.append('-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-unknown-linux-gnu')
     cmake_args.append('-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON')
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index c863434..89ad0ec 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -36,7 +36,7 @@
 # Reverting problematic clang rolls is safe, though.
 # This is the output of `git describe` and is usable as a commit-ish.
 CLANG_REVISION = 'llvmorg-17-init-8029-g27f27d15'
-CLANG_SUB_REVISION = 1
+CLANG_SUB_REVISION = 3
 
 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION)
 RELEASE_VERSION = '17'
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index b5375e41..52654e5 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -241,6 +241,7 @@
       'android-code-coverage': 'gpu_tests_android_release_bot_minimal_symbols_arm64_fastbuild_java_coverage_reclient',
       'android-code-coverage-native': 'gpu_tests_android_release_bot_no_symbols_arm64_fastbuild_native_coverage_reclient',
       'android-x86-code-coverage': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_reclient_coverage',
+      'chromeos-js-code-coverage': 'js_coverage_reclient',
       'fuchsia-code-coverage': 'fuchsia_clang_code_coverage_reclient',
       'ios-simulator-code-coverage': 'clang_code_coverage_ios_xctest_reclient',
       'linux-chromeos-code-coverage': 'chromeos_with_codecs_release_bot_coverage_reclient',
@@ -401,6 +402,7 @@
       'Win x64 Builder (reclient)': 'gpu_tests_release_bot_minimal_symbols_reclient',
       'android-backuprefptr-arm-fyi-rel': 'release_trybot_backuprefptr_arm_reclient',
       'android-backuprefptr-arm64-fyi-rel': 'release_trybot_backuprefptr_arm64_reclient',
+      'android-build-perf-developer': 'android_developer',
       'android-fieldtrial-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_reclient',
       'android-perfetto-rel': 'perfetto_release_bot_reclient_android',
       # Keep in sync with android-arm64-rel
@@ -449,6 +451,7 @@
       'linux-blink-heap-concurrent-marking-tsan-rel': 'release_trybot_minimal_symbols_tsan',
       'linux-blink-heap-verification': 'release_bot_enable_blink_heap_verification_dcheck_always_on_reclient',
       'linux-blink-wpt-reset-rel': 'release_bot_blink_minimal_symbols_reclient',
+      'linux-build-perf-developer': 'developer',
       'linux-chromeos-annotator-rel': 'chromeos_with_codecs_release_bot_reclient',
       'linux-fieldtrial-rel': 'release_bot_minimal_symbols_reclient',
       'linux-headless-shell-rel': 'headless_shell_release_bot_reclient',
@@ -482,6 +485,7 @@
       'win-annotator-rel': 'release_bot_reclient',
       'win-backuprefptr-x64-fyi-rel': 'release_trybot_backuprefptr_x64_reclient',
       'win-backuprefptr-x86-fyi-rel': 'release_trybot_backuprefptr_x86_reclient',
+      'win-build-perf-developer': 'developer',
       'win-celab-builder-rel': 'release_bot_minimal_symbols_reclient',
       'win-fieldtrial-rel': 'release_bot_minimal_symbols_reclient',
       'win-perfetto-rel': 'perfetto_release_bot_reclient',
@@ -1186,6 +1190,7 @@
 
     'tryserver.chromium.linux': {
       'cast-binary-size': 'cast_binary_size',
+      'chromeos-js-code-coverage': 'js_coverage_reclient',
       'chromium_presubmit': 'presubmit',
       'gpu-fyi-try-lacros-amd-rel': 'gpu_tests_ozone_linux_non_x11_release_trybot_reclient',
       'gpu-fyi-try-lacros-intel-rel': 'gpu_tests_ozone_linux_non_x11_release_trybot_reclient',
@@ -1649,6 +1654,11 @@
       'android', 'debug_bot_reclient', 'x64', 'webview_trichrome', 'webview_shell',
     ],
 
+    # GN args to simulate Android developer builds.
+    'android_developer': [
+      'android_developer',
+    ],
+
     'android_official_optimize_reclient': [
       'official_optimize_reclient', 'android_without_codecs',
     ],
@@ -2594,6 +2604,10 @@
       'debug_bot_reclient', 'x86',
     ],
 
+    'developer': [
+      'developer',
+    ],
+
     'fuchsia_clang_code_coverage_reclient': [
       'clang', 'fuchsia', 'fuchsia_code_coverage', 'no_symbols', 'release_bot_reclient',
       'use_clang_coverage',
@@ -3765,6 +3779,12 @@
       'mixins': ['android_without_codecs', 'chrome_with_codecs'],
     },
 
+    # Representative GN args for Android developer builds.
+    'android_developer': {
+      'gn_args': 'target_os="android"',
+      'mixins': ['arm64', 'developer'],
+    },
+
     'android_external': {
       'gn_args': 'enable_chrome_android_internal=false',
     },
@@ -4134,6 +4154,11 @@
       'mixins': ['debug', 'static', 'minimal_symbols', 'reclient'],
     },
 
+    # Representative GN args for developer builds.
+    'developer': {
+      'mixins': ['debug', 'full_symbols', 'disable_nacl', 'shared'],
+    },
+
     'devtools_do_typecheck': {
       'gn_args': 'devtools_skip_typecheck=false',
     },
diff --git a/tools/mb/mb_config_expectations/chromium.coverage.json b/tools/mb/mb_config_expectations/chromium.coverage.json
index af3727f6..cd4adf3 100644
--- a/tools/mb/mb_config_expectations/chromium.coverage.json
+++ b/tools/mb/mb_config_expectations/chromium.coverage.json
@@ -57,6 +57,19 @@
       "use_remoteexec": true
     }
   },
+  "chromeos-js-code-coverage": {
+    "gn_args": {
+      "dcheck_always_on": false,
+      "enable_webui_inline_sourcemaps": true,
+      "is_clang": true,
+      "is_component_build": false,
+      "is_debug": false,
+      "optimize_webui": false,
+      "symbol_level": 0,
+      "use_javascript_coverage": true,
+      "use_remoteexec": true
+    }
+  },
   "fuchsia-code-coverage": {
     "gn_args": {
       "dcheck_always_on": false,
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 252b180..72737af 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -407,6 +407,16 @@
       "use_remoteexec": true
     }
   },
+  "android-build-perf-developer": {
+    "gn_args": {
+      "enable_nacl": false,
+      "is_component_build": true,
+      "is_debug": true,
+      "symbol_level": 2,
+      "target_cpu": "arm64",
+      "target_os": "android"
+    }
+  },
   "android-fieldtrial-rel": {
     "gn_args": {
       "android_static_analysis": "off",
@@ -958,6 +968,14 @@
       "use_remoteexec": true
     }
   },
+  "linux-build-perf-developer": {
+    "gn_args": {
+      "enable_nacl": false,
+      "is_component_build": true,
+      "is_debug": true,
+      "symbol_level": 2
+    }
+  },
   "linux-chromeos-annotator-rel": {
     "gn_args": {
       "dcheck_always_on": false,
@@ -1300,6 +1318,14 @@
       "use_remoteexec": true
     }
   },
+  "win-build-perf-developer": {
+    "gn_args": {
+      "enable_nacl": false,
+      "is_component_build": true,
+      "is_debug": true,
+      "symbol_level": 2
+    }
+  },
   "win-celab-builder-rel": {
     "gn_args": {
       "dcheck_always_on": false,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
index 639b5a8..405fb55 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
@@ -10,6 +10,19 @@
       "use_goma": true
     }
   },
+  "chromeos-js-code-coverage": {
+    "gn_args": {
+      "dcheck_always_on": false,
+      "enable_webui_inline_sourcemaps": true,
+      "is_clang": true,
+      "is_component_build": false,
+      "is_debug": false,
+      "optimize_webui": false,
+      "symbol_level": 0,
+      "use_javascript_coverage": true,
+      "use_remoteexec": true
+    }
+  },
   "gpu-fyi-try-lacros-amd-rel": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 99dcad4..9018ca44 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -13625,6 +13625,13 @@
   <int value="1" label="Zip has AES"/>
 </enum>
 
+<enum name="BootlockboxAvailability">
+  <int value="0" label="Available"/>
+  <int value="1" label="Write Locked"/>
+  <int value="2" label="Need Power Wash"/>
+  <int value="3" label="Unknown"/>
+</enum>
+
 <enum name="BorealisInstallResult">
   <int value="0" label="Success"/>
   <int value="1" label="User cancelled installation"/>
@@ -18089,6 +18096,25 @@
   <int value="3" label="Header set by client code"/>
 </enum>
 
+<enum name="Companion.PromoEvent">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="SignIn.Shown"/>
+  <int value="2" label="SignIn.Accepted"/>
+  <int value="3" label="SignIn.Rejected"/>
+  <int value="4" label="Msbb.Shown"/>
+  <int value="5" label="Msbb.Accepted"/>
+  <int value="6" label="Msbb.Rejected"/>
+  <int value="7" label="Exps.Shown"/>
+  <int value="8" label="Exps.Accepted"/>
+  <int value="9" label="Exps.Rejected"/>
+</enum>
+
+<enum name="Companion.UiEvent">
+  <int value="1" label="Not vailable"/>
+  <int value="2" label="Shown"/>
+  <int value="3" label="Clicked"/>
+</enum>
+
 <enum name="CompanionLibraryApisList">
 <!-- Value from components/arc/mojom/metrics.mojom -->
 
@@ -19632,6 +19658,8 @@
 <enum name="ConversionAttributionSupport">
   <int value="0" label="Web"/>
   <int value="1" label="Web and OS"/>
+  <int value="2" label="OS"/>
+  <int value="3" label="None"/>
 </enum>
 
 <enum name="ConversionCreateAggregatableReportStatus">
@@ -25694,6 +25722,20 @@
   <int value="1" label="New key accelerator is used"/>
 </enum>
 
+<enum name="DeprecatedWindowSnapActionSource">
+  <int value="0" label="Drag window to screen edge to snap"/>
+  <int value="1" label="Use window caption button to snap"/>
+  <int value="2" label="Use keyboard shortcut to snap"/>
+  <int value="3" label="Drag or select overview window to snap"/>
+  <int value="4" label="Long press overview button to snap"/>
+  <int value="5" label="Drag up from shelf to snap"/>
+  <int value="6" label="Drag down from top to snap"/>
+  <int value="7" label="Drag a tab to snap"/>
+  <int value="8" label="Auto snapped by splitview"/>
+  <int value="9" label="Window is snapped from window state restore"/>
+  <int value="10" label="Other ways to snap a window"/>
+</enum>
+
 <enum name="DeprecateStylusFeaturesToastEvent">
   <obsolete>
     Deprecated in M111.
@@ -58324,6 +58366,7 @@
   <int value="-2041091005" label="OmniboxDomainSuggestions:enabled"/>
   <int value="-2040471724" label="CrOSComponent:disabled"/>
   <int value="-2040360427" label="DesktopScreenshots:disabled"/>
+  <int value="-2040154722" label="TimeOfDayScreenSaver:enabled"/>
   <int value="-2040115518" label="load-media-router-component-extension"/>
   <int value="-2039971160" label="UseNAT64ForIPv4Literal:enabled"/>
   <int value="-2039439354"
@@ -59200,8 +59243,6 @@
   <int value="-1583533050" label="RuntimeHostPermissions:disabled"/>
   <int value="-1581969217" label="enable-switch-access-point-scanning"/>
   <int value="-1581724231" label="ModalPermissionPrompts:enabled"/>
-  <int value="-1581034742"
-      label="FeatureManagementTimeOfDayScreenSaver:enabled"/>
   <int value="-1580376019" label="ShowAllDialogsWithViewsToolkit:enabled"/>
   <int value="-1578781240" label="QuickAnswersV2:enabled"/>
   <int value="-1578677451" label="EnableAppGridGhost:disabled"/>
@@ -61068,8 +61109,6 @@
   <int value="-599932554" label="DoodlesOnLocalNtp:disabled"/>
   <int value="-599878733" label="ContextualTriggersSelectionHandles:disabled"/>
   <int value="-599005750" label="ScanningUI:disabled"/>
-  <int value="-598628987"
-      label="FeatureManagementTimeOfDayScreenSaver:disabled"/>
   <int value="-598191408" label="OmniboxKeywordSpaceTriggeringSetting:enabled"/>
   <int value="-598050737" label="disable-es3-apis"/>
   <int value="-596822155" label="AppManagementIntentSettings:enabled"/>
@@ -61750,6 +61789,7 @@
   <int value="-222282965"
       label="disable_idle_sockets_close_on_memory_pressure:enabled"/>
   <int value="-221649438" label="AllowTouchpadHapticClickSettings:disabled"/>
+  <int value="-220829663" label="TimeOfDayScreenSaver:disabled"/>
   <int value="-220599034" label="UsePdfCompositorServiceForPrint:enabled"/>
   <int value="-220298483" label="ImeOptionsInSettings:enabled"/>
   <int value="-218843425" label="auto-framing-override"/>
@@ -61970,6 +62010,7 @@
   <int value="-97145978" label="DesktopPWAsStayInWindow:enabled"/>
   <int value="-96820962"
       label="ExperimentalAccessibilitySelectToSpeakVoiceSwitching:enabled"/>
+  <int value="-94535722" label="TimeOfDayWallpaper:enabled"/>
   <int value="-94335249" label="UseAAudioDriver:enabled"/>
   <int value="-93619449" label="video-tutorials-instant-fetch"/>
   <int value="-92116820" label="InlineUpdateFlow:enabled"/>
@@ -63433,7 +63474,6 @@
   <int value="690185633" label="NonValidatingReloadOnNormalReload:disabled"/>
   <int value="691020108" label="NTPCondensedTileLayout:disabled"/>
   <int value="691982483" label="WifiConnectMacAddressRandomization:disabled"/>
-  <int value="692775563" label="FeatureManagementTimeOfDayWallpaper:enabled"/>
   <int value="693012666" label="QuickUnlockPin:disabled"/>
   <int value="693480759" label="PageInfoAboutThisSiteEn:disabled"/>
   <int value="693545401"
@@ -63816,7 +63856,6 @@
   <int value="899347105" label="NearbySharingWifiLan:enabled"/>
   <int value="900614020" label="ContentSuggestionsShowSummary:disabled"/>
   <int value="902209599" label="ShelfHotseat:enabled"/>
-  <int value="902442795" label="time-before-discard-in-minutes"/>
   <int value="902649149" label="ArcGhostWindowNewStyle:enabled"/>
   <int value="902839593" label="WebContentsForceDark:disabled"/>
   <int value="903267263" label="disable-offline-pages"/>
@@ -64432,7 +64471,6 @@
   <int value="1235940786" label="ChromeHomePersistentIph:enabled"/>
   <int value="1236772382" label="BiometricAuthenticationInSettings:disabled"/>
   <int value="1237297772" label="no-pings"/>
-  <int value="1237444391" label="FeatureManagementTimeOfDayWallpaper:disabled"/>
   <int value="1237574783" label="SyncAccessHandleAllSyncSurface:enabled"/>
   <int value="1237659269"
       label="OmniboxHistoryQuickProviderAllowButDoNotScoreMidwordTerms:enabled"/>
@@ -65054,6 +65092,7 @@
   <int value="1586251544" label="VoiceButtonInTopToolbar:disabled"/>
   <int value="1586476635" label="LargeFaviconFromGoogle:enabled"/>
   <int value="1587521886" label="SSLCommittedInterstitials:enabled"/>
+  <int value="1587972722" label="TimeOfDayWallpaper:disabled"/>
   <int value="1588716465" label="CrostiniUseLxd4:disabled"/>
   <int value="1589341623" label="disable-easy-unlock"/>
   <int value="1590278995"
@@ -77554,7 +77593,6 @@
   <int value="7" label="Vpn Details"/>
   <int value="8" label="APN"/>
   <int value="9" label="Hotspot Details"/>
-  <int value="10" label="Passpoint Details"/>
   <int value="100" label="Bluetooth Devices"/>
   <int value="101" label="Bluetooth Device Details"/>
   <int value="102" label="Bluetooth Saved Devices"/>
@@ -78149,6 +78187,7 @@
   <int value="7" label="Three fingers swiping up on the trackpad"/>
   <int value="8" label="Entering overview through dev tools"/>
   <int value="9" label="Entering overview in tests"/>
+  <int value="11" label="Entering overview via desk button on shelf"/>
 </enum>
 
 <enum name="OwnerKeyUmaEvent">
@@ -92944,6 +92983,7 @@
   <int value="18" label="ContextualPageActions"/>
   <int value="23" label="SearchUserSegment"/>
   <int value="28" label="AdaptiveToolbar"/>
+  <int value="31" label="WebAppInstallationPromo"/>
 </enum>
 
 <enum name="SegmentationPlatformTrainingDataCollectionEvent">
@@ -111458,17 +111498,24 @@
 </enum>
 
 <enum name="WindowSnapActionSource">
-  <int value="0" label="Drag window to screen edge to snap"/>
-  <int value="1" label="Use window caption button to snap"/>
-  <int value="2" label="Use keyboard shortcut to snap"/>
-  <int value="3" label="Drag or select overview window to snap"/>
-  <int value="4" label="Long press overview button to snap"/>
-  <int value="5" label="Drag up from shelf to snap"/>
-  <int value="6" label="Drag down from top to snap"/>
-  <int value="7" label="Drag a tab to snap"/>
-  <int value="8" label="Auto snapped by splitview"/>
-  <int value="9" label="Window is snapped from window state restore"/>
-  <int value="10" label="Other ways to snap a window"/>
+  <int value="0" label="Not specified"/>
+  <int value="1" label="Drag window to screen edge to snap"/>
+  <int value="2" label="Use window caption button to snap"/>
+  <int value="3" label="Use keyboard shortcut to snap"/>
+  <int value="4" label="Drag or select overview window to snap"/>
+  <int value="5" label="Long press overview button to snap"/>
+  <int value="6" label="Drag up from shelf to snap"/>
+  <int value="7" label="Drag down from top to snap"/>
+  <int value="8" label="Drag a tab to snap"/>
+  <int value="9" label="Auto snapped in split screen"/>
+  <int value="10" label="Window is snapped from window state restore"/>
+  <int value="11" label="Window is snapped by the window layout menu"/>
+  <int value="12"
+      label="Window is snapped by full restore or desk template or saved desk
+             launch"/>
+  <int value="13"
+      label="Window is snapped due to tablet and clamshell transition"/>
+  <int value="14" label="Window is snapped due to desk or session change"/>
 </enum>
 
 <enum name="WindowsNotificationActivationStatus">
@@ -113117,6 +113164,7 @@
   <int value="56" label="Menu opened"/>
   <int value="57" label="Visited Chrome Web Store via extensions sub menu."/>
   <int value="58" label="Password Manager"/>
+  <int value="59" label="Translate Page"/>
 </enum>
 
 <enum name="WrongConfigurationMetric">
diff --git a/tools/metrics/histograms/histograms_index.txt b/tools/metrics/histograms/histograms_index.txt
index d48203b..e11b4020 100644
--- a/tools/metrics/histograms/histograms_index.txt
+++ b/tools/metrics/histograms/histograms_index.txt
@@ -23,6 +23,7 @@
 tools/metrics/histograms/metadata/chromeos_hps/histograms.xml
 tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
 tools/metrics/histograms/metadata/commerce/histograms.xml
+tools/metrics/histograms/metadata/companion/histograms.xml
 tools/metrics/histograms/metadata/compositing/histograms.xml
 tools/metrics/histograms/metadata/content/histograms.xml
 tools/metrics/histograms/metadata/content_creation/histograms.xml
diff --git a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
index 633e3af..0ad29ae 100644
--- a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
+++ b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
@@ -81,6 +81,10 @@
 tbansal@chromium.org
 # commerce
 ayman@chromium.org
+# companion
+mcrouse@chromium.org
+shaktisahu@chromium.org
+tbansal@chromium.org
 # compositing
 schenney@chromium.org
 jonross@chromium.org
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml
index 78799bb..6489043 100644
--- a/tools/metrics/histograms/metadata/accessibility/histograms.xml
+++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -1486,7 +1486,7 @@
 
 <histogram
     name="Accessibility.LiveCaption.{SodaLanguageCode}.SessionContainsRecognizedSpeech"
-    enum="BooleanEnabled" expires_after="2023-06-01">
+    enum="BooleanEnabled" expires_after="2024-02-01">
   <owner>evliu@google.com</owner>
   <owner>chrome-media-ux@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index baedccff..d2ee79c 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -6667,8 +6667,21 @@
   </summary>
 </histogram>
 
-<histogram name="Ash.Wm.WindowSnapActionSource" enum="WindowSnapActionSource"
-    expires_after="2023-09-03">
+<histogram name="Ash.Wm.WindowSnapActionSource"
+    enum="DeprecatedWindowSnapActionSource" expires_after="2023-05-03">
+  <obsolete>
+    Deprecated Apr 2023. See the new metrics Ash.Wm.WindowSnapActionSource2.
+  </obsolete>
+  <owner>xdai@chromium.org</owner>
+  <owner>nupurjain@chromium.org</owner>
+  <summary>
+    Emitted when a window is to be snapped. Records different ways for a user to
+    snap a window. Deprecated.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Wm.WindowSnapActionSource2" enum="WindowSnapActionSource"
+    expires_after="2024-04-21">
   <owner>xdai@chromium.org</owner>
   <owner>nupurjain@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 118e18ff..3265d71 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -3089,7 +3089,7 @@
 </histogram>
 
 <histogram name="Autofill.OfferNotificationBubbleOffer.{BubbleType}"
-    enum="BooleanPreviouslyShown" expires_after="2023-05-01">
+    enum="BooleanPreviouslyShown" expires_after="2024-04-01">
   <owner>siyua@chromium.org</owner>
   <owner>jsaul@google.com</owner>
   <owner>payments-autofill-team@google.com</owner>
@@ -3117,7 +3117,7 @@
 
 <histogram
     name="Autofill.OfferNotificationBubbleResult.{BubbleType}.{ShowType}"
-    enum="AutofillOfferNotificationBubbleResult" expires_after="2023-05-01">
+    enum="AutofillOfferNotificationBubbleResult" expires_after="2024-04-01">
   <owner>siyua@chromium.org</owner>
   <owner>jsaul@google.com</owner>
   <owner>payments-autofill-team@google.com</owner>
@@ -3146,7 +3146,7 @@
 </histogram>
 
 <histogram name="Autofill.OfferNotificationInfoBarOffer.{OfferType}"
-    enum="BooleanShown" expires_after="2023-05-01">
+    enum="BooleanShown" expires_after="2024-04-01">
   <owner>siashah@chromium.org</owner>
   <owner>siyua@chromium.org</owner>
   <owner>payments-autofill-team@google.com</owner>
@@ -3158,7 +3158,7 @@
 </histogram>
 
 <histogram name="Autofill.OfferNotificationInfoBarResult.{OfferType}"
-    enum="AutofillOfferNotificationInfoBarResult" expires_after="2023-05-01">
+    enum="AutofillOfferNotificationInfoBarResult" expires_after="2024-04-01">
   <owner>siashah@chromium.org</owner>
   <owner>siyua@chromium.org</owner>
   <owner>payments-autofill-team@google.com</owner>
@@ -3897,7 +3897,7 @@
 </histogram>
 
 <histogram name="Autofill.ServerCardUnmask.{CardType}.Attempt"
-    enum="BooleanAttempted" expires_after="2023-06-01">
+    enum="BooleanAttempted" expires_after="2024-05-01">
   <owner>siyua@chromium.org</owner>
   <owner>payments-autofill-team@google.com</owner>
   <summary>
@@ -3908,7 +3908,7 @@
 </histogram>
 
 <histogram name="Autofill.ServerCardUnmask.{CardType}.FormSubmission"
-    enum="BooleanSubmitted" expires_after="2023-06-01">
+    enum="BooleanSubmitted" expires_after="2024-05-01">
   <owner>siyua@chromium.org</owner>
   <owner>payments-autofill-team@google.com</owner>
   <summary>
@@ -3919,7 +3919,7 @@
 </histogram>
 
 <histogram name="Autofill.ServerCardUnmask.{CardType}.Result.{FlowType}"
-    enum="AutofillServerCardUnmaskResult" expires_after="2023-06-01">
+    enum="AutofillServerCardUnmaskResult" expires_after="2024-05-01">
   <owner>siyua@chromium.org</owner>
   <owner>payments-autofill-team@google.com</owner>
   <summary>
@@ -4025,7 +4025,7 @@
 </histogram>
 
 <histogram name="Autofill.StoredCreditCardCount.Server.WithCardArtImage"
-    units="units" expires_after="2023-05-01">
+    units="units" expires_after="2024-04-01">
   <owner>siyua@chromium.org</owner>
   <owner>payments-autofill-team@google.com</owner>
   <summary>
@@ -4866,7 +4866,7 @@
 </histogram>
 
 <histogram name="Autofill.UsedCachedServerCard" units="uses"
-    expires_after="2023-06-01">
+    expires_after="2024-05-01">
   <owner>siyua@chromium.org</owner>
   <owner>jsaul@google.com</owner>
   <owner>payments-autofill-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/browser/histograms.xml b/tools/metrics/histograms/metadata/browser/histograms.xml
index b2ce9de..35f9b116 100644
--- a/tools/metrics/histograms/metadata/browser/histograms.xml
+++ b/tools/metrics/histograms/metadata/browser/histograms.xml
@@ -1035,7 +1035,7 @@
   </summary>
 </histogram>
 
-<histogram name="SidePanel.ResizedWidth" units="px" expires_after="2023-08-08">
+<histogram name="SidePanel.ResizedWidth" units="px" expires_after="2024-02-01">
   <owner>emshack@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -1045,7 +1045,7 @@
 </histogram>
 
 <histogram name="SidePanel.ResizedWidthPercentage" units="% of window width"
-    expires_after="2023-08-08">
+    expires_after="2024-02-01">
   <owner>emshack@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -1055,7 +1055,7 @@
 </histogram>
 
 <histogram name="SidePanel.{SidePanelEntry}.ResizedWidth" units="px"
-    expires_after="2023-06-04">
+    expires_after="2024-02-01">
   <owner>emshack@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -1066,7 +1066,7 @@
 </histogram>
 
 <histogram name="SidePanel.{SidePanelEntry}.ResizedWidthPercentage"
-    units="% of window width" expires_after="2023-06-04">
+    units="% of window width" expires_after="2024-02-01">
   <owner>emshack@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -1078,7 +1078,7 @@
 </histogram>
 
 <histogram name="SidePanel.{SidePanelEntry}.ShownDuration" units="ms"
-    expires_after="2023-06-04">
+    expires_after="2024-02-01">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -1090,7 +1090,7 @@
 </histogram>
 
 <histogram name="SidePanel.{SidePanelEntry}.ShowTriggered"
-    enum="SidePanelOpenTrigger" expires_after="2023-06-04">
+    enum="SidePanelOpenTrigger" expires_after="2024-02-01">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/chrome/histograms.xml b/tools/metrics/histograms/metadata/chrome/histograms.xml
index 1269cadd..04901425 100644
--- a/tools/metrics/histograms/metadata/chrome/histograms.xml
+++ b/tools/metrics/histograms/metadata/chrome/histograms.xml
@@ -315,58 +315,62 @@
   </summary>
 </histogram>
 
-<histogram name="ChromeElf.ApplyHookResult" enum="NTSTATUS" expires_after="M82">
-  <owner>chrisha@chromium.org</owner>
+<histogram name="ChromeElf.ApplyHookResult" enum="NTSTATUS"
+    expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     Records the NTSTATUS result that was returned when attempting to hook
     NtMapViewOfSection during chrome_elf.dll initialization. Emitted
-    asynchronously shortly after startup.
+    asynchronously shortly after startup. This histogram was expired between M82
+    and M114.
   </summary>
 </histogram>
 
 <histogram name="ChromeElf.Beacon.RetryAttemptsBeforeSuccess" units="units"
-    expires_after="M82">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     Records the number of attempts needed before third-party DLL blocking was
     properly set up. This is logged immediately after a successful setup. Only
-    recorded on Windows.
+    recorded on Windows. This histogram was expired between M82 and M114.
   </summary>
 </histogram>
 
 <histogram name="ChromeElf.Beacon.SetupStatus" enum="BlacklistSetup"
-    expires_after="M82">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     Records the successes and failures when running the third-party DLL blocking
     setup code, taking into account the safety beacon. Used to determine how
     often the third-party DLL blocking is disabled because it failed to
-    initialize properly twice in a row. Only recorded on Windows.
+    initialize properly twice in a row. Only recorded on Windows. This histogram
+    was expired between M82 and M114.
   </summary>
 </histogram>
 
 <histogram name="ChromeElf.ExtensionPoint.EnableState"
-    enum="ExtensionPointEnableState" expires_after="M93">
+    enum="ExtensionPointEnableState" expires_after="M121">
   <owner>wfh@chromium.org</owner>
   <owner>ssmole@microsoft.com</owner>
   <summary>
     Records the outcome of the heuristic to selectively enable or disable the
     ProcessExtensionPointDisablePolicy. Used to determine how often the policy
     will be enabled in practice, as the heuristic detects the presence of third
-    party software. Only recorded on Windows.
+    party software. Only recorded on Windows. This histogram was expired between
+    M93 and M114.
   </summary>
 </histogram>
 
 <histogram name="ChromeElf.ThirdPartyStatus" enum="ThirdPartyStatus"
-    expires_after="M82">
+    expires_after="M121">
   <obsolete>
     Retained for historical data.
   </obsolete>
-  <owner>chrisha@chromium.org</owner>
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     Records the different status codes that are emitted by chrome_elf.dll while
     initializing the NtMapViewOfSection hook used to blocked third-party DLLs.
@@ -374,7 +378,7 @@
     status codes represent non-fatal failures. E.g. Failure to clear the
     previous failure codes. This also means that duplicates are possible. This
     is recorded shortly after Chrome launches, since chrome_elf.dll doesn't have
-    access to the //base API.
+    access to the //base API. This histogram was expired between M82 and M114.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/companion/OWNERS b/tools/metrics/histograms/metadata/companion/OWNERS
new file mode 100644
index 0000000..381d518e
--- /dev/null
+++ b/tools/metrics/histograms/metadata/companion/OWNERS
@@ -0,0 +1,7 @@
+per-file OWNERS=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
+
+# Prefer sending CLs to the owners listed below.
+# Use chromium-metrics-reviews@google.com as a backup.
+mcrouse@chromium.org
+shaktisahu@chromium.org
+tbansal@chromium.org
diff --git a/tools/metrics/histograms/metadata/companion/histograms.xml b/tools/metrics/histograms/metadata/companion/histograms.xml
new file mode 100644
index 0000000..bc00bfe
--- /dev/null
+++ b/tools/metrics/histograms/metadata/companion/histograms.xml
@@ -0,0 +1,62 @@
+<!--
+Copyright 2023 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<!--
+This file is used to generate a comprehensive list of Signin histograms
+along with a detailed description for each histogram.
+
+For best practices on writing histogram descriptions, see
+https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md
+
+Please follow the instructions in the OWNERS file in this directory to find a
+reviewer. If no OWNERS file exists, please consider signing up at
+go/reviewing-metrics (Googlers only), as all subdirectories are expected to
+have an OWNERS file. As a last resort you can send the CL to
+chromium-metrics-reviews@google.com.
+-->
+
+<histogram-configuration>
+
+<histograms>
+
+<variants name="UiSurface">
+  <variant name="CQ"/>
+  <variant name="PH"/>
+  <variant name="RegionSearch"/>
+</variants>
+
+<histogram name="Companion.PromoEvent" enum="Companion.PromoEvent"
+    expires_after="2023-10-20">
+  <owner>shaktisahu@chromium.org</owner>
+  <summary>
+    Records various events (e.g. displayed, accepted or rejected) on various
+    promo surfaces on the companion page. Recorded as soon as the event happens.
+  </summary>
+</histogram>
+
+<histogram name="Companion.{UiSurface}.Clicked" enum="BooleanClicked"
+    expires_after="2023-10-20">
+  <owner>shaktisahu@chromium.org</owner>
+  <summary>
+    Records whether {UiSurface} was clicked by the user on the companion page.
+    Recorded as soon as the surface is clicked.
+  </summary>
+  <token key="UiSurface" variants="UiSurface"/>
+</histogram>
+
+<histogram name="Companion.{UiSurface}.Shown" enum="BooleanShown"
+    expires_after="2023-10-20">
+  <owner>shaktisahu@chromium.org</owner>
+  <summary>
+    Records whether {UiSurface} was shown on the companion page. Recorded as
+    soon as the surface is shown.
+  </summary>
+  <token key="UiSurface" variants="UiSurface"/>
+</histogram>
+
+</histograms>
+
+</histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/families/histograms.xml b/tools/metrics/histograms/metadata/families/histograms.xml
index 0c15b84d..ce69d63f 100644
--- a/tools/metrics/histograms/metadata/families/histograms.xml
+++ b/tools/metrics/histograms/metadata/families/histograms.xml
@@ -172,6 +172,8 @@
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records an error that occurs in the parent access widget. ChromeOS Only.
+    WebApprovals metrics are available from M110 onwards. ExtensionApprovals
+    metrics are available from M115 onwards.
   </summary>
   <token key="FlowType">
     <variant name="All"/>
@@ -189,9 +191,12 @@
   <summary>
     Records an error where the parent access widget dialog cannot be shown.
     Reported by the browser when the dialog fails to show. ChromeOS only.
+    WebApprovals metrics are available from M110 onwards. ExtensionApprovals
+    metrics are available from M115 onwards.
   </summary>
   <token key="FlowType">
     <variant name="All"/>
+    <variant name="ExtensionApprovals"/>
     <variant name="WebApprovals"/>
   </token>
 </histogram>
diff --git a/tools/metrics/histograms/metadata/history/histograms.xml b/tools/metrics/histograms/metadata/history/histograms.xml
index 9b9772d..0fcb903 100644
--- a/tools/metrics/histograms/metadata/history/histograms.xml
+++ b/tools/metrics/histograms/metadata/history/histograms.xml
@@ -784,7 +784,7 @@
 
 <histogram
     name="History.Clusters.Backend.ContentClustering.NumClustersAfterMerge"
-    units="counts" expires_after="2023-06-04">
+    units="counts" expires_after="2023-10-08">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -798,7 +798,7 @@
 
 <histogram
     name="History.Clusters.Backend.ContentClustering.NumClustersBeforeMerge"
-    units="counts" expires_after="2023-06-04">
+    units="counts" expires_after="2023-10-08">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -812,7 +812,7 @@
 
 <histogram
     name="History.Clusters.Backend.ContentClustering.PairwiseMergeNumIterations"
-    units="counts" expires_after="2023-06-04">
+    units="counts" expires_after="2023-10-08">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
diff --git a/tools/metrics/histograms/metadata/input/histograms.xml b/tools/metrics/histograms/metadata/input/histograms.xml
index 1ddee6bc..afdb01f 100644
--- a/tools/metrics/histograms/metadata/input/histograms.xml
+++ b/tools/metrics/histograms/metadata/input/histograms.xml
@@ -669,6 +669,17 @@
   </summary>
 </histogram>
 
+<histogram name="InputMethod.Assistive.MultiWord.ImplicitRejection"
+    enum="IMEAssistiveMultiWordSuggestionType" expires_after="2023-10-01">
+  <owner>curtismcmullan@google.com</owner>
+  <owner>essential-inputs-team@google.com</owner>
+  <summary>
+    This metric is recorded when a user implicitly rejects a multi word
+    suggestion that is shown to them. Implicit rejection here means the user has
+    typed some text that does not match the suggestion shown to them.
+  </summary>
+</histogram>
+
 <histogram name="InputMethod.Assistive.MultiWord.InputState"
     enum="IMEAssistiveTextInputState" expires_after="2023-08-20">
   <owner>curtismcmullan@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 05da40b..6eef8b5 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -5011,7 +5011,7 @@
 </histogram>
 
 <histogram name="Media.Video.Autoplay.Muted.PlayMethod.BecomesVisible"
-    enum="Boolean" expires_after="2023-04-30">
+    enum="Boolean" expires_after="2024-01-30">
   <owner>dalecurtis@chromium.org</owner>
   <owner>evliu@google.com</owner>
   <owner>media-dev@chromium.org</owner>
@@ -5025,7 +5025,7 @@
 </histogram>
 
 <histogram name="Media.Video.Autoplay.Muted.PlayMethod.OffscreenDuration"
-    units="ms" expires_after="2023-04-30">
+    units="ms" expires_after="2024-01-30">
   <owner>dalecurtis@chromium.org</owner>
   <owner>evliu@google.com</owner>
   <owner>media-dev@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/nearby/histograms.xml b/tools/metrics/histograms/metadata/nearby/histograms.xml
index 2204b621..a5df5f9 100644
--- a/tools/metrics/histograms/metadata/nearby/histograms.xml
+++ b/tools/metrics/histograms/metadata/nearby/histograms.xml
@@ -54,7 +54,7 @@
 </histogram>
 
 <histogram name="Nearby.Connections.Bluetooth.ClassicMedium.{Operation}.Result"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>Records the result of {Operation}.</summary>
@@ -85,7 +85,7 @@
 </histogram>
 
 <histogram name="Nearby.Connections.Bluetooth.LEMedium.StopAdvertising.Result"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -102,7 +102,7 @@
 
 <histogram
     name="Nearby.Connections.InstantMessaging.ReceiveExpress.NumParsingAttempts"
-    units="attempts" expires_after="2023-06-04">
+    units="attempts" expires_after="2023-10-08">
   <owner>julietlevesque@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -126,7 +126,7 @@
 
 <histogram
     name="Nearby.Connections.InstantMessaging.TachyonIceConfigFetcher.FailureReason"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-06-04">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -137,7 +137,7 @@
 
 <histogram
     name="Nearby.Connections.InstantMessaging.TachyonIceConfigFetcher.OAuthTokenFetchResult"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -148,7 +148,7 @@
 
 <histogram
     name="Nearby.Connections.InstantMessaging.TachyonIceConfigFetcher.Result"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -159,7 +159,7 @@
 
 <histogram
     name="Nearby.Connections.InstantMessaging.{Direction}Express.OAuthTokenFetchResult"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -175,7 +175,7 @@
 </histogram>
 
 <histogram name="Nearby.Connections.InstantMessaging.{Direction}Express.Result"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -190,7 +190,7 @@
 
 <histogram
     name="Nearby.Connections.InstantMessaging.{Direction}Express.Result.FailureReason"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-06-04">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -258,7 +258,7 @@
 </histogram>
 
 <histogram name="Nearby.Connections.WifiLan.Socket.AcceptResult"
-    enum="NetErrorCodes" expires_after="2023-06-04">
+    enum="NetErrorCodes" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -272,7 +272,7 @@
 </histogram>
 
 <histogram name="Nearby.Connections.WifiLan.TimeToConnect" units="ms"
-    expires_after="2023-06-04">
+    expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -283,7 +283,7 @@
 </histogram>
 
 <histogram name="Nearby.Connections.{Medium}.Socket.{Operation}.Result"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -303,7 +303,7 @@
 <histogram
     name="Nearby.Share.BackgroundScanning.DeviceNearbySharing.Notification.Flow"
     enum="NearbyShareBackgroundScanningDeviceNearbySharingNotificationFlowEvent"
-    expires_after="2023-08-13">
+    expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -317,7 +317,7 @@
 
 <histogram
     name="Nearby.Share.BackgroundScanning.DeviceNearbySharing.Notification.TimeToAction"
-    units="ms" expires_after="2023-08-08">
+    units="ms" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -329,7 +329,7 @@
 
 <histogram name="Nearby.Share.BackgroundScanning.DevicesDetected"
     enum="NearbyShareBackgroundScanningDevicesDetectedEvent"
-    expires_after="2023-08-13">
+    expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -343,7 +343,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.BackgroundScanning.DevicesDetected.Duration"
-    units="ms" expires_after="2023-06-04">
+    units="ms" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -367,7 +367,7 @@
 
 <histogram name="Nearby.Share.BackgroundScanning.Setup.Notification.Flow"
     enum="NearbyShareBackgroundScanningSetupNotificationFlowEvent"
-    expires_after="2023-06-04">
+    expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -381,7 +381,7 @@
 
 <histogram
     name="Nearby.Share.BackgroundScanning.Setup.Notification.TimeToAction"
-    units="ms" expires_after="2023-06-04">
+    units="ms" expires_after="2023-10-08">
   <owner>hansenmichael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -408,7 +408,7 @@
 
 <histogram
     name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesCount"
-    units="certificates" expires_after="2023-08-13">
+    units="certificates" expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -420,7 +420,7 @@
 
 <histogram
     name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesFailuePageCount"
-    units="pages" expires_after="2023-06-04">
+    units="pages" expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -432,7 +432,7 @@
 
 <histogram
     name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesHttpResult"
-    enum="NearbyHttpResult" expires_after="2023-08-13">
+    enum="NearbyHttpResult" expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -445,7 +445,7 @@
 
 <histogram
     name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesSuccessPageCount"
-    units="pages" expires_after="2023-06-04">
+    units="pages" expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -478,7 +478,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Certificates.Storage.InitializeAttemptCount"
-    units="attempts" expires_after="2023-06-04">
+    units="attempts" expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -489,7 +489,7 @@
 
 <histogram name="Nearby.Share.Certificates.Storage.InitializeAttemptResult"
     enum="NearbyShareCertificateStorageInitializationResult"
-    expires_after="2023-06-04">
+    expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -500,7 +500,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Certificates.Storage.InitializeSuccessDuration"
-    units="ms" expires_after="2023-08-20">
+    units="ms" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -511,7 +511,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Certificates.Storage.{Operation}SuccessRate"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>cclem@chromium.org</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -567,7 +567,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Contacts.CanGetProfileUserName"
-    enum="BooleanSuccess" expires_after="2023-06-11">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -582,7 +582,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Contacts.DownloadPageCount.{Result}"
-    units="pages" expires_after="2023-06-04">
+    units="pages" expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -630,7 +630,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Contacts.NumContacts.{Type}" units="contacts"
-    expires_after="2023-06-04">
+    expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -653,7 +653,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Contacts.Percent{Type}" units="%"
-    expires_after="2023-06-04">
+    expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -676,7 +676,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Contacts.TimeToDownload.{Result}" units="ms"
-    expires_after="2023-06-04">
+    expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -694,7 +694,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.DeviceType{Direction}"
-    enum="NearbyShareDeviceType" expires_after="2023-06-04">
+    enum="NearbyShareDeviceType" expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -710,7 +710,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Discovery.Delay.FromStartDiscoveryTo{EndState}"
-    units="ms" expires_after="2023-06-04">
+    units="ms" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -735,7 +735,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Discovery.LookUpSelectedShareTarget"
-    enum="BooleanFound" expires_after="2023-06-04">
+    enum="BooleanFound" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -747,7 +747,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Discovery.NumShareTargets.{Variation}"
-    units="share targets" expires_after="2023-06-04">
+    units="share targets" expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -762,7 +762,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Discovery.{Operation}"
-    enum="NearbyShareServiceStatusCode" expires_after="2023-06-04">
+    enum="NearbyShareServiceStatusCode" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -794,7 +794,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.EnabledStateChanged" enum="BooleanEnabled"
-    expires_after="2023-06-11">
+    expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -874,7 +874,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Onboarding.EntryPoint"
-    enum="NearbyShareOnboardingEntryPoint" expires_after="2023-09-03">
+    enum="NearbyShareOnboardingEntryPoint" expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -886,7 +886,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Onboarding.FlowEvent"
-    enum="NearbyShareOnboardingFlowEvent" expires_after="2023-06-11">
+    enum="NearbyShareOnboardingFlowEvent" expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -909,7 +909,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Payload.AttachmentType{Variation}"
-    enum="NearbyShareAttachmentType" expires_after="2023-06-04">
+    enum="NearbyShareAttachmentType" expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -929,7 +929,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Payload.FinalStatus{UpgradedMedium}"
-    enum="NearbyShareFinalStatus" expires_after="2023-06-04">
+    enum="NearbyShareFinalStatus" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -948,7 +948,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Payload.FuseBox.Open.Success"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <obsolete>
     Removed in 10/2022. Now using
     Nearby.Share.Payload{Operation}.Success{FilePath} to support different
@@ -971,7 +971,7 @@
 
 <histogram
     name="Nearby.Share.Payload.Medium.Over5MbTransferred{ShareTargetType}"
-    enum="NearbyShareUpgradedMedium" expires_after="2023-06-04">
+    enum="NearbyShareUpgradedMedium" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -990,7 +990,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Payload.NumAttachments{Type}" units="attachments"
-    expires_after="2023-06-04">
+    expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -1006,7 +1006,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Payload.TotalSize{Variation}" units="KB"
-    expires_after="2023-06-04">
+    expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -1039,7 +1039,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Payload.TransferRate{Variation}" units="KB/s"
-    expires_after="2023-06-04">
+    expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -1072,9 +1072,10 @@
 </histogram>
 
 <histogram name="Nearby.Share.Payload{Operation}.Success{FilePath}"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>alanding@google.com</owner>
   <owner>cros-sharesheet@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the success/failure of a Nearby Share file {Operation} where the
     file path is created within a mount point owned by file manager. Emitted
@@ -1094,7 +1095,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.StartAdvertising.Result.FailureReason{Mode}"
-    enum="NearbyShareStartAdvertisingFailureReason" expires_after="2023-06-04">
+    enum="NearbyShareStartAdvertisingFailureReason" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -1108,7 +1109,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.StartAdvertising.Result{Mode}"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>pushi@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -1149,7 +1150,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.Transfer.FinalStatus{Variation}"
-    enum="NearbyShareTransferFinalStatus" expires_after="2023-06-04">
+    enum="NearbyShareTransferFinalStatus" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -1186,7 +1187,7 @@
 
 <histogram
     name="Nearby.Share.Transfer.Success.{Direction}.{ShareTargetType}.{ContactStatus}"
-    enum="BooleanSuccess" expires_after="2023-06-04">
+    enum="BooleanSuccess" expires_after="2023-10-08">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
@@ -1223,7 +1224,7 @@
 </histogram>
 
 <histogram name="Nearby.Share.WifiNetworkConfiguration.Result"
-    enum="BooleanSuccess" expires_after="2023-08-13">
+    enum="BooleanSuccess" expires_after="2023-10-15">
   <owner>crisrael@google.com</owner>
   <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml
index 3294176e..be1b53b 100644
--- a/tools/metrics/histograms/metadata/optimization/histograms.xml
+++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -70,6 +70,8 @@
       summary="Segmentation: Tablet Productivity user"/>
   <variant name="SegmentationVoice" summary="Segmentation: Voice user"/>
   <variant name="TextClassifier" summary="Smart text selection"/>
+  <variant name="WebAppInstallationPromo"
+      summary="PWA: Show web app installation promotion"/>
 </variants>
 
 <variants name="OptimizationType">
@@ -734,6 +736,9 @@
 <histogram
     name="OptimizationGuide.PageContentAnnotationsService.ContentAnnotationsStorageMinMagnitudeForVisitNotFound"
     units="ms" expires_after="2023-06-04">
+  <obsolete>
+    Obsolete as of 04/2023.
+  </obsolete>
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-intelligence-core@google.com</owner>
   <summary>
@@ -749,6 +754,9 @@
 <histogram
     name="OptimizationGuide.PageContentAnnotationsService.ContentAnnotationsStorageMinMagnitudeForVisitNotFound.{PageContentAnnotationsStorageType}"
     units="ms" expires_after="M117">
+  <obsolete>
+    Obsolete as of 04/2023.
+  </obsolete>
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-intelligence-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 822363d..d90a5ed 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -3264,7 +3264,7 @@
 </histogram>
 
 <histogram name="ContextMenu.Shown{Type}" enum="BooleanPresent"
-    expires_after="2023-05-27">
+    expires_after="2024-05-27">
   <owner>mpearson@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <owner>clank-app-team@google.com</owner>
@@ -3581,7 +3581,7 @@
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
   <summary>
-    Records whether OS-level attribution is supported on the device. Only
+    Records whether web or OS-level attribution is supported on the device. Only
     recorded on Android when the AttributionReportingCrossAppWeb feature is
     enabled. Recorded once per browser session when the browser starts up.
   </summary>
@@ -12653,158 +12653,182 @@
 </histogram>
 
 <histogram name="ThirdPartyModules.Certificates.Microsoft" units="certificates"
-    expires_after="M85">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
+  <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The total number of certificates for modules loaded (or potentially loaded)
     into the browser process that are signed by Microsoft. A catalog counts as a
     single certificate, and may refer to many modules. Measured shortly after
-    startup. Windows only.
+    startup. Windows only. This histogram was expired between M85 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Certificates.Total" units="certificates"
-    expires_after="2019-12-31">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
+  <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The total number of certificates for modules loaded (or potentially loaded)
     into the browser process. A catalog counts as a single certificate, and may
-    refer to many modules. Measured shortly after startup. Windows only.
+    refer to many modules. Measured shortly after startup. Windows only. This
+    histogram was expired between 2019-12-31 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.GetDriveLetterPathFound" enum="BooleanFound"
-    expires_after="M85">
+    expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     Records whether an equivalent driver letter path was found for a device
-    path.
+    path. This histogram was expired between M85 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Heartbeat.BlockedModulesCount"
-    units="modules" expires_after="M85">
+    units="modules" expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     Records the number of modules that were blocked from loading into the
     browser process by the third-party DLL blocking feature. This is recorded
-    every 5 minutes.
+    every 5 minutes. This histogram was expired between M85 and M114.
   </summary>
 </histogram>
 
 <histogram
     name="ThirdPartyModules.Heartbeat.PrintingWorkaround.BlockingEnabled"
-    enum="BooleanEnabled" expires_after="M85">
+    enum="BooleanEnabled" expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     Records whether or not Chrome is still blocking third-party DLLs. This is a
     bit that turns to false when the in-process printing is invoked. Recorded
-    every 5 minutes.
+    every 5 minutes. This histogram was expired between M85 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Heartbeat.UniqueBlockedModulesCount"
-    units="modules" expires_after="M85">
+    units="modules" expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     Records the number of unique modules that were blocked from loading into the
     browser process by the third-party DLL blocking feature. This is recorded
-    every 5 minutes.
+    every 5 minutes. This histogram was expired between M85 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.InputMethodEditorsCount" units="counts"
-    expires_after="M77">
+    expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The number of registered input method editors found on the user's machine.
     This is emitted shortly after startup when the IME enumeration takes place.
+    This histogram was expired between M77 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Modules.Loaded" units="modules"
-    expires_after="M85">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
+  <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The total number of third-party modules (neither Microsoft nor Google) that
     are loaded in the browser process. Measured shortly after startup. Windows
-    only.
+    only. This histogram was expired between M85 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Modules.NotLoaded" units="modules"
-    expires_after="2019-12-31">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
+  <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The total number of third-party modules (neither Microsoft nor Google) that
     are not yet loaded in the browser process, but may potentially be (shell
-    extensions, for example). Measured shortly after startup. Windows only.
+    extensions, for example). Measured shortly after startup. Windows only. This
+    histogram was expired between 2019-12-31 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Modules.Signed" units="modules"
-    expires_after="2019-12-31">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
+  <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The total number of signed modules loaded (or potentially loaded) into the
-    browser process. Measured shortly after startup. Windows only.
+    browser process. Measured shortly after startup. Windows only. This
+    histogram was expired between 2019-12-31 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Modules.Signed.Catalog" units="modules"
-    expires_after="2019-12-31">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
+  <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The total number of modules loaded (or potentially loaded) into the browser
     process that are signed via a catalog. Measured shortly after startup.
-    Windows only.
+    Windows only. This histogram was expired between 2019-12-31 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Modules.Signed.Microsoft" units="modules"
-    expires_after="M85">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
+  <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The total number of modules loaded (or potentially loaded) into the browser
     process that are signed by Microsoft. Measured shortly after startup.
-    Windows only.
+    Windows only. This histogram was expired between M85 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Modules.Total" units="modules"
-    expires_after="M85">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
+  <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The total number of modules loaded (or potentially loaded) into the browser
-    process. Measured shortly after startup. Windows only.
+    process. Measured shortly after startup. Windows only. This histogram was
+    expired between M85 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Modules.Unsigned" units="modules"
-    expires_after="M85">
-  <owner>chrisha@chromium.org</owner>
+    expires_after="M121">
+  <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The total number of unsigned modules loaded (or potentially loaded) into the
-    browser process. Measured shortly after startup. Windows only.
+    browser process. Measured shortly after startup. Windows only. This
+    histogram was expired between M85 and M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.ShellExtensionsCount3" units="counts"
-    expires_after="M85">
+    expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     The number of registered shell extensions found on the user's machine. This
     is emitted shortly after startup when the shell extensions enumeration is
-    done. Doesn't count duplicates.
+    done. Doesn't count duplicates. This histogram was expired between M85 and
+    M114.
   </summary>
 </histogram>
 
 <histogram name="ThirdPartyModules.Uninstallable" enum="BooleanUninstallable"
-    expires_after="M85">
+    expires_after="M121">
   <owner>pmonette@chromium.org</owner>
+  <owner>kristianm@chromium.org</owner>
   <summary>
     Records whether or not a loaded third party module could be uninstalled
-    using the Windows Apps &amp; Features page.
+    using the Windows Apps &amp; Features page. This histogram was expired
+    between M85 and M114.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 1ff273b..cbfd5af 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -1726,6 +1726,16 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.Import.FileDeletionSelected" units="Boolean"
+    expires_after="2023-10-15">
+  <owner>eliaskh@chromium.org</owner>
+  <owner>natiahlyi@google.com</owner>
+  <summary>
+    Records if the user selected to delete a file after a succesful import with
+    no errors. Reported before the import success dialog is closed.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.Import.Only{ErrorType}" units="Boolean"
     expires_after="2023-09-15">
   <owner>eliaskh@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/phonehub/histograms.xml b/tools/metrics/histograms/metadata/phonehub/histograms.xml
index 79b50c0..d194b29 100644
--- a/tools/metrics/histograms/metadata/phonehub/histograms.xml
+++ b/tools/metrics/histograms/metadata/phonehub/histograms.xml
@@ -279,6 +279,27 @@
   </summary>
 </histogram>
 
+<histogram name="PhoneHub.InitialPhoneStatusSnapshot.Latency" units="ms"
+    expires_after="2023-10-15">
+  <owner>pushi@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    The duration of time the chromebook sends CrosState request message and
+    completes processing returned PhoneStatusSnapshot message. Emitted when
+    PhoneStatusSnapshot is processed.
+  </summary>
+</histogram>
+
+<histogram name="PhoneHub.InitialPhoneStatusSnapshot.Received"
+    enum="BooleanSuccess" expires_after="2023-10-15">
+  <owner>pushi@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Measures success rate of Phone Hub PhoneStatusSnapshot processing during a
+    connection session. Emitted when Phone Hub is disconnected.
+  </summary>
+</histogram>
+
 <histogram name="PhoneHub.InterstitialScreenEvent.{Screen}"
     enum="PhoneHubInterstitialScreenEvent" expires_after="2023-06-11">
   <owner>jonmann@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml
index c3f5229d..44de465 100644
--- a/tools/metrics/histograms/metadata/platform/histograms.xml
+++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -67,6 +67,15 @@
   </summary>
 </histogram>
 
+<histogram name="Platform.Bootlockbox.AvailabilityAtStart"
+    enum="BootlockboxAvailability" expires_after="2023-10-24">
+  <owner>yich@google.com</owner>
+  <owner>cros-hwsec-userland-eng+uma@google.com</owner>
+  <summary>
+    Record the bootlockbox space availability when bootlockbox started.
+  </summary>
+</histogram>
+
 <histogram name="Platform.BootMode.DevSwitch"
     enum="Platform.BootMode.SwitchStatus" expires_after="2022-04-03">
   <owner>mnissler@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/preloading/histograms.xml b/tools/metrics/histograms/metadata/preloading/histograms.xml
index d9199ae..c41a2b0c 100644
--- a/tools/metrics/histograms/metadata/preloading/histograms.xml
+++ b/tools/metrics/histograms/metadata/preloading/histograms.xml
@@ -76,7 +76,7 @@
 </histogram>
 
 <histogram name="Preloading.Predictor.{PreloadingPredictor}.Precision"
-    enum="PredictorConfusionMatrix" expires_after="2023-06-04">
+    enum="PredictorConfusionMatrix" expires_after="2024-06-01">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -93,7 +93,7 @@
 </histogram>
 
 <histogram name="Preloading.Predictor.{PreloadingPredictor}.Recall"
-    enum="PredictorConfusionMatrix" expires_after="2023-06-04">
+    enum="PredictorConfusionMatrix" expires_after="2024-06-01">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -123,7 +123,7 @@
 
 <histogram
     name="Preloading.{PreloadingType}.Attempt.{PreloadingPredictor}.Precision"
-    enum="PredictorConfusionMatrix" expires_after="2023-06-04">
+    enum="PredictorConfusionMatrix" expires_after="2024-06-01">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -143,7 +143,7 @@
 
 <histogram
     name="Preloading.{PreloadingType}.Attempt.{PreloadingPredictor}.Recall"
-    enum="PredictorConfusionMatrix" expires_after="2023-06-04">
+    enum="PredictorConfusionMatrix" expires_after="2024-06-01">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -164,7 +164,7 @@
 
 <histogram
     name="Preloading.{PreloadingType}.Attempt.{PreloadingPredictor}.TriggeringOutcome"
-    enum="PreloadingTriggeringOutcome" expires_after="M115">
+    enum="PreloadingTriggeringOutcome" expires_after="2024-06-01">
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
   <owner>jbroman@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml b/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml
index 21461ae..9c86e19 100644
--- a/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml
+++ b/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml
@@ -76,6 +76,7 @@
   <variant name="SearchUser"/>
   <variant name="ShoppingUser"/>
   <variant name="TabletProductivityUser"/>
+  <variant name="WebAppInstallationPromo"/>
 </variants>
 
 <variants name="SegmentationModel">
@@ -101,6 +102,7 @@
   <variant name="TabletProductivityUser"/>
   <variant name="Unknown"/>
   <variant name="Voice"/>
+  <variant name="WebAppInstallationPromo"/>
 </variants>
 
 <variants name="SignalType">
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index eca047fe..c07bdbcf 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -6475,6 +6475,43 @@
   </metric>
 </event>
 
+<event name="Companion.PageView">
+  <owner>shaktisahu@chromium.org</owner>
+  <summary>
+    Records metrics for the companion side panel. The events correspond to a
+    single page load in the main frame and the metrics are flushed when the page
+    navigates away. For most of the UI surfaces, only the last event (e.g.
+    displayed or clicked) is recorded.
+  </summary>
+  <metric name="CQ.ChildElementCount">
+    <summary>
+      The number of child elements shown within the CQ suface, e.g. the number
+      of related queries in the related queries component. Clamped to a max
+      value of 10.
+    </summary>
+  </metric>
+  <metric name="CQ.LastEvent" enum="Companion.UiEvent">
+    <summary>
+      The last event on the CQ surface.
+    </summary>
+  </metric>
+  <metric name="PH.LastEvent" enum="Companion.UiEvent">
+    <summary>
+      The last event on the PH surface.
+    </summary>
+  </metric>
+  <metric name="PromoEvent" enum="Companion.PromoEvent">
+    <summary>
+      The last event on the promo surface.
+    </summary>
+  </metric>
+  <metric name="RegionSearch.ClickCount">
+    <summary>
+      The number of times region search in the multimodal box was clicked.
+    </summary>
+  </metric>
+</event>
+
 <event name="Compositor.Rendering">
   <owner>khushalsagar@chromium.org</owner>
   <summary>
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py
index 6fa92c64..33381da9 100644
--- a/tools/perf/core/bot_platforms.py
+++ b/tools/perf/core/bot_platforms.py
@@ -658,8 +658,8 @@
     'Low end windows 10 HP laptops. HD Graphics 5500, x86-64-i3-5005U, '
     'SSD, 4GB RAM.',
     _WIN_10_LOW_END_BENCHMARK_CONFIGS,
-    # TODO(crbug.com/1305291): Increase the count back to 46 when issue fixed.
-    40,
+    # TODO(b/278947510): Increase the count when m.2 disks stop failing.
+    20,
     'win')
 WIN_10_LOW_END_PGO = PerfPlatform(
     'win-10_laptop_low_end-perf-pgo',
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 00b98ac..d1c64e2 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": "perfetto-luci-artifacts/adbbb6c78e3a86c5e87b0338d9e42eb6b4ddbf4d/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "963dfb9e6dde58df884a2210c7dac4d74c36d3e8",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/5437caf87b2d6711ead7eef50c762fd1114e7ef9/trace_processor_shell.exe"
+            "hash": "4aa50a24ddb9a4c3ed8030e9f42f8f4bca2de186",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/20b114cd063623e63ef1b0a31167d60081567e51/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "1d229abc94dea54ab4bb4327e78e18f942d08bf9",
             "full_remote_path": "perfetto-luci-artifacts/adbbb6c78e3a86c5e87b0338d9e42eb6b4ddbf4d/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "b05dc5f4284bdb5c41c23ed084a16e64343d7389",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/934a4a6572827e1e911fa214556906e6520f23bf/trace_processor_shell"
+            "hash": "3543a8889331e0aa162550aa9c4dc4c97349f19c",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/20b114cd063623e63ef1b0a31167d60081567e51/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "7a4026b8718994145a52586fdec6e9447573345a",
             "full_remote_path": "perfetto-luci-artifacts/adbbb6c78e3a86c5e87b0338d9e42eb6b4ddbf4d/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "dd8ace566651e1a986bfa4e57191d24817fe549c",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/5437caf87b2d6711ead7eef50c762fd1114e7ef9/trace_processor_shell"
+            "hash": "e37031bb126628ab866fb6be371269051e802e91",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/20b114cd063623e63ef1b0a31167d60081567e51/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/core/shard_maps/timing_data/win-10_laptop_low_end-perf_timing.json b/tools/perf/core/shard_maps/timing_data/win-10_laptop_low_end-perf_timing.json
index 628a023..af92315 100644
--- a/tools/perf/core/shard_maps/timing_data/win-10_laptop_low_end-perf_timing.json
+++ b/tools/perf/core/shard_maps/timing_data/win-10_laptop_low_end-perf_timing.json
@@ -1,34 +1,58 @@
 [
     {
-        "duration": "52.0",
-        "name": "blink_perf.accessibility/build-table.html"
+        "duration": "28.0",
+        "name": "ad_frames.fencedframe/fencedframe: https://ad.doubleclick.net/ddm/adi/N378.275220.MYBESTOPTION.IT4/B8455269.126839257;sz=970x250"
     },
     {
-        "duration": "22.0",
-        "name": "blink_perf.accessibility/focus-links.html"
+        "duration": "27.0",
+        "name": "ad_frames.fencedframe/fencedframe: https://ad.doubleclick.net/ddm/adi/N378.275220.MYBESTOPTION.IT4/B9340305.127461685;sz=970x250"
     },
     {
-        "duration": "19.0",
-        "name": "blink_perf.accessibility/insert-block-child-after-many-inline-children.html"
+        "duration": "38.0",
+        "name": "ad_frames.fencedframe/fencedframe: https://ad.doubleclick.net/ddm/adi/N378.275220.MYBESTOPTION.IT4/B9340305.127562781;sz=970x250"
     },
     {
-        "duration": "21.0",
-        "name": "blink_perf.accessibility/line-breaks.html"
+        "duration": "27.0",
+        "name": "ad_frames.fencedframe/fencedframe: https://ad.doubleclick.net/ddm/adi/N378.275220.MYBESTOPTION.IT4/B9340305.128470354;sz=300x600"
     },
     {
-        "duration": "59.0",
-        "name": "blink_perf.accessibility/many-nodes-toggle-content-visibility-auto.html"
+        "duration": "27.0",
+        "name": "ad_frames.fencedframe/fencedframe: https://ad.doubleclick.net/ddm/adi/N378.275220.MYBESTOPTION.IT4/B9340305.128710365;sz=970x250"
     },
     {
-        "duration": "52.0",
-        "name": "blink_perf.accessibility/many-nodes-toggle-content-visibility-hidden.html"
+        "duration": "28.0",
+        "name": "ad_frames.fencedframe/fencedframe: https://ad.doubleclick.net/ddm/adi/N378.3159.GOOGLE3/B9340305.138620671;sz=970x250"
     },
     {
         "duration": "32.0",
+        "name": "blink_perf.accessibility/build-table.html"
+    },
+    {
+        "duration": "28.0",
+        "name": "blink_perf.accessibility/focus-links.html"
+    },
+    {
+        "duration": "25.0",
+        "name": "blink_perf.accessibility/insert-block-child-after-many-inline-children.html"
+    },
+    {
+        "duration": "25.0",
+        "name": "blink_perf.accessibility/line-breaks.html"
+    },
+    {
+        "duration": "31.0",
+        "name": "blink_perf.accessibility/many-nodes-toggle-content-visibility-auto.html"
+    },
+    {
+        "duration": "30.0",
+        "name": "blink_perf.accessibility/many-nodes-toggle-content-visibility-hidden.html"
+    },
+    {
+        "duration": "26.0",
         "name": "blink_perf.accessibility/many-nodes-toggle-display-none-in-focusable.html"
     },
     {
-        "duration": "41.0",
+        "duration": "26.0",
         "name": "blink_perf.accessibility/many-nodes-toggle-display-none.html"
     },
     {
@@ -36,19 +60,19 @@
         "name": "blink_perf.accessibility/many-text-changes-deep-block-subtree.html"
     },
     {
-        "duration": "24.0",
+        "duration": "26.0",
         "name": "blink_perf.accessibility/many-text-changes-deep-hidden-subtree.html"
     },
     {
-        "duration": "23.0",
+        "duration": "25.0",
         "name": "blink_perf.accessibility/many-text-changes-deep-inline-subtree.html"
     },
     {
-        "duration": "28.0",
+        "duration": "26.0",
         "name": "blink_perf.accessibility/many-text-changes-small-wait-between.html"
     },
     {
-        "duration": "20.0",
+        "duration": "25.0",
         "name": "blink_perf.accessibility/slot-updates.html"
     },
     {
@@ -56,23 +80,23 @@
         "name": "blink_perf.accessibility/text-changes-ignored-in-focusable.html"
     },
     {
-        "duration": "27.0",
+        "duration": "26.0",
         "name": "blink_perf.accessibility/text-changes-unignored-in-focusable.html"
     },
     {
-        "duration": "20.0",
+        "duration": "25.0",
         "name": "blink_perf.accessibility/textarea-append.html"
     },
     {
-        "duration": "28.0",
+        "duration": "26.0",
         "name": "blink_perf.accessibility/unassignable-slots-deep-tree.html"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "blink_perf.accessibility/unassignable-slots-focusable-containers.html"
     },
     {
-        "duration": "52.0",
+        "duration": "25.0",
         "name": "blink_perf.accessibility/unassignable-slots-wide-tree.html"
     },
     {
@@ -84,7 +108,7 @@
         "name": "blink_perf.bindings/create-element.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/document-implementation.html"
     },
     {
@@ -92,19 +116,19 @@
         "name": "blink_perf.bindings/dom-attribute-on-prototoype.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/first-child.html"
     },
     {
-        "duration": "9.0",
+        "duration": "7.0",
         "name": "blink_perf.bindings/gc-forest.html"
     },
     {
-        "duration": "11.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/gc-mini-tree.html"
     },
     {
-        "duration": "17.0",
+        "duration": "15.0",
         "name": "blink_perf.bindings/gc-tree.html"
     },
     {
@@ -124,7 +148,7 @@
         "name": "blink_perf.bindings/get-elements-by-tag-name.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/id-getter.html"
     },
     {
@@ -132,11 +156,11 @@
         "name": "blink_perf.bindings/id-setter.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.bindings/indexed-getter.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/insert-before.html"
     },
     {
@@ -144,11 +168,11 @@
         "name": "blink_perf.bindings/named-property-enumerator.html"
     },
     {
-        "duration": "19.0",
+        "duration": "16.0",
         "name": "blink_perf.bindings/node-list-access.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/node-type.html"
     },
     {
@@ -156,7 +180,7 @@
         "name": "blink_perf.bindings/post-message.html"
     },
     {
-        "duration": "8.0",
+        "duration": "10.0",
         "name": "blink_perf.bindings/sequence-conversion-array.html"
     },
     {
@@ -168,11 +192,11 @@
         "name": "blink_perf.bindings/serialize-array.html"
     },
     {
-        "duration": "3.0",
+        "duration": "2.0",
         "name": "blink_perf.bindings/serialize-long-string.html"
     },
     {
-        "duration": "6.0",
+        "duration": "5.0",
         "name": "blink_perf.bindings/serialize-map.html"
     },
     {
@@ -188,11 +212,11 @@
         "name": "blink_perf.bindings/set-attribute.html"
     },
     {
-        "duration": "12.0",
+        "duration": "11.0",
         "name": "blink_perf.bindings/structured-clone-json-deserialize.html"
     },
     {
-        "duration": "12.0",
+        "duration": "11.0",
         "name": "blink_perf.bindings/structured-clone-json-serialize.html"
     },
     {
@@ -208,7 +232,7 @@
         "name": "blink_perf.bindings/typed-array-construct-from-array.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/typed-array-construct-from-same-type.html"
     },
     {
@@ -216,367 +240,395 @@
         "name": "blink_perf.bindings/typed-array-construct-from-typed.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/typed-array-set-from-typed.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/undefined-first-child.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/undefined-get-element-by-id.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/undefined-id-getter.html"
     },
     {
-        "duration": "2.0",
+        "duration": "3.0",
         "name": "blink_perf.bindings/worker-structured-clone-different-payloads.html"
     },
     {
-        "duration": "22.0",
+        "duration": "21.0",
         "name": "blink_perf.bindings/worker-structured-clone-json-from-worker.html"
     },
     {
-        "duration": "37.0",
+        "duration": "21.0",
         "name": "blink_perf.bindings/worker-structured-clone-json-roundtrip.html"
     },
     {
-        "duration": "29.0",
+        "duration": "21.0",
         "name": "blink_perf.bindings/worker-structured-clone-json-to-worker.html"
     },
     {
-        "duration": "7.0",
+        "duration": "5.0",
         "name": "blink_perf.bindings/worker-structured-clone-workerDOM-DBMon-from-worker.html"
     },
     {
-        "duration": "4.0",
+        "duration": "8.0",
         "name": "blink_perf.bindings/worker-structured-clone-workerDOM-Map-from-worker.html"
     },
     {
-        "duration": "17.0",
+        "duration": "14.0",
         "name": "blink_perf.bindings/worker-text-encoded-transferable-from-worker.html"
     },
     {
-        "duration": "23.0",
+        "duration": "16.0",
         "name": "blink_perf.bindings/worker-text-encoded-transferable-roundtrip.html"
     },
     {
-        "duration": "30.0",
+        "duration": "14.0",
         "name": "blink_perf.bindings/worker-text-encoded-transferable-to-worker.html"
     },
     {
-        "duration": "27.0",
+        "duration": "12.0",
         "name": "blink_perf.bindings/worker-transferable-from-worker.html"
     },
     {
-        "duration": "25.0",
+        "duration": "12.0",
         "name": "blink_perf.bindings/worker-transferable-roundtrip.html"
     },
     {
-        "duration": "21.0",
+        "duration": "12.0",
         "name": "blink_perf.bindings/worker-transferable-to-worker.html"
     },
     {
-        "duration": "33.0",
+        "duration": "12.0",
+        "name": "blink_perf.css/AtScope.html"
+    },
+    {
+        "duration": "17.0",
         "name": "blink_perf.css/AttributeDescendantSelector.html"
     },
     {
-        "duration": "13.0",
+        "duration": "4.0",
+        "name": "blink_perf.css/BigContainerQuery.html"
+    },
+    {
+        "duration": "5.0",
         "name": "blink_perf.css/CSSLogicalDirection.html"
     },
     {
-        "duration": "20.0",
+        "duration": "10.0",
         "name": "blink_perf.css/CSSPropertySetterGetter.html"
     },
     {
-        "duration": "21.0",
+        "duration": "10.0",
         "name": "blink_perf.css/CSSPropertySetterGetterMethods.html"
     },
     {
-        "duration": "20.0",
+        "duration": "10.0",
         "name": "blink_perf.css/CSSPropertyUpdateValue.html"
     },
     {
-        "duration": "17.0",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleCSSVariableRecalc.html"
     },
     {
-        "duration": "17.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleChildClassSelector.html"
     },
     {
-        "duration": "16.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleChildElementSelectors.html"
     },
     {
-        "duration": "21.0",
+        "duration": "9.0",
         "name": "blink_perf.css/ChangeStyleCustomPropertyDeclaration.html"
     },
     {
-        "duration": "20.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleElementSelector.html"
     },
     {
-        "duration": "16.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleGrandChildElementSelector.html"
     },
     {
-        "duration": "16.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleMultipleClassSelector.html"
     },
     {
-        "duration": "17.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleMultipleQualifiedDataAttributesWithValuesSelector.html"
     },
     {
-        "duration": "17.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleNestedPseudoSelector.html"
     },
     {
-        "duration": "16.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStylePairOfNthChildSelector.html"
     },
     {
-        "duration": "17.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStylePartialAttributeMatchingSelector.html"
     },
     {
-        "duration": "17.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleQualifiedDataAttributeSelector.html"
     },
     {
-        "duration": "16.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleQualifiedDataAttributeWithValueSelector.html"
     },
     {
-        "duration": "21.0",
+        "duration": "8.0",
         "name": "blink_perf.css/ChangeStyleShallowTree.html"
     },
     {
-        "duration": "17.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleSingleClassSelector.html"
     },
     {
-        "duration": "15.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleSingleNthChildSelector.html"
     },
     {
-        "duration": "17.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleSinglePseudoSelector.html"
     },
     {
-        "duration": "18.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleUniversalSelector.html"
     },
     {
-        "duration": "16.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleUnqualifiedDataAttributeSelector.html"
     },
     {
-        "duration": "17.0",
+        "duration": "7.0",
         "name": "blink_perf.css/ChangeStyleUnqualifiedDataAttributeWithValueSelector.html"
     },
     {
-        "duration": "30.0",
+        "duration": "16.0",
         "name": "blink_perf.css/ClassDescendantSelector.html"
     },
     {
-        "duration": "22.0",
+        "duration": "12.0",
         "name": "blink_perf.css/ClassInvalidation.html"
     },
     {
-        "duration": "12.0",
+        "duration": "5.0",
         "name": "blink_perf.css/CustomPropertiesCascade.html"
     },
     {
-        "duration": "13.0",
+        "duration": "6.0",
         "name": "blink_perf.css/CustomPropertiesDependency.html"
     },
     {
-        "duration": "15.0",
+        "duration": "6.0",
         "name": "blink_perf.css/CustomPropertiesIdenticalSets.html"
     },
     {
-        "duration": "14.0",
+        "duration": "5.0",
         "name": "blink_perf.css/CustomPropertiesNonRootInheritance.html"
     },
     {
-        "duration": "13.0",
+        "duration": "5.0",
         "name": "blink_perf.css/CustomPropertiesPendingSubstitution.html"
     },
     {
-        "duration": "14.0",
+        "duration": "5.0",
         "name": "blink_perf.css/CustomPropertiesRootInheritance.html"
     },
     {
-        "duration": "12.0",
+        "duration": "5.0",
         "name": "blink_perf.css/CustomPropertiesVarAlias.html"
     },
     {
-        "duration": "12.0",
+        "duration": "6.0",
         "name": "blink_perf.css/ExplicitInheritance.html"
     },
     {
-        "duration": "24.0",
+        "duration": "13.0",
         "name": "blink_perf.css/FocusUpdate.html"
     },
     {
-        "duration": "22.0",
+        "duration": "12.0",
         "name": "blink_perf.css/HasDescendantInAncestorPositionInvalidation.html"
     },
     {
-        "duration": "23.0",
+        "duration": "12.0",
         "name": "blink_perf.css/HasDescendantInvalidation.html"
     },
     {
-        "duration": "20.0",
+        "duration": "10.0",
         "name": "blink_perf.css/HasDescendantInvalidationAllSubjects.html"
     },
     {
-        "duration": "21.0",
+        "duration": "13.0",
         "name": "blink_perf.css/HasDescendantInvalidationMultipleSubjects.html"
     },
     {
-        "duration": "20.0",
+        "duration": "11.0",
+        "name": "blink_perf.css/HasDescendantInvalidationWith1NonMatchingHasRule.html"
+    },
+    {
+        "duration": "12.0",
+        "name": "blink_perf.css/HasDescendantInvalidationWithMultipleNonMatchingHasRules.html"
+    },
+    {
+        "duration": "12.0",
+        "name": "blink_perf.css/HasDescendantInvalidationWithoutNonMatchingHasRule.html"
+    },
+    {
+        "duration": "10.0",
         "name": "blink_perf.css/HasInvalidationFiltering.html"
     },
     {
-        "duration": "23.0",
+        "duration": "13.0",
         "name": "blink_perf.css/HasSiblingDescendantInvalidation.html"
     },
     {
-        "duration": "19.0",
+        "duration": "10.0",
         "name": "blink_perf.css/HasSiblingDescendantInvalidationAllSubjects.html"
     },
     {
-        "duration": "21.0",
+        "duration": "11.0",
         "name": "blink_perf.css/HasSiblingInvalidation.html"
     },
     {
-        "duration": "20.0",
+        "duration": "10.0",
         "name": "blink_perf.css/HasSiblingInvalidationAllSubjects.html"
     },
     {
-        "duration": "12.0",
+        "duration": "5.0",
         "name": "blink_perf.css/HighlightInheritanceRecalc.html"
     },
     {
-        "duration": "25.0",
+        "duration": "10.0",
         "name": "blink_perf.css/HighlightInheritanceSelected.html"
     },
     {
-        "duration": "16.0",
+        "duration": "8.0",
         "name": "blink_perf.css/LoadBootstrapBlog.html"
     },
     {
-        "duration": "18.0",
+        "duration": "8.0",
         "name": "blink_perf.css/LoadMaterializeStarterPage.html"
     },
     {
-        "duration": "18.0",
+        "duration": "13.0",
         "name": "blink_perf.css/LoadSemanticPageExample.html"
     },
     {
-        "duration": "19.0",
+        "duration": "12.0",
+        "name": "blink_perf.css/ModifySelectorText.html"
+    },
+    {
+        "duration": "7.0",
+        "name": "blink_perf.css/NamedContainerLookup.html"
+    },
+    {
+        "duration": "10.0",
         "name": "blink_perf.css/PseudoClassSelectors.html"
     },
     {
-        "duration": "40.0",
+        "duration": "15.0",
         "name": "blink_perf.css/SelectorCountScaling.html"
     },
     {
-        "duration": "23.0",
+        "duration": "15.0",
         "name": "blink_perf.dom/custom-element-default-style-with-shadow.html"
     },
     {
-        "duration": "15.0",
+        "duration": "9.0",
         "name": "blink_perf.dom/custom-element-default-style.html"
     },
     {
-        "duration": "20.0",
+        "duration": "17.0",
         "name": "blink_perf.dom/insert-text-with-dir-auto.html"
     },
     {
-        "duration": "26.0",
+        "duration": "11.0",
         "name": "blink_perf.dom/long-sibling-list.html"
     },
     {
-        "duration": "14.0",
+        "duration": "6.0",
         "name": "blink_perf.dom/modify-element-classname.html"
     },
     {
-        "duration": "16.0",
+        "duration": "5.0",
         "name": "blink_perf.dom/modify-element-id.html"
     },
     {
-        "duration": "12.0",
+        "duration": "5.0",
         "name": "blink_perf.dom/modify-element-title.html"
     },
     {
-        "duration": "15.0",
+        "duration": "8.0",
         "name": "blink_perf.dom/replace-text-with-dir-auto.html"
     },
     {
-        "duration": "16.0",
+        "duration": "9.0",
         "name": "blink_perf.dom/select-multiple-add.html"
     },
     {
-        "duration": "17.0",
+        "duration": "9.0",
         "name": "blink_perf.dom/select-single-add.html"
     },
     {
-        "duration": "15.0",
+        "duration": "9.0",
         "name": "blink_perf.dom/select-single-remove.html"
     },
     {
-        "duration": "24.0",
+        "duration": "14.0",
         "name": "blink_perf.events/EventsDispatching.html"
     },
     {
-        "duration": "18.0",
+        "duration": "11.0",
         "name": "blink_perf.events/EventsDispatchingInDeeplyNestedV1ShadowTrees.html"
     },
     {
-        "duration": "56.0",
+        "duration": "24.0",
         "name": "blink_perf.events/EventsDispatchingInV1ShadowTrees.html"
     },
     {
-        "duration": "33.0",
+        "duration": "21.0",
         "name": "blink_perf.events/hit-test-lots-of-layers.html"
     },
     {
-        "duration": "16.0",
+        "duration": "9.0",
         "name": "blink_perf.events/is-input-pending-default-events.html"
     },
     {
-        "duration": "18.0",
+        "duration": "9.0",
         "name": "blink_perf.events/is-input-pending-include-continuous-events.html"
     },
     {
-        "duration": "35.0",
+        "duration": "21.0",
         "name": "blink_perf.image_decoder/decode-gif.html"
     },
     {
-        "duration": "27.0",
+        "duration": "12.0",
         "name": "blink_perf.image_decoder/decode-jpeg-h1v1.html"
     },
     {
-        "duration": "27.0",
+        "duration": "12.0",
         "name": "blink_perf.image_decoder/decode-jpeg-h1v2.html"
     },
     {
-        "duration": "27.0",
+        "duration": "12.0",
         "name": "blink_perf.image_decoder/decode-jpeg-h2v1.html"
     },
     {
-        "duration": "19.0",
+        "duration": "12.0",
         "name": "blink_perf.image_decoder/decode-jpeg-h2v2.html"
     },
     {
-        "duration": "24.0",
+        "duration": "23.0",
         "name": "blink_perf.image_decoder/decode-lossless-webp.html"
     },
     {
@@ -588,15 +640,15 @@
         "name": "blink_perf.image_decoder/decode-png-palette-opaque.html"
     },
     {
-        "duration": "13.0",
+        "duration": "12.0",
         "name": "blink_perf.image_decoder/decode-png-palette.html"
     },
     {
-        "duration": "24.0",
+        "duration": "23.0",
         "name": "blink_perf.image_decoder/decode-png.html"
     },
     {
-        "duration": "15.0",
+        "duration": "14.0",
         "name": "blink_perf.layout/ArabicLineLayout.html"
     },
     {
@@ -628,27 +680,27 @@
         "name": "blink_perf.layout/attach-inlines.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/auto-grid-lots-of-data.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/auto-grid-lots-of-spanning-data.html"
     },
     {
-        "duration": "8.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/chapter-reflow-once-random.html"
     },
     {
-        "duration": "11.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/chapter-reflow-once.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/chapter-reflow-thrice.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/chapter-reflow-twice.html"
     },
     {
@@ -664,7 +716,7 @@
         "name": "blink_perf.layout/contain-content-style-change.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/css-contain-change-text-different-subtree-root.html"
     },
     {
@@ -672,11 +724,11 @@
         "name": "blink_perf.layout/css-contain-change-text-without-subtree-root.html"
     },
     {
-        "duration": "10.0",
+        "duration": "8.0",
         "name": "blink_perf.layout/css-contain-change-text.html"
     },
     {
-        "duration": "5.0",
+        "duration": "4.0",
         "name": "blink_perf.layout/culled-inline-bounding-rects.html"
     },
     {
@@ -696,15 +748,15 @@
         "name": "blink_perf.layout/editing_append_single_line.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.layout/editing_delete.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.layout/editing_insert.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.layout/editing_prepend.html"
     },
     {
@@ -716,71 +768,71 @@
         "name": "blink_perf.layout/fit-content-change-available-size-text.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/fixed-grid-lots-of-data.html"
     },
     {
-        "duration": "11.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/fixed-grid-lots-of-stretched-data.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-column-nowrap.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-column-wrap.html"
     },
     {
-        "duration": "11.0",
+        "duration": "8.0",
         "name": "blink_perf.layout/flexbox-deeply-nested-column-flow.html"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-hittest.html"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-input.html"
     },
     {
-        "duration": "11.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-lots-of-data.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-nested-rows-and-columns-auto-overflow.html"
     },
     {
-        "duration": "11.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-row-nowrap.html"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/flexbox-row-stretch-height-definite.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-row-stretch-height-indefinite.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.layout/flexbox-row-wrap.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.layout/flexbox-with-stretch-layout.html"
     },
     {
-        "duration": "18.0",
+        "duration": "19.0",
         "name": "blink_perf.layout/flexbox_with_list_item.html"
     },
     {
-        "duration": "11.0",
+        "duration": "6.0",
         "name": "blink_perf.layout/floats_100_100.html"
     },
     {
-        "duration": "11.0",
+        "duration": "8.0",
         "name": "blink_perf.layout/floats_100_100_nested.html"
     },
     {
@@ -804,11 +856,11 @@
         "name": "blink_perf.layout/floats_2_100_nested.html"
     },
     {
-        "duration": "7.0",
+        "duration": "6.0",
         "name": "blink_perf.layout/floats_50_100.html"
     },
     {
-        "duration": "7.0",
+        "duration": "6.0",
         "name": "blink_perf.layout/floats_50_100_nested.html"
     },
     {
@@ -816,27 +868,27 @@
         "name": "blink_perf.layout/floats_show_hide.html"
     },
     {
-        "duration": "12.0",
+        "duration": "10.0",
         "name": "blink_perf.layout/grid-nested-baseline.html"
     },
     {
-        "duration": "16.0",
+        "duration": "10.0",
         "name": "blink_perf.layout/grid-with-block-constraints-dependence.html"
     },
     {
-        "duration": "11.0",
+        "duration": "13.0",
         "name": "blink_perf.layout/hindi-line-layout.html"
     },
     {
-        "duration": "6.0",
+        "duration": "7.0",
         "name": "blink_perf.layout/hittest-block-children.html"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "blink_perf.layout/hittest-nested-inline-blocks-listbased.html"
     },
     {
-        "duration": "7.0",
+        "duration": "8.0",
         "name": "blink_perf.layout/japanese-kokoro-insert.html"
     },
     {
@@ -848,123 +900,131 @@
         "name": "blink_perf.layout/large-spanning-grid-item.html"
     },
     {
-        "duration": "15.0",
+        "duration": "19.0",
         "name": "blink_perf.layout/large-table-with-collapsed-borders-and-colspans-wider-than-table.html"
     },
     {
-        "duration": "15.0",
+        "duration": "20.0",
         "name": "blink_perf.layout/large-table-with-collapsed-borders-and-colspans.html"
     },
     {
-        "duration": "15.0",
+        "duration": "22.0",
         "name": "blink_perf.layout/large-table-with-collapsed-borders-and-no-colspans.html"
     },
     {
-        "duration": "12.0",
+        "duration": "16.0",
         "name": "blink_perf.layout/latin-ebook-resize.html"
     },
     {
-        "duration": "7.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/latin-ebook.html"
     },
     {
-        "duration": "4.0",
+        "duration": "7.0",
         "name": "blink_perf.layout/layers_overlap_2d.html"
     },
     {
-        "duration": "4.0",
+        "duration": "7.0",
         "name": "blink_perf.layout/layers_overlap_3d.html"
     },
     {
-        "duration": "4.0",
+        "duration": "7.0",
         "name": "blink_perf.layout/line-layout-fit-content-break-word.html"
     },
     {
-        "duration": "9.0",
+        "duration": "14.0",
         "name": "blink_perf.layout/line-layout-fit-content.html"
     },
     {
-        "duration": "14.0",
+        "duration": "19.0",
         "name": "blink_perf.layout/line-layout-line-height.html"
     },
     {
-        "duration": "10.0",
+        "duration": "13.0",
         "name": "blink_perf.layout/line-layout-repeat-append-select.html"
     },
     {
-        "duration": "8.0",
+        "duration": "11.0",
         "name": "blink_perf.layout/line-layout-repeat-append.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/line-layout.html"
     },
     {
-        "duration": "3.0",
+        "duration": "6.0",
         "name": "blink_perf.layout/long-line-nowrap-collapse.html"
     },
     {
-        "duration": "3.0",
+        "duration": "6.0",
         "name": "blink_perf.layout/long-line-nowrap-spans-collapse.html"
     },
     {
-        "duration": "8.0",
+        "duration": "13.0",
         "name": "blink_perf.layout/long-line-nowrap.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/many-block-children-auto-inline-size.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/many-block-children-fixed-inline-size.html"
     },
     {
-        "duration": "9.0",
+        "duration": "11.0",
         "name": "blink_perf.layout/many-block-children-rebuild-box-tree.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/multicol/balance-forced-breaks.html"
     },
     {
-        "duration": "9.0",
+        "duration": "24.0",
+        "name": "blink_perf.layout/multicol/balance-list-items-with-tall-marker.html"
+    },
+    {
+        "duration": "13.0",
+        "name": "blink_perf.layout/multicol/deeply-nested-tables-2.html"
+    },
+    {
+        "duration": "12.0",
         "name": "blink_perf.layout/multicol/deeply-nested-tables.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/multicol/fixed-height-with-spanner-and-nested-tables.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/multicol/lots-of-small-nested-unbreakable-blocks-autofill.html"
     },
     {
-        "duration": "9.0",
+        "duration": "11.0",
         "name": "blink_perf.layout/multicol/lots-of-small-unbreakable-blocks-autofill.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/multicol/lots-of-small-unbreakable-blocks-balanced.html"
     },
     {
-        "duration": "9.0",
+        "duration": "13.0",
         "name": "blink_perf.layout/multicol/lots-of-text-autofill.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/multicol/lots-of-text-balanced-orphans-widows.html"
     },
     {
-        "duration": "10.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/multicol/lots-of-text-balanced.html"
     },
     {
-        "duration": "9.0",
+        "duration": "13.0",
         "name": "blink_perf.layout/multicol/nested-forced-breaks.html"
     },
     {
-        "duration": "8.0",
+        "duration": "11.0",
         "name": "blink_perf.layout/multicol/tall-content-short-columns-realistic.html"
     },
     {
@@ -972,151 +1032,167 @@
         "name": "blink_perf.layout/multicol/tall-content-short-columns.html"
     },
     {
-        "duration": "10.0",
+        "duration": "13.0",
         "name": "blink_perf.layout/nested-blocks-with-percent-height-and-max-height.html"
     },
     {
-        "duration": "9.0",
+        "duration": "13.0",
         "name": "blink_perf.layout/nested-grid-lots-of-tracks.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/nested-grid.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/nested-percent-height-tables.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.layout/nested-tables-with-overflow-auto.html"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "blink_perf.layout/ruby.html"
     },
     {
-        "duration": "78.0",
+        "duration": "99.0",
         "name": "blink_perf.layout/subtree-detaching.html"
     },
     {
-        "duration": "7.0",
+        "duration": "11.0",
         "name": "blink_perf.layout/subtree-layout-scrollable-area.html"
     },
     {
-        "duration": "8.0",
+        "duration": "12.0",
+        "name": "blink_perf.layout/text-wrap-balance.html"
+    },
+    {
+        "duration": "12.0",
         "name": "blink_perf.layout/vertical-japanese-kokoro-insert.html"
     },
     {
-        "duration": "3.0",
+        "duration": "6.0",
         "name": "blink_perf.layout/word-break-break-all.html"
     },
     {
-        "duration": "3.0",
+        "duration": "6.0",
         "name": "blink_perf.layout/word-break-break-word.html"
     },
     {
-        "duration": "3.0",
+        "duration": "6.0",
         "name": "blink_perf.layout/word-wrap-break-word.html"
     },
     {
-        "duration": "16.0",
+        "duration": "25.0",
         "name": "blink_perf.owp_storage/blob-perf-files.html"
     },
     {
-        "duration": "14.0",
+        "duration": "23.0",
         "name": "blink_perf.owp_storage/blob-perf-ipc.html"
     },
     {
-        "duration": "11.0",
+        "duration": "20.0",
         "name": "blink_perf.owp_storage/blob-perf-shm.html"
     },
     {
-        "duration": "14.0",
+        "duration": "23.0",
         "name": "blink_perf.owp_storage/blob-perf-tiny.html"
     },
     {
-        "duration": "15.0",
+        "duration": "24.0",
         "name": "blink_perf.owp_storage/idb-load-docs.html"
     },
     {
-        "duration": "17.0",
+        "duration": "24.0",
         "name": "blink_perf.paint/appending-text.html"
     },
     {
-        "duration": "23.0",
+        "duration": "34.0",
         "name": "blink_perf.paint/color-changes.html"
     },
     {
-        "duration": "20.0",
+        "duration": "26.0",
         "name": "blink_perf.paint/complex-content-slow-scroll.html"
     },
     {
-        "duration": "26.0",
+        "duration": "33.0",
         "name": "blink_perf.paint/contain-update-layer-tree.html"
     },
     {
-        "duration": "16.0",
+        "duration": "22.0",
         "name": "blink_perf.paint/containment-resize.html"
     },
     {
-        "duration": "13.0",
+        "duration": "5.0",
         "name": "blink_perf.paint/custom-highlights-baseline.html"
     },
     {
-        "duration": "13.0",
+        "duration": "5.0",
+        "name": "blink_perf.paint/custom-highlights-heavy.html"
+    },
+    {
+        "duration": "5.0",
         "name": "blink_perf.paint/custom-highlights.html"
     },
     {
-        "duration": "17.0",
+        "duration": "23.0",
         "name": "blink_perf.paint/fixed-and-many-layers-scroll.html"
     },
     {
-        "duration": "19.0",
+        "duration": "28.0",
         "name": "blink_perf.paint/large-table-background-change.html"
     },
     {
-        "duration": "21.0",
+        "duration": "31.0",
         "name": "blink_perf.paint/large-table-collapsed-border-change.html"
     },
     {
-        "duration": "14.0",
+        "duration": "20.0",
         "name": "blink_perf.paint/modify-selection.html"
     },
     {
-        "duration": "18.0",
+        "duration": "27.0",
         "name": "blink_perf.paint/paint-offset-changes.html"
     },
     {
-        "duration": "15.0",
+        "duration": "30.0",
         "name": "blink_perf.paint/spelling-errors.html"
     },
     {
-        "duration": "23.0",
+        "duration": "34.0",
         "name": "blink_perf.paint/transform-changes.html"
     },
     {
-        "duration": "14.0",
+        "duration": "5.0",
+        "name": "blink_perf.paint/wavy-decorations-long.html"
+    },
+    {
+        "duration": "5.0",
+        "name": "blink_perf.paint/wavy-decorations-many.html"
+    },
+    {
+        "duration": "21.0",
         "name": "blink_perf.parser/css-parser-yui.html"
     },
     {
-        "duration": "19.0",
+        "duration": "18.0",
         "name": "blink_perf.parser/declarative-shadow-dom-cloning.html"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "blink_perf.parser/declarative-shadow-dom.html"
     },
     {
-        "duration": "8.0",
+        "duration": "14.0",
         "name": "blink_perf.parser/html-parser.html"
     },
     {
-        "duration": "53.0",
+        "duration": "55.0",
         "name": "blink_perf.parser/html5-full-render.html"
     },
     {
-        "duration": "16.0",
+        "duration": "23.0",
         "name": "blink_perf.parser/iframe-append-remove.html"
     },
     {
@@ -1124,15 +1200,15 @@
         "name": "blink_perf.parser/innerHTML-setter-siblings.html"
     },
     {
-        "duration": "9.0",
+        "duration": "11.0",
         "name": "blink_perf.parser/innerHTML-setter.html"
     },
     {
-        "duration": "8.0",
+        "duration": "10.0",
         "name": "blink_perf.parser/query-selector-all-attribute-complex.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.parser/query-selector-all-attribute.html"
     },
     {
@@ -1144,7 +1220,7 @@
         "name": "blink_perf.parser/query-selector-all-class-first.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-all-class-last.html"
     },
     {
@@ -1184,11 +1260,11 @@
         "name": "blink_perf.parser/query-selector-first.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-id-deep.html"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "blink_perf.parser/query-selector-id-last.html"
     },
     {
@@ -1196,11 +1272,11 @@
         "name": "blink_perf.parser/query-selector-last.html"
     },
     {
-        "duration": "9.0",
+        "duration": "8.0",
         "name": "blink_perf.parser/simple-url.html"
     },
     {
-        "duration": "11.0",
+        "duration": "10.0",
         "name": "blink_perf.parser/textarea-parsing.html"
     },
     {
@@ -1208,11 +1284,11 @@
         "name": "blink_perf.parser/tiny-innerHTML.html"
     },
     {
-        "duration": "9.0",
+        "duration": "15.0",
         "name": "blink_perf.parser/url-parser.html"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "blink_perf.parser/xml-parser.html"
     },
     {
@@ -1228,11 +1304,11 @@
         "name": "blink_perf.shadow_dom/imperative-api-assign.html"
     },
     {
-        "duration": "2.0",
+        "duration": "3.0",
         "name": "blink_perf.shadow_dom/imperative-api-assigned-elements.html"
     },
     {
-        "duration": "2.0",
+        "duration": "3.0",
         "name": "blink_perf.shadow_dom/imperative-api-assigned-slot.html"
     },
     {
@@ -1252,23 +1328,23 @@
         "name": "blink_perf.shadow_dom/imperative-api-detail-summary.html"
     },
     {
-        "duration": "2.0",
+        "duration": "3.0",
         "name": "blink_perf.shadow_dom/imperative-api-insertbefore.html"
     },
     {
-        "duration": "2.0",
+        "duration": "3.0",
         "name": "blink_perf.shadow_dom/imperative-api.html"
     },
     {
-        "duration": "277.0",
+        "duration": "255.0",
         "name": "blink_perf.shadow_dom/imperative-shadow-dom-overhead.html"
     },
     {
-        "duration": "239.0",
+        "duration": "217.0",
         "name": "blink_perf.shadow_dom/shadow-dom-overhead-iframe.html"
     },
     {
-        "duration": "80.0",
+        "duration": "60.0",
         "name": "blink_perf.shadow_dom/shadow-dom-overhead.html"
     },
     {
@@ -1292,11 +1368,11 @@
         "name": "blink_perf.shadow_dom/style-sheet-insert.html"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "blink_perf.shadow_dom/v1-distribution-disconnected-and-reconnected.html"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "blink_perf.shadow_dom/v1-distribution.html"
     },
     {
@@ -1304,11 +1380,11 @@
         "name": "blink_perf.shadow_dom/v1-host-child-append.html"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "blink_perf.shadow_dom/v1-large-deep-distribution.html"
     },
     {
-        "duration": "12.0",
+        "duration": "14.0",
         "name": "blink_perf.shadow_dom/v1-large-deep-layout.html"
     },
     {
@@ -1376,7 +1452,7 @@
         "name": "blink_perf.svg/AzLizardBenjiPark.html"
     },
     {
-        "duration": "5.0",
+        "duration": "6.0",
         "name": "blink_perf.svg/Bamboo.html"
     },
     {
@@ -1432,7 +1508,7 @@
         "name": "blink_perf.svg/HereGear.html"
     },
     {
-        "duration": "6.0",
+        "duration": "7.0",
         "name": "blink_perf.svg/MtSaintHelens.html"
     },
     {
@@ -1468,63 +1544,75 @@
         "name": "blink_perf.svg/Worldcup.html"
     },
     {
-        "duration": "21.0",
+        "duration": "25.0",
         "name": "blink_perf.webaudio/audio-buffer-source-node.html"
     },
     {
-        "duration": "103.0",
+        "duration": "110.0",
         "name": "blink_perf.webaudio/audio-worklet-node.html"
     },
     {
-        "duration": "103.0",
+        "duration": "115.0",
         "name": "blink_perf.webaudio/biquad-filter-node.html"
     },
     {
-        "duration": "81.0",
+        "duration": "92.0",
         "name": "blink_perf.webaudio/dynamics-compressor-node-knee.html"
     },
     {
-        "duration": "82.0",
+        "duration": "95.0",
         "name": "blink_perf.webaudio/dynamics-compressor-node-post-knee.html"
     },
     {
-        "duration": "81.0",
+        "duration": "90.0",
         "name": "blink_perf.webaudio/dynamics-compressor-node-pre-knee.html"
     },
     {
-        "duration": "102.0",
+        "duration": "111.0",
         "name": "blink_perf.webaudio/gain-node.html"
     },
     {
-        "duration": "38.0",
+        "duration": "42.0",
         "name": "blink_perf.webaudio/panner-node.html"
     },
     {
-        "duration": "19.0",
+        "duration": "20.0",
         "name": "blink_perf.webaudio/timeline-insert-event.html"
     },
     {
-        "duration": "14.0",
+        "duration": "15.0",
         "name": "blink_perf.webcodecs/hardware-video-encoding.html"
     },
     {
-        "duration": "8.0",
+        "duration": "7.0",
         "name": "blink_perf.webcodecs/software-video-encoding.html"
     },
     {
-        "duration": "2.0",
+        "duration": "4.0",
+        "name": "blink_perf.webcodecs/videoFrame-batch-copyTo-canvas.html"
+    },
+    {
+        "duration": "3.0",
+        "name": "blink_perf.webcodecs/videoFrame-copyTo-canvas.html"
+    },
+    {
+        "duration": "3.0",
+        "name": "blink_perf.webcodecs/videoFrame-copyTo-videoDecoder.html"
+    },
+    {
+        "duration": "3.0",
         "name": "blink_perf.webcodecs/videoFrame-createImageBitmap-canvas.html"
     },
     {
-        "duration": "2.0",
+        "duration": "3.0",
         "name": "blink_perf.webcodecs/videoFrame-createImageBitmap-imageDecoder.html"
     },
     {
-        "duration": "2.0",
+        "duration": "3.0",
         "name": "blink_perf.webcodecs/videoFrame-createImageBitmap-videoDecoder.html"
     },
     {
-        "duration": "4.0",
+        "duration": "5.0",
         "name": "blink_perf.webcodecs/videoFrame-drawImage-imageDecoder.html"
     },
     {
@@ -1544,7 +1632,7 @@
         "name": "blink_perf.webgl/binding-buffer-sub-data.html"
     },
     {
-        "duration": "3.0",
+        "duration": "4.0",
         "name": "blink_perf.webgl/binding-draw-arrays.html"
     },
     {
@@ -1560,7 +1648,7 @@
         "name": "blink_perf.webgl_fast_call/binding-buffer-sub-data.html"
     },
     {
-        "duration": "3.0",
+        "duration": "4.0",
         "name": "blink_perf.webgl_fast_call/binding-draw-arrays.html"
     },
     {
@@ -1568,102 +1656,122 @@
         "name": "blink_perf.webgl_fast_call/binding-typed-array-uniforms.html"
     },
     {
-        "duration": "9.0",
+        "duration": "12.0",
         "name": "blink_perf.webgpu/binding-draw.html"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "blink_perf.webgpu_fast_call/binding-draw.html"
     },
     {
-        "duration": "30.0",
+        "duration": "27.0",
         "name": "desktop_ui/new_tab_page:loading"
     },
     {
-        "duration": "25.0",
+        "duration": "27.0",
         "name": "desktop_ui/omnibox:pedal"
     },
     {
-        "duration": "24.0",
+        "duration": "21.0",
         "name": "desktop_ui/omnibox:scoped_search"
     },
     {
-        "duration": "23.0",
+        "duration": "20.0",
         "name": "desktop_ui/omnibox:search"
     },
     {
-        "duration": "16.0",
+        "duration": "13.0",
         "name": "desktop_ui/side_search:measure_memory"
     },
     {
-        "duration": "16.0",
+        "duration": "13.0",
         "name": "desktop_ui/side_search:navigation"
     },
     {
-        "duration": "282.0",
+        "duration": "289.0",
         "name": "desktop_ui/tab_search:100_recently_closed"
     },
     {
-        "duration": "41.0",
+        "duration": "56.0",
         "name": "desktop_ui/tab_search:10_recently_closed"
     },
     {
-        "duration": "147.0",
+        "duration": "161.0",
         "name": "desktop_ui/tab_search:50_recently_closed"
     },
     {
-        "duration": "20.0",
+        "duration": "18.0",
         "name": "desktop_ui/tab_search:clean_slate"
     },
     {
-        "duration": "66.0",
+        "duration": "61.0",
         "name": "desktop_ui/tab_search:close_and_open:2020"
     },
     {
-        "duration": "53.0",
+        "duration": "13.0",
         "name": "desktop_ui/tab_search:close_and_open:loading:2020"
     },
     {
-        "duration": "29.0",
+        "duration": "25.0",
         "name": "desktop_ui/tab_search:measure_memory:2tab_search"
     },
     {
-        "duration": "29.0",
+        "duration": "25.0",
         "name": "desktop_ui/tab_search:measure_memory:3tab_search"
     },
     {
-        "duration": "28.0",
+        "duration": "24.0",
         "name": "desktop_ui/tab_search:measure_memory:after"
     },
     {
-        "duration": "29.0",
+        "duration": "25.0",
         "name": "desktop_ui/tab_search:measure_memory:before"
     },
     {
-        "duration": "32.0",
+        "duration": "29.0",
         "name": "desktop_ui/tab_search:measure_memory:multiwindow"
     },
     {
-        "duration": "82.0",
+        "duration": "88.0",
         "name": "desktop_ui/tab_search:scroll_up_and_down:2020"
     },
     {
-        "duration": "61.0",
+        "duration": "76.0",
         "name": "desktop_ui/tab_search:top10:2020"
     },
     {
-        "duration": "36.0",
+        "duration": "46.0",
         "name": "desktop_ui/tab_search:top10:loading:2020"
     },
     {
-        "duration": "10.0",
+        "duration": "24.0",
         "name": "desktop_ui/tab_search:top50:2020"
     },
     {
-        "duration": "97.0",
+        "duration": "107.0",
         "name": "desktop_ui/tab_search:top50:loading:2020"
     },
     {
+        "duration": "22.0",
+        "name": "desktop_ui/webui_tab_strip:clean_slate"
+    },
+    {
+        "duration": "24.0",
+        "name": "desktop_ui/webui_tab_strip:measure_memory"
+    },
+    {
+        "duration": "26.0",
+        "name": "desktop_ui/webui_tab_strip:measure_memory:2window"
+    },
+    {
+        "duration": "55.0",
+        "name": "desktop_ui/webui_tab_strip:top10:2020"
+    },
+    {
+        "duration": "57.0",
+        "name": "desktop_ui/webui_tab_strip:top10:loading:2020"
+    },
+    {
         "duration": "5.0",
         "name": "dummy_benchmark.noisy_benchmark_1/dummy_page.html"
     },
@@ -1672,115 +1780,115 @@
         "name": "dummy_benchmark.stable_benchmark_1/dummy_page.html"
     },
     {
-        "duration": "321.0",
+        "duration": "287.0",
         "name": "jetstream2/JetStream2"
     },
     {
-        "duration": "44.0",
+        "duration": "31.0",
         "name": "loading.desktop/24h_cold"
     },
     {
-        "duration": "54.0",
+        "duration": "40.0",
         "name": "loading.desktop/24h_warm"
     },
     {
-        "duration": "53.0",
+        "duration": "40.0",
         "name": "loading.desktop/AirBnB_cold"
     },
     {
-        "duration": "70.0",
+        "duration": "55.0",
         "name": "loading.desktop/AirBnB_warm"
     },
     {
-        "duration": "31.0",
+        "duration": "29.0",
         "name": "loading.desktop/Aljayyash_cold"
     },
     {
-        "duration": "38.0",
+        "duration": "35.0",
         "name": "loading.desktop/Aljayyash_warm"
     },
     {
-        "duration": "40.0",
+        "duration": "17.0",
         "name": "loading.desktop/AllRecipes_cold"
     },
     {
-        "duration": "82.0",
+        "duration": "38.0",
         "name": "loading.desktop/AllRecipes_warm"
     },
     {
-        "duration": "64.0",
+        "duration": "39.0",
         "name": "loading.desktop/ArsTechnica_cold"
     },
     {
-        "duration": "79.0",
+        "duration": "63.0",
         "name": "loading.desktop/ArsTechnica_warm"
     },
     {
-        "duration": "55.0",
+        "duration": "30.0",
         "name": "loading.desktop/Baidu_cold"
     },
     {
-        "duration": "48.0",
+        "duration": "50.0",
         "name": "loading.desktop/Baidu_warm"
     },
     {
-        "duration": "61.0",
+        "duration": "40.0",
         "name": "loading.desktop/Bhaskar_cold"
     },
     {
-        "duration": "59.0",
+        "duration": "51.0",
         "name": "loading.desktop/Bhaskar_warm"
     },
     {
-        "duration": "48.0",
+        "duration": "30.0",
         "name": "loading.desktop/Chosun_cold"
     },
     {
-        "duration": "58.0",
+        "duration": "38.0",
         "name": "loading.desktop/Chosun_warm"
     },
     {
-        "duration": "41.0",
+        "duration": "50.0",
         "name": "loading.desktop/Colorado.edu_cold"
     },
     {
-        "duration": "49.0",
+        "duration": "40.0",
         "name": "loading.desktop/Colorado.edu_warm"
     },
     {
-        "duration": "47.0",
+        "duration": "35.0",
         "name": "loading.desktop/Danawa_cold"
     },
     {
-        "duration": "81.0",
+        "duration": "39.0",
         "name": "loading.desktop/Danawa_warm"
     },
     {
-        "duration": "46.0",
+        "duration": "30.0",
         "name": "loading.desktop/Daum_cold"
     },
     {
-        "duration": "54.0",
+        "duration": "38.0",
         "name": "loading.desktop/Daum_warm"
     },
     {
-        "duration": "48.0",
+        "duration": "30.0",
         "name": "loading.desktop/Donga_cold"
     },
     {
-        "duration": "58.0",
+        "duration": "37.0",
         "name": "loading.desktop/Donga_warm"
     },
     {
-        "duration": "63.0",
+        "duration": "35.0",
         "name": "loading.desktop/Economist_cold"
     },
     {
-        "duration": "79.0",
+        "duration": "49.0",
         "name": "loading.desktop/Economist_warm"
     },
     {
-        "duration": "42.0",
+        "duration": "33.0",
         "name": "loading.desktop/Elmundo_cold"
     },
     {
@@ -1788,407 +1896,407 @@
         "name": "loading.desktop/Elmundo_warm"
     },
     {
-        "duration": "42.0",
+        "duration": "31.0",
         "name": "loading.desktop/FC2Blog_cold"
     },
     {
-        "duration": "51.0",
+        "duration": "39.0",
         "name": "loading.desktop/FC2Blog_warm"
     },
     {
-        "duration": "57.0",
+        "duration": "32.0",
         "name": "loading.desktop/FIFA_cold"
     },
     {
-        "duration": "66.0",
+        "duration": "42.0",
         "name": "loading.desktop/FIFA_warm"
     },
     {
-        "duration": "43.0",
+        "duration": "40.0",
         "name": "loading.desktop/FarsNews_cold"
     },
     {
-        "duration": "42.0",
+        "duration": "38.0",
         "name": "loading.desktop/FarsNews_warm"
     },
     {
-        "duration": "42.0",
+        "duration": "30.0",
         "name": "loading.desktop/Flickr_cold"
     },
     {
-        "duration": "51.0",
+        "duration": "39.0",
         "name": "loading.desktop/Flickr_warm"
     },
     {
-        "duration": "40.0",
+        "duration": "41.0",
         "name": "loading.desktop/FlipKart_cold"
     },
     {
-        "duration": "49.0",
+        "duration": "38.0",
         "name": "loading.desktop/FlipKart_warm"
     },
     {
-        "duration": "48.0",
+        "duration": "42.0",
         "name": "loading.desktop/Free.fr_cold"
     },
     {
-        "duration": "42.0",
+        "duration": "37.0",
         "name": "loading.desktop/Free.fr_warm"
     },
     {
-        "duration": "50.0",
+        "duration": "36.0",
         "name": "loading.desktop/Google_cold"
     },
     {
-        "duration": "60.0",
+        "duration": "44.0",
         "name": "loading.desktop/Google_warm"
     },
     {
-        "duration": "68.0",
+        "duration": "29.0",
         "name": "loading.desktop/HTML5Rocks_cold"
     },
     {
-        "duration": "60.0",
+        "duration": "35.0",
         "name": "loading.desktop/HTML5Rocks_warm"
     },
     {
-        "duration": "31.0",
+        "duration": "33.0",
         "name": "loading.desktop/Haraj_cold"
     },
     {
-        "duration": "38.0",
+        "duration": "34.0",
         "name": "loading.desktop/Haraj_warm"
     },
     {
-        "duration": "42.0",
+        "duration": "31.0",
         "name": "loading.desktop/HatenaBookmark_cold"
     },
     {
-        "duration": "51.0",
+        "duration": "40.0",
         "name": "loading.desktop/HatenaBookmark_warm"
     },
     {
-        "duration": "46.0",
+        "duration": "33.0",
         "name": "loading.desktop/IGN_cold"
     },
     {
-        "duration": "55.0",
+        "duration": "41.0",
         "name": "loading.desktop/IGN_warm"
     },
     {
-        "duration": "43.0",
+        "duration": "31.0",
         "name": "loading.desktop/IMDB_cold"
     },
     {
-        "duration": "53.0",
+        "duration": "42.0",
         "name": "loading.desktop/IMDB_warm"
     },
     {
-        "duration": "37.0",
+        "duration": "31.0",
         "name": "loading.desktop/IndiaTimes_cold"
     },
     {
-        "duration": "46.0",
+        "duration": "41.0",
         "name": "loading.desktop/IndiaTimes_warm"
     },
     {
-        "duration": "43.0",
+        "duration": "31.0",
         "name": "loading.desktop/Kakaku_cold"
     },
     {
-        "duration": "54.0",
+        "duration": "40.0",
         "name": "loading.desktop/Kakaku_warm"
     },
     {
-        "duration": "61.0",
+        "duration": "38.0",
         "name": "loading.desktop/Kenh14_cold"
     },
     {
-        "duration": "32.0",
+        "duration": "18.0",
         "name": "loading.desktop/Kenh14_warm"
     },
     {
-        "duration": "36.0",
+        "duration": "31.0",
         "name": "loading.desktop/Mercadolivre_cold"
     },
     {
-        "duration": "44.0",
+        "duration": "38.0",
         "name": "loading.desktop/Mercadolivre_warm"
     },
     {
-        "duration": "53.0",
+        "duration": "34.0",
         "name": "loading.desktop/Naver_cold"
     },
     {
-        "duration": "54.0",
+        "duration": "37.0",
         "name": "loading.desktop/Naver_warm"
     },
     {
-        "duration": "21.0",
+        "duration": "18.0",
         "name": "loading.desktop/Orange_cold"
     },
     {
-        "duration": "21.0",
+        "duration": "18.0",
         "name": "loading.desktop/Orange_warm"
     },
     {
-        "duration": "56.0",
+        "duration": "42.0",
         "name": "loading.desktop/Pantip_cold"
     },
     {
-        "duration": "66.0",
+        "duration": "39.0",
         "name": "loading.desktop/Pantip_warm"
     },
     {
-        "duration": "43.0",
+        "duration": "38.0",
         "name": "loading.desktop/PremierLeague_cold"
     },
     {
-        "duration": "53.0",
+        "duration": "42.0",
         "name": "loading.desktop/PremierLeague_warm"
     },
     {
-        "duration": "46.0",
+        "duration": "33.0",
         "name": "loading.desktop/QQ_cold"
     },
     {
-        "duration": "57.0",
+        "duration": "43.0",
         "name": "loading.desktop/QQ_warm"
     },
     {
-        "duration": "58.0",
+        "duration": "31.0",
         "name": "loading.desktop/REI_cold"
     },
     {
-        "duration": "67.0",
+        "duration": "40.0",
         "name": "loading.desktop/REI_warm"
     },
     {
-        "duration": "42.0",
+        "duration": "31.0",
         "name": "loading.desktop/Ruten_cold"
     },
     {
-        "duration": "50.0",
+        "duration": "38.0",
         "name": "loading.desktop/Ruten_warm"
     },
     {
-        "duration": "45.0",
+        "duration": "33.0",
         "name": "loading.desktop/Sina_cold"
     },
     {
-        "duration": "56.0",
+        "duration": "44.0",
         "name": "loading.desktop/Sina_warm"
     },
     {
-        "duration": "47.0",
+        "duration": "36.0",
         "name": "loading.desktop/Taobao_cold"
     },
     {
-        "duration": "63.0",
+        "duration": "48.0",
         "name": "loading.desktop/Taobao_warm"
     },
     {
-        "duration": "63.0",
+        "duration": "34.0",
         "name": "loading.desktop/TheOnion_cold"
     },
     {
-        "duration": "40.0",
+        "duration": "18.0",
         "name": "loading.desktop/TheOnion_warm"
     },
     {
-        "duration": "73.0",
+        "duration": "36.0",
         "name": "loading.desktop/TheVerge_cold"
     },
     {
-        "duration": "61.0",
+        "duration": "49.0",
         "name": "loading.desktop/TheVerge_warm"
     },
     {
-        "duration": "48.0",
+        "duration": "36.0",
         "name": "loading.desktop/TicketMaster_cold"
     },
     {
-        "duration": "60.0",
+        "duration": "48.0",
         "name": "loading.desktop/TicketMaster_warm"
     },
     {
-        "duration": "70.0",
+        "duration": "31.0",
         "name": "loading.desktop/Vietnamnet_cold"
     },
     {
-        "duration": "69.0",
+        "duration": "49.0",
         "name": "loading.desktop/Vietnamnet_warm"
     },
     {
-        "duration": "48.0",
+        "duration": "36.0",
         "name": "loading.desktop/Vnexpress_cold"
     },
     {
-        "duration": "61.0",
+        "duration": "53.0",
         "name": "loading.desktop/Vnexpress_warm"
     },
     {
-        "duration": "26.0",
+        "duration": "20.0",
         "name": "loading.desktop/Walgreens_cold"
     },
     {
-        "duration": "26.0",
+        "duration": "20.0",
         "name": "loading.desktop/Walgreens_warm"
     },
     {
-        "duration": "35.0",
+        "duration": "30.0",
         "name": "loading.desktop/Yandex_cold"
     },
     {
-        "duration": "43.0",
+        "duration": "38.0",
         "name": "loading.desktop/Yandex_warm"
     },
     {
-        "duration": "44.0",
+        "duration": "33.0",
         "name": "loading.desktop/amazon.co.jp_cold"
     },
     {
-        "duration": "56.0",
+        "duration": "45.0",
         "name": "loading.desktop/amazon.co.jp_warm"
     },
     {
-        "duration": "45.0",
+        "duration": "33.0",
         "name": "loading.desktop/ja.wikipedia_cold"
     },
     {
-        "duration": "57.0",
+        "duration": "48.0",
         "name": "loading.desktop/ja.wikipedia_warm"
     },
     {
-        "duration": "48.0",
+        "duration": "30.0",
         "name": "loading.desktop/money.cnn_cold"
     },
     {
-        "duration": "63.0",
+        "duration": "39.0",
         "name": "loading.desktop/money.cnn_warm"
     },
     {
-        "duration": "37.0",
+        "duration": "31.0",
         "name": "loading.desktop/ru.wikipedia_cold"
     },
     {
-        "duration": "46.0",
+        "duration": "40.0",
         "name": "loading.desktop/ru.wikipedia_warm"
     },
     {
-        "duration": "44.0",
+        "duration": "38.0",
         "name": "loading.desktop/uol.com.br_cold"
     },
     {
-        "duration": "60.0",
+        "duration": "53.0",
         "name": "loading.desktop/uol.com.br_warm"
     },
     {
-        "duration": "41.0",
+        "duration": "31.0",
         "name": "loading.desktop/yahoo.co.jp_cold"
     },
     {
-        "duration": "50.0",
+        "duration": "39.0",
         "name": "loading.desktop/yahoo.co.jp_warm"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "media.desktop/mse.html?media=aac_audio.mp4"
     },
     {
-        "duration": "19.0",
+        "duration": "22.0",
         "name": "media.desktop/mse.html?media=aac_audio.mp4,h264_video.mp4"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "media.desktop/mse.html?media=h264_video.mp4"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "media.desktop/mse.html?media=tulip0.av1.mp4"
     },
     {
-        "duration": "19.0",
+        "duration": "21.0",
         "name": "media.desktop/mse.html?media=tulip2.vp9.webm"
     },
     {
-        "duration": "147.0",
+        "duration": "141.0",
         "name": "media.desktop/video.html?src=boat_1080p60fps_vp9.webm"
     },
     {
-        "duration": "33.0",
+        "duration": "27.0",
         "name": "media.desktop/video.html?src=crowd1080.mp4"
     },
     {
-        "duration": "35.0",
+        "duration": "29.0",
         "name": "media.desktop/video.html?src=crowd1080.webm"
     },
     {
-        "duration": "32.0",
+        "duration": "26.0",
         "name": "media.desktop/video.html?src=crowd1080_vp9.webm"
     },
     {
-        "duration": "146.0",
+        "duration": "139.0",
         "name": "media.desktop/video.html?src=foodmarket_720p30fps.mp4"
     },
     {
-        "duration": "10.0",
+        "duration": "13.0",
         "name": "media.desktop/video.html?src=garden2_10s.mp4&seek"
     },
     {
-        "duration": "10.0",
+        "duration": "13.0",
         "name": "media.desktop/video.html?src=garden2_10s.webm&seek"
     },
     {
-        "duration": "10.0",
+        "duration": "13.0",
         "name": "media.desktop/video.html?src=smpte_3840x2160_60fps_vp9.webm&seek"
     },
     {
-        "duration": "10.0",
+        "duration": "13.0",
         "name": "media.desktop/video.html?src=tulip0.av1.mp4"
     },
     {
-        "duration": "15.0",
+        "duration": "18.0",
         "name": "media.desktop/video.html?src=tulip0.av1.mp4&seek"
     },
     {
-        "duration": "38.0",
+        "duration": "32.0",
         "name": "media.desktop/video.html?src=tulip2.m4a&type=audio"
     },
     {
-        "duration": "38.0",
+        "duration": "32.0",
         "name": "media.desktop/video.html?src=tulip2.mp3&type=audio"
     },
     {
-        "duration": "23.0",
+        "duration": "17.0",
         "name": "media.desktop/video.html?src=tulip2.mp3&type=audio&seek"
     },
     {
-        "duration": "39.0",
+        "duration": "33.0",
         "name": "media.desktop/video.html?src=tulip2.mp4"
     },
     {
-        "duration": "81.0",
+        "duration": "75.0",
         "name": "media.desktop/video.html?src=tulip2.mp4&busyjs"
     },
     {
-        "duration": "38.0",
+        "duration": "32.0",
         "name": "media.desktop/video.html?src=tulip2.ogg&type=audio"
     },
     {
-        "duration": "23.0",
+        "duration": "17.0",
         "name": "media.desktop/video.html?src=tulip2.ogg&type=audio&seek"
     },
     {
-        "duration": "39.0",
+        "duration": "33.0",
         "name": "media.desktop/video.html?src=tulip2.vp9.webm"
     },
     {
-        "duration": "26.0",
+        "duration": "27.0",
         "name": "media.desktop/video.html?src=tulip2.vp9.webm&background"
     },
     {
-        "duration": "39.0",
+        "duration": "33.0",
         "name": "media.desktop/video.html?src=tulip2.vp9.webm_WiFi"
     },
     {
@@ -2196,11 +2304,11 @@
         "name": "memory.desktop/TrivialAnimationPageSharedPageState"
     },
     {
-        "duration": "24.0",
+        "duration": "23.0",
         "name": "memory.desktop/TrivialBlinkingCursorPageSharedPageState"
     },
     {
-        "duration": "24.0",
+        "duration": "25.0",
         "name": "memory.desktop/TrivialBlurAnimationPageSharedPageState"
     },
     {
@@ -2208,7 +2316,7 @@
         "name": "memory.desktop/TrivialCanvasPageSharedPageState"
     },
     {
-        "duration": "25.0",
+        "duration": "24.0",
         "name": "memory.desktop/TrivialFullscreenVideoPageSharedPageState"
     },
     {
@@ -2216,83 +2324,83 @@
         "name": "memory.desktop/TrivialGifPageSharedPageState"
     },
     {
-        "duration": "25.0",
+        "duration": "24.0",
         "name": "memory.desktop/TrivialScrollingPageSharedPageState"
     },
     {
-        "duration": "24.0",
+        "duration": "23.0",
         "name": "memory.desktop/TrivialWebGLPageSharedPageState"
     },
     {
-        "duration": "64.0",
+        "duration": "56.0",
         "name": "memory.desktop/WebWorker"
     },
     {
-        "duration": "49.0",
+        "duration": "47.0",
         "name": "octane/Octane"
     },
     {
-        "duration": "46.0",
+        "duration": "48.0",
         "name": "power.desktop/TrivialAnimationPageSharedPageState"
     },
     {
-        "duration": "46.0",
+        "duration": "48.0",
         "name": "power.desktop/TrivialBlinkingCursorPageSharedPageState"
     },
     {
-        "duration": "46.0",
+        "duration": "48.0",
         "name": "power.desktop/TrivialBlurAnimationPageSharedPageState"
     },
     {
-        "duration": "46.0",
+        "duration": "48.0",
         "name": "power.desktop/TrivialCanvasPageSharedPageState"
     },
     {
-        "duration": "47.0",
+        "duration": "49.0",
         "name": "power.desktop/TrivialFullscreenVideoPageSharedPageState"
     },
     {
-        "duration": "46.0",
+        "duration": "48.0",
         "name": "power.desktop/TrivialGifPageSharedPageState"
     },
     {
-        "duration": "49.0",
+        "duration": "51.0",
         "name": "power.desktop/TrivialScrollingPageSharedPageState"
     },
     {
-        "duration": "46.0",
+        "duration": "48.0",
         "name": "power.desktop/TrivialWebGLPageSharedPageState"
     },
     {
-        "duration": "13.0",
+        "duration": "14.0",
         "name": "power.desktop/abcnews"
     },
     {
-        "duration": "48.0",
+        "duration": "61.0",
         "name": "power.desktop/indiatimes"
     },
     {
-        "duration": "47.0",
+        "duration": "48.0",
         "name": "power.desktop/instagram"
     },
     {
-        "duration": "47.0",
+        "duration": "48.0",
         "name": "power.desktop/microsoft"
     },
     {
-        "duration": "50.0",
+        "duration": "48.0",
         "name": "power.desktop/sina"
     },
     {
-        "duration": "51.0",
+        "duration": "54.0",
         "name": "power.desktop/slideshare"
     },
     {
-        "duration": "49.0",
+        "duration": "48.0",
         "name": "power.desktop/uol"
     },
     {
-        "duration": "28.0",
+        "duration": "29.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/amazon.html"
     },
     {
@@ -2308,35 +2416,35 @@
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/cnn.html"
     },
     {
-        "duration": "13.0",
+        "duration": "11.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/ebay.html"
     },
     {
-        "duration": "23.0",
+        "duration": "22.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/espn.html"
     },
     {
-        "duration": "12.0",
+        "duration": "14.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/facebook.html"
     },
     {
-        "duration": "12.0",
+        "duration": "13.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/gmail.html"
     },
     {
-        "duration": "11.0",
+        "duration": "10.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/google.html"
     },
     {
-        "duration": "8.0",
+        "duration": "9.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/googlecalendar.html"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/googledocs.html"
     },
     {
-        "duration": "18.0",
+        "duration": "17.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/googleimagesearch.html"
     },
     {
@@ -2344,11 +2452,11 @@
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/googleplus.html"
     },
     {
-        "duration": "10.0",
+        "duration": "11.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/linkedin.html"
     },
     {
-        "duration": "7.0",
+        "duration": "8.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/pinterest.html"
     },
     {
@@ -2356,11 +2464,11 @@
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/techcrunch.html"
     },
     {
-        "duration": "22.0",
+        "duration": "21.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/twitter.html"
     },
     {
-        "duration": "11.0",
+        "duration": "12.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/weather.html"
     },
     {
@@ -2368,15 +2476,15 @@
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/wikipedia.html"
     },
     {
-        "duration": "25.0",
+        "duration": "17.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/wordpress.html"
     },
     {
-        "duration": "15.0",
+        "duration": "16.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/yahooanswers.html"
     },
     {
-        "duration": "16.0",
+        "duration": "15.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/yahoogames.html"
     },
     {
@@ -2388,487 +2496,495 @@
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/yahoosports.html"
     },
     {
-        "duration": "18.0",
+        "duration": "19.0",
         "name": "rasterize_and_record_micro.top_25/file://static_top_25/youtube.html"
     },
     {
-        "duration": "53.0",
-        "name": "rendering.desktop/accu_weather_2018"
-    },
-    {
-        "duration": "57.0",
-        "name": "rendering.desktop/accu_weather_pinch_2018"
-    },
-    {
-        "duration": "47.0",
-        "name": "rendering.desktop/amazon_2018"
-    },
-    {
-        "duration": "45.0",
-        "name": "rendering.desktop/amazon_pinch_2018"
-    },
-    {
-        "duration": "45.0",
-        "name": "rendering.desktop/analog_clock_svg"
-    },
-    {
-        "duration": "51.0",
-        "name": "rendering.desktop/animometer_webgl"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/animometer_webgl_attrib_arrays"
-    },
-    {
-        "duration": "40.0",
-        "name": "rendering.desktop/animometer_webgl_fast_call"
-    },
-    {
-        "duration": "39.0",
-        "name": "rendering.desktop/animometer_webgl_indexed"
-    },
-    {
-        "duration": "38.0",
-        "name": "rendering.desktop/animometer_webgl_indexed_fast_call"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/animometer_webgl_indexed_multi_draw"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/animometer_webgl_indexed_multi_draw_base_vertex_base_instance"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/animometer_webgl_multi_draw"
-    },
-    {
-        "duration": "42.0",
-        "name": "rendering.desktop/aquarium"
-    },
-    {
-        "duration": "43.0",
-        "name": "rendering.desktop/aquarium_20k"
-    },
-    {
-        "duration": "43.0",
-        "name": "rendering.desktop/aquarium_20k_fast_call"
-    },
-    {
-        "duration": "38.0",
-        "name": "rendering.desktop/background_color_animation"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/background_color_animation_with_gradient"
-    },
-    {
-        "duration": "37.0",
-        "name": "rendering.desktop/balls_css_key_frame_animations"
-    },
-    {
-        "duration": "39.0",
-        "name": "rendering.desktop/balls_css_key_frame_animations_composited_transform"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/balls_css_transition_2_properties"
-    },
-    {
-        "duration": "37.0",
-        "name": "rendering.desktop/balls_css_transition_40_properties"
-    },
-    {
-        "duration": "37.0",
-        "name": "rendering.desktop/balls_css_transition_all_properties"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/balls_javascript_canvas"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/balls_javascript_css"
-    },
-    {
-        "duration": "37.0",
-        "name": "rendering.desktop/balls_svg_animations"
-    },
-    {
-        "duration": "37.0",
-        "name": "rendering.desktop/blob"
-    },
-    {
-        "duration": "48.0",
-        "name": "rendering.desktop/blogspot_2018"
-    },
-    {
-        "duration": "40.0",
-        "name": "rendering.desktop/blogspot_pinch_2018"
-    },
-    {
-        "duration": "30.0",
-        "name": "rendering.desktop/blur_rotating_background"
-    },
-    {
-        "duration": "32.0",
-        "name": "rendering.desktop/booking.com_2018"
-    },
-    {
-        "duration": "32.0",
-        "name": "rendering.desktop/booking_pinch_2018"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/bouncing_balls_15"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/bouncing_balls_shadow"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/bouncing_clipped_rectangles"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/bouncing_gradient_circles"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/bouncing_png_images"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/bouncing_svg_images"
-    },
-    {
-        "duration": "20.0",
-        "name": "rendering.desktop/camera_to_webgl"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/canvas2d_to_texture.html"
-    },
-    {
-        "duration": "50.0",
-        "name": "rendering.desktop/canvas_05000_pixels_per_second"
-    },
-    {
-        "duration": "49.0",
-        "name": "rendering.desktop/canvas_10000_pixels_per_second"
-    },
-    {
-        "duration": "47.0",
-        "name": "rendering.desktop/canvas_20000_pixels_per_second"
-    },
-    {
-        "duration": "48.0",
-        "name": "rendering.desktop/canvas_40000_pixels_per_second"
-    },
-    {
-        "duration": "48.0",
-        "name": "rendering.desktop/canvas_60000_pixels_per_second"
-    },
-    {
-        "duration": "47.0",
-        "name": "rendering.desktop/canvas_75000_pixels_per_second"
-    },
-    {
-        "duration": "48.0",
-        "name": "rendering.desktop/canvas_90000_pixels_per_second"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/canvas_animation_no_clear"
-    },
-    {
-        "duration": "33.0",
-        "name": "rendering.desktop/canvas_arcs"
-    },
-    {
-        "duration": "38.0",
-        "name": "rendering.desktop/canvas_font_cycler"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/canvas_lines"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/canvas_to_blob"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/canvas_to_canvas_draw"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/cc_poster_circle"
-    },
-    {
-        "duration": "31.0",
-        "name": "rendering.desktop/cc_scroll_text_only"
-    },
-    {
-        "duration": "39.0",
-        "name": "rendering.desktop/chip_tune"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/cnn_2018"
-    },
-    {
-        "duration": "50.0",
-        "name": "rendering.desktop/cnn_pinch_2018"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/compositor_heavy_animation"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/crafty_mind"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/css_animations_many_keyframes"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/css_animations_simultaneous_inline_style"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/css_animations_simultaneous_new_element"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/css_animations_simultaneous_style_element"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/css_animations_simultaneous_updating_class"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/css_animations_staggered_infinite_iterations"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/css_animations_staggered_inline_style"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/css_animations_staggered_new_element"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/css_animations_staggered_style_element"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/css_animations_staggered_updating_class"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/css_animations_triggered_inline_style"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/css_animations_triggered_new_element"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/css_animations_triggered_style_element"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/css_animations_triggered_updating_class"
-    },
-    {
-        "duration": "36.0",
-        "name": "rendering.desktop/css_opacity_plus_n_layers_99"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/css_transitions_inline_style"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/css_transitions_new_element"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/css_transitions_staggered_inline_style"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/css_transitions_staggered_new_element"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/css_transitions_staggered_style_element"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/css_transitions_staggered_updating_class"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/css_transitions_style_element"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/css_transitions_triggered_inline_style"
-    },
-    {
-        "duration": "35.0",
-        "name": "rendering.desktop/css_transitions_triggered_new_element"
-    },
-    {
-        "duration": "51.0",
-        "name": "rendering.desktop/css_transitions_triggered_style_element"
-    },
-    {
-        "duration": "49.0",
-        "name": "rendering.desktop/css_transitions_triggered_updating_class"
-    },
-    {
-        "duration": "47.0",
-        "name": "rendering.desktop/css_transitions_updating_class"
-    },
-    {
-        "duration": "47.0",
-        "name": "rendering.desktop/css_value_type_color"
-    },
-    {
-        "duration": "48.0",
-        "name": "rendering.desktop/css_value_type_filter"
-    },
-    {
-        "duration": "60.0",
-        "name": "rendering.desktop/css_value_type_length"
-    },
-    {
-        "duration": "55.0",
-        "name": "rendering.desktop/css_value_type_length_complex"
-    },
-    {
-        "duration": "63.0",
-        "name": "rendering.desktop/css_value_type_length_simple"
-    },
-    {
-        "duration": "64.0",
-        "name": "rendering.desktop/css_value_type_path"
-    },
-    {
-        "duration": "60.0",
-        "name": "rendering.desktop/css_value_type_shadow"
-    },
-    {
-        "duration": "61.0",
-        "name": "rendering.desktop/css_value_type_transform_complex"
-    },
-    {
-        "duration": "60.0",
-        "name": "rendering.desktop/css_value_type_transform_simple"
-    },
-    {
-        "duration": "62.0",
-        "name": "rendering.desktop/docs_paper.html"
+        "duration": "331.0",
+        "name": "rendering.desktop.notracing/motionmark_ramp_composite"
     },
     {
         "duration": "66.0",
-        "name": "rendering.desktop/docs_resume.html"
+        "name": "rendering.desktop/accu_weather_2018"
     },
     {
-        "duration": "65.0",
-        "name": "rendering.desktop/docs_table.html"
+        "duration": "71.0",
+        "name": "rendering.desktop/accu_weather_pinch_2018"
+    },
+    {
+        "duration": "54.0",
+        "name": "rendering.desktop/amazon_2018"
+    },
+    {
+        "duration": "56.0",
+        "name": "rendering.desktop/amazon_pinch_2018"
+    },
+    {
+        "duration": "53.0",
+        "name": "rendering.desktop/analog_clock_svg"
+    },
+    {
+        "duration": "54.0",
+        "name": "rendering.desktop/animometer_webgl"
     },
     {
         "duration": "59.0",
-        "name": "rendering.desktop/draw_image"
+        "name": "rendering.desktop/animometer_webgl_attrib_arrays"
     },
     {
-        "duration": "59.0",
-        "name": "rendering.desktop/draw_image_not_pixel_aligned"
-    },
-    {
-        "duration": "64.0",
-        "name": "rendering.desktop/dynamic_canvas_to_hw_accelerated_canvas.html"
-    },
-    {
-        "duration": "72.0",
-        "name": "rendering.desktop/dynamic_cube_map"
-    },
-    {
-        "duration": "64.0",
-        "name": "rendering.desktop/dynamic_webgl_to_hw_accelerated_canvas.html"
-    },
-    {
-        "duration": "62.0",
-        "name": "rendering.desktop/earth"
-    },
-    {
-        "duration": "78.0",
-        "name": "rendering.desktop/ebay_2018"
-    },
-    {
-        "duration": "82.0",
-        "name": "rendering.desktop/ebay_pinch_2018"
+        "duration": "53.0",
+        "name": "rendering.desktop/animometer_webgl_fast_call"
     },
     {
         "duration": "70.0",
-        "name": "rendering.desktop/effect_games"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/espn_2018"
-    },
-    {
-        "duration": "34.0",
-        "name": "rendering.desktop/espn_pinch_2018"
-    },
-    {
-        "duration": "65.0",
-        "name": "rendering.desktop/extra_large_texture_uploads"
+        "name": "rendering.desktop/animometer_webgl_indexed"
     },
     {
         "duration": "68.0",
-        "name": "rendering.desktop/facebook_2018"
+        "name": "rendering.desktop/animometer_webgl_indexed_fast_call"
+    },
+    {
+        "duration": "59.0",
+        "name": "rendering.desktop/animometer_webgl_indexed_multi_draw"
+    },
+    {
+        "duration": "60.0",
+        "name": "rendering.desktop/animometer_webgl_indexed_multi_draw_base_vertex_base_instance"
+    },
+    {
+        "duration": "58.0",
+        "name": "rendering.desktop/animometer_webgl_multi_draw"
+    },
+    {
+        "duration": "72.0",
+        "name": "rendering.desktop/aquarium"
     },
     {
         "duration": "70.0",
+        "name": "rendering.desktop/aquarium_20k"
+    },
+    {
+        "duration": "86.0",
+        "name": "rendering.desktop/aquarium_20k_fast_call"
+    },
+    {
+        "duration": "50.0",
+        "name": "rendering.desktop/background_color_animation"
+    },
+    {
+        "duration": "48.0",
+        "name": "rendering.desktop/background_color_animation_with_gradient"
+    },
+    {
+        "duration": "50.0",
+        "name": "rendering.desktop/balls_css_key_frame_animations"
+    },
+    {
+        "duration": "54.0",
+        "name": "rendering.desktop/balls_css_key_frame_animations_composited_transform"
+    },
+    {
+        "duration": "50.0",
+        "name": "rendering.desktop/balls_css_transition_2_properties"
+    },
+    {
+        "duration": "50.0",
+        "name": "rendering.desktop/balls_css_transition_40_properties"
+    },
+    {
+        "duration": "50.0",
+        "name": "rendering.desktop/balls_css_transition_all_properties"
+    },
+    {
+        "duration": "32.0",
+        "name": "rendering.desktop/balls_javascript_canvas"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/balls_javascript_css"
+    },
+    {
+        "duration": "31.0",
+        "name": "rendering.desktop/balls_svg_animations"
+    },
+    {
+        "duration": "33.0",
+        "name": "rendering.desktop/blob"
+    },
+    {
+        "duration": "38.0",
+        "name": "rendering.desktop/blogspot_2018"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/blogspot_pinch_2018"
+    },
+    {
+        "duration": "22.0",
+        "name": "rendering.desktop/blur_rotating_background"
+    },
+    {
+        "duration": "26.0",
+        "name": "rendering.desktop/booking.com_2018"
+    },
+    {
+        "duration": "25.0",
+        "name": "rendering.desktop/booking_pinch_2018"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/bouncing_balls_15"
+    },
+    {
+        "duration": "28.0",
+        "name": "rendering.desktop/bouncing_balls_shadow"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/bouncing_clipped_rectangles"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/bouncing_gradient_circles"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/bouncing_png_images"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/bouncing_svg_images"
+    },
+    {
+        "duration": "15.0",
+        "name": "rendering.desktop/camera_to_webgl"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/canvas2d_to_texture.html"
+    },
+    {
+        "duration": "46.0",
+        "name": "rendering.desktop/canvas_05000_pixels_per_second"
+    },
+    {
+        "duration": "44.0",
+        "name": "rendering.desktop/canvas_10000_pixels_per_second"
+    },
+    {
+        "duration": "42.0",
+        "name": "rendering.desktop/canvas_20000_pixels_per_second"
+    },
+    {
+        "duration": "42.0",
+        "name": "rendering.desktop/canvas_40000_pixels_per_second"
+    },
+    {
+        "duration": "42.0",
+        "name": "rendering.desktop/canvas_60000_pixels_per_second"
+    },
+    {
+        "duration": "42.0",
+        "name": "rendering.desktop/canvas_75000_pixels_per_second"
+    },
+    {
+        "duration": "42.0",
+        "name": "rendering.desktop/canvas_90000_pixels_per_second"
+    },
+    {
+        "duration": "31.0",
+        "name": "rendering.desktop/canvas_animation_no_clear"
+    },
+    {
+        "duration": "28.0",
+        "name": "rendering.desktop/canvas_arcs"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/canvas_font_cycler"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/canvas_globalAlpha"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/canvas_lines"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/canvas_to_blob"
+    },
+    {
+        "duration": "30.0",
+        "name": "rendering.desktop/canvas_to_canvas_draw"
+    },
+    {
+        "duration": "31.0",
+        "name": "rendering.desktop/cc_poster_circle"
+    },
+    {
+        "duration": "25.0",
+        "name": "rendering.desktop/cc_scroll_text_only"
+    },
+    {
+        "duration": "33.0",
+        "name": "rendering.desktop/chip_tune"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/cnn_2018"
+    },
+    {
+        "duration": "15.0",
+        "name": "rendering.desktop/cnn_pinch_2018"
+    },
+    {
+        "duration": "28.0",
+        "name": "rendering.desktop/compositor_heavy_animation"
+    },
+    {
+        "duration": "33.0",
+        "name": "rendering.desktop/crafty_mind"
+    },
+    {
+        "duration": "32.0",
+        "name": "rendering.desktop/css_animations_many_keyframes"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/css_animations_simultaneous_inline_style"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/css_animations_simultaneous_new_element"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/css_animations_simultaneous_style_element"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/css_animations_simultaneous_updating_class"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/css_animations_staggered_infinite_iterations"
+    },
+    {
+        "duration": "32.0",
+        "name": "rendering.desktop/css_animations_staggered_inline_style"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_animations_staggered_new_element"
+    },
+    {
+        "duration": "40.0",
+        "name": "rendering.desktop/css_animations_staggered_style_element"
+    },
+    {
+        "duration": "40.0",
+        "name": "rendering.desktop/css_animations_staggered_updating_class"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_animations_triggered_inline_style"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_animations_triggered_new_element"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_animations_triggered_style_element"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_animations_triggered_updating_class"
+    },
+    {
+        "duration": "31.0",
+        "name": "rendering.desktop/css_opacity_plus_n_layers_99"
+    },
+    {
+        "duration": "38.0",
+        "name": "rendering.desktop/css_transitions_inline_style"
+    },
+    {
+        "duration": "38.0",
+        "name": "rendering.desktop/css_transitions_new_element"
+    },
+    {
+        "duration": "40.0",
+        "name": "rendering.desktop/css_transitions_staggered_inline_style"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_transitions_staggered_new_element"
+    },
+    {
+        "duration": "40.0",
+        "name": "rendering.desktop/css_transitions_staggered_style_element"
+    },
+    {
+        "duration": "40.0",
+        "name": "rendering.desktop/css_transitions_staggered_updating_class"
+    },
+    {
+        "duration": "38.0",
+        "name": "rendering.desktop/css_transitions_style_element"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_transitions_triggered_inline_style"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_transitions_triggered_new_element"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_transitions_triggered_style_element"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_transitions_triggered_updating_class"
+    },
+    {
+        "duration": "39.0",
+        "name": "rendering.desktop/css_transitions_updating_class"
+    },
+    {
+        "duration": "40.0",
+        "name": "rendering.desktop/css_value_type_color"
+    },
+    {
+        "duration": "40.0",
+        "name": "rendering.desktop/css_value_type_filter"
+    },
+    {
+        "duration": "42.0",
+        "name": "rendering.desktop/css_value_type_length"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_value_type_length_complex"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/css_value_type_length_simple"
+    },
+    {
+        "duration": "45.0",
+        "name": "rendering.desktop/css_value_type_path"
+    },
+    {
+        "duration": "42.0",
+        "name": "rendering.desktop/css_value_type_shadow"
+    },
+    {
+        "duration": "39.0",
+        "name": "rendering.desktop/css_value_type_transform_complex"
+    },
+    {
+        "duration": "39.0",
+        "name": "rendering.desktop/css_value_type_transform_simple"
+    },
+    {
+        "duration": "41.0",
+        "name": "rendering.desktop/docs_paper.html"
+    },
+    {
+        "duration": "40.0",
+        "name": "rendering.desktop/docs_resume.html"
+    },
+    {
+        "duration": "40.0",
+        "name": "rendering.desktop/docs_table.html"
+    },
+    {
+        "duration": "31.0",
+        "name": "rendering.desktop/draw_image"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/draw_image_not_pixel_aligned"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/dynamic_canvas_to_hw_accelerated_canvas.html"
+    },
+    {
+        "duration": "35.0",
+        "name": "rendering.desktop/dynamic_cube_map"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/dynamic_webgl_to_hw_accelerated_canvas.html"
+    },
+    {
+        "duration": "31.0",
+        "name": "rendering.desktop/earth"
+    },
+    {
+        "duration": "34.0",
+        "name": "rendering.desktop/ebay_2018"
+    },
+    {
+        "duration": "34.0",
+        "name": "rendering.desktop/ebay_pinch_2018"
+    },
+    {
+        "duration": "34.0",
+        "name": "rendering.desktop/effect_games"
+    },
+    {
+        "duration": "16.0",
+        "name": "rendering.desktop/espn_2018"
+    },
+    {
+        "duration": "16.0",
+        "name": "rendering.desktop/espn_pinch_2018"
+    },
+    {
+        "duration": "32.0",
+        "name": "rendering.desktop/extra_large_texture_uploads"
+    },
+    {
+        "duration": "29.0",
+        "name": "rendering.desktop/facebook_2018"
+    },
+    {
+        "duration": "29.0",
         "name": "rendering.desktop/facebook_pinch_2018"
     },
     {
-        "duration": "63.0",
+        "duration": "31.0",
         "name": "rendering.desktop/falling_particle_simulation_cpu.html"
     },
     {
-        "duration": "62.0",
+        "duration": "32.0",
         "name": "rendering.desktop/falling_particle_simulation_gpu.html"
     },
     {
-        "duration": "63.0",
+        "duration": "30.0",
         "name": "rendering.desktop/fill_clear_rect.html"
     },
     {
-        "duration": "65.0",
+        "duration": "29.0",
         "name": "rendering.desktop/fill_shapes"
     },
     {
-        "duration": "64.0",
+        "duration": "33.0",
         "name": "rendering.desktop/filter_terrain_svg"
     },
     {
-        "duration": "32.0",
+        "duration": "31.0",
         "name": "rendering.desktop/get_image_data_cpu.html"
     },
     {
-        "duration": "32.0",
+        "duration": "31.0",
         "name": "rendering.desktop/get_image_data_gpu.html"
     },
     {
@@ -2880,7 +2996,7 @@
         "name": "rendering.desktop/gmail_move_2018"
     },
     {
-        "duration": "36.0",
+        "duration": "33.0",
         "name": "rendering.desktop/gmail_pinch_2018"
     },
     {
@@ -2888,7 +3004,7 @@
         "name": "rendering.desktop/google_calendar_2018"
     },
     {
-        "duration": "29.0",
+        "duration": "27.0",
         "name": "rendering.desktop/google_calendar_pinch_2018"
     },
     {
@@ -2896,27 +3012,27 @@
         "name": "rendering.desktop/google_docs_2018"
     },
     {
-        "duration": "28.0",
+        "duration": "26.0",
         "name": "rendering.desktop/google_image_pinch_2018"
     },
     {
-        "duration": "28.0",
+        "duration": "26.0",
         "name": "rendering.desktop/google_image_search_2018"
     },
     {
-        "duration": "28.0",
+        "duration": "27.0",
         "name": "rendering.desktop/google_plus_2018"
     },
     {
-        "duration": "28.0",
+        "duration": "26.0",
         "name": "rendering.desktop/google_search_pinch_2018"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "rendering.desktop/google_web_search_2018"
     },
     {
-        "duration": "30.0",
+        "duration": "32.0",
         "name": "rendering.desktop/gpu_bound_shader.html"
     },
     {
@@ -2924,7 +3040,7 @@
         "name": "rendering.desktop/guimark_vector_chart"
     },
     {
-        "duration": "33.0",
+        "duration": "32.0",
         "name": "rendering.desktop/hakim"
     },
     {
@@ -2932,11 +3048,11 @@
         "name": "rendering.desktop/hw_accelerated_canvas_to_sw_canvas.html"
     },
     {
-        "duration": "50.0",
+        "duration": "39.0",
         "name": "rendering.desktop/ie_chalkboard"
     },
     {
-        "duration": "40.0",
+        "duration": "39.0",
         "name": "rendering.desktop/ie_pirate_mark"
     },
     {
@@ -2952,15 +3068,15 @@
         "name": "rendering.desktop/infinite_scroll_root_n_layers_99"
     },
     {
-        "duration": "33.0",
+        "duration": "30.0",
         "name": "rendering.desktop/jarro_doverson"
     },
     {
-        "duration": "61.0",
+        "duration": "24.0",
         "name": "rendering.desktop/jpeg_decoding_rgb_and_gpu_rasterization"
     },
     {
-        "duration": "59.0",
+        "duration": "24.0",
         "name": "rendering.desktop/jpeg_decoding_yuv_and_gpu_rasterization"
     },
     {
@@ -2968,7 +3084,7 @@
         "name": "rendering.desktop/js_full_screen_invalidation"
     },
     {
-        "duration": "33.0",
+        "duration": "34.0",
         "name": "rendering.desktop/js_opacity_plus_n_layers_99"
     },
     {
@@ -2976,7 +3092,7 @@
         "name": "rendering.desktop/js_paint_plus_n_layers_99"
     },
     {
-        "duration": "33.0",
+        "duration": "32.0",
         "name": "rendering.desktop/js_poster_circle"
     },
     {
@@ -2984,107 +3100,107 @@
         "name": "rendering.desktop/js_scroll_text_only"
     },
     {
-        "duration": "81.0",
+        "duration": "30.0",
         "name": "rendering.desktop/kevs_3d"
     },
     {
-        "duration": "64.0",
+        "duration": "29.0",
         "name": "rendering.desktop/keyframed_animations"
     },
     {
-        "duration": "67.0",
+        "duration": "32.0",
         "name": "rendering.desktop/large_texture_uploads"
     },
     {
-        "duration": "71.0",
+        "duration": "29.0",
         "name": "rendering.desktop/linkedin_2018"
     },
     {
-        "duration": "83.0",
+        "duration": "30.0",
         "name": "rendering.desktop/linkedin_pinch_2018"
     },
     {
-        "duration": "116.0",
+        "duration": "71.0",
         "name": "rendering.desktop/lost_crypt"
     },
     {
-        "duration": "108.0",
+        "duration": "64.0",
         "name": "rendering.desktop/lost_crypt_fast_call"
     },
     {
-        "duration": "62.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_0fps_impl_60fps"
     },
     {
-        "duration": "61.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_0fps_impl_60fps_no_update"
     },
     {
-        "duration": "61.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_0fps_impl_60fps_no_update_jank"
     },
     {
-        "duration": "61.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_0fps_with_jank_impl_0fps"
     },
     {
-        "duration": "61.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_15fps_impl_0fps"
     },
     {
-        "duration": "65.0",
+        "duration": "33.0",
         "name": "rendering.desktop/main_15fps_with_jank_impl_0fps"
     },
     {
-        "duration": "62.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_30fps_impl_0fps"
     },
     {
-        "duration": "63.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_30fps_impl_60fps"
     },
     {
-        "duration": "62.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_60fps_impl_0fps"
     },
     {
-        "duration": "62.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_60fps_impl_60fps"
     },
     {
-        "duration": "60.0",
+        "duration": "30.0",
         "name": "rendering.desktop/main_60fps_impl_60fps_no_update"
     },
     {
-        "duration": "65.0",
+        "duration": "32.0",
         "name": "rendering.desktop/main_60fps_impl_60fps_no_update_jank"
     },
     {
-        "duration": "79.0",
+        "duration": "47.0",
         "name": "rendering.desktop/main_60fps_with_extreme_jank_impl_0fps"
     },
     {
-        "duration": "68.0",
+        "duration": "32.0",
         "name": "rendering.desktop/main_60fps_with_jank_and_delay_impl_60fps"
     },
     {
-        "duration": "66.0",
+        "duration": "32.0",
         "name": "rendering.desktop/main_60fps_with_jank_impl_0fps"
     },
     {
-        "duration": "67.0",
+        "duration": "33.0",
         "name": "rendering.desktop/main_animations_half_presented"
     },
     {
-        "duration": "69.0",
+        "duration": "40.0",
         "name": "rendering.desktop/man_in_blue"
     },
     {
-        "duration": "77.0",
+        "duration": "33.0",
         "name": "rendering.desktop/many_images"
     },
     {
-        "duration": "68.0",
+        "duration": "33.0",
         "name": "rendering.desktop/many_planets_deep"
     },
     {
@@ -3092,263 +3208,295 @@
         "name": "rendering.desktop/maps_move_2018"
     },
     {
-        "duration": "74.0",
+        "duration": "33.0",
         "name": "rendering.desktop/maps_perf_test"
     },
     {
-        "duration": "68.0",
+        "duration": "32.0",
         "name": "rendering.desktop/medium_texture_uploads"
     },
     {
-        "duration": "64.0",
+        "duration": "29.0",
         "name": "rendering.desktop/megi_dish"
     },
     {
-        "duration": "104.0",
+        "duration": "72.0",
         "name": "rendering.desktop/microgame_fps"
     },
     {
-        "duration": "80.0",
+        "duration": "65.0",
         "name": "rendering.desktop/microgame_fps_fast_call"
     },
     {
-        "duration": "42.0",
+        "duration": "32.0",
         "name": "rendering.desktop/microsoft_asteroid_belt"
     },
     {
-        "duration": "40.0",
+        "duration": "39.0",
         "name": "rendering.desktop/microsoft_fireflies"
     },
     {
-        "duration": "39.0",
+        "duration": "31.0",
         "name": "rendering.desktop/microsoft_fish_ie_tank"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.desktop/microsoft_performance"
     },
     {
-        "duration": "39.0",
+        "duration": "33.0",
         "name": "rendering.desktop/microsoft_snow"
     },
     {
-        "duration": "37.0",
+        "duration": "30.0",
         "name": "rendering.desktop/microsoft_speed_reading"
     },
     {
-        "duration": "37.0",
+        "duration": "30.0",
         "name": "rendering.desktop/microsoft_tweet_map"
     },
     {
-        "duration": "40.0",
+        "duration": "33.0",
         "name": "rendering.desktop/microsoft_video_city"
     },
     {
-        "duration": "39.0",
+        "duration": "33.0",
         "name": "rendering.desktop/microsoft_worker_fountains"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.desktop/mix_10k"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.desktop/mix_blend_mode_animation_difference"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.desktop/mix_blend_mode_animation_hue"
     },
     {
-        "duration": "40.0",
+        "duration": "34.0",
         "name": "rendering.desktop/mix_blend_mode_animation_propagating_isolation"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.desktop/mix_blend_mode_animation_screen"
     },
     {
-        "duration": "37.0",
+        "duration": "31.0",
         "name": "rendering.desktop/motion_mark_canvas_fill_shapes"
     },
     {
-        "duration": "37.0",
+        "duration": "30.0",
         "name": "rendering.desktop/motion_mark_canvas_stroke_shapes"
     },
     {
-        "duration": "60.0",
+        "duration": "17.0",
+        "name": "rendering.desktop/motionmark_fixed_2_seconds_canvas_arcs"
+    },
+    {
+        "duration": "17.0",
+        "name": "rendering.desktop/motionmark_fixed_2_seconds_canvas_lines"
+    },
+    {
+        "duration": "17.0",
+        "name": "rendering.desktop/motionmark_fixed_2_seconds_design"
+    },
+    {
+        "duration": "17.0",
+        "name": "rendering.desktop/motionmark_fixed_2_seconds_images"
+    },
+    {
+        "duration": "17.0",
+        "name": "rendering.desktop/motionmark_fixed_2_seconds_leaves"
+    },
+    {
+        "duration": "17.0",
+        "name": "rendering.desktop/motionmark_fixed_2_seconds_multiply"
+    },
+    {
+        "duration": "17.0",
+        "name": "rendering.desktop/motionmark_fixed_2_seconds_paths"
+    },
+    {
+        "duration": "17.0",
+        "name": "rendering.desktop/motionmark_fixed_2_seconds_suits"
+    },
+    {
+        "duration": "67.0",
         "name": "rendering.desktop/motionmark_ramp_canvas_arcs"
     },
     {
-        "duration": "57.0",
+        "duration": "50.0",
         "name": "rendering.desktop/motionmark_ramp_canvas_lines"
     },
     {
-        "duration": "53.0",
+        "duration": "47.0",
         "name": "rendering.desktop/motionmark_ramp_design"
     },
     {
-        "duration": "53.0",
+        "duration": "47.0",
         "name": "rendering.desktop/motionmark_ramp_images"
     },
     {
-        "duration": "55.0",
+        "duration": "49.0",
         "name": "rendering.desktop/motionmark_ramp_leaves"
     },
     {
-        "duration": "57.0",
+        "duration": "50.0",
         "name": "rendering.desktop/motionmark_ramp_multiply"
     },
     {
-        "duration": "55.0",
+        "duration": "49.0",
         "name": "rendering.desktop/motionmark_ramp_paths"
     },
     {
-        "duration": "54.0",
+        "duration": "52.0",
         "name": "rendering.desktop/motionmark_ramp_suits"
     },
     {
-        "duration": "41.0",
+        "duration": "34.0",
         "name": "rendering.desktop/new_tilings"
     },
     {
-        "duration": "39.0",
+        "duration": "32.0",
         "name": "rendering.desktop/no_update_compositor_animation_with_janky_main_animation"
     },
     {
-        "duration": "46.0",
+        "duration": "40.0",
         "name": "rendering.desktop/non_opaque_background_compositor_thread_scrolling_00050_pixels_per_second"
     },
     {
-        "duration": "46.0",
+        "duration": "40.0",
         "name": "rendering.desktop/non_opaque_background_main_thread_scrolling_00050_pixels_per_second"
     },
     {
-        "duration": "42.0",
+        "duration": "36.0",
         "name": "rendering.desktop/nvidia_vertex_buffer_object"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.desktop/off_screen_main_60fps"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.desktop/off_screen_main_60fps_jank"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.desktop/offscreen_animation_no_damage"
     },
     {
-        "duration": "40.0",
+        "duration": "33.0",
         "name": "rendering.desktop/overlay_background_color_css_transitions_page"
     },
     {
-        "duration": "37.0",
+        "duration": "31.0",
         "name": "rendering.desktop/paint_worklet"
     },
     {
-        "duration": "39.0",
+        "duration": "33.0",
         "name": "rendering.desktop/particles"
     },
     {
-        "duration": "40.0",
+        "duration": "33.0",
         "name": "rendering.desktop/pinterest_2018"
     },
     {
-        "duration": "39.0",
+        "duration": "38.0",
         "name": "rendering.desktop/put_and_create_imagebitmap_from_imagedata"
     },
     {
-        "duration": "38.0",
+        "duration": "35.0",
         "name": "rendering.desktop/put_get_image_data"
     },
     {
-        "duration": "44.0",
+        "duration": "35.0",
         "name": "rendering.desktop/put_image_data.html"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.desktop/raf"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.desktop/raf_animation"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.desktop/raf_canvas"
     },
     {
-        "duration": "38.0",
+        "duration": "32.0",
         "name": "rendering.desktop/raf_touch_animation"
     },
     {
-        "duration": "40.0",
+        "duration": "31.0",
         "name": "rendering.desktop/repaint_amazon_2018"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.desktop/repaint_cnn_2018"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.desktop/repaint_facebook_2018"
     },
     {
-        "duration": "38.0",
+        "duration": "29.0",
         "name": "rendering.desktop/repaint_google_search_2018"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.desktop/repaint_instagram_2018"
     },
     {
-        "duration": "38.0",
+        "duration": "29.0",
         "name": "rendering.desktop/repaint_reddit_2018"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.desktop/repaint_theverge_2018"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.desktop/repaint_twitter_2018"
     },
     {
-        "duration": "37.0",
+        "duration": "28.0",
         "name": "rendering.desktop/repaint_wikipedia_2018"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.desktop/repaint_yahoo_homepage_2018"
     },
     {
-        "duration": "47.0",
+        "duration": "35.0",
         "name": "rendering.desktop/runway_2019"
     },
     {
-        "duration": "45.0",
+        "duration": "38.0",
         "name": "rendering.desktop/san_angeles"
     },
     {
-        "duration": "32.0",
+        "duration": "29.0",
         "name": "rendering.desktop/second_batch_js_heavy"
     },
     {
-        "duration": "32.0",
+        "duration": "29.0",
         "name": "rendering.desktop/second_batch_js_light"
     },
     {
-        "duration": "32.0",
+        "duration": "29.0",
         "name": "rendering.desktop/second_batch_js_medium"
     },
     {
-        "duration": "42.0",
+        "duration": "40.0",
         "name": "rendering.desktop/sheets_render.html"
     },
     {
-        "duration": "38.0",
+        "duration": "33.0",
         "name": "rendering.desktop/simple_text_page"
     },
     {
@@ -3356,223 +3504,223 @@
         "name": "rendering.desktop/simple_touch_drag"
     },
     {
-        "duration": "84.0",
+        "duration": "78.0",
         "name": "rendering.desktop/skelebuddies_wasm_2020"
     },
     {
-        "duration": "76.0",
+        "duration": "71.0",
         "name": "rendering.desktop/skelebuddies_wasm_2020_fast_call"
     },
     {
-        "duration": "40.0",
+        "duration": "36.0",
         "name": "rendering.desktop/small_texture_uploads"
     },
     {
-        "duration": "46.0",
+        "duration": "41.0",
         "name": "rendering.desktop/smash_cat"
     },
     {
-        "duration": "40.0",
+        "duration": "36.0",
         "name": "rendering.desktop/spielzeugz"
     },
     {
-        "duration": "41.0",
+        "duration": "36.0",
         "name": "rendering.desktop/static_canvas_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "41.0",
+        "duration": "36.0",
         "name": "rendering.desktop/static_webgl_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "40.0",
+        "duration": "36.0",
         "name": "rendering.desktop/stroke_shapes"
     },
     {
-        "duration": "37.0",
+        "duration": "31.0",
         "name": "rendering.desktop/sync_scroll_offset"
     },
     {
-        "duration": "53.0",
+        "duration": "47.0",
         "name": "rendering.desktop/techcrunch_2018"
     },
     {
-        "duration": "50.0",
+        "duration": "45.0",
         "name": "rendering.desktop/text_05000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "44.0",
         "name": "rendering.desktop/text_10000_pixels_per_second"
     },
     {
-        "duration": "46.0",
+        "duration": "42.0",
         "name": "rendering.desktop/text_20000_pixels_per_second"
     },
     {
-        "duration": "46.0",
+        "duration": "41.0",
         "name": "rendering.desktop/text_40000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "46.0",
         "name": "rendering.desktop/text_60000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "44.0",
         "name": "rendering.desktop/text_75000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "44.0",
         "name": "rendering.desktop/text_90000_pixels_per_second"
     },
     {
-        "duration": "54.0",
+        "duration": "51.0",
         "name": "rendering.desktop/text_constant_full_page_raster_05000_pixels_per_second"
     },
     {
-        "duration": "52.0",
+        "duration": "49.0",
         "name": "rendering.desktop/text_constant_full_page_raster_10000_pixels_per_second"
     },
     {
-        "duration": "49.0",
+        "duration": "46.0",
         "name": "rendering.desktop/text_constant_full_page_raster_20000_pixels_per_second"
     },
     {
-        "duration": "49.0",
+        "duration": "46.0",
         "name": "rendering.desktop/text_constant_full_page_raster_40000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "45.0",
         "name": "rendering.desktop/text_constant_full_page_raster_60000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "45.0",
         "name": "rendering.desktop/text_constant_full_page_raster_75000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "45.0",
         "name": "rendering.desktop/text_constant_full_page_raster_90000_pixels_per_second"
     },
     {
-        "duration": "39.0",
+        "duration": "36.0",
         "name": "rendering.desktop/text_fling_05000_pixels_per_second"
     },
     {
-        "duration": "36.0",
+        "duration": "35.0",
         "name": "rendering.desktop/text_fling_10000_pixels_per_second"
     },
     {
-        "duration": "36.0",
+        "duration": "35.0",
         "name": "rendering.desktop/text_fling_20000_pixels_per_second"
     },
     {
-        "duration": "50.0",
+        "duration": "48.0",
         "name": "rendering.desktop/text_hover_05000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "45.0",
         "name": "rendering.desktop/text_hover_10000_pixels_per_second"
     },
     {
-        "duration": "46.0",
+        "duration": "44.0",
         "name": "rendering.desktop/text_hover_20000_pixels_per_second"
     },
     {
-        "duration": "50.0",
+        "duration": "43.0",
         "name": "rendering.desktop/text_hover_40000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "45.0",
         "name": "rendering.desktop/text_hover_60000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "44.0",
         "name": "rendering.desktop/text_hover_75000_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "44.0",
         "name": "rendering.desktop/text_hover_90000_pixels_per_second"
     },
     {
-        "duration": "50.0",
+        "duration": "43.0",
         "name": "rendering.desktop/text_scrollbar_100_pixels_per_second"
     },
     {
-        "duration": "47.0",
+        "duration": "41.0",
         "name": "rendering.desktop/text_scrollbar_1200_pixels_per_second"
     },
     {
-        "duration": "47.0",
+        "duration": "39.0",
         "name": "rendering.desktop/text_scrollbar_200_pixels_per_second"
     },
     {
-        "duration": "47.0",
+        "duration": "39.0",
         "name": "rendering.desktop/text_scrollbar_2300_pixels_per_second"
     },
     {
-        "duration": "48.0",
+        "duration": "44.0",
         "name": "rendering.desktop/text_scrollbar_700_pixels_per_second"
     },
     {
-        "duration": "43.0",
+        "duration": "39.0",
         "name": "rendering.desktop/throughput_scrolling_active_handler"
     },
     {
-        "duration": "43.0",
+        "duration": "38.0",
         "name": "rendering.desktop/throughput_scrolling_composited"
     },
     {
-        "duration": "43.0",
+        "duration": "36.0",
         "name": "rendering.desktop/throughput_scrolling_passive_handler"
     },
     {
-        "duration": "43.0",
+        "duration": "36.0",
         "name": "rendering.desktop/throughput_scrolling_uncomposited"
     },
     {
-        "duration": "76.0",
+        "duration": "73.0",
         "name": "rendering.desktop/tiny_racing_v3_wasm_2020"
     },
     {
-        "duration": "76.0",
+        "duration": "68.0",
         "name": "rendering.desktop/tiny_racing_v3_wasm_2020_fast_call"
     },
     {
-        "duration": "42.0",
+        "duration": "35.0",
         "name": "rendering.desktop/toBlob_duration.html"
     },
     {
-        "duration": "42.0",
+        "duration": "35.0",
         "name": "rendering.desktop/toBlob_duration_jpeg.html"
     },
     {
-        "duration": "36.0",
+        "duration": "35.0",
         "name": "rendering.desktop/toBlob_small_canvas_in_worker.html"
     },
     {
-        "duration": "27.0",
+        "duration": "29.0",
         "name": "rendering.desktop/touch_handler_scrolling"
     },
     {
-        "duration": "30.0",
+        "duration": "32.0",
         "name": "rendering.desktop/transfer_from_imageBitmap.html"
     },
     {
-        "duration": "32.0",
+        "duration": "34.0",
         "name": "rendering.desktop/transform_transitions"
     },
     {
-        "duration": "30.0",
+        "duration": "32.0",
         "name": "rendering.desktop/transform_transitions_js_block"
     },
     {
-        "duration": "39.0",
+        "duration": "41.0",
         "name": "rendering.desktop/twitch_2018"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "rendering.desktop/twitch_pinch_2018"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.desktop/twitter_2018"
     },
     {
@@ -3580,67 +3728,67 @@
         "name": "rendering.desktop/twitter_pinch_2018"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "rendering.desktop/video_to_hw_accelerated_canvas"
     },
     {
-        "duration": "33.0",
+        "duration": "36.0",
         "name": "rendering.desktop/video_to_sub_texture"
     },
     {
-        "duration": "33.0",
+        "duration": "36.0",
         "name": "rendering.desktop/video_to_sub_texture_flip_and_premultiply"
     },
     {
-        "duration": "33.0",
+        "duration": "36.0",
         "name": "rendering.desktop/video_to_sub_texture_flip_y"
     },
     {
-        "duration": "33.0",
+        "duration": "36.0",
         "name": "rendering.desktop/video_to_sub_texture_premultiply"
     },
     {
-        "duration": "34.0",
+        "duration": "35.0",
         "name": "rendering.desktop/video_to_texture"
     },
     {
-        "duration": "31.0",
+        "duration": "33.0",
         "name": "rendering.desktop/web_animation_value_type_color"
     },
     {
-        "duration": "33.0",
+        "duration": "34.0",
         "name": "rendering.desktop/web_animation_value_type_length_3d"
     },
     {
-        "duration": "32.0",
+        "duration": "34.0",
         "name": "rendering.desktop/web_animation_value_type_length_complex"
     },
     {
-        "duration": "32.0",
+        "duration": "34.0",
         "name": "rendering.desktop/web_animation_value_type_length_simple"
     },
     {
-        "duration": "32.0",
+        "duration": "34.0",
         "name": "rendering.desktop/web_animation_value_type_path"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.desktop/web_animation_value_type_shadow"
     },
     {
-        "duration": "30.0",
+        "duration": "32.0",
         "name": "rendering.desktop/web_animation_value_type_transform_complex"
     },
     {
-        "duration": "30.0",
+        "duration": "32.0",
         "name": "rendering.desktop/web_animation_value_type_transform_simple"
     },
     {
-        "duration": "37.0",
+        "duration": "36.0",
         "name": "rendering.desktop/web_animations_many_keyframes"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.desktop/web_animations_set_current_time"
     },
     {
@@ -3652,35 +3800,35 @@
         "name": "rendering.desktop/web_animations_staggered_chaining"
     },
     {
-        "duration": "30.0",
+        "duration": "32.0",
         "name": "rendering.desktop/web_animations_staggered_infinite_iterations"
     },
     {
-        "duration": "33.0",
+        "duration": "34.0",
         "name": "rendering.desktop/web_animations_staggered_triggering_page"
     },
     {
-        "duration": "33.0",
+        "duration": "39.0",
         "name": "rendering.desktop/webgl_to_texture"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "rendering.desktop/webp_decoding_rgb_and_gpu_rasterization"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "rendering.desktop/webp_decoding_yuv_and_gpu_rasterization"
     },
     {
-        "duration": "31.0",
+        "duration": "34.0",
         "name": "rendering.desktop/wikipedia_2018"
     },
     {
-        "duration": "31.0",
+        "duration": "30.0",
         "name": "rendering.desktop/wordpress_2018"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "rendering.desktop/yahoo_answers_2018"
     },
     {
@@ -3692,43 +3840,43 @@
         "name": "rendering.desktop/yahoo_news_pinch_2018"
     },
     {
-        "duration": "18.0",
+        "duration": "12.0",
         "name": "rendering.desktop/yahoo_sports_2018"
     },
     {
-        "duration": "34.0",
+        "duration": "39.0",
         "name": "rendering.desktop/yahoo_sports_pinch_2018"
     },
     {
-        "duration": "18.0",
+        "duration": "12.0",
         "name": "rendering.desktop/youtube_2018"
     },
     {
-        "duration": "18.0",
+        "duration": "12.0",
         "name": "rendering.desktop/youtube_pinch_2018"
     },
     {
-        "duration": "67.0",
+        "duration": "57.0",
         "name": "speedometer-future/http://browserbench.org/Speedometer/"
     },
     {
-        "duration": "68.0",
+        "duration": "56.0",
         "name": "speedometer/http://browserbench.org/Speedometer/"
     },
     {
-        "duration": "144.0",
+        "duration": "101.0",
         "name": "speedometer2-future/Speedometer2"
     },
     {
-        "duration": "142.0",
+        "duration": "106.0",
         "name": "speedometer2/Speedometer2"
     },
     {
-        "duration": "45.0",
+        "duration": "41.0",
         "name": "system_health.common_desktop/browse:media:googleplaystore:2021"
     },
     {
-        "duration": "100.0",
+        "duration": "84.0",
         "name": "system_health.common_desktop/browse:media:imgur"
     },
     {
@@ -3736,55 +3884,55 @@
         "name": "system_health.common_desktop/browse:media:pinterest:2018"
     },
     {
-        "duration": "76.0",
+        "duration": "94.0",
         "name": "system_health.common_desktop/browse:media:tumblr:2018"
     },
     {
-        "duration": "14.0",
+        "duration": "18.0",
         "name": "system_health.common_desktop/browse:media:youtube:2019"
     },
     {
-        "duration": "76.0",
+        "duration": "80.0",
         "name": "system_health.common_desktop/browse:media:youtubetv:2019"
     },
     {
-        "duration": "91.0",
+        "duration": "89.0",
         "name": "system_health.common_desktop/browse:media:youtubetv_watch:2020"
     },
     {
-        "duration": "66.0",
+        "duration": "55.0",
         "name": "system_health.common_desktop/browse:news:cnn:2021"
     },
     {
-        "duration": "59.0",
+        "duration": "53.0",
         "name": "system_health.common_desktop/browse:news:flipboard:2020"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:news:hackernews:2020"
     },
     {
-        "duration": "94.0",
+        "duration": "83.0",
         "name": "system_health.common_desktop/browse:news:nytimes:2020"
     },
     {
-        "duration": "81.0",
+        "duration": "76.0",
         "name": "system_health.common_desktop/browse:news:reddit:2020"
     },
     {
-        "duration": "62.0",
+        "duration": "58.0",
         "name": "system_health.common_desktop/browse:search:google:2020"
     },
     {
-        "duration": "46.0",
+        "duration": "42.0",
         "name": "system_health.common_desktop/browse:search:google_india:2021"
     },
     {
-        "duration": "86.0",
+        "duration": "80.0",
         "name": "system_health.common_desktop/browse:social:facebook_infinite_scroll:2018"
     },
     {
-        "duration": "13.0",
+        "duration": "18.0",
         "name": "system_health.common_desktop/browse:social:tumblr_infinite_scroll:2018"
     },
     {
@@ -3792,335 +3940,335 @@
         "name": "system_health.common_desktop/browse:social:twitter:2018"
     },
     {
-        "duration": "71.0",
+        "duration": "76.0",
         "name": "system_health.common_desktop/browse:social:twitter_infinite_scroll:2018"
     },
     {
-        "duration": "72.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:tech:discourse_infinite_scroll:2018"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:tools:autocad:2021"
     },
     {
-        "duration": "48.0",
+        "duration": "43.0",
         "name": "system_health.common_desktop/browse:tools:docs_scrolling"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:tools:gmail-compose:2020"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:tools:gmail-labelclick:2020"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:tools:gmail-openconversation:2020"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:tools:gmail-search:2020"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:tools:maps:2019"
     },
     {
-        "duration": "63.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:tools:photoshop:2021"
     },
     {
-        "duration": "169.0",
+        "duration": "180.0",
         "name": "system_health.common_desktop/browse:tools:photoshop_warm:2021"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse:tools:sheets:2019"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/browse_accessibility:media:youtube"
     },
     {
-        "duration": "40.0",
+        "duration": "36.0",
         "name": "system_health.common_desktop/browse_accessibility:tech:codesearch:2018"
     },
     {
-        "duration": "30.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:chrome:blank"
     },
     {
-        "duration": "31.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:games:alphabetty:2018"
     },
     {
-        "duration": "29.0",
+        "duration": "25.0",
         "name": "system_health.common_desktop/load:games:bubbles:2020"
     },
     {
-        "duration": "35.0",
+        "duration": "33.0",
         "name": "system_health.common_desktop/load:games:lazors"
     },
     {
-        "duration": "32.0",
+        "duration": "31.0",
         "name": "system_health.common_desktop/load:games:miniclip:2018"
     },
     {
-        "duration": "32.0",
+        "duration": "30.0",
         "name": "system_health.common_desktop/load:games:spychase:2018"
     },
     {
-        "duration": "35.0",
+        "duration": "34.0",
         "name": "system_health.common_desktop/load:media:9gag"
     },
     {
-        "duration": "31.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:media:dailymotion:2019"
     },
     {
-        "duration": "33.0",
+        "duration": "29.0",
         "name": "system_health.common_desktop/load:media:facebook_feed:desktop:2020"
     },
     {
-        "duration": "33.0",
+        "duration": "28.0",
         "name": "system_health.common_desktop/load:media:facebook_photos:2018"
     },
     {
-        "duration": "32.0",
+        "duration": "28.0",
         "name": "system_health.common_desktop/load:media:facebook_photos:desktop:2020"
     },
     {
-        "duration": "32.0",
+        "duration": "28.0",
         "name": "system_health.common_desktop/load:media:flickr:2018"
     },
     {
-        "duration": "28.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:media:google_images:2018"
     },
     {
-        "duration": "13.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/load:media:imgur:2018"
     },
     {
-        "duration": "33.0",
+        "duration": "30.0",
         "name": "system_health.common_desktop/load:media:soundcloud:2018"
     },
     {
-        "duration": "29.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:media:youtube:2018"
     },
     {
-        "duration": "28.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:media:youtubelivingroom:2020"
     },
     {
-        "duration": "30.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:news:bbc:2018"
     },
     {
-        "duration": "32.0",
+        "duration": "28.0",
         "name": "system_health.common_desktop/load:news:cnn:2020"
     },
     {
-        "duration": "32.0",
+        "duration": "28.0",
         "name": "system_health.common_desktop/load:news:flipboard"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "system_health.common_desktop/load:news:hackernews:2018"
     },
     {
-        "duration": "34.0",
+        "duration": "31.0",
         "name": "system_health.common_desktop/load:news:nytimes:2018"
     },
     {
-        "duration": "30.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:news:qq:2018"
     },
     {
-        "duration": "31.0",
+        "duration": "30.0",
         "name": "system_health.common_desktop/load:news:reddit:2018"
     },
     {
-        "duration": "29.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:news:wikipedia:2018"
     },
     {
-        "duration": "31.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:search:amazon:2018"
     },
     {
-        "duration": "29.0",
+        "duration": "25.0",
         "name": "system_health.common_desktop/load:search:baidu:2018"
     },
     {
-        "duration": "31.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:search:ebay:2018"
     },
     {
-        "duration": "29.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:search:flipkart:2018"
     },
     {
-        "duration": "28.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:search:google:2018"
     },
     {
-        "duration": "28.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:search:taobao:2018"
     },
     {
-        "duration": "27.0",
+        "duration": "25.0",
         "name": "system_health.common_desktop/load:search:yahoo:2018"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:search:yandex:2018"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:social:instagram:2018"
     },
     {
-        "duration": "31.0",
+        "duration": "29.0",
         "name": "system_health.common_desktop/load:social:pinterest:2019"
     },
     {
-        "duration": "29.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:social:vk:2018"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/load:tools:chat:2020"
     },
     {
-        "duration": "15.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/load:tools:docs:2019"
     },
     {
-        "duration": "32.0",
+        "duration": "28.0",
         "name": "system_health.common_desktop/load:tools:drive:2019"
     },
     {
-        "duration": "13.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/load:tools:gmail:2019"
     },
     {
-        "duration": "29.0",
+        "duration": "27.0",
         "name": "system_health.common_desktop/load:tools:stackoverflow:2018"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load:tools:weather:2019"
     },
     {
-        "duration": "31.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load_accessibility:media:wikipedia:2018"
     },
     {
-        "duration": "31.0",
+        "duration": "26.0",
         "name": "system_health.common_desktop/load_accessibility:shopping:amazon:2018"
     },
     {
-        "duration": "13.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/long_running:tools:gmail-background"
     },
     {
-        "duration": "13.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/long_running:tools:gmail-foreground"
     },
     {
-        "duration": "13.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/multitab:misc:typical24"
     },
     {
-        "duration": "13.0",
+        "duration": "12.0",
         "name": "system_health.common_desktop/multitab:misc:typical24:2018"
     },
     {
-        "duration": "59.0",
+        "duration": "54.0",
         "name": "system_health.common_desktop/play:media:google_play_music"
     },
     {
-        "duration": "55.0",
+        "duration": "59.0",
         "name": "system_health.common_desktop/play:media:soundcloud:2018"
     },
     {
-        "duration": "35.0",
+        "duration": "34.0",
         "name": "system_health.memory_desktop/browse:media:googleplaystore:2021"
     },
     {
-        "duration": "80.0",
+        "duration": "74.0",
         "name": "system_health.memory_desktop/browse:media:imgur"
     },
     {
-        "duration": "90.0",
+        "duration": "89.0",
         "name": "system_health.memory_desktop/browse:media:pinterest:2018"
     },
     {
-        "duration": "65.0",
+        "duration": "64.0",
         "name": "system_health.memory_desktop/browse:media:tumblr:2018"
     },
     {
-        "duration": "7.0",
+        "duration": "5.0",
         "name": "system_health.memory_desktop/browse:media:youtube:2019"
     },
     {
-        "duration": "65.0",
+        "duration": "64.0",
         "name": "system_health.memory_desktop/browse:media:youtubetv:2019"
     },
     {
-        "duration": "74.0",
+        "duration": "79.0",
         "name": "system_health.memory_desktop/browse:media:youtubetv_watch:2020"
     },
     {
-        "duration": "48.0",
+        "duration": "45.0",
         "name": "system_health.memory_desktop/browse:news:cnn:2021"
     },
     {
-        "duration": "45.0",
+        "duration": "44.0",
         "name": "system_health.memory_desktop/browse:news:flipboard:2020"
     },
     {
-        "duration": "52.0",
+        "duration": "49.0",
         "name": "system_health.memory_desktop/browse:news:hackernews:2020"
     },
     {
-        "duration": "77.0",
+        "duration": "70.0",
         "name": "system_health.memory_desktop/browse:news:nytimes:2020"
     },
     {
-        "duration": "70.0",
+        "duration": "60.0",
         "name": "system_health.memory_desktop/browse:news:reddit:2020"
     },
     {
-        "duration": "49.0",
+        "duration": "50.0",
         "name": "system_health.memory_desktop/browse:search:google:2020"
     },
     {
-        "duration": "33.0",
+        "duration": "34.0",
         "name": "system_health.memory_desktop/browse:search:google_india:2021"
     },
     {
-        "duration": "69.0",
+        "duration": "68.0",
         "name": "system_health.memory_desktop/browse:social:facebook_infinite_scroll:2018"
     },
     {
-        "duration": "5.0",
+        "duration": "6.0",
         "name": "system_health.memory_desktop/browse:social:tumblr_infinite_scroll:2018"
     },
     {
-        "duration": "52.0",
+        "duration": "46.0",
         "name": "system_health.memory_desktop/browse:social:twitter:2018"
     },
     {
-        "duration": "7.0",
+        "duration": "5.0",
         "name": "system_health.memory_desktop/browse:social:twitter_infinite_scroll:2018"
     },
     {
-        "duration": "58.0",
+        "duration": "5.0",
         "name": "system_health.memory_desktop/browse:tech:discourse_infinite_scroll:2018"
     },
     {
@@ -4128,7 +4276,7 @@
         "name": "system_health.memory_desktop/browse:tools:autocad:2021"
     },
     {
-        "duration": "35.0",
+        "duration": "36.0",
         "name": "system_health.memory_desktop/browse:tools:docs_scrolling"
     },
     {
@@ -4152,11 +4300,11 @@
         "name": "system_health.memory_desktop/browse:tools:maps:2019"
     },
     {
-        "duration": "5.0",
+        "duration": "6.0",
         "name": "system_health.memory_desktop/browse:tools:photoshop:2021"
     },
     {
-        "duration": "5.0",
+        "duration": "6.0",
         "name": "system_health.memory_desktop/browse:tools:photoshop_warm:2021"
     },
     {
@@ -4180,31 +4328,31 @@
         "name": "system_health.memory_desktop/load:games:alphabetty:2018"
     },
     {
-        "duration": "18.0",
+        "duration": "19.0",
         "name": "system_health.memory_desktop/load:games:bubbles:2020"
     },
     {
-        "duration": "19.0",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:games:lazors"
     },
     {
-        "duration": "23.0",
+        "duration": "24.0",
         "name": "system_health.memory_desktop/load:games:miniclip:2018"
     },
     {
-        "duration": "31.0",
+        "duration": "25.0",
         "name": "system_health.memory_desktop/load:games:spychase:2018"
     },
     {
-        "duration": "24.0",
+        "duration": "25.0",
         "name": "system_health.memory_desktop/load:media:9gag"
     },
     {
-        "duration": "22.0",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:media:dailymotion:2019"
     },
     {
-        "duration": "22.0",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:media:facebook_feed:desktop:2020"
     },
     {
@@ -4216,19 +4364,19 @@
         "name": "system_health.memory_desktop/load:media:facebook_photos:desktop:2020"
     },
     {
-        "duration": "21.0",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:media:flickr:2018"
     },
     {
-        "duration": "19.0",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:media:google_images:2018"
     },
     {
-        "duration": "21.0",
+        "duration": "7.0",
         "name": "system_health.memory_desktop/load:media:imgur:2018"
     },
     {
-        "duration": "31.0",
+        "duration": "25.0",
         "name": "system_health.memory_desktop/load:media:soundcloud:2018"
     },
     {
@@ -4236,7 +4384,7 @@
         "name": "system_health.memory_desktop/load:media:youtube:2018"
     },
     {
-        "duration": "28.0",
+        "duration": "29.0",
         "name": "system_health.memory_desktop/load:media:youtubelivingroom:2020"
     },
     {
@@ -4244,7 +4392,7 @@
         "name": "system_health.memory_desktop/load:news:bbc:2018"
     },
     {
-        "duration": "21.0",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:news:cnn:2020"
     },
     {
@@ -4256,19 +4404,19 @@
         "name": "system_health.memory_desktop/load:news:hackernews:2018"
     },
     {
-        "duration": "33.0",
+        "duration": "24.0",
         "name": "system_health.memory_desktop/load:news:nytimes:2018"
     },
     {
-        "duration": "28.0",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:news:qq:2018"
     },
     {
-        "duration": "31.0",
+        "duration": "24.0",
         "name": "system_health.memory_desktop/load:news:reddit:2018"
     },
     {
-        "duration": "28.0",
+        "duration": "29.0",
         "name": "system_health.memory_desktop/load:news:wikipedia:2018"
     },
     {
@@ -4280,11 +4428,11 @@
         "name": "system_health.memory_desktop/load:search:baidu:2018"
     },
     {
-        "duration": "20.0",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:search:ebay:2018"
     },
     {
-        "duration": "20.0",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:search:flipkart:2018"
     },
     {
@@ -4292,27 +4440,27 @@
         "name": "system_health.memory_desktop/load:search:google:2018"
     },
     {
-        "duration": "27.0",
+        "duration": "28.0",
         "name": "system_health.memory_desktop/load:search:taobao:2018"
     },
     {
-        "duration": "26.0",
+        "duration": "27.0",
         "name": "system_health.memory_desktop/load:search:yahoo:2018"
     },
     {
-        "duration": "27.0",
+        "duration": "28.0",
         "name": "system_health.memory_desktop/load:search:yandex:2018"
     },
     {
-        "duration": "19.0",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:social:instagram:2018"
     },
     {
-        "duration": "31.0",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:social:pinterest:2019"
     },
     {
-        "duration": "28.0",
+        "duration": "29.0",
         "name": "system_health.memory_desktop/load:social:vk:2018"
     },
     {
@@ -4332,11 +4480,11 @@
         "name": "system_health.memory_desktop/load:tools:gmail:2019"
     },
     {
-        "duration": "28.0",
+        "duration": "29.0",
         "name": "system_health.memory_desktop/load:tools:stackoverflow:2018"
     },
     {
-        "duration": "28.0",
+        "duration": "29.0",
         "name": "system_health.memory_desktop/load:tools:weather:2019"
     },
     {
@@ -4344,23 +4492,23 @@
         "name": "system_health.memory_desktop/load_accessibility:media:wikipedia:2018"
     },
     {
-        "duration": "19.0",
+        "duration": "18.0",
         "name": "system_health.memory_desktop/load_accessibility:shopping:amazon:2018"
     },
     {
-        "duration": "148.0",
+        "duration": "153.0",
         "name": "system_health.memory_desktop/long_running:tools:gmail-background"
     },
     {
-        "duration": "153.0",
+        "duration": "147.0",
         "name": "system_health.memory_desktop/long_running:tools:gmail-foreground"
     },
     {
-        "duration": "5.0",
+        "duration": "6.0",
         "name": "system_health.memory_desktop/multitab:misc:typical24"
     },
     {
-        "duration": "5.0",
+        "duration": "6.0",
         "name": "system_health.memory_desktop/multitab:misc:typical24:2018"
     },
     {
@@ -4368,7 +4516,7 @@
         "name": "system_health.memory_desktop/play:media:google_play_music"
     },
     {
-        "duration": "45.0",
+        "duration": "44.0",
         "name": "system_health.memory_desktop/play:media:soundcloud:2018"
     },
     {
@@ -4376,439 +4524,439 @@
         "name": "tab_switching.typical_25/multitab:misc:typical24"
     },
     {
-        "duration": "18.0",
+        "duration": "17.0",
         "name": "tracing.tracing_with_background_memory_infra/Facebook"
     },
     {
-        "duration": "17.0",
+        "duration": "16.0",
         "name": "tracing.tracing_with_background_memory_infra/Wikipedia"
     },
     {
-        "duration": "15.0",
+        "duration": "14.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.amazon.com"
     },
     {
-        "duration": "15.0",
+        "duration": "14.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.ask.com/"
     },
     {
-        "duration": "16.0",
+        "duration": "15.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.bing.com/"
     },
     {
-        "duration": "16.0",
+        "duration": "14.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.yahoo.com/"
     },
     {
-        "duration": "19.0",
+        "duration": "15.0",
         "name": "tracing.tracing_with_background_memory_infra/http://www.youtube.com"
     },
     {
-        "duration": "17.0",
+        "duration": "15.0",
         "name": "tracing.tracing_with_background_memory_infra/https://www.google.com/#hl=en&q=barack+obama"
     },
     {
-        "duration": "16.0",
+        "duration": "15.0",
         "name": "tracing.tracing_with_background_memory_infra/https://www.google.com/calendar/"
     },
     {
-        "duration": "76.0",
+        "duration": "54.0",
         "name": "v8.browsing_desktop-future/browse:media:googleplaystore:2021"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:media:imgur"
     },
     {
-        "duration": "135.0",
+        "duration": "118.0",
         "name": "v8.browsing_desktop-future/browse:media:pinterest:2018"
     },
     {
-        "duration": "110.0",
+        "duration": "101.0",
         "name": "v8.browsing_desktop-future/browse:media:tumblr:2018"
     },
     {
-        "duration": "58.0",
+        "duration": "39.0",
         "name": "v8.browsing_desktop-future/browse:media:youtube:2019"
     },
     {
-        "duration": "120.0",
+        "duration": "101.0",
         "name": "v8.browsing_desktop-future/browse:media:youtubetv:2019"
     },
     {
-        "duration": "130.0",
+        "duration": "111.0",
         "name": "v8.browsing_desktop-future/browse:media:youtubetv_watch:2020"
     },
     {
-        "duration": "99.0",
+        "duration": "70.0",
         "name": "v8.browsing_desktop-future/browse:news:cnn:2021"
     },
     {
-        "duration": "90.0",
+        "duration": "67.0",
         "name": "v8.browsing_desktop-future/browse:news:flipboard:2020"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:news:hackernews:2020"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:news:nytimes:2020"
     },
     {
-        "duration": "117.0",
+        "duration": "93.0",
         "name": "v8.browsing_desktop-future/browse:news:reddit:2020"
     },
     {
-        "duration": "93.0",
+        "duration": "72.0",
         "name": "v8.browsing_desktop-future/browse:search:google:2020"
     },
     {
-        "duration": "75.0",
+        "duration": "54.0",
         "name": "v8.browsing_desktop-future/browse:search:google_india:2021"
     },
     {
-        "duration": "126.0",
+        "duration": "104.0",
         "name": "v8.browsing_desktop-future/browse:social:facebook_infinite_scroll:2018"
     },
     {
-        "duration": "103.0",
+        "duration": "104.0",
         "name": "v8.browsing_desktop-future/browse:social:tumblr_infinite_scroll:2018"
     },
     {
-        "duration": "111.0",
+        "duration": "82.0",
         "name": "v8.browsing_desktop-future/browse:social:twitter:2018"
     },
     {
-        "duration": "118.0",
+        "duration": "104.0",
         "name": "v8.browsing_desktop-future/browse:social:twitter_infinite_scroll:2018"
     },
     {
-        "duration": "103.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:tech:discourse_infinite_scroll:2018"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:tools:autocad:2021"
     },
     {
-        "duration": "78.0",
+        "duration": "56.0",
         "name": "v8.browsing_desktop-future/browse:tools:docs_scrolling"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:tools:gmail-compose:2020"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:tools:gmail-labelclick:2020"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:tools:gmail-openconversation:2020"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:tools:gmail-search:2020"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:tools:maps:2019"
     },
     {
-        "duration": "100.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:tools:photoshop:2021"
     },
     {
-        "duration": "205.0",
+        "duration": "194.0",
         "name": "v8.browsing_desktop-future/browse:tools:photoshop_warm:2021"
     },
     {
-        "duration": "45.0",
+        "duration": "25.0",
         "name": "v8.browsing_desktop-future/browse:tools:sheets:2019"
     },
     {
-        "duration": "67.0",
+        "duration": "49.0",
         "name": "v8.browsing_desktop/browse:media:googleplaystore:2021"
     },
     {
-        "duration": "58.0",
+        "duration": "19.0",
         "name": "v8.browsing_desktop/browse:media:imgur"
     },
     {
-        "duration": "147.0",
+        "duration": "134.0",
         "name": "v8.browsing_desktop/browse:media:pinterest:2018"
     },
     {
-        "duration": "123.0",
+        "duration": "114.0",
         "name": "v8.browsing_desktop/browse:media:tumblr:2018"
     },
     {
-        "duration": "58.0",
+        "duration": "45.0",
         "name": "v8.browsing_desktop/browse:media:youtube:2019"
     },
     {
-        "duration": "121.0",
+        "duration": "108.0",
         "name": "v8.browsing_desktop/browse:media:youtubetv:2019"
     },
     {
-        "duration": "131.0",
+        "duration": "137.0",
         "name": "v8.browsing_desktop/browse:media:youtubetv_watch:2020"
     },
     {
-        "duration": "90.0",
+        "duration": "62.0",
         "name": "v8.browsing_desktop/browse:news:cnn:2021"
     },
     {
-        "duration": "80.0",
+        "duration": "59.0",
         "name": "v8.browsing_desktop/browse:news:flipboard:2020"
     },
     {
-        "duration": "58.0",
+        "duration": "19.0",
         "name": "v8.browsing_desktop/browse:news:hackernews:2020"
     },
     {
-        "duration": "58.0",
+        "duration": "19.0",
         "name": "v8.browsing_desktop/browse:news:nytimes:2020"
     },
     {
-        "duration": "130.0",
+        "duration": "109.0",
         "name": "v8.browsing_desktop/browse:news:reddit:2020"
     },
     {
-        "duration": "84.0",
+        "duration": "64.0",
         "name": "v8.browsing_desktop/browse:search:google:2020"
     },
     {
-        "duration": "66.0",
+        "duration": "47.0",
         "name": "v8.browsing_desktop/browse:search:google_india:2021"
     },
     {
-        "duration": "112.0",
+        "duration": "93.0",
         "name": "v8.browsing_desktop/browse:social:facebook_infinite_scroll:2018"
     },
     {
-        "duration": "123.0",
+        "duration": "112.0",
         "name": "v8.browsing_desktop/browse:social:tumblr_infinite_scroll:2018"
     },
     {
-        "duration": "104.0",
+        "duration": "88.0",
         "name": "v8.browsing_desktop/browse:social:twitter:2018"
     },
     {
-        "duration": "118.0",
+        "duration": "103.0",
         "name": "v8.browsing_desktop/browse:social:twitter_infinite_scroll:2018"
     },
     {
-        "duration": "94.0",
+        "duration": "17.0",
         "name": "v8.browsing_desktop/browse:tech:discourse_infinite_scroll:2018"
     },
     {
-        "duration": "36.0",
+        "duration": "17.0",
         "name": "v8.browsing_desktop/browse:tools:autocad:2021"
     },
     {
-        "duration": "69.0",
+        "duration": "49.0",
         "name": "v8.browsing_desktop/browse:tools:docs_scrolling"
     },
     {
-        "duration": "36.0",
+        "duration": "17.0",
         "name": "v8.browsing_desktop/browse:tools:gmail-compose:2020"
     },
     {
-        "duration": "36.0",
+        "duration": "17.0",
         "name": "v8.browsing_desktop/browse:tools:gmail-labelclick:2020"
     },
     {
-        "duration": "36.0",
+        "duration": "17.0",
         "name": "v8.browsing_desktop/browse:tools:gmail-openconversation:2020"
     },
     {
-        "duration": "36.0",
+        "duration": "17.0",
         "name": "v8.browsing_desktop/browse:tools:gmail-search:2020"
     },
     {
-        "duration": "36.0",
+        "duration": "17.0",
         "name": "v8.browsing_desktop/browse:tools:maps:2019"
     },
     {
-        "duration": "114.0",
+        "duration": "19.0",
         "name": "v8.browsing_desktop/browse:tools:photoshop:2021"
     },
     {
-        "duration": "221.0",
+        "duration": "214.0",
         "name": "v8.browsing_desktop/browse:tools:photoshop_warm:2021"
     },
     {
-        "duration": "58.0",
+        "duration": "19.0",
         "name": "v8.browsing_desktop/browse:tools:sheets:2019"
     },
     {
-        "duration": "36.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/AdsAMPAds_cold"
     },
     {
-        "duration": "40.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/AdsAMPAds_hot"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/AdsAMPAds_warm"
     },
     {
-        "duration": "36.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/AdsAdSenseAsyncAds_cold"
     },
     {
-        "duration": "41.0",
+        "duration": "44.0",
         "name": "v8.runtime_stats.top_25/AdsAdSenseAsyncAds_hot"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/AdsAdSenseAsyncAds_warm"
     },
     {
-        "duration": "35.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/AdsAsyncAdSenseImage_cold"
     },
     {
-        "duration": "40.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/AdsAsyncAdSenseImage_hot"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/AdsAsyncAdSenseImage_warm"
     },
     {
-        "duration": "35.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/AdsDoubleClickAsyncAds_cold"
     },
     {
-        "duration": "40.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/AdsDoubleClickAsyncAds_hot"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/AdsDoubleClickAsyncAds_warm"
     },
     {
-        "duration": "35.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/AdsMultipleAdSlots_cold"
     },
     {
-        "duration": "40.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/AdsMultipleAdSlots_hot"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/AdsMultipleAdSlots_warm"
     },
     {
-        "duration": "35.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/AdsOnScreenDetection_cold"
     },
     {
-        "duration": "40.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/AdsOnScreenDetection_hot"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/AdsOnScreenDetection_warm"
     },
     {
-        "duration": "36.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/AdsSyncAdSenseImage_cold"
     },
     {
-        "duration": "40.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/AdsSyncAdSenseImage_hot"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/AdsSyncAdSenseImage_warm"
     },
     {
-        "duration": "36.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/AdsSyncLoadAsyncRenderAdSenseImage_cold"
     },
     {
-        "duration": "40.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/AdsSyncLoadAsyncRenderAdSenseImage_hot"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/AdsSyncLoadAsyncRenderAdSenseImage_warm"
     },
     {
-        "duration": "43.0",
+        "duration": "42.0",
         "name": "v8.runtime_stats.top_25/AdsViewOptimizedRendering_cold"
     },
     {
-        "duration": "63.0",
+        "duration": "66.0",
         "name": "v8.runtime_stats.top_25/AdsViewOptimizedRendering_hot"
     },
     {
-        "duration": "53.0",
+        "duration": "54.0",
         "name": "v8.runtime_stats.top_25/AdsViewOptimizedRendering_warm"
     },
     {
-        "duration": "43.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://edition.cnn.com_cold"
     },
     {
-        "duration": "55.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/http://edition.cnn.com_hot"
     },
     {
-        "duration": "50.0",
+        "duration": "38.0",
         "name": "v8.runtime_stats.top_25/http://edition.cnn.com_warm"
     },
     {
-        "duration": "53.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://hi.wikipedia.org/wiki/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0_cold"
     },
     {
-        "duration": "49.0",
+        "duration": "46.0",
         "name": "v8.runtime_stats.top_25/http://hi.wikipedia.org/wiki/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0_hot"
     },
     {
-        "duration": "45.0",
+        "duration": "40.0",
         "name": "v8.runtime_stats.top_25/http://hi.wikipedia.org/wiki/%E0%A4%AE%E0%A5%81%E0%A4%96%E0%A4%AA%E0%A5%83%E0%A4%B7%E0%A5%8D%E0%A4%A0_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://inbox.google.com_cold"
     },
     {
-        "duration": "44.0",
+        "duration": "51.0",
         "name": "v8.runtime_stats.top_25/http://inbox.google.com_hot"
     },
     {
-        "duration": "41.0",
+        "duration": "45.0",
         "name": "v8.runtime_stats.top_25/http://inbox.google.com_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://maps.google.co.jp/maps/search/restaurant+tokyo_cold"
     },
     {
-        "duration": "45.0",
+        "duration": "187.0",
         "name": "v8.runtime_stats.top_25/http://maps.google.co.jp/maps/search/restaurant+tokyo_hot"
     },
     {
-        "duration": "41.0",
+        "duration": "216.0",
         "name": "v8.runtime_stats.top_25/http://maps.google.co.jp/maps/search/restaurant+tokyo_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "40.0",
         "name": "v8.runtime_stats.top_25/http://meta.discourse.org_cold"
     },
     {
-        "duration": "45.0",
+        "duration": "51.0",
         "name": "v8.runtime_stats.top_25/http://meta.discourse.org_hot"
     },
     {
-        "duration": "42.0",
+        "duration": "47.0",
         "name": "v8.runtime_stats.top_25/http://meta.discourse.org_warm"
     },
     {
@@ -4816,35 +4964,35 @@
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?angular_cold"
     },
     {
-        "duration": "41.0",
+        "duration": "46.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?angular_hot"
     },
     {
-        "duration": "39.0",
+        "duration": "45.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?angular_warm"
     },
     {
-        "duration": "37.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?backbone_cold"
     },
     {
-        "duration": "41.0",
+        "duration": "55.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?backbone_hot"
     },
     {
-        "duration": "39.0",
+        "duration": "41.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?backbone_warm"
     },
     {
-        "duration": "37.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?ember_cold"
     },
     {
-        "duration": "50.0",
+        "duration": "46.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?ember_hot"
     },
     {
-        "duration": "39.0",
+        "duration": "213.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?ember_warm"
     },
     {
@@ -4852,267 +5000,267 @@
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?jquery_cold"
     },
     {
-        "duration": "41.0",
+        "duration": "46.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?jquery_hot"
     },
     {
-        "duration": "39.0",
+        "duration": "51.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?jquery_warm"
     },
     {
-        "duration": "35.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?vanilla_cold"
     },
     {
-        "duration": "40.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?vanilla_hot"
     },
     {
-        "duration": "37.0",
+        "duration": "38.0",
         "name": "v8.runtime_stats.top_25/http://pollouer.muc/Speedometer/CustomRunner.html?vanilla_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://reddit.musicplayer.io_cold"
     },
     {
-        "duration": "45.0",
+        "duration": "52.0",
         "name": "v8.runtime_stats.top_25/http://reddit.musicplayer.io_hot"
     },
     {
-        "duration": "42.0",
+        "duration": "46.0",
         "name": "v8.runtime_stats.top_25/http://reddit.musicplayer.io_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://weibo.com_cold"
     },
     {
-        "duration": "44.0",
+        "duration": "50.0",
         "name": "v8.runtime_stats.top_25/http://weibo.com_hot"
     },
     {
-        "duration": "41.0",
+        "duration": "64.0",
         "name": "v8.runtime_stats.top_25/http://weibo.com_warm"
     },
     {
-        "duration": "41.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://world.taobao.com_cold"
     },
     {
-        "duration": "46.0",
+        "duration": "44.0",
         "name": "v8.runtime_stats.top_25/http://world.taobao.com_hot"
     },
     {
-        "duration": "44.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://world.taobao.com_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://www.amazon.com/s/?field-keywords=v8_cold"
     },
     {
-        "duration": "45.0",
+        "duration": "44.0",
         "name": "v8.runtime_stats.top_25/http://www.amazon.com/s/?field-keywords=v8_hot"
     },
     {
-        "duration": "41.0",
+        "duration": "50.0",
         "name": "v8.runtime_stats.top_25/http://www.amazon.com/s/?field-keywords=v8_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://www.baidu.com/s?wd=v8_cold"
     },
     {
-        "duration": "44.0",
+        "duration": "48.0",
         "name": "v8.runtime_stats.top_25/http://www.baidu.com/s?wd=v8_hot"
     },
     {
-        "duration": "41.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://www.baidu.com/s?wd=v8_warm"
     },
     {
-        "duration": "39.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/http://www.bing.com/search?q=v8+engine_cold"
     },
     {
-        "duration": "45.0",
+        "duration": "50.0",
         "name": "v8.runtime_stats.top_25/http://www.bing.com/search?q=v8+engine_hot"
     },
     {
-        "duration": "42.0",
+        "duration": "53.0",
         "name": "v8.runtime_stats.top_25/http://www.bing.com/search?q=v8+engine_warm"
     },
     {
-        "duration": "42.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://www.ebay.fr/sch/i.html?_nkw=v8_cold"
     },
     {
-        "duration": "54.0",
+        "duration": "44.0",
         "name": "v8.runtime_stats.top_25/http://www.ebay.fr/sch/i.html?_nkw=v8_hot"
     },
     {
-        "duration": "48.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://www.ebay.fr/sch/i.html?_nkw=v8_warm"
     },
     {
-        "duration": "40.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://www.instagram.com/archdigest_cold"
     },
     {
-        "duration": "46.0",
+        "duration": "44.0",
         "name": "v8.runtime_stats.top_25/http://www.instagram.com/archdigest_hot"
     },
     {
-        "duration": "43.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://www.instagram.com/archdigest_warm"
     },
     {
-        "duration": "41.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/http://www.msn.com/ar-ae_cold"
     },
     {
-        "duration": "48.0",
+        "duration": "47.0",
         "name": "v8.runtime_stats.top_25/http://www.msn.com/ar-ae_hot"
     },
     {
-        "duration": "45.0",
+        "duration": "46.0",
         "name": "v8.runtime_stats.top_25/http://www.msn.com/ar-ae_warm"
     },
     {
-        "duration": "41.0",
+        "duration": "40.0",
         "name": "v8.runtime_stats.top_25/http://www.pinterest.com/categories/popular_cold"
     },
     {
-        "duration": "58.0",
+        "duration": "53.0",
         "name": "v8.runtime_stats.top_25/http://www.pinterest.com/categories/popular_hot"
     },
     {
-        "duration": "45.0",
+        "duration": "63.0",
         "name": "v8.runtime_stats.top_25/http://www.pinterest.com/categories/popular_warm"
     },
     {
-        "duration": "45.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://www.qq.com_cold"
     },
     {
-        "duration": "53.0",
+        "duration": "45.0",
         "name": "v8.runtime_stats.top_25/http://www.qq.com_hot"
     },
     {
-        "duration": "50.0",
+        "duration": "40.0",
         "name": "v8.runtime_stats.top_25/http://www.qq.com_warm"
     },
     {
-        "duration": "40.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://www.reddit.com_cold"
     },
     {
-        "duration": "47.0",
+        "duration": "45.0",
         "name": "v8.runtime_stats.top_25/http://www.reddit.com_hot"
     },
     {
-        "duration": "44.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://www.reddit.com_warm"
     },
     {
-        "duration": "42.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/http://www.twitter.com/taylorswift13_cold"
     },
     {
-        "duration": "50.0",
+        "duration": "47.0",
         "name": "v8.runtime_stats.top_25/http://www.twitter.com/taylorswift13_hot"
     },
     {
-        "duration": "46.0",
+        "duration": "41.0",
         "name": "v8.runtime_stats.top_25/http://www.twitter.com/taylorswift13_warm"
     },
     {
-        "duration": "39.0",
+        "duration": "40.0",
         "name": "v8.runtime_stats.top_25/http://www.wikiwand.com/en/hill_cold"
     },
     {
-        "duration": "47.0",
+        "duration": "53.0",
         "name": "v8.runtime_stats.top_25/http://www.wikiwand.com/en/hill_hot"
     },
     {
-        "duration": "43.0",
+        "duration": "47.0",
         "name": "v8.runtime_stats.top_25/http://www.wikiwand.com/en/hill_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/http://www.yahoo.co.jp_cold"
     },
     {
-        "duration": "44.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/http://www.yahoo.co.jp_hot"
     },
     {
-        "duration": "41.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://www.yahoo.co.jp_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/http://yandex.ru/search/?text=v8_cold"
     },
     {
-        "duration": "43.0",
+        "duration": "49.0",
         "name": "v8.runtime_stats.top_25/http://yandex.ru/search/?text=v8_hot"
     },
     {
-        "duration": "41.0",
+        "duration": "45.0",
         "name": "v8.runtime_stats.top_25/http://yandex.ru/search/?text=v8_warm"
     },
     {
-        "duration": "41.0",
+        "duration": "77.0",
         "name": "v8.runtime_stats.top_25/https://adwords.google.com_cold"
     },
     {
-        "duration": "50.0",
+        "duration": "221.0",
         "name": "v8.runtime_stats.top_25/https://adwords.google.com_hot"
     },
     {
-        "duration": "46.0",
+        "duration": "222.0",
         "name": "v8.runtime_stats.top_25/https://adwords.google.com_warm"
     },
     {
-        "duration": "35.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3_cold"
     },
     {
-        "duration": "41.0",
+        "duration": "43.0",
         "name": "v8.runtime_stats.top_25/https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3_hot"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/https://cdn.ampproject.org/c/www.bbc.co.uk/news/amp/37344292#log=3_warm"
     },
     {
-        "duration": "14.0",
+        "duration": "11.0",
         "name": "v8.runtime_stats.top_25/https://en.wikipedia.org/w/index.php?title=Barack_Obama&veaction=edit_cold"
     },
     {
-        "duration": "14.0",
+        "duration": "11.0",
         "name": "v8.runtime_stats.top_25/https://en.wikipedia.org/w/index.php?title=Barack_Obama&veaction=edit_hot"
     },
     {
-        "duration": "14.0",
+        "duration": "11.0",
         "name": "v8.runtime_stats.top_25/https://en.wikipedia.org/w/index.php?title=Barack_Obama&veaction=edit_warm"
     },
     {
-        "duration": "39.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/https://www.facebook.com/shakira_cold"
     },
     {
-        "duration": "47.0",
+        "duration": "46.0",
         "name": "v8.runtime_stats.top_25/https://www.facebook.com/shakira_hot"
     },
     {
-        "duration": "43.0",
+        "duration": "44.0",
         "name": "v8.runtime_stats.top_25/https://www.facebook.com/shakira_warm"
     },
     {
-        "duration": "44.0",
+        "duration": "40.0",
         "name": "v8.runtime_stats.top_25/https://www.google.de/search?q=v8_cold"
     },
     {
@@ -5120,23 +5268,23 @@
         "name": "v8.runtime_stats.top_25/https://www.google.de/search?q=v8_hot"
     },
     {
-        "duration": "41.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/https://www.google.de/search?q=v8_warm"
     },
     {
-        "duration": "41.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/https://www.linkedin.com/m/_cold"
     },
     {
-        "duration": "47.0",
+        "duration": "46.0",
         "name": "v8.runtime_stats.top_25/https://www.linkedin.com/m/_hot"
     },
     {
-        "duration": "45.0",
+        "duration": "42.0",
         "name": "v8.runtime_stats.top_25/https://www.linkedin.com/m/_warm"
     },
     {
-        "duration": "38.0",
+        "duration": "34.0",
         "name": "v8.runtime_stats.top_25/https://www.youtube.com/watch?v=_kZsOISarzg_cold"
     },
     {
@@ -5144,11 +5292,11 @@
         "name": "v8.runtime_stats.top_25/https://www.youtube.com/watch?v=_kZsOISarzg_hot"
     },
     {
-        "duration": "41.0",
+        "duration": "39.0",
         "name": "v8.runtime_stats.top_25/https://www.youtube.com/watch?v=_kZsOISarzg_warm"
     },
     {
-        "duration": "39.0",
+        "duration": "35.0",
         "name": "v8.runtime_stats.top_25/https://www.youtube.com_cold"
     },
     {
@@ -5156,35 +5304,35 @@
         "name": "v8.runtime_stats.top_25/https://www.youtube.com_hot"
     },
     {
-        "duration": "44.0",
+        "duration": "54.0",
         "name": "v8.runtime_stats.top_25/https://www.youtube.com_warm"
     },
     {
-        "duration": "122.0",
+        "duration": "115.0",
         "name": "wasmpspdfkit/https://pspdfkit.com/webassembly-benchmark/"
     },
     {
-        "duration": "34.0",
+        "duration": "35.0",
         "name": "webrtc/10s_datachannel_transfer"
     },
     {
-        "duration": "25.0",
+        "duration": "26.0",
         "name": "webrtc/canvas_capture_peer_connection"
     },
     {
-        "duration": "36.0",
+        "duration": "37.0",
         "name": "webrtc/codec_constraints_h264"
     },
     {
-        "duration": "36.0",
+        "duration": "37.0",
         "name": "webrtc/codec_constraints_vp8"
     },
     {
-        "duration": "36.0",
+        "duration": "37.0",
         "name": "webrtc/codec_constraints_vp9"
     },
     {
-        "duration": "25.0",
+        "duration": "26.0",
         "name": "webrtc/hd_local_stream_10s"
     },
     {
@@ -5200,7 +5348,7 @@
         "name": "webrtc/insertable_streams_video_processing_camera_noop_video"
     },
     {
-        "duration": "26.0",
+        "duration": "27.0",
         "name": "webrtc/insertable_streams_video_processing_camera_webgl_pc"
     },
     {
@@ -5208,15 +5356,15 @@
         "name": "webrtc/insertable_streams_video_processing_camera_webgl_video"
     },
     {
-        "duration": "26.0",
+        "duration": "27.0",
         "name": "webrtc/insertable_streams_video_processing_pc_webgl_video"
     },
     {
-        "duration": "26.0",
+        "duration": "27.0",
         "name": "webrtc/insertable_streams_video_processing_video_webgl_video"
     },
     {
-        "duration": "13.0",
+        "duration": "14.0",
         "name": "webrtc/multiple_peerconnections"
     },
     {
@@ -5224,7 +5372,7 @@
         "name": "webrtc/negotiate-timing"
     },
     {
-        "duration": "13.0",
+        "duration": "14.0",
         "name": "webrtc/pause_play_peerconnections"
     }
 ]
\ No newline at end of file
diff --git a/tools/perf/core/shard_maps/win-10_laptop_low_end-perf_map.json b/tools/perf/core/shard_maps/win-10_laptop_low_end-perf_map.json
index d592bc6..d1d61fe 100644
--- a/tools/perf/core/shard_maps/win-10_laptop_low_end-perf_map.json
+++ b/tools/perf/core/shard_maps/win-10_laptop_low_end-perf_map.json
@@ -8,39 +8,9 @@
                 "abridged": false
             },
             "blink_perf.bindings": {
-                "end": 44,
-                "abridged": false
-            },
-            "jetstream2": {
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "1": {
-        "benchmarks": {
-            "blink_perf.bindings": {
-                "begin": 44,
                 "abridged": false
             },
             "blink_perf.css": {
-                "end": 54,
-                "abridged": false
-            },
-            "jetstream2": {
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "2": {
-        "benchmarks": {
-            "blink_perf.css": {
-                "begin": 54,
                 "abridged": false
             },
             "blink_perf.dom": {
@@ -53,7 +23,7 @@
                 "abridged": false
             },
             "blink_perf.layout": {
-                "end": 44,
+                "end": 38,
                 "abridged": false
             },
             "jetstream2": {
@@ -64,10 +34,10 @@
             }
         }
     },
-    "3": {
+    "1": {
         "benchmarks": {
             "blink_perf.layout": {
-                "begin": 44,
+                "begin": 38,
                 "abridged": false
             },
             "blink_perf.owp_storage": {
@@ -77,7 +47,10 @@
                 "abridged": false
             },
             "blink_perf.parser": {
-                "end": 5,
+                "abridged": false
+            },
+            "blink_perf.shadow_dom": {
+                "end": 20,
                 "abridged": false
             },
             "jetstream2": {
@@ -88,28 +61,15 @@
             }
         }
     },
-    "4": {
+    "2": {
         "benchmarks": {
-            "blink_perf.parser": {
-                "begin": 5,
-                "abridged": false
-            },
             "blink_perf.shadow_dom": {
+                "begin": 20,
                 "abridged": false
             },
             "blink_perf.svg": {
                 "abridged": false
             },
-            "jetstream2": {
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "5": {
-        "benchmarks": {
             "blink_perf.webaudio": {
                 "abridged": false
             },
@@ -129,7 +89,10 @@
                 "abridged": false
             },
             "desktop_ui": {
-                "end": 7,
+                "end": 25,
+                "abridged": false
+            },
+            "jetstream2": {
                 "abridged": false
             },
             "speedometer2": {
@@ -137,10 +100,10 @@
             }
         }
     },
-    "6": {
+    "3": {
         "benchmarks": {
             "desktop_ui": {
-                "begin": 7,
+                "begin": 25,
                 "abridged": false
             },
             "dummy_benchmark.noisy_benchmark_1": {
@@ -153,7 +116,58 @@
                 "abridged": false
             },
             "loading.desktop": {
-                "end": 7,
+                "end": 33,
+                "abridged": false
+            },
+            "speedometer2": {
+                "abridged": false
+            }
+        }
+    },
+    "4": {
+        "benchmarks": {
+            "loading.desktop": {
+                "begin": 33,
+                "end": 65,
+                "abridged": false
+            },
+            "jetstream2": {
+                "abridged": false
+            },
+            "speedometer2": {
+                "abridged": false
+            }
+        }
+    },
+    "5": {
+        "benchmarks": {
+            "loading.desktop": {
+                "begin": 65,
+                "end": 100,
+                "abridged": false
+            },
+            "speedometer2": {
+                "abridged": false
+            }
+        }
+    },
+    "6": {
+        "benchmarks": {
+            "loading.desktop": {
+                "begin": 100,
+                "abridged": false
+            },
+            "media.desktop": {
+                "abridged": false
+            },
+            "memory.desktop": {
+                "abridged": false
+            },
+            "octane": {
+                "abridged": false
+            },
+            "power.desktop": {
+                "end": 4,
                 "abridged": false
             },
             "speedometer2": {
@@ -163,9 +177,15 @@
     },
     "7": {
         "benchmarks": {
-            "loading.desktop": {
-                "begin": 7,
-                "end": 24,
+            "power.desktop": {
+                "begin": 4,
+                "abridged": false
+            },
+            "rasterize_and_record_micro.top_25": {
+                "abridged": false
+            },
+            "rendering.desktop": {
+                "end": 36,
                 "abridged": false
             },
             "speedometer2": {
@@ -175,9 +195,9 @@
     },
     "8": {
         "benchmarks": {
-            "loading.desktop": {
-                "begin": 24,
-                "end": 39,
+            "rendering.desktop": {
+                "begin": 36,
+                "end": 114,
                 "abridged": false
             },
             "speedometer2": {
@@ -187,9 +207,9 @@
     },
     "9": {
         "benchmarks": {
-            "loading.desktop": {
-                "begin": 39,
-                "end": 53,
+            "rendering.desktop": {
+                "begin": 114,
+                "end": 196,
                 "abridged": false
             },
             "speedometer2": {
@@ -199,9 +219,9 @@
     },
     "10": {
         "benchmarks": {
-            "loading.desktop": {
-                "begin": 53,
-                "end": 66,
+            "rendering.desktop": {
+                "begin": 196,
+                "end": 266,
                 "abridged": false
             },
             "speedometer2": {
@@ -211,9 +231,8 @@
     },
     "11": {
         "benchmarks": {
-            "loading.desktop": {
-                "begin": 66,
-                "end": 77,
+            "rendering.desktop": {
+                "begin": 266,
                 "abridged": false
             },
             "speedometer2": {
@@ -223,173 +242,6 @@
     },
     "12": {
         "benchmarks": {
-            "loading.desktop": {
-                "begin": 77,
-                "end": 90,
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "13": {
-        "benchmarks": {
-            "loading.desktop": {
-                "begin": 90,
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "14": {
-        "benchmarks": {
-            "media.desktop": {
-                "abridged": false
-            },
-            "memory.desktop": {
-                "end": 4,
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "15": {
-        "benchmarks": {
-            "memory.desktop": {
-                "begin": 4,
-                "abridged": false
-            },
-            "octane": {
-                "abridged": false
-            },
-            "power.desktop": {
-                "end": 13,
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "16": {
-        "benchmarks": {
-            "power.desktop": {
-                "begin": 13,
-                "abridged": false
-            },
-            "rasterize_and_record_micro.top_25": {
-                "abridged": false
-            },
-            "rendering.desktop": {
-                "end": 23,
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "17": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 23,
-                "end": 63,
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "18": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 63,
-                "end": 94,
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "19": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 94,
-                "end": 119,
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            }
-        }
-    },
-    "20": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 119,
-                "end": 154,
-                "abridged": false
-            }
-        }
-    },
-    "21": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 154,
-                "end": 177,
-                "abridged": false
-            }
-        }
-    },
-    "22": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 177,
-                "end": 220,
-                "abridged": false
-            }
-        }
-    },
-    "23": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 220,
-                "end": 256,
-                "abridged": false
-            }
-        }
-    },
-    "24": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 256,
-                "end": 289,
-                "abridged": false
-            }
-        }
-    },
-    "25": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 289,
-                "end": 334,
-                "abridged": false
-            }
-        }
-    },
-    "26": {
-        "benchmarks": {
-            "rendering.desktop": {
-                "begin": 334,
-                "abridged": false
-            },
             "rendering.desktop.notracing": {
                 "abridged": false
             },
@@ -406,141 +258,105 @@
                 "abridged": false
             },
             "system_health.common_desktop": {
-                "end": 27,
+                "end": 71,
                 "abridged": false
             }
         }
     },
-    "27": {
+    "13": {
         "benchmarks": {
             "system_health.common_desktop": {
-                "begin": 27,
-                "end": 72,
-                "abridged": false
-            }
-        }
-    },
-    "28": {
-        "benchmarks": {
-            "system_health.common_desktop": {
-                "begin": 72,
+                "begin": 71,
                 "abridged": false
             },
             "system_health.memory_desktop": {
-                "end": 14,
+                "end": 23,
+                "abridged": false
+            },
+            "speedometer2": {
                 "abridged": false
             }
         }
     },
-    "29": {
+    "14": {
         "benchmarks": {
             "system_health.memory_desktop": {
-                "begin": 14,
-                "end": 31,
+                "begin": 23,
+                "end": 64,
+                "abridged": false
+            },
+            "speedometer2": {
                 "abridged": false
             }
         }
     },
-    "30": {
+    "15": {
         "benchmarks": {
             "system_health.memory_desktop": {
-                "begin": 31,
-                "end": 55,
-                "abridged": false
-            }
-        }
-    },
-    "31": {
-        "benchmarks": {
-            "system_health.memory_desktop": {
-                "begin": 55,
-                "end": 66,
-                "abridged": false
-            }
-        }
-    },
-    "32": {
-        "benchmarks": {
-            "system_health.memory_desktop": {
-                "begin": 66,
-                "end": 80,
-                "abridged": false
-            }
-        }
-    },
-    "33": {
-        "benchmarks": {
-            "system_health.memory_desktop": {
-                "begin": 80,
+                "begin": 64,
                 "abridged": false
             },
             "tab_switching.typical_25": {
                 "abridged": false
             },
             "tracing.tracing_with_background_memory_infra": {
-                "abridged": false
-            },
-            "v8.browsing_desktop": {
-                "end": 19,
-                "abridged": false
-            }
-        }
-    },
-    "34": {
-        "benchmarks": {
-            "v8.browsing_desktop": {
-                "begin": 19,
-                "abridged": false
-            },
-            "v8.browsing_desktop-future": {
                 "end": 3,
                 "abridged": false
-            }
-        }
-    },
-    "35": {
-        "benchmarks": {
-            "v8.browsing_desktop-future": {
-                "begin": 3,
-                "end": 22,
+            },
+            "speedometer2": {
                 "abridged": false
             }
         }
     },
-    "36": {
+    "16": {
+        "benchmarks": {
+            "tracing.tracing_with_background_memory_infra": {
+                "begin": 3,
+                "abridged": false
+            },
+            "v8.browsing_desktop": {
+                "abridged": false
+            },
+            "v8.browsing_desktop-future": {
+                "end": 17,
+                "abridged": false
+            },
+            "speedometer2": {
+                "abridged": false
+            }
+        }
+    },
+    "17": {
         "benchmarks": {
             "v8.browsing_desktop-future": {
-                "begin": 22,
+                "begin": 17,
                 "abridged": false
             },
             "v8.runtime_stats.top_25": {
-                "end": 19,
+                "end": 40,
+                "abridged": false
+            },
+            "speedometer2": {
                 "abridged": false
             }
         }
     },
-    "37": {
+    "18": {
         "benchmarks": {
             "v8.runtime_stats.top_25": {
-                "begin": 19,
-                "end": 55,
+                "begin": 40,
+                "end": 84,
+                "abridged": false
+            },
+            "speedometer2": {
                 "abridged": false
             }
         }
     },
-    "38": {
+    "19": {
         "benchmarks": {
             "v8.runtime_stats.top_25": {
-                "begin": 55,
-                "end": 92,
-                "abridged": false
-            }
-        }
-    },
-    "39": {
-        "benchmarks": {
-            "v8.runtime_stats.top_25": {
-                "begin": 92,
+                "begin": 84,
                 "abridged": false
             },
             "wasmpspdfkit": {
@@ -548,54 +364,37 @@
             },
             "webrtc": {
                 "abridged": false
+            },
+            "speedometer2": {
+                "abridged": false
             }
         }
     },
     "extra_infos": {
         "num_stories": 1367,
-        "predicted_min_shard_time": 1500.0,
-        "predicted_min_shard_index": 11,
-        "predicted_max_shard_time": 2004.0,
-        "predicted_max_shard_index": 39,
-        "shard #0": 1558.0,
-        "shard #1": 1552.0,
-        "shard #2": 1557.0,
-        "shard #3": 1573.0,
-        "shard #4": 1551.0,
-        "shard #5": 1582.0,
-        "shard #6": 1554.0,
-        "shard #7": 1538.0,
-        "shard #8": 1582.0,
-        "shard #9": 1604.0,
-        "shard #10": 1560.0,
-        "shard #11": 1500.0,
-        "shard #12": 1592.0,
-        "shard #13": 1578.0,
-        "shard #14": 1550.0,
-        "shard #15": 1568.0,
-        "shard #16": 1568.0,
-        "shard #17": 1547.0,
-        "shard #18": 1563.0,
-        "shard #19": 1545.0,
-        "shard #20": 1555.0,
-        "shard #21": 1543.0,
-        "shard #22": 1567.0,
-        "shard #23": 1547.0,
-        "shard #24": 1547.0,
-        "shard #25": 1559.0,
-        "shard #26": 1555.0,
-        "shard #27": 1537.0,
-        "shard #28": 1527.0,
-        "shard #29": 1560.0,
-        "shard #30": 1545.0,
-        "shard #31": 1650.0,
-        "shard #32": 1509.0,
-        "shard #33": 1595.0,
-        "shard #34": 1523.0,
-        "shard #35": 1500.0,
-        "shard #36": 1545.0,
-        "shard #37": 1550.0,
-        "shard #38": 1549.0,
-        "shard #39": 2004.0
+        "predicted_min_shard_time": 2673.0,
+        "predicted_min_shard_index": 19,
+        "predicted_max_shard_time": 2789.0,
+        "predicted_max_shard_index": 12,
+        "shard #0": 2737.0,
+        "shard #1": 2734.0,
+        "shard #2": 2734.0,
+        "shard #3": 2760.0,
+        "shard #4": 2757.0,
+        "shard #5": 2720.0,
+        "shard #6": 2749.0,
+        "shard #7": 2745.0,
+        "shard #8": 2743.0,
+        "shard #9": 2723.0,
+        "shard #10": 2746.0,
+        "shard #11": 2717.0,
+        "shard #12": 2789.0,
+        "shard #13": 2682.0,
+        "shard #14": 2734.0,
+        "shard #15": 2719.0,
+        "shard #16": 2724.0,
+        "shard #17": 2733.0,
+        "shard #18": 2764.0,
+        "shard #19": 2673.0
     }
 }
\ No newline at end of file
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc
index 316c7b62..7085cc62 100644
--- a/ui/accessibility/ax_node.cc
+++ b/ui/accessibility/ax_node.cc
@@ -1751,7 +1751,6 @@
     case ax::mojom::Role::kTabList:
       return item_role == ax::mojom::Role::kTab;
     case ax::mojom::Role::kTree:
-    case ax::mojom::Role::kTreeItem:
       return item_role == ax::mojom::Role::kTreeItem;
     case ax::mojom::Role::kListBox:
       return item_role == ax::mojom::Role::kListBoxOption;
diff --git a/ui/accessibility/ax_node_unittest.cc b/ui/accessibility/ax_node_unittest.cc
index b593a53..bc39008 100644
--- a/ui/accessibility/ax_node_unittest.cc
+++ b/ui/accessibility/ax_node_unittest.cc
@@ -993,57 +993,4 @@
   EXPECT_EQ(tree.GetFromId(6)->GetSetSize(), 2);
 }
 
-TEST(AXNodeTest, TreeItemAsTreeItemParentPosInSetSetSize) {
-  TestAXTreeUpdate update(std::string(R"HTML(
-    ++1 kRootWebArea
-    ++++2 kTree
-    ++++++3 kTreeItem intAttribute=kPosInSet,1 intAttribute=kSetSize,2
-    ++++++++4 kTreeItem intAttribute=kPosInSet,1 intAttribute=kSetSize,6
-    ++++++++5 kTreeItem intAttribute=kPosInSet,2 intAttribute=kSetSize,6
-    ++++++6 kTreeItem intAttribute=kPosInSet,2 intAttribute=kSetSize,2
-    ++++++++7 kTreeItem intAttribute=kPosInSet,3 intAttribute=kSetSize,6
-  )HTML"));
-
-  AXTree tree(update);
-
-  EXPECT_EQ(tree.GetFromId(3)->GetPosInSet(), 1);
-  EXPECT_EQ(tree.GetFromId(3)->GetSetSize(), 2);
-
-  EXPECT_EQ(tree.GetFromId(4)->GetPosInSet(), 1);
-  EXPECT_EQ(tree.GetFromId(4)->GetSetSize(), 6);
-
-  EXPECT_EQ(tree.GetFromId(5)->GetPosInSet(), 2);
-  EXPECT_EQ(tree.GetFromId(5)->GetSetSize(), 6);
-
-  EXPECT_EQ(tree.GetFromId(6)->GetPosInSet(), 2);
-  EXPECT_EQ(tree.GetFromId(6)->GetSetSize(), 2);
-
-  EXPECT_EQ(tree.GetFromId(7)->GetPosInSet(), 3);
-  EXPECT_EQ(tree.GetFromId(7)->GetSetSize(), 6);
-}
-
-TEST(AXNodeTest, GroupAsTreeItemParentPosInSetSetSize) {
-  TestAXTreeUpdate update(std::string(R"HTML(
-    ++1 kRootWebArea
-    ++++2 kTree
-    ++++++3 kGroup
-    ++++++++4 kTreeItem intAttribute=kPosInSet,1 intAttribute=kSetSize,6
-    ++++++++5 kTreeItem intAttribute=kPosInSet,2 intAttribute=kSetSize,6
-    ++++++6 kTreeItem
-    ++++++++7 kGroup
-    ++++++++++8 kTreeItem intAttribute=kPosInSet,1 intAttribute=kSetSize,6
-  )HTML"));
-
-  AXTree tree(update);
-
-  EXPECT_EQ(tree.GetFromId(4)->GetPosInSet(), 1);
-  EXPECT_EQ(tree.GetFromId(4)->GetSetSize(), 6);
-
-  EXPECT_EQ(tree.GetFromId(5)->GetPosInSet(), 2);
-  EXPECT_EQ(tree.GetFromId(5)->GetSetSize(), 6);
-
-  EXPECT_EQ(tree.GetFromId(8)->GetPosInSet(), 1);
-  EXPECT_EQ(tree.GetFromId(8)->GetSetSize(), 6);
-}
-
 }  // namespace ui
diff --git a/ui/chromeos/styles/cros_sys_colors.json5 b/ui/chromeos/styles/cros_sys_colors.json5
index a34daf60..07292f71 100644
--- a/ui/chromeos/styles/cros_sys_colors.json5
+++ b/ui/chromeos/styles/cros_sys_colors.json5
@@ -375,6 +375,10 @@
       light: 'rgba($cros.sys.on-surface.rgb, 0.38)',
       dark: 'rgba($cros.sys.on-surface.rgb, 0.38)',
     },
+    'disabled-opaque': {
+      light: '$cros.ref.neutralvariant80',
+      dark: '$cros.ref.neutralvariant30',
+    },
     'disabled-container': 'rgba($cros.sys.on-surface.rgb, 0.12)',
     // TODO(b/224402466): Add cros.sys.warning
     // TODO(b/224402466): Add cros.sys.success
diff --git a/ui/color/color_id.h b/ui/color/color_id.h
index b2951c1d..ce4e2f4e 100644
--- a/ui/color/color_id.h
+++ b/ui/color/color_id.h
@@ -253,8 +253,6 @@
   E_CPONLY(kColorButtonForegroundProminent) \
   E_CPONLY(kColorButtonForegroundTonal) \
   E_CPONLY(kColorButtonHoverBackgroundText) \
-  E_CPONLY(kColorMultitaskFeedbackButtonLabelBackground) \
-  E_CPONLY(kColorMultitaskFeedbackButtonLabelForeground) \
   E_CPONLY(kColorMultitaskMenuNudgePulse) \
   E_CPONLY(kColorCheckboxBackgroundDisabled) \
   E_CPONLY(kColorCheckboxForegroundChecked) \
diff --git a/ui/color/ui_color_mixer.cc b/ui/color/ui_color_mixer.cc
index dd3dc0dc9..5120d66f 100644
--- a/ui/color/ui_color_mixer.cc
+++ b/ui/color/ui_color_mixer.cc
@@ -29,8 +29,7 @@
   mixer[kColorBadgeBackground] =
       PickGoogleColor(kColorAccent, kColorDialogBackground,
                       color_utils::kMinimumVisibleContrastRatio);
-  mixer[kColorBadgeForeground] =
-      GetColorWithMaxContrast(kColorButtonBackgroundProminent);
+  mixer[kColorBadgeForeground] = GetColorWithMaxContrast(kColorBadgeBackground);
   mixer[kColorBadgeInCocoaMenuBackground] = {kColorBadgeBackground};
   mixer[kColorBadgeInCocoaMenuForeground] = {kColorBadgeForeground};
   mixer[kColorBubbleBackground] = {kColorPrimaryBackground};
@@ -64,11 +63,6 @@
   mixer[kColorButtonHoverBackgroundText] = {kColorSysStateHoverOnSubtle};
   mixer[kColorCheckboxForegroundUnchecked] = {kColorSecondaryForeground};
   mixer[kColorCheckboxForegroundChecked] = {kColorButtonForeground};
-  mixer[kColorMultitaskFeedbackButtonLabelBackground] = {
-      dark_mode ? SetAlpha(SK_ColorWHITE, 0x1A)
-                : SetAlpha(SK_ColorBLACK, 0x0D)};
-  mixer[kColorMultitaskFeedbackButtonLabelForeground] = {
-      dark_mode ? gfx::kGoogleGrey200 : gfx::kGoogleGrey900};
   mixer[kColorCustomFrameCaptionForeground] = {SK_ColorWHITE};
   mixer[kColorDebugBoundsOutline] = SetAlpha(SK_ColorRED, 0x30);
   mixer[kColorDebugContentOutline] = SetAlpha(SK_ColorBLUE, 0x30);
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index b749930..921b8c8 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -134,8 +134,6 @@
     "test/fake_context_factory.h",
     "test/in_process_context_factory.cc",
     "test/in_process_context_factory.h",
-    "test/in_process_context_provider.cc",
-    "test/in_process_context_provider.h",
     "test/layer_animation_observer_test_api.cc",
     "test/layer_animation_observer_test_api.h",
     "test/layer_animation_stopped_waiter.cc",
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index 7fa7ed1..846887d 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -35,14 +35,15 @@
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/gl/gpu_service_impl.h"
 #include "components/viz/test/test_gpu_service_holder.h"
+#include "components/viz/test/test_in_process_context_provider.h"
 #include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/client/raster_interface.h"
 #include "gpu/command_buffer/common/context_creation_attribs.h"
 #include "services/viz/privileged/mojom/compositing/display_private.mojom.h"
 #include "ui/compositor/compositor_switches.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/test/direct_layer_tree_frame_sink.h"
-#include "ui/compositor/test/in_process_context_provider.h"
 #include "ui/display/display_switches.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/geometry/skia_conversions.h"
@@ -221,9 +222,9 @@
   }
   if (!shared_worker_context_provider_wrapper_ ||
       shared_worker_context_provider_lost) {
-    scoped_refptr<InProcessContextProvider> shared_worker_context_provider =
-        InProcessContextProvider::CreateOffscreen(&gpu_memory_buffer_manager_,
-                                                  /*is_worker=*/true);
+    auto shared_worker_context_provider =
+        base::MakeRefCounted<viz::TestInProcessContextProvider>(
+            viz::TestContextType::kSoftwareRaster, /*support_locking=*/true);
     auto result = shared_worker_context_provider->BindToCurrentSequence();
     if (result != gpu::ContextResult::kSuccess) {
       shared_worker_context_provider_wrapper_ = nullptr;
@@ -303,8 +304,9 @@
     return shared_main_thread_contexts_;
 
   shared_main_thread_contexts_ =
-      InProcessContextProvider::CreateOffscreen(&gpu_memory_buffer_manager_,
-                                                /*is_worker=*/false);
+      base::MakeRefCounted<viz::TestInProcessContextProvider>(
+          viz::TestContextType::kGLES2WithRaster, /*support_locking=*/false);
+
   auto result = shared_main_thread_contexts_->BindToCurrentSequence();
   if (result != gpu::ContextResult::kSuccess)
     shared_main_thread_contexts_.reset();
diff --git a/ui/compositor/test/in_process_context_factory.h b/ui/compositor/test/in_process_context_factory.h
index 7bacfc8..96cfe40 100644
--- a/ui/compositor/test/in_process_context_factory.h
+++ b/ui/compositor/test/in_process_context_factory.h
@@ -28,10 +28,10 @@
 
 namespace viz {
 class HostFrameSinkManager;
+class TestInProcessContextProvider;
 }
 
 namespace ui {
-class InProcessContextProvider;
 
 class InProcessContextFactory : public ContextFactory {
  public:
@@ -90,7 +90,7 @@
 
   PerCompositorData* CreatePerCompositorData(Compositor* compositor);
 
-  scoped_refptr<InProcessContextProvider> shared_main_thread_contexts_;
+  scoped_refptr<viz::TestInProcessContextProvider> shared_main_thread_contexts_;
   scoped_refptr<cc::RasterContextProviderWrapper>
       shared_worker_context_provider_wrapper_;
   viz::TestSharedBitmapManager shared_bitmap_manager_;
diff --git a/ui/compositor/test/in_process_context_provider.cc b/ui/compositor/test/in_process_context_provider.cc
deleted file mode 100644
index 20127e1..0000000
--- a/ui/compositor/test/in_process_context_provider.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2013 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/compositor/test/in_process_context_provider.h"
-
-#include "base/functional/bind.h"
-#include "base/functional/callback_helpers.h"
-#include "base/lazy_instance.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/trace_event/trace_event.h"
-#include "components/viz/common/gpu/context_cache_controller.h"
-#include "components/viz/service/gl/gpu_service_impl.h"
-#include "components/viz/test/test_gpu_service_holder.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/client/raster_implementation.h"
-#include "gpu/command_buffer/client/raster_implementation_gles.h"
-#include "gpu/command_buffer/client/shared_memory_limits.h"
-#include "gpu/config/skia_limits.h"
-#include "gpu/ipc/gl_in_process_context.h"
-#include "gpu/skia_bindings/grcontext_for_gles2_interface.h"
-#include "ipc/common/surface_handle.h"
-#include "ipc/raster_in_process_context.h"
-#include "third_party/skia/include/gpu/GrDirectContext.h"
-#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
-
-namespace ui {
-
-// static
-scoped_refptr<InProcessContextProvider>
-InProcessContextProvider::CreateOffscreen(
-    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    bool is_worker) {
-  gpu::ContextCreationAttribs attribs;
-  attribs.alpha_size = 8;
-  attribs.blue_size = 8;
-  attribs.green_size = 8;
-  attribs.red_size = 8;
-  attribs.depth_size = 0;
-  attribs.stencil_size = 8;
-  attribs.samples = 0;
-  attribs.sample_buffers = 0;
-  attribs.fail_if_major_perf_caveat = false;
-  attribs.bind_generates_resource = false;
-  attribs.enable_raster_interface = true;
-  attribs.enable_gles2_interface = !is_worker;
-  attribs.enable_oop_rasterization = is_worker;
-  return new InProcessContextProvider(attribs, gpu_memory_buffer_manager,
-                                      is_worker);
-}
-
-InProcessContextProvider::InProcessContextProvider(
-    const gpu::ContextCreationAttribs& attribs,
-    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    bool support_locking)
-    : support_locking_(support_locking), attribs_(attribs) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  context_thread_checker_.DetachFromThread();
-}
-
-InProcessContextProvider::~InProcessContextProvider() {
-  DCHECK(main_thread_checker_.CalledOnValidThread() ||
-         context_thread_checker_.CalledOnValidThread());
-}
-
-void InProcessContextProvider::AddRef() const {
-  base::RefCountedThreadSafe<InProcessContextProvider>::AddRef();
-}
-
-void InProcessContextProvider::Release() const {
-  base::RefCountedThreadSafe<InProcessContextProvider>::Release();
-}
-
-gpu::ContextResult InProcessContextProvider::BindToCurrentSequence() {
-  // This is called on the thread the context will be used.
-  DCHECK(context_thread_checker_.CalledOnValidThread());
-
-  if (bind_tried_)
-    return bind_result_;
-  bind_tried_ = true;
-
-  auto* holder = viz::TestGpuServiceHolder::GetInstance();
-
-  if (attribs_.enable_oop_rasterization) {
-    DCHECK(!attribs_.enable_gles2_interface);
-    DCHECK(!attribs_.enable_grcontext);
-
-    raster_context_ = std::make_unique<gpu::RasterInProcessContext>();
-    bind_result_ = raster_context_->Initialize(
-        holder->task_executor(), attribs_, gpu::SharedMemoryLimits(),
-        holder->gpu_service()->gr_shader_cache(), nullptr);
-
-    impl_base_ = raster_context_->GetImplementation();
-  } else {
-    gles2_context_ = std::make_unique<gpu::GLInProcessContext>();
-    bind_result_ = gles2_context_->Initialize(
-        viz::TestGpuServiceHolder::GetInstance()->task_executor(), attribs_,
-        gpu::SharedMemoryLimits());
-
-    impl_base_ = gles2_context_->GetImplementation();
-  }
-
-  if (bind_result_ != gpu::ContextResult::kSuccess)
-    return bind_result_;
-
-  cache_controller_ = std::make_unique<viz::ContextCacheController>(
-      impl_base_, base::SingleThreadTaskRunner::GetCurrentDefault());
-  if (support_locking_)
-    cache_controller_->SetLock(GetLock());
-
-  if (gles2_context_) {
-    gles2_raster_impl_ =
-        std::make_unique<gpu::raster::RasterImplementationGLES>(
-            ContextGL(), ContextSupport(), ContextCapabilities());
-  }
-
-  return bind_result_;
-}
-
-const gpu::Capabilities& InProcessContextProvider::ContextCapabilities() const {
-  CheckValidThreadOrLockAcquired();
-  return impl_base_->capabilities();
-}
-
-const gpu::GpuFeatureInfo& InProcessContextProvider::GetGpuFeatureInfo() const {
-  CheckValidThreadOrLockAcquired();
-
-  return gles2_context_ ? gles2_context_->GetGpuFeatureInfo()
-                        : raster_context_->GetGpuFeatureInfo();
-}
-
-gpu::gles2::GLES2Interface* InProcessContextProvider::ContextGL() {
-  CheckValidThreadOrLockAcquired();
-  if (!gles2_context_)
-    return nullptr;
-
-  return gles2_context_->GetImplementation();
-}
-
-gpu::raster::RasterInterface* InProcessContextProvider::RasterInterface() {
-  CheckValidThreadOrLockAcquired();
-  return raster_context_ ? raster_context_->GetImplementation()
-                         : gles2_raster_impl_.get();
-}
-
-gpu::ContextSupport* InProcessContextProvider::ContextSupport() {
-  return impl_base_;
-}
-
-class GrDirectContext* InProcessContextProvider::GrContext() {
-  CheckValidThreadOrLockAcquired();
-
-  if (attribs_.enable_oop_rasterization)
-    return nullptr;
-
-  if (gr_context_)
-    return gr_context_->get();
-
-  size_t max_resource_cache_bytes;
-  size_t max_glyph_cache_texture_bytes;
-  gpu::DefaultGrCacheLimitsForTests(&max_resource_cache_bytes,
-                                    &max_glyph_cache_texture_bytes);
-  gr_context_ = std::make_unique<skia_bindings::GrContextForGLES2Interface>(
-      ContextGL(), ContextSupport(), ContextCapabilities(),
-      max_resource_cache_bytes, max_glyph_cache_texture_bytes);
-  cache_controller_->SetGrContext(gr_context_->get());
-
-  return gr_context_->get();
-}
-
-gpu::SharedImageInterface* InProcessContextProvider::SharedImageInterface() {
-  return gles2_context_ ? gles2_context_->GetSharedImageInterface()
-                        : raster_context_->GetSharedImageInterface();
-}
-
-viz::ContextCacheController* InProcessContextProvider::CacheController() {
-  CheckValidThreadOrLockAcquired();
-  return cache_controller_.get();
-}
-
-base::Lock* InProcessContextProvider::GetLock() {
-  if (!support_locking_)
-    return nullptr;
-  return &context_lock_;
-}
-
-void InProcessContextProvider::AddObserver(viz::ContextLostObserver* obs) {
-  observers_.AddObserver(obs);
-}
-
-void InProcessContextProvider::RemoveObserver(viz::ContextLostObserver* obs) {
-  observers_.RemoveObserver(obs);
-}
-
-void InProcessContextProvider::SendOnContextLost() {
-  for (auto& observer : observers_)
-    observer.OnContextLost();
-}
-
-void InProcessContextProvider::CheckValidThreadOrLockAcquired() const {
-#if DCHECK_IS_ON()
-  if (support_locking_) {
-    context_lock_.AssertAcquired();
-  } else {
-    DCHECK(context_thread_checker_.CalledOnValidThread());
-  }
-#endif
-}
-
-}  // namespace ui
diff --git a/ui/compositor/test/in_process_context_provider.h b/ui/compositor/test/in_process_context_provider.h
deleted file mode 100644
index 3f0a766d..0000000
--- a/ui/compositor/test/in_process_context_provider.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2013 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_COMPOSITOR_TEST_IN_PROCESS_CONTEXT_PROVIDER_H_
-#define UI_COMPOSITOR_TEST_IN_PROCESS_CONTEXT_PROVIDER_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/memory/raw_ptr.h"
-#include "base/observer_list.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
-#include "components/viz/common/gpu/context_lost_observer.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/gpu/raster_context_provider.h"
-#include "gpu/command_buffer/common/context_creation_attribs.h"
-#include "gpu/ipc/common/surface_handle.h"
-#include "ipc/raster_in_process_context.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace gpu {
-class GLInProcessContext;
-class GpuMemoryBufferManager;
-class ImplementationBase;
-}
-
-namespace skia_bindings {
-class GrContextForGLES2Interface;
-}
-
-namespace ui {
-
-// TODO(crbug.com/1292507): Merge into viz::TestInProcessContextProvider once
-// on-screen context support is no longer needed.
-class InProcessContextProvider
-    : public base::RefCountedThreadSafe<InProcessContextProvider>,
-      public viz::ContextProvider,
-      public viz::RasterContextProvider {
- public:
-  // Uses default attributes for creating an offscreen context. If `is_worker`
-  // is true then the context will support locking and OOP-R (through
-  // RasterInterface) and won't support GLES2 or GrContext.
-  static scoped_refptr<InProcessContextProvider> CreateOffscreen(
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      bool is_worker);
-
-  InProcessContextProvider(const InProcessContextProvider&) = delete;
-  InProcessContextProvider& operator=(const InProcessContextProvider&) = delete;
-
-  // viz::ContextProvider / viz::RasterContextProvider implementation.
-  void AddRef() const override;
-  void Release() const override;
-  gpu::ContextResult BindToCurrentSequence() override;
-  const gpu::Capabilities& ContextCapabilities() const override;
-  const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override;
-  gpu::gles2::GLES2Interface* ContextGL() override;
-  gpu::raster::RasterInterface* RasterInterface() override;
-  gpu::ContextSupport* ContextSupport() override;
-  class GrDirectContext* GrContext() override;
-  gpu::SharedImageInterface* SharedImageInterface() override;
-  viz::ContextCacheController* CacheController() override;
-  base::Lock* GetLock() override;
-  void AddObserver(viz::ContextLostObserver* obs) override;
-  void RemoveObserver(viz::ContextLostObserver* obs) override;
-
-  // Calls OnContextLost() on all observers. This doesn't modify the context.
-  void SendOnContextLost();
-
- private:
-  friend class base::RefCountedThreadSafe<InProcessContextProvider>;
-
-  InProcessContextProvider(
-      const gpu::ContextCreationAttribs& attribs,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      bool support_locking);
-  ~InProcessContextProvider() override;
-
-  void CheckValidThreadOrLockAcquired() const;
-
-  base::ThreadChecker main_thread_checker_;
-  base::ThreadChecker context_thread_checker_;
-
-  std::unique_ptr<gpu::GLInProcessContext> gles2_context_;
-  std::unique_ptr<gpu::RasterInProcessContext> raster_context_;
-  raw_ptr<gpu::ImplementationBase> impl_base_ = nullptr;
-
-  // Initialized only when `gles2_context_` is used.
-  std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_;
-  std::unique_ptr<gpu::raster::RasterInterface> gles2_raster_impl_;
-
-  std::unique_ptr<viz::ContextCacheController> cache_controller_;
-
-  const bool support_locking_;
-  bool bind_tried_ = false;
-  gpu::ContextResult bind_result_;
-
-  gpu::ContextCreationAttribs attribs_;
-
-  base::Lock context_lock_;
-
-  base::ObserverList<viz::ContextLostObserver>::Unchecked observers_;
-};
-
-}  // namespace ui
-
-#endif  // UI_COMPOSITOR_TEST_IN_PROCESS_CONTEXT_PROVIDER_H_
diff --git a/ui/events/ash/keyboard_capability.cc b/ui/events/ash/keyboard_capability.cc
index d7c1c07..95986d5 100644
--- a/ui/events/ash/keyboard_capability.cc
+++ b/ui/events/ash/keyboard_capability.cc
@@ -6,6 +6,8 @@
 
 #include <fcntl.h>
 #include <linux/input-event-codes.h>
+#include <linux/input.h>
+#include <cstring>
 #include <memory>
 
 #include "ash/constants/ash_features.h"
@@ -14,6 +16,8 @@
 #include "base/containers/fixed_flat_map.h"
 #include "base/containers/fixed_flat_set.h"
 #include "base/containers/flat_set.h"
+#include "base/files/scoped_file.h"
+#include "base/functional/bind.h"
 #include "base/no_destructor.h"
 #include "base/notreached.h"
 #include "base/ranges/algorithm.h"
@@ -28,6 +32,10 @@
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device.h"
 #include "ui/events/devices/input_device_event_observer.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/events/keycodes/dom_us_layout_data.h"
+#include "ui/events/keycodes/keyboard_code_conversion.h"
 #include "ui/events/keycodes/keyboard_codes_posix.h"
 #include "ui/events/ozone/evdev/event_device_info.h"
 
@@ -152,6 +160,43 @@
   return true;
 }
 
+base::ScopedFD GetEventDeviceNameFd(const InputDevice& keyboard) {
+  const char kDevNameProperty[] = "DEVNAME";
+  std::string dev_name;
+  if (!GetDeviceProperty(keyboard.sys_path, kDevNameProperty, dev_name) ||
+      dev_name.empty()) {
+    return base::ScopedFD();
+  }
+
+  base::ScopedFD fd(open(dev_name.c_str(), O_RDONLY));
+  if (fd.get() < 0) {
+    LOG(ERROR) << "Cannot open " << dev_name.c_str() << " : " << errno;
+    return base::ScopedFD();
+  }
+
+  return fd;
+}
+
+absl::optional<uint32_t> ConvertScanCodeToEvdevKey(const base::ScopedFD& fd,
+                                                   uint32_t scancode) {
+  if (fd.get() < 0) {
+    return absl::nullopt;
+  }
+
+  struct input_keymap_entry keymap_entry {
+    .flags = 0, .len = sizeof(scancode), .keycode = 0
+  };
+  memcpy(keymap_entry.scancode, &scancode, sizeof(scancode));
+
+  int ret = ioctl(fd.get(), EVIOCGKEYCODE_V2, &keymap_entry);
+  if (ret < 0) {
+    LOG(ERROR) << "Failed EVIOCGKEYCODE_V2 syscall";
+    return absl::nullopt;
+  }
+
+  return keymap_entry.keycode;
+}
+
 bool GetCustomTopRowLayoutAttribute(const InputDevice& keyboard,
                                     std::string& out_prop) {
   bool result = GetDeviceAttributeRecursive(
@@ -308,61 +353,40 @@
 }
 
 std::vector<TopRowActionKey> IdentifyCustomTopRowActionKeys(
+    const KeyboardCapability::ScanCodeToEvdevKeyConverter&
+        scan_code_to_evdev_key_converter,
+    const InputDevice& keyboard,
     const std::vector<uint32_t>& top_row_scan_codes) {
+  base::ScopedFD fd = GetEventDeviceNameFd(keyboard);
+
   // TODO(dpad): Handle privacy screen in scan code mapping.
-  static constexpr auto kCustomScancodeMapping =
-      base::MakeFixedFlatMap<uint32_t, TopRowActionKey>({
-          // Scan code is only `kCustomScanCodeFKeyMissing` when the FKey is
-          // absent on the keyboard.
-          {kCustomAbsentScanCode, TopRowActionKey::kNone},
-
-          // Vivaldi-specific extended Set-1 AT-style scancodes.
-          {0x90, TopRowActionKey::kPreviousTrack},
-          {0x91, TopRowActionKey::kFullscreen},
-          {0x92, TopRowActionKey::kOverview},
-          {0x93, TopRowActionKey::kScreenshot},
-          {0x94, TopRowActionKey::kScreenBrightnessDown},
-          {0x95, TopRowActionKey::kScreenBrightnessUp},
-          {0x97, TopRowActionKey::kKeyboardBacklightDown},
-          {0x98, TopRowActionKey::kKeyboardBacklightUp},
-          {0x99, TopRowActionKey::kNextTrack},
-          {0x9A, TopRowActionKey::kPlayPause},
-          {0x9B, TopRowActionKey::kMicrophoneMute},
-          {0x9E, TopRowActionKey::kKeyboardBacklightToggle},
-          {0xA0, TopRowActionKey::kVolumeMute},
-          {0xAE, TopRowActionKey::kVolumeDown},
-          {0xB0, TopRowActionKey::kVolumeUp},
-          {0xE9, TopRowActionKey::kForward},
-          {0xEA, TopRowActionKey::kBack},
-          {0xE7, TopRowActionKey::kRefresh},
-
-          // HID 32-bit usage codes
-          {0x070046, TopRowActionKey::kScreenshot},
-          {0x0B002F, TopRowActionKey::kMicrophoneMute},
-          {0x0C00E2, TopRowActionKey::kVolumeMute},
-          {0x0C00E9, TopRowActionKey::kVolumeUp},
-          {0x0C00EA, TopRowActionKey::kVolumeDown},
-          {0x0C006F, TopRowActionKey::kScreenBrightnessUp},
-          {0x0C0070, TopRowActionKey::kScreenBrightnessDown},
-          {0x0C0079, TopRowActionKey::kKeyboardBacklightUp},
-          {0x0C007A, TopRowActionKey::kKeyboardBacklightDown},
-          {0x0C007C, TopRowActionKey::kKeyboardBacklightToggle},
-          {0x0C00B5, TopRowActionKey::kNextTrack},
-          {0x0C00B6, TopRowActionKey::kPreviousTrack},
-          {0x0C00CD, TopRowActionKey::kPlayPause},
-          {0x0C0224, TopRowActionKey::kBack},
-          {0x0C0225, TopRowActionKey::kForward},
-          {0x0C0227, TopRowActionKey::kRefresh},
-          {0x0C0232, TopRowActionKey::kFullscreen},
-          {0x0C029F, TopRowActionKey::kOverview},
-      });
-
   std::vector<TopRowActionKey> top_row_action_keys;
   top_row_action_keys.reserve(top_row_scan_codes.size());
   for (const auto& scancode : top_row_scan_codes) {
-    auto* action_key = kCustomScancodeMapping.find(scancode);
-    if (action_key != kCustomScancodeMapping.end()) {
-      top_row_action_keys.push_back(action_key->second);
+    if (scancode == kCustomAbsentScanCode) {
+      top_row_action_keys.push_back(TopRowActionKey::kNone);
+      continue;
+    }
+
+    auto evdev_key_code = scan_code_to_evdev_key_converter.Run(fd, scancode);
+    if (!evdev_key_code) {
+      top_row_action_keys.push_back(TopRowActionKey::kUnknown);
+      continue;
+    }
+
+    const DomCode dom_code =
+        KeycodeConverter::EvdevCodeToDomCode(*evdev_key_code);
+    KeyboardCode action_vkey = DomCodeToUsLayoutKeyboardCode(dom_code);
+    if (action_vkey == VKEY_UNKNOWN) {
+      if (dom_code == DomCode::SHOW_ALL_WINDOWS) {
+        // Show all windows is through VKEY_MEDIA_LAUNCH_APP1.
+        action_vkey = VKEY_MEDIA_LAUNCH_APP1;
+      }
+    }
+
+    auto action_key = KeyboardCapability::ConvertToTopRowActionKey(action_vkey);
+    if (action_key) {
+      top_row_action_keys.push_back(*action_key);
     } else {
       top_row_action_keys.push_back(TopRowActionKey::kUnknown);
     }
@@ -371,6 +395,9 @@
 }
 
 std::vector<TopRowActionKey> IdentifyTopRowActionKeys(
+    const KeyboardCapability::ScanCodeToEvdevKeyConverter&
+        scan_code_to_evdev_key_converter,
+    const InputDevice& keyboard,
     DeviceType device_type,
     KeyboardTopRowLayout layout,
     const std::vector<uint32_t>& top_row_scan_codes) {
@@ -384,7 +411,8 @@
       return {kLayoutWilcoDrallionTopRowActionKeys.begin(),
               kLayoutWilcoDrallionTopRowActionKeys.end()};
     case KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayoutCustom:
-      return IdentifyCustomTopRowActionKeys(top_row_scan_codes);
+      return IdentifyCustomTopRowActionKeys(scan_code_to_evdev_key_converter,
+                                            keyboard, top_row_scan_codes);
   }
 }
 
@@ -396,6 +424,17 @@
 
 KeyboardCapability::KeyboardCapability(std::unique_ptr<Delegate> delegate)
     : delegate_(std::move(delegate)) {
+  scan_code_to_evdev_key_converter_ =
+      base::BindRepeating(&ConvertScanCodeToEvdevKey);
+  DeviceDataManager::GetInstance()->AddObserver(this);
+}
+
+KeyboardCapability::KeyboardCapability(
+    ScanCodeToEvdevKeyConverter scan_code_to_evdev_key_converter,
+    std::unique_ptr<Delegate> delegate)
+    : scan_code_to_evdev_key_converter_(
+          std::move(scan_code_to_evdev_key_converter)),
+      delegate_(std::move(delegate)) {
   DeviceDataManager::GetInstance()->AddObserver(this);
 }
 
@@ -420,16 +459,8 @@
 std::unique_ptr<EventDeviceInfo>
 KeyboardCapability::CreateEventDeviceInfoFromInputDevice(
     const InputDevice& keyboard) {
-  const char kDevNameProperty[] = "DEVNAME";
-  std::string dev_name;
-  if (!GetDeviceProperty(keyboard.sys_path, kDevNameProperty, dev_name) ||
-      dev_name.empty()) {
-    return nullptr;
-  }
-
-  base::ScopedFD fd(open(dev_name.c_str(), O_RDONLY));
+  base::ScopedFD fd = GetEventDeviceNameFd(keyboard);
   if (fd.get() < 0) {
-    LOG(ERROR) << "Cannot open " << dev_name.c_str() << " : " << errno;
     return nullptr;
   }
 
@@ -468,7 +499,9 @@
           {VKEY_MEDIA_NEXT_TRACK, TopRowActionKey::kNextTrack},
           {VKEY_MEDIA_PREV_TRACK, TopRowActionKey::kPreviousTrack},
           {VKEY_MEDIA_PLAY_PAUSE, TopRowActionKey::kPlayPause},
-          {VKEY_ALL_APPLICATIONS, TopRowActionKey::kLauncher},
+          {VKEY_ALL_APPLICATIONS, TopRowActionKey::kAllApplications},
+          {VKEY_EMOJI_PICKER, TopRowActionKey::kEmojiPicker},
+          {VKEY_DICTATE, TopRowActionKey::kDictation},
       });
   const auto* action_key = kVKeyToTopRowActionKeyMap.find(key_code);
   return (action_key != kVKeyToTopRowActionKeyMap.end())
@@ -748,8 +781,8 @@
   std::tie(keyboard_info.device_type, keyboard_info.top_row_layout,
            keyboard_info.top_row_scan_codes) = IdentifyKeyboardInfo(keyboard);
   keyboard_info.top_row_action_keys = IdentifyTopRowActionKeys(
-      keyboard_info.device_type, keyboard_info.top_row_layout,
-      keyboard_info.top_row_scan_codes);
+      scan_code_to_evdev_key_converter_, keyboard, keyboard_info.device_type,
+      keyboard_info.top_row_layout, keyboard_info.top_row_scan_codes);
   // Enable only when flag is enabled to avoid crashing while problem is
   // addressed. This issue exists the `EventDeviceInfo` objects are only allowed
   // to be created on a thread that allows blocking. See b/272960076
diff --git a/ui/events/ash/keyboard_capability.h b/ui/events/ash/keyboard_capability.h
index bd5e4b8..436881b 100644
--- a/ui/events/ash/keyboard_capability.h
+++ b/ui/events/ash/keyboard_capability.h
@@ -11,6 +11,7 @@
 #include "base/containers/fixed_flat_map.h"
 #include "base/containers/fixed_flat_set.h"
 #include "base/containers/flat_map.h"
+#include "base/files/scoped_file.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/events/ash/mojom/modifier_key.mojom-shared.h"
@@ -44,8 +45,10 @@
   kNextTrack,
   kPreviousTrack,
   kPlayPause,
-  kLauncher,
-  kMaxValue = kLauncher,
+  kAllApplications,
+  kEmojiPicker,
+  kDictation,
+  kMaxValue = kDictation,
 };
 
 inline constexpr auto kLayout1TopRowActionKeys =
@@ -160,6 +163,9 @@
 // as top row key layout, existence of certain keys, what is top right key, etc.
 class KeyboardCapability : public InputDeviceEventObserver {
  public:
+  using ScanCodeToEvdevKeyConverter =
+      base::RepeatingCallback<absl::optional<uint32_t>(const base::ScopedFD& fd,
+                                                       uint32_t scancode)>;
   enum class DeviceType {
     kDeviceUnknown = 0,
     kDeviceInternalKeyboard,
@@ -235,6 +241,8 @@
   };
 
   explicit KeyboardCapability(std::unique_ptr<Delegate> delegate);
+  KeyboardCapability(ScanCodeToEvdevKeyConverter converter,
+                     std::unique_ptr<Delegate> delegate);
   KeyboardCapability(const KeyboardCapability&) = delete;
   KeyboardCapability& operator=(const KeyboardCapability&) = delete;
   ~KeyboardCapability() override;
@@ -258,6 +266,8 @@
   // function keys instead of having them rewritten into back, forward,
   // brightness, volume, etc. or if the user has specified that they desire
   // top-row keys to be treated as function keys globally.
+  // Only useful when InputDeviceSettingsSplit flag is disabled. Otherwise, it
+  // returns non-useful data.
   bool TopRowKeysAreFKeys() const;
 
   // Enable or disable top row keys as F-Keys.
@@ -365,6 +375,8 @@
   const KeyboardInfo* GetKeyboardInfo(const InputDevice& keyboard) const;
   void TrimKeyboardInfoMap();
 
+  ScanCodeToEvdevKeyConverter scan_code_to_evdev_key_converter_;
+
   // Stores event device info objects so they do not need to be constructed
   // multiple times. This is mutable to allow caching results from the APIs
   // which are effectively const.
diff --git a/ui/gfx/geometry/resize_utils.cc b/ui/gfx/geometry/resize_utils.cc
index ff1720a..9b1a0b1 100644
--- a/ui/gfx/geometry/resize_utils.cc
+++ b/ui/gfx/geometry/resize_utils.cc
@@ -32,24 +32,42 @@
 
 }  // namespace
 
-void SizeRectToAspectRatio(ResizeEdge resize_edge,
-                           float aspect_ratio,
-                           const Size& min_window_size,
-                           absl::optional<Size> max_window_size,
-                           Rect* rect) {
+void SizeRectToAspectRatioWithExcludedMargin(
+    ResizeEdge resize_edge,
+    float aspect_ratio,
+    const Size& original_min_window_size,
+    absl::optional<Size> max_window_size,
+    const Size& excluded_margin,
+    Rect& rect) {
   DCHECK_GT(aspect_ratio, 0.0f);
   if (max_window_size.has_value()) {
-    DCHECK_GE(max_window_size->width(), min_window_size.width());
-    DCHECK_GE(max_window_size->height(), min_window_size.height());
-    DCHECK(Rect(rect->origin(), *max_window_size).Contains(*rect))
-        << rect->ToString() << " is larger than the maximum size "
+    DCHECK_GE(max_window_size->width(), original_min_window_size.width());
+    DCHECK_GE(max_window_size->height(), original_min_window_size.height());
+    DCHECK_GE(max_window_size->width(), excluded_margin.width());
+    DCHECK_GE(max_window_size->height(), excluded_margin.height());
+    DCHECK(Rect(rect.origin(), *max_window_size).Contains(rect))
+        << rect.ToString() << " is larger than the maximum size "
         << max_window_size->ToString();
   }
-  DCHECK(rect->Contains(Rect(rect->origin(), min_window_size)))
-      << rect->ToString() << " is smaller than the minimum size "
-      << min_window_size.ToString();
+  DCHECK(rect.Contains(Rect(rect.origin(), original_min_window_size)))
+      << rect.ToString() << " is smaller than the minimum size "
+      << original_min_window_size.ToString();
 
-  Size new_size = rect->size();
+  // Compute the aspect ratio with the excluded margin removed from both the
+  // rectangle and the maximum size. Note that the edge we ask for doesn't
+  // really matter; we'll position the resulting rectangle correctly later.
+  Size new_size(rect.width() - excluded_margin.width(),
+                rect.height() - excluded_margin.height());
+  if (max_window_size) {
+    max_window_size.emplace(
+        max_window_size->width() - excluded_margin.width(),
+        max_window_size->height() - excluded_margin.height());
+  }
+
+  // Also remove the margin from the minimum size, since it'll get added back at
+  // the end.
+  const Size min_window_size = original_min_window_size - excluded_margin;
+
   if (IsResizingHorizontally(resize_edge)) {
     new_size.set_height(base::ClampRound(new_size.width() / aspect_ratio));
     if (min_window_size.height() > new_size.height() ||
@@ -85,13 +103,19 @@
   if (max_window_size.has_value())
     new_size.SetToMin(*max_window_size);
 
+  // The minimum size also excludes any excluded margin, so the content area has
+  // to make up the adjusted difference.
   new_size.SetToMax(min_window_size);
 
+  // Now add the excluded margin back to the total size, so that the total size
+  // is aligned with the resize edge.
+  new_size.Enlarge(excluded_margin.width(), excluded_margin.height());
+
   // |rect| bounds before sizing to aspect ratio.
-  int left = rect->x();
-  int top = rect->y();
-  int right = rect->right();
-  int bottom = rect->bottom();
+  int left = rect.x();
+  int top = rect.y();
+  int right = rect.right();
+  int bottom = rect.bottom();
 
   switch (resize_edge) {
     case ResizeEdge::kRight:
@@ -122,7 +146,17 @@
       break;
   }
 
-  rect->SetByBounds(left, top, right, bottom);
+  rect.SetByBounds(left, top, right, bottom);
+}
+
+void SizeRectToAspectRatio(ResizeEdge resize_edge,
+                           float aspect_ratio,
+                           const Size& min_window_size,
+                           absl::optional<Size> max_window_size,
+                           Rect* rect) {
+  SizeRectToAspectRatioWithExcludedMargin(
+      resize_edge, aspect_ratio, min_window_size, std::move(max_window_size),
+      gfx::Size(), *rect);
 }
 
 }  // namespace gfx
diff --git a/ui/gfx/geometry/resize_utils.h b/ui/gfx/geometry/resize_utils.h
index 7766d4e3..8804f97 100644
--- a/ui/gfx/geometry/resize_utils.h
+++ b/ui/gfx/geometry/resize_utils.h
@@ -35,6 +35,21 @@
                                            absl::optional<Size> max_window_size,
                                            Rect* rect);
 
+// As above, but computes a size for `rect` such that it has the right aspect
+// ratio after subtracting `excluded_margin` from it.  This lets the aspect
+// ratio ignore fixed borders, like a title bar.  For example, if
+// `excluded_margin` is (10, 5) and `aspect_ratio` is 1.0f, then the resulting
+// rectangle might have a size of (30, 25) or (40, 35).  One could use the
+// margin for drawing in the edges, and the part that's left over would have the
+// proper aspect ratio: 20/20 or 30/30, respectively.
+void GEOMETRY_EXPORT
+SizeRectToAspectRatioWithExcludedMargin(ResizeEdge resize_edge,
+                                        float aspect_ratio,
+                                        const Size& min_window_size,
+                                        absl::optional<Size> max_window_size,
+                                        const Size& excluded_margin,
+                                        Rect& rect);
+
 }  // namespace gfx
 
 #endif  // UI_GFX_GEOMETRY_RESIZE_UTILS_H_
diff --git a/ui/gfx/geometry/resize_utils_unittest.cc b/ui/gfx/geometry/resize_utils_unittest.cc
index 1fc6a06c..e3d80cf 100644
--- a/ui/gfx/geometry/resize_utils_unittest.cc
+++ b/ui/gfx/geometry/resize_utils_unittest.cc
@@ -75,6 +75,29 @@
   EXPECT_EQ(rect, GetParam().expected_output_rect) << GetParam().ToString();
 }
 
+TEST_P(ResizeUtilsTest, SizeRectToAspectRatioWithExcludedMargin) {
+  Rect rect = GetParam().input_rect;
+  gfx::Size excluded_margin(2, 4);
+  SizeRectToAspectRatioWithExcludedMargin(
+      GetParam().resize_edge, GetParam().aspect_ratio, GetParam().min_size,
+      GetParam().max_size, excluded_margin, rect);
+  // With excluded margin, size should have the same aspect ratio once we remove
+  // the margin.
+  gfx::Size adjusted_size = rect.size() - excluded_margin;
+  const double actual_ratio =
+      static_cast<double>(adjusted_size.width()) / adjusted_size.height();
+  // Note that all of the aspect ratios are exactly representable, so `EQ` is
+  // really expected.
+  EXPECT_EQ(actual_ratio, GetParam().aspect_ratio) << GetParam().ToString();
+  // Also verify min / max.
+  EXPECT_GE(rect.size().width(), GetParam().min_size.width());
+  EXPECT_GE(rect.size().height(), GetParam().min_size.height());
+  if (GetParam().max_size) {
+    EXPECT_LE(rect.size().width(), GetParam().max_size->width());
+    EXPECT_LE(rect.size().height(), GetParam().max_size->height());
+  }
+}
+
 const SizingParams kSizeRectToSquareAspectRatioTestCases[] = {
     // Dragging the top resizer up.
     {ResizeEdge::kTop, kAspectRatioSquare, kMinSizeHorizontal,
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index 8086578c..3f5d064 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -351,7 +351,8 @@
   // it might indicate that an unsupported ES version was requested. Try
   // falling back to a lower version.
   GLint error = eglGetError();
-  if (gl_display_->ext->b_EGL_KHR_no_config_context && error == EGL_BAD_MATCH) {
+  if (gl_display_->ext->b_EGL_KHR_no_config_context &&
+      (error == EGL_BAD_MATCH || error == EGL_BAD_ATTRIBUTE)) {
     // Set up the list of versions to try: 3.1 -> 3.0 -> 2.0
     std::vector<std::pair<EGLint, EGLint>> candidate_versions;
     if (context_client_major_version == 3 &&
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc
index 0bd3f57..224850e1 100644
--- a/ui/gl/swap_chain_presenter.cc
+++ b/ui/gl/swap_chain_presenter.cc
@@ -321,110 +321,6 @@
   return (std::abs(i - j) < kFullScreenMargin);
 }
 
-void DumpWithoutCrashingForVpSuperResolution(
-    const std::string& hr_key_name,
-    HRESULT hr,
-    UINT gpu_vendor_id,
-    bool is_yuv_swapchain,
-    bool content_is_hdr,
-    const gfx::ColorSpace& src_color_space,
-    const gfx::ColorSpace& output_color_space,
-    bool is_d3d11_video_context1,
-    bool sets_stream_hdr_metadata,
-    bool sets_output_hdr_metadata,
-    bool enables_vp_super_resolution) {
-  // ToggleVpSuperResolution() is called for all GPUs unless a flag disables it.
-  // Only generate dump for GPUs that supports VP Super Resolution.
-  if (gpu_vendor_id != 0x8086 && gpu_vendor_id != 0x10de) {
-    return;
-  }
-
-  // Error code of ToggleVpSuperResolution or VideoProcessorBlt.
-  static auto* hr_key = base::debug::AllocateCrashKeyString(
-      hr_key_name.c_str(), base::debug::CrashKeySize::Size32);
-  base::debug::ScopedCrashKeyString scoped_crash_key(hr_key,
-                                                     base::NumberToString(hr));
-
-  // Video configuration
-  SCOPED_CRASH_KEY_BOOL("", "is_yuv_swapchain", is_yuv_swapchain);
-  SCOPED_CRASH_KEY_BOOL("", "content_is_hdr", content_is_hdr);
-  SCOPED_CRASH_KEY_BOOL("", "is_d3d11_video_context1", is_d3d11_video_context1);
-  SCOPED_CRASH_KEY_BOOL("", "sets_stream_hdr_metadata",
-                        sets_stream_hdr_metadata);
-  SCOPED_CRASH_KEY_BOOL("", "sets_output_hdr_metadata",
-                        sets_output_hdr_metadata);
-  SCOPED_CRASH_KEY_BOOL("", "enables_vp_super_resolution",
-                        enables_vp_super_resolution);
-
-  // Src color space
-  SCOPED_CRASH_KEY_STRING32("", "src_color_space_primary_id",
-                            base::NumberToString(static_cast<uint8_t>(
-                                src_color_space.GetPrimaryID())));
-  SCOPED_CRASH_KEY_STRING32("", "src_color_space_transfer_id",
-                            base::NumberToString(static_cast<uint8_t>(
-                                src_color_space.GetTransferID())));
-  SCOPED_CRASH_KEY_STRING32("", "src_color_space_matrix_id",
-                            base::NumberToString(static_cast<uint8_t>(
-                                src_color_space.GetMatrixID())));
-  SCOPED_CRASH_KEY_STRING32(
-      "", "src_color_space_range_id",
-      base::NumberToString(static_cast<uint8_t>(src_color_space.GetRangeID())));
-
-  // Output color space
-  SCOPED_CRASH_KEY_STRING32("", "output_color_space_primary_id",
-                            base::NumberToString(static_cast<uint8_t>(
-                                output_color_space.GetPrimaryID())));
-  SCOPED_CRASH_KEY_STRING32("", "output_color_space_transfer_id",
-                            base::NumberToString(static_cast<uint8_t>(
-                                output_color_space.GetTransferID())));
-  SCOPED_CRASH_KEY_STRING32("", "output_color_space_matrix_id",
-                            base::NumberToString(static_cast<uint8_t>(
-                                output_color_space.GetMatrixID())));
-  SCOPED_CRASH_KEY_STRING32("", "output_color_space_range_id",
-                            base::NumberToString(static_cast<uint8_t>(
-                                output_color_space.GetRangeID())));
-
-  base::debug::DumpWithoutCrashing();
-}
-
-void DumpWithoutCrashingForToggleVpSuperResolutionError(
-    HRESULT hr,
-    UINT gpu_vendor_id,
-    bool is_yuv_swapchain,
-    bool content_is_hdr,
-    const gfx::ColorSpace& src_color_space,
-    const gfx::ColorSpace& output_color_space,
-    bool is_d3d11_video_context1,
-    bool sets_stream_hdr_metadata,
-    bool sets_output_hdr_metadata,
-    bool enables_vp_super_resolution) {
-  std::string hr_key_name = "vp_super_resolution_ext_error";
-  DumpWithoutCrashingForVpSuperResolution(
-      hr_key_name, hr, gpu_vendor_id, is_yuv_swapchain, content_is_hdr,
-      src_color_space, output_color_space, is_d3d11_video_context1,
-      sets_stream_hdr_metadata, sets_output_hdr_metadata,
-      enables_vp_super_resolution);
-}
-
-void DumpWithoutCrashingForSuperResolutionVideoProcessorBlt(
-    HRESULT hr,
-    UINT gpu_vendor_id,
-    bool is_yuv_swapchain,
-    bool content_is_hdr,
-    const gfx::ColorSpace& src_color_space,
-    const gfx::ColorSpace& output_color_space,
-    bool is_d3d11_video_context1,
-    bool sets_stream_hdr_metadata,
-    bool sets_output_hdr_metadata,
-    bool use_vp_super_resolution) {
-  std::string hr_key_name = "video_processor_blt_error";
-  DumpWithoutCrashingForVpSuperResolution(
-      hr_key_name, hr, gpu_vendor_id, is_yuv_swapchain, content_is_hdr,
-      src_color_space, output_color_space, is_d3d11_video_context1,
-      sets_stream_hdr_metadata, sets_output_hdr_metadata,
-      use_vp_super_resolution);
-}
-
 }  // namespace
 
 SwapChainPresenter::PresentationHistory::PresentationHistory() = default;
@@ -1617,18 +1513,12 @@
   Microsoft::WRL::ComPtr<ID3D11VideoProcessor> video_processor =
       video_processor_wrapper->video_processor;
 
-  // Used for crash keys.
-  bool is_d3d11_video_context1 = false;
-  bool sets_stream_hdr_metadata = false;
-  bool sets_output_hdr_metadata = false;
-
   Microsoft::WRL::ComPtr<IDXGISwapChain3> swap_chain3;
   Microsoft::WRL::ComPtr<ID3D11VideoContext1> context1;
   if (SUCCEEDED(swap_chain_.As(&swap_chain3)) &&
       SUCCEEDED(video_context.As(&context1))) {
     DCHECK(swap_chain3);
     DCHECK(context1);
-    is_d3d11_video_context1 = true;
     // Set input color space.
     context1->VideoProcessorSetStreamColorSpace1(
         video_processor.Get(), 0,
@@ -1660,13 +1550,11 @@
       layer_tree_->GetHDRMetadataHelper()->GetDisplayMetadata();
   if (display_metadata.has_value() && SUCCEEDED(video_context.As(&context2))) {
     if (stream_hdr_metadata.has_value()) {
-      sets_stream_hdr_metadata = true;
       context2->VideoProcessorSetStreamHDRMetaData(
           video_processor.Get(), 0, DXGI_HDR_METADATA_TYPE_HDR10,
           sizeof(DXGI_HDR_METADATA_HDR10), &(*stream_hdr_metadata));
     }
 
-    sets_output_hdr_metadata = true;
     context2->VideoProcessorSetOutputHDRMetaData(
         video_processor.Get(), DXGI_HDR_METADATA_TYPE_HDR10,
         sizeof(DXGI_HDR_METADATA_HDR10), &(*display_metadata));
@@ -1752,13 +1640,6 @@
                                   video_processor.Get(), !is_on_battery_power_);
       if (FAILED(hr)) {
         force_vp_super_resolution_off_ = true;
-        // TODO(crbug.com/1318380): Temporary only. Remove the crash dump once
-        // GPU data is collected.
-        DumpWithoutCrashingForToggleVpSuperResolutionError(
-            hr, gpu_vendor_id_, is_yuv_swapchain, content_is_hdr,
-            src_color_space, output_color_space, is_d3d11_video_context1,
-            sets_stream_hdr_metadata, sets_output_hdr_metadata,
-            !is_on_battery_power_);
       }
       use_vp_super_resolution = !is_on_battery_power_ && SUCCEEDED(hr);
     }
@@ -1774,13 +1655,6 @@
     if (FAILED(hr)) {
       // Retry VideoProcessorBlt with vp super resolution off if it was on.
       if (use_vp_super_resolution) {
-        // TODO(crbug.com/1318380): Temporary only. Remove the crash dump once
-        // GPU data is collected.
-        DumpWithoutCrashingForSuperResolutionVideoProcessorBlt(
-            hr, gpu_vendor_id_, is_yuv_swapchain, content_is_hdr,
-            src_color_space, output_color_space, is_d3d11_video_context1,
-            sets_stream_hdr_metadata, sets_output_hdr_metadata,
-            use_vp_super_resolution);
         DLOG(ERROR) << "Retry VideoProcessorBlt with VpSuperResolution off "
                        "after it failed with error 0x"
                     << std::hex << hr;
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 444ceb3..11515d6 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -1014,6 +1014,8 @@
     "test/mock_drag_controller.h",
     "test/mock_input_event_activation_protector.cc",
     "test/mock_input_event_activation_protector.h",
+    "test/mock_native_widget.cc",
+    "test/mock_native_widget.h",
     "test/native_widget_factory.cc",
     "test/native_widget_factory.h",
     "test/scoped_views_test_helper.cc",
diff --git a/ui/views/test/mock_native_widget.cc b/ui/views/test/mock_native_widget.cc
new file mode 100644
index 0000000..05bd7850
--- /dev/null
+++ b/ui/views/test/mock_native_widget.cc
@@ -0,0 +1,21 @@
+//, Copyright 2023 The Chromium Authors
+//, Use of this source code is governed by a BSD-style license that can be
+//, found in the LICENSE file.
+
+#include "ui/views/test/mock_native_widget.h"
+
+using testing::Return;
+
+namespace views {
+
+MockNativeWidget::MockNativeWidget(Widget* widget) : widget_(widget) {}
+
+MockNativeWidget::~MockNativeWidget() {
+  widget_->OnNativeWidgetDestroyed();
+}
+
+base::WeakPtr<internal::NativeWidgetPrivate> MockNativeWidget::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
+}  // namespace views
diff --git a/ui/views/test/mock_native_widget.h b/ui/views/test/mock_native_widget.h
new file mode 100644
index 0000000..fc291e51
--- /dev/null
+++ b/ui/views/test/mock_native_widget.h
@@ -0,0 +1,179 @@
+//, Copyright 2023 The Chromium Authors
+//, Use of this source code is governed by a BSD-style license that can be
+//, found in the LICENSE file.
+
+#ifndef UI_VIEWS_TEST_MOCK_NATIVE_WIDGET_H_
+#define UI_VIEWS_TEST_MOCK_NATIVE_WIDGET_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/views/widget/native_widget_private.h"
+
+namespace views {
+
+class MockNativeWidget : public internal::NativeWidgetPrivate {
+ public:
+  explicit MockNativeWidget(Widget*);
+  ~MockNativeWidget() override;
+
+  MOCK_METHOD(void, InitNativeWidget, (Widget::InitParams), (override));
+  MOCK_METHOD(void, OnWidgetInitDone, (), (override));
+
+  MOCK_METHOD(std::unique_ptr<NonClientFrameView>,
+              CreateNonClientFrameView,
+              (),
+              (override));
+
+  MOCK_METHOD(bool, ShouldUseNativeFrame, (), (const override));
+  MOCK_METHOD(bool, ShouldWindowContentsBeTransparent, (), (const override));
+  MOCK_METHOD(void, FrameTypeChanged, (), (override));
+  MOCK_METHOD(Widget*, GetWidget, (), (override));
+  MOCK_METHOD(const Widget*, GetWidget, (), (const override));
+  MOCK_METHOD(gfx::NativeView, GetNativeView, (), (const override));
+  MOCK_METHOD(gfx::NativeWindow, GetNativeWindow, (), (const override));
+  MOCK_METHOD(Widget*, GetTopLevelWidget, (), (override));
+  MOCK_METHOD(const ui::Compositor*, GetCompositor, (), (const override));
+  MOCK_METHOD(const ui::Layer*, GetLayer, (), (const override));
+  MOCK_METHOD(void, ReorderNativeViews, (), (override));
+  MOCK_METHOD(void, ViewRemoved, (View * view), (override));
+  MOCK_METHOD(void,
+              SetNativeWindowProperty,
+              (const char* name, void* value),
+              (override));
+  MOCK_METHOD(void*,
+              GetNativeWindowProperty,
+              (const char* name),
+              (const override));
+  MOCK_METHOD(TooltipManager*, GetTooltipManager, (), (const override));
+  MOCK_METHOD(void, SetCapture, (), (override));
+  MOCK_METHOD(void, ReleaseCapture, (), (override));
+  MOCK_METHOD(bool, HasCapture, (), (const override));
+  MOCK_METHOD(ui::InputMethod*, GetInputMethod, (), (override));
+  MOCK_METHOD(void, CenterWindow, (const gfx::Size& size), (override));
+  MOCK_METHOD(void,
+              GetWindowPlacement,
+              (gfx::Rect * bounds, ui::WindowShowState* show_state),
+              (const override));
+  MOCK_METHOD(bool, SetWindowTitle, (const std::u16string& title), (override));
+  MOCK_METHOD(void,
+              SetWindowIcons,
+              (const gfx::ImageSkia& window_icon,
+               const gfx::ImageSkia& app_icon),
+              (override));
+  MOCK_METHOD(const gfx::ImageSkia*, GetWindowIcon, (), (override));
+  MOCK_METHOD(const gfx::ImageSkia*, GetWindowAppIcon, (), (override));
+  MOCK_METHOD(void, InitModalType, (ui::ModalType modal_type), (override));
+  MOCK_METHOD(gfx::Rect, GetWindowBoundsInScreen, (), (const override));
+  MOCK_METHOD(gfx::Rect, GetClientAreaBoundsInScreen, (), (const override));
+  MOCK_METHOD(gfx::Rect, GetRestoredBounds, (), (const override));
+  MOCK_METHOD(std::string, GetWorkspace, (), (const override));
+  MOCK_METHOD(void, SetBounds, (const gfx::Rect& bounds), (override));
+  MOCK_METHOD(void,
+              SetBoundsConstrained,
+              (const gfx::Rect& bounds),
+              (override));
+  MOCK_METHOD(void, SetSize, (const gfx::Size& size), (override));
+  MOCK_METHOD(void, StackAbove, (gfx::NativeView native_view), (override));
+  MOCK_METHOD(void, StackAtTop, (), (override));
+  MOCK_METHOD(bool, IsStackedAbove, (gfx::NativeView native_view), (override));
+  MOCK_METHOD(void,
+              SetShape,
+              (std::unique_ptr<Widget::ShapeRects> shape),
+              (override));
+  MOCK_METHOD(void, Close, (), (override));
+  MOCK_METHOD(void, CloseNow, (), (override));
+  MOCK_METHOD(void,
+              Show,
+              (ui::WindowShowState show_state, const gfx::Rect& restore_bounds),
+              (override));
+  MOCK_METHOD(void, Hide, (), (override));
+  MOCK_METHOD(bool, IsVisible, (), (const override));
+  MOCK_METHOD(void, Activate, (), (override));
+  MOCK_METHOD(void, Deactivate, (), (override));
+  MOCK_METHOD(bool, IsActive, (), (const override));
+  MOCK_METHOD(void, SetZOrderLevel, (ui::ZOrderLevel order), (override));
+  MOCK_METHOD(ui::ZOrderLevel, GetZOrderLevel, (), (const override));
+  MOCK_METHOD(void,
+              SetVisibleOnAllWorkspaces,
+              (bool always_visible),
+              (override));
+  MOCK_METHOD(bool, IsVisibleOnAllWorkspaces, (), (const override));
+  MOCK_METHOD(void, Maximize, (), (override));
+  MOCK_METHOD(void, Minimize, (), (override));
+  MOCK_METHOD(bool, IsMaximized, (), (const override));
+  MOCK_METHOD(bool, IsMinimized, (), (const override));
+  MOCK_METHOD(void, Restore, (), (override));
+  MOCK_METHOD(void,
+              SetFullscreen,
+              (bool fullscreen, int64_t target_display_id),
+              (override));
+  MOCK_METHOD(bool, IsFullscreen, (), (const override));
+  MOCK_METHOD(void,
+              SetCanAppearInExistingFullscreenSpaces,
+              (bool can_appear_in_existing_fullscreen_spaces),
+              (override));
+  MOCK_METHOD(void, SetOpacity, (float opacity), (override));
+  MOCK_METHOD(void,
+              SetAspectRatio,
+              (const gfx::SizeF& aspect_ratio,
+               const gfx::Size& excluded_margin),
+              (override));
+  MOCK_METHOD(void, FlashFrame, (bool flash), (override));
+  MOCK_METHOD(void,
+              RunShellDrag,
+              (View * view,
+               std::unique_ptr<ui::OSExchangeData> data,
+               const gfx::Point& location,
+               int operation,
+               ui::mojom::DragEventSource source),
+              (override));
+  MOCK_METHOD(void, SchedulePaintInRect, (const gfx::Rect& rect), (override));
+  MOCK_METHOD(void, ScheduleLayout, (), (override));
+  MOCK_METHOD(void, SetCursor, (const ui::Cursor& cursor), (override));
+  MOCK_METHOD(void, ShowEmojiPanel, (), (override));
+  MOCK_METHOD(bool, IsMouseEventsEnabled, (), (const override));
+  MOCK_METHOD(bool, IsMouseButtonDown, (), (const override));
+  MOCK_METHOD(void, ClearNativeFocus, (), (override));
+  MOCK_METHOD(gfx::Rect, GetWorkAreaBoundsInScreen, (), (const override));
+  MOCK_METHOD(bool, IsMoveLoopSupported, (), (const override));
+  MOCK_METHOD(Widget::MoveLoopResult,
+              RunMoveLoop,
+              (const gfx::Vector2d& drag_offset,
+               Widget::MoveLoopSource source,
+               Widget::MoveLoopEscapeBehavior escape_behavior),
+              (override));
+  MOCK_METHOD(void, EndMoveLoop, (), (override));
+  MOCK_METHOD(void,
+              SetVisibilityChangedAnimationsEnabled,
+              (bool value),
+              (override));
+  MOCK_METHOD(void,
+              SetVisibilityAnimationDuration,
+              (const base::TimeDelta& duration),
+              (override));
+  MOCK_METHOD(void,
+              SetVisibilityAnimationTransition,
+              (Widget::VisibilityTransition transition),
+              (override));
+  MOCK_METHOD(bool, IsTranslucentWindowOpacitySupported, (), (const override));
+  MOCK_METHOD(ui::GestureRecognizer*, GetGestureRecognizer, (), (override));
+  MOCK_METHOD(ui::GestureConsumer*, GetGestureConsumer, (), (override));
+  MOCK_METHOD(void, OnSizeConstraintsChanged, (), (override));
+  MOCK_METHOD(void, OnNativeViewHierarchyWillChange, (), (override));
+  MOCK_METHOD(void, OnNativeViewHierarchyChanged, (), (override));
+  MOCK_METHOD(std::string, GetName, (), (const override));
+
+  base::WeakPtr<NativeWidgetPrivate> GetWeakPtr() override;
+
+ private:
+  raw_ptr<Widget> widget_;
+  base::WeakPtrFactory<MockNativeWidget> weak_factory_{this};
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_TEST_MOCK_NATIVE_WIDGET_H_
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 8f1aab2..07f4fc7 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -1033,9 +1033,10 @@
     desktop_window_tree_host_->SetOpacity(opacity);
 }
 
-void DesktopNativeWidgetAura::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
+void DesktopNativeWidgetAura::SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                                             const gfx::Size& excluded_margin) {
   if (desktop_window_tree_host_)
-    desktop_window_tree_host_->SetAspectRatio(aspect_ratio);
+    desktop_window_tree_host_->SetAspectRatio(aspect_ratio, excluded_margin);
 }
 
 void DesktopNativeWidgetAura::FlashFrame(bool flash_frame) {
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index b49e493..fbee21c 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -184,7 +184,9 @@
   void SetCanAppearInExistingFullscreenSpaces(
       bool can_appear_in_existing_fullscreen_spaces) override;
   void SetOpacity(float opacity) override;
-  void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
+  // See NativeWidgetPrivate::SetAspectRatio for more information.
+  void SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                      const gfx::Size& excluded_margin) override;
   void FlashFrame(bool flash_frame) override;
   void RunShellDrag(View* view,
                     std::unique_ptr<ui::OSExchangeData> data,
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/ui/views/widget/desktop_aura/desktop_window_tree_host.h
index b219dca..6828dd7 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host.h
@@ -175,7 +175,10 @@
 
   virtual void SetOpacity(float opacity) = 0;
 
-  virtual void SetAspectRatio(const gfx::SizeF& aspect_ratio) = 0;
+  // See NativeWidgetPrivate::SetAspectRatio for more information about what
+  // `excluded_margin` does.
+  virtual void SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                              const gfx::Size& excluded_margin) = 0;
 
   virtual void SetWindowIcons(const gfx::ImageSkia& window_icon,
                               const gfx::ImageSkia& app_icon) = 0;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index 217c3c58..22487e3 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -731,7 +731,12 @@
 }
 
 void DesktopWindowTreeHostPlatform::SetAspectRatio(
-    const gfx::SizeF& aspect_ratio) {
+    const gfx::SizeF& aspect_ratio,
+    const gfx::Size& excluded_margin) {
+  // TODO(crbug.com/1407629): send `excluded_margin`.
+  if (excluded_margin.width() > 0 || excluded_margin.height() > 0) {
+    NOTIMPLEMENTED_LOG_ONCE();
+  }
   platform_window()->SetAspectRatio(aspect_ratio);
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
index 5cecf15..cbbfcd0 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -123,7 +123,8 @@
   void SetFullscreen(bool fullscreen, int64_t display_id) override;
   bool IsFullscreen() const override;
   void SetOpacity(float opacity) override;
-  void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
+  void SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                      const gfx::Size& excluded_margin) override;
   void SetWindowIcons(const gfx::ImageSkia& window_icon,
                       const gfx::ImageSkia& app_icon) override;
   void InitModalType(ui::ModalType modal_type) override;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index a9a0ae058..3d22d93 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -567,10 +567,12 @@
   content_window()->layer()->SetOpacity(opacity);
 }
 
-void DesktopWindowTreeHostWin::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
+void DesktopWindowTreeHostWin::SetAspectRatio(
+    const gfx::SizeF& aspect_ratio,
+    const gfx::Size& excluded_margin) {
   DCHECK(!aspect_ratio.IsEmpty());
-  message_handler_->SetAspectRatio(aspect_ratio.width() /
-                                   aspect_ratio.height());
+  message_handler_->SetAspectRatio(aspect_ratio.width() / aspect_ratio.height(),
+                                   excluded_margin);
 }
 
 void DesktopWindowTreeHostWin::SetWindowIcons(const gfx::ImageSkia& window_icon,
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
index 812f9a6..2e4bacce 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -146,7 +146,8 @@
   void SetFullscreen(bool fullscreen, int64_t target_display_id) override;
   bool IsFullscreen() const override;
   void SetOpacity(float opacity) override;
-  void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
+  void SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                      const gfx::Size& excluded_margin) override;
   void SetWindowIcons(const gfx::ImageSkia& window_icon,
                       const gfx::ImageSkia& app_icon) override;
   void InitModalType(ui::ModalType modal_type) override;
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index f1949d4..648f6f8 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -787,11 +787,16 @@
     window_->layer()->SetOpacity(opacity);
 }
 
-void NativeWidgetAura::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
+void NativeWidgetAura::SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                                      const gfx::Size& excluded_margin) {
   DCHECK(!aspect_ratio.IsEmpty());
+  if (excluded_margin.width() > 0 || excluded_margin.height() > 0) {
+    NOTIMPLEMENTED_LOG_ONCE();
+  }
   if (window_) {
     // aura::client::kAspectRatio is owned, which allows for passing by value.
-    window_->SetProperty(aura::client::kAspectRatio, gfx::SizeF(aspect_ratio));
+    window_->SetProperty(aura::client::kAspectRatio, aspect_ratio);
+    // TODO(crbug.com/1407629): send `excluded_margin`.
   }
 }
 
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h
index 5fcf32d..18f07072 100644
--- a/ui/views/widget/native_widget_aura.h
+++ b/ui/views/widget/native_widget_aura.h
@@ -139,7 +139,8 @@
   void SetCanAppearInExistingFullscreenSpaces(
       bool can_appear_in_existing_fullscreen_spaces) override;
   void SetOpacity(float opacity) override;
-  void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
+  void SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                      const gfx::Size& excluded_margin) override;
   void FlashFrame(bool flash_frame) override;
   void RunShellDrag(View* view,
                     std::unique_ptr<ui::OSExchangeData> data,
diff --git a/ui/views/widget/native_widget_mac.h b/ui/views/widget/native_widget_mac.h
index dd05df21..e24ce9d 100644
--- a/ui/views/widget/native_widget_mac.h
+++ b/ui/views/widget/native_widget_mac.h
@@ -175,7 +175,8 @@
   void SetCanAppearInExistingFullscreenSpaces(
       bool can_appear_in_existing_fullscreen_spaces) override;
   void SetOpacity(float opacity) override;
-  void SetAspectRatio(const gfx::SizeF& aspect_ratio) override;
+  void SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                      const gfx::Size& excluded_margin) override;
   void FlashFrame(bool flash_frame) override;
   void RunShellDrag(View* view,
                     std::unique_ptr<ui::OSExchangeData> data,
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 8ba3c85c..9684386 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -724,10 +724,11 @@
   GetNSWindowMojo()->SetOpacity(opacity);
 }
 
-void NativeWidgetMac::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
+void NativeWidgetMac::SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                                     const gfx::Size& excluded_margin) {
   if (!GetNSWindowMojo())
     return;
-  GetNSWindowMojo()->SetAspectRatio(aspect_ratio);
+  GetNSWindowMojo()->SetAspectRatio(aspect_ratio, excluded_margin);
 }
 
 void NativeWidgetMac::FlashFrame(bool flash_frame) {
diff --git a/ui/views/widget/native_widget_private.h b/ui/views/widget/native_widget_private.h
index 1317ea4..b2bd0509 100644
--- a/ui/views/widget/native_widget_private.h
+++ b/ui/views/widget/native_widget_private.h
@@ -204,7 +204,16 @@
   virtual void SetCanAppearInExistingFullscreenSpaces(
       bool can_appear_in_existing_fullscreen_spaces) = 0;
   virtual void SetOpacity(float opacity) = 0;
-  virtual void SetAspectRatio(const gfx::SizeF& aspect_ratio) = 0;
+  // The size of the widget will be set such that it is in the same proportion
+  // as `aspect_ratio` after subtracting `excluded_margin` from the widget size.
+  //
+  // This allows the aspect ratio to refer to just a subrectangle of the widget,
+  // to leave room for, e.g., a client-drawn title bar or window decorations.
+  // System-drawn decorations are excluded automatically, but the system has no
+  // idea if we decide to draw our own.  By setting `excluded_margin` to our
+  // custom-drawn decorations, we can maintain the same behavior.
+  virtual void SetAspectRatio(const gfx::SizeF& aspect_ratio,
+                              const gfx::Size& excluded_margin) = 0;
   virtual void FlashFrame(bool flash) = 0;
   virtual void RunShellDrag(View* view,
                             std::unique_ptr<ui::OSExchangeData> data,
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 7052e57..eb53fdc1 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -954,8 +954,19 @@
 }
 
 void Widget::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
-  if (native_widget_)
-    native_widget_->SetAspectRatio(aspect_ratio);
+  if (!native_widget_) {
+    return;
+  }
+
+  // The aspect ratio affects the client view only, so figure out how much of
+  // the widget isn't taken up by the client view.
+  gfx::Size excluded_margin;
+  if (non_client_view() && non_client_view()->frame_view()) {
+    excluded_margin =
+        non_client_view()->bounds().size() -
+        non_client_view()->frame_view()->GetBoundsForClientView().size();
+  }
+  native_widget_->SetAspectRatio(aspect_ratio, excluded_margin);
 }
 
 void Widget::FlashFrame(bool flash) {
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 4d64cbb6..478b38681 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -783,8 +783,12 @@
   // underlying windowing system.
   void SetOpacity(float opacity);
 
-  // Sets the aspect ratio of the widget's content, which will be maintained
-  // during interactive resizing. This size disregards title bar and borders.
+  // Sets the aspect ratio of the widget's client view, which will be maintained
+  // during interactive resizing.  Note that for widgets that have a client view
+  // that is framed by custom-drawn borders / window frame / etc, the widget
+  // size will be chosen so that the aspect ratio of client view, not the entire
+  // widget, will be `aspect_ratio`.
+  //
   // Once set, some platforms ensure the content will only size to integer
   // multiples of |aspect_ratio|.
   void SetAspectRatio(const gfx::SizeF& aspect_ratio);
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
index 68490051..5fd4c36 100644
--- a/ui/views/widget/widget_unittest.cc
+++ b/ui/views/widget/widget_unittest.cc
@@ -45,6 +45,7 @@
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/style/platform_style.h"
 #include "ui/views/test/mock_drag_controller.h"
+#include "ui/views/test/mock_native_widget.h"
 #include "ui/views/test/native_widget_factory.h"
 #include "ui/views/test/test_views.h"
 #include "ui/views/test/test_widget_observer.h"
@@ -56,6 +57,7 @@
 #include "ui/views/widget/native_widget_private.h"
 #include "ui/views/widget/root_view.h"
 #include "ui/views/widget/unique_widget_ptr.h"
+#include "ui/views/widget/widget_delegate.h"
 #include "ui/views/widget/widget_deletion_observer.h"
 #include "ui/views/widget/widget_interactive_uitest_utils.h"
 #include "ui/views/widget/widget_removals_observer.h"
@@ -5281,6 +5283,88 @@
   }
 }
 
+// Parameterized test that verifies the behavior of SetAspectRatio with respect
+// to the excluded margin.
+class WidgetSetAspectRatioTest
+    : public ViewsTestBase,
+      public testing::WithParamInterface<gfx::Size /* margin */> {
+ public:
+  WidgetSetAspectRatioTest() : margin_(GetParam()) {}
+
+  WidgetSetAspectRatioTest(const WidgetSetAspectRatioTest&) = delete;
+  WidgetSetAspectRatioTest& operator=(const WidgetSetAspectRatioTest&) = delete;
+
+  ~WidgetSetAspectRatioTest() override = default;
+
+  // ViewsTestBase:
+  void SetUp() override {
+    ViewsTestBase::SetUp();
+    widget_ = std::make_unique<Widget>();
+    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+    native_widget_ = std::make_unique<MockNativeWidget>(widget());
+    ON_CALL(*native_widget(), CreateNonClientFrameView).WillByDefault([this]() {
+      return std::make_unique<NonClientFrameViewWithFixedMargin>(margin());
+    });
+    params.native_widget = native_widget();
+    widget()->Init(std::move(params));
+    task_environment()->RunUntilIdle();
+  }
+
+  void TearDown() override {
+    native_widget_.reset();
+    widget()->Close();
+    widget_.reset();
+    ViewsTestBase::TearDown();
+  }
+
+  const gfx::Size& margin() const { return margin_; }
+  Widget* widget() { return widget_.get(); }
+  MockNativeWidget* native_widget() { return native_widget_.get(); }
+
+ private:
+  // Margin around the client view that should be excluded.
+  const gfx::Size margin_;
+  std::unique_ptr<Widget> widget_;
+  std::unique_ptr<MockNativeWidget> native_widget_;
+
+  // `NonClientFrameView` that pads the client view with a fixed-size margin,
+  // to leave room for drawing that's not included in the aspect ratio.
+  class NonClientFrameViewWithFixedMargin : public NonClientFrameView {
+   public:
+    // `margin` is the margin that we'll provide to our client view.
+    explicit NonClientFrameViewWithFixedMargin(const gfx::Size& margin)
+        : margin_(margin) {}
+
+    // NonClientFrameView
+    gfx::Rect GetBoundsForClientView() const override {
+      gfx::Rect r = bounds();
+      return gfx::Rect(r.x(), r.y(), r.width() - margin_.width(),
+                       r.height() - margin_.height());
+    }
+
+    const gfx::Size margin_;
+  };
+};
+
+TEST_P(WidgetSetAspectRatioTest, SetAspectRatioIncludesMargin) {
+  // Provide a nonzero size.  It doesn't particularly matter what, as long as
+  // it's larger than our margin.
+  const gfx::Rect root_view_bounds(0, 0, 100, 200);
+  ASSERT_GT(root_view_bounds.width(), margin().width());
+  ASSERT_GT(root_view_bounds.height(), margin().height());
+  widget()->non_client_view()->SetBoundsRect(root_view_bounds);
+
+  // Verify that the excluded margin matches the margin that our custom
+  // non-client frame provides.
+  const gfx::SizeF aspect_ratio(1.5f, 1.0f);
+  EXPECT_CALL(*native_widget(), SetAspectRatio(aspect_ratio, margin()));
+  widget()->SetAspectRatio(aspect_ratio);
+}
+
+INSTANTIATE_TEST_SUITE_P(WidgetSetAspectRatioTestInstantiation,
+                         WidgetSetAspectRatioTest,
+                         ::testing::Values(gfx::Size(15, 20), gfx::Size(0, 0)));
+
 class WidgetShadowTest : public WidgetTest {
  public:
   WidgetShadowTest() = default;
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 05f4c45..bde6bc5a 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -1133,12 +1133,17 @@
     PerformDwmTransition();
 }
 
-void HWNDMessageHandler::SetAspectRatio(float aspect_ratio) {
+void HWNDMessageHandler::SetAspectRatio(float aspect_ratio,
+                                        const gfx::Size& excluded_margin) {
   // If the aspect ratio is not in the valid range, do nothing.
   DCHECK_GT(aspect_ratio, 0.0f);
 
   aspect_ratio_ = aspect_ratio;
 
+  // Convert to pixels.
+  excluded_margin_ =
+      display::win::ScreenWin::DIPToScreenSize(hwnd(), excluded_margin);
+
   // When the aspect ratio is set, size the window to adhere to it. This keeps
   // the same origin point as the original window.
   RECT window_rect;
@@ -3797,8 +3802,9 @@
   if (!max_window_size.IsEmpty())
     max_size_param = max_window_size;
 
-  gfx::SizeRectToAspectRatio(GetWindowResizeEdge(param), aspect_ratio_.value(),
-                             min_window_size, max_size_param, window_rect);
+  gfx::SizeRectToAspectRatioWithExcludedMargin(
+      GetWindowResizeEdge(param), aspect_ratio_.value(), min_window_size,
+      max_size_param, excluded_margin_, *window_rect);
 }
 
 POINT HWNDMessageHandler::GetCursorPos() const {
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h
index 3afa60b..694945c 100644
--- a/ui/views/win/hwnd_message_handler.h
+++ b/ui/views/win/hwnd_message_handler.h
@@ -187,7 +187,7 @@
   void SetFullscreen(bool fullscreen, int64_t target_display_id);
 
   // Updates the aspect ratio of the window.
-  void SetAspectRatio(float aspect_ratio);
+  void SetAspectRatio(float aspect_ratio, const gfx::Size& excluded_mar);
 
   // Updates the window style to reflect whether it can be resized or maximized.
   void SizeConstraintsChanged();
@@ -652,6 +652,9 @@
   // for the non-client area.
   absl::optional<float> aspect_ratio_;
 
+  // Size to exclude from aspect ratio calculation.
+  gfx::Size excluded_margin_;
+
   // The current DPI.
   int dpi_;
 
diff --git a/ui/webui/examples/browser/ui/web/webui.cc b/ui/webui/examples/browser/ui/web/webui.cc
index 952b030..ec2045f7 100644
--- a/ui/webui/examples/browser/ui/web/webui.cc
+++ b/ui/webui/examples/browser/ui/web/webui.cc
@@ -47,7 +47,7 @@
   EnableTrustedTypesCSP(source);
   source->AddString(
       "chromeRefresh2023Attribute",
-      features::IsChromeRefresh2023() ? "chrome-refresh-2023" : "");
+      features::IsChromeWebuiRefresh2023() ? "chrome-refresh-2023" : "");
   source->AddResourcePaths(resources);
   source->AddResourcePath("", default_resource);
 }
diff --git a/weblayer/browser/java/BUILD.gn b/weblayer/browser/java/BUILD.gn
index 1b411748..bf26aee 100644
--- a/weblayer/browser/java/BUILD.gn
+++ b/weblayer/browser/java/BUILD.gn
@@ -9,15 +9,6 @@
 import("//tools/grit/grit_rule.gni")
 import("//weblayer/variables.gni")
 
-_bundle_utils_output =
-    "$target_gen_dir/org/chromium/weblayer_private/WebLayerBundleUtils.java"
-
-jinja_template("weblayer_bundle_utils") {
-  input = "WebLayerBundleUtils.java.jinja2"
-  output = _bundle_utils_output
-  variables = "weblayer_in_split=$weblayer_in_split"
-}
-
 android_resources("weblayer_resources") {
   sources = [
     "res/drawable/weblayer_tab_indicator.xml",
@@ -188,7 +179,6 @@
     "org/chromium/weblayer_private/resources/ResourceMapper.java",
     "org/chromium/weblayer_private/settings/WebLayerAccessibilitySettingsDelegate.java",
     "org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java",
-    _bundle_utils_output,
   ]
   resources_package = "org.chromium.weblayer_private"
 
@@ -197,7 +187,6 @@
     ":base_module_java",
     ":gms_bridge_java",
     ":interfaces_java",
-    ":weblayer_bundle_utils",
     ":weblayer_resources",
     "//base:base_java",
     "//base:jni_java",
diff --git a/weblayer/browser/java/WebLayerBundleUtils.java.jinja2 b/weblayer/browser/java/WebLayerBundleUtils.java.jinja2
deleted file mode 100644
index 0b7c14b..0000000
--- a/weblayer/browser/java/WebLayerBundleUtils.java.jinja2
+++ /dev/null
@@ -1,9 +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.
-
-package org.chromium.weblayer_private;
-
-public final class WebLayerBundleUtils {
-  public static final boolean IS_WEBLAYER_IN_SPLIT = {{ weblayer_in_split }};
-}
diff --git a/weblayer/variables.gni b/weblayer/variables.gni
index 1cbbaff..d954ffe 100644
--- a/weblayer/variables.gni
+++ b/weblayer/variables.gni
@@ -7,9 +7,6 @@
 declare_args() {
   # Include the //weblayer code in WebView implementation APKs.
   webview_includes_weblayer = true
-
-  # Whether WebLayer will be included as a DFM.
-  weblayer_in_split = true
 }
 
 weblayer_product_config_java_package = "org.chromium.weblayer_private"