diff --git a/DEPS b/DEPS
index d240a87..16ef234 100644
--- a/DEPS
+++ b/DEPS
@@ -304,15 +304,15 @@
   # 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': '787feb9bce958b384ed5ac3540f66ccee995799f',
+  'skia_revision': '8a10a599da12aa6a4c0e7a8257e0c9126cfdc40a',
   # 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': 'bae471798c44a9c74535d84763f8df0783f3984c',
+  'v8_revision': '06394358bbdcc16c717137e250f6b16e92f0d97a',
   # 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': 'e960355a9a22876559e251953080349a755bb497',
+  'angle_revision': 'c98a413c3ea78e848aba54ca2073e8b188e0de55',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -351,7 +351,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': 'b3e21e407441add84bcb5ee6ce90528678c53840',
+  'nacl_revision': '5b530a9ffd34be8541037262cf47cf3924bfc973',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -375,7 +375,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': '4d42668497b0dfda68985c15abd012ec68135325',
+  'catapult_revision': 'e4385f1ba03b39417360173ed600c9c5b7f7909a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -383,7 +383,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': '9ce7b48e6fe5aeb2a5585da4490ff2f76911b6fa',
+  'devtools_frontend_revision': 'd3c717b31da5d37df246c6b0ba3318171fde83d3',
   # 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.
@@ -419,7 +419,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': '0f72763efd10050192de79255504265985c4a4f2',
+  'dawn_revision': '785ccde2f588a76e7b1024f54f27032e0606be11',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -770,12 +770,12 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    '546fb1c936ae81f7cea8b3c521af866b303229be',
+    'b1e22352ca1cb924399d685bcbaeb7e753240ee0',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '24f53f9c8b1f5c4724047441918d9c6c4524d2f4',
+    'url': Var('chromium_git') + '/website.git' + '@' + '044f408f0cd7d614d7f1dfa3e25a8063544bfc42',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -1204,13 +1204,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c8f23e26bee90ce6b02211c9489d4e4e947af02a',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'aec39c38f8ed9e10e61679a0d7f7cdbd949e302c',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '8463f321ba6713c0929ae6840ffdee703b1e3ccc',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'f584941aba199d17623d55f2776e4d48d6d6f296',
     'condition': 'checkout_src_internal',
   },
 
@@ -1430,7 +1430,7 @@
     Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'e8712e415627f22d0b00ebee8db99547077f39bd',
 
   'src/third_party/libaom/source/libaom':
-    Var('aomedia_git') + '/aom.git' + '@' +  '0b76cc07c5a3a5bfcb737cddc7452137d58197d9',
+    Var('aomedia_git') + '/aom.git' + '@' +  '5115747345e7de18fdbafc333e078604f39ba932',
 
   'src/third_party/libavif/src':
     Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'),
@@ -1899,7 +1899,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@51b9a57e687a853b77dc0060d944f95d28693ea3',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2cd58e3be41167469f9d6a06fcd2bc34afa11b3f',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwPageLoadMetricsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwPageLoadMetricsTest.java
index 9cea38e6e..57095a2 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwPageLoadMetricsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwPageLoadMetricsTest.java
@@ -20,7 +20,6 @@
 import org.chromium.android_webview.metrics.AwMetricsServiceClient;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.MetricsUtils;
 import org.chromium.blink.mojom.WebFeature;
@@ -121,7 +120,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest(message = "https://crbug.com/1312527")
     public void testFirstInputDelay4() throws Throwable {
         final String data = "<html><head></head><body>"
                 + "<p>Hello World</p><input type='text' id='text1'>"
@@ -131,7 +129,18 @@
                 "PageLoad.InteractiveTiming.FirstInputDelay4");
         loadUrlSync(url);
         executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
-        dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
+
+        // On emulator, the page might not ready for accepting the input, multiple endeavor is
+        // needed.
+        AwActivityTestRule.pollInstrumentationThread(() -> {
+            try {
+                dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
+                return !"\"\"".equals(executeJavaScriptAndWaitForResult(
+                        "document.getElementById('text1').value;"));
+            } catch (Throwable e) {
+                return false;
+            }
+        });
         AwActivityTestRule.pollInstrumentationThread(
                 () -> (1 + firstInputDelay4
                         == RecordHistogram.getHistogramTotalCountForTesting(
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 9aaeb29..d873df3 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -252,8 +252,6 @@
     "assistant/assistant_notification_controller_impl.h",
     "assistant/assistant_notification_expiry_monitor.cc",
     "assistant/assistant_notification_expiry_monitor.h",
-    "assistant/assistant_screen_context_controller_impl.cc",
-    "assistant/assistant_screen_context_controller_impl.h",
     "assistant/assistant_setup_controller.cc",
     "assistant/assistant_setup_controller.h",
     "assistant/assistant_state_controller.cc",
@@ -586,14 +584,6 @@
     "glanceables/glanceables_window_hider.h",
     "glanceables/signout_screenshot_handler.cc",
     "glanceables/signout_screenshot_handler.h",
-    "highlighter/highlighter_controller.cc",
-    "highlighter/highlighter_controller.h",
-    "highlighter/highlighter_gesture_util.cc",
-    "highlighter/highlighter_gesture_util.h",
-    "highlighter/highlighter_result_view.cc",
-    "highlighter/highlighter_result_view.h",
-    "highlighter/highlighter_view.cc",
-    "highlighter/highlighter_view.h",
     "host/ash_window_tree_host.cc",
     "host/ash_window_tree_host.h",
     "host/ash_window_tree_host_delegate.h",
@@ -1344,9 +1334,8 @@
     "system/input_device_settings/input_device_settings_controller_impl.h",
     "system/input_device_settings/input_device_settings_defaults.h",
     "system/input_device_settings/input_device_settings_pref_names.h",
+    "system/input_device_settings/input_device_tracker.cc",
     "system/input_device_settings/input_device_tracker.h",
-    "system/input_device_settings/input_device_tracker_impl.cc",
-    "system/input_device_settings/input_device_tracker_impl.h",
     "system/input_device_settings/pref_handlers/keyboard_pref_handler.h",
     "system/input_device_settings/pref_handlers/keyboard_pref_handler_impl.cc",
     "system/input_device_settings/pref_handlers/keyboard_pref_handler_impl.h",
@@ -1619,6 +1608,8 @@
     "system/phonehub/phone_connecting_view.h",
     "system/phonehub/phone_disconnected_view.cc",
     "system/phonehub/phone_disconnected_view.h",
+    "system/phonehub/phone_hub_app_count_icon.cc",
+    "system/phonehub/phone_hub_app_count_icon.h",
     "system/phonehub/phone_hub_content_view.cc",
     "system/phonehub/phone_hub_content_view.h",
     "system/phonehub/phone_hub_interstitial_view.cc",
@@ -2277,6 +2268,8 @@
     "wm/snap_group/snap_group.h",
     "wm/snap_group/snap_group_controller.cc",
     "wm/snap_group/snap_group_controller.h",
+    "wm/snap_group/snap_group_lock_button.cc",
+    "wm/snap_group/snap_group_lock_button.h",
     "wm/splitview/split_view_constants.h",
     "wm/splitview/split_view_controller.cc",
     "wm/splitview/split_view_controller.h",
@@ -2801,7 +2794,6 @@
     "assistant/assistant_controller_impl_unittest.cc",
     "assistant/assistant_interaction_controller_impl_unittest.cc",
     "assistant/assistant_notification_controller_impl_unittest.cc",
-    "assistant/assistant_screen_context_controller_impl_unittest.cc",
     "assistant/assistant_setup_controller_unittest.cc",
     "assistant/assistant_state_controller_unittest.cc",
     "assistant/assistant_suggestions_controller_impl_unittest.cc",
@@ -2894,8 +2886,6 @@
     "glanceables/glanceables_unittests.cc",
     "glanceables/glanceables_welcome_label_unittest.cc",
     "glanceables/signout_screenshot_handler_unittest.cc",
-    "highlighter/highlighter_controller_unittest.cc",
-    "highlighter/highlighter_gesture_util_unittest.cc",
     "host/ash_window_tree_host_platform_unittest.cc",
     "host/ash_window_tree_host_unified_unittest.cc",
     "ime/ime_controller_impl_unittest.cc",
@@ -3083,8 +3073,6 @@
     "system/human_presence/snooping_protection_notification_blocker_unittest.cc",
     "system/ime/ime_feature_pod_controller_unittest.cc",
     "system/ime_menu/ime_menu_tray_unittest.cc",
-    "system/input_device_settings/fake_input_device_tracker.cc",
-    "system/input_device_settings/fake_input_device_tracker.h",
     "system/input_device_settings/input_device_notifier_unittest.cc",
     "system/input_device_settings/input_device_pref_manager_unittest.cc",
     "system/input_device_settings/input_device_settings_controller_unittest.cc",
@@ -3705,8 +3693,6 @@
     "frame_throttler/mock_frame_throttling_observer.h",
     "glanceables/test_glanceables_delegate.cc",
     "glanceables/test_glanceables_delegate.h",
-    "highlighter/highlighter_controller_test_api.cc",
-    "highlighter/highlighter_controller_test_api.h",
     "ime/test_ime_controller_client.cc",
     "ime/test_ime_controller_client.h",
     "keyboard/test_keyboard_ui.cc",
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc
index e9ca729..bcb69cd4 100644
--- a/ash/ash_prefs.cc
+++ b/ash/ash_prefs.cc
@@ -37,7 +37,7 @@
 #include "ash/system/caps_lock_notification_controller.h"
 #include "ash/system/gesture_education/gesture_education_notification_controller.h"
 #include "ash/system/human_presence/snooping_protection_controller.h"
-#include "ash/system/input_device_settings/input_device_tracker_impl.h"
+#include "ash/system/input_device_settings/input_device_tracker.h"
 #include "ash/system/keyboard_brightness/keyboard_backlight_color_controller.h"
 #include "ash/system/media/media_tray.h"
 #include "ash/system/message_center/message_center_controller.h"
@@ -99,7 +99,7 @@
   GestureEducationNotificationController::RegisterProfilePrefs(registry,
                                                                for_test);
   holding_space_prefs::RegisterProfilePrefs(registry);
-  InputDeviceTrackerImpl::RegisterProfilePrefs(registry);
+  InputDeviceTracker::RegisterProfilePrefs(registry);
   LoginScreenController::RegisterProfilePrefs(registry, for_test);
   LogoutButtonTray::RegisterProfilePrefs(registry);
   LogoutConfirmationController::RegisterProfilePrefs(registry);
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index c368d94..084cfe4 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -4680,9 +4680,6 @@
       <message name="IDS_ASH_ASSISTANT_CHIP_WHATS_ON_MY_CALENDAR" desc="Message shown on suggestion chip in Assistant UI to initiate a query for upcoming calendar events.">
         What's on my calendar?
       </message>
-      <message name="IDS_ASH_ASSISTANT_CHIP_WHATS_ON_MY_SCREEN" desc="Message shown on suggestion chip in Assistant UI to initiate a contextual search for results matching screen content.">
-        What's on my screen?
-      </message>
       <message name="IDS_ASH_ASSISTANT_CHIP_WHATS_THE_WEATHER" desc="Message shown on suggestion chip in Assistant UI to initiate a query for the current weather.">
         What's the weather?
       </message>
@@ -5337,6 +5334,14 @@
         Linux files
       </message>
 
+      <!-- Snap Group -->
+      <message name="IDS_ASH_SNAP_GROUP_CLICK_TO_LOCK_WINDOWS" desc="Click to lock the windows.">
+        Lock the windows
+      </message>
+      <message name="IDS_ASH_SNAP_GROUP_CLICK_TO_UNLOCK_WINDOWS" desc="Click to unlock the locked windows.">
+        Unlock the windows
+      </message>
+
       <!-- Switch Between TABLET/LAPTOP MODE-->
       <message name="IDS_ASH_SWITCH_TO_TABLET_MODE" desc="Alert of switching to tablet mode.">
         Switched to tablet mode
diff --git a/ash/ash_strings_grd/IDS_ASH_SNAP_GROUP_CLICK_TO_LOCK_WINDOWS.png.sha1 b/ash/ash_strings_grd/IDS_ASH_SNAP_GROUP_CLICK_TO_LOCK_WINDOWS.png.sha1
new file mode 100644
index 0000000..2e7792d
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_SNAP_GROUP_CLICK_TO_LOCK_WINDOWS.png.sha1
@@ -0,0 +1 @@
+b199547c766db8578e9ca86f9df458e62a2ba4b8
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_SNAP_GROUP_CLICK_TO_UNLOCK_WINDOWS.png.sha1 b/ash/ash_strings_grd/IDS_ASH_SNAP_GROUP_CLICK_TO_UNLOCK_WINDOWS.png.sha1
new file mode 100644
index 0000000..e406aa9
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_SNAP_GROUP_CLICK_TO_UNLOCK_WINDOWS.png.sha1
@@ -0,0 +1 @@
+f173c113518b4c3a846d7919b59dc8a484648cd6
\ No newline at end of file
diff --git a/ash/assistant/assistant_controller_impl.h b/ash/assistant/assistant_controller_impl.h
index 0459ff2..2ad8b237 100644
--- a/ash/assistant/assistant_controller_impl.h
+++ b/ash/assistant/assistant_controller_impl.h
@@ -15,7 +15,6 @@
 #include "ash/assistant/assistant_alarm_timer_controller_impl.h"
 #include "ash/assistant/assistant_interaction_controller_impl.h"
 #include "ash/assistant/assistant_notification_controller_impl.h"
-#include "ash/assistant/assistant_screen_context_controller_impl.h"
 #include "ash/assistant/assistant_setup_controller.h"
 #include "ash/assistant/assistant_state_controller.h"
 #include "ash/assistant/assistant_suggestions_controller_impl.h"
@@ -116,10 +115,6 @@
     return &assistant_notification_controller_;
   }
 
-  AssistantScreenContextControllerImpl* screen_context_controller() {
-    return &assistant_screen_context_controller_;
-  }
-
   AssistantSetupController* setup_controller() {
     return &assistant_setup_controller_;
   }
@@ -164,7 +159,6 @@
   AssistantInteractionControllerImpl assistant_interaction_controller_{this};
   AssistantNotificationControllerImpl assistant_notification_controller_;
   AssistantStateController assistant_state_controller_;
-  AssistantScreenContextControllerImpl assistant_screen_context_controller_;
   AssistantSetupController assistant_setup_controller_{this};
   AssistantSuggestionsControllerImpl assistant_suggestions_controller_;
   AssistantUiControllerImpl assistant_ui_controller_{this};
diff --git a/ash/assistant/assistant_interaction_controller_impl.cc b/ash/assistant/assistant_interaction_controller_impl.cc
index cb699151..14755dc 100644
--- a/ash/assistant/assistant_interaction_controller_impl.cc
+++ b/ash/assistant/assistant_interaction_controller_impl.cc
@@ -8,7 +8,6 @@
 
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/assistant/assistant_controller_impl.h"
-#include "ash/assistant/assistant_screen_context_controller_impl.h"
 #include "ash/assistant/model/assistant_interaction_model_observer.h"
 #include "ash/assistant/model/assistant_query.h"
 #include "ash/assistant/model/assistant_response.h"
@@ -90,8 +89,6 @@
   model_.AddObserver(this);
 
   assistant_controller_observation_.Observe(AssistantController::Get());
-  highlighter_controller_observation_.Observe(
-      Shell::Get()->highlighter_controller());
   tablet_mode_controller_observation_.Observe(GetTabletModeController());
 }
 
@@ -256,23 +253,6 @@
   }
 }
 
-void AssistantInteractionControllerImpl::OnHighlighterSelectionRecognized(
-    const gfx::Rect& rect) {
-  DCHECK(AssistantState::Get()->IsScreenContextAllowed());
-
-  AssistantUiController::Get()->ShowUi(AssistantEntryPoint::kStylus);
-  StartScreenContextInteraction(rect, AssistantQuerySource::kStylus);
-}
-
-void AssistantInteractionControllerImpl::OnInteractionStateChanged(
-    InteractionState interaction_state) {
-  if (!HasActiveInteraction())
-    return;
-
-  // Metalayer mode should not be sticky. Disable it on interaction start.
-  Shell::Get()->highlighter_controller()->AbortSession();
-}
-
 void AssistantInteractionControllerImpl::OnInputModalityChanged(
     InputModality input_modality) {
   if (!IsVisible())
@@ -281,11 +261,6 @@
   if (input_modality == InputModality::kVoice)
     return;
 
-  // Metalayer interactions cause an input modality change that causes us to
-  // lose the pending query. We cache the source before stopping the active
-  // interaction so we can restore the pending query when using the stylus.
-  const auto source = model_.pending_query().source();
-
   // When switching to a non-voice input modality we instruct the underlying
   // service to terminate any pending query. We do not do this when switching to
   // voice input modality because initiation of a voice interaction will
@@ -293,12 +268,6 @@
   // interaction here for voice input modality would actually have the undesired
   // effect of stopping the voice interaction.
   StopActiveInteraction(false);
-
-  if (source == AssistantQuerySource::kStylus) {
-    model_.SetPendingQuery(std::make_unique<AssistantTextQuery>(
-        l10n_util::GetStringUTF8(IDS_ASH_ASSISTANT_CHIP_WHATS_ON_MY_SCREEN),
-        AssistantQuerySource::kStylus));
-  }
 }
 
 void AssistantInteractionControllerImpl::OnMicStateChanged(MicState mic_state) {
@@ -350,9 +319,6 @@
     const AssistantInteractionMetadata& metadata) {
   VLOG(1) << __func__;
 
-  // Abort any request in progress.
-  screen_context_request_factory_.InvalidateWeakPtrs();
-
   // Stop the interaction if the opt-in window is active.
   auto* assistant_setup = AssistantSetup::GetInstance();
   if (assistant_setup && assistant_setup->BounceOptInWindowIfActive()) {
@@ -789,28 +755,6 @@
   }
 }
 
-void AssistantInteractionControllerImpl::StartScreenContextInteraction(
-    const gfx::Rect& region,
-    AssistantQuerySource query_source) {
-  StopActiveInteraction(false);
-
-  model_.SetPendingQuery(std::make_unique<AssistantTextQuery>(
-      l10n_util::GetStringUTF8(IDS_ASH_ASSISTANT_CHIP_WHATS_ON_MY_SCREEN),
-      query_source));
-
-  assistant_controller_->screen_context_controller()->RequestScreenshot(
-      region,
-      base::BindOnce(
-          [](const base::WeakPtr<AssistantInteractionControllerImpl>& self,
-             const std::vector<uint8_t>& screenshot) {
-            if (!self)
-              return;
-
-            self->assistant_->StartScreenContextInteraction(screenshot);
-          },
-          screen_context_request_factory_.GetWeakPtr()));
-}
-
 void AssistantInteractionControllerImpl::StartVoiceInteraction() {
   model_.SetPendingQuery(std::make_unique<AssistantVoiceQuery>());
 
@@ -826,9 +770,6 @@
   model_.SetInteractionState(InteractionState::kInactive);
   model_.ClearPendingQuery();
 
-  // Abort any request in progress.
-  screen_context_request_factory_.InvalidateWeakPtrs();
-
   if (AssistantState::Get()->assistant_status() ==
       assistant::AssistantStatus::READY) {
     assistant_->StopActiveInteraction(cancel_conversation);
diff --git a/ash/assistant/assistant_interaction_controller_impl.h b/ash/assistant/assistant_interaction_controller_impl.h
index 53fb32d..86fc82cd 100644
--- a/ash/assistant/assistant_interaction_controller_impl.h
+++ b/ash/assistant/assistant_interaction_controller_impl.h
@@ -14,7 +14,6 @@
 #include "ash/assistant/model/assistant_interaction_model_observer.h"
 #include "ash/assistant/model/assistant_ui_model_observer.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
-#include "ash/highlighter/highlighter_controller.h"
 #include "ash/public/cpp/assistant/controller/assistant_controller.h"
 #include "ash/public/cpp/assistant/controller/assistant_controller_observer.h"
 #include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h"
@@ -39,8 +38,7 @@
       public AssistantInteractionModelObserver,
       public AssistantUiModelObserver,
       public AssistantViewDelegateObserver,
-      public TabletModeObserver,
-      public HighlighterController::Observer {
+      public TabletModeObserver {
  public:
   using AssistantInteractionMetadata = assistant::AssistantInteractionMetadata;
   using AssistantInteractionResolution =
@@ -81,7 +79,6 @@
       const std::map<std::string, std::string>& params) override;
 
   // AssistantInteractionModelObserver:
-  void OnInteractionStateChanged(InteractionState interaction_state) override;
   void OnInputModalityChanged(InputModality input_modality) override;
   void OnMicStateChanged(MicState mic_state) override;
   void OnCommittedQueryChanged(const AssistantQuery& assistant_query) override;
@@ -93,9 +90,6 @@
       absl::optional<AssistantEntryPoint> entry_point,
       absl::optional<AssistantExitPoint> exit_point) override;
 
-  // HighlighterController::Observer:
-  void OnHighlighterSelectionRecognized(const gfx::Rect& rect) override;
-
   // assistant::AssistantInteractionSubscriber:
   void OnInteractionStarted(
       const AssistantInteractionMetadata& metadata) override;
@@ -132,8 +126,6 @@
   void OnTabletModeChanged();
   bool HasActiveInteraction() const;
   void OnUiVisible(AssistantEntryPoint entry_point);
-  void StartScreenContextInteraction(const gfx::Rect& region,
-                                     AssistantQuerySource query_source);
   void StartVoiceInteraction();
   void StopActiveInteraction(bool cancel_conversation);
 
@@ -152,15 +144,9 @@
   base::ScopedObservation<AssistantController, AssistantControllerObserver>
       assistant_controller_observation_{this};
 
-  base::ScopedObservation<HighlighterController,
-                          HighlighterController::Observer>
-      highlighter_controller_observation_{this};
-
   base::ScopedObservation<TabletModeController, TabletModeObserver>
       tablet_mode_controller_observation_{this};
 
-  base::WeakPtrFactory<AssistantInteractionControllerImpl>
-      screen_context_request_factory_{this};
   base::WeakPtrFactory<AssistantInteractionControllerImpl> weak_factory_{this};
 };
 
diff --git a/ash/assistant/assistant_screen_context_controller_impl.cc b/ash/assistant/assistant_screen_context_controller_impl.cc
deleted file mode 100644
index 0ebbc4e..0000000
--- a/ash/assistant/assistant_screen_context_controller_impl.cc
+++ /dev/null
@@ -1,196 +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.
-
-#include "ash/assistant/assistant_screen_context_controller_impl.h"
-
-#include <utility>
-#include <vector>
-
-#include "ash/public/cpp/assistant/controller/assistant_screen_context_controller.h"
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/shell.h"
-#include "ash/wm/mru_window_tracker.h"
-#include "base/containers/contains.h"
-#include "base/functional/bind.h"
-#include "base/task/thread_pool.h"
-#include "chromeos/ui/base/window_properties.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_tree_owner.h"
-#include "ui/gfx/codec/jpeg_codec.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/skbitmap_operations.h"
-#include "ui/snapshot/snapshot.h"
-#include "ui/snapshot/snapshot_aura.h"
-#include "ui/wm/core/focus_controller.h"
-#include "ui/wm/core/window_util.h"
-
-namespace ash {
-
-namespace {
-
-// When the screenshot's dimensions are smaller than this size, we will stop
-// downsampling.
-constexpr int kScreenshotMaxWidth = 1366;
-constexpr int kScreenshotMaxHeight = 768;
-
-std::vector<uint8_t> DownsampleAndEncodeImage(gfx::Image image) {
-  // We'll downsample the screenshot to avoid exceeding max allowed size on
-  // Assistant server side if we are taking screenshot from high-res screen.
-  std::vector<uint8_t> res;
-  gfx::JPEGCodec::Encode(
-      SkBitmapOperations::DownsampleByTwoUntilSize(
-          image.AsBitmap(), kScreenshotMaxWidth, kScreenshotMaxHeight),
-      /*quality=*/100, &res);
-  return res;
-}
-
-void EncodeScreenshotAndRunCallback(
-    AssistantScreenContextController::RequestScreenshotCallback callback,
-    std::unique_ptr<ui::LayerTreeOwner> layer_owner,
-    gfx::Image image) {
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
-      base::BindOnce(&DownsampleAndEncodeImage, std::move(image)),
-      std::move(callback));
-}
-
-void MirrorChildren(ui::Layer* to_mirror,
-                    ui::Layer* mirror,
-                    const ::wm::MapLayerFunc& map_func) {
-  for (auto* child : to_mirror->children()) {
-    ui::LayerOwner* owner = child->owner();
-    ui::Layer* child_mirror = owner ? map_func.Run(owner).release() : nullptr;
-    if (child_mirror) {
-      mirror->Add(child_mirror);
-      MirrorChildren(child, child_mirror, map_func);
-    }
-  }
-}
-
-std::unique_ptr<ui::LayerTreeOwner> MirrorLayersWithClosure(
-    ui::LayerOwner* root,
-    const ::wm::MapLayerFunc& map_func) {
-  DCHECK(root->OwnsLayer());
-  auto layer = map_func.Run(root);
-  if (!layer)
-    return nullptr;
-
-  auto mirror = std::make_unique<ui::LayerTreeOwner>(std::move(layer));
-  MirrorChildren(root->layer(), mirror->root(), map_func);
-  return mirror;
-}
-
-std::unique_ptr<ui::LayerTreeOwner> CreateLayerForAssistantSnapshot(
-    aura::Window* root_window) {
-  using LayerSet = base::flat_set<const ui::Layer*>;
-  LayerSet excluded_layers;
-  LayerSet blocked_layers;
-
-  aura::Window* overlay_container =
-      ash::Shell::GetContainer(root_window, kShellWindowId_OverlayContainer);
-
-  if (overlay_container)
-    excluded_layers.insert(overlay_container->layer());
-
-  aura::Window* always_on_top_container = ash::Shell::GetContainer(
-      root_window, kShellWindowId_AlwaysOnTopContainer);
-
-  // Ignore windows in always on top container. This will prevent assistant
-  // window from being snapshot.
-  // TODO(muyuanli): We can add Ash property to indicate specific windows to
-  //                 be excluded from snapshot (e.g. assistant window itself).
-  if (always_on_top_container)
-    excluded_layers.insert(always_on_top_container->layer());
-
-  aura::Window* app_list_container =
-      ash::Shell::GetContainer(root_window, kShellWindowId_AppListContainer);
-  aura::Window* app_list_tablet_mode_container =
-      ash::Shell::GetContainer(root_window, kShellWindowId_HomeScreenContainer);
-
-  // Prevent app list from being snapshot on top of other contents.
-  if (app_list_container)
-    excluded_layers.insert(app_list_container->layer());
-  if (app_list_tablet_mode_container)
-    excluded_layers.insert(app_list_tablet_mode_container->layer());
-
-  MruWindowTracker::WindowList windows =
-      Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk);
-
-  for (aura::Window* window : windows) {
-    if (window->GetProperty(chromeos::kBlockedForAssistantSnapshotKey))
-      blocked_layers.insert(window->layer());
-  }
-
-  return MirrorLayersWithClosure(
-      root_window,
-      base::BindRepeating(
-          [](LayerSet blocked_layers, LayerSet excluded_layers,
-             ui::LayerOwner* owner) -> std::unique_ptr<ui::Layer> {
-            // Parent layer is excluded meaning that it's pointless to clone
-            // current child and all its descendants. This reduces the number
-            // of layers to create.
-            if (base::Contains(blocked_layers, owner->layer()->parent()))
-              return nullptr;
-
-            if (base::Contains(blocked_layers, owner->layer())) {
-              // Blocked layers are replaced with solid black layers so that
-              // they won't be included in the screenshot but still preserve
-              // the window stacking.
-              auto layer =
-                  std::make_unique<ui::Layer>(ui::LayerType::LAYER_SOLID_COLOR);
-              layer->SetBounds(owner->layer()->bounds());
-              layer->SetColor(SK_ColorBLACK);
-              return layer;
-            }
-
-            if (excluded_layers.count(owner->layer()))
-              return nullptr;
-
-            return owner->layer()->Mirror();
-          },
-          std::move(blocked_layers), std::move(excluded_layers)));
-}
-
-}  // namespace
-
-AssistantScreenContextControllerImpl::AssistantScreenContextControllerImpl() =
-    default;
-
-AssistantScreenContextControllerImpl::~AssistantScreenContextControllerImpl() =
-    default;
-
-void AssistantScreenContextControllerImpl::RequestScreenshot(
-    const gfx::Rect& rect,
-    RequestScreenshotCallback callback) {
-  aura::Window* root_window = Shell::Get()->GetRootWindowForNewWindows();
-
-  std::unique_ptr<ui::LayerTreeOwner> layer_owner =
-      CreateLayerForAssistantSnapshot(root_window);
-
-  ui::Layer* root_layer = layer_owner->root();
-
-  gfx::Rect source_rect =
-      rect.IsEmpty() ? gfx::Rect(root_window->bounds().size()) : rect;
-
-  // The root layer might have a scaling transform applied (if the user has
-  // changed the UI scale via Ctrl-Shift-Plus/Minus). Clear the transform so
-  // that the snapshot is taken at 1:1 scale relative to screen pixels.
-  root_layer->SetTransform(gfx::Transform());
-  root_window->layer()->Add(root_layer);
-  root_window->layer()->StackAtBottom(root_layer);
-
-  ui::GrabLayerSnapshotAsync(
-      root_layer, source_rect,
-      base::BindOnce(&EncodeScreenshotAndRunCallback, std::move(callback),
-                     std::move(layer_owner)));
-}
-
-std::unique_ptr<ui::LayerTreeOwner>
-AssistantScreenContextControllerImpl::CreateLayerForAssistantSnapshotForTest() {
-  aura::Window* root_window = Shell::GetPrimaryRootWindow();
-  return CreateLayerForAssistantSnapshot(root_window);
-}
-
-}  // namespace ash
diff --git a/ash/assistant/assistant_screen_context_controller_impl.h b/ash/assistant/assistant_screen_context_controller_impl.h
deleted file mode 100644
index 3af398e3..0000000
--- a/ash/assistant/assistant_screen_context_controller_impl.h
+++ /dev/null
@@ -1,45 +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.
-
-#ifndef ASH_ASSISTANT_ASSISTANT_SCREEN_CONTEXT_CONTROLLER_IMPL_H_
-#define ASH_ASSISTANT_ASSISTANT_SCREEN_CONTEXT_CONTROLLER_IMPL_H_
-
-#include <memory>
-
-#include "ash/ash_export.h"
-#include "ash/public/cpp/assistant/controller/assistant_screen_context_controller.h"
-#include "base/functional/callback_forward.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace ui {
-class LayerTreeOwner;
-}  // namespace ui
-
-namespace ash {
-
-class ASH_EXPORT AssistantScreenContextControllerImpl
-    : public AssistantScreenContextController {
- public:
-  AssistantScreenContextControllerImpl();
-
-  AssistantScreenContextControllerImpl(
-      const AssistantScreenContextControllerImpl&) = delete;
-  AssistantScreenContextControllerImpl& operator=(
-      const AssistantScreenContextControllerImpl&) = delete;
-
-  ~AssistantScreenContextControllerImpl() override;
-
-  // AssistantScreenContextController:
-  void RequestScreenshot(const gfx::Rect& rect,
-                         RequestScreenshotCallback callback) override;
-
-  std::unique_ptr<ui::LayerTreeOwner> CreateLayerForAssistantSnapshotForTest();
-
- private:
-  friend class AssistantScreenContextControllerTest;
-};
-
-}  // namespace ash
-
-#endif  // ASH_ASSISTANT_ASSISTANT_SCREEN_CONTEXT_CONTROLLER_IMPL_H_
diff --git a/ash/assistant/assistant_screen_context_controller_impl_unittest.cc b/ash/assistant/assistant_screen_context_controller_impl_unittest.cc
deleted file mode 100644
index ec18757..0000000
--- a/ash/assistant/assistant_screen_context_controller_impl_unittest.cc
+++ /dev/null
@@ -1,105 +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.
-
-#include "ash/assistant/assistant_screen_context_controller_impl.h"
-
-#include <memory>
-
-#include "ash/assistant/assistant_controller_impl.h"
-#include "ash/assistant/test/assistant_ash_test_base.h"
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/shell.h"
-#include "ash/wm/desks/desks_util.h"
-#include "base/functional/bind.h"
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ui/base/window_properties.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_tree_owner.h"
-#include "ui/compositor/layer_type.h"
-
-namespace ash {
-
-namespace {
-
-ui::Layer* FindLayerWithClosure(
-    ui::Layer* root,
-    const base::RepeatingCallback<bool(ui::Layer*)>& callback) {
-  if (callback.Run(root))
-    return root;
-  for (ui::Layer* child : root->children()) {
-    ui::Layer* result = FindLayerWithClosure(child, callback);
-    if (result)
-      return result;
-  }
-  return nullptr;
-}
-
-}  // namespace
-
-class AssistantScreenContextControllerTest : public AssistantAshTestBase {
- public:
-  AssistantScreenContextControllerTest(
-      const AssistantScreenContextControllerTest&) = delete;
-  AssistantScreenContextControllerTest& operator=(
-      const AssistantScreenContextControllerTest&) = delete;
-
- protected:
-  AssistantScreenContextControllerTest()
-      : AssistantAshTestBase(
-            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
-  ~AssistantScreenContextControllerTest() override = default;
-
-  void SetUp() override {
-    AssistantAshTestBase::SetUp();
-
-    controller_ =
-        Shell::Get()->assistant_controller()->screen_context_controller();
-    DCHECK(controller_);
-  }
-
-  AssistantScreenContextControllerImpl* controller() { return controller_; }
-
- private:
-  AssistantScreenContextControllerImpl* controller_ = nullptr;
-};
-
-// Verify that incognito windows are blocked in screenshot.
-TEST_F(AssistantScreenContextControllerTest, Screenshot) {
-  std::unique_ptr<aura::Window> window1 = CreateToplevelTestWindow(
-      gfx::Rect(0, 0, 200, 200), desks_util::GetActiveDeskContainerId());
-  std::unique_ptr<aura::Window> window2 = CreateToplevelTestWindow(
-      gfx::Rect(30, 30, 100, 100), desks_util::GetActiveDeskContainerId());
-
-  ui::Layer* window1_layer = window1->layer();
-  ui::Layer* window2_layer = window2->layer();
-
-  window1->SetProperty(chromeos::kBlockedForAssistantSnapshotKey, true);
-
-  std::unique_ptr<ui::LayerTreeOwner> layer_owner =
-      controller()->CreateLayerForAssistantSnapshotForTest();
-
-  // Test that windows marked as blocked for assistant snapshot is not included.
-  EXPECT_FALSE(FindLayerWithClosure(
-      layer_owner->root(), base::BindRepeating(
-                               [](ui::Layer* layer, ui::Layer* mirror) {
-                                 return layer->ContainsMirrorForTest(mirror);
-                               },
-                               window1_layer)));
-  EXPECT_TRUE(FindLayerWithClosure(
-      layer_owner->root(), base::BindRepeating(
-                               [](ui::Layer* layer, ui::Layer* mirror) {
-                                 return layer->ContainsMirrorForTest(mirror);
-                               },
-                               window2_layer)));
-
-  // Test that a solid black layer is inserted.
-  EXPECT_TRUE(FindLayerWithClosure(
-      layer_owner->root(), base::BindRepeating([](ui::Layer* layer) {
-        return layer->type() == ui::LayerType::LAYER_SOLID_COLOR;
-      })));
-}
-
-}  // namespace ash
diff --git a/ash/assistant/assistant_ui_controller_impl.cc b/ash/assistant/assistant_ui_controller_impl.cc
index 5e6d5d2..3febb4d 100644
--- a/ash/assistant/assistant_ui_controller_impl.cc
+++ b/ash/assistant/assistant_ui_controller_impl.cc
@@ -45,7 +45,6 @@
 
 // Toast -----------------------------------------------------------------------
 
-constexpr char kStylusPromptToastId[] = "stylus_prompt_for_embedded_ui";
 constexpr char kUnboundServiceToastId[] =
     "assistant_controller_unbound_service";
 
@@ -65,8 +64,6 @@
     : assistant_controller_(assistant_controller) {
   model_.AddObserver(this);
   assistant_controller_observation_.Observe(AssistantController::Get());
-  highlighter_controller_observation_.Observe(
-      Shell::Get()->highlighter_controller());
   overview_controller_observation_.Observe(Shell::Get()->overview_controller());
 }
 
@@ -213,10 +210,6 @@
   }
 
   if (old_visibility == AssistantVisibility::kVisible) {
-    // Metalayer should not be sticky. Disable when the UI is no longer visible.
-    if (exit_point != AssistantExitPoint::kStylus)
-      Shell::Get()->highlighter_controller()->AbortSession();
-
     // Only record the exit point when Assistant UI becomes invisible to
     // avoid recording duplicate events (e.g. pressing ESC key).
     assistant::util::RecordAssistantExitPoint(exit_point.value());
@@ -234,16 +227,6 @@
                              GetNumberOfSessionsWhereOnboardingShown() + 1);
 }
 
-void AssistantUiControllerImpl::OnHighlighterEnabledChanged(
-    HighlighterEnabledState state) {
-  if (state != HighlighterEnabledState::kEnabled)
-    return;
-
-  ShowToast(kStylusPromptToastId, ToastCatalogName::kStylusPrompt,
-            IDS_ASH_ASSISTANT_PROMPT_STYLUS);
-  CloseUi(AssistantExitPoint::kStylus);
-}
-
 void AssistantUiControllerImpl::OnOverviewModeWillStart() {
   // Close Assistant UI before entering overview mode.
   CloseUi(AssistantExitPoint::kOverviewMode);
diff --git a/ash/assistant/assistant_ui_controller_impl.h b/ash/assistant/assistant_ui_controller_impl.h
index 7e374a1..f77909a 100644
--- a/ash/assistant/assistant_ui_controller_impl.h
+++ b/ash/assistant/assistant_ui_controller_impl.h
@@ -10,7 +10,6 @@
 #include "ash/assistant/model/assistant_ui_model.h"
 #include "ash/assistant/model/assistant_ui_model_observer.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
-#include "ash/highlighter/highlighter_controller.h"
 #include "ash/public/cpp/assistant/controller/assistant_controller.h"
 #include "ash/public/cpp/assistant/controller/assistant_controller_observer.h"
 #include "ash/public/cpp/assistant/controller/assistant_ui_controller.h"
@@ -39,7 +38,6 @@
       public AssistantInteractionModelObserver,
       public AssistantUiModelObserver,
       public AssistantViewDelegateObserver,
-      public HighlighterController::Observer,
       public OverviewObserver {
  public:
   explicit AssistantUiControllerImpl(
@@ -88,9 +86,6 @@
   // AssistantViewDelegateObserver:
   void OnOnboardingShown() override;
 
-  // HighlighterController::Observer:
-  void OnHighlighterEnabledChanged(HighlighterEnabledState state) override;
-
   // OverviewObserver:
   void OnOverviewModeWillStart() override;
 
@@ -107,10 +102,6 @@
   base::ScopedObservation<AssistantController, AssistantControllerObserver>
       assistant_controller_observation_{this};
 
-  base::ScopedObservation<HighlighterController,
-                          HighlighterController::Observer>
-      highlighter_controller_observation_{this};
-
   base::ScopedObservation<OverviewController, OverviewObserver>
       overview_controller_observation_{this};
 
diff --git a/ash/assistant/test/test_assistant_service.cc b/ash/assistant/test/test_assistant_service.cc
index aa49796..8c44af39 100644
--- a/ash/assistant/test/test_assistant_service.cc
+++ b/ash/assistant/test/test_assistant_service.cc
@@ -213,9 +213,6 @@
 void TestAssistantService::StartEditReminderInteraction(
     const std::string& client_id) {}
 
-void TestAssistantService::StartScreenContextInteraction(
-    const std::vector<uint8_t>& assistant_screenshot) {}
-
 void TestAssistantService::StartTextInteraction(
     const std::string& query,
     assistant::AssistantQuerySource source,
diff --git a/ash/assistant/test/test_assistant_service.h b/ash/assistant/test/test_assistant_service.h
index 48f8a9e..6fa6d2a 100644
--- a/ash/assistant/test/test_assistant_service.h
+++ b/ash/assistant/test/test_assistant_service.h
@@ -88,8 +88,6 @@
 
   // Assistant overrides:
   void StartEditReminderInteraction(const std::string& client_id) override;
-  void StartScreenContextInteraction(
-      const std::vector<uint8_t>& assistant_screenshot) override;
   void StartTextInteraction(const std::string& query,
                             assistant::AssistantQuerySource source,
                             bool allow_tts) override;
diff --git a/ash/capture_mode/capture_mode_constants.h b/ash/capture_mode/capture_mode_constants.h
index c02211c..744865125 100644
--- a/ash/capture_mode/capture_mode_constants.h
+++ b/ash/capture_mode/capture_mode_constants.h
@@ -95,6 +95,10 @@
 // confined bounds.
 constexpr int kKeyWidgetDistanceFromBottom = 24;
 
+// Border value applied between the right edge of the key combo viewer when it's
+// approaching the right edge of the recording area.
+constexpr int kKeyWidgetBorderPadding = 16;
+
 // The duration to continue showing the key combo view on key up of the
 // non-modifier key with no modifier keys pressed or on key up of the last
 // modifier key up with no non-modifier key that can be displayed independently
diff --git a/ash/capture_mode/capture_mode_demo_tools_controller.cc b/ash/capture_mode/capture_mode_demo_tools_controller.cc
index 0fed7cb5..8e992c1 100644
--- a/ash/capture_mode/capture_mode_demo_tools_controller.cc
+++ b/ash/capture_mode/capture_mode_demo_tools_controller.cc
@@ -101,7 +101,7 @@
   params.parent =
       video_recording_watcher->GetOnCaptureSurfaceWidgetParentWindow();
   params.child = true;
-  params.name = "CaptureModeDemoToolsWidget";
+  params.name = "KeyComboWidget";
   return params;
 }
 
@@ -164,7 +164,7 @@
 }
 
 void CaptureModeDemoToolsController::RefreshBounds() {
-  demo_tools_widget_->SetBounds(CalculateBounds());
+  demo_tools_widget_->SetBounds(CalculateKeyComboWidgetBounds());
 }
 
 void CaptureModeDemoToolsController::OnTouchEvent(
@@ -277,15 +277,20 @@
   RefreshBounds();
 }
 
-gfx::Rect CaptureModeDemoToolsController::CalculateBounds() const {
+gfx::Rect CaptureModeDemoToolsController::CalculateKeyComboWidgetBounds()
+    const {
   const gfx::Size preferred_size = key_combo_view_->GetPreferredSize();
-  auto bounds = video_recording_watcher_->GetCaptureSurfaceConfineBounds();
-  int demo_tools_y = bounds.bottom() -
-                     capture_mode::kKeyWidgetDistanceFromBottom -
-                     preferred_size.height();
-  bounds.ClampToCenteredSize(preferred_size);
-  bounds.set_y(demo_tools_y);
-  return bounds;
+  const auto confine_bounds =
+      video_recording_watcher_->GetCaptureSurfaceConfineBounds();
+  const int key_combo_x =
+      preferred_size.width() > confine_bounds.width()
+          ? confine_bounds.right() - preferred_size.width() -
+                capture_mode::kKeyWidgetBorderPadding
+          : confine_bounds.CenterPoint().x() - preferred_size.width() / 2;
+  const int key_combo_y = confine_bounds.bottom() -
+                          capture_mode::kKeyWidgetDistanceFromBottom -
+                          preferred_size.height();
+  return gfx::Rect(gfx::Point(key_combo_x, key_combo_y), preferred_size);
 }
 
 bool CaptureModeDemoToolsController::ShouldResetWidget() const {
diff --git a/ash/capture_mode/capture_mode_demo_tools_controller.h b/ash/capture_mode/capture_mode_demo_tools_controller.h
index 8b2a582..29f4ecd8 100644
--- a/ash/capture_mode/capture_mode_demo_tools_controller.h
+++ b/ash/capture_mode/capture_mode_demo_tools_controller.h
@@ -76,7 +76,7 @@
   // `modifiers_` and `last_non_modifier_key_`.
   void RefreshKeyComboViewer();
 
-  gfx::Rect CalculateBounds() const;
+  gfx::Rect CalculateKeyComboWidgetBounds() const;
 
   // Returns true if there is no modifier keys pressed and the non-modifier key
   // can not be displayed independently.
diff --git a/ash/capture_mode/capture_mode_demo_tools_test_api.cc b/ash/capture_mode/capture_mode_demo_tools_test_api.cc
index d2360c4..d9faa5f0 100644
--- a/ash/capture_mode/capture_mode_demo_tools_test_api.cc
+++ b/ash/capture_mode/capture_mode_demo_tools_test_api.cc
@@ -16,19 +16,23 @@
     CaptureModeDemoToolsController* demo_tools_controller)
     : demo_tools_controller_(demo_tools_controller) {}
 
-views::Widget* CaptureModeDemoToolsTestApi::GetDemoToolsWidget() {
+views::Widget* CaptureModeDemoToolsTestApi::GetKeyComboWidget() {
+  DCHECK(demo_tools_controller_);
   return demo_tools_controller_->demo_tools_widget_.get();
 }
 
 KeyComboView* CaptureModeDemoToolsTestApi::GetKeyComboView() {
+  DCHECK(demo_tools_controller_);
   return demo_tools_controller_->key_combo_view_;
 }
 
 int CaptureModeDemoToolsTestApi::GetCurrentModifiersFlags() {
+  DCHECK(demo_tools_controller_);
   return demo_tools_controller_->modifiers_;
 }
 
 ui::KeyboardCode CaptureModeDemoToolsTestApi::GetLastNonModifierKey() {
+  DCHECK(demo_tools_controller_);
   return demo_tools_controller_->last_non_modifier_key_;
 }
 
diff --git a/ash/capture_mode/capture_mode_demo_tools_test_api.h b/ash/capture_mode/capture_mode_demo_tools_test_api.h
index 906dcfd..6e216d70 100644
--- a/ash/capture_mode/capture_mode_demo_tools_test_api.h
+++ b/ash/capture_mode/capture_mode_demo_tools_test_api.h
@@ -38,9 +38,9 @@
   CaptureModeDemoToolsTestApi& operator=(CaptureModeDemoToolsTestApi) = delete;
   ~CaptureModeDemoToolsTestApi() = default;
 
-  views::Widget* GetDemoToolsWidget();
+  views::Widget* GetKeyComboWidget();
 
-  // Returns the contents view for the `demo_tools_widget_`.
+  // Returns the contents view for the `key_combo_widget_`.
   KeyComboView* GetKeyComboView();
 
   // Returns the state of modifier keys in the `CaptureModeDemoToolsController`.
diff --git a/ash/capture_mode/capture_mode_demo_tools_unittests.cc b/ash/capture_mode/capture_mode_demo_tools_unittests.cc
index bb65691c..c1bf8224b 100644
--- a/ash/capture_mode/capture_mode_demo_tools_unittests.cc
+++ b/ash/capture_mode/capture_mode_demo_tools_unittests.cc
@@ -143,7 +143,7 @@
 
     if (should_hide_view) {
       waiter.Wait();
-      EXPECT_FALSE(capture_mode_demo_tools_test_api.GetDemoToolsWidget());
+      EXPECT_FALSE(capture_mode_demo_tools_test_api.GetKeyComboWidget());
       EXPECT_FALSE(capture_mode_demo_tools_test_api.GetKeyComboView());
     }
   }
@@ -228,7 +228,7 @@
   // corresponding key widget.
   event_generator->PressKey(ui::VKEY_A, ui::EF_NONE);
   CaptureModeDemoToolsTestApi demo_tools_test_api(demo_tools_controller);
-  EXPECT_FALSE(demo_tools_test_api.GetDemoToolsWidget());
+  EXPECT_FALSE(demo_tools_test_api.GetKeyComboWidget());
   event_generator->ReleaseKey(ui::VKEY_A, ui::EF_NONE);
   EXPECT_EQ(demo_tools_test_api.GetCurrentModifiersFlags(), 0);
   EXPECT_EQ(demo_tools_test_api.GetLastNonModifierKey(), ui::VKEY_UNKNOWN);
@@ -237,7 +237,7 @@
   // corresponding key widget.
   event_generator->PressKey(ui::VKEY_A, ui::EF_NONE);
   event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE);
-  EXPECT_TRUE(demo_tools_test_api.GetDemoToolsWidget());
+  EXPECT_TRUE(demo_tools_test_api.GetKeyComboWidget());
   EXPECT_EQ(demo_tools_test_api.GetCurrentModifiersFlags(),
             ui::EF_CONTROL_DOWN);
   EXPECT_EQ(demo_tools_test_api.GetLastNonModifierKey(), ui::VKEY_A);
@@ -246,12 +246,12 @@
   base::OneShotTimer* timer = demo_tools_test_api.GetRefreshKeyComboTimer();
   EXPECT_TRUE(timer->IsRunning());
   timer->FireNow();
-  EXPECT_FALSE(demo_tools_test_api.GetDemoToolsWidget());
+  EXPECT_FALSE(demo_tools_test_api.GetKeyComboWidget());
   EXPECT_EQ(demo_tools_test_api.GetCurrentModifiersFlags(), 0);
   event_generator->ReleaseKey(ui::VKEY_A, ui::EF_NONE);
 
   event_generator->PressKey(ui::VKEY_TAB, ui::EF_NONE);
-  EXPECT_TRUE(demo_tools_test_api.GetDemoToolsWidget());
+  EXPECT_TRUE(demo_tools_test_api.GetKeyComboWidget());
   EXPECT_EQ(demo_tools_test_api.GetCurrentModifiersFlags(), 0);
   EXPECT_EQ(demo_tools_test_api.GetLastNonModifierKey(), ui::VKEY_TAB);
 }
@@ -284,7 +284,7 @@
       GetCaptureModeDemoToolsController();
   EXPECT_TRUE(demo_tools_controller);
   CaptureModeDemoToolsTestApi demo_tools_test_api(demo_tools_controller);
-  EXPECT_TRUE(demo_tools_test_api.GetDemoToolsWidget());
+  EXPECT_TRUE(demo_tools_test_api.GetKeyComboWidget());
   controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
   WaitForCaptureFileToBeSaved();
   EXPECT_FALSE(controller->IsActive());
@@ -325,7 +325,7 @@
   auto* event_generator = GetEventGenerator();
   event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE);
   event_generator->PressKey(ui::VKEY_C, ui::EF_NONE);
-  EXPECT_TRUE(demo_tools_test_api.GetDemoToolsWidget());
+  EXPECT_TRUE(demo_tools_test_api.GetKeyComboWidget());
   EXPECT_TRUE(demo_tools_test_api.GetKeyComboView());
   std::vector<ui::KeyboardCode> expected_modifier_key_vector = {
       ui::VKEY_CONTROL};
@@ -345,7 +345,7 @@
   event_generator->ReleaseKey(ui::VKEY_SHIFT, ui::EF_NONE);
   event_generator->ReleaseKey(ui::VKEY_CONTROL, ui::EF_NONE);
   FireTimerAndVerifyWidget(/*should_hide_view=*/true);
-  EXPECT_FALSE(demo_tools_test_api.GetDemoToolsWidget());
+  EXPECT_FALSE(demo_tools_test_api.GetKeyComboWidget());
 }
 
 // Tests the timer behaviors for the key combo view:
@@ -376,7 +376,7 @@
   auto* event_generator = GetEventGenerator();
   event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE);
   event_generator->PressKey(ui::VKEY_A, ui::EF_NONE);
-  EXPECT_TRUE(demo_tools_test_api.GetDemoToolsWidget());
+  EXPECT_TRUE(demo_tools_test_api.GetKeyComboWidget());
   KeyComboView* key_combo_view = demo_tools_test_api.GetKeyComboView();
   EXPECT_TRUE(key_combo_view);
   std::vector<ui::KeyboardCode> expected_modifier_key_vector = {
@@ -417,7 +417,7 @@
   event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE);
   event_generator->PressKey(ui::VKEY_SHIFT, ui::EF_NONE);
   event_generator->PressKey(ui::VKEY_A, ui::EF_NONE);
-  EXPECT_TRUE(demo_tools_test_api.GetDemoToolsWidget());
+  EXPECT_TRUE(demo_tools_test_api.GetKeyComboWidget());
   expected_modifier_key_vector = {ui::VKEY_CONTROL, ui::VKEY_SHIFT};
   EXPECT_EQ(demo_tools_test_api.GetShownModifiersKeyCodes(),
             expected_modifier_key_vector);
@@ -517,7 +517,7 @@
     // key combo viewer will not display when pressing 'Ctrl' and 'T'.
     event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE);
     event_generator->PressKey(ui::VKEY_T, ui::EF_NONE);
-    EXPECT_FALSE(demo_tools_test_api.GetDemoToolsWidget());
+    EXPECT_FALSE(demo_tools_test_api.GetKeyComboWidget());
     EXPECT_FALSE(demo_tools_test_api.GetKeyComboView());
     event_generator->ReleaseKey(ui::VKEY_T, ui::EF_NONE);
     event_generator->ReleaseKey(ui::VKEY_CONTROL, ui::EF_NONE);
@@ -527,7 +527,7 @@
     DisableTextInputFocus();
     event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE);
     event_generator->PressKey(ui::VKEY_T, ui::EF_NONE);
-    EXPECT_TRUE(demo_tools_test_api.GetDemoToolsWidget());
+    EXPECT_TRUE(demo_tools_test_api.GetKeyComboWidget());
     EXPECT_TRUE(demo_tools_test_api.GetKeyComboView());
     event_generator->ReleaseKey(ui::VKEY_T, ui::EF_NONE);
     event_generator->ReleaseKey(ui::VKEY_CONTROL, ui::EF_NONE);
@@ -538,7 +538,7 @@
     EnableTextInputFocus(input_type);
     event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE);
     event_generator->PressKey(ui::VKEY_T, ui::EF_NONE);
-    EXPECT_FALSE(demo_tools_test_api.GetDemoToolsWidget());
+    EXPECT_FALSE(demo_tools_test_api.GetKeyComboWidget());
     EXPECT_FALSE(demo_tools_test_api.GetKeyComboView());
     event_generator->ReleaseKey(ui::VKEY_T, ui::EF_NONE);
     event_generator->ReleaseKey(ui::VKEY_CONTROL, ui::EF_NONE);
@@ -649,6 +649,35 @@
   FireTimerAndVerifyWidget(/*should_hide_view=*/true);
 }
 
+// Tests that if the width of the confined bounds is smaller than that of the
+// preferred size of the key combo widget, the key combo widget will be shifted
+// to the left. But the right edge of the key combo widget will always be to the
+// left of the right edge of the capture surface confined bounds.
+TEST_F(CaptureModeDemoToolsTest,
+       ConfinedBoundsSizeSmallerThanPreferredSizeTest) {
+  auto* controller = CaptureModeController::Get();
+  const gfx::Rect capture_region(100, 200, 200, 50);
+  controller->SetUserCaptureRegion(capture_region, /*by_user=*/true);
+  StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
+  controller->EnableDemoTools(true);
+  StartVideoRecordingImmediately();
+
+  auto* event_generator = GetEventGenerator();
+  event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE);
+  event_generator->PressKey(ui::VKEY_SHIFT, ui::EF_NONE);
+  event_generator->PressKey(ui::VKEY_C, ui::EF_NONE);
+
+  auto* demo_tools_controller = GetCaptureModeDemoToolsController();
+  DCHECK(demo_tools_controller);
+  CaptureModeDemoToolsTestApi demo_tools_test_api(demo_tools_controller);
+  KeyComboView* key_combo_view = demo_tools_test_api.GetKeyComboView();
+  const auto confine_bounds = controller->GetCaptureSurfaceConfineBounds();
+  EXPECT_LT(confine_bounds.width(),
+            key_combo_view->GetBoundsInScreen().width());
+  EXPECT_GT(confine_bounds.right(),
+            key_combo_view->GetBoundsInScreen().right());
+}
+
 // Tests that the metrics that record if a recording starts with demo tools
 // feature enabled are recorded correctly in a capture session both in clamshell
 // and tablet mode.
@@ -735,7 +764,7 @@
   void VerifyKeyComboWidgetPosition() {
     CaptureModeDemoToolsTestApi demo_tools_test_api(
         GetCaptureModeDemoToolsController());
-    auto* demo_tools_widget = demo_tools_test_api.GetDemoToolsWidget();
+    auto* demo_tools_widget = demo_tools_test_api.GetKeyComboWidget();
     ASSERT_TRUE(demo_tools_widget);
     auto confined_bounds_in_screen =
         GetDemoToolsConfinedBoundsInScreenCoordinates();
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 961f244..b6a9fb9c 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1046,6 +1046,11 @@
 // native screen capture tool.
 BASE_FEATURE(kGifRecording, "GifRecording", base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables a Files banner about Google One offer.
+BASE_FEATURE(kGoogleOneOfferFilesBanner,
+             "GoogleOneOfferFilesBanner",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables editing with handwriting gestures within the virtual keyboard.
 BASE_FEATURE(kHandwritingGestureEditing,
              "HandwritingGestureEditing",
@@ -1950,6 +1955,13 @@
 // Controls whether the snap group feature is enabled or not.
 BASE_FEATURE(kSnapGroup, "SnapGroup", base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Controls whether to create the snap group automatically when two windows are
+// snapped if true. Otherwise, the user has to explicitly lock the two windows
+// when both are snapped via cliking on the lock button when hovering the mouse
+// over the shared edge of the two snapped windows.
+constexpr base::FeatureParam<bool> kAutomaticallyLockGroup{
+    &kSnapGroup, "AutomaticLockGroup", true};
+
 // Controls whether the speak-on-mute detection feature is enabled or not.
 BASE_FEATURE(kSpeakOnMuteEnabled,
              "SpeakOnMuteEnabled",
@@ -2829,6 +2841,10 @@
          base::FeatureList::IsEnabled(kEcheSWA);
 }
 
+bool IsEcheLauncherIconsInMoreAppsButtonEnabled() {
+  return base::FeatureList::IsEnabled(kEcheLauncherIconsInMoreAppsButton);
+}
+
 bool IsEcheLauncherListViewEnabled() {
   return IsEcheLauncherEnabled() &&
          base::FeatureList::IsEnabled(kEcheLauncherListView);
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 6dded8c9b..aaa98119 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -312,6 +312,8 @@
 BASE_DECLARE_FEATURE(kGesturePropertiesDBusService);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kGifRecording);
 COMPONENT_EXPORT(ASH_CONSTANTS)
+BASE_DECLARE_FEATURE(kGoogleOneOfferFilesBanner);
+COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kHandwritingGestureEditing);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kHandwritingLegacyRecognition);
@@ -551,6 +553,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSmartLockSignInRemoved);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSmartLockUIRevamp);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSnapGroup);
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::FeatureParam<bool> kAutomaticallyLockGroup;
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSnoopingProtection);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSpeakOnMuteEnabled);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kStylusBatteryStatus);
@@ -718,6 +722,8 @@
 bool ShouldForceEnableServerSideSpeechRecognitionForDev();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheLauncherEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheLauncherListViewEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS)
+bool IsEcheLauncherIconsInMoreAppsButtonEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFullscreenAfterUnlockAllowed();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFullscreenAlertBubbleEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGaiaReauthEndpointEnabled();
diff --git a/ash/highlighter/OWNERS b/ash/highlighter/OWNERS
deleted file mode 100644
index cff9d45..0000000
--- a/ash/highlighter/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-kaznacheev@chromium.org
diff --git a/ash/highlighter/highlighter_controller.cc b/ash/highlighter/highlighter_controller.cc
deleted file mode 100644
index 2bd7d006..0000000
--- a/ash/highlighter/highlighter_controller.cc
+++ /dev/null
@@ -1,276 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/highlighter/highlighter_controller.h"
-
-#include <memory>
-#include <utility>
-
-#include "ash/highlighter/highlighter_gesture_util.h"
-#include "ash/highlighter/highlighter_result_view.h"
-#include "ash/highlighter/highlighter_view.h"
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/shell.h"
-#include "ash/system/palette/palette_utils.h"
-#include "base/functional/bind.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/timer/timer.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/events/base_event_utils.h"
-#include "ui/views/widget/widget.h"
-
-namespace ash {
-
-namespace {
-
-// Bezel stroke detection margin, in DP.
-const int kScreenEdgeMargin = 2;
-
-const int kInterruptedStrokeTimeoutMs = 500;
-
-// Adjust the height of the bounding box to match the pen tip height,
-// while keeping the same vertical center line. Adjust the width to
-// account for the pen tip width.
-gfx::RectF AdjustHorizontalStroke(const gfx::RectF& box,
-                                  const gfx::SizeF& pen_tip_size) {
-  return gfx::RectF(box.x() - pen_tip_size.width() / 2,
-                    box.CenterPoint().y() - pen_tip_size.height() / 2,
-                    box.width() + pen_tip_size.width(), pen_tip_size.height());
-}
-
-}  // namespace
-
-HighlighterController::HighlighterController() {
-  Shell::Get()->AddPreTargetHandler(this);
-}
-
-HighlighterController::~HighlighterController() {
-  Shell::Get()->RemovePreTargetHandler(this);
-}
-
-void HighlighterController::AddObserver(Observer* observer) {
-  DCHECK(observer);
-  observers_.AddObserver(observer);
-}
-
-void HighlighterController::RemoveObserver(Observer* observer) {
-  DCHECK(observer);
-  observers_.RemoveObserver(observer);
-}
-
-void HighlighterController::SetExitCallback(base::OnceClosure exit_callback,
-                                            bool require_success) {
-  exit_callback_ = std::move(exit_callback);
-  require_success_ = require_success;
-}
-
-void HighlighterController::UpdateEnabledState(
-    HighlighterEnabledState enabled_state) {
-  if (enabled_state_ == enabled_state)
-    return;
-  enabled_state_ = enabled_state;
-
-  SetEnabled(enabled_state == HighlighterEnabledState::kEnabled);
-  for (auto& observer : observers_)
-    observer.OnHighlighterEnabledChanged(enabled_state);
-}
-
-void HighlighterController::AbortSession() {
-  if (enabled_state_ == HighlighterEnabledState::kEnabled)
-    UpdateEnabledState(HighlighterEnabledState::kDisabledBySessionAbort);
-}
-
-void HighlighterController::SetEnabled(bool enabled) {
-  FastInkPointerController::SetEnabled(enabled);
-  if (enabled) {
-    session_start_ = ui::EventTimeForNow();
-    gesture_counter_ = 0;
-    recognized_gesture_counter_ = 0;
-  } else {
-    UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.Palette.Assistant.GesturesPerSession",
-                             gesture_counter_);
-    UMA_HISTOGRAM_COUNTS_100(
-        "Ash.Shelf.Palette.Assistant.GesturesPerSession.Recognized",
-        recognized_gesture_counter_);
-
-    // If |highlighter_view_widget_| is animating it will delete itself when
-    // done animating. |result_view_widget_| will exist only if
-    // |highlighter_view_widget_| is animating, and it will also delete itself
-    // when done animating.
-    if (highlighter_view_widget_ && !GetHighlighterView()->animating())
-      DestroyPointerView();
-  }
-}
-
-views::View* HighlighterController::GetPointerView() const {
-  return const_cast<HighlighterController*>(this)->GetHighlighterView();
-}
-
-void HighlighterController::CreatePointerView(
-    base::TimeDelta presentation_delay,
-    aura::Window* root_window) {
-  highlighter_view_widget_ = HighlighterView::Create(
-      presentation_delay,
-      Shell::GetContainer(root_window, kShellWindowId_OverlayContainer));
-  result_view_widget_.reset();
-}
-
-void HighlighterController::UpdatePointerView(ui::TouchEvent* event) {
-  interrupted_stroke_timer_.reset();
-
-  GetHighlighterView()->AddNewPoint(event->root_location_f(),
-                                    event->time_stamp());
-
-  if (event->type() != ui::ET_TOUCH_RELEASED)
-    return;
-
-  gfx::Rect bounds =
-      highlighter_view_widget_->GetNativeWindow()->GetRootWindow()->bounds();
-  bounds.Inset(kScreenEdgeMargin);
-
-  const gfx::PointF pos = GetHighlighterView()->points().GetNewest().location;
-  if (bounds.Contains(
-          gfx::Point(static_cast<int>(pos.x()), static_cast<int>(pos.y())))) {
-    // The stroke has ended far enough from the screen edge, process it
-    // immediately.
-    RecognizeGesture();
-    return;
-  }
-
-  // The stroke has ended close to the screen edge. Delay gesture recognition
-  // a little to give the pen a chance to re-enter the screen.
-  GetHighlighterView()->AddGap();
-
-  interrupted_stroke_timer_ = std::make_unique<base::OneShotTimer>();
-  interrupted_stroke_timer_->Start(
-      FROM_HERE, base::Milliseconds(kInterruptedStrokeTimeoutMs),
-      base::BindOnce(&HighlighterController::RecognizeGesture,
-                     base::Unretained(this)));
-}
-
-void HighlighterController::RecognizeGesture() {
-  interrupted_stroke_timer_.reset();
-
-  aura::Window* current_window =
-      highlighter_view_widget_->GetNativeWindow()->GetRootWindow();
-  const gfx::Rect bounds = current_window->bounds();
-
-  const fast_ink::FastInkPoints& points = GetHighlighterView()->points();
-  gfx::RectF box = points.GetBoundingBoxF();
-
-  const HighlighterGestureType gesture_type =
-      DetectHighlighterGesture(box, HighlighterView::kPenTipSize, points);
-
-  if (gesture_type == HighlighterGestureType::kHorizontalStroke) {
-    UMA_HISTOGRAM_COUNTS_10000("Ash.Shelf.Palette.Assistant.HighlighterLength",
-                               static_cast<int>(box.width()));
-
-    box = AdjustHorizontalStroke(box, HighlighterView::kPenTipSize);
-  } else if (gesture_type == HighlighterGestureType::kClosedShape) {
-    const float fraction =
-        box.width() * box.height() / (bounds.width() * bounds.height());
-    UMA_HISTOGRAM_PERCENTAGE("Ash.Shelf.Palette.Assistant.CircledPercentage",
-                             static_cast<int>(fraction * 100));
-  }
-
-  GetHighlighterView()->Animate(
-      box.CenterPoint(), gesture_type,
-      base::BindOnce(&HighlighterController::DestroyHighlighterView,
-                     base::Unretained(this)));
-
-  // |box| is not guaranteed to be inside the screen bounds, clip it.
-  // Not converting |box| to gfx::Rect here to avoid accumulating rounding
-  // errors, instead converting |bounds| to gfx::RectF.
-  box.Intersect(
-      gfx::RectF(bounds.x(), bounds.y(), bounds.width(), bounds.height()));
-
-  if (!box.IsEmpty() &&
-      gesture_type != HighlighterGestureType::kNotRecognized) {
-    // The window for selection should be the root window to show assistant.
-    Shell::SetRootWindowForNewWindows(current_window->GetRootWindow());
-
-    const gfx::Rect selection_rect = gfx::ToEnclosingRect(box);
-    for (auto& observer : observers_)
-      observer.OnHighlighterSelectionRecognized(selection_rect);
-
-    result_view_widget_ = HighlighterResultView::Create(current_window);
-    static_cast<HighlighterResultView*>(result_view_widget_->GetContentsView())
-        ->Animate(box, gesture_type,
-                  base::BindOnce(&HighlighterController::DestroyResultView,
-                                 base::Unretained(this)));
-
-    recognized_gesture_counter_++;
-    CallExitCallback();
-  } else {
-    if (!require_success_)
-      CallExitCallback();
-  }
-
-  gesture_counter_++;
-
-  const base::TimeTicks gesture_start = points.GetOldest().time;
-  if (gesture_counter_ > 1) {
-    // Up to 3 minutes.
-    UMA_HISTOGRAM_MEDIUM_TIMES("Ash.Shelf.Palette.Assistant.GestureInterval",
-                               gesture_start - previous_gesture_end_);
-  }
-  previous_gesture_end_ = points.GetNewest().time;
-
-  // Up to 10 seconds.
-  UMA_HISTOGRAM_TIMES("Ash.Shelf.Palette.Assistant.GestureDuration",
-                      points.GetNewest().time - gesture_start);
-
-  UMA_HISTOGRAM_ENUMERATION("Ash.Shelf.Palette.Assistant.GestureType",
-                            gesture_type,
-                            HighlighterGestureType::kGestureCount);
-}
-
-void HighlighterController::DestroyPointerView() {
-  DestroyHighlighterView();
-  DestroyResultView();
-}
-
-bool HighlighterController::CanStartNewGesture(ui::LocatedEvent* event) {
-  // Ignore events over the palette.
-  if (palette_utils::PaletteContainsPointInScreen(event->root_location()))
-    return false;
-  return !interrupted_stroke_timer_ &&
-         FastInkPointerController::CanStartNewGesture(event);
-}
-
-bool HighlighterController::ShouldProcessEvent(ui::LocatedEvent* event) {
-  // Allow mouse clicking when Assistant tool is enabled.
-  if (event->type() == ui::ET_MOUSE_PRESSED ||
-      event->type() == ui::ET_MOUSE_RELEASED) {
-    return false;
-  }
-
-  return FastInkPointerController::ShouldProcessEvent(event);
-}
-
-void HighlighterController::DestroyHighlighterView() {
-  highlighter_view_widget_.reset();
-  // |interrupted_stroke_timer_| should never be non null when
-  // |highlighter_view_widget_| is null.
-  interrupted_stroke_timer_.reset();
-}
-
-void HighlighterController::DestroyResultView() {
-  result_view_widget_.reset();
-}
-
-void HighlighterController::CallExitCallback() {
-  if (!exit_callback_.is_null())
-    std::move(exit_callback_).Run();
-}
-
-HighlighterView* HighlighterController::GetHighlighterView() {
-  return highlighter_view_widget_
-             ? static_cast<HighlighterView*>(
-                   highlighter_view_widget_->GetContentsView())
-             : nullptr;
-}
-
-}  // namespace ash
diff --git a/ash/highlighter/highlighter_controller.h b/ash/highlighter/highlighter_controller.h
deleted file mode 100644
index 73fcf49..0000000
--- a/ash/highlighter/highlighter_controller.h
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_HIGHLIGHTER_HIGHLIGHTER_CONTROLLER_H_
-#define ASH_HIGHLIGHTER_HIGHLIGHTER_CONTROLLER_H_
-
-#include <memory>
-
-#include "ash/ash_export.h"
-#include "ash/fast_ink/fast_ink_pointer_controller.h"
-#include "base/functional/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/time/time.h"
-#include "ui/views/widget/unique_widget_ptr.h"
-
-namespace base {
-class OneShotTimer;
-}
-
-namespace gfx {
-class Rect;
-}
-
-namespace ash {
-
-class HighlighterView;
-
-// Highlighter enabled state that is notified to observers.
-enum class HighlighterEnabledState {
-  // Highlighter is enabled by any ways.
-  kEnabled,
-  // Highlighter is disabled by user directly, for example disabling palette
-  // tool by user actions on palette menu.
-  kDisabledByUser,
-  // Highlighter is disabled on metalayer session complete.
-  kDisabledBySessionComplete,
-  // Highlighter is disabled on metalayer session abort. An abort may occur due
-  // to dismissal of Assistant UI or due to interruption by user via hotword.
-  kDisabledBySessionAbort,
-};
-
-// Controller for the highlighter functionality, which can be enabled/disabled
-// by switching "Assistant" tool under Stylus panel on/off.
-// Enables/disables highlighter as well as receives points
-// and passes them off to be rendered.
-class ASH_EXPORT HighlighterController
-    : public fast_ink::FastInkPointerController {
- public:
-  // Interface for classes that wish to be notified with highlighter status.
-  class Observer {
-   public:
-    // Called when highlighter enabled state changes.
-    virtual void OnHighlighterEnabledChanged(HighlighterEnabledState state) {}
-
-    // Called when highlighter selection is recognized.
-    virtual void OnHighlighterSelectionRecognized(const gfx::Rect& rect) {}
-
-   protected:
-    virtual ~Observer() = default;
-  };
-
-  HighlighterController();
-
-  HighlighterController(const HighlighterController&) = delete;
-  HighlighterController& operator=(const HighlighterController&) = delete;
-
-  ~HighlighterController() override;
-
-  HighlighterEnabledState enabled_state() { return enabled_state_; }
-
-  void AddObserver(Observer* observer);
-  void RemoveObserver(Observer* observer);
-
-  // Set the callback to exit the highlighter mode. If |require_success| is
-  // true, the callback will be called only after a successful gesture
-  // recognition. If |require_success| is false, the callback will be  called
-  // after the first complete gesture, regardless of the recognition result.
-  void SetExitCallback(base::OnceClosure callback, bool require_success);
-
-  // Update highlighter enabled |state| and notify observers.
-  void UpdateEnabledState(HighlighterEnabledState enabled_state);
-
-  // Aborts the current metalayer session. If no metalayer session exists,
-  // calling this method is a no-op.
-  void AbortSession();
-
- private:
-  friend class HighlighterControllerTestApi;
-
-  // fast_ink::FastInkPointerController:
-  void SetEnabled(bool enabled) override;
-  views::View* GetPointerView() const override;
-  void CreatePointerView(base::TimeDelta presentation_delay,
-                         aura::Window* root_window) override;
-  void UpdatePointerView(ui::TouchEvent* event) override;
-  void DestroyPointerView() override;
-  bool CanStartNewGesture(ui::LocatedEvent* event) override;
-  bool ShouldProcessEvent(ui::LocatedEvent* event) override;
-
-  // Performs gesture recognition, initiates appropriate visual effects,
-  // notifies the observer if necessary.
-  void RecognizeGesture();
-
-  // Destroys |highlighter_view_widget_|, if it exists.
-  void DestroyHighlighterView();
-
-  // Destroys |result_view_widget_|, if it exists.
-  void DestroyResultView();
-
-  // Calls and clears the mode exit callback, if it is set.
-  void CallExitCallback();
-
-  // Returns the Widget contents view of the highlighter widget as
-  // HighlighterView*.
-  HighlighterView* GetHighlighterView();
-
-  // Caches the highlighter enabled state.
-  HighlighterEnabledState enabled_state_ =
-      HighlighterEnabledState::kDisabledByUser;
-
-  // |highlighter_view_widget_| will only hold an instance when the highlighter
-  // is enabled and activated (pressed or dragged) and until the fade out
-  // animation is done.
-  views::UniqueWidgetPtr highlighter_view_widget_;
-
-  // |result_view_widget_| will only hold an instance when the selection result
-  // animation is in progress.
-  views::UniqueWidgetPtr result_view_widget_;
-
-  // Time of the session start (e.g. when the controller was enabled).
-  base::TimeTicks session_start_;
-
-  // Time of the previous gesture end, valid after the first gesture
-  // within the session is complete.
-  base::TimeTicks previous_gesture_end_;
-
-  // Gesture counter withing a session.
-  int gesture_counter_ = 0;
-
-  // Recognized gesture counter withing a session.
-  int recognized_gesture_counter_ = 0;
-
-  // Not null while waiting for the next event to continue an interrupted
-  // stroke.
-  std::unique_ptr<base::OneShotTimer> interrupted_stroke_timer_;
-
-  // The callback to exit the mode in the UI.
-  base::OnceClosure exit_callback_;
-
-  // If true, the mode is not exited until a valid selection is made.
-  bool require_success_ = true;
-
-  base::ObserverList<Observer>::Unchecked observers_;
-
-  base::WeakPtrFactory<HighlighterController> weak_factory_{this};
-};
-
-}  // namespace ash
-
-#endif  // ASH_HIGHLIGHTER_HIGHLIGHTER_CONTROLLER_H_
diff --git a/ash/highlighter/highlighter_controller_test_api.cc b/ash/highlighter/highlighter_controller_test_api.cc
deleted file mode 100644
index afb0479..0000000
--- a/ash/highlighter/highlighter_controller_test_api.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/highlighter/highlighter_controller_test_api.h"
-
-#include "ash/fast_ink/fast_ink_points.h"
-#include "ash/highlighter/highlighter_controller.h"
-#include "ash/highlighter/highlighter_view.h"
-#include "base/timer/timer.h"
-
-namespace ash {
-
-HighlighterControllerTestApi::HighlighterControllerTestApi(
-    HighlighterController* instance)
-    : instance_(instance) {
-  AttachClient();
-}
-
-HighlighterControllerTestApi::~HighlighterControllerTestApi() {
-  if (scoped_observation_)
-    DetachClient();
-  if (instance_->is_enabled())
-    instance_->SetEnabled(false);
-  instance_->DestroyPointerView();
-}
-
-void HighlighterControllerTestApi::AttachClient() {
-  scoped_observation_ = std::make_unique<ScopedObservation>(this);
-  scoped_observation_->Observe(instance_);
-}
-
-void HighlighterControllerTestApi::DetachClient() {
-  scoped_observation_.reset();
-  instance_->CallExitCallback();
-}
-
-void HighlighterControllerTestApi::SetEnabled(bool enabled) {
-  instance_->UpdateEnabledState(
-      enabled ? HighlighterEnabledState::kEnabled
-              : HighlighterEnabledState::kDisabledBySessionComplete);
-}
-
-void HighlighterControllerTestApi::DestroyPointerView() {
-  instance_->DestroyPointerView();
-}
-
-void HighlighterControllerTestApi::SimulateInterruptedStrokeTimeout() {
-  if (!instance_->interrupted_stroke_timer_)
-    return;
-  instance_->interrupted_stroke_timer_->Stop();
-  instance_->RecognizeGesture();
-}
-
-bool HighlighterControllerTestApi::IsShowingHighlighter() const {
-  return !!instance_->highlighter_view_widget_;
-}
-
-bool HighlighterControllerTestApi::IsFadingAway() const {
-  return IsShowingHighlighter() && instance_->GetHighlighterView()->animating();
-}
-
-bool HighlighterControllerTestApi::IsShowingSelectionResult() const {
-  return !!instance_->result_view_widget_;
-}
-
-bool HighlighterControllerTestApi::IsWaitingToResumeStroke() const {
-  return instance_->interrupted_stroke_timer_ &&
-         instance_->interrupted_stroke_timer_->IsRunning();
-}
-
-const fast_ink::FastInkPoints& HighlighterControllerTestApi::points() const {
-  return instance_->GetHighlighterView()->points_;
-}
-
-const fast_ink::FastInkPoints& HighlighterControllerTestApi::predicted_points()
-    const {
-  return instance_->GetHighlighterView()->predicted_points_;
-}
-
-bool HighlighterControllerTestApi::HandleEnabledStateChangedCalled() {
-  return handle_enabled_state_changed_called_;
-}
-
-bool HighlighterControllerTestApi::HandleSelectionCalled() {
-  return handle_selection_called_;
-}
-
-void HighlighterControllerTestApi::OnHighlighterSelectionRecognized(
-    const gfx::Rect& rect) {
-  handle_selection_called_ = true;
-  selection_ = rect;
-}
-
-void HighlighterControllerTestApi::OnHighlighterEnabledChanged(
-    HighlighterEnabledState state) {
-  const bool enabled = (state == HighlighterEnabledState::kEnabled);
-  handle_enabled_state_changed_called_ = true;
-  enabled_ = enabled;
-}
-
-}  // namespace ash
diff --git a/ash/highlighter/highlighter_controller_test_api.h b/ash/highlighter/highlighter_controller_test_api.h
deleted file mode 100644
index cbf1ad84..0000000
--- a/ash/highlighter/highlighter_controller_test_api.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_HIGHLIGHTER_HIGHLIGHTER_CONTROLLER_TEST_API_H_
-#define ASH_HIGHLIGHTER_HIGHLIGHTER_CONTROLLER_TEST_API_H_
-
-#include "ash/highlighter/highlighter_controller.h"
-#include "base/scoped_observation.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace fast_ink {
-class FastInkPoints;
-}
-
-namespace ash {
-
-// An api for testing the HighlighterController class.
-// Implements ash::mojom::HighlighterControllerClient and binds itself as the
-// client to provide the tests with access to gesture recognition results.
-class HighlighterControllerTestApi : public HighlighterController::Observer {
- public:
-  explicit HighlighterControllerTestApi(HighlighterController* instance);
-
-  HighlighterControllerTestApi(const HighlighterControllerTestApi&) = delete;
-  HighlighterControllerTestApi& operator=(const HighlighterControllerTestApi&) =
-      delete;
-
-  ~HighlighterControllerTestApi() override;
-
-  // Attaches itself as the client to the controller. This method is called
-  // automatically from the constructor, and should be explicitly called only
-  // if DetachClient has been called previously.
-  void AttachClient();
-
-  // Detaches itself from the controller.
-  void DetachClient();
-
-  void SetEnabled(bool enabled);
-  void DestroyPointerView();
-  void SimulateInterruptedStrokeTimeout();
-  bool IsShowingHighlighter() const;
-  bool IsFadingAway() const;
-  bool IsWaitingToResumeStroke() const;
-  bool IsShowingSelectionResult() const;
-  const fast_ink::FastInkPoints& points() const;
-  const fast_ink::FastInkPoints& predicted_points() const;
-
-  void ResetEnabledState() { handle_enabled_state_changed_called_ = false; }
-  bool HandleEnabledStateChangedCalled();
-  bool enabled() const { return enabled_; }
-
-  void ResetSelection() { handle_selection_called_ = false; }
-  bool HandleSelectionCalled();
-  const gfx::Rect& selection() const { return selection_; }
-
- private:
-  using ScopedObservation =
-      base::ScopedObservation<HighlighterController,
-                              HighlighterController::Observer>;
-
-  // HighlighterSelectionObserver:
-  void OnHighlighterSelectionRecognized(const gfx::Rect& rect) override;
-  void OnHighlighterEnabledChanged(HighlighterEnabledState state) override;
-
-  std::unique_ptr<ScopedObservation> scoped_observation_;
-  HighlighterController* instance_;
-
-  bool handle_selection_called_ = false;
-  bool handle_enabled_state_changed_called_ = false;
-  gfx::Rect selection_;
-  bool enabled_ = false;
-};
-
-}  // namespace ash
-
-#endif  // ASH_HIGHLIGHTER_HIGHLIGHTER_CONTROLLER_TEST_API_H_
diff --git a/ash/highlighter/highlighter_controller_unittest.cc b/ash/highlighter/highlighter_controller_unittest.cc
deleted file mode 100644
index d23cd7a..0000000
--- a/ash/highlighter/highlighter_controller_unittest.cc
+++ /dev/null
@@ -1,556 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/highlighter/highlighter_controller.h"
-
-#include <memory>
-
-#include "ash/assistant/test/assistant_ash_test_base.h"
-#include "ash/fast_ink/fast_ink_points.h"
-#include "ash/highlighter/highlighter_controller_test_api.h"
-#include "ash/public/cpp/stylus_utils.h"
-#include "ash/shell.h"
-#include "base/strings/stringprintf.h"
-#include "build/build_config.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/compositor/test/draw_waiter_for_test.h"
-#include "ui/events/test/event_generator.h"
-
-namespace ash {
-namespace {
-
-class TestHighlighterObserver : public HighlighterController::Observer {
- public:
-  TestHighlighterObserver() = default;
-
-  TestHighlighterObserver(const TestHighlighterObserver&) = delete;
-  TestHighlighterObserver& operator=(const TestHighlighterObserver&) = delete;
-
-  ~TestHighlighterObserver() override = default;
-
-  // HighlighterController::Observer:
-  void OnHighlighterEnabledChanged(HighlighterEnabledState state) override {
-    switch (state) {
-      case HighlighterEnabledState::kEnabled:
-        ++enabled_count_;
-        break;
-      case HighlighterEnabledState::kDisabledByUser:
-        ++disabled_by_user_count_;
-        break;
-      case HighlighterEnabledState::kDisabledBySessionAbort:
-        ++disabled_by_session_abort_;
-        break;
-      case HighlighterEnabledState::kDisabledBySessionComplete:
-        ++disabled_by_session_complete_;
-        break;
-    }
-  }
-
-  void OnHighlighterSelectionRecognized(const gfx::Rect& rect) override {
-    last_recognized_rect_ = rect;
-  }
-
-  int enabled_count_ = 0;
-  int disabled_by_user_count_ = 0;
-  int disabled_by_session_abort_ = 0;
-  int disabled_by_session_complete_ = 0;
-  gfx::Rect last_recognized_rect_;
-};
-
-class HighlighterControllerTest : public AssistantAshTestBase {
- public:
-  HighlighterControllerTest() = default;
-
-  HighlighterControllerTest(const HighlighterControllerTest&) = delete;
-  HighlighterControllerTest& operator=(const HighlighterControllerTest&) =
-      delete;
-
-  ~HighlighterControllerTest() override = default;
-
-  void SetUp() override {
-    AssistantAshTestBase::SetUp();
-    controller_ = Shell::Get()->highlighter_controller();
-    controller_test_api_ =
-        std::make_unique<HighlighterControllerTestApi>(controller_);
-  }
-
-  void TearDown() override {
-    // This needs to be called first to reset the controller state before the
-    // shell instance gets torn down.
-    controller_test_api_.reset();
-    AssistantAshTestBase::TearDown();
-  }
-
-  void UpdateDisplayAndWaitForCompositingEnded(
-      const std::string& display_specs) {
-    UpdateDisplay(display_specs);
-    ui::DrawWaiterForTest::WaitForCompositingEnded(
-        Shell::GetPrimaryRootWindow()->GetHost()->compositor());
-  }
-
- protected:
-  void TraceRect(const gfx::Rect& rect) {
-    ui::test::EventGenerator* event_generator = GetEventGenerator();
-    event_generator->MoveTouch(gfx::Point(rect.x(), rect.y()));
-    event_generator->PressTouch();
-    event_generator->MoveTouch(gfx::Point(rect.right(), rect.y()));
-    event_generator->MoveTouch(gfx::Point(rect.right(), rect.bottom()));
-    event_generator->MoveTouch(gfx::Point(rect.x(), rect.bottom()));
-    event_generator->MoveTouch(gfx::Point(rect.x(), rect.y()));
-    event_generator->ReleaseTouch();
-
-    // The the events above will trigger a frame, so wait until a new
-    // CompositorFrame is generated before terminating.
-    ui::DrawWaiterForTest::WaitForCompositingEnded(
-        Shell::GetPrimaryRootWindow()->GetHost()->compositor());
-  }
-
-  std::unique_ptr<HighlighterControllerTestApi> controller_test_api_;
-
-  HighlighterController* controller_ = nullptr;  // Not owned.
-};
-
-}  // namespace
-
-// Test to ensure the class responsible for drawing the highlighter pointer
-// receives points from stylus movements as expected.
-TEST_F(HighlighterControllerTest, HighlighterRenderer) {
-  ash::stylus_utils::SetHasStylusInputForTesting();
-
-  // The highlighter pointer mode only works with stylus.
-  ui::test::EventGenerator* event_generator = GetEventGenerator();
-  event_generator->EnterPenPointerMode();
-
-  // When disabled the highlighter pointer should not be showing.
-  event_generator->MoveTouch(gfx::Point(1, 1));
-  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
-
-  // Verify that by enabling the mode, the highlighter pointer should still not
-  // be showing.
-  controller_test_api_->SetEnabled(true);
-  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
-
-  // Verify moving the stylus 4 times will not display the highlighter pointer.
-  event_generator->MoveTouch(gfx::Point(2, 2));
-  event_generator->MoveTouch(gfx::Point(3, 3));
-  event_generator->MoveTouch(gfx::Point(4, 4));
-  event_generator->MoveTouch(gfx::Point(5, 5));
-  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
-
-  // Verify pressing the stylus will show the highlighter pointer and add a
-  // point but will not activate fading out.
-  event_generator->PressTouch();
-  EXPECT_TRUE(controller_test_api_->IsShowingHighlighter());
-  EXPECT_FALSE(controller_test_api_->IsFadingAway());
-  EXPECT_EQ(1, controller_test_api_->points().GetNumberOfPoints());
-
-  // Verify dragging the stylus 2 times will add 2 more points.
-  event_generator->MoveTouch(gfx::Point(6, 6));
-  event_generator->MoveTouch(gfx::Point(7, 7));
-  EXPECT_EQ(3, controller_test_api_->points().GetNumberOfPoints());
-
-  // Verify releasing the stylus still shows the highlighter pointer, which is
-  // fading away.
-  event_generator->ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_->IsShowingHighlighter());
-  EXPECT_TRUE(controller_test_api_->IsFadingAway());
-
-  // Verify that disabling the mode right after the gesture completion does not
-  // hide the highlighter pointer immediately but lets it play out the
-  // animation.
-  controller_test_api_->SetEnabled(false);
-  EXPECT_TRUE(controller_test_api_->IsShowingHighlighter());
-  EXPECT_TRUE(controller_test_api_->IsFadingAway());
-
-  // Verify that disabling the mode mid-gesture hides the highlighter pointer
-  // immediately.
-  controller_test_api_->DestroyPointerView();
-  controller_test_api_->SetEnabled(true);
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(6, 6));
-  EXPECT_TRUE(controller_test_api_->IsShowingHighlighter());
-  controller_test_api_->SetEnabled(false);
-  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
-
-  // Verify that the highlighter pointer does not add points while disabled.
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(8, 8));
-  event_generator->ReleaseTouch();
-  event_generator->MoveTouch(gfx::Point(9, 9));
-  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
-
-  // Verify that the highlighter pointer does not get shown if points are not
-  // coming from the stylus, even when enabled.
-  event_generator->ExitPenPointerMode();
-  controller_test_api_->SetEnabled(true);
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(10, 10));
-  event_generator->MoveTouch(gfx::Point(11, 11));
-  EXPECT_FALSE(controller_test_api_->IsShowingHighlighter());
-  event_generator->ReleaseTouch();
-}
-
-// Test to ensure the class responsible for drawing the highlighter pointer
-// handles prediction as expected when it receives points from stylus movements.
-TEST_F(HighlighterControllerTest, HighlighterPrediction) {
-  controller_test_api_->SetEnabled(true);
-  // The highlighter pointer mode only works with stylus.
-  ui::test::EventGenerator* event_generator = GetEventGenerator();
-  event_generator->EnterPenPointerMode();
-  event_generator->PressTouch();
-  EXPECT_TRUE(controller_test_api_->IsShowingHighlighter());
-
-  EXPECT_EQ(1, controller_test_api_->points().GetNumberOfPoints());
-  // Initial press event shouldn't generate any predicted points as there's no
-  // history to use for prediction.
-  EXPECT_EQ(0, controller_test_api_->predicted_points().GetNumberOfPoints());
-
-  // Verify dragging the stylus 3 times will add some predicted points.
-  event_generator->MoveTouch(gfx::Point(10, 10));
-  event_generator->MoveTouch(gfx::Point(20, 20));
-  event_generator->MoveTouch(gfx::Point(30, 30));
-  EXPECT_NE(0, controller_test_api_->predicted_points().GetNumberOfPoints());
-  // Verify predicted points are in the right direction.
-  for (const auto& point : controller_test_api_->predicted_points().points()) {
-    EXPECT_LT(30, point.location.x());
-    EXPECT_LT(30, point.location.y());
-  }
-}
-
-// Test that stylus gestures are correctly recognized by HighlighterController.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#define MAYBE_HighlighterGestures DISABLED_HighlighterGestures
-#else
-#define MAYBE_HighlighterGestures HighlighterGestures
-#endif
-TEST_F(HighlighterControllerTest, MAYBE_HighlighterGestures) {
-  controller_test_api_->SetEnabled(true);
-  ui::test::EventGenerator* event_generator = GetEventGenerator();
-  event_generator->EnterPenPointerMode();
-
-  TestHighlighterObserver observer;
-  controller_->AddObserver(&observer);
-
-  // A non-horizontal stroke is not recognized
-  controller_test_api_->ResetSelection();
-  event_generator->MoveTouch(gfx::Point(100, 100));
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(200, 200));
-  event_generator->ReleaseTouch();
-  EXPECT_FALSE(controller_test_api_->HandleSelectionCalled());
-
-  // An almost horizontal stroke is recognized
-  controller_test_api_->ResetSelection();
-  event_generator->MoveTouch(gfx::Point(100, 100));
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(300, 102));
-  event_generator->ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-
-  // Horizontal stroke selection rectangle should:
-  //   have the same horizontal center line as the stroke bounding box,
-  //   be 4dp wider than the stroke bounding box,
-  //   be exactly 14dp high.
-  gfx::Rect expected_rect(98, 94, 204, 14);
-  EXPECT_EQ(expected_rect, controller_test_api_->selection());
-  EXPECT_EQ(expected_rect, observer.last_recognized_rect_);
-
-  // An insufficiently closed C-like shape is not recognized
-  controller_test_api_->ResetSelection();
-  event_generator->MoveTouch(gfx::Point(100, 0));
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(0, 0));
-  event_generator->MoveTouch(gfx::Point(0, 100));
-  event_generator->MoveTouch(gfx::Point(100, 100));
-  event_generator->ReleaseTouch();
-  EXPECT_FALSE(controller_test_api_->HandleSelectionCalled());
-
-  // An almost closed G-like shape is recognized
-  controller_test_api_->ResetSelection();
-  event_generator->MoveTouch(gfx::Point(200, 0));
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(0, 0));
-  event_generator->MoveTouch(gfx::Point(0, 100));
-  event_generator->MoveTouch(gfx::Point(200, 100));
-  event_generator->MoveTouch(gfx::Point(200, 20));
-  event_generator->ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-  expected_rect = gfx::Rect(0, 0, 200, 100);
-  EXPECT_EQ(expected_rect, controller_test_api_->selection());
-  EXPECT_EQ(expected_rect, observer.last_recognized_rect_);
-
-  // A closed diamond shape is recognized
-  controller_test_api_->ResetSelection();
-  event_generator->MoveTouch(gfx::Point(100, 50));
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(200, 150));
-  event_generator->MoveTouch(gfx::Point(100, 250));
-  event_generator->MoveTouch(gfx::Point(0, 150));
-  event_generator->MoveTouch(gfx::Point(100, 50));
-  event_generator->ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-  expected_rect = gfx::Rect(0, 50, 200, 200);
-  EXPECT_EQ(expected_rect, controller_test_api_->selection());
-  EXPECT_EQ(expected_rect, observer.last_recognized_rect_);
-
-  controller_->RemoveObserver(&observer);
-}
-
-// TODO(1346951): Disable HighlighterGesturesScaled on Linux Chromium OS Asan
-// Lsan Tests.
-#if defined(LEAK_SANITIZER) && BUILDFLAG(IS_CHROMEOS)
-#define MAYBE_HighlighterGesturesScaled DISABLED_HighlighterGesturesScaled
-#else
-#define MAYBE_HighlighterGesturesScaled HighlighterGesturesScaled
-#endif
-TEST_F(HighlighterControllerTest, MAYBE_HighlighterGesturesScaled) {
-  controller_test_api_->SetEnabled(true);
-  ui::test::EventGenerator* event_generator = GetEventGenerator();
-  event_generator->EnterPenPointerMode();
-
-  const gfx::Rect original_px(200, 100, 400, 300);
-
-  constexpr float display_scales[] = {1.f, 1.5f, 2.0f};
-  constexpr float ui_scales[] = {0.5f,  0.67f, 1.0f,  1.25f,
-                                 1.33f, 1.5f,  1.67f, 2.0f};
-
-  for (size_t i = 0; i < sizeof(display_scales) / sizeof(float); ++i) {
-    const float display_scale = display_scales[i];
-    for (size_t j = 0; j < sizeof(ui_scales) / sizeof(float); ++j) {
-      const float ui_scale = ui_scales[j];
-
-      std::string display_spec =
-          base::StringPrintf("1500x1000*%.2f@%.2f", display_scale, ui_scale);
-      SCOPED_TRACE(display_spec);
-      UpdateDisplayAndWaitForCompositingEnded(display_spec);
-
-      controller_test_api_->ResetSelection();
-      TraceRect(original_px);
-      EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-
-      const float combined_scale = display_scale * ui_scale;
-
-      const gfx::Rect selection_dp = controller_test_api_->selection();
-      const gfx::Rect selection_px = gfx::ToEnclosingRect(
-          gfx::ScaleRect(gfx::RectF(selection_dp), combined_scale));
-      EXPECT_TRUE(selection_px.Contains(original_px));
-
-      gfx::Rect inflated_px(original_px);
-      // Allow for rounding errors within 1dp.
-      const int error_margin = static_cast<int>(std::ceil(combined_scale));
-      inflated_px.Inset(-error_margin);
-      EXPECT_TRUE(inflated_px.Contains(selection_px));
-    }
-  }
-}
-
-// Test that stylus gesture recognition correctly handles display rotation
-TEST_F(HighlighterControllerTest, HighlighterGesturesRotated) {
-  controller_test_api_->SetEnabled(true);
-  ui::test::EventGenerator* event_generator = GetEventGenerator();
-  event_generator->EnterPenPointerMode();
-
-  const gfx::Rect trace(200, 100, 400, 300);
-
-  // No rotation
-  UpdateDisplayAndWaitForCompositingEnded("1500x1000");
-  controller_test_api_->ResetSelection();
-  TraceRect(trace);
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-  EXPECT_EQ("200,100 400x300", controller_test_api_->selection().ToString());
-
-  // Rotate to 90 degrees
-  UpdateDisplayAndWaitForCompositingEnded("1500x1000/r");
-  controller_test_api_->ResetSelection();
-  TraceRect(trace);
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-  EXPECT_EQ("100,900 300x400", controller_test_api_->selection().ToString());
-
-  // Rotate to 180 degrees
-  UpdateDisplayAndWaitForCompositingEnded("1500x1000/u");
-  controller_test_api_->ResetSelection();
-  TraceRect(trace);
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-  EXPECT_EQ("900,600 400x300", controller_test_api_->selection().ToString());
-
-  // Rotate to 270 degrees
-  UpdateDisplayAndWaitForCompositingEnded("1500x1000/l");
-  controller_test_api_->ResetSelection();
-  TraceRect(trace);
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-  EXPECT_EQ("600,200 300x400", controller_test_api_->selection().ToString());
-}
-
-// Flaky on Linux Chromium OS ASan LSan. https://crbug.com/1315061
-#if defined(ADDRESS_SANITIZER)
-#define MAYBE_InterruptedStroke DISABLED_InterruptedStroke
-#else
-#define MAYBE_InterruptedStroke InterruptedStroke
-#endif
-
-// Test that a stroke interrupted close to the screen edge is treated as
-// contiguous.
-TEST_F(HighlighterControllerTest, MAYBE_InterruptedStroke) {
-  controller_test_api_->SetEnabled(true);
-  ui::test::EventGenerator* event_generator = GetEventGenerator();
-  event_generator->EnterPenPointerMode();
-
-  UpdateDisplayAndWaitForCompositingEnded("1500x1000");
-
-  // An interrupted stroke close to the screen edge should be recognized as a
-  // contiguous stroke.
-  controller_test_api_->ResetSelection();
-  event_generator->MoveTouch(gfx::Point(300, 100));
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(0, 100));
-  event_generator->ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_->IsWaitingToResumeStroke());
-  EXPECT_FALSE(controller_test_api_->HandleSelectionCalled());
-  EXPECT_FALSE(controller_test_api_->IsFadingAway());
-
-  event_generator->MoveTouch(gfx::Point(0, 200));
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(300, 200));
-  event_generator->ReleaseTouch();
-  EXPECT_FALSE(controller_test_api_->IsWaitingToResumeStroke());
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-  EXPECT_EQ("0,100 300x100", controller_test_api_->selection().ToString());
-
-  // Repeat the same gesture, but simulate a timeout after the gap. This should
-  // force the gesture completion.
-  controller_test_api_->ResetSelection();
-  event_generator->MoveTouch(gfx::Point(300, 100));
-  event_generator->PressTouch();
-  event_generator->MoveTouch(gfx::Point(0, 100));
-  event_generator->ReleaseTouch();
-  EXPECT_TRUE(controller_test_api_->IsWaitingToResumeStroke());
-  EXPECT_FALSE(controller_test_api_->HandleSelectionCalled());
-  EXPECT_FALSE(controller_test_api_->IsFadingAway());
-
-  controller_test_api_->SimulateInterruptedStrokeTimeout();
-  EXPECT_FALSE(controller_test_api_->IsWaitingToResumeStroke());
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-  EXPECT_TRUE(controller_test_api_->IsFadingAway());
-}
-
-// Test that the selection is never crossing the screen bounds.
-// Flaky, https://crbug.com/1311772
-TEST_F(HighlighterControllerTest, DISABLED_SelectionInsideScreen) {
-  controller_test_api_->SetEnabled(true);
-  ui::test::EventGenerator* event_generator = GetEventGenerator();
-  event_generator->EnterPenPointerMode();
-
-  constexpr float display_scales[] = {1.f, 1.5f, 2.0f};
-
-  for (size_t i = 0; i < sizeof(display_scales) / sizeof(float); ++i) {
-    // 2nd display is for offscreen test.
-    std::string display_spec = base::StringPrintf(
-        "1000x999*%.2f,500x1000*%.2f", display_scales[i], display_scales[i]);
-    SCOPED_TRACE(display_spec);
-    UpdateDisplayAndWaitForCompositingEnded(display_spec);
-
-    const gfx::Rect screen(0, 0, 1000, 999);
-
-    // Rectangle completely offscreen.
-    controller_test_api_->ResetSelection();
-    TraceRect(gfx::Rect(-100, -100, 10, 10));
-    controller_test_api_->SimulateInterruptedStrokeTimeout();
-    EXPECT_FALSE(controller_test_api_->HandleSelectionCalled());
-
-    // Rectangle crossing the left edge.
-    controller_test_api_->ResetSelection();
-    TraceRect(gfx::Rect(-100, 100, 200, 200));
-    controller_test_api_->SimulateInterruptedStrokeTimeout();
-    EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-    EXPECT_TRUE(screen.Contains(controller_test_api_->selection()));
-
-    // Rectangle crossing the top edge.
-    controller_test_api_->ResetSelection();
-    TraceRect(gfx::Rect(100, -100, 200, 200));
-    controller_test_api_->SimulateInterruptedStrokeTimeout();
-    EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-    EXPECT_TRUE(screen.Contains(controller_test_api_->selection()));
-
-    // Rectangle crossing the right edge.
-    controller_test_api_->ResetSelection();
-    TraceRect(gfx::Rect(900, 100, 200, 200));
-    controller_test_api_->SimulateInterruptedStrokeTimeout();
-    EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-    EXPECT_TRUE(screen.Contains(controller_test_api_->selection()));
-
-    // Rectangle crossing the bottom edge.
-    controller_test_api_->ResetSelection();
-    TraceRect(gfx::Rect(100, 900, 200, 200));
-    controller_test_api_->SimulateInterruptedStrokeTimeout();
-    EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-    EXPECT_TRUE(screen.Contains(controller_test_api_->selection()));
-
-    // Vertical stroke completely offscreen.
-    controller_test_api_->ResetSelection();
-    event_generator->MoveTouch(gfx::Point(1100, 100));
-    event_generator->PressTouch();
-    event_generator->MoveTouch(gfx::Point(1100, 500));
-    event_generator->ReleaseTouch();
-    controller_test_api_->SimulateInterruptedStrokeTimeout();
-    EXPECT_FALSE(controller_test_api_->HandleSelectionCalled());
-
-    // Horizontal stroke along the top edge of the screen.
-    controller_test_api_->ResetSelection();
-    event_generator->MoveTouch(gfx::Point(0, 0));
-    event_generator->PressTouch();
-    event_generator->MoveTouch(gfx::Point(1000, 0));
-    event_generator->ReleaseTouch();
-    controller_test_api_->SimulateInterruptedStrokeTimeout();
-    EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-    EXPECT_TRUE(screen.Contains(controller_test_api_->selection()));
-
-    // Horizontal stroke along the bottom edge of the screen.
-    controller_test_api_->ResetSelection();
-    event_generator->MoveTouch(gfx::Point(0, 999));
-    event_generator->PressTouch();
-    event_generator->MoveTouch(gfx::Point(1000, 999));
-    event_generator->ReleaseTouch();
-    controller_test_api_->SimulateInterruptedStrokeTimeout();
-    EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-    EXPECT_TRUE(screen.Contains(controller_test_api_->selection()));
-  }
-}
-
-// Test that a detached client does not receive notifications.
-TEST_F(HighlighterControllerTest, DetachedClient) {
-  controller_test_api_->SetEnabled(true);
-  ui::test::EventGenerator* event_generator = GetEventGenerator();
-  event_generator->EnterPenPointerMode();
-
-  UpdateDisplayAndWaitForCompositingEnded("1500x1000");
-  const gfx::Rect trace(200, 100, 400, 300);
-
-  // Detach the client, no notifications should reach it.
-  controller_test_api_->DetachClient();
-
-  controller_test_api_->ResetEnabledState();
-  controller_test_api_->SetEnabled(false);
-  EXPECT_FALSE(controller_test_api_->HandleEnabledStateChangedCalled());
-  controller_test_api_->SetEnabled(true);
-  EXPECT_FALSE(controller_test_api_->HandleEnabledStateChangedCalled());
-
-  controller_test_api_->ResetSelection();
-  TraceRect(trace);
-  EXPECT_FALSE(controller_test_api_->HandleSelectionCalled());
-
-  // Attach the client again, notifications should be delivered normally.
-  controller_test_api_->AttachClient();
-
-  controller_test_api_->ResetEnabledState();
-  controller_test_api_->SetEnabled(false);
-  EXPECT_TRUE(controller_test_api_->HandleEnabledStateChangedCalled());
-  controller_test_api_->SetEnabled(true);
-  EXPECT_TRUE(controller_test_api_->HandleEnabledStateChangedCalled());
-
-  controller_test_api_->ResetSelection();
-  TraceRect(trace);
-  EXPECT_TRUE(controller_test_api_->HandleSelectionCalled());
-}
-
-}  // namespace ash
diff --git a/ash/highlighter/highlighter_gesture_util.cc b/ash/highlighter/highlighter_gesture_util.cc
deleted file mode 100644
index ec3d05bb..0000000
--- a/ash/highlighter/highlighter_gesture_util.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/highlighter/highlighter_gesture_util.h"
-
-#include <cmath>
-
-#include "ash/fast_ink/fast_ink_points.h"
-#include "base/numerics/math_constants.h"
-
-namespace ash {
-
-namespace {
-
-constexpr float kHorizontalStrokeLengthThreshold = 20;
-constexpr float kHorizontalStrokeThicknessThreshold = 2;
-constexpr float kHorizontalStrokeFlatnessThreshold = 0.1;
-
-constexpr double kClosedShapeSweepThreshold = base::kPiDouble * 2 * 0.8;
-constexpr double kClosedShapeJiggleThreshold = 0.1;
-
-bool DetectHorizontalStroke(const gfx::RectF& box,
-                            const gfx::SizeF& pen_tip_size) {
-  return box.width() > kHorizontalStrokeLengthThreshold &&
-         box.height() <
-             pen_tip_size.height() * kHorizontalStrokeThicknessThreshold &&
-         box.height() < box.width() * kHorizontalStrokeFlatnessThreshold;
-}
-
-bool DetectClosedShape(const gfx::RectF& box,
-                       const fast_ink::FastInkPoints& points) {
-  if (points.GetNumberOfPoints() < 3)
-    return false;
-
-  const gfx::PointF center = box.CenterPoint();
-
-  // Analyze vectors pointing from the center to each point.
-  // Compute the cumulative swept angle and count positive
-  // and negative angles separately.
-  double swept_angle = 0.0;
-  int positive = 0;
-  int negative = 0;
-
-  double prev_angle = 0.0;
-  bool has_prev_angle = false;
-
-  for (const auto& point : points.points()) {
-    const double angle =
-        atan2(point.location.y() - center.y(), point.location.x() - center.x());
-    if (has_prev_angle) {
-      double diff_angle = angle - prev_angle;
-      if (diff_angle > base::kPiDouble) {
-        diff_angle -= base::kPiDouble * 2;
-      } else if (diff_angle < -base::kPiDouble) {
-        diff_angle += base::kPiDouble * 2;
-      }
-      swept_angle += diff_angle;
-      if (diff_angle > 0)
-        positive++;
-      if (diff_angle < 0)
-        negative++;
-    } else {
-      has_prev_angle = true;
-    }
-    prev_angle = angle;
-  }
-
-  if (std::abs(swept_angle) < kClosedShapeSweepThreshold) {
-    // Has not swept enough of the full circle.
-    return false;
-  }
-
-  if (swept_angle > 0 && (static_cast<double>(negative) / positive) >
-                             kClosedShapeJiggleThreshold) {
-    // Main direction is positive, but went too often in the negative direction.
-    return false;
-  }
-  if (swept_angle < 0 && (static_cast<double>(positive) / negative) >
-                             kClosedShapeJiggleThreshold) {
-    // Main direction is negative, but went too often in the positive direction.
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace
-
-HighlighterGestureType DetectHighlighterGesture(
-    const gfx::RectF& box,
-    const gfx::SizeF& pen_tip_size,
-    const fast_ink::FastInkPoints& points) {
-  if (DetectHorizontalStroke(box, pen_tip_size))
-    return HighlighterGestureType::kHorizontalStroke;
-
-  if (DetectClosedShape(box, points))
-    return HighlighterGestureType::kClosedShape;
-
-  return HighlighterGestureType::kNotRecognized;
-}
-
-}  // namespace ash
diff --git a/ash/highlighter/highlighter_gesture_util.h b/ash/highlighter/highlighter_gesture_util.h
deleted file mode 100644
index 8271ec4..0000000
--- a/ash/highlighter/highlighter_gesture_util.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_HIGHLIGHTER_HIGHLIGHTER_GESTURE_UTIL_H_
-#define ASH_HIGHLIGHTER_HIGHLIGHTER_GESTURE_UTIL_H_
-
-#include "ash/ash_export.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace fast_ink {
-class FastInkPoints;
-}
-
-namespace ash {
-
-// Highlighter gesture recognition result type. This enum is used to back
-// an UMA histogram and should be treated as append-only.
-enum class HighlighterGestureType {
-  kNotRecognized = 0,
-  kHorizontalStroke,
-  kClosedShape,
-  kGestureCount
-};
-
-// Returns the recognized gesture type.
-HighlighterGestureType ASH_EXPORT
-DetectHighlighterGesture(const gfx::RectF& box,
-                         const gfx::SizeF& pen_tip_size,
-                         const fast_ink::FastInkPoints& points);
-
-}  // namespace ash
-
-#endif  // ASH_HIGHLIGHTER_HIGHLIGHTER_GESTURE_UTIL_H_
diff --git a/ash/highlighter/highlighter_gesture_util_unittest.cc b/ash/highlighter/highlighter_gesture_util_unittest.cc
deleted file mode 100644
index a3796b74..0000000
--- a/ash/highlighter/highlighter_gesture_util_unittest.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/highlighter/highlighter_gesture_util.h"
-#include "ash/fast_ink/fast_ink_points.h"
-#include "ash/test/ash_test_base.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-
-namespace ash {
-
-namespace {
-
-constexpr float kLength = 400;
-
-constexpr gfx::RectF kFrame(50, 50, 300, 200);
-
-constexpr gfx::SizeF kPenTipSize(4.0, 14);
-
-constexpr int kPointsPerLine = 10;
-
-float LinearInterpolate(float from, float to, int position, int range) {
-  return from + ((to - from) * position) / range;
-}
-
-class HighlighterGestureUtilTest : public AshTestBase {
- public:
-  HighlighterGestureUtilTest() : points_(base::TimeDelta()) {}
-
-  HighlighterGestureUtilTest(const HighlighterGestureUtilTest&) = delete;
-  HighlighterGestureUtilTest& operator=(const HighlighterGestureUtilTest&) =
-      delete;
-
-  ~HighlighterGestureUtilTest() override = default;
-
- protected:
-  fast_ink::FastInkPoints points_;
-
-  void MoveTo(float x, float y) { AddPoint(x, y); }
-
-  void LineTo(float x, float y) {
-    const gfx::PointF origin = points_.GetNewest().location;
-    for (int i = 1; i <= kPointsPerLine; i++) {
-      AddPoint(LinearInterpolate(origin.x(), x, i, kPointsPerLine),
-               LinearInterpolate(origin.y(), y, i, kPointsPerLine));
-    }
-  }
-
-  void TraceLine(float x0, float y0, float x1, float y1) {
-    MoveTo(x0, y0);
-    LineTo(x1, y1);
-  }
-
-  void TraceRect(const gfx::RectF& rect, float tilt) {
-    MoveTo(rect.x() + tilt, rect.y());
-    LineTo(rect.right(), rect.y() + tilt);
-    LineTo(rect.right() - tilt, rect.bottom());
-    LineTo(rect.x(), rect.bottom() - tilt);
-    LineTo(rect.x() + tilt, rect.y());
-  }
-
-  void TraceZigZag(float w, float h) {
-    MoveTo(0, 0);
-    LineTo(w / 4, h);
-    LineTo(w / 2, 0);
-    LineTo(w * 3 / 4, h);
-    LineTo(w, 0);
-  }
-
-  HighlighterGestureType DetectGesture() {
-    return DetectHighlighterGesture(points_.GetBoundingBoxF(), kPenTipSize,
-                                    points_);
-  }
-
- private:
-  void AddPoint(float x, float y) {
-    points_.AddPoint(gfx::PointF(x, y), base::TimeTicks());
-  }
-};
-
-}  // namespace
-
-TEST_F(HighlighterGestureUtilTest, HorizontalStrokeTooShort) {
-  TraceLine(0, 0, 1, 0);
-  EXPECT_EQ(HighlighterGestureType::kNotRecognized, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, HorizontalStrokeFlat) {
-  TraceLine(0, 0, kLength, 0);
-  EXPECT_EQ(HighlighterGestureType::kHorizontalStroke, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, HorizontalStrokeTiltedLeftSlightly) {
-  const float kTilt = kLength / 20;
-  TraceLine(0, kTilt, kLength, 0);
-  EXPECT_EQ(HighlighterGestureType::kHorizontalStroke, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, HorizontalStrokeTiltedRightSlightly) {
-  const float kTilt = kLength / 20;
-  TraceLine(0, 0, kLength, kTilt);
-  EXPECT_EQ(HighlighterGestureType::kHorizontalStroke, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, HorizontalStrokeTiltedLeftTooMuch) {
-  const float kTilt = kLength / 5;
-  TraceLine(0, kTilt, kLength, 0);
-  EXPECT_EQ(HighlighterGestureType::kNotRecognized, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, HorizontalStrokeTiltedRightTooMuch) {
-  const float kTilt = kLength / 5;
-  TraceLine(0, 0, kLength, kTilt);
-  EXPECT_EQ(HighlighterGestureType::kNotRecognized, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, HorizontalStrokeZigZagSlightly) {
-  const float kHeight = kLength / 20;
-  TraceZigZag(kLength, kHeight);
-  EXPECT_EQ(HighlighterGestureType::kHorizontalStroke, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, HorizontalStrokeZigZagTooMuch) {
-  const float kHeight = kLength / 5;
-  TraceZigZag(kLength, kHeight);
-  EXPECT_EQ(HighlighterGestureType::kNotRecognized, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, ClosedShapeRectangle) {
-  TraceRect(kFrame, 0);
-  EXPECT_EQ(HighlighterGestureType::kClosedShape, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, ClosedShapeRectangleThin) {
-  TraceRect(gfx::RectF(0, 0, kLength, kLength / 20), 0);
-  EXPECT_EQ(HighlighterGestureType::kHorizontalStroke, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, ClosedShapeRectangleTilted) {
-  TraceRect(kFrame, 10.0);
-  EXPECT_EQ(HighlighterGestureType::kClosedShape, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, ClosedShapeWithOverlap) {
-  // 1/4 overlap
-  MoveTo(kFrame.right(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.y());
-  EXPECT_EQ(HighlighterGestureType::kClosedShape, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, ClosedShapeLikeU) {
-  // 1/4 open shape
-  MoveTo(kFrame.x(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.y());
-  EXPECT_EQ(HighlighterGestureType::kNotRecognized, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, ClosedShapeLikeG) {
-  // 1/8 open shape
-  MoveTo(kFrame.right(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.CenterPoint().y());
-  EXPECT_EQ(HighlighterGestureType::kClosedShape, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, ClosedShapeWithLittleBackAndForth) {
-  MoveTo(kFrame.right(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.y());
-  // Go back one pixel, then go forward again.
-  MoveTo(kFrame.x() + 1, kFrame.y());
-  MoveTo(kFrame.x(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.CenterPoint().y());
-  EXPECT_EQ(HighlighterGestureType::kClosedShape, DetectGesture());
-}
-
-TEST_F(HighlighterGestureUtilTest, ClosedShapeWithTooMuchBackAndForth) {
-  MoveTo(kFrame.right(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.y());
-  LineTo(kFrame.right(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.bottom());
-  LineTo(kFrame.x(), kFrame.y());
-  LineTo(kFrame.x(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.bottom());
-  LineTo(kFrame.x(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.bottom());
-  LineTo(kFrame.right(), kFrame.CenterPoint().y());
-  EXPECT_EQ(HighlighterGestureType::kNotRecognized, DetectGesture());
-}
-
-}  // namespace ash
diff --git a/ash/highlighter/highlighter_result_view.cc b/ash/highlighter/highlighter_result_view.cc
deleted file mode 100644
index 4794d60..0000000
--- a/ash/highlighter/highlighter_result_view.cc
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/highlighter/highlighter_result_view.h"
-
-#include <memory>
-
-#include "ash/highlighter/highlighter_gesture_util.h"
-#include "ash/highlighter/highlighter_view.h"
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/shell.h"
-#include "base/functional/bind.h"
-#include "base/timer/timer.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/paint_recorder.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/views/widget/widget.h"
-
-namespace ash {
-
-namespace {
-
-// Variables for rendering the highlight result. Sizes in DIP.
-constexpr float kCornerCircleRadius = 6;
-constexpr float kStrokeFillWidth = 2;
-constexpr float kStrokeOutlineWidth = 1;
-constexpr float kOutsetForAntialiasing = 1;
-constexpr float kResultLayerMargin =
-    kOutsetForAntialiasing + kCornerCircleRadius;
-
-constexpr int kInnerFillOpacity = 0x0D;
-const SkColor kInnerFillColor = SkColorSetRGB(0x00, 0x00, 0x00);
-
-constexpr int kStrokeFillOpacity = 0xFF;
-const SkColor kStrokeFillColor = SkColorSetRGB(0xFF, 0xFF, 0xFF);
-
-constexpr int kStrokeOutlineOpacity = 0x14;
-const SkColor kStrokeOutlineColor = SkColorSetRGB(0x00, 0x00, 0x00);
-
-constexpr int kCornerCircleOpacity = 0xFF;
-const SkColor kCornerCircleColorLT = SkColorSetRGB(0x42, 0x85, 0xF4);
-const SkColor kCornerCircleColorRT = SkColorSetRGB(0xEA, 0x43, 0x35);
-const SkColor kCornerCircleColorLB = SkColorSetRGB(0x34, 0xA8, 0x53);
-const SkColor kCornerCircleColorRB = SkColorSetRGB(0xFB, 0xBC, 0x05);
-
-constexpr int kResultFadeinDelayMs = 200;
-constexpr int kResultFadeinDurationMs = 400;
-constexpr int kResultFadeoutDelayMs = 500;
-constexpr int kResultFadeoutDurationMs = 200;
-
-constexpr int kResultInPlaceFadeinDelayMs = 100;
-constexpr int kResultInPlaceFadeinDurationMs = 500;
-
-constexpr float kInitialScale = 1.2;
-
-class ResultLayer : public ui::Layer, public ui::LayerDelegate {
- public:
-  ResultLayer(const gfx::Rect& bounds);
-
-  ResultLayer(const ResultLayer&) = delete;
-  ResultLayer& operator=(const ResultLayer&) = delete;
-
- private:
-  // ui::LayerDelegate:
-  void OnDeviceScaleFactorChanged(float old_device_scale_factor,
-                                  float new_device_scale_factor) override {}
-  void OnPaintLayer(const ui::PaintContext& context) override;
-
-  void DrawVerticalBar(gfx::Canvas& canvas,
-                       float x,
-                       float y,
-                       float height,
-                       cc::PaintFlags& flags);
-  void DrawHorizontalBar(gfx::Canvas& canvas,
-                         float x,
-                         float y,
-                         float width,
-                         cc::PaintFlags& flags);
-};
-
-ResultLayer::ResultLayer(const gfx::Rect& box) {
-  SetName("HighlighterResultView:ResultLayer");
-  gfx::Rect bounds = box;
-  bounds.Inset(-kResultLayerMargin);
-  SetBounds(bounds);
-  SetFillsBoundsOpaquely(false);
-  SetMasksToBounds(false);
-  set_delegate(this);
-}
-
-void ResultLayer::OnPaintLayer(const ui::PaintContext& context) {
-  ui::PaintRecorder recorder(context, size());
-  gfx::Canvas& canvas = *recorder.canvas();
-
-  cc::PaintFlags flags;
-  flags.setStyle(cc::PaintFlags::kFill_Style);
-  flags.setAntiAlias(true);
-
-  const float left = kResultLayerMargin;
-  const float right = size().width() - kResultLayerMargin;
-  const float width = right - left;
-
-  const float top = kResultLayerMargin;
-  const float bottom = size().height() - kResultLayerMargin;
-  const float height = bottom - top;
-
-  flags.setColor(SkColorSetA(kInnerFillColor, kInnerFillOpacity));
-  canvas.DrawRect(gfx::RectF(left, top, width, height), flags);
-
-  DrawVerticalBar(canvas, left, top, height, flags);
-  DrawVerticalBar(canvas, right, top, height, flags);
-  DrawHorizontalBar(canvas, left, top, width, flags);
-  DrawHorizontalBar(canvas, left, bottom, width, flags);
-
-  flags.setColor(SkColorSetA(kCornerCircleColorLT, kCornerCircleOpacity));
-  canvas.DrawCircle(gfx::PointF(left, top), kCornerCircleRadius, flags);
-
-  flags.setColor(SkColorSetA(kCornerCircleColorRT, kCornerCircleOpacity));
-  canvas.DrawCircle(gfx::PointF(right, top), kCornerCircleRadius, flags);
-
-  flags.setColor(SkColorSetA(kCornerCircleColorLB, kCornerCircleOpacity));
-  canvas.DrawCircle(gfx::PointF(right, bottom), kCornerCircleRadius, flags);
-
-  flags.setColor(SkColorSetA(kCornerCircleColorRB, kCornerCircleOpacity));
-  canvas.DrawCircle(gfx::PointF(left, bottom), kCornerCircleRadius, flags);
-}
-
-void ResultLayer::DrawVerticalBar(gfx::Canvas& canvas,
-                                  float x,
-                                  float y,
-                                  float height,
-                                  cc::PaintFlags& flags) {
-  const float x_fill = x - kStrokeFillWidth / 2;
-  const float x_outline_left = x_fill - kStrokeOutlineWidth;
-  const float x_outline_right = x_fill + kStrokeFillWidth;
-
-  flags.setColor(SkColorSetA(kStrokeFillColor, kStrokeFillOpacity));
-  canvas.DrawRect(gfx::RectF(x_fill, y, kStrokeFillWidth, height), flags);
-
-  flags.setColor(SkColorSetA(kStrokeOutlineColor, kStrokeOutlineOpacity));
-  canvas.DrawRect(gfx::RectF(x_outline_left, y, kStrokeOutlineWidth, height),
-                  flags);
-  canvas.DrawRect(gfx::RectF(x_outline_right, y, kStrokeOutlineWidth, height),
-                  flags);
-}
-
-void ResultLayer::DrawHorizontalBar(gfx::Canvas& canvas,
-                                    float x,
-                                    float y,
-                                    float width,
-                                    cc::PaintFlags& flags) {
-  const float y_fill = y - kStrokeFillWidth / 2;
-  const float y_outline_left = y_fill - kStrokeOutlineWidth;
-  const float y_outline_right = y_fill + kStrokeFillWidth;
-
-  flags.setColor(SkColorSetA(kStrokeFillColor, kStrokeFillOpacity));
-  canvas.DrawRect(gfx::RectF(x, y_fill, width, kStrokeFillWidth), flags);
-
-  flags.setColor(SkColorSetA(kStrokeOutlineColor, kStrokeOutlineOpacity));
-  canvas.DrawRect(gfx::RectF(x, y_outline_left, width, kStrokeOutlineWidth),
-                  flags);
-  canvas.DrawRect(gfx::RectF(x, y_outline_right, width, kStrokeOutlineWidth),
-                  flags);
-}
-
-}  // namespace
-
-HighlighterResultView::HighlighterResultView() = default;
-
-HighlighterResultView::~HighlighterResultView() = default;
-
-// static
-views::UniqueWidgetPtr HighlighterResultView::Create(
-    aura::Window* root_window) {
-  views::Widget::InitParams params;
-  params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
-  params.name = "HighlighterResult";
-  params.accept_events = false;
-  params.activatable = views::Widget::InitParams::Activatable::kNo;
-  params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
-  params.parent =
-      Shell::GetContainer(root_window, kShellWindowId_OverlayContainer);
-  params.layer_type = ui::LAYER_SOLID_COLOR;
-
-  auto widget = views::UniqueWidgetPtr(
-      std::make_unique<views::Widget>(std::move(params)));
-  widget->SetContentsView(std::make_unique<HighlighterResultView>());
-  widget->SetFullscreen(true);
-  widget->Show();
-  return widget;
-}
-
-void HighlighterResultView::Animate(const gfx::RectF& bounds,
-                                    HighlighterGestureType gesture_type,
-                                    base::OnceClosure done) {
-  ui::Layer* layer = GetWidget()->GetLayer();
-
-  base::TimeDelta delay;
-  base::TimeDelta duration;
-
-  if (gesture_type == HighlighterGestureType::kHorizontalStroke) {
-    // The original stroke is fading out in place.
-    // Fade in a solid transparent rectangle.
-    result_layer_ = std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR);
-    result_layer_->SetName("HighlighterResultView:SOLID_LAYER");
-    result_layer_->SetBounds(gfx::ToEnclosingRect(bounds));
-    result_layer_->SetFillsBoundsOpaquely(false);
-    result_layer_->SetMasksToBounds(false);
-    result_layer_->SetColor(fast_ink::FastInkPoints::kDefaultColor);
-
-    layer->Add(result_layer_.get());
-
-    delay = base::Milliseconds(kResultInPlaceFadeinDelayMs);
-    duration = base::Milliseconds(kResultInPlaceFadeinDurationMs);
-  } else {
-    DCHECK(gesture_type == HighlighterGestureType::kClosedShape);
-    // The original stroke is fading out and inflating.
-    // Fade in the deflating lens overlay.
-    result_layer_ = std::make_unique<ResultLayer>(gfx::ToEnclosingRect(bounds));
-    layer->Add(result_layer_.get());
-
-    gfx::Transform transform;
-    const gfx::PointF pivot = bounds.CenterPoint();
-    transform.Translate(pivot.x() * (1 - kInitialScale),
-                        pivot.y() * (1 - kInitialScale));
-    transform.Scale(kInitialScale, kInitialScale);
-    layer->SetTransform(transform);
-
-    delay = base::Milliseconds(kResultFadeinDelayMs);
-    duration = base::Milliseconds(kResultFadeinDurationMs);
-  }
-
-  layer->SetOpacity(0);
-
-  animation_timer_ = std::make_unique<base::OneShotTimer>();
-  animation_timer_->Start(
-      FROM_HERE, delay,
-      base::BindOnce(&HighlighterResultView::FadeIn, base::Unretained(this),
-                     duration, std::move(done)));
-}
-
-void HighlighterResultView::FadeIn(const base::TimeDelta& duration,
-                                   base::OnceClosure done) {
-  ui::Layer* layer = GetWidget()->GetLayer();
-
-  {
-    ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
-    settings.SetTransitionDuration(duration);
-    settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN);
-    layer->SetOpacity(1);
-
-    gfx::Transform transform;
-    transform.Scale(1, 1);
-    transform.Translate(0, 0);
-    layer->SetTransform(transform);
-  }
-
-  animation_timer_ = std::make_unique<base::OneShotTimer>();
-  animation_timer_->Start(
-      FROM_HERE, duration + base::Milliseconds(kResultFadeoutDelayMs),
-      base::BindOnce(&HighlighterResultView::FadeOut, base::Unretained(this),
-                     std::move(done)));
-}
-
-void HighlighterResultView::FadeOut(base::OnceClosure done) {
-  ui::Layer* layer = GetWidget()->GetLayer();
-
-  base::TimeDelta duration = base::Milliseconds(kResultFadeoutDurationMs);
-
-  ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
-  settings.SetTransitionDuration(duration);
-  settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN);
-  layer->SetOpacity(0);
-
-  animation_timer_ = std::make_unique<base::OneShotTimer>();
-  animation_timer_->Start(FROM_HERE, duration, std::move(done));
-}
-
-}  // namespace ash
diff --git a/ash/highlighter/highlighter_result_view.h b/ash/highlighter/highlighter_result_view.h
deleted file mode 100644
index 4ca5158..0000000
--- a/ash/highlighter/highlighter_result_view.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_HIGHLIGHTER_HIGHLIGHTER_RESULT_VIEW_H_
-#define ASH_HIGHLIGHTER_HIGHLIGHTER_RESULT_VIEW_H_
-
-#include <memory>
-
-#include "base/time/time.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/unique_widget_ptr.h"
-
-namespace aura {
-class Window;
-}
-
-namespace base {
-class OneShotTimer;
-}
-
-namespace ui {
-class Layer;
-}
-
-namespace ash {
-
-enum class HighlighterGestureType;
-
-// HighlighterResultView displays an animated shape that represents
-// the result of the selection.
-class HighlighterResultView : public views::View {
- public:
-  HighlighterResultView();
-
-  HighlighterResultView(const HighlighterResultView&) = delete;
-  HighlighterResultView& operator=(const HighlighterResultView&) = delete;
-
-  ~HighlighterResultView() override;
-
-  static views::UniqueWidgetPtr Create(aura::Window* root_window);
-
-  void Animate(const gfx::RectF& bounds,
-               HighlighterGestureType gesture_type,
-               base::OnceClosure done);
-
- private:
-  void FadeIn(const base::TimeDelta& duration, base::OnceClosure done);
-  void FadeOut(base::OnceClosure done);
-
-  std::unique_ptr<ui::Layer> result_layer_;
-  std::unique_ptr<base::OneShotTimer> animation_timer_;
-};
-
-}  // namespace ash
-
-#endif  // ASH_HIGHLIGHTER_HIGHLIGHTER_RESULT_VIEW_H_
diff --git a/ash/highlighter/highlighter_view.cc b/ash/highlighter/highlighter_view.cc
deleted file mode 100644
index 58d983e4..0000000
--- a/ash/highlighter/highlighter_view.cc
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/highlighter/highlighter_view.h"
-
-#include <memory>
-
-#include "ash/highlighter/highlighter_gesture_util.h"
-#include "base/functional/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/timer/timer.h"
-#include "base/trace_event/trace_event.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/core/SkPathUtils.h"
-#include "third_party/skia/include/core/SkTypes.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/events/base_event_utils.h"
-#include "ui/gfx/canvas.h"
-#include "ui/views/widget/widget.h"
-
-namespace ash {
-namespace {
-
-// Variables for rendering the highlighter. Sizes in DIP.
-constexpr float kPenTipWidth = 4;
-constexpr float kPenTipHeight = 14;
-constexpr int kOutsetForAntialiasing = 1;
-
-constexpr float kStrokeScale = 1.2;
-
-constexpr int kStrokeFadeoutDelayMs = 100;
-constexpr int kStrokeFadeoutDurationMs = 500;
-constexpr int kStrokeScaleDurationMs = 300;
-
-gfx::Rect InflateDamageRect(const gfx::Rect& r) {
-  gfx::Rect inflated = r;
-  inflated.Inset(gfx::Insets::VH(
-      -kOutsetForAntialiasing - static_cast<int>(kPenTipHeight / 2 + 1),
-      -kOutsetForAntialiasing - static_cast<int>(kPenTipWidth / 2 + 1)));
-  return inflated;
-}
-
-// A highlighter segment is a parallelogram with two vertical sides.
-// |p1| and |p2| are the center points of the vertical sides.
-// |height| is the height of a vertical side.
-void DrawSegment(gfx::Canvas& canvas,
-                 const gfx::PointF& p1,
-                 const gfx::PointF& p2,
-                 int height,
-                 const cc::PaintFlags& flags,
-                 float stroke_width) {
-  const float y_offset = height / 2;
-  SkPath frame;
-  frame.moveTo(p1.x(), p1.y() - y_offset);
-  frame.lineTo(p2.x(), p2.y() - y_offset);
-  frame.lineTo(p2.x(), p2.y() + y_offset);
-  frame.lineTo(p1.x(), p1.y() + y_offset);
-  frame.close();
-
-  SkPaint paint;
-  paint.setStroke(true);
-  paint.setStrokeWidth(stroke_width);
-  paint.setStrokeJoin(SkPaint::kRound_Join);
-  paint.setStrokeCap(SkPaint::kRound_Cap);
-
-  SkPath fill;
-  skpathutils::FillPathWithPaint(frame, paint, &fill);
-  fill.addPath(frame);
-  canvas.DrawPath(fill, flags);
-}
-
-}  // namespace
-
-const gfx::SizeF HighlighterView::kPenTipSize(kPenTipWidth, kPenTipHeight);
-
-HighlighterView::HighlighterView(base::TimeDelta presentation_delay)
-    : points_(base::TimeDelta()),
-      predicted_points_(base::TimeDelta()),
-      presentation_delay_(presentation_delay) {}
-
-HighlighterView::~HighlighterView() = default;
-
-// static
-views::UniqueWidgetPtr HighlighterView::Create(
-    const base::TimeDelta presentation_delay,
-    aura::Window* container) {
-  return fast_ink::FastInkView::CreateWidgetWithContents(
-      base::WrapUnique(new HighlighterView(presentation_delay)), container);
-}
-
-void HighlighterView::ChangeColor(SkColor color) {
-  pen_color_ = color;
-  if (!points_.IsEmpty())
-    AddGap();
-}
-
-void HighlighterView::AddNewPoint(const gfx::PointF& point,
-                                  const base::TimeTicks& time) {
-  TRACE_EVENT1("ui", "HighlighterView::AddNewPoint", "point", point.ToString());
-
-  TRACE_COUNTER1(
-      "ui", "HighlighterPredictionError",
-      predicted_points_.GetNumberOfPoints()
-          ? std::round(
-                (point - predicted_points_.GetOldest().location).Length())
-          : 0);
-  // The new segment needs to be drawn.
-  if (!points_.IsEmpty()) {
-    highlighter_damage_rect_.Union(InflateDamageRect(gfx::ToEnclosingRect(
-        gfx::BoundingRect(points_.GetNewest().location, point))));
-  }
-
-  // Previous prediction needs to be erased.
-  if (!predicted_points_.IsEmpty()) {
-    highlighter_damage_rect_.Union(
-        InflateDamageRect(predicted_points_.GetBoundingBox()));
-  }
-
-  points_.AddPoint(point, time, pen_color_);
-
-  base::TimeTicks current_time = ui::EventTimeForNow();
-  gfx::Rect screen_bounds = GetWidget()->GetNativeView()->GetBoundsInScreen();
-  predicted_points_.Predict(points_, current_time, presentation_delay_,
-                            screen_bounds.size());
-
-  // New prediction needs to be drawn.
-  if (!predicted_points_.IsEmpty()) {
-    highlighter_damage_rect_.Union(
-        InflateDamageRect(predicted_points_.GetBoundingBox()));
-  }
-
-  ScheduleUpdateBuffer();
-}
-
-void HighlighterView::AddGap() {
-  points_.AddGap();
-}
-
-void HighlighterView::Animate(const gfx::PointF& pivot,
-                              HighlighterGestureType gesture_type,
-                              base::OnceClosure done) {
-  animation_timer_ = std::make_unique<base::OneShotTimer>();
-  animation_timer_->Start(
-      FROM_HERE, base::Milliseconds(kStrokeFadeoutDelayMs),
-      base::BindOnce(&HighlighterView::FadeOut, base::Unretained(this), pivot,
-                     gesture_type, std::move(done)));
-}
-
-void HighlighterView::UndoLastStroke() {
-  if (points_.IsEmpty())
-    return;
-
-  // Previous prediction needs to be erased.
-  if (!predicted_points_.IsEmpty()) {
-    highlighter_damage_rect_.Union(
-        InflateDamageRect(predicted_points_.GetBoundingBox()));
-    predicted_points_.Clear();
-  }
-
-  const gfx::Rect bounding_box = points_.UndoLastStroke();
-  // Ensure deleting the points also erases them by expanding the damage
-  // rectangle.
-  highlighter_damage_rect_.Union(InflateDamageRect(bounding_box));
-  ScheduleUpdateBuffer();
-}
-
-void HighlighterView::FadeOut(const gfx::PointF& pivot,
-                              HighlighterGestureType gesture_type,
-                              base::OnceClosure done) {
-  ui::Layer* layer = GetWidget()->GetLayer();
-
-  base::TimeDelta duration = base::Milliseconds(kStrokeFadeoutDurationMs);
-
-  {
-    ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
-    settings.SetTransitionDuration(duration);
-    settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN);
-
-    layer->SetOpacity(0);
-  }
-
-  if (gesture_type != HighlighterGestureType::kHorizontalStroke) {
-    ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
-    settings.SetTransitionDuration(base::Milliseconds(kStrokeScaleDurationMs));
-    settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN);
-
-    const float scale = gesture_type == HighlighterGestureType::kClosedShape
-                            ? kStrokeScale
-                            : (1 / kStrokeScale);
-
-    gfx::Transform transform;
-    transform.Translate(pivot.x() * (1 - scale), pivot.y() * (1 - scale));
-    transform.Scale(scale, scale);
-
-    layer->SetTransform(transform);
-  }
-
-  animation_timer_ = std::make_unique<base::OneShotTimer>();
-  animation_timer_->Start(FROM_HERE, duration, std::move(done));
-}
-
-void HighlighterView::ScheduleUpdateBuffer() {
-  if (pending_update_buffer_)
-    return;
-
-  pending_update_buffer_ = true;
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE, base::BindOnce(&HighlighterView::UpdateBuffer,
-                                weak_ptr_factory_.GetWeakPtr()));
-}
-
-void HighlighterView::UpdateBuffer() {
-  TRACE_EVENT1("ui", "FastInkView::UpdateBuffer", "damage",
-               highlighter_damage_rect_.ToString());
-
-  DCHECK(pending_update_buffer_);
-  pending_update_buffer_ = false;
-
-  {
-    ScopedPaint paint(this, highlighter_damage_rect_);
-
-    Draw(paint.canvas());
-  }
-
-  gfx::Rect screen_bounds = GetWidget()->GetNativeView()->GetBoundsInScreen();
-  UpdateSurface(screen_bounds, highlighter_damage_rect_, /*auto_refresh=*/true);
-  highlighter_damage_rect_ = gfx::Rect();
-}
-
-void HighlighterView::Draw(gfx::Canvas& canvas) {
-  const int num_points =
-      points_.GetNumberOfPoints() + predicted_points_.GetNumberOfPoints();
-  if (num_points < 2)
-    return;
-
-  gfx::Rect clip_rect;
-  if (!canvas.GetClipBounds(&clip_rect))
-    return;
-
-  cc::PaintFlags flags;
-  flags.setStyle(cc::PaintFlags::kFill_Style);
-  flags.setAntiAlias(true);
-  flags.setBlendMode(SkBlendMode::kSrc);
-
-  // Decrease the segment height by the outline stroke width,
-  // so that the vertical cross-section of the drawn segment
-  // is exactly kPenTipHeight.
-  const int height = kPenTipHeight - kPenTipWidth;
-
-  fast_ink::FastInkPoints::FastInkPoint previous_point;
-
-  for (int i = 0; i < num_points; ++i) {
-    fast_ink::FastInkPoints::FastInkPoint current_point;
-    if (i < points_.GetNumberOfPoints()) {
-      current_point = points_.points()[i];
-    } else {
-      current_point =
-          predicted_points_.points()[i - points_.GetNumberOfPoints()];
-    }
-
-    if (i != 0 && !previous_point.gap_after) {
-      gfx::Rect damage_rect = InflateDamageRect(gfx::ToEnclosingRect(
-          gfx::BoundingRect(previous_point.location, current_point.location)));
-      // Only draw the segment if it is touching the clip rect.
-      if (clip_rect.Intersects(damage_rect)) {
-        flags.setColor(current_point.color);
-        DrawSegment(canvas, previous_point.location, current_point.location,
-                    height, flags, kPenTipWidth);
-      }
-    }
-
-    previous_point = current_point;
-  }
-}
-
-}  // namespace ash
diff --git a/ash/highlighter/highlighter_view.h b/ash/highlighter/highlighter_view.h
deleted file mode 100644
index 965db1ce..0000000
--- a/ash/highlighter/highlighter_view.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_HIGHLIGHTER_HIGHLIGHTER_VIEW_H_
-#define ASH_HIGHLIGHTER_HIGHLIGHTER_VIEW_H_
-
-#include <vector>
-
-#include "ash/fast_ink/fast_ink_points.h"
-#include "ash/fast_ink/fast_ink_view.h"
-#include "base/time/time.h"
-#include "ui/views/widget/unique_widget_ptr.h"
-
-namespace aura {
-class Window;
-}
-
-namespace base {
-class OneShotTimer;
-}
-
-namespace gfx {
-class PointF;
-}
-
-namespace ash {
-
-enum class HighlighterGestureType;
-
-// HighlighterView displays the highlighter palette tool. It draws the
-// highlighter stroke which consists of a series of thick lines connecting
-// touch points.
-class HighlighterView : public fast_ink::FastInkView {
- public:
-  static const gfx::SizeF kPenTipSize;
-
-  HighlighterView(const HighlighterView&) = delete;
-  HighlighterView& operator=(const HighlighterView&) = delete;
-
-  ~HighlighterView() override;
-
-  // Function to create a container Widget, initialize |highlighter_view| and
-  // pass ownership as the contents view to the Widget.
-  static views::UniqueWidgetPtr Create(const base::TimeDelta presentation_delay,
-                                       aura::Window* container);
-
-  const fast_ink::FastInkPoints& points() const { return points_; }
-  bool animating() const { return animation_timer_.get(); }
-
-  void ChangeColor(SkColor color);
-  void AddNewPoint(const gfx::PointF& new_point, const base::TimeTicks& time);
-  void AddGap();
-  void Animate(const gfx::PointF& pivot,
-               HighlighterGestureType gesture_type,
-               base::OnceClosure done);
-  // Deletes the last stroke.
-  void UndoLastStroke();
-
- private:
-  friend class HighlighterControllerTestApi;
-  friend class MarkerControllerTestApi;
-
-  explicit HighlighterView(const base::TimeDelta presentation_delay);
-
-  void FadeOut(const gfx::PointF& pivot,
-               HighlighterGestureType gesture_type,
-               base::OnceClosure done);
-  void ScheduleUpdateBuffer();
-  void UpdateBuffer();
-  void Draw(gfx::Canvas& canvas);
-
-  fast_ink::FastInkPoints points_;
-  fast_ink::FastInkPoints predicted_points_;
-  const base::TimeDelta presentation_delay_;
-  std::unique_ptr<base::OneShotTimer> animation_timer_;
-  gfx::Rect highlighter_damage_rect_;
-  bool pending_update_buffer_ = false;
-  SkColor pen_color_ = fast_ink::FastInkPoints::kDefaultColor;
-
-  base::WeakPtrFactory<HighlighterView> weak_ptr_factory_{this};
-};
-
-}  // namespace ash
-
-#endif  // ASH_HIGHLIGHTER_HIGHLIGHTER_VIEW_H_
diff --git a/ash/shell.cc b/ash/shell.cc
index 7462e46..195dbbfa 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -74,7 +74,6 @@
 #include "ash/frame_throttler/frame_throttling_controller.h"
 #include "ash/glanceables/glanceables_controller.h"
 #include "ash/glanceables/glanceables_delegate.h"
-#include "ash/highlighter/highlighter_controller.h"
 #include "ash/host/ash_window_tree_host_init_params.h"
 #include "ash/hud_display/hud_display.h"
 #include "ash/ime/ime_controller_impl.h"
@@ -131,6 +130,8 @@
 #include "ash/system/geolocation/geolocation_controller.h"
 #include "ash/system/human_presence/human_presence_orientation_controller.h"
 #include "ash/system/human_presence/snooping_protection_controller.h"
+#include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
+#include "ash/system/input_device_settings/input_device_tracker.h"
 #include "ash/system/keyboard_brightness/keyboard_backlight_color_controller.h"
 #include "ash/system/keyboard_brightness/keyboard_brightness_controller.h"
 #include "ash/system/keyboard_brightness_control_delegate.h"
@@ -736,6 +737,8 @@
   wm_mode_controller_.reset();
 
   event_rewriter_controller_.reset();
+  input_device_tracker_.reset();
+  input_device_settings_controller_.reset();
 
   screen_orientation_controller_.reset();
   screen_layout_observer_.reset();
@@ -886,7 +889,6 @@
   modality_filter_.reset();
 
   touch_transformer_controller_.reset();
-  highlighter_controller_.reset();
   key_accessibility_enabler_.reset();
 
   display_speaker_controller_.reset();
@@ -1233,6 +1235,11 @@
   window_modality_controller_ =
       std::make_unique<::wm::WindowModalityController>(this, env);
 
+  // The `InputDeviceSettingsController` is a dependency of the
+  // `EventRewriterController` so it must be initialized first.
+  input_device_settings_controller_ =
+      std::make_unique<InputDeviceSettingsControllerImpl>();
+  input_device_tracker_ = std::make_unique<InputDeviceTracker>();
   event_rewriter_controller_ = std::make_unique<EventRewriterControllerImpl>();
 
   env_filter_ = std::make_unique<::wm::CompoundEventFilter>();
@@ -1386,7 +1393,6 @@
   laser_pointer_controller_ = std::make_unique<LaserPointerController>();
   partial_magnifier_controller_ =
       std::make_unique<PartialMagnifierController>();
-  highlighter_controller_ = std::make_unique<HighlighterController>();
   if (::features::IsTouchTextEditingRedesignEnabled()) {
     touch_selection_magnifier_runner_ash_ =
         std::make_unique<TouchSelectionMagnifierRunnerAsh>();
diff --git a/ash/shell.h b/ash/shell.h
index 60dbd7c..bcd36da 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -16,6 +16,8 @@
 #include "ash/public/cpp/session/session_observer.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/system_sounds_delegate.h"
+#include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
+#include "ash/system/input_device_settings/input_device_tracker.h"
 #include "ash/wm/system_modal_container_event_filter_delegate.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
@@ -143,7 +145,6 @@
 class GeolocationController;
 class GlanceablesController;
 class ColorEnhancementController;
-class HighlighterController;
 class HoldingSpaceController;
 class HumanPresenceOrientationController;
 class ImeControllerImpl;
@@ -476,6 +477,10 @@
   EventRewriterControllerImpl* event_rewriter_controller() {
     return event_rewriter_controller_.get();
   }
+  InputDeviceSettingsControllerImpl* input_device_settings_controller() {
+    return input_device_settings_controller_.get();
+  }
+
   EventClientImpl* event_client() { return event_client_.get(); }
   EventTransformationHandler* event_transformation_handler() {
     return event_transformation_handler_.get();
@@ -503,9 +508,6 @@
   GlanceablesController* glanceables_controller() {
     return glanceables_controller_.get();
   }
-  HighlighterController* highlighter_controller() {
-    return highlighter_controller_.get();
-  }
   ColorEnhancementController* color_enhancement_controller() {
     return color_enhancement_controller_.get();
   }
@@ -850,6 +852,10 @@
   std::unique_ptr<::wm::CompoundEventFilter> env_filter_;
 
   std::unique_ptr<EventRewriterControllerImpl> event_rewriter_controller_;
+  std::unique_ptr<InputDeviceSettingsControllerImpl>
+      input_device_settings_controller_;
+
+  std::unique_ptr<InputDeviceTracker> input_device_tracker_;
 
   std::unique_ptr<UserMetricsRecorder> user_metrics_recorder_;
   std::unique_ptr<WindowPositioner> window_positioner_;
@@ -1058,7 +1064,6 @@
   std::unique_ptr<ui::EventHandler> speech_feedback_handler_;
   std::unique_ptr<LaserPointerController> laser_pointer_controller_;
   std::unique_ptr<PartialMagnifierController> partial_magnifier_controller_;
-  std::unique_ptr<HighlighterController> highlighter_controller_;
 
   std::unique_ptr<DockedMagnifierController> docked_magnifier_controller_;
 
diff --git a/ash/system/holding_space/holding_space_tray_unittest.cc b/ash/system/holding_space/holding_space_tray_unittest.cc
index 5e1f61e..e93d166 100644
--- a/ash/system/holding_space/holding_space_tray_unittest.cc
+++ b/ash/system/holding_space/holding_space_tray_unittest.cc
@@ -54,6 +54,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/canvas_painter.h"
 #include "ui/compositor/layer.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/compositor/test/layer_animation_stopped_waiter.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/gfx/color_utils.h"
@@ -2003,9 +2004,12 @@
   EXPECT_FALSE(test_api()->IsShowing());
 }
 
-// TODO(crbug.com/1208501): Fix flakes and re-enable.
 // Verifies that the holding space tray animates in and out as expected.
-TEST_F(HoldingSpaceTrayTest, DISABLED_EnterAndExitAnimations) {
+TEST_F(HoldingSpaceTrayTest, EnterAndExitAnimations) {
+  // Ensure animations are run.
+  ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
+      ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
+
   // Prior to session start, the tray should not be showing.
   EXPECT_FALSE(test_api()->IsShowingInShelf());
 
@@ -2071,7 +2075,7 @@
   // Lock the screen. The tray should animate out.
   auto* session_controller =
       ash_test_helper()->test_session_controller_client();
-  session_controller->LockScreen();
+  session_controller->SetSessionState(session_manager::SessionState::LOCKED);
   ViewVisibilityChangedWaiter().Wait(tray);
   EXPECT_FALSE(test_api()->IsShowingInShelf());
 
diff --git a/ash/system/input_device_settings/fake_input_device_tracker.cc b/ash/system/input_device_settings/fake_input_device_tracker.cc
deleted file mode 100644
index 079fc3f..0000000
--- a/ash/system/input_device_settings/fake_input_device_tracker.cc
+++ /dev/null
@@ -1,29 +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 "ash/system/input_device_settings/fake_input_device_tracker.h"
-
-#include "base/containers/contains.h"
-
-namespace ash {
-
-FakeInputDeviceTracker::FakeInputDeviceTracker() = default;
-FakeInputDeviceTracker::~FakeInputDeviceTracker() = default;
-
-void FakeInputDeviceTracker::Init(PrefService* pref_service) {}
-
-void FakeInputDeviceTracker::RecordDeviceConnected(
-    InputDeviceCategory category,
-    const base::StringPiece& device_key) {
-  tracker_data_.emplace_back(category, device_key);
-}
-
-bool FakeInputDeviceTracker::WasDeviceRecorded(
-    InputDeviceCategory category,
-    const base::StringPiece& device_key) {
-  return base::Contains(tracker_data_,
-                        InputDeviceTrackerData(category, device_key));
-}
-
-}  // namespace ash
diff --git a/ash/system/input_device_settings/fake_input_device_tracker.h b/ash/system/input_device_settings/fake_input_device_tracker.h
deleted file mode 100644
index d28c3fd..0000000
--- a/ash/system/input_device_settings/fake_input_device_tracker.h
+++ /dev/null
@@ -1,51 +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 ASH_SYSTEM_INPUT_DEVICE_SETTINGS_FAKE_INPUT_DEVICE_TRACKER_H_
-#define ASH_SYSTEM_INPUT_DEVICE_SETTINGS_FAKE_INPUT_DEVICE_TRACKER_H_
-
-#include <vector>
-
-#include "ash/system/input_device_settings/input_device_tracker.h"
-
-namespace ash {
-
-// Data received by the InputDeviceTracker, used only for unit testing.
-struct InputDeviceTrackerData {
-  InputDeviceTrackerData(InputDeviceCategory category,
-                         const base::StringPiece& device_key)
-      : category(category), device_key(device_key) {}
-
-  bool operator==(const InputDeviceTrackerData& other) const {
-    return category == other.category && device_key == other.device_key;
-  }
-
-  InputDeviceCategory category;
-  std::string device_key;
-};
-
-// Fake implementation of InputDeviceTracker to be used in unit tests.
-class FakeInputDeviceTracker : public InputDeviceTracker {
- public:
-  FakeInputDeviceTracker();
-  FakeInputDeviceTracker(const FakeInputDeviceTracker&) = delete;
-  FakeInputDeviceTracker& operator=(const FakeInputDeviceTracker&) = delete;
-  ~FakeInputDeviceTracker() override;
-
-  // InputDeviceTracker:
-  void Init(PrefService* pref_service) override;
-  void RecordDeviceConnected(InputDeviceCategory category,
-                             const base::StringPiece& device_key) override;
-
-  // Checks whether a call with matching args was made to RecordDeviceConnected.
-  bool WasDeviceRecorded(InputDeviceCategory category,
-                         const base::StringPiece& device_key);
-
- private:
-  std::vector<InputDeviceTrackerData> tracker_data_;
-};
-
-}  // namespace ash
-
-#endif  // ASH_SYSTEM_INPUT_DEVICE_SETTINGS_FAKE_INPUT_DEVICE_TRACKER_H_
diff --git a/ash/system/input_device_settings/input_device_pref_manager_impl.cc b/ash/system/input_device_settings/input_device_pref_manager_impl.cc
index 5b3f880..f2221638 100644
--- a/ash/system/input_device_settings/input_device_pref_manager_impl.cc
+++ b/ash/system/input_device_settings/input_device_pref_manager_impl.cc
@@ -3,14 +3,38 @@
 // found in the LICENSE file.
 
 #include "ash/system/input_device_settings/input_device_pref_manager_impl.h"
+
+#include <cstdint>
+
 #include "ash/public/mojom/input_device_settings.mojom.h"
 #include "base/notreached.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 
 namespace ash {
 
+namespace {
+std::string HexEncode(uint16_t v) {
+  // Load the bytes into the bytes array in reverse order as hex number should
+  // be read from left to right.
+  uint8_t bytes[sizeof(uint16_t)];
+  bytes[1] = v & 0xFF;
+  bytes[0] = v >> 8;
+  return base::ToLowerASCII(base::HexEncode(bytes));
+}
+}  // namespace
+
 InputDevicePrefManagerImpl::InputDevicePrefManagerImpl() = default;
 InputDevicePrefManagerImpl::~InputDevicePrefManagerImpl() = default;
 
+// static
+std::string InputDevicePrefManagerImpl::BuildDeviceKey(
+    const ui::InputDevice& device) {
+  return base::StrCat(
+      {HexEncode(device.vendor_id), ":", HexEncode(device.product_id)});
+}
+
 // TODO(dpad): Implement retrieval of settings when keyboard is initially
 // connected.
 void InputDevicePrefManagerImpl::InitializeKeyboardSettings(
diff --git a/ash/system/input_device_settings/input_device_pref_manager_impl.h b/ash/system/input_device_settings/input_device_pref_manager_impl.h
index 9ff326e..37bb24e2 100644
--- a/ash/system/input_device_settings/input_device_pref_manager_impl.h
+++ b/ash/system/input_device_settings/input_device_pref_manager_impl.h
@@ -8,6 +8,7 @@
 #include "ash/ash_export.h"
 #include "ash/public/mojom/input_device_settings.mojom.h"
 #include "ash/system/input_device_settings/input_device_pref_manager.h"
+#include "ui/events/devices/input_device.h"
 
 namespace ash {
 
@@ -19,6 +20,9 @@
       delete;
   ~InputDevicePrefManagerImpl() override;
 
+  // Builds `device_key` for use in storing device settings in prefs.
+  static std::string BuildDeviceKey(const ui::InputDevice& device);
+
   // InputDevicePrefManager:
   void InitializeKeyboardSettings(mojom::Keyboard* keyboard) override;
 };
diff --git a/ash/system/input_device_settings/input_device_pref_manager_unittest.cc b/ash/system/input_device_settings/input_device_pref_manager_unittest.cc
index 0a18e85..f5cf6c0 100644
--- a/ash/system/input_device_settings/input_device_pref_manager_unittest.cc
+++ b/ash/system/input_device_settings/input_device_pref_manager_unittest.cc
@@ -4,7 +4,10 @@
 
 #include "ash/system/input_device_settings/input_device_pref_manager_impl.h"
 
+#include <cstdint>
+
 #include "ash/test/ash_test_base.h"
+#include "ui/events/devices/input_device.h"
 
 namespace ash {
 
@@ -35,4 +38,28 @@
   EXPECT_NE(controller_.get(), nullptr);
 }
 
+class DeviceKeyTest : public testing::TestWithParam<
+                          std::tuple<uint16_t, uint16_t, std::string>> {};
+
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    DeviceKeyTest,
+    testing::ValuesIn(std::vector<std::tuple<uint16_t, uint16_t, std::string>>{
+        {0x1234, 0x4321, "1234:4321"},
+        {0xaaaa, 0xbbbb, "aaaa:bbbb"},
+        {0xaa54, 0xffa1, "aa54:ffa1"},
+        {0x1a2b, 0x3c4d, "1a2b:3c4d"},
+        {0x5e6f, 0x7890, "5e6f:7890"},
+        {0x0001, 0x0001, "0001:0001"},
+        {0x1000, 0x1000, "1000:1000"}}));
+
+TEST_P(DeviceKeyTest, BuildDeviceKey) {
+  std::string expected_key;
+  ui::InputDevice device;
+  std::tie(device.vendor_id, device.product_id, expected_key) = GetParam();
+
+  auto key = InputDevicePrefManagerImpl::BuildDeviceKey(device);
+  EXPECT_EQ(expected_key, key);
+}
+
 }  // namespace ash
diff --git a/ash/system/input_device_settings/input_device_settings_controller_impl.cc b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
index 216ead5..9f6e882 100644
--- a/ash/system/input_device_settings/input_device_settings_controller_impl.cc
+++ b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
@@ -25,6 +25,8 @@
   mojom::KeyboardPtr mojom_keyboard = mojom::Keyboard::New();
   mojom_keyboard->id = keyboard.id;
   mojom_keyboard->name = keyboard.name;
+  mojom_keyboard->device_key =
+      InputDevicePrefManagerImpl::BuildDeviceKey(keyboard);
   return mojom_keyboard;
 }
 }  // namespace
diff --git a/ash/system/input_device_settings/input_device_settings_controller_unittest.cc b/ash/system/input_device_settings/input_device_settings_controller_unittest.cc
index 3ba142f..d2d3c0e 100644
--- a/ash/system/input_device_settings/input_device_settings_controller_unittest.cc
+++ b/ash/system/input_device_settings/input_device_settings_controller_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "ash/public/cpp/input_device_settings_controller.h"
 #include "ash/public/mojom/input_device_settings.mojom.h"
+#include "ash/shell.h"
 #include "ash/system/input_device_settings/input_device_pref_manager.h"
 #include "ash/test/ash_test_base.h"
 #include "base/ranges/algorithm.h"
@@ -58,7 +59,7 @@
   uint32_t num_keyboards_connected_;
 };
 
-class InputDeviceSettingsControllerTest : public AshTestBase {
+class InputDeviceSettingsControllerTest : public testing::Test {
  public:
   InputDeviceSettingsControllerTest() = default;
   InputDeviceSettingsControllerTest(const InputDeviceSettingsControllerTest&) =
@@ -69,8 +70,6 @@
 
   // testing::Test:
   void SetUp() override {
-    AshTestBase::SetUp();
-
     observer_ = std::make_unique<FakeInputDeviceSettingsControllerObserver>();
 
     std::unique_ptr<FakeInputDevicePrefManager> pref_manager =
@@ -91,7 +90,6 @@
 
     pref_manager_ = nullptr;
     controller_.reset();
-    AshTestBase::TearDown();
   }
 
  protected:
diff --git a/ash/system/input_device_settings/input_device_tracker.cc b/ash/system/input_device_settings/input_device_tracker.cc
new file mode 100644
index 0000000..12ec4c46
--- /dev/null
+++ b/ash/system/input_device_settings/input_device_tracker.cc
@@ -0,0 +1,118 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/input_device_settings/input_device_tracker.h"
+
+#include <memory>
+#include <string>
+
+#include "ash/constants/ash_features.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
+#include "ash/system/input_device_settings/input_device_settings_pref_names.h"
+#include "base/containers/contains.h"
+#include "base/strings/string_piece_forward.h"
+#include "components/prefs/pref_member.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+
+namespace ash {
+
+InputDeviceTracker::InputDeviceTracker() {
+  if (!features::IsInputDeviceSettingsSplitEnabled()) {
+    Shell::Get()->session_controller()->AddObserver(this);
+    Shell::Get()->input_device_settings_controller()->AddObserver(this);
+  }
+}
+
+InputDeviceTracker::~InputDeviceTracker() {
+  if (!features::IsInputDeviceSettingsSplitEnabled()) {
+    Shell::Get()->session_controller()->RemoveObserver(this);
+    Shell::Get()->input_device_settings_controller()->RemoveObserver(this);
+  }
+}
+
+void InputDeviceTracker::RegisterProfilePrefs(
+    PrefRegistrySimple* pref_registry) {
+  pref_registry->RegisterListPref(prefs::kMouseObservedDevicesPref);
+  pref_registry->RegisterListPref(prefs::kKeyboardObservedDevicesPref);
+  pref_registry->RegisterListPref(prefs::kTouchpadObservedDevicesPref);
+  pref_registry->RegisterListPref(prefs::kPointingStickObservedDevicesPref);
+}
+
+void InputDeviceTracker::ResetPrefMembers() {
+  mouse_observed_devices_ = std::make_unique<StringListPrefMember>();
+  touchpad_observed_devices_ = std::make_unique<StringListPrefMember>();
+  keyboard_observed_devices_ = std::make_unique<StringListPrefMember>();
+  pointing_stick_observed_devices_ = std::make_unique<StringListPrefMember>();
+}
+
+void InputDeviceTracker::OnKeyboardConnected(const mojom::Keyboard& keyboard) {
+  RecordDeviceConnected(InputDeviceCategory::kKeyboard, keyboard.device_key);
+}
+
+void InputDeviceTracker::OnActiveUserPrefServiceChanged(
+    PrefService* pref_service) {
+  // When the user's `pref_service` changes, we need to re-initialize our
+  // `StringListPrefMember`s and record that we have seen all currently
+  // connected devices.
+  Init(pref_service);
+  RecordConnectedDevices();
+}
+
+void InputDeviceTracker::RecordConnectedDevices() {
+  const auto keyboards =
+      Shell::Get()->input_device_settings_controller()->GetConnectedKeyboards();
+  for (const auto& keyboard : keyboards) {
+    OnKeyboardConnected(*keyboard);
+  }
+}
+
+void InputDeviceTracker::Init(PrefService* pref_service) {
+  ResetPrefMembers();
+
+  mouse_observed_devices_->Init(prefs::kMouseObservedDevicesPref, pref_service);
+  touchpad_observed_devices_->Init(prefs::kTouchpadObservedDevicesPref,
+                                   pref_service);
+  keyboard_observed_devices_->Init(prefs::kKeyboardObservedDevicesPref,
+                                   pref_service);
+  pointing_stick_observed_devices_->Init(
+      prefs::kPointingStickObservedDevicesPref, pref_service);
+}
+
+void InputDeviceTracker::RecordDeviceConnected(
+    InputDeviceCategory category,
+    const base::StringPiece& device_key) {
+  StringListPrefMember* observed_devices = nullptr;
+  switch (category) {
+    case InputDeviceCategory::kMouse:
+      observed_devices = mouse_observed_devices_.get();
+      break;
+    case InputDeviceCategory::kKeyboard:
+      observed_devices = keyboard_observed_devices_.get();
+      break;
+    case InputDeviceCategory::kPointingStick:
+      observed_devices = pointing_stick_observed_devices_.get();
+      break;
+    case InputDeviceCategory::kTouchpad:
+      observed_devices = touchpad_observed_devices_.get();
+      break;
+  }
+
+  // If `observed_devices` is null, that means we are not yet in a valid chrome
+  // session.
+  if (!observed_devices) {
+    return;
+  }
+
+  std::vector<std::string> previously_observed_devices =
+      observed_devices->GetValue();
+
+  if (!base::Contains(previously_observed_devices, device_key)) {
+    previously_observed_devices.emplace_back(device_key);
+    observed_devices->SetValue(previously_observed_devices);
+  }
+}
+
+}  // namespace ash
diff --git a/ash/system/input_device_settings/input_device_tracker.h b/ash/system/input_device_settings/input_device_tracker.h
index 8ba2ef3..dd5729cf 100644
--- a/ash/system/input_device_settings/input_device_tracker.h
+++ b/ash/system/input_device_settings/input_device_tracker.h
@@ -5,34 +5,59 @@
 #ifndef ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_TRACKER_H_
 #define ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_TRACKER_H_
 
-#include "base/strings/string_piece.h"
+#include <memory>
+
+#include "ash/ash_export.h"
+#include "ash/public/cpp/input_device_settings_controller.h"
+#include "ash/public/cpp/session/session_observer.h"
+#include "ash/public/mojom/input_device_settings.mojom-forward.h"
+#include "components/prefs/pref_member.h"
 
 class PrefService;
+class PrefRegistrySimple;
 
 namespace ash {
 
-// Used to denote the category of a given input device.
-enum class InputDeviceCategory {
-  kMouse,
-  kTouchpad,
-  kPointingStick,
-  kKeyboard,
-};
-
 // Store observed connected input devices in prefs to be used during the
 // transition period from global settings to per-device input settings.
 // TODO(dpad@): Remove once transitioned to per-device settings.
-class InputDeviceTracker {
+class ASH_EXPORT InputDeviceTracker
+    : public InputDeviceSettingsController::Observer,
+      public SessionObserver {
  public:
-  virtual ~InputDeviceTracker() = default;
+  // Used to denote the category of a given input device.
+  enum class InputDeviceCategory {
+    kMouse,
+    kTouchpad,
+    kPointingStick,
+    kKeyboard,
+  };
 
-  // Initializes the tracker to write updates to a new `PrefService`.
-  virtual void Init(PrefService* pref_service) = 0;
+  InputDeviceTracker();
+  InputDeviceTracker(const InputDeviceTracker&) = delete;
+  InputDeviceTracker& operator=(const InputDeviceTracker&) = delete;
+  ~InputDeviceTracker() override;
 
-  // Records that the given `device_key` has been seen in the correct
-  // `category`.
-  virtual void RecordDeviceConnected(InputDeviceCategory category,
-                                     const base::StringPiece& device_key) = 0;
+  static void RegisterProfilePrefs(PrefRegistrySimple* pref_registry);
+
+  // InputDeviceSettingsController::Observer:
+  void OnKeyboardConnected(const mojom::Keyboard& keyboard) override;
+
+  // SessionObserver:
+  void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
+
+ private:
+  void Init(PrefService* pref_service);
+  void RecordDeviceConnected(InputDeviceCategory category,
+                             const base::StringPiece& device_key);
+
+  void ResetPrefMembers();
+  void RecordConnectedDevices();
+
+  std::unique_ptr<StringListPrefMember> keyboard_observed_devices_;
+  std::unique_ptr<StringListPrefMember> mouse_observed_devices_;
+  std::unique_ptr<StringListPrefMember> touchpad_observed_devices_;
+  std::unique_ptr<StringListPrefMember> pointing_stick_observed_devices_;
 };
 
 }  // namespace ash
diff --git a/ash/system/input_device_settings/input_device_tracker_impl.cc b/ash/system/input_device_settings/input_device_tracker_impl.cc
deleted file mode 100644
index d730babf..0000000
--- a/ash/system/input_device_settings/input_device_tracker_impl.cc
+++ /dev/null
@@ -1,78 +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 "ash/system/input_device_settings/input_device_tracker_impl.h"
-
-#include <memory>
-#include <string>
-
-#include "ash/system/input_device_settings/input_device_settings_pref_names.h"
-#include "base/containers/contains.h"
-#include "base/strings/string_piece_forward.h"
-#include "components/prefs/pref_member.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-
-namespace ash {
-
-InputDeviceTrackerImpl::InputDeviceTrackerImpl() = default;
-InputDeviceTrackerImpl::~InputDeviceTrackerImpl() = default;
-
-void InputDeviceTrackerImpl::RegisterProfilePrefs(
-    PrefRegistrySimple* pref_registry) {
-  pref_registry->RegisterListPref(prefs::kMouseObservedDevicesPref);
-  pref_registry->RegisterListPref(prefs::kKeyboardObservedDevicesPref);
-  pref_registry->RegisterListPref(prefs::kTouchpadObservedDevicesPref);
-  pref_registry->RegisterListPref(prefs::kPointingStickObservedDevicesPref);
-}
-
-void InputDeviceTrackerImpl::ResetPrefMembers() {
-  mouse_observed_devices_ = std::make_unique<StringListPrefMember>();
-  touchpad_observed_devices_ = std::make_unique<StringListPrefMember>();
-  keyboard_observed_devices_ = std::make_unique<StringListPrefMember>();
-  pointing_stick_observed_devices_ = std::make_unique<StringListPrefMember>();
-}
-
-void InputDeviceTrackerImpl::Init(PrefService* pref_service) {
-  ResetPrefMembers();
-
-  mouse_observed_devices_->Init(prefs::kMouseObservedDevicesPref, pref_service);
-  touchpad_observed_devices_->Init(prefs::kTouchpadObservedDevicesPref,
-                                   pref_service);
-  keyboard_observed_devices_->Init(prefs::kKeyboardObservedDevicesPref,
-                                   pref_service);
-  pointing_stick_observed_devices_->Init(
-      prefs::kPointingStickObservedDevicesPref, pref_service);
-}
-
-void InputDeviceTrackerImpl::RecordDeviceConnected(
-    InputDeviceCategory category,
-    const base::StringPiece& device_key) {
-  StringListPrefMember* observed_devices = nullptr;
-  switch (category) {
-    case InputDeviceCategory::kMouse:
-      observed_devices = mouse_observed_devices_.get();
-      break;
-    case InputDeviceCategory::kKeyboard:
-      observed_devices = keyboard_observed_devices_.get();
-      break;
-    case InputDeviceCategory::kPointingStick:
-      observed_devices = pointing_stick_observed_devices_.get();
-      break;
-    case InputDeviceCategory::kTouchpad:
-      observed_devices = touchpad_observed_devices_.get();
-      break;
-  }
-  DCHECK(observed_devices);
-
-  std::vector<std::string> previously_observed_devices =
-      observed_devices->GetValue();
-
-  if (!base::Contains(previously_observed_devices, device_key)) {
-    previously_observed_devices.emplace_back(device_key);
-    observed_devices->SetValue(previously_observed_devices);
-  }
-}
-
-}  // namespace ash
diff --git a/ash/system/input_device_settings/input_device_tracker_impl.h b/ash/system/input_device_settings/input_device_tracker_impl.h
deleted file mode 100644
index d70f2c74d..0000000
--- a/ash/system/input_device_settings/input_device_tracker_impl.h
+++ /dev/null
@@ -1,45 +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 ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_TRACKER_IMPL_H_
-#define ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_TRACKER_IMPL_H_
-
-#include <memory>
-
-#include "ash/ash_export.h"
-#include "ash/system/input_device_settings/input_device_tracker.h"
-#include "components/prefs/pref_member.h"
-
-class PrefService;
-class PrefRegistrySimple;
-
-namespace ash {
-
-// TODO(dpad@): Remove once transitioned to per-device settings.
-class ASH_EXPORT InputDeviceTrackerImpl : public InputDeviceTracker {
- public:
-  InputDeviceTrackerImpl();
-  InputDeviceTrackerImpl(const InputDeviceTrackerImpl&) = delete;
-  InputDeviceTrackerImpl& operator=(const InputDeviceTrackerImpl&) = delete;
-  ~InputDeviceTrackerImpl() override;
-
-  static void RegisterProfilePrefs(PrefRegistrySimple* pref_registry);
-
-  // InputDeviceTracker:
-  void Init(PrefService* pref_service) override;
-  void RecordDeviceConnected(InputDeviceCategory category,
-                             const base::StringPiece& device_key) override;
-
- private:
-  void ResetPrefMembers();
-
-  std::unique_ptr<StringListPrefMember> keyboard_observed_devices_;
-  std::unique_ptr<StringListPrefMember> mouse_observed_devices_;
-  std::unique_ptr<StringListPrefMember> touchpad_observed_devices_;
-  std::unique_ptr<StringListPrefMember> pointing_stick_observed_devices_;
-};
-
-}  // namespace ash
-
-#endif  // ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_TRACKER_IMPL_H_
diff --git a/ash/system/input_device_settings/input_device_tracker_unittest.cc b/ash/system/input_device_settings/input_device_tracker_unittest.cc
index 3fa43c7c..5f81b6f 100644
--- a/ash/system/input_device_settings/input_device_tracker_unittest.cc
+++ b/ash/system/input_device_settings/input_device_tracker_unittest.cc
@@ -2,25 +2,29 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/input_device_settings/input_device_tracker_impl.h"
+#include "ash/system/input_device_settings/input_device_tracker.h"
 
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/system/input_device_settings/input_device_settings_pref_names.h"
 #include "ash/test/ash_test_base.h"
 #include "base/containers/contains.h"
+#include "base/notreached.h"
 #include "base/strings/string_piece_forward.h"
 #include "components/account_id/account_id.h"
 #include "components/prefs/pref_service.h"
 
 namespace ash {
 
+using InputDeviceCategory = InputDeviceTracker::InputDeviceCategory;
+
 namespace {
 const base::StringPiece kDeviceKey1 = "5555:1111";
 const base::StringPiece kDeviceKey2 = "3333:22aa";
 const base::StringPiece kDeviceKey3 = "aa22:eeff";
 
-constexpr char kUserEmail[] = "email@peripherals";
+constexpr char kUserEmail1[] = "email1@peripherals";
+constexpr char kUserEmail2[] = "email2@peripherals";
 }  // namespace
 
 class InputDeviceTrackerTest
@@ -37,9 +41,8 @@
   void SetUp() override {
     AshTestBase::SetUp();
     std::tie(category_, pref_path_) = GetParam();
-    pref_service_ = Shell::Get()->session_controller()->GetActivePrefService();
-    tracker_ = std::make_unique<InputDeviceTrackerImpl>();
-    tracker_->Init(pref_service_);
+    tracker_ = std::make_unique<InputDeviceTracker>();
+    SimulateUserLogin(GetAccountId(kUserEmail1));
   }
 
   void TearDown() override {
@@ -47,10 +50,13 @@
     AshTestBase::TearDown();
   }
 
-  AccountId GetAccountId() { return AccountId::FromUserEmail(kUserEmail); }
+  AccountId GetAccountId(base::StringPiece email) {
+    return AccountId::FromUserEmail(std::string(email));
+  }
 
   void CheckObservedDevicesList(
       std::vector<base::StringPiece> expected_devices) {
+    pref_service_ = Shell::Get()->session_controller()->GetActivePrefService();
     const auto& list = pref_service_->GetList(pref_path_);
     EXPECT_EQ(expected_devices.size(), list.size());
 
@@ -59,69 +65,80 @@
     }
   }
 
+  // TODO(dpad): Implement for mouse/touchpad/pointing stick once mojo objects
+  // are available.
+  void CallOnDeviceConnected(base::StringPiece device_key) {
+    switch (category_) {
+      case InputDeviceCategory::kKeyboard: {
+        mojom::Keyboard keyboard;
+        keyboard.device_key = std::string(device_key);
+        tracker_->OnKeyboardConnected(keyboard);
+        break;
+      }
+      case InputDeviceCategory::kMouse:
+      case InputDeviceCategory::kTouchpad:
+      case InputDeviceCategory::kPointingStick:
+        NOTIMPLEMENTED();
+        break;
+    }
+  }
+
  protected:
-  std::unique_ptr<InputDeviceTrackerImpl> tracker_;
+  std::unique_ptr<InputDeviceTracker> tracker_;
   base::raw_ptr<PrefService> pref_service_;
 
   InputDeviceCategory category_;
   base::StringPiece pref_path_;
 };
 
+// TODO(dpad): Add in mouse/touchpad/pointing stick once implemented.
 INSTANTIATE_TEST_SUITE_P(
     ,
     InputDeviceTrackerTest,
     testing::ValuesIn(
         std::vector<std::pair<InputDeviceCategory, base::StringPiece>>{
-            {InputDeviceCategory::kMouse, prefs::kMouseObservedDevicesPref},
-            {InputDeviceCategory::kTouchpad,
-             prefs::kTouchpadObservedDevicesPref},
-            {InputDeviceCategory::kPointingStick,
-             prefs::kPointingStickObservedDevicesPref},
             {InputDeviceCategory::kKeyboard,
              prefs::kKeyboardObservedDevicesPref}}));
 
 TEST_P(InputDeviceTrackerTest, RecordDevices) {
-  tracker_->RecordDeviceConnected(category_, kDeviceKey1);
-  tracker_->RecordDeviceConnected(category_, kDeviceKey2);
-  tracker_->RecordDeviceConnected(category_, kDeviceKey3);
+  CallOnDeviceConnected(kDeviceKey1);
+  CallOnDeviceConnected(kDeviceKey2);
+  CallOnDeviceConnected(kDeviceKey3);
   CheckObservedDevicesList({kDeviceKey1, kDeviceKey2, kDeviceKey3});
 }
 
 TEST_P(InputDeviceTrackerTest, RecordDuplicateDevices) {
-  tracker_->RecordDeviceConnected(category_, kDeviceKey1);
-  tracker_->RecordDeviceConnected(category_, kDeviceKey2);
-  tracker_->RecordDeviceConnected(category_, kDeviceKey3);
+  CallOnDeviceConnected(kDeviceKey1);
+  CallOnDeviceConnected(kDeviceKey2);
+  CallOnDeviceConnected(kDeviceKey3);
 
   CheckObservedDevicesList({kDeviceKey1, kDeviceKey2, kDeviceKey3});
 
-  tracker_->RecordDeviceConnected(category_, kDeviceKey1);
-  tracker_->RecordDeviceConnected(category_, kDeviceKey2);
-  tracker_->RecordDeviceConnected(category_, kDeviceKey3);
+  CallOnDeviceConnected(kDeviceKey1);
+  CallOnDeviceConnected(kDeviceKey2);
+  CallOnDeviceConnected(kDeviceKey3);
 
   CheckObservedDevicesList({kDeviceKey1, kDeviceKey2, kDeviceKey3});
 }
 
 TEST_P(InputDeviceTrackerTest, RecordDevicesTwoUsers) {
-  tracker_->RecordDeviceConnected(category_, kDeviceKey1);
-  tracker_->RecordDeviceConnected(category_, kDeviceKey2);
-  tracker_->RecordDeviceConnected(category_, kDeviceKey3);
+  CallOnDeviceConnected(kDeviceKey1);
+  CallOnDeviceConnected(kDeviceKey2);
+  CallOnDeviceConnected(kDeviceKey3);
 
   CheckObservedDevicesList({kDeviceKey1, kDeviceKey2, kDeviceKey3});
 
   // Switch account
-  SimulateUserLogin(GetAccountId());
-  pref_service_ = Shell::Get()->session_controller()->GetActivePrefService();
-  tracker_->Init(pref_service_);
-
+  SimulateUserLogin(GetAccountId(kUserEmail2));
   CheckObservedDevicesList({});
 
-  tracker_->RecordDeviceConnected(category_, kDeviceKey1);
+  CallOnDeviceConnected(kDeviceKey1);
   CheckObservedDevicesList({kDeviceKey1});
 
-  tracker_->RecordDeviceConnected(category_, kDeviceKey2);
+  CallOnDeviceConnected(kDeviceKey2);
   CheckObservedDevicesList({kDeviceKey1, kDeviceKey2});
 
-  tracker_->RecordDeviceConnected(category_, kDeviceKey3);
+  CallOnDeviceConnected(kDeviceKey3);
   CheckObservedDevicesList({kDeviceKey1, kDeviceKey2, kDeviceKey3});
 }
 }  // namespace ash
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc
index abf5b997..d2ad071 100644
--- a/ash/system/palette/palette_tray_unittest.cc
+++ b/ash/system/palette/palette_tray_unittest.cc
@@ -9,8 +9,6 @@
 
 #include "ash/constants/ash_pref_names.h"
 #include "ash/constants/ash_switches.h"
-#include "ash/highlighter/highlighter_controller.h"
-#include "ash/highlighter/highlighter_controller_test_api.h"
 #include "ash/projector/model/projector_session_impl.h"
 #include "ash/projector/projector_controller_impl.h"
 #include "ash/public/cpp/stylus_utils.h"
diff --git a/ash/system/phonehub/phone_hub_app_count_icon.cc b/ash/system/phonehub/phone_hub_app_count_icon.cc
new file mode 100644
index 0000000..647754c
--- /dev/null
+++ b/ash/system/phonehub/phone_hub_app_count_icon.cc
@@ -0,0 +1,55 @@
+// 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 "phone_hub_app_count_icon.h"
+
+#include "ash/style/ash_color_provider.h"
+#include "base/i18n/number_formatting.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/image/canvas_image_source.h"
+
+namespace ash {
+
+class NumberIconImageSource : public gfx::CanvasImageSource {
+ public:
+  explicit NumberIconImageSource(size_t count)
+      : CanvasImageSource(gfx::Size(18, 18)), count_(count) {}
+
+  NumberIconImageSource(const NumberIconImageSource&) = delete;
+  NumberIconImageSource& operator=(const NumberIconImageSource&) = delete;
+
+  void Draw(gfx::Canvas* canvas) override {
+    float radius = size().width() / 2.0f;
+
+    canvas->DrawStringRectWithFlags(
+        base::FormatNumber(count_), GetNumberIconFontList(),
+        AshColorProvider::Get()->GetContentLayerColor(
+            AshColorProvider::ContentLayerType::kIconColorSecondary),
+        gfx::Rect(size()),
+        gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_SUBPIXEL_RENDERING);
+    cc::PaintFlags flags;
+    flags.setBlendMode(SkBlendMode::kXor);
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    flags.setAntiAlias(true);
+    flags.setColor(AshColorProvider::Get()->GetContentLayerColor(
+        AshColorProvider::ContentLayerType::kIconColorSecondaryBackground));
+    canvas->DrawCircle(gfx::PointF(radius, radius), radius, flags);
+  }
+
+ private:
+  size_t count_;
+  const gfx::FontList& GetNumberIconFontList() {
+    static gfx::FontList font_list({"Roboto"}, gfx::Font::NORMAL, 10,
+                                   gfx::Font::Weight::NORMAL);
+    return font_list;
+  }
+};
+
+AppCountIcon::AppCountIcon(const int count)
+    : SmallAppIcon(gfx::Image(
+          gfx::CanvasImageSource::MakeImageSkia<NumberIconImageSource>(0))) {}
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/system/phonehub/phone_hub_app_count_icon.h b/ash/system/phonehub/phone_hub_app_count_icon.h
new file mode 100644
index 0000000..2030408
--- /dev/null
+++ b/ash/system/phonehub/phone_hub_app_count_icon.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 ASH_SYSTEM_PHONEHUB_PHONE_HUB_APP_COUNT_ICON_H_
+#define ASH_SYSTEM_PHONEHUB_PHONE_HUB_APP_COUNT_ICON_H_
+#include "ash/ash_export.h"
+#include "ash/system/phonehub/phone_hub_small_app_icon.h"
+
+namespace ash {
+
+class ASH_EXPORT AppCountIcon : public SmallAppIcon {
+ public:
+  explicit AppCountIcon(const int count);
+};
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_PHONEHUB_PHONE_HUB_APP_COUNT_ICON_H_
\ No newline at end of file
diff --git a/ash/system/phonehub/phone_hub_more_apps_button.cc b/ash/system/phonehub/phone_hub_more_apps_button.cc
index 4b313510..abea9c5 100644
--- a/ash/system/phonehub/phone_hub_more_apps_button.cc
+++ b/ash/system/phonehub/phone_hub_more_apps_button.cc
@@ -4,9 +4,12 @@
 
 #include "ash/system/phonehub/phone_hub_more_apps_button.h"
 
+#include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/system/phonehub/phone_hub_app_count_icon.h"
 #include "ash/system/phonehub/phone_hub_small_app_icon.h"
 #include "chromeos/ash/components/phonehub/app_stream_launcher_data_model.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/views/background.h"
 #include "ui/views/layout/table_layout.h"
@@ -19,8 +22,13 @@
 constexpr int kMoreAppsButtonBackgroundRadius = 16;
 
 PhoneHubMoreAppsButton::PhoneHubMoreAppsButton(
-    phonehub::AppStreamLauncherDataModel* app_stream_launcher_data_model)
-    : app_stream_launcher_data_model_(app_stream_launcher_data_model) {
+    phonehub::AppStreamLauncherDataModel* app_stream_launcher_data_model,
+    views::Button::PressedCallback callback)
+    : views::Button(callback),
+      app_stream_launcher_data_model_(app_stream_launcher_data_model) {
+  SetFocusBehavior(FocusBehavior::ALWAYS);
+  SetAccessibleName(
+      l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_FULL_APPS_LIST_BUTTON_TITLE));
   InitLayout();
   app_stream_launcher_data_model_->AddObserver(this);
 }
@@ -45,6 +53,8 @@
                                kMoreAppsButtonColumnPadding);
   table_layout_->AddRows(1, kMoreAppsButtonRowPadding);
 
+  OnAppListChanged();
+
   SetBackground(views::CreateRoundedRectBackground(
       AshColorProvider::Get()->GetControlsLayerColor(
           AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive),
@@ -60,16 +70,18 @@
 void PhoneHubMoreAppsButton::LoadAppList() {
   RemoveAllChildViews();
   const std::vector<phonehub::Notification::AppMetadata>* app_list =
-      app_stream_launcher_data_model_->GetAppsList();
+      app_stream_launcher_data_model_->GetAppsListSortedByName();
   if (!app_list->empty()) {
-    auto app_count = std::min(app_list->size(), size_t{4});
+    auto app_count = std::min(app_list->size(), size_t{3});
     for (size_t i = 0; i < app_count; i++) {
       AddChildView(std::make_unique<SmallAppIcon>(app_list->at(i).icon));
     }
   }
+
+  AddChildView(std::make_unique<AppCountIcon>(app_list->size()));
 }
 
-BEGIN_METADATA(PhoneHubMoreAppsButton, views::View)
+BEGIN_METADATA(PhoneHubMoreAppsButton, views::Button)
 END_METADATA
 
 }  // namespace ash
\ No newline at end of file
diff --git a/ash/system/phonehub/phone_hub_more_apps_button.h b/ash/system/phonehub/phone_hub_more_apps_button.h
index bcf0f8c..909913a 100644
--- a/ash/system/phonehub/phone_hub_more_apps_button.h
+++ b/ash/system/phonehub/phone_hub_more_apps_button.h
@@ -6,21 +6,22 @@
 #define ASH_SYSTEM_PHONEHUB_PHONE_HUB_MORE_APPS_BUTTON_H_
 
 #include "chromeos/ash/components/phonehub/app_stream_launcher_data_model.h"
+#include "ui/views/controls/button/button.h"
 #include "ui/views/layout/table_layout.h"
-#include "ui/views/view.h"
 
 namespace ash {
 
 // A view in phone hub that displays the first three apps in a user's app
 // drawer, as well as a count of how many apps they have on their phone.
 class VIEWS_EXPORT PhoneHubMoreAppsButton
-    : public views::View,
+    : public views::Button,
       phonehub::AppStreamLauncherDataModel::Observer {
  public:
   METADATA_HEADER(PhoneHubMoreAppsButton);
 
   explicit PhoneHubMoreAppsButton(
-      phonehub::AppStreamLauncherDataModel* app_stream_launcher_data_model);
+      phonehub::AppStreamLauncherDataModel* app_stream_launcher_data_model,
+      views::Button::PressedCallback callback);
   PhoneHubMoreAppsButton(const PhoneHubMoreAppsButton&) = delete;
   PhoneHubMoreAppsButton& operator=(const PhoneHubMoreAppsButton&) = delete;
   ~PhoneHubMoreAppsButton() override;
diff --git a/ash/system/phonehub/phone_hub_recent_apps_view.cc b/ash/system/phonehub/phone_hub_recent_apps_view.cc
index 74d2a55..90368feb 100644
--- a/ash/system/phonehub/phone_hub_recent_apps_view.cc
+++ b/ash/system/phonehub/phone_hub_recent_apps_view.cc
@@ -13,6 +13,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_id.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/system/phonehub/phone_hub_more_apps_button.h"
 #include "ash/system/phonehub/phone_hub_recent_app_button.h"
 #include "ash/system/phonehub/phone_hub_view_ids.h"
 #include "ash/system/phonehub/ui_constants.h"
@@ -166,8 +167,9 @@
       children(), std::back_inserter(visible_children), [](const auto* v) {
         return v->GetVisible() && (v->GetPreferredSize().width() > 0);
       });
-  if (visible_children.empty())
+  if (visible_children.empty()) {
     return;
+  }
   const int visible_child_width =
       std::accumulate(visible_children.cbegin(), visible_children.cend(), 0,
                       [](int width, const auto* v) {
@@ -225,14 +227,6 @@
           recent_apps_interaction_handler_->FetchRecentAppMetadataList();
 
       for (const auto& recent_app : recent_apps_list) {
-        if (features::IsEcheLauncherEnabled() &&
-            recent_app_button_list_.size() == kMaxAppsWithMoreAppsButton) {
-          recent_app_button_list_.push_back(
-              recent_app_buttons_view_->AddRecentAppButton(
-                  GenerateMoreAppsButton()));
-          break;
-        }
-
         auto pressed_callback = base::BindRepeating(
             &phonehub::RecentAppsInteractionHandler::NotifyRecentAppClicked,
             base::Unretained(recent_apps_interaction_handler_), recent_app,
@@ -244,6 +238,13 @@
                     pressed_callback)));
       }
 
+      if (features::IsEcheLauncherEnabled() &&
+          recent_app_button_list_.size() >= kMaxAppsWithMoreAppsButton) {
+        recent_app_button_list_.push_back(
+            recent_app_buttons_view_->AddRecentAppButton(
+                GenerateMoreAppsButton()));
+      }
+
       recent_app_buttons_view_->SetVisible(true);
       placeholder_view_->SetVisible(false);
       SetVisible(true);
@@ -260,12 +261,17 @@
       ->SetShouldShowMiniLauncher(true);
 }
 
-std::unique_ptr<views::ImageButton>
-PhoneHubRecentAppsView::GenerateMoreAppsButton() {
+std::unique_ptr<views::View> PhoneHubRecentAppsView::GenerateMoreAppsButton() {
+  if (features::IsEcheLauncherIconsInMoreAppsButtonEnabled()) {
+    return std::make_unique<PhoneHubMoreAppsButton>(
+        phone_hub_manager_->GetAppStreamLauncherDataModel(),
+        base::BindRepeating(&PhoneHubRecentAppsView::SwitchToFullAppsList,
+                            base::Unretained(this)));
+  }
+
   auto more_apps_button = std::make_unique<views::ImageButton>(
       base::BindRepeating(&PhoneHubRecentAppsView::SwitchToFullAppsList,
                           base::Unretained(this)));
-
   gfx::ImageSkia image = gfx::CreateVectorIcon(
       kPhoneHubFullAppsListIcon,
       AshColorProvider::Get()->GetContentLayerColor(
diff --git a/ash/system/phonehub/phone_hub_recent_apps_view.h b/ash/system/phonehub/phone_hub_recent_apps_view.h
index ba42c94..dcac3ba 100644
--- a/ash/system/phonehub/phone_hub_recent_apps_view.h
+++ b/ash/system/phonehub/phone_hub_recent_apps_view.h
@@ -74,7 +74,7 @@
   void SwitchToFullAppsList();
 
   // Generate more apps button.
-  std::unique_ptr<views::ImageButton> GenerateMoreAppsButton();
+  std::unique_ptr<views::View> GenerateMoreAppsButton();
 
   RecentAppButtonsView* recent_app_buttons_view_ = nullptr;
   std::vector<views::View*> recent_app_button_list_;
diff --git a/ash/system/phonehub/phone_hub_recent_apps_view_unittest.cc b/ash/system/phonehub/phone_hub_recent_apps_view_unittest.cc
index dd5331d..9c41bdca 100644
--- a/ash/system/phonehub/phone_hub_recent_apps_view_unittest.cc
+++ b/ash/system/phonehub/phone_hub_recent_apps_view_unittest.cc
@@ -154,7 +154,7 @@
   FeatureStateChanged(FeatureState::kEnabledByUser);
   recent_apps_view()->Update();
 
-  size_t expected_recent_app_button = 6;
+  size_t expected_recent_app_button = 7;
   EXPECT_EQ(expected_recent_app_button,
             recent_apps_view()->recent_app_buttons_view_->children().size());
 
@@ -162,11 +162,7 @@
        i != recent_apps_view()->recent_app_buttons_view_->children().size();
        i++) {
     auto* child = recent_apps_view()->recent_app_buttons_view_->children()[i];
-    if (i == 5) {
-      views::ImageButton* more_apps_button =
-          static_cast<views::ImageButton*>(child);
-      views::test::ButtonTestApi(more_apps_button)
-          .NotifyClick(ui::test::TestEvent());
+    if (i == 6) {
       break;
     }
     PhoneHubRecentAppButton* recent_app =
@@ -175,10 +171,9 @@
     views::test::ButtonTestApi(recent_app).NotifyClick(ui::test::TestEvent());
   }
 
-  size_t expected_number_of_button_be_clicked = 5;
+  size_t expected_number_of_button_be_clicked = 6;
   EXPECT_EQ(expected_number_of_button_be_clicked,
             PackageNameToClickCount(kPackageName));
-  EXPECT_TRUE(AppStreamLauncherShowState());
 }
 
 }  // namespace ash
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc
index ec10f4a..bfa34d8 100644
--- a/ash/system/unified/unified_system_tray_view.cc
+++ b/ash/system/unified/unified_system_tray_view.cc
@@ -43,6 +43,9 @@
 
 namespace {
 
+// The padding between sliders inside the `UnifiedSlidersContainerView`.
+const int kSlidersPadding = 8;
+
 class DetailedViewContainer : public views::View {
  public:
   DetailedViewContainer() = default;
@@ -102,10 +105,10 @@
 }
 
 int UnifiedSlidersContainerView::GetExpandedHeight() const {
-  return std::accumulate(children().cbegin(), children().cend(), 0,
-                         [](int height, const auto* v) {
-                           return height + v->GetHeightForWidth(kTrayMenuWidth);
-                         });
+  return std::accumulate(
+      children().cbegin(), children().cend(), 0, [](int height, const auto* v) {
+        return height + v->GetHeightForWidth(kTrayMenuWidth) + kSlidersPadding;
+      });
 }
 
 void UnifiedSlidersContainerView::Layout() {
@@ -113,7 +116,7 @@
   for (auto* child : children()) {
     int height = child->GetHeightForWidth(kTrayMenuWidth);
     child->SetBounds(0, y, kTrayMenuWidth, height);
-    y += height;
+    y += height + kSlidersPadding;
   }
 }
 
diff --git a/ash/wm/snap_group/snap_group_controller.cc b/ash/wm/snap_group/snap_group_controller.cc
index 292aa34..5bcc7c1 100644
--- a/ash/wm/snap_group/snap_group_controller.cc
+++ b/ash/wm/snap_group/snap_group_controller.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/shell.h"
 #include "ash/wm/snap_group/snap_group.h"
 #include "base/check.h"
 #include "base/containers/cxx20_erase.h"
@@ -17,6 +18,12 @@
 
 SnapGroupController::~SnapGroupController() = default;
 
+bool SnapGroupController::AreWindowsInSnapGroup(aura::Window* window1,
+                                                aura::Window* window2) const {
+  return window1 == RetrieveTheOtherWindowInSnapGroup(window2) &&
+         window2 == RetrieveTheOtherWindowInSnapGroup(window1);
+}
+
 bool SnapGroupController::AddSnapGroup(aura::Window* window1,
                                        aura::Window* window2) {
   if (window_to_snap_group_map_.find(window1) !=
@@ -49,4 +56,27 @@
   return true;
 }
 
+bool SnapGroupController::RemoveSnapGroupContainingWindow(
+    aura::Window* window) {
+  if (window_to_snap_group_map_.find(window) ==
+      window_to_snap_group_map_.end()) {
+    return false;
+  }
+
+  SnapGroup* snap_group = window_to_snap_group_map_.find(window)->second;
+  return RemoveSnapGroup(snap_group);
+}
+
+aura::Window* SnapGroupController::RetrieveTheOtherWindowInSnapGroup(
+    aura::Window* window) const {
+  if (window_to_snap_group_map_.find(window) ==
+      window_to_snap_group_map_.end()) {
+    return nullptr;
+  }
+
+  SnapGroup* snap_group = window_to_snap_group_map_.find(window)->second;
+  return window == snap_group->window1() ? snap_group->window2()
+                                         : snap_group->window1();
+}
+
 }  // namespace ash
\ No newline at end of file
diff --git a/ash/wm/snap_group/snap_group_controller.h b/ash/wm/snap_group/snap_group_controller.h
index f4f345bb..44a16b1 100644
--- a/ash/wm/snap_group/snap_group_controller.h
+++ b/ash/wm/snap_group/snap_group_controller.h
@@ -20,7 +20,7 @@
 class SnapGroup;
 
 // Works as the centralized place to manage the `SnapGroup`. A single instance
-// of this class will be created and owned by `Shell`. it controls the creation
+// of this class will be created and owned by `Shell`. It controls the creation
 // and destruction of the `SnapGroup`. TODO: It also implements the
 // `OverviewObserver` and `TabletObserver`.
 class ASH_EXPORT SnapGroupController {
@@ -33,6 +33,10 @@
   SnapGroupController& operator=(const SnapGroupController&) = delete;
   ~SnapGroupController();
 
+  // Returns true if `window1` and `window2` are in the same snap group.
+  bool AreWindowsInSnapGroup(aura::Window* window1,
+                             aura::Window* window2) const;
+
   // Returns true if the corresponding SnapGroup for the given `window1` and
   // `window2` gets created, added to the `snap_groups_` and updated
   // `window_to_snap_group_map_` successfully. False otherwise.
@@ -43,12 +47,21 @@
   // `window_to_snap_group_map_`. False otherwise.
   bool RemoveSnapGroup(SnapGroup* snap_group);
 
+  // Returns true if the corresponding snap group that contains the
+  // given `window` has been removed successfully. Returns false otherwise.
+  bool RemoveSnapGroupContainingWindow(aura::Window* window);
+
   const SnapGroups& snap_groups_for_testing() const { return snap_groups_; }
   const WindowToSnapGroupMap& window_to_snap_group_map_for_testing() const {
     return window_to_snap_group_map_;
   }
 
  private:
+  // Retrieves the other window that is in the same snap group if any. Returns
+  // nullptr if such window can't be found i.e. the window is not in a snap
+  // group.
+  aura::Window* RetrieveTheOtherWindowInSnapGroup(aura::Window* window) const;
+
   // Contains all the `SnapGroup`, we will have one `SnapGroup` globally for the
   // first iteration but will have multiple in the future iteration.
   SnapGroups snap_groups_;
diff --git a/ash/wm/snap_group/snap_group_lock_button.cc b/ash/wm/snap_group/snap_group_lock_button.cc
new file mode 100644
index 0000000..13bf4aa
--- /dev/null
+++ b/ash/wm/snap_group/snap_group_lock_button.cc
@@ -0,0 +1,84 @@
+// 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 "ash/wm/snap_group/snap_group_lock_button.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/snap_group/snap_group_controller.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/models/image_model.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/background.h"
+
+namespace ash {
+
+namespace {
+
+constexpr int kLockButtonCornerRadius = 1;
+
+}  // namespace
+
+SnapGroupLockButton::SnapGroupLockButton(aura::Window* window1,
+                                         aura::Window* window2)
+    : ImageButton(base::BindRepeating(&SnapGroupLockButton::OnLockButtonPressed,
+                                      base::Unretained(this),
+                                      window1,
+                                      window2)) {
+  SetImageHorizontalAlignment(ALIGN_CENTER);
+  SetImageVerticalAlignment(ALIGN_MIDDLE);
+
+  SnapGroupController* snap_group_controller =
+      Shell::Get()->snap_group_controller();
+  const bool locked =
+      snap_group_controller->AreWindowsInSnapGroup(window1, window2);
+  UpdateLockButtonIcon(locked);
+  UpdateLockButtonTooltip(locked);
+
+  SetBackground(views::CreateThemedRoundedRectBackground(
+      kColorAshShieldAndBase80, kLockButtonCornerRadius));
+}
+
+SnapGroupLockButton::~SnapGroupLockButton() = default;
+
+void SnapGroupLockButton::OnLockButtonPressed(aura::Window* window1,
+                                              aura::Window* window2) {
+  DCHECK(window1);
+  DCHECK(window2);
+  SnapGroupController* snap_group_controller =
+      Shell::Get()->snap_group_controller();
+  const bool locked =
+      snap_group_controller->AreWindowsInSnapGroup(window1, window2);
+
+  if (locked) {
+    snap_group_controller->RemoveSnapGroupContainingWindow(window1);
+  } else {
+    snap_group_controller->AddSnapGroup(window1, window2);
+  }
+
+  UpdateLockButtonIcon(!locked);
+  UpdateLockButtonTooltip(!locked);
+}
+
+void SnapGroupLockButton::UpdateLockButtonIcon(bool locked) {
+  SetImageModel(
+      views::Button::STATE_NORMAL,
+      ui::ImageModel::FromVectorIcon(locked ? kLockScreenEasyUnlockCloseIcon
+                                            : kLockScreenEasyUnlockOpenIcon,
+                                     kColorAshIconColorPrimary));
+}
+
+void SnapGroupLockButton::UpdateLockButtonTooltip(bool locked) {
+  SetTooltipText(l10n_util::GetStringUTF16(
+      locked ? IDS_ASH_SNAP_GROUP_CLICK_TO_UNLOCK_WINDOWS
+             : IDS_ASH_SNAP_GROUP_CLICK_TO_LOCK_WINDOWS));
+}
+
+BEGIN_METADATA(SnapGroupLockButton, views::ImageButton)
+END_METADATA
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/wm/snap_group/snap_group_lock_button.h b/ash/wm/snap_group/snap_group_lock_button.h
new file mode 100644
index 0000000..ab0e4f5b
--- /dev/null
+++ b/ash/wm/snap_group/snap_group_lock_button.h
@@ -0,0 +1,40 @@
+// 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 ASH_WM_SNAP_GROUP_SNAP_GROUP_LOCK_BUTTON_H_
+#define ASH_WM_SNAP_GROUP_SNAP_GROUP_LOCK_BUTTON_H_
+
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/views/controls/button/image_button.h"
+
+namespace aura {
+class Window;
+}  // namespace aura
+
+namespace ash {
+
+// Contents view of the lock widget that appears below the resize widget when
+// two windows are snapped. It acts as the entry point for the creating or
+// removing the `SnapGroup`. This entry point is guarded by the feature flag
+// `kSnapGroup` and will only be enabled when the feature param
+// `kAutomaticallyLockGroup` is false.
+class SnapGroupLockButton : public views::ImageButton {
+ public:
+  METADATA_HEADER(SnapGroupLockButton);
+  SnapGroupLockButton(aura::Window* window1, aura::Window* window2);
+  SnapGroupLockButton(const SnapGroupLockButton&) = delete;
+  SnapGroupLockButton& operator=(const SnapGroupLockButton&) = delete;
+  ~SnapGroupLockButton() override;
+
+  // Decides to create or remove a snap group on button toggled.
+  void OnLockButtonPressed(aura::Window* window1, aura::Window* window2);
+
+ private:
+  void UpdateLockButtonIcon(bool locked);
+  void UpdateLockButtonTooltip(bool locked);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_SNAP_GROUP_SNAP_GROUP_LOCK_BUTTON_H_
\ No newline at end of file
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc
index d383999..5d30fe7 100644
--- a/ash/wm/snap_group/snap_group_unittest.cc
+++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -6,15 +6,29 @@
 #include <vector>
 
 #include "ash/constants/ash_features.h"
+#include "ash/public/cpp/test/shell_test_api.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/test/ash_test_base.h"
 #include "ash/test/ash_test_util.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/snap_group/snap_group_controller.h"
+#include "ash/wm/snap_group/snap_group_lock_button.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
+#include "ash/wm/workspace/multi_window_resize_controller.h"
+#include "ash/wm/workspace/workspace_event_handler_test_helper.h"
+#include "ash/wm/workspace_controller_test_api.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/timer/timer.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_unittest_util.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/widget/widget.h"
 #include "ui/wm/core/window_util.h"
 
 namespace ash {
@@ -137,4 +151,217 @@
   EXPECT_TRUE(IsStackedBelow(w3.get(), w2.get()));
 }
 
+// A test fixture that tests the user-initiated snap group entry point. This
+// entry point is guarded by the feature flag `kSnapGroup` and will only be
+// enabled when the feature param `kAutomaticallyLockGroup` is false.
+class SnapGroupEntryPointArm2Test : public SnapGroupTest {
+ public:
+  SnapGroupEntryPointArm2Test() = default;
+  SnapGroupEntryPointArm2Test(const SnapGroupEntryPointArm2Test&) = delete;
+  SnapGroupEntryPointArm2Test& operator=(const SnapGroupEntryPointArm2Test&) =
+      delete;
+  ~SnapGroupEntryPointArm2Test() override = default;
+
+  // SnapGroupTest:
+  void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeatureWithParameters(
+        features::kSnapGroup, {{"AutomaticLockGroup", "false"}});
+    AshTestBase::SetUp();
+    WorkspaceEventHandler* event_handler =
+        WorkspaceControllerTestApi(ShellTestApi().workspace_controller())
+            .GetEventHandler();
+    resize_controller_ =
+        WorkspaceEventHandlerTestHelper(event_handler).resize_controller();
+  }
+
+  views::Widget* GetLockWidget() const {
+    return resize_controller_->lock_widget_.get();
+  }
+
+  views::Widget* GetResizeWidget() const {
+    return resize_controller_->resize_widget_.get();
+  }
+
+  base::OneShotTimer* GetShowTimer() const {
+    return &resize_controller_->show_timer_;
+  }
+
+  bool IsShowing() const { return resize_controller_->IsShowing(); }
+
+  MultiWindowResizeController* resize_controller() const {
+    return resize_controller_;
+  }
+
+  // Verifies that the given two windows can be locked properly and the tooltip
+  // is updated accordingly.
+  void ToggleLockWidgetToLockTwoWindows(aura::Window* window1,
+                                        aura::Window* window2) {
+    auto* snap_group_controller = Shell::Get()->snap_group_controller();
+    ASSERT_TRUE(snap_group_controller);
+    EXPECT_TRUE(snap_group_controller->snap_groups_for_testing().empty());
+    EXPECT_TRUE(
+        snap_group_controller->window_to_snap_group_map_for_testing().empty());
+    EXPECT_FALSE(
+        snap_group_controller->AreWindowsInSnapGroup(window1, window2));
+
+    auto* event_generator = GetEventGenerator();
+    auto hover_location = window1->bounds().right_center();
+    event_generator->MoveMouseTo(hover_location);
+    auto* timer = GetShowTimer();
+    EXPECT_TRUE(timer->IsRunning());
+    EXPECT_TRUE(IsShowing());
+    timer->FireNow();
+    EXPECT_TRUE(GetLockWidget());
+
+    gfx::Rect lock_widget_bounds(GetLockWidget()->GetWindowBoundsInScreen());
+    hover_location = lock_widget_bounds.CenterPoint();
+    event_generator->MoveMouseTo(hover_location);
+    EXPECT_TRUE(GetLockWidget());
+    event_generator->PressLeftButton();
+    event_generator->ReleaseLeftButton();
+    EXPECT_TRUE(snap_group_controller->AreWindowsInSnapGroup(window1, window2));
+    VerifyLockButton(/*locked=*/true,
+                     resize_controller_->lock_button_for_testing());
+  }
+
+  // Verifies that the given two windows can be unlocked properly and the
+  // tooltip is updated accordingly.
+  void ToggleLockWidgetToUnlockTwoWindows(aura::Window* window1,
+                                          aura::Window* window2) {
+    auto* snap_group_controller = Shell::Get()->snap_group_controller();
+    ASSERT_TRUE(snap_group_controller);
+    EXPECT_TRUE(snap_group_controller->AreWindowsInSnapGroup(window1, window2));
+
+    auto* event_generator = GetEventGenerator();
+    const auto hover_location =
+        GetLockWidget()->GetWindowBoundsInScreen().CenterPoint();
+    event_generator->MoveMouseTo(hover_location);
+    EXPECT_TRUE(GetLockWidget());
+    event_generator->PressLeftButton();
+    event_generator->ReleaseLeftButton();
+    EXPECT_FALSE(
+        snap_group_controller->AreWindowsInSnapGroup(window1, window2));
+    VerifyLockButton(/*locked=*/false,
+                     resize_controller_->lock_button_for_testing());
+  }
+
+ private:
+  // Verifies that the icon image and the tooltip of the lock button gets
+  // updated correctly based on the `locked` state.
+  void VerifyLockButton(bool locked, SnapGroupLockButton* lock_button) {
+    SkColor color =
+        lock_button->GetColorProvider()->GetColor(kColorAshIconColorPrimary);
+    const gfx::ImageSkia locked_icon_image =
+        gfx::CreateVectorIcon(kLockScreenEasyUnlockCloseIcon, color);
+    const gfx::ImageSkia unlocked_icon_image =
+        gfx::CreateVectorIcon(kLockScreenEasyUnlockOpenIcon, color);
+    const SkBitmap* expected_icon =
+        locked ? locked_icon_image.bitmap() : unlocked_icon_image.bitmap();
+    const SkBitmap* actual_icon =
+        lock_button->GetImage(views::ImageButton::ButtonState::STATE_NORMAL)
+            .bitmap();
+    EXPECT_TRUE(gfx::test::AreBitmapsEqual(*actual_icon, *expected_icon));
+
+    const auto expected_tooltip_string = l10n_util::GetStringUTF16(
+        locked ? IDS_ASH_SNAP_GROUP_CLICK_TO_UNLOCK_WINDOWS
+               : IDS_ASH_SNAP_GROUP_CLICK_TO_LOCK_WINDOWS);
+    EXPECT_EQ(lock_button->GetTooltipText(), expected_tooltip_string);
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+  MultiWindowResizeController* resize_controller_;
+};
+
+// Tests that the lock widget will show below the resize widget when two windows
+// are snapped. And the location of the lock widget will be updated on mouse
+// move.
+TEST_F(SnapGroupEntryPointArm2Test, LockWidgetShowAndMoveTest) {
+  std::unique_ptr<aura::Window> w1(CreateTestWindow());
+  std::unique_ptr<aura::Window> w2(CreateTestWindow());
+  SnapTwoTestWindows(w1.get(), w2.get());
+  EXPECT_FALSE(GetResizeWidget());
+  EXPECT_FALSE(GetLockWidget());
+
+  auto* event_generator = GetEventGenerator();
+  auto hover_location = w1->bounds().right_center();
+  event_generator->MoveMouseTo(hover_location);
+  auto* timer = GetShowTimer();
+  EXPECT_TRUE(timer->IsRunning());
+  EXPECT_TRUE(IsShowing());
+  timer->FireNow();
+  EXPECT_TRUE(GetResizeWidget());
+  EXPECT_TRUE(GetLockWidget());
+
+  gfx::Rect ori_resize_widget_bounds(
+      GetResizeWidget()->GetWindowBoundsInScreen());
+  gfx::Rect ori_lock_widget_bounds(GetLockWidget()->GetWindowBoundsInScreen());
+
+  resize_controller()->MouseMovedOutOfHost();
+  EXPECT_FALSE(timer->IsRunning());
+  EXPECT_FALSE(IsShowing());
+
+  const int x_delta = 0;
+  const int y_delta = 5;
+  hover_location.Offset(x_delta, y_delta);
+  event_generator->MoveMouseTo(hover_location);
+  EXPECT_TRUE(timer->IsRunning());
+  EXPECT_TRUE(IsShowing());
+  timer->FireNow();
+  EXPECT_TRUE(GetResizeWidget());
+  EXPECT_TRUE(GetLockWidget());
+
+  gfx::Rect new_resize_widget_bounds(
+      GetResizeWidget()->GetWindowBoundsInScreen());
+  gfx::Rect new_lock_widget_bounds(GetLockWidget()->GetWindowBoundsInScreen());
+
+  gfx::Rect expected_resize_widget_bounds = ori_resize_widget_bounds;
+  expected_resize_widget_bounds.Offset(x_delta, y_delta);
+  gfx::Rect expected_lock_widget_bounds = ori_lock_widget_bounds;
+  expected_lock_widget_bounds.Offset(x_delta, y_delta);
+  EXPECT_EQ(expected_resize_widget_bounds, new_resize_widget_bounds);
+  EXPECT_EQ(expected_lock_widget_bounds, new_lock_widget_bounds);
+}
+
+// Tests that a snap group will be created and removed by toggling the lock
+// widget.
+TEST_F(SnapGroupEntryPointArm2Test,
+       SnapGroupAddAndRemovalThroughLockButtonTest) {
+  std::unique_ptr<aura::Window> w1(CreateTestWindow());
+  std::unique_ptr<aura::Window> w2(CreateTestWindow());
+  SnapTwoTestWindows(w1.get(), w2.get());
+  EXPECT_FALSE(GetLockWidget());
+
+  auto* snap_group_controller = Shell::Get()->snap_group_controller();
+  ToggleLockWidgetToLockTwoWindows(w1.get(), w2.get());
+  EXPECT_EQ(
+      snap_group_controller->window_to_snap_group_map_for_testing().size(), 2u);
+  EXPECT_EQ(snap_group_controller->snap_groups_for_testing().size(), 1u);
+
+  ToggleLockWidgetToUnlockTwoWindows(w1.get(), w2.get());
+  EXPECT_TRUE(
+      snap_group_controller->window_to_snap_group_map_for_testing().empty());
+  EXPECT_TRUE(snap_group_controller->snap_groups_for_testing().empty());
+}
+
+// Tests the activation functionalities of the snap group.
+TEST_F(SnapGroupEntryPointArm2Test, SnapGroupActivationTest) {
+  std::unique_ptr<aura::Window> w1(CreateTestWindow());
+  std::unique_ptr<aura::Window> w2(CreateTestWindow());
+  SnapTwoTestWindows(w1.get(), w2.get());
+  EXPECT_FALSE(GetLockWidget());
+
+  ToggleLockWidgetToLockTwoWindows(w1.get(), w2.get());
+
+  std::unique_ptr<aura::Window> w3(CreateTestWindow());
+  wm::ActivateWindow(w3.get());
+  wm::ActivateWindow(w1.get());
+  EXPECT_TRUE(IsStackedBelow(w3.get(), w2.get()));
+
+  ToggleLockWidgetToUnlockTwoWindows(w1.get(), w2.get());
+
+  wm::ActivateWindow(w3.get());
+  wm::ActivateWindow(w1.get());
+  EXPECT_FALSE(IsStackedBelow(w3.get(), w2.get()));
+}
+
 }  // namespace ash
\ No newline at end of file
diff --git a/ash/wm/workspace/multi_window_resize_controller.cc b/ash/wm/workspace/multi_window_resize_controller.cc
index 7f5c0d3..f0c4045 100644
--- a/ash/wm/workspace/multi_window_resize_controller.cc
+++ b/ash/wm/workspace/multi_window_resize_controller.cc
@@ -6,34 +6,33 @@
 
 #include <memory>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/resize_shadow_controller.h"
+#include "ash/wm/snap_group/snap_group_lock_button.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_metrics.h"
 #include "ash/wm/workspace/workspace_window_resizer.h"
 #include "base/containers/adapters.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
 #include "base/time/time.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window_delegate.h"
-#include "ui/base/cursor/cursor.h"
 #include "ui/base/hit_test.h"
 #include "ui/display/screen.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/point_f.h"
-#include "ui/gfx/image/image.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_delegate.h"
 #include "ui/wm/core/compound_event_filter.h"
 #include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/core/window_animations.h"
 
 namespace ash {
+
 namespace {
 
 // Delay before hiding the `resize_widget_`.
@@ -42,6 +41,21 @@
 // Padding from the bottom/right edge the resize widget is shown at.
 const int kResizeWidgetPadding = 15;
 
+// Distance between the resize widget and lock widget.
+const int kResizeWidgetAndLockWidgetDistance = 75;
+
+// Returns the widget init params needed to create the resize widget or snap
+// group lock widget.
+views::Widget::InitParams CreateWidgetParams(aura::Window* parent_window,
+                                             const std::string& widget_name) {
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
+  params.parent = parent_window;
+  params.name = widget_name;
+  params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  return params;
+}
+
 gfx::PointF ConvertPointFromScreen(aura::Window* window,
                                    const gfx::PointF& point) {
   gfx::PointF result(point);
@@ -83,7 +97,7 @@
   return ContainsY(window, window_loc.y());
 }
 
-// Returns true if |p| is on the edge |edge_want| of |window|.
+// Returns true if `p` is on the edge `edge_want` of `window`.
 bool PointOnWindowEdge(aura::Window* window,
                        int edge_want,
                        const gfx::Point& p) {
@@ -106,8 +120,17 @@
   return x2 <= max_1 && max_2 > x1;
 }
 
+// Returns true if the entry point to create and remove the snap group through
+// the multi-window resizer is enabled.
+bool CanShowLockWidget() {
+  return features::IsSnapGroupEnabled() &&
+         !features::kAutomaticallyLockGroup.Get();
+}
+
 }  // namespace
 
+// -----------------------------------------------------------------------------
+// ResizeView:
 // View contained in the widget. Passes along mouse events to the
 // MultiWindowResizeController so that it can start/stop the resize loop.
 class MultiWindowResizeController::ResizeView : public views::View {
@@ -117,13 +140,15 @@
 
   ResizeView(const ResizeView&) = delete;
   ResizeView& operator=(const ResizeView&) = delete;
+  ~ResizeView() override = default;
 
-  // views::View overrides:
+  // views::View:
   gfx::Size CalculatePreferredSize() const override {
     const bool vert = direction_ == Direction::kLeftRight;
     return gfx::Size(vert ? kShortSide : kLongSide,
                      vert ? kLongSide : kShortSide);
   }
+
   void OnPaint(gfx::Canvas* canvas) override {
     cc::PaintFlags flags;
     flags.setColor(SkColorSetA(SK_ColorBLACK, 0x7F));
@@ -190,20 +215,26 @@
   const Direction direction_;
 };
 
+// -----------------------------------------------------------------------------
+// ResizeMouseWatcherHost:
 // MouseWatcherHost implementation for MultiWindowResizeController. Forwards
 // Contains() to MultiWindowResizeController.
 class MultiWindowResizeController::ResizeMouseWatcherHost
     : public views::MouseWatcherHost {
  public:
-  ResizeMouseWatcherHost(MultiWindowResizeController* host) : host_(host) {}
+  explicit ResizeMouseWatcherHost(MultiWindowResizeController* host)
+      : host_(host) {}
 
   ResizeMouseWatcherHost(const ResizeMouseWatcherHost&) = delete;
   ResizeMouseWatcherHost& operator=(const ResizeMouseWatcherHost&) = delete;
+  ~ResizeMouseWatcherHost() override = default;
 
-  // MouseWatcherHost overrides:
+  // views::MouseWatcherHost:
   bool Contains(const gfx::Point& point_in_screen, EventType type) override {
     return (type == EventType::kPress)
-               ? host_->IsOverResizeWidget(point_in_screen)
+               ? host_->IsOverResizeWidget(point_in_screen) ||
+                     (CanShowLockWidget() &&
+                      host_->IsOverLockWidget(point_in_screen))
                : host_->IsOverWindows(point_in_screen);
   }
 
@@ -225,6 +256,8 @@
          direction == other.direction;
 }
 
+// -----------------------------------------------------------------------------
+// MultiWindowResizeController:
 MultiWindowResizeController::MultiWindowResizeController() {
   Shell::Get()->overview_controller()->AddObserver(this);
 }
@@ -312,8 +345,10 @@
 
 void MultiWindowResizeController::OnOverviewModeEndingAnimationComplete(
     bool canceled) {
-  if (canceled)
+  if (canceled) {
     return;
+  }
+
   // Show resize-lock shadow UI after exiting overview.
   Shell::Get()->resize_shadow_controller()->TryShowAllShadows();
 }
@@ -445,7 +480,7 @@
         NOTREACHED();
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 void MultiWindowResizeController::FindWindowsTouching(
@@ -488,26 +523,25 @@
   show_timer_.Stop();
   aura::Window* window1 = windows_.window1;
   aura::Window* window2 = windows_.window2;
+
   resize_widget_ = std::make_unique<views::Widget>();
-  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-  params.name = "MultiWindowResizeController";
-  params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
-  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.parent = window1->GetRootWindow()->GetChildById(
-      kShellWindowId_AlwaysOnTopContainer);
   resize_widget_->set_focus_on_creation(false);
-  resize_widget_->Init(std::move(params));
+  aura::Window* parent_window = window1->GetRootWindow()->GetChildById(
+      kShellWindowId_AlwaysOnTopContainer);
+  resize_widget_->Init(CreateWidgetParams(
+      parent_window, /*widget_name=*/"MultiWindowResizeController"));
+
   ::wm::SetWindowVisibilityAnimationType(
       resize_widget_->GetNativeWindow(),
       ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
   resize_widget_->SetContentsView(
       std::make_unique<ResizeView>(this, windows_.direction));
-  show_bounds_in_screen_ = ConvertRectToScreen(
-      window1->parent(),
-      CalculateResizeWidgetBounds(gfx::PointF(show_location_in_parent_)));
-  resize_widget_->SetBounds(show_bounds_in_screen_);
+  gfx::Rect resize_widget_bounds =
+      CalculateResizeWidgetBounds(gfx::PointF(show_location_in_parent_));
+  resize_widget_show_bounds_in_screen_ =
+      ConvertRectToScreen(window1->parent(), resize_widget_bounds);
+  resize_widget_->SetBounds(resize_widget_show_bounds_in_screen_);
   resize_widget_->Show();
-  CreateMouseWatcher();
 
   base::RecordAction(base::UserMetricsAction(kMultiWindowResizerShow));
   base::UmaHistogramBoolean(kMultiWindowResizerShowHistogramName, true);
@@ -518,7 +552,24 @@
         base::UserMetricsAction(kMultiWindowResizerShowTwoWindowsSnapped));
     base::UmaHistogramBoolean(
         kMultiWindowResizerShowTwoWindowsSnappedHistogramName, true);
+
+    if (CanShowLockWidget()) {
+      DCHECK(!lock_widget_.get());
+      lock_widget_ = std::make_unique<views::Widget>();
+      lock_widget_->Init(CreateWidgetParams(
+          parent_window, /*widget_name=*/"SnapGroupLockWidget"));
+      lock_button_ = lock_widget_->SetContentsView(
+          std::make_unique<SnapGroupLockButton>(window1, window2));
+
+      gfx::Rect lock_widget_show_bounds_in_screen =
+          ConvertRectToScreen(windows_.window1->parent(),
+                              CalculateLockWidgetBounds(resize_widget_bounds));
+      lock_widget_->SetBounds(lock_widget_show_bounds_in_screen);
+      lock_widget_->Show();
+    }
   }
+
+  CreateMouseWatcher();
 }
 
 bool MultiWindowResizeController::IsShowing() const {
@@ -526,8 +577,10 @@
 }
 
 void MultiWindowResizeController::Hide() {
-  if (window_resizer_)
-    return;  // Ignore hides while actively resizing.
+  // Ignore `Hide` while actively resizing.
+  if (window_resizer_) {
+    return;
+  }
 
   if (windows_.window1) {
     StopObserving(windows_.window1);
@@ -539,12 +592,16 @@
   }
 
   show_timer_.Stop();
+  lock_widget_.reset();
 
-  if (!resize_widget_)
+  if (!resize_widget_) {
     return;
+  }
 
-  for (auto* window : windows_.other_windows)
+  for (auto* window : windows_.other_windows) {
     StopObserving(window);
+  }
+
   mouse_watcher_.reset();
   resize_widget_.reset();
   windows_ = ResizeWindows();
@@ -567,10 +624,12 @@
   DCHECK(windows_.other_windows.empty());
   FindWindowsTouching(windows_.window2, windows_.direction,
                       &windows_.other_windows);
-  for (size_t i = 0; i < windows_.other_windows.size(); ++i) {
-    StartObserving(windows_.other_windows[i]);
-    windows.push_back(windows_.other_windows[i]);
+
+  for (auto* other_window : windows_.other_windows) {
+    StartObserving(other_window);
+    windows.push_back(other_window);
   }
+
   int component =
       windows_.direction == Direction::kLeftRight ? HTRIGHT : HTBOTTOM;
   WindowState* window_state = WindowState::Get(windows_.window1);
@@ -601,10 +660,12 @@
       ConvertRectToScreen(windows_.window1->parent(),
                           CalculateResizeWidgetBounds(location_in_parent));
 
-  if (windows_.direction == Direction::kLeftRight)
-    bounds.set_y(show_bounds_in_screen_.y());
-  else
-    bounds.set_x(show_bounds_in_screen_.x());
+  if (windows_.direction == Direction::kLeftRight) {
+    bounds.set_y(resize_widget_show_bounds_in_screen_.y());
+  } else {
+    bounds.set_x(resize_widget_show_bounds_in_screen_.x());
+  }
+
   resize_widget_->SetBounds(bounds);
 }
 
@@ -619,19 +680,23 @@
     Hide();
   } else {
     // If the mouse is over the resizer we need to remove observers on any of
-    // the |other_windows|. If we start another resize we'll recalculate the
-    // |other_windows| and invoke AddObserver() as necessary.
-    for (size_t i = 0; i < windows_.other_windows.size(); ++i)
-      StopObserving(windows_.other_windows[i]);
-    windows_.other_windows.clear();
+    // the `other_windows`. If we start another resize we'll recalculate the
+    // `other_windows` and invoke AddObserver() as necessary.
+    for (auto* other_window : windows_.other_windows) {
+      StopObserving(other_window);
+    }
 
+    windows_.other_windows.clear();
     CreateMouseWatcher();
   }
 }
 
 void MultiWindowResizeController::CancelResize() {
-  if (!window_resizer_)
-    return;  // Happens if window was destroyed and we nuked the WindowResizer.
+  // Happens if window was destroyed and we nuked the WindowResizer.
+  if (!window_resizer_) {
+    return;
+  }
+
   window_resizer_->RevertDrag();
   WindowState::Get(window_resizer_->GetTarget())->DeleteDragDetails();
   ResetResizer();
@@ -659,15 +724,40 @@
   return gfx::Rect(x, y, pref.width(), pref.height());
 }
 
+gfx::Rect MultiWindowResizeController::CalculateLockWidgetBounds(
+    const gfx::Rect& resize_widget_bounds) const {
+  if (windows_.direction == Direction::kLeftRight) {
+    return gfx::Rect(
+        resize_widget_bounds.x(),
+        resize_widget_bounds.y() + kResizeWidgetAndLockWidgetDistance,
+        resize_widget_bounds.width(), resize_widget_bounds.width());
+  } else {
+    return gfx::Rect(
+        resize_widget_bounds.x() + kResizeWidgetAndLockWidgetDistance,
+        resize_widget_bounds.y(), resize_widget_bounds.height(),
+        resize_widget_bounds.height());
+  }
+}
+
 bool MultiWindowResizeController::IsOverResizeWidget(
     const gfx::Point& location_in_screen) const {
   return resize_widget_->GetWindowBoundsInScreen().Contains(location_in_screen);
 }
 
+bool MultiWindowResizeController::IsOverLockWidget(
+    const gfx::Point& location_in_screen) const {
+  return lock_widget_->GetWindowBoundsInScreen().Contains(location_in_screen);
+}
+
 bool MultiWindowResizeController::IsOverWindows(
     const gfx::Point& location_in_screen) const {
-  if (IsOverResizeWidget(location_in_screen))
+  if (IsOverResizeWidget(location_in_screen)) {
     return true;
+  }
+
+  if (CanShowLockWidget() && IsOverLockWidget(location_in_screen)) {
+    return true;
+  }
 
   if (windows_.direction == Direction::kTopBottom) {
     if (!ContainsScreenX(windows_.window1, location_in_screen.x()) ||
@@ -681,7 +771,7 @@
     }
   }
 
-  // Check whether |location_in_screen| is in the event target's resize region.
+  // Check whether `location_in_screen` is in the event target's resize region.
   // This is tricky because a window's resize region can extend outside a
   // window's bounds.
   aura::Window* target = RootWindowController::ForWindow(windows_.window1)
diff --git a/ash/wm/workspace/multi_window_resize_controller.h b/ash/wm/workspace/multi_window_resize_controller.h
index ee47795..1ec340b4 100644
--- a/ash/wm/workspace/multi_window_resize_controller.h
+++ b/ash/wm/workspace/multi_window_resize_controller.h
@@ -10,6 +10,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/wm/overview/overview_observer.h"
+#include "ash/wm/snap_group/snap_group_lock_button.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_state_observer.h"
 #include "base/scoped_multi_source_observation.h"
@@ -34,7 +35,10 @@
 
 // MultiWindowResizeController is responsible for determining and showing a
 // widget that allows resizing multiple windows at the same time.
-// MultiWindowResizeController is driven by WorkspaceEventHandler.
+// MultiWindowResizeController is driven by WorkspaceEventHandler. It can also
+// be an entry point to create or remove a snap group which is guarded by the
+// feature flag `kSnapGroup` and will only be available when the feature param
+// `kAutomaticallyLockGroup` is false.
 class ASH_EXPORT MultiWindowResizeController
     : public views::MouseWatcherListener,
       public aura::WindowObserver,
@@ -74,8 +78,11 @@
   void OnOverviewModeStarting() override;
   void OnOverviewModeEndingAnimationComplete(bool canceled) override;
 
+  SnapGroupLockButton* lock_button_for_testing() const { return lock_button_; }
+
  private:
   friend class MultiWindowResizeControllerTest;
+  friend class SnapGroupEntryPointArm2Test;
   class ResizeMouseWatcherHost;
   class ResizeView;
 
@@ -156,7 +163,7 @@
   // Returns true if the widget is showing.
   bool IsShowing() const;
 
-  // Hides the resize widget.
+  // Hides the resize widget and lock widget if it gets created.
   void Hide();
 
   // Resets the window resizer and hides the resize widget.
@@ -178,10 +185,20 @@
   gfx::Rect CalculateResizeWidgetBounds(
       const gfx::PointF& location_in_parent) const;
 
-  // Returns true if |location_in_screen| is over the resize widget.
+  // Returns the bounds for the `lock_widget_` based on the
+  // `resize_widget_bounds`.
+  gfx::Rect CalculateLockWidgetBounds(
+      const gfx::Rect& resize_widget_bounds) const;
+
+  // Returns true if `location_in_screen` is over the resize widget.
   bool IsOverResizeWidget(const gfx::Point& location_in_screen) const;
 
-  // Returns true if |location_in_screen| is over the resize windows
+  // Returns true if `location_in_screen` is over the resize widget.
+  // TODO(michelefan): combine with `IsOverResizeWidget` to create a more
+  // general function if arm2 under the `kSnapGroup` flag is enabled by default.
+  bool IsOverLockWidget(const gfx::Point& location_in_screen) const;
+
+  // Returns true if `location_in_screen` is over the resize windows
   // (or the resize widget itself).
   bool IsOverWindows(const gfx::Point& location_in_screen) const;
 
@@ -198,14 +215,24 @@
 
   std::unique_ptr<views::Widget> resize_widget_;
 
+  // The lock widget that is used to create or remove a snap group when
+  // `kAutomaticallyLockGroup` of `kSnapGroup` is false.
+  std::unique_ptr<views::Widget> lock_widget_;
+
+  // The contents view of the `lock_widget_`.
+  SnapGroupLockButton* lock_button_;
+
   // If non-null we're in a resize loop.
   std::unique_ptr<WorkspaceWindowResizer> window_resizer_;
 
   // Mouse coordinate passed to Show() in container's coodinates.
   gfx::Point show_location_in_parent_;
 
-  // Bounds the widget was last shown at in screen coordinates.
-  gfx::Rect show_bounds_in_screen_;
+  // Bounds the resize widget was last shown at in screen coordinates.
+  gfx::Rect resize_widget_show_bounds_in_screen_;
+
+  // Bounds the lock widget was last shown at in screen coordinates.
+  gfx::Rect lock_widget_show_bounds_in_screen_;
 
   // Used to detect whether the mouse is over the windows. While
   // |resize_widget_| is non-NULL (ie the widget is showing) we ignore calls
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
index f419a3c..d4e2e556 100644
--- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc
+++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -69,6 +69,7 @@
 
   ~MultiWindowResizeControllerTest() override = default;
 
+  // AshTestBase:
   void SetUp() override {
     AshTestBase::SetUp();
     WorkspaceController* wc = ShellTestApi().workspace_controller();
diff --git a/base/BUILD.gn b/base/BUILD.gn
index f95986f..36efb22c3 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1497,6 +1497,7 @@
   deps = [
     ":message_pump_buildflags",
     "//base/allocator:buildflags",
+    "//base/allocator/partition_allocator:raw_ptr",
     "//base/third_party/double_conversion",
     "//base/third_party/dynamic_annotations",
     "//build:branding_buildflags",
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index 56b26cd..76023f6 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -18,8 +18,6 @@
     "USE_ALLOCATOR_SHIM=$use_allocator_shim",
 
     "USE_PARTITION_ALLOC_AS_GWP_ASAN_STORE=$enable_backup_ref_ptr_support",
-
-    "FORCE_ENABLE_RAW_PTR_EXCLUSION=$force_enable_raw_ptr_exclusion",
   ]
 }
 
diff --git a/base/allocator/allocator.gni b/base/allocator/allocator.gni
index cf0785b..a25da86 100644
--- a/base/allocator/allocator.gni
+++ b/base/allocator/allocator.gni
@@ -12,10 +12,6 @@
 declare_args() {
   # Causes all the allocations to be routed via allocator_shim.cc.
   use_allocator_shim = use_allocator_shim_default
-
-  # RAW_PTR_EXCLUSION macro is disabled on official builds because it increased
-  # binary size. This flag can be used to enable it for official builds too.
-  force_enable_raw_ptr_exclusion = false
 }
 
 assert(
diff --git a/base/allocator/partition_allocator/BUILD.gn b/base/allocator/partition_allocator/BUILD.gn
index 0fd73aa2..a6f2b1a 100644
--- a/base/allocator/partition_allocator/BUILD.gn
+++ b/base/allocator/partition_allocator/BUILD.gn
@@ -367,6 +367,14 @@
   }
 }
 
+source_set("raw_ptr") {
+  public = [ "pointers/raw_ptr_exclusion.h" ]
+  if (use_partition_alloc) {
+    public_deps = [ ":partition_alloc" ]
+  }
+  deps = [ ":buildflags" ]
+}
+
 buildflag_header("partition_alloc_buildflags") {
   header = "partition_alloc_buildflags.h"
 
@@ -397,6 +405,8 @@
     "USE_HOOKABLE_RAW_PTR=$use_hookable_raw_ptr",
     "ENABLE_GWP_ASAN_SUPPORT=$_enable_gwp_asan_support",
 
+    "FORCE_ENABLE_RAW_PTR_EXCLUSION=$force_enable_raw_ptr_exclusion",
+
     # Not to be used directly - instead use
     # PA_CONFIG(ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
     "ENABLE_MTE_CHECKED_PTR_SUPPORT=$enable_mte_checked_ptr_support",
diff --git a/base/allocator/partition_allocator/partition_alloc.gni b/base/allocator/partition_allocator/partition_alloc.gni
index cc6855a..31e7f6cd 100644
--- a/base/allocator/partition_allocator/partition_alloc.gni
+++ b/base/allocator/partition_allocator/partition_alloc.gni
@@ -69,6 +69,10 @@
       use_partition_alloc && enable_backup_ref_ptr_support_default
   enable_mte_checked_ptr_support =
       use_partition_alloc && enable_mte_checked_ptr_support_default
+
+  # RAW_PTR_EXCLUSION macro is disabled on official builds because it increased
+  # binary size. This flag can be used to enable it for official builds too.
+  force_enable_raw_ptr_exclusion = false
 }
 
 assert(!(enable_backup_ref_ptr_support && enable_mte_checked_ptr_support),
diff --git a/base/allocator/partition_allocator/pointers/raw_ptr_exclusion.h b/base/allocator/partition_allocator/pointers/raw_ptr_exclusion.h
new file mode 100644
index 0000000..dc94d6b
--- /dev/null
+++ b/base/allocator/partition_allocator/pointers/raw_ptr_exclusion.h
@@ -0,0 +1,37 @@
+// 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 BASE_ALLOCATOR_PARTITION_ALLOCATOR_POINTERS_RAW_PTR_EXCLUSION_H_
+#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_POINTERS_RAW_PTR_EXCLUSION_H_
+
+// This header will be leakily included even when
+// `!use_partition_alloc`, which is okay because it's a leaf header.
+#include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"  // nogncheck
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
+#include "build/build_config.h"
+
+#if PA_HAS_ATTRIBUTE(annotate)
+#if defined(OFFICIAL_BUILD) && !BUILDFLAG(FORCE_ENABLE_RAW_PTR_EXCLUSION)
+// The annotation changed compiler output and increased binary size so disable
+// for official builds.
+// TODO(crbug.com/1320670): Remove when issue is resolved.
+#define RAW_PTR_EXCLUSION
+#else
+// Marks a field as excluded from the `raw_ptr<T>` usage enforcement via
+// Chromium Clang plugin.
+//
+// Example:
+//     RAW_PTR_EXCLUSION Foo* foo_;
+//
+// `RAW_PTR_EXCLUSION` should be avoided, as exclusions makes it significantly
+// easier for any bug involving the pointer to become a security vulnerability.
+// For additional guidance please see the "When to use raw_ptr<T>" section of
+// `//base/memory/raw_ptr.md`.
+#define RAW_PTR_EXCLUSION __attribute__((annotate("raw_ptr_exclusion")))
+#endif
+#else
+#define RAW_PTR_EXCLUSION
+#endif
+
+#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_POINTERS_RAW_PTR_EXCLUSION_H_
diff --git a/base/memory/platform_shared_memory_region_win.cc b/base/memory/platform_shared_memory_region_win.cc
index bdf62a3e..e38701524 100644
--- a/base/memory/platform_shared_memory_region_win.cc
+++ b/base/memory/platform_shared_memory_region_win.cc
@@ -14,14 +14,9 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/process/process_handle.h"
-#include "base/rand_util.h"
 #include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/windows_version.h"
 
-namespace base {
-namespace subtle {
+namespace base::subtle {
 
 namespace {
 
@@ -216,18 +211,6 @@
   }
 
   std::u16string name;
-  if (win::GetVersion() < win::Version::WIN8_1) {
-    // Windows < 8.1 ignores DACLs on certain unnamed objects (like shared
-    // sections). So, we generate a random name when we need to enforce
-    // read-only.
-    uint64_t rand_values[4];
-    RandBytes(&rand_values, sizeof(rand_values));
-    name = ASCIIToUTF16(StringPrintf("CrSharedMem_%016llx%016llx%016llx%016llx",
-                                     rand_values[0], rand_values[1],
-                                     rand_values[2], rand_values[3]));
-    DCHECK(!name.empty());
-  }
-
   SECURITY_ATTRIBUTES sa = {sizeof(sa), &sd, FALSE};
   // Ask for the file mapping with reduced permisions to avoid passing the
   // access control permissions granted by default into unpriviledged process.
@@ -284,5 +267,4 @@
     const UnguessableToken& guid)
     : handle_(std::move(handle)), mode_(mode), size_(size), guid_(guid) {}
 
-}  // namespace subtle
-}  // namespace base
+}  // namespace base::subtle
diff --git a/base/memory/raw_ptr_exclusion.h b/base/memory/raw_ptr_exclusion.h
index 9a1bfb8..3ce1d60 100644
--- a/base/memory/raw_ptr_exclusion.h
+++ b/base/memory/raw_ptr_exclusion.h
@@ -1,35 +1,13 @@
-// Copyright 2022 The Chromium Authors
+// 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_MEMORY_RAW_PTR_EXCLUSION_H_
 #define BASE_MEMORY_RAW_PTR_EXCLUSION_H_
 
-#include "base/allocator/buildflags.h"
-#include "base/compiler_specific.h"
-#include "build/build_config.h"
-
-#if HAS_ATTRIBUTE(annotate)
-#if defined(OFFICIAL_BUILD) && !BUILDFLAG(FORCE_ENABLE_RAW_PTR_EXCLUSION)
-// The annotation changed compiler output and increased binary size so disable
-// for official builds.
-// TODO(crbug.com/1320670): Remove when issue is resolved.
-#define RAW_PTR_EXCLUSION
-#else
-// Marks a field as excluded from the `raw_ptr<T>` usage enforcement via
-// Chromium Clang plugin.
-//
-// Example:
-//     RAW_PTR_EXCLUSION Foo* foo_;
-//
-// `RAW_PTR_EXCLUSION` should be avoided, as exclusions makes it significantly
-// easier for any bug involving the pointer to become a security vulnerability.
-// For additional guidance please see the "When to use raw_ptr<T>" section of
-// `//base/memory/raw_ptr.md`.
-#define RAW_PTR_EXCLUSION __attribute__((annotate("raw_ptr_exclusion")))
-#endif
-#else
-#define RAW_PTR_EXCLUSION
-#endif
+// Although `raw_ptr` is part of the standalone PA distribution, it is
+// easier to use the shorter path in `//base/memory`. We retain this
+// facade header for ease of typing.
+#include "base/allocator/partition_allocator/pointers/raw_ptr_exclusion.h"  // IWYU pragma: export
 
 #endif  // BASE_MEMORY_RAW_PTR_EXCLUSION_H_
diff --git a/base/win/scoped_handle_unittest.cc b/base/win/scoped_handle_unittest.cc
index 10368896..d6f74e0 100644
--- a/base/win/scoped_handle_unittest.cc
+++ b/base/win/scoped_handle_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/test/multiprocess_test.h"
 #include "base/test/test_timeouts.h"
 #include "base/win/scoped_handle.h"
-#include "base/win/windows_version.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/multiprocess_func_list.h"
@@ -36,18 +35,6 @@
 #endif  // defined(NDEBUG) && defined(OFFICIAL_BUILD)
 }
 
-// Death tests don't seem to work on Windows 7 32-bit native with hooks enabled.
-bool DoDeathTestsWork() {
-#if defined(ARCH_CPU_32_BITS)
-    const auto* os_info = base::win::OSInfo::GetInstance();
-    if (os_info->version() <= base::win::Version::WIN7 &&
-        os_info->IsWowDisabled()) {
-      return false;
-    }
-#endif  // defined(ARCH_CPU_32_BITS)
-    return true;
-}
-
 }  // namespace
 
 namespace testing {
@@ -83,9 +70,6 @@
 }
 
 TEST_F(ScopedHandleDeathTest, HandleVerifierTrackedHasBeenClosed) {
-  // This test is only valid if hooks are enabled.
-  if (!DoDeathTestsWork())
-    return;
   HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
   ASSERT_NE(HANDLE(nullptr), handle);
   using NtCloseFunc = decltype(&::NtClose);
@@ -104,10 +88,6 @@
 }
 
 TEST_F(ScopedHandleDeathTest, HandleVerifierCloseTrackedHandle) {
-  // This test is only valid if hooks are enabled.
-  if (!DoDeathTestsWork())
-    return;
-
   ASSERT_DEATH(
       {
         HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
@@ -130,9 +110,6 @@
 }
 
 TEST_F(ScopedHandleDeathTest, HandleVerifierDoubleTracking) {
-  if (!DoDeathTestsWork())
-    return;
-
   HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
   ASSERT_NE(HANDLE(nullptr), handle);
 
@@ -143,9 +120,6 @@
 }
 
 TEST_F(ScopedHandleDeathTest, HandleVerifierWrongOwner) {
-  if (!DoDeathTestsWork())
-    return;
-
   HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
   ASSERT_NE(HANDLE(nullptr), handle);
 
@@ -161,9 +135,6 @@
 }
 
 TEST_F(ScopedHandleDeathTest, HandleVerifierUntrackedHandle) {
-  if (!DoDeathTestsWork())
-    return;
-
   HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
   ASSERT_NE(HANDLE(nullptr), handle);
 
diff --git a/base/win/shortcut_unittest.cc b/base/win/shortcut_unittest.cc
index 8025079..258dfad 100644
--- a/base/win/shortcut_unittest.cc
+++ b/base/win/shortcut_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/test/test_file_util.h"
 #include "base/test/test_shortcut_win.h"
 #include "base/win/scoped_com_initializer.h"
-#include "base/win/windows_version.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -94,11 +93,6 @@
 }  // namespace
 
 TEST_F(ShortcutTest, CreateAndResolveShortcutProperties) {
-  // This test is extremely flaky on Win7, so disable.
-  // TODO(crbug.com/1264563): Investigate why it's so flaky on Win7 bots.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   // Test all properties.
   FilePath file_1(temp_dir_.GetPath().Append(FILE_PATH_LITERAL("Link1.lnk")));
   ASSERT_TRUE(CreateOrUpdateShortcutLink(file_1, link_properties_,
@@ -146,10 +140,6 @@
 }
 
 TEST_F(ShortcutTest, CreateAndResolveShortcut) {
-  // TODO(crbug.com/1264563): Disabled on Win7 bots for being flaky.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   ShortcutProperties only_target_properties;
   only_target_properties.set_target(link_properties_.target);
 
@@ -165,10 +155,6 @@
 }
 
 TEST_F(ShortcutTest, ResolveShortcutWithArgs) {
-  // TODO(crbug.com/1264563): Disabled on Win7 bots for being flaky.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          ShortcutOperation::kCreateAlways));
 
@@ -183,10 +169,6 @@
 }
 
 TEST_F(ShortcutTest, CreateShortcutWithOnlySomeProperties) {
-  // This test is extremely flaky on Win7, so disable.
-  // TODO(crbug.com/1291225): Investigate why it's so flaky on Win7 bots.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
   ShortcutProperties target_and_args_properties;
   target_and_args_properties.set_target(link_properties_.target);
   target_and_args_properties.set_arguments(link_properties_.arguments);
@@ -198,9 +180,6 @@
 }
 
 TEST_F(ShortcutTest, CreateShortcutVerifyProperties) {
-  // TODO(crbug.com/1264563) Flaky on Win 7.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          ShortcutOperation::kCreateAlways));
 
@@ -208,9 +187,6 @@
 }
 
 TEST_F(ShortcutTest, UpdateShortcutVerifyPropertiess) {
-  // TODO(crbug.com/1264563) Flaky on Win 7.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          ShortcutOperation::kCreateAlways));
 
@@ -221,11 +197,6 @@
 }
 
 TEST_F(ShortcutTest, UpdateShortcutUpdateOnlyTargetAndResolve) {
-  // This test is extremely flaky on Win7, so disable.
-  // TODO(crbug.com/1264563): Investigate why it's so flaky on Win7 bots.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          ShortcutOperation::kCreateAlways));
 
@@ -249,11 +220,6 @@
 }
 
 TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) {
-  // This test is extremely flaky on Win7, so disable.
-  // TODO(crbug.com/1264563): Investigate why it's so flaky on Win7 bots.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          ShortcutOperation::kCreateAlways));
 
@@ -269,11 +235,6 @@
 }
 
 TEST_F(ShortcutTest, UpdateShortcutRemoveDualMode) {
-  // This test is extremely flaky on Win7, so disable.
-  // TODO(crbug.com/1264563): Investigate why it's so flaky on Win7 bots.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_2_,
                                          ShortcutOperation::kCreateAlways));
 
@@ -290,11 +251,6 @@
 }
 
 TEST_F(ShortcutTest, UpdateShortcutClearArguments) {
-  // This test is extremely flaky on Win7, so disable.
-  // TODO(crbug.com/1264563): Investigate why it's so flaky on Win7 bots.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          ShortcutOperation::kCreateAlways));
 
@@ -316,11 +272,6 @@
 }
 
 TEST_F(ShortcutTest, ReplaceShortcutAllProperties) {
-  // This test is extremely flaky on Win7, so disable.
-  // TODO(crbug.com/1264563): Investigate why it's so flaky on Win7 bots.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          ShortcutOperation::kCreateAlways));
 
@@ -331,11 +282,6 @@
 }
 
 TEST_F(ShortcutTest, ReplaceShortcutSomeProperties) {
-  // This test is extremely flaky on Win7, so disable.
-  // TODO(crbug.com/1264563): Investigate why it's so flaky on Win7 bots.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          ShortcutOperation::kCreateAlways));
 
@@ -365,11 +311,6 @@
 // Test that the old arguments remain on the replaced shortcut when not
 // otherwise specified.
 TEST_F(ShortcutTest, ReplaceShortcutKeepOldArguments) {
-  // This test is extremely flaky on Win7, so disable.
-  // TODO(crbug.com/1264563): Investigate why it's so flaky on Win7 bots.
-  if (base::win::OSInfo::GetInstance()->version() <= base::win::Version::WIN7)
-    GTEST_SKIP() << "Skipping test for win7";
-
   ASSERT_TRUE(CreateOrUpdateShortcutLink(link_file_, link_properties_,
                                          ShortcutOperation::kCreateAlways));
 
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index b1b2f55..13d8a98 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -101,11 +101,9 @@
   return PowerDeterminePlatformRoleEx(POWER_PLATFORM_ROLE_V2);
 }
 
-// Method used for Windows 8.1 and later.
-// Since we support versions earlier than 8.1, we must dynamically load this
-// function from user32.dll, so it won't fail to load in runtime. For earlier
-// Windows versions GetProcAddress will return null and report failure so that
-// callers can fall back on the deprecated SetProcessDPIAware.
+// Because we used to support versions earlier than 8.1, we dynamically load
+// this function from user32.dll, so it won't fail to load in runtime.
+// TODO(https://crbug.com/1408307): Call SetProcessDpiAwareness directly.
 bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) {
   if (!IsUser32AndGdi32Available())
     return false;
@@ -126,9 +124,8 @@
     return false;
   }
 
-  DCHECK_LT(GetVersion(), Version::WIN8_1) << "SetProcessDpiAwarenessInternal "
-                                              "should be available on all "
-                                              "platforms >= Windows 8.1";
+  NOTREACHED() << "SetProcessDpiAwarenessInternal "
+                  "should be available on all platforms >= Windows 8.1";
   return false;
 }
 
@@ -302,13 +299,6 @@
 bool IsKeyboardPresentOnSlate(HWND hwnd, std::string* reason) {
   bool result = false;
 
-  if (GetVersion() < Version::WIN8) {
-    if (reason)
-      *reason = "Detection not supported";
-    return false;
-  }
-
-  // This function is only supported for Windows 8 and up.
   if (CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableUsbKeyboardDetect)) {
     if (reason)
@@ -554,12 +544,6 @@
 }
 
 bool IsTabletDevice(std::string* reason, HWND hwnd) {
-  if (GetVersion() < Version::WIN8) {
-    if (reason)
-      *reason = "Tablet device detection not supported below Windows 8\n";
-    return false;
-  }
-
   if (IsWindows10OrGreaterTabletMode(hwnd))
     return true;
 
@@ -577,12 +561,6 @@
   // reason is NULL.
   absl::optional<bool> ret;
 
-  if (GetVersion() < Version::WIN8) {
-    if (reason)
-      *reason = "Tablet device detection not supported below Windows 8\n";
-    return false;
-  }
-
   if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0) {
     if (reason) {
       *reason += "Device does not support touch.\n";
@@ -662,10 +640,6 @@
   static auto is_user32_and_gdi32_available = []() {
     // If win32k syscalls aren't disabled, then user32 and gdi32 are available.
 
-    // Can't disable win32k prior to windows 8.
-    if (GetVersion() < Version::WIN8)
-      return true;
-
     using GetProcessMitigationPolicyType =
         decltype(GetProcessMitigationPolicy)*;
     GetProcessMitigationPolicyType get_process_mitigation_policy_func =
@@ -774,15 +748,11 @@
   if (EnablePerMonitorV2())
     return;
 
-  // Fall back to per-monitor DPI for older versions of Win10 instead of
-  // Win8.1 since Win8.1 does not have EnableChildWindowDpiMessage,
-  // necessary for correct non-client area scaling across monitors.
-  PROCESS_DPI_AWARENESS process_dpi_awareness =
-      GetVersion() >= Version::WIN10 ? PROCESS_PER_MONITOR_DPI_AWARE
-                                     : PROCESS_SYSTEM_DPI_AWARE;
+  // Fall back to per-monitor DPI for older versions of Win10.
+  PROCESS_DPI_AWARENESS process_dpi_awareness = PROCESS_PER_MONITOR_DPI_AWARE;
   if (!SetProcessDpiAwarenessWrapper(process_dpi_awareness)) {
-    // For windows versions where SetProcessDpiAwareness is not available or
-    // failed, try its predecessor.
+    // For windows versions where SetProcessDpiAwareness fails, try its
+    // predecessor.
     BOOL result = ::SetProcessDPIAware();
     DCHECK(result) << "SetProcessDPIAware failed.";
   }
diff --git a/chrome/VERSION b/chrome/VERSION
index eb897db..c5ca429 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=111
 MINOR=0
-BUILD=5549
+BUILD=5550
 PATCH=0
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 461c083..27c818d 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
@@ -5,8 +5,13 @@
 package org.chromium.chrome.browser.customtabs.features.partialcustomtab;
 
 import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.InsetDrawable;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
 
@@ -14,8 +19,11 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 
+import org.chromium.base.SysUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
+import org.chromium.ui.base.ViewUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -30,10 +38,11 @@
     protected final boolean mIsFixedHeight;
     protected final OnResizedCallback mOnResizedCallback;
     protected final FullscreenManager mFullscreenManager;
-    protected boolean mIsTablet;
+    protected final boolean mIsTablet;
     protected final boolean mInteractWithBackground;
-
+    protected final int mCachedHandleHeight;
     protected final PartialCustomTabVersionCompat mVersionCompat;
+
     protected @Px int mDisplayHeight;
     protected @Px int mDisplayWidth;
 
@@ -57,6 +66,13 @@
     protected int mHeight;
     protected int mWidth;
 
+    protected View mToolbarView;
+    protected View mToolbarCoordinator;
+    protected int mToolbarColor;
+
+    protected int mShadowOffset;
+    protected boolean mDrawOutlineShadow;
+
     @IntDef({PartialCustomTabType.NONE, PartialCustomTabType.BOTTOM_SHEET,
             PartialCustomTabType.SIDE_SHEET, PartialCustomTabType.FULL_SIZE})
     @Retention(RetentionPolicy.SOURCE)
@@ -83,6 +99,10 @@
 
         mFullscreenManager = fullscreenManager;
         mFullscreenManager.addObserver(this);
+
+        mDrawOutlineShadow = SysUtils.isLowEndDevice();
+        mCachedHandleHeight =
+                mActivity.getResources().getDimensionPixelSize(R.dimen.custom_tabs_handle_height);
     }
 
     @Override
@@ -101,6 +121,16 @@
         mFullscreenManager.removeObserver(this);
     }
 
+    @Override
+    public void onToolbarInitialized(
+            View coordinatorView, CustomTabToolbar toolbar, @Px int toolbarCornerRadius) {
+        mToolbarCoordinator = coordinatorView;
+        mToolbarView = toolbar;
+        mToolbarColor = toolbar.getBackground().getColor();
+
+        roundCorners(coordinatorView, toolbar, toolbarCornerRadius);
+    }
+
     @PartialCustomTabType
     public abstract int getStrategyType();
 
@@ -108,8 +138,16 @@
 
     protected abstract void updatePosition();
 
+    protected abstract int getHandleHeight();
+
     protected abstract boolean isFullHeight();
 
+    protected abstract void adjustCornerRadius(GradientDrawable d, int radius);
+
+    protected abstract void setTopMargins(int shadowOffset, int handleOffset);
+
+    protected abstract boolean shouldHaveNoShadowOffset();
+
     protected boolean canInteractWithBackground() {
         return mInteractWithBackground;
     }
@@ -144,4 +182,54 @@
             dragHandlebar.setVisibility(dragHandlebarVisibility);
         }
     }
+
+    protected void updateShadowOffset() {
+        if (isFullHeight() || mDrawOutlineShadow || shouldHaveNoShadowOffset()) {
+            mShadowOffset = 0;
+        } else {
+            mShadowOffset = mActivity.getResources().getDimensionPixelSize(
+                    R.dimen.custom_tabs_shadow_offset);
+        }
+        setTopMargins(mShadowOffset, getHandleHeight() + mShadowOffset);
+        ViewUtils.requestLayout(
+                mToolbarCoordinator, "PartialCustomTabBaseStrategy.updateShadowOffset");
+    }
+
+    protected void roundCorners(
+            View coordinator, CustomTabToolbar toolbar, @Px int toolbarCornerRadius) {
+        // Inflate the handle View.
+        ViewStub handleViewStub = mActivity.findViewById(R.id.custom_tabs_handle_view_stub);
+        handleViewStub.inflate();
+        View handleView = mActivity.findViewById(R.id.custom_tabs_handle_view);
+        handleView.setElevation(
+                mActivity.getResources().getDimensionPixelSize(R.dimen.custom_tabs_elevation));
+        updateShadowOffset();
+
+        GradientDrawable cctBackground = (GradientDrawable) handleView.getBackground();
+        adjustCornerRadius(cctBackground, toolbarCornerRadius);
+        handleView.setBackground(cctBackground);
+
+        // Inner frame |R.id.drag_bar| is used for setting background color to match that of
+        // the toolbar. Outer frame |R.id.custom_tabs_handle_view| is not suitable since it
+        // covers the entire client area for rendering outline shadow around the CCT.
+        View dragBar = handleView.findViewById(R.id.drag_bar);
+        GradientDrawable dragBarBackground = (GradientDrawable) dragBar.getBackground();
+        adjustCornerRadius(dragBarBackground, toolbarCornerRadius);
+        if (mDrawOutlineShadow) {
+            int width = mActivity.getResources().getDimensionPixelSize(
+                    R.dimen.custom_tabs_outline_width);
+            cctBackground.setStroke(width, toolbar.getToolbarHairlineColor(mToolbarColor));
+
+            // We need an inset to make the outline shadow visible.
+            dragBar.setBackground(new InsetDrawable(dragBarBackground, width, width, width, 0));
+        } else {
+            dragBar.setBackground(dragBarBackground);
+        }
+
+        // Pass the drag bar portion to CustomTabToolbar for background color management.
+        toolbar.setHandleBackground(dragBarBackground);
+
+        // Having the transparent background is necessary for the shadow effect.
+        mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabHeightStrategy.java
index 1056832..4376c8c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabHeightStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/partialcustomtab/PartialCustomTabHeightStrategy.java
@@ -12,16 +12,12 @@
 import android.animation.ValueAnimator;
 import android.app.Activity;
 import android.content.res.Configuration;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.InsetDrawable;
 import android.os.Build;
 import android.os.Handler;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.animation.AccelerateInterpolator;
@@ -37,7 +33,6 @@
 import androidx.swiperefreshlayout.widget.CircularProgressDrawable;
 
 import org.chromium.base.MathUtils;
-import org.chromium.base.SysUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
@@ -48,7 +43,6 @@
 import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.ui.base.ViewUtils;
 import org.chromium.ui.util.ColorUtils;
 
 import java.lang.annotation.Retention;
@@ -92,12 +86,9 @@
     }
 
     private final AnimatorListener mSpinnerFadeoutAnimatorListener;
-    private final int mCachedHandleHeight;
 
     private @Px int mFullyExpandedAdjustmentHeight;
     private TabAnimator mTabAnimator;
-    private int mShadowOffset;
-    private boolean mDrawOutlineShadow;
     private BooleanSupplier mIsFullscreen;
 
     private @HeightStatus int mStatus = HeightStatus.INITIAL_HEIGHT;
@@ -110,9 +101,6 @@
     private ImageView mSpinnerView;
     private LinearLayout mNavbar;
     private CircularProgressDrawable mSpinner;
-    private View mToolbarView;
-    private View mToolbarCoordinator;
-    private int mToolbarColor;
     private Runnable mSoftKeyboardRunnable;
     private boolean mStopShowingSpinner;
     private boolean mRestoreAfterFindPage;
@@ -154,9 +142,6 @@
 
         mOrientation = mActivity.getResources().getConfiguration().orientation;
         mIsInMultiWindowMode = MultiWindowUtils.getInstance().isInMultiWindowMode(mActivity);
-        mDrawOutlineShadow = SysUtils.isLowEndDevice();
-        mCachedHandleHeight =
-                mActivity.getResources().getDimensionPixelSize(R.dimen.custom_tabs_handle_height);
         mSpinnerFadeoutAnimatorListener = new AnimatorListener() {
             @Override
             public void onAnimationStart(Animator animator) {}
@@ -174,7 +159,7 @@
         mPositionUpdater = mVersionCompat::updatePosition;
 
         mIsFullscreen = fullscreenManager::getPersistentFullscreenMode;
-        mIsTablet = isTablet;
+
         mHeight = MATCH_PARENT;
         mWidth = MATCH_PARENT;
     }
@@ -267,10 +252,8 @@
     @Override
     public void onToolbarInitialized(
             View coordinatorView, CustomTabToolbar toolbar, @Px int toolbarCornerRadius) {
-        mToolbarCoordinator = coordinatorView;
-        mToolbarView = toolbar;
-        mToolbarColor = toolbar.getBackground().getColor();
-        roundCorners(coordinatorView, toolbar, toolbarCornerRadius);
+        super.onToolbarInitialized(coordinatorView, toolbar, toolbarCornerRadius);
+
         toolbar.setHandleStrategy(new PartialCustomTabHandleStrategy(
                 mActivity, this::isFullHeight, () -> mStatus, this));
         updateDragBarVisibility();
@@ -315,45 +298,8 @@
         updateWindowPos(value, false);
     }
 
-    private void roundCorners(
-            View coordinator, CustomTabToolbar toolbar, @Px int toolbarCornerRadius) {
-        // Inflate the handle View.
-        ViewStub handleViewStub = mActivity.findViewById(R.id.custom_tabs_handle_view_stub);
-        handleViewStub.inflate();
-        View handleView = mActivity.findViewById(R.id.custom_tabs_handle_view);
-        handleView.setElevation(
-                mActivity.getResources().getDimensionPixelSize(R.dimen.custom_tabs_elevation));
-        updateShadowOffset();
-
-        GradientDrawable cctBackground = (GradientDrawable) handleView.getBackground();
-        adjustCornerRadius(cctBackground, toolbarCornerRadius);
-        handleView.setBackground(cctBackground);
-
-        // Inner frame |R.id.drag_bar| is used for setting background color to match that of
-        // the toolbar. Outer frame |R.id.custom_tabs_handle_view| is not suitable since it
-        // covers the entire client area for rendering outline shadow around the CCT.
-        View dragBar = handleView.findViewById(R.id.drag_bar);
-        GradientDrawable dragBarBackground = (GradientDrawable) dragBar.getBackground();
-        adjustCornerRadius(dragBarBackground, toolbarCornerRadius);
-        if (mDrawOutlineShadow) {
-            int width = mActivity.getResources().getDimensionPixelSize(
-                    R.dimen.custom_tabs_outline_width);
-            cctBackground.setStroke(width, toolbar.getToolbarHairlineColor(mToolbarColor));
-
-            // We need an inset to make the outline shadow visible.
-            dragBar.setBackground(new InsetDrawable(dragBarBackground, width, width, width, 0));
-        } else {
-            dragBar.setBackground(dragBarBackground);
-        }
-
-        // Pass the drag bar portion to CustomTabToolbar for background color management.
-        toolbar.setHandleBackground(dragBarBackground);
-
-        // Having the transparent background is necessary for the shadow effect.
-        mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
-    }
-
-    private static void adjustCornerRadius(GradientDrawable d, int radius) {
+    @Override
+    protected void adjustCornerRadius(GradientDrawable d, int radius) {
         d.mutate();
         d.setCornerRadii(new float[] {radius, radius, radius, radius, 0, 0, 0, 0});
     }
@@ -472,19 +418,8 @@
                 /*dragHandlebarVisibility*/ isFixedHeight() ? View.GONE : View.VISIBLE);
     }
 
-    private void updateShadowOffset() {
-        if (isFullHeight() || mDrawOutlineShadow || mStatus == HeightStatus.TOP) {
-            mShadowOffset = 0;
-        } else {
-            mShadowOffset = mActivity.getResources().getDimensionPixelSize(
-                    R.dimen.custom_tabs_shadow_offset);
-        }
-        setTopMargins(mShadowOffset, getHandleHeight() + mShadowOffset);
-        ViewUtils.requestLayout(
-                mToolbarCoordinator, "PartialCustomTabHeightStrategy.updateShadowOffet");
-    }
-
-    private void setTopMargins(int shadowOffset, int handleOffset) {
+    @Override
+    protected void setTopMargins(int shadowOffset, int handleOffset) {
         View handleView = mActivity.findViewById(R.id.custom_tabs_handle_view);
         ViewGroup.MarginLayoutParams lp =
                 (ViewGroup.MarginLayoutParams) handleView.getLayoutParams();
@@ -496,11 +431,17 @@
         mlp.setMargins(0, handleOffset, 0, 0);
     }
 
-    private int getHandleHeight() {
+    @Override
+    protected int getHandleHeight() {
         return isFullHeight() ? 0 : mCachedHandleHeight;
     }
 
     @Override
+    protected boolean shouldHaveNoShadowOffset() {
+        return mStatus == HeightStatus.TOP;
+    }
+
+    @Override
     protected boolean isFullHeight() {
         return isLandscape() || MultiWindowUtils.getInstance().isInMultiWindowMode(mActivity);
     }
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 ccb00bbc..c73f5c7 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
@@ -10,8 +10,10 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.app.Activity;
+import android.graphics.drawable.GradientDrawable;
 import android.view.Gravity;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.animation.AccelerateInterpolator;
@@ -19,6 +21,7 @@
 import androidx.annotation.Px;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 
 /**
@@ -71,6 +74,23 @@
     }
 
     @Override
+    public void onToolbarInitialized(
+            View coordinatorView, CustomTabToolbar toolbar, @Px int toolbarCornerRadius) {
+        super.onToolbarInitialized(coordinatorView, toolbar, toolbarCornerRadius);
+
+        toolbar.setHandleStrategy(null);
+        updateDragBarVisibility(/*dragHandlebarVisibility*/ View.GONE);
+    }
+
+    @Override
+    protected int getHandleHeight() {
+        // TODO(crbug.com/1408288) by default the side-sheet will have no round corners so this will
+        // just return 0. We will implement the handle height logic as part of adding customization
+        // support.
+        return 0;
+    }
+
+    @Override
     protected boolean isFullHeight() {
         return false;
     }
@@ -80,10 +100,36 @@
         if (mActivity.findViewById(android.R.id.content) == null) return;
 
         initializeSize();
-        // TODO(crbug.com/1406102): Update shadow offset
+        updateShadowOffset();
         // TODO(crbug.com/1406107): Check if we should invoke the resize callback
     }
 
+    @Override
+    protected void setTopMargins(int shadowOffset, int handleOffset) {
+        View handleView = mActivity.findViewById(org.chromium.chrome.R.id.custom_tabs_handle_view);
+        ViewGroup.MarginLayoutParams lp =
+                (ViewGroup.MarginLayoutParams) handleView.getLayoutParams();
+        lp.setMargins(shadowOffset, 0, 0, 0);
+
+        // Make enough room for the handle View.
+        int topOffset = Math.max(handleOffset - shadowOffset, 0);
+        ViewGroup.MarginLayoutParams mlp =
+                (ViewGroup.MarginLayoutParams) mToolbarCoordinator.getLayoutParams();
+        mlp.setMargins(shadowOffset, topOffset, 0, 0);
+    }
+
+    @Override
+    protected boolean shouldHaveNoShadowOffset() {
+        return false;
+    }
+
+    @Override
+    protected void adjustCornerRadius(GradientDrawable d, int radius) {
+        d.mutate();
+        // Left top corner rounded.
+        d.setCornerRadii(new float[] {radius, radius, 0, 0, 0, 0, 0, 0});
+    }
+
     private void setupCloseAnimation() {
         mCloseAnimator = new ValueAnimator();
         mCloseAnimator.addListener(new AnimatorListenerAdapter() {
@@ -124,8 +170,11 @@
     }
 
     @VisibleForTesting
-    void setMockViewForTesting() {
+    void setMockViewForTesting(View toolbar, View toolbarCoordinator) {
         mPositionUpdater = this::updatePosition;
+        mToolbarView = toolbar;
+        mToolbarCoordinator = toolbarCoordinator;
+
         onPostInflationStartup();
     }
 }
\ No newline at end of file
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 32c53a0..f6787653 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
@@ -332,7 +332,13 @@
         return false;
     }
 
-    public void setHandleStrategy(HandleStrategy strategy) {
+    public void setHandleStrategy(@Nullable HandleStrategy strategy) {
+        // When the (P)CCT does not need to be resized the handle strategy can be null.
+        if (strategy == null) {
+            mHandleStrategy = null;
+            return;
+        }
+
         mHandleStrategy = strategy;
         mHandleStrategy.setCloseClickHandler(mCloseButton::callOnClick);
         if (!CustomTabsConnection.getInstance().isDynamicFeatureEnabled(
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 5662157..267cb28 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
@@ -5,10 +5,16 @@
 package org.chromium.chrome.browser.customtabs.features.partialcustomtab;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
 
 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_LANDSCAPE;
 
+import android.view.View;
+
 import androidx.annotation.Px;
 
 import org.junit.Rule;
@@ -22,6 +28,8 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.test.util.browser.Features;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /** Tests for {@link PartialCustomTabSideSheetStrategy}. */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
@@ -37,7 +45,7 @@
         PartialCustomTabSideSheetStrategy pcct = new PartialCustomTabSideSheetStrategy(
                 mPCCTTestRule.mActivity, heightPx, false, mPCCTTestRule.mOnResizedCallback,
                 mPCCTTestRule.mFullscreenManager, false, true);
-        pcct.setMockViewForTesting();
+        pcct.setMockViewForTesting(mPCCTTestRule.mToolbarView, mPCCTTestRule.mToolbarCoordinator);
         return pcct;
     }
 
@@ -90,6 +98,59 @@
         assertEquals(DEVICE_WIDTH_LANDSCAPE / 2, mPCCTTestRule.mAttributeResults.get(0).width);
     }
 
+    @Test
+    public void onShowSoftInputRunsRunnable() {
+        mPCCTTestRule.configLandscapeMode();
+        var strategy = createPcctSideSheetStrategy(2000);
+        AtomicBoolean hasRunnableRun = new AtomicBoolean(false);
+
+        strategy.onShowSoftInput(() -> { hasRunnableRun.set(true); });
+
+        assertEquals("The runnable should be run", true, hasRunnableRun.get());
+        assertTabIsAtFullLandscapeHeight();
+    }
+
+    @Test
+    public void dragHandlebarInvisible() {
+        mPCCTTestRule.configLandscapeMode();
+        createPcctSideSheetStrategy(2000);
+
+        mPCCTTestRule.verifyWindowFlagsSet();
+        assertEquals(1, mPCCTTestRule.mAttributeResults.size());
+        assertTabIsAtFullLandscapeHeight();
+        verify(mPCCTTestRule.mDragHandlebar).setVisibility(View.GONE);
+    }
+
+    @Test
+    public void noTopShadow() {
+        doReturn(47)
+                .when(mPCCTTestRule.mResources)
+                .getDimensionPixelSize(eq(org.chromium.chrome.R.dimen.custom_tabs_shadow_offset));
+
+        mPCCTTestRule.configLandscapeMode();
+        createPcctSideSheetStrategy(2000);
+
+        mPCCTTestRule.verifyWindowFlagsSet();
+        assertTabIsAtFullLandscapeHeight();
+        assertEquals("Top margin should be zero for the shadow", 0,
+                mPCCTTestRule.mLayoutParams.topMargin);
+    }
+
+    @Test
+    public void leftShadowIsVisible() {
+        doReturn(47)
+                .when(mPCCTTestRule.mResources)
+                .getDimensionPixelSize(eq(org.chromium.chrome.R.dimen.custom_tabs_shadow_offset));
+
+        mPCCTTestRule.configLandscapeMode();
+        createPcctSideSheetStrategy(2000);
+
+        mPCCTTestRule.verifyWindowFlagsSet();
+        assertTabIsAtFullLandscapeHeight();
+        assertNotEquals("Left margin should be non-zero for the shadow", 0,
+                mPCCTTestRule.mLayoutParams.leftMargin);
+    }
+
     private void assertTabIsAtFullLandscapeHeight() {
         assertEquals(
                 "Should only have one attribute result", 1, mPCCTTestRule.mAttributeResults.size());
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index bdee40d..c0f31231 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -700,6 +700,10 @@
          desc="Message shown to the user on chrome://downloads page to explain that this download is blocked because it is unwanted sofware.">
         This file may be dangerous, so Chromium has blocked it.
       </message>
+      <message name="IDS_BLOCK_REASON_PROMPT_FOR_SCANNING"
+         desc="Message shown to the user on chrome://downloads page to explain that this download is recommended to be scanned.">
+        Chromium recommends scanning this file because it may be dangerous.
+      </message>
 
       <!-- Abandon in-progress downloads confirmation dialog -->
       <if expr="not is_macosx">
diff --git a/chrome/app/chromium_strings_grd/IDS_BLOCK_REASON_PROMPT_FOR_SCANNING.png.sha1 b/chrome/app/chromium_strings_grd/IDS_BLOCK_REASON_PROMPT_FOR_SCANNING.png.sha1
new file mode 100644
index 0000000..1924cfa
--- /dev/null
+++ b/chrome/app/chromium_strings_grd/IDS_BLOCK_REASON_PROMPT_FOR_SCANNING.png.sha1
@@ -0,0 +1 @@
+7f05ba3b0edc6da809fac67cad993bdab950a343
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 128f817..fcd3102e 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2220,6 +2220,14 @@
       <message name="IDS_DOWNLOAD_TOAST_CLEARED_ALL" desc="Toast message for clearing all download entries">
         Cleared all
       </message>
+      <message name="IDS_DOWNLOAD_DEEP_SCAN"
+               desc="In the download view, the 'Scan' button when prompt for deep scan">
+        Scan
+      </message>
+      <message name="IDS_DOWNLOAD_BYPASS_DEEP_SCAN"
+               desc="In the download view, the 'Open' button when prompt for deep scan">
+        Open
+      </message>
 
 
       <!-- Download Alerts for Accessibility -->
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BYPASS_DEEP_SCAN.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BYPASS_DEEP_SCAN.png.sha1
new file mode 100644
index 0000000..bfe3d364
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BYPASS_DEEP_SCAN.png.sha1
@@ -0,0 +1 @@
+7d1282f374436706b534d1161b57edebb0371653
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_DEEP_SCAN.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_DEEP_SCAN.png.sha1
new file mode 100644
index 0000000..bfe3d364
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_DEEP_SCAN.png.sha1
@@ -0,0 +1 @@
+7d1282f374436706b534d1161b57edebb0371653
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 4585619..8f52d27 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -731,11 +731,14 @@
          desc="Message shown to the user on chrome://downloads page to explain that this download is blocked because it is malware.">
         This file is dangerous, so Chrome has blocked it.
       </message>
-
       <message name="IDS_BLOCK_REASON_UNWANTED_DOWNLOAD"
          desc="Message shown to the user on chrome://downloads page to explain that this download is blocked because it is unwanted sofware.">
         This file may be dangerous, so Chrome has blocked it.
       </message>
+      <message name="IDS_BLOCK_REASON_PROMPT_FOR_SCANNING"
+         desc="Message shown to the user on chrome://downloads page to explain that this download is recommended to be scanned.">
+        Chrome recommends scanning this file because it may be dangerous.
+      </message>
 
       <!-- Abandon in-progress downloads confirmation dialog -->
       <if expr="not is_macosx">
diff --git a/chrome/app/google_chrome_strings_grd/IDS_BLOCK_REASON_PROMPT_FOR_SCANNING.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_BLOCK_REASON_PROMPT_FOR_SCANNING.png.sha1
new file mode 100644
index 0000000..9bb0d67
--- /dev/null
+++ b/chrome/app/google_chrome_strings_grd/IDS_BLOCK_REASON_PROMPT_FOR_SCANNING.png.sha1
@@ -0,0 +1 @@
+0692c62f68c706212fc1672ae01239563a6e97cb
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b3b825e..39946af 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4603,6 +4603,8 @@
   if (is_chromeos_ash) {
     assert(enable_system_notifications)
     sources += [
+      "apps/app_deduplication_service/app_deduplication_cache.cc",
+      "apps/app_deduplication_service/app_deduplication_cache.h",
       "apps/app_deduplication_service/app_deduplication_mapper.cc",
       "apps/app_deduplication_service/app_deduplication_mapper.h",
       "apps/app_deduplication_service/app_deduplication_server_connector.cc",
@@ -5239,6 +5241,8 @@
   if (is_chromeos_lacros) {
     assert(enable_system_notifications)
     sources += [
+      "accessibility/live_caption_surface.cc",
+      "accessibility/live_caption_surface.h",
       "apps/digital_goods/digital_goods_factory_stub.cc",
       "apps/digital_goods/digital_goods_factory_stub.h",
       "apps/digital_goods/digital_goods_lacros.cc",
@@ -5349,6 +5353,7 @@
       "lacros/screen_orientation_delegate_lacros.h",
       "lacros/standalone_browser_test_controller.cc",
       "lacros/standalone_browser_test_controller.h",
+      "lacros/sync/crosapi_session_sync_notifier.h",
       "lacros/sync/sync_crosapi_manager_lacros.cc",
       "lacros/sync/sync_crosapi_manager_lacros.h",
       "lacros/sync/sync_explicit_passphrase_client_lacros.cc",
diff --git a/chrome/browser/accessibility/DEPS b/chrome/browser/accessibility/DEPS
index ee2809f..749bbd4 100644
--- a/chrome/browser/accessibility/DEPS
+++ b/chrome/browser/accessibility/DEPS
@@ -2,4 +2,6 @@
   "+components/live_caption",
   "+components/soda",
   "+services/image_annotation",
+  "+testing/gmock",
+  "+testing/gtest",
 ]
diff --git a/chrome/browser/accessibility/live_caption_surface.cc b/chrome/browser/accessibility/live_caption_surface.cc
new file mode 100644
index 0000000..79315e2
--- /dev/null
+++ b/chrome/browser/accessibility/live_caption_surface.cc
@@ -0,0 +1,120 @@
+// 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/accessibility/live_caption_surface.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/functional/callback_forward.h"
+#include "base/unguessable_token.h"
+#include "build/build_config.h"
+#include "chrome/browser/accessibility/caption_bubble_context_browser.h"
+#include "chrome/browser/accessibility/live_caption_controller_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "components/live_caption/live_caption_controller.h"
+#include "components/live_caption/views/caption_bubble_model.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/page.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/views/widget/widget.h"
+
+namespace captions {
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(LiveCaptionSurface);
+
+// static
+LiveCaptionSurface* LiveCaptionSurface::GetOrCreateForWebContents(
+    content::WebContents* web_contents) {
+  // No-op if a surface is already attached.
+  CreateForWebContents(web_contents);
+
+  return FromWebContents(web_contents);
+}
+
+LiveCaptionSurface::LiveCaptionSurface(content::WebContents* web_contents)
+    : content::WebContentsUserData<LiveCaptionSurface>(*web_contents),
+      content::WebContentsObserver(web_contents),
+      session_id_(base::UnguessableToken::Create()) {}
+
+LiveCaptionSurface::~LiveCaptionSurface() = default;
+
+void LiveCaptionSurface::BindToSurfaceClient(
+    mojo::PendingReceiver<media::mojom::SpeechRecognitionSurface> receiver,
+    mojo::PendingRemote<media::mojom::SpeechRecognitionSurfaceClient> remote) {
+  receivers_.Add(this, std::move(receiver));
+  clients_.Add(std::move(remote));
+}
+
+void LiveCaptionSurface::Activate() {
+  if (!web_contents()) {
+    return;
+  }
+
+  // Activate the web contents and the browser window that the web contents is
+  // in. Order matters: web contents needs to be active in order for the widget
+  // getter to work.
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
+  if (!browser) {
+    return;
+  }
+
+  TabStripModel* tab_strip_model = browser->tab_strip_model();
+  DCHECK(tab_strip_model);
+
+  const int index = tab_strip_model->GetIndexOfWebContents(web_contents());
+  if (index == TabStripModel::kNoTab) {
+    return;
+  }
+
+  tab_strip_model->ActivateTabAt(index);
+  views::Widget* context_widget = views::Widget::GetTopLevelWidgetForNativeView(
+      web_contents()->GetNativeView());
+  if (context_widget) {
+    context_widget->Activate();
+  }
+}
+
+void LiveCaptionSurface::GetBounds(GetBoundsCallback callback) {
+  if (!web_contents()) {
+    std::move(callback).Run(absl::nullopt);
+    return;
+  }
+
+  views::Widget* context_widget = views::Widget::GetTopLevelWidgetForNativeView(
+      web_contents()->GetNativeView());
+  if (!context_widget) {
+    std::move(callback).Run(absl::nullopt);
+    return;
+  }
+
+  std::move(callback).Run(context_widget->GetClientAreaBoundsInScreen());
+}
+
+void LiveCaptionSurface::MediaEffectivelyFullscreenChanged(
+    bool /*is_fullscreen*/) {
+  for (const auto& client : clients_) {
+    client->OnFullscreenToggled();
+  }
+}
+
+void LiveCaptionSurface::PrimaryPageChanged(content::Page& /*page*/) {
+  for (const auto& client : clients_) {
+    client->OnSessionEnded();
+  }
+}
+
+std::string LiveCaptionSurface::GetSessionId() const {
+  return session_id_.ToString();
+}
+
+}  // namespace captions
diff --git a/chrome/browser/accessibility/live_caption_surface.h b/chrome/browser/accessibility/live_caption_surface.h
new file mode 100644
index 0000000..1279f17c
--- /dev/null
+++ b/chrome/browser/accessibility/live_caption_surface.h
@@ -0,0 +1,78 @@
+// 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_ACCESSIBILITY_LIVE_CAPTION_SURFACE_H_
+#define CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_SURFACE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/unguessable_token.h"
+#include "build/build_config.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "media/mojo/mojom/speech_recognition.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
+
+namespace content {
+class Page;
+class WebContents;
+}  // namespace content
+
+namespace captions {
+
+// Represents the document as a user-facing surface that produces live captions.
+// This interface allows remote processes to manipulate the document as required
+// for live caption rendering (e.g. by bringing it into focus).
+//
+// An instance of this object is owned by a `WebContents` and its lifetime is
+// bound to the `WebContents`' lifetime. Up to one instance of this class can
+// be instantiated for a single `WebContents`.
+class LiveCaptionSurface
+    : public media::mojom::SpeechRecognitionSurface,
+      public content::WebContentsUserData<LiveCaptionSurface>,
+      public content::WebContentsObserver {
+ public:
+  LiveCaptionSurface(const LiveCaptionSurface&) = delete;
+  LiveCaptionSurface& operator=(const LiveCaptionSurface&) = delete;
+  ~LiveCaptionSurface() override;
+
+  // static
+  static LiveCaptionSurface* GetOrCreateForWebContents(
+      content::WebContents* web_contents);
+
+  // Set up coordintation with a new surface client in Ash.
+  void BindToSurfaceClient(
+      mojo::PendingReceiver<media::mojom::SpeechRecognitionSurface> receiver,
+      mojo::PendingRemote<media::mojom::SpeechRecognitionSurfaceClient> remote);
+
+  // media::mojom::SpeechRecognitionSurface:
+  void Activate() override;
+  void GetBounds(GetBoundsCallback callback) override;
+
+  // content::WebContentsObserver:
+  void MediaEffectivelyFullscreenChanged(bool is_fullscreen) override;
+  void PrimaryPageChanged(content::Page& page) override;
+
+  // Returns a unique string identifier for the current web contents.
+  std::string GetSessionId() const;
+
+ private:
+  friend content::WebContentsUserData<LiveCaptionSurface>;
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+
+  explicit LiveCaptionSurface(content::WebContents* web_contents);
+
+  const base::UnguessableToken session_id_;
+
+  mojo::ReceiverSet<media::mojom::SpeechRecognitionSurface> receivers_;
+  mojo::RemoteSet<media::mojom::SpeechRecognitionSurfaceClient> clients_;
+};
+
+}  // namespace captions
+
+#endif  // CHROME_BROWSER_ACCESSIBILITY_LIVE_CAPTION_SURFACE_H_
diff --git a/chrome/browser/accessibility/live_caption_surface_browsertest.cc b/chrome/browser/accessibility/live_caption_surface_browsertest.cc
new file mode 100644
index 0000000..66d2597
--- /dev/null
+++ b/chrome/browser/accessibility/live_caption_surface_browsertest.cc
@@ -0,0 +1,311 @@
+// 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/accessibility/live_caption_surface.h"
+
+#include "base/path_service.h"
+#include "base/test/bind.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/mojom/frame/fullscreen.mojom.h"
+#include "ui/base/page_transition_types.h"
+#include "ui/gfx/geometry/rect.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+namespace captions {
+namespace {
+
+// A WebContentsObserver that runs tasks until some media starts / stops playing
+// fullscreen.
+class ScopedFullscreenRunner : public content::WebContentsObserver {
+ public:
+  explicit ScopedFullscreenRunner(content::WebContents* web_contents)
+      : WebContentsObserver(web_contents) {}
+
+  ScopedFullscreenRunner(const ScopedFullscreenRunner&) = delete;
+  ScopedFullscreenRunner& operator=(const ScopedFullscreenRunner&) = delete;
+
+  ~ScopedFullscreenRunner() override {
+    // On destruction, wait for any fullscreen hooks to have executed. Then,
+    // allow any tasks scheduled by the hooks to complete too.
+    run_loop_.Run();
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void MediaEffectivelyFullscreenChanged(bool /*is_fullscreen*/) override {
+    run_loop_.Quit();
+  }
+
+ private:
+  base::RunLoop run_loop_;
+};
+
+// A surface client whose methods can have expectations placed on them.
+class MockSurfaceClient : public media::mojom::SpeechRecognitionSurfaceClient {
+ public:
+  MockSurfaceClient() = default;
+  ~MockSurfaceClient() override = default;
+
+  MockSurfaceClient(const MockSurfaceClient&) = delete;
+  MockSurfaceClient& operator=(const MockSurfaceClient&) = delete;
+
+  // media::mojom::SpeechRecognitionSurfaceClient:
+  MOCK_METHOD(void, OnSessionEnded, (), (override));
+  MOCK_METHOD(void, OnFullscreenToggled, (), (override));
+
+  void BindToSurface(
+      mojo::PendingReceiver<media::mojom::SpeechRecognitionSurfaceClient>
+          receiver,
+      mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> surface) {
+    receiver_.Bind(std::move(receiver));
+    surface_.Bind(std::move(surface));
+  }
+
+ private:
+  // The remote must be held somewhere even though we don't call methods on it.
+  mojo::Remote<media::mojom::SpeechRecognitionSurface> surface_;
+
+  mojo::Receiver<media::mojom::SpeechRecognitionSurfaceClient> receiver_{this};
+};
+
+class LiveCaptionSurfaceTest : public InProcessBrowserTest {
+ public:
+  LiveCaptionSurfaceTest() = default;
+  ~LiveCaptionSurfaceTest() override = default;
+
+  LiveCaptionSurfaceTest(const LiveCaptionSurfaceTest&) = delete;
+  LiveCaptionSurfaceTest& operator=(const LiveCaptionSurfaceTest&) = delete;
+
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+
+    // Load premade test pages.
+    base::FilePath test_data_dir;
+    CHECK(base::PathService::Get(content::DIR_TEST_DATA, &test_data_dir));
+    embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
+    CHECK(embedded_test_server()->Start());
+  }
+
+  // Opens a new tab and waits for it to load the given URL.
+  content::WebContents* LoadNewTab(GURL url) {
+    content::RenderFrameHost* rfh = ui_test_utils::NavigateToURLWithDisposition(
+        browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
+        ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
+    return content::WebContents::FromRenderFrameHost(rfh);
+  }
+
+  // Attaches a new surface to the given web contents and binds it to the given
+  // client.
+  LiveCaptionSurface* NewSurfaceForWebContents(
+      content::WebContents* web_contents,
+      MockSurfaceClient* mock_client) {
+    mojo::PendingReceiver<media::mojom::SpeechRecognitionSurface>
+        surface_receiver;
+    mojo::PendingRemote<media::mojom::SpeechRecognitionSurfaceClient>
+        client_remote;
+
+    mock_client->BindToSurface(client_remote.InitWithNewPipeAndPassReceiver(),
+                               surface_receiver.InitWithNewPipeAndPassRemote());
+
+    auto* surface = LiveCaptionSurface::GetOrCreateForWebContents(web_contents);
+    surface->BindToSurfaceClient(std::move(surface_receiver),
+                                 std::move(client_remote));
+
+    return surface;
+  }
+
+  const GURL kAboutBlankUrl = GURL(url::kAboutBlankURL);
+};
+
+// Test that the surface can be used to focus its tab.
+IN_PROC_BROWSER_TEST_F(LiveCaptionSurfaceTest, Activate) {
+  // Create an initial tab with a surface attached.
+  MockSurfaceClient client;
+  content::WebContents* wc_1 = LoadNewTab(kAboutBlankUrl);
+  LiveCaptionSurface* surface = NewSurfaceForWebContents(wc_1, &client);
+
+  // The initial tab should be focused.
+  EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(), wc_1);
+
+  // Create a new tab, which should start focused.
+  content::WebContents* wc_2 = LoadNewTab(kAboutBlankUrl);
+  EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(), wc_2);
+
+  // Activating the first tab via its surface should bring it into focus.
+  surface->Activate();
+  EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(), wc_1);
+}
+
+// Test that the surface correctly reports tab bounds on screen.
+IN_PROC_BROWSER_TEST_F(LiveCaptionSurfaceTest, Bounds) {
+  // Create a tab with a surface attached.
+  MockSurfaceClient client;
+  LiveCaptionSurface* surface =
+      NewSurfaceForWebContents(LoadNewTab(kAboutBlankUrl), &client);
+
+  // Callback to assign bounds to local variables.
+  const auto assign_bounds = [](gfx::Rect* d,
+                                const absl::optional<gfx::Rect>& b) {
+    ASSERT_TRUE(b.has_value());
+    *d = *b;
+  };
+
+  // Set known window bounds.
+  const gfx::Rect window_bounds_1 = gfx::Rect(10, 10, 800, 600);
+  browser()->window()->SetBounds(window_bounds_1);
+
+  // Fetch bounds using the surface.
+  gfx::Rect bounds_1;
+  surface->GetBounds(base::BindOnce(assign_bounds, &bounds_1));
+  base::RunLoop().RunUntilIdle();
+
+  // The surface should have correctly reported the window bounds.
+  EXPECT_EQ(window_bounds_1, bounds_1);
+
+  // Set new window bounds.
+  const gfx::Rect window_bounds_2 = gfx::Rect(50, 50, 800, 600);
+  browser()->window()->SetBounds(window_bounds_2);
+
+  // Fetch bounds using the surface.
+  gfx::Rect bounds_2;
+  surface->GetBounds(base::BindOnce(assign_bounds, &bounds_2));
+  base::RunLoop().RunUntilIdle();
+
+  // The surface should have correctly reported the window bounds.
+  EXPECT_EQ(window_bounds_2, bounds_2);
+}
+
+// Test that the client is informed of fullscreen changes.
+IN_PROC_BROWSER_TEST_F(LiveCaptionSurfaceTest, Fullscreen) {
+  // Load a pre-prepared page that defines JS to (un/)fullscreen the tab.
+  MockSurfaceClient client;
+  content::WebContents* web_contents =
+      LoadNewTab(embedded_test_server()->GetURL("/media/fullscreen.html"));
+  NewSurfaceForWebContents(web_contents, &client);
+
+  // We use a mock function to set up "checkpoints" by which each side effect
+  // should have occurred.
+  testing::MockFunction<void(int)> checkpointer;
+
+  {
+    testing::InSequence seq;
+
+    // Fullscreen media on the page.
+    EXPECT_CALL(client, OnFullscreenToggled());
+    EXPECT_CALL(checkpointer, Call(1));
+    {
+      ScopedFullscreenRunner runner(web_contents);
+      EXPECT_TRUE(
+          content::ExecJs(web_contents, "makeFullscreen('small_video')"));
+    }
+    checkpointer.Call(1);
+
+    // Un-fullscreen the media.
+    EXPECT_CALL(client, OnFullscreenToggled());
+    EXPECT_CALL(checkpointer, Call(2));
+    {
+      ScopedFullscreenRunner runner(web_contents);
+      EXPECT_TRUE(content::ExecJs(web_contents, "exitFullscreen()"));
+    }
+    checkpointer.Call(2);
+  }
+}
+
+// Test that the surface correctly reports session IDs.
+IN_PROC_BROWSER_TEST_F(LiveCaptionSurfaceTest, SessionIds) {
+  // Create two tabs with two surfaces.
+  MockSurfaceClient client_1, client_2;
+  LiveCaptionSurface* surface_1 =
+      NewSurfaceForWebContents(LoadNewTab(kAboutBlankUrl), &client_1);
+  LiveCaptionSurface* surface_2 =
+      NewSurfaceForWebContents(LoadNewTab(kAboutBlankUrl), &client_2);
+
+  // The session IDs of the two surfaces should be different because they
+  // represent different web contents.
+  const std::string init_id_1 = surface_1->GetSessionId();
+  EXPECT_NE("", init_id_1);
+  EXPECT_NE("", surface_2->GetSessionId());
+  EXPECT_NE(init_id_1, surface_2->GetSessionId());
+
+  // Navigating a tab shouldn't change its session ID.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kAboutBlankUrl));
+  EXPECT_EQ(init_id_1, surface_1->GetSessionId());
+}
+
+// Test that a surface reports the end of live caption sessions.
+//
+// TODO(b/266148747): this test is very-occasionaly flaky.
+IN_PROC_BROWSER_TEST_F(LiveCaptionSurfaceTest, DISABLED_Sessions) {
+  // Create two tabs with surfaces attached.
+  MockSurfaceClient client_1, client_2;
+  content::WebContents* wc_1 = LoadNewTab(kAboutBlankUrl);
+  content::WebContents* wc_2 = LoadNewTab(kAboutBlankUrl);
+  LiveCaptionSurface* surface_1 = NewSurfaceForWebContents(wc_1, &client_1);
+  NewSurfaceForWebContents(wc_2, &client_2);
+
+  // We use a mock function to set up "checkpoints" by which each side effect
+  // should have occurred.
+  testing::MockFunction<void(int)> checkpointer;
+
+  {
+    testing::InSequence seq;
+
+    // We will start by making a navigation in the focused tab. We expect this
+    // should end its session, but not the other tab's.
+
+    EXPECT_CALL(client_1, OnSessionEnded()).Times(0);
+    EXPECT_CALL(client_2, OnSessionEnded());
+    EXPECT_CALL(checkpointer, Call(1));
+
+    ASSERT_EQ(wc_2, browser()->tab_strip_model()->GetActiveWebContents());
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kAboutBlankUrl));
+    base::RunLoop().RunUntilIdle();
+    checkpointer.Call(1);
+
+    // Next we will refresh the first tab. We expect this should end its
+    // session.
+
+    EXPECT_CALL(client_1, OnSessionEnded());
+    EXPECT_CALL(checkpointer, Call(2));
+
+    surface_1->Activate();
+    ASSERT_EQ(wc_1, browser()->tab_strip_model()->GetActiveWebContents());
+
+    chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
+    content::WaitForLoadStop(wc_2);
+    base::RunLoop().RunUntilIdle();
+    checkpointer.Call(2);
+
+    // Lastly, we will navigate from the first tab. This should end the session
+    // again.
+
+    EXPECT_CALL(client_1, OnSessionEnded());
+    EXPECT_CALL(checkpointer, Call(3));
+
+    // Navigating from the first tab should end its session again.
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kAboutBlankUrl));
+    base::RunLoop().RunUntilIdle();
+    checkpointer.Call(3);
+  }
+}
+
+}  // namespace
+}  // namespace captions
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_cache.cc b/chrome/browser/apps/app_deduplication_service/app_deduplication_cache.cc
new file mode 100644
index 0000000..0149496
--- /dev/null
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_cache.cc
@@ -0,0 +1,75 @@
+// 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/apps/app_deduplication_service/app_deduplication_cache.h"
+
+#include <string>
+
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+
+namespace apps::deduplication {
+
+AppDeduplicationCache::AppDeduplicationCache(base::FilePath& path)
+    : folder_path_(path) {
+  if (!base::PathExists(folder_path_)) {
+    base::CreateDirectory(folder_path_);
+  }
+}
+
+AppDeduplicationCache::~AppDeduplicationCache() = default;
+
+bool AppDeduplicationCache::WriteDeduplicateDataToDisk(
+    const base::FilePath& deduplicate_data_path,
+    proto::DeduplicateData& data) {
+  base::File file(deduplicate_data_path,
+                  (base::File::FLAG_CREATE | base::File::FLAG_WRITE));
+
+  if (!file.IsValid() || !file.created()) {
+    LOG(ERROR) << "Failed to create deduplicate data file at "
+               << deduplicate_data_path.MaybeAsASCII();
+    return false;
+  }
+
+  std::string deduplicate_data_string;
+  data.SerializeToString(&deduplicate_data_string);
+
+  const int written = file.WriteAtCurrentPos(deduplicate_data_string.c_str(),
+                                             deduplicate_data_string.length());
+
+  if (written != static_cast<int>(deduplicate_data_string.length())) {
+    LOG(ERROR) << "Failed to write all data to deduplicate data file.";
+    base::DeleteFile(deduplicate_data_path);
+    return false;
+  }
+
+  return true;
+}
+
+absl::optional<proto::DeduplicateData>
+AppDeduplicationCache::ReadDeduplicateDataFromDisk(
+    const base::FilePath& deduplicate_data_path) {
+  std::string deduplicate_data_string;
+
+  if (!base::PathExists(deduplicate_data_path)) {
+    LOG(ERROR) << "Path to deduplicate data file does not exist.";
+    return absl::nullopt;
+  }
+
+  if (!base::ReadFileToString(deduplicate_data_path,
+                              &deduplicate_data_string)) {
+    LOG(ERROR) << "Reading deduplicate data file from disk failed.";
+    return absl::nullopt;
+  }
+
+  proto::DeduplicateData deduplicate_data;
+  if (!deduplicate_data.ParseFromString(deduplicate_data_string)) {
+    LOG(ERROR) << "Parsing proto to string failed.";
+    return absl::nullopt;
+  }
+  return deduplicate_data;
+}
+
+}  // namespace apps::deduplication
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_cache.h b/chrome/browser/apps/app_deduplication_service/app_deduplication_cache.h
new file mode 100644
index 0000000..c85f2aa
--- /dev/null
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_cache.h
@@ -0,0 +1,41 @@
+// 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_APPS_APP_DEDUPLICATION_SERVICE_APP_DEDUPLICATION_CACHE_H_
+#define CHROME_BROWSER_APPS_APP_DEDUPLICATION_SERVICE_APP_DEDUPLICATION_CACHE_H_
+
+#include "base/files/file_path.h"
+#include "chrome/browser/apps/app_deduplication_service/proto/deduplication_data.pb.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace apps::deduplication {
+
+// The AppDeduplicationCache is used to store deduplicate app data on disk and
+// read the stored data from disk. Two versions of the data will be stored to
+// the disk at a time in case reading data from the most recent version fails.
+// TODO(b/266005828): add functionality to store two versions of data.
+class AppDeduplicationCache {
+ public:
+  // `path` refers to path of the folder on disk which will store the data.
+  explicit AppDeduplicationCache(base::FilePath& path);
+  AppDeduplicationCache(const AppDeduplicationCache&) = delete;
+  AppDeduplicationCache& operator=(const AppDeduplicationCache&) = delete;
+  ~AppDeduplicationCache();
+
+  // Creates a file at given file path and stores duplicate data on disk.
+  // Returns true if all data is written successfully and false otherwise.
+  bool WriteDeduplicateDataToDisk(const base::FilePath& deduplicate_data_path,
+                                  proto::DeduplicateData& data);
+
+  // Reads and returns deduplicate data from file at `deduplicate_data_path`.
+  absl::optional<proto::DeduplicateData> ReadDeduplicateDataFromDisk(
+      const base::FilePath& deduplicate_data_path);
+
+ private:
+  base::FilePath folder_path_;
+};
+
+}  // namespace apps::deduplication
+
+#endif  // CHROME_BROWSER_APPS_APP_DEDUPLICATION_SERVICE_APP_DEDUPLICATION_CACHE_H_
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_cache_unittest.cc b/chrome/browser/apps/app_deduplication_service/app_deduplication_cache_unittest.cc
new file mode 100644
index 0000000..2a88badd
--- /dev/null
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_cache_unittest.cc
@@ -0,0 +1,85 @@
+// 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/apps/app_deduplication_service/app_deduplication_cache.h"
+
+#include <memory>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "chrome/browser/apps/app_deduplication_service/proto/deduplication_data.pb.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace apps::deduplication {
+
+class AppDeduplicationCacheTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    temp_dir_path_ = temp_dir_.GetPath().AppendASCII(
+        "app_deduplication_service/deduplication_data/");
+    cache_ = std::make_unique<AppDeduplicationCache>(temp_dir_path_);
+  }
+
+  void TearDown() override { ASSERT_TRUE(temp_dir_.Delete()); }
+
+  std::unique_ptr<AppDeduplicationCache> cache_;
+  base::FilePath temp_dir_path_;
+
+ private:
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(AppDeduplicationCacheTest, WriteAndReadDataSuccess) {
+  proto::DeduplicateData data;
+  auto* app = data.add_app_group()->add_app();
+  app->set_app_id("com.skype.raidar");
+  app->set_platform("phonehub");
+
+  const base::FilePath file_path = temp_dir_path_.AppendASCII("test.pb");
+
+  EXPECT_TRUE(cache_->WriteDeduplicateDataToDisk(file_path, data));
+
+  EXPECT_TRUE(base::PathExists(file_path));
+
+  absl::optional<proto::DeduplicateData> data_read =
+      cache_->ReadDeduplicateDataFromDisk(file_path);
+
+  EXPECT_TRUE(data_read.has_value());
+  EXPECT_EQ(data_read->app_group_size(), 1);
+
+  auto observed_app = data_read->app_group(0).app(0);
+  EXPECT_EQ(observed_app.app_id(), "com.skype.raidar");
+  EXPECT_EQ(observed_app.platform(), "phonehub");
+}
+
+TEST_F(AppDeduplicationCacheTest, WriteDataInvalidPath) {
+  proto::DeduplicateData data;
+
+  EXPECT_FALSE(cache_->WriteDeduplicateDataToDisk(
+      temp_dir_path_.AppendASCII("fake_folder").AppendASCII("test.pb"), data));
+}
+
+TEST_F(AppDeduplicationCacheTest, ReadDataInvalidPath) {
+  proto::DeduplicateData data;
+  auto* app = data.add_app_group()->add_app();
+  app->set_app_id("com.skype.raidar");
+  app->set_platform("phonehub");
+
+  EXPECT_TRUE(cache_->WriteDeduplicateDataToDisk(
+      temp_dir_path_.AppendASCII("test.pb"), data));
+
+  EXPECT_FALSE(cache_
+                   ->ReadDeduplicateDataFromDisk(
+                       temp_dir_path_.AppendASCII("fake_file.pb"))
+                   .has_value());
+}
+
+}  // namespace apps::deduplication
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 0bbac7c..645bd0e 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -3805,6 +3805,7 @@
     "//chromeos/ash/components/multidevice/logging",
     "//chromeos/ash/components/peripheral_notification",
     "//chromeos/ash/components/power",
+    "//chromeos/ash/components/standalone_browser",
     "//chromeos/ash/components/sync_wifi",
     "//chromeos/ash/components/tpm",
     "//chromeos/ash/components/tpm:buildflags",
@@ -5280,6 +5281,7 @@
     "sync/sync_explicit_passphrase_client_ash_unittest.cc",
     "sync/sync_mojo_service_ash_unittest.cc",
     "sync/sync_user_settings_client_ash_unittest.cc",
+    "sync/synced_session_client_ash_unittest.cc",
     "system/automatic_reboot_manager_unittest.cc",
     "system/device_disabling_manager_unittest.cc",
     "system/procfs_util_unittest.cc",
diff --git a/chrome/browser/ash/app_list/search/system_info/battery_health.h b/chrome/browser/ash/app_list/search/system_info/battery_health.h
new file mode 100644
index 0000000..d90c5ee
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/system_info/battery_health.h
@@ -0,0 +1,43 @@
+// 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_ASH_APP_LIST_SEARCH_SYSTEM_INFO_BATTERY_HEALTH_H_
+#define CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_BATTERY_HEALTH_H_
+
+#include <string>
+
+namespace app_list {
+
+class BatteryHealth {
+ public:
+  BatteryHealth() = default;
+
+  ~BatteryHealth() = default;
+
+  void SetCycleCount(int cycle_count) { cycle_count_ = cycle_count; }
+  void SetBatteryWearPercentage(int battery_wear_percentage) {
+    battery_wear_percentage_ = battery_wear_percentage;
+  }
+  void SetPowerTime(const std::u16string& power_time) {
+    power_time_ = power_time;
+  }
+  void SetBatteryPercentage(int battery_percentage) {
+    battery_percentage_ = battery_percentage;
+  }
+
+  int GetCycleCount() const { return cycle_count_; }
+  int GetBatteryWearPercentage() const { return battery_wear_percentage_; }
+  std::u16string GetPowerTime() const { return power_time_; }
+  int GetBatteryPercentage() const { return battery_percentage_; }
+
+ private:
+  int cycle_count_ = 0;
+  int battery_wear_percentage_ = 0;
+  std::u16string power_time_ = u"";
+  int battery_percentage_ = 0;
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_BATTERY_HEALTH_H_
diff --git a/chrome/browser/ash/app_list/search/system_info/cpu_data.h b/chrome/browser/ash/app_list/search/system_info/cpu_data.h
new file mode 100644
index 0000000..45335860
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/system_info/cpu_data.h
@@ -0,0 +1,55 @@
+// 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_ASH_APP_LIST_SEARCH_SYSTEM_INFO_CPU_DATA_H_
+#define CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_CPU_DATA_H_
+
+namespace app_list {
+
+/* This class is used to store the final CPU usage and health data for the
+System Info Provider. */
+class CpuData {
+ public:
+  CpuData() = default;
+
+  ~CpuData() = default;
+
+  void SetPercentUsageUser(int percent_usage_user) {
+    percent_usage_user_ = percent_usage_user;
+  }
+  void SetPercentUsageSystem(int percent_usage_system) {
+    percent_usage_system_ = percent_usage_system;
+  }
+  void SetPercentUsageFree(int percent_usage_free) {
+    percent_usage_free_ = percent_usage_free;
+  }
+  void SetAverageCpuTempCelsius(int average_cpu_temp_celsius) {
+    average_cpu_temp_celsius_ = average_cpu_temp_celsius;
+  }
+  void SetScalingAverageCurrentFrequencyKhz(int scaling_current_frequency_khz) {
+    scaling_current_frequency_khz_ = scaling_current_frequency_khz;
+  }
+
+  int GetPercentUsageUser() const { return percent_usage_user_; }
+  int GetPercentUsageSystem() const { return percent_usage_system_; }
+  int GetPercentUsageFree() const { return percent_usage_free_; }
+  int GetPercentUsageTotal() const {
+    return percent_usage_user_ + percent_usage_system_;
+  }
+  int GetAverageCpuTempCelsius() const { return average_cpu_temp_celsius_; }
+  int GetScalingAverageCurrentFrequencyKhz() const {
+    return scaling_current_frequency_khz_;
+  }
+
+ private:
+  int percent_usage_user_ = 0;
+  int percent_usage_system_ = 0;
+  int percent_usage_free_ = 0;
+  int average_cpu_temp_celsius_ = 0;
+  int scaling_current_frequency_khz_ = 0;
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_CPU_DATA_H_
diff --git a/chrome/browser/ash/app_list/search/system_info/cpu_usage_data.cc b/chrome/browser/ash/app_list/search/system_info/cpu_usage_data.cc
new file mode 100644
index 0000000..30b1520b
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/system_info/cpu_usage_data.cc
@@ -0,0 +1,50 @@
+// 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/ash/app_list/search/system_info/cpu_usage_data.h"
+
+namespace app_list {
+
+CpuUsageData::CpuUsageData(uint64_t user_time,
+                           uint64_t system_time,
+                           uint64_t idle_time)
+    : user_time_(user_time), system_time_(system_time), idle_time_(idle_time) {}
+
+bool CpuUsageData::IsInitialized() const {
+  return user_time_ != std::numeric_limits<uint64_t>::max() &&
+         system_time_ != std::numeric_limits<uint64_t>::max() &&
+         idle_time_ != std::numeric_limits<uint64_t>::max();
+}
+
+uint64_t CpuUsageData::GetTotalTime() const {
+  return user_time_ + system_time_ + idle_time_;
+}
+
+CpuUsageData CpuUsageData::operator+(const CpuUsageData& other) const {
+  return CpuUsageData(user_time_ + other.user_time_,
+                      system_time_ + other.system_time_,
+                      idle_time_ + other.idle_time_);
+}
+
+CpuUsageData& CpuUsageData::operator+=(const CpuUsageData& other) {
+  user_time_ += other.user_time_;
+  system_time_ += other.system_time_;
+  idle_time_ += other.idle_time_;
+  return *this;
+}
+
+CpuUsageData CpuUsageData::operator-(const CpuUsageData& other) const {
+  return CpuUsageData(user_time_ - other.user_time_,
+                      system_time_ - other.system_time_,
+                      idle_time_ - other.idle_time_);
+}
+
+CpuUsageData& CpuUsageData::operator-=(const CpuUsageData& other) {
+  user_time_ -= other.user_time_;
+  system_time_ -= other.system_time_;
+  idle_time_ -= other.idle_time_;
+  return *this;
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ash/app_list/search/system_info/cpu_usage_data.h b/chrome/browser/ash/app_list/search/system_info/cpu_usage_data.h
new file mode 100644
index 0000000..7fcd6b31
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/system_info/cpu_usage_data.h
@@ -0,0 +1,49 @@
+// 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_ASH_APP_LIST_SEARCH_SYSTEM_INFO_CPU_USAGE_DATA_H_
+#define CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_CPU_USAGE_DATA_H_
+
+#include <cstdint>
+#include <limits>
+
+namespace app_list {
+
+/* This class is used to store and calculate the system and user usage. The
+delta between the current previous values is used to calculate the final cpu
+usage values which are stored in CPU data.*/
+class CpuUsageData {
+ public:
+  CpuUsageData() = default;
+  CpuUsageData(uint64_t user_time, uint64_t system_time, uint64_t idle_time);
+
+  ~CpuUsageData() = default;
+
+  CpuUsageData(const CpuUsageData& other) = default;
+  CpuUsageData& operator=(const CpuUsageData& other) = default;
+
+  bool IsInitialized() const;
+
+  uint64_t GetUserTime() const { return user_time_; }
+
+  uint64_t GetSystemTime() const { return system_time_; }
+
+  uint64_t GetIdleTime() const { return idle_time_; }
+
+  uint64_t GetTotalTime() const;
+
+  CpuUsageData operator+(const CpuUsageData& other) const;
+  CpuUsageData& operator+=(const CpuUsageData& other);
+  CpuUsageData operator-(const CpuUsageData& other) const;
+  CpuUsageData& operator-=(const CpuUsageData& other);
+
+ private:
+  uint64_t user_time_ = std::numeric_limits<uint64_t>::max();
+  uint64_t system_time_ = std::numeric_limits<uint64_t>::max();
+  uint64_t idle_time_ = std::numeric_limits<uint64_t>::max();
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_CPU_USAGE_DATA_H_
diff --git a/chrome/browser/ash/app_list/search/system_info/cpu_usage_data_unittest.cc b/chrome/browser/ash/app_list/search/system_info/cpu_usage_data_unittest.cc
new file mode 100644
index 0000000..97309a4
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/system_info/cpu_usage_data_unittest.cc
@@ -0,0 +1,77 @@
+// 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/ash/app_list/search/system_info/cpu_usage_data.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace app_list {
+
+class CpuUsageDataTest : public testing::Test {
+ public:
+  CpuUsageDataTest() = default;
+  ~CpuUsageDataTest() override = default;
+};
+
+TEST_F(CpuUsageDataTest, Initialized) {
+  CpuUsageData data;
+
+  EXPECT_FALSE(data.IsInitialized());
+
+  data = CpuUsageData(1, 2, 3);
+
+  EXPECT_TRUE(data.IsInitialized());
+}
+
+TEST_F(CpuUsageDataTest, Total) {
+  CpuUsageData data(1, 2, 3);
+
+  EXPECT_EQ(6u, data.GetTotalTime());
+}
+
+TEST_F(CpuUsageDataTest, Addition) {
+  CpuUsageData data_1(1, 2, 3);
+  CpuUsageData data_2(4, 5, 6);
+
+  CpuUsageData data_3 = data_1 + data_2;
+
+  EXPECT_EQ(5u, data_3.GetUserTime());
+  EXPECT_EQ(7u, data_3.GetSystemTime());
+  EXPECT_EQ(9u, data_3.GetIdleTime());
+}
+
+TEST_F(CpuUsageDataTest, CompoundAddition) {
+  CpuUsageData data_1(1, 2, 3);
+  CpuUsageData data_2(4, 5, 6);
+
+  data_1 += data_2;
+
+  EXPECT_EQ(5u, data_1.GetUserTime());
+  EXPECT_EQ(7u, data_1.GetSystemTime());
+  EXPECT_EQ(9u, data_1.GetIdleTime());
+}
+
+TEST_F(CpuUsageDataTest, Subtraction) {
+  CpuUsageData data_1(1, 2, 3);
+  CpuUsageData data_2(4, 5, 6);
+
+  CpuUsageData data_3 = data_2 - data_1;
+
+  EXPECT_EQ(3u, data_3.GetUserTime());
+  EXPECT_EQ(3u, data_3.GetSystemTime());
+  EXPECT_EQ(3u, data_3.GetIdleTime());
+}
+
+TEST_F(CpuUsageDataTest, CompoundSubtraction) {
+  CpuUsageData data_1(1, 2, 3);
+  CpuUsageData data_2(4, 5, 6);
+
+  data_2 -= data_1;
+
+  EXPECT_EQ(3u, data_2.GetUserTime());
+  EXPECT_EQ(3u, data_2.GetSystemTime());
+  EXPECT_EQ(3u, data_2.GetIdleTime());
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ash/app_list/search/system_info/system_info_card_provider.cc b/chrome/browser/ash/app_list/search/system_info/system_info_card_provider.cc
new file mode 100644
index 0000000..954ac4b
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/system_info/system_info_card_provider.cc
@@ -0,0 +1,243 @@
+// 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/ash/app_list/search/system_info/system_info_card_provider.h"
+
+#include <memory>
+#include <optional>
+#include <string>
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "chrome/browser/ash/app_list/search/system_info/cpu_data.h"
+#include "chrome/browser/ash/app_list/search/system_info/cpu_usage_data.h"
+#include "chrome/browser/ash/app_list/search/system_info/system_info_util.h"
+#include "chromeos/ash/components/string_matching/fuzzy_tokenized_string_match.h"
+#include "chromeos/ash/services/cros_healthd/public/cpp/service_connection.h"
+#include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_probe.mojom-shared.h"
+#include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
+
+namespace app_list {
+namespace {
+
+using ProbeCategories = ash::cros_healthd::mojom::ProbeCategoryEnum;
+using ash::cros_healthd::mojom::BatteryInfo;
+using ash::cros_healthd::mojom::CpuInfo;
+using ash::cros_healthd::mojom::PhysicalCpuInfoPtr;
+using ash::cros_healthd::mojom::TelemetryInfoPtr;
+using ::ash::string_matching::FuzzyTokenizedStringMatch;
+using ::ash::string_matching::TokenizedString;
+
+constexpr double kRelevanceThreshold = 0.64;
+
+}  // namespace
+
+SystemInfoCardProvider::SystemInfoCardProvider(Profile* profile)
+    : profile_(profile) {
+  DCHECK(profile_);
+  ash::cros_healthd::ServiceConnection::GetInstance()->BindProbeService(
+      probe_service_.BindNewPipeAndPassReceiver());
+  probe_service_.set_disconnect_handler(
+      base::BindOnce(&SystemInfoCardProvider::OnProbeServiceDisconnect,
+                     weak_factory_.GetWeakPtr()));
+}
+
+SystemInfoCardProvider::~SystemInfoCardProvider() {
+  chromeos::PowerManagerClient::Get()->RemoveObserver(this);
+}
+
+void SystemInfoCardProvider::Start(const std::u16string& query) {
+  // TODO(b/263994165): Replace with complete implementation with keywords
+  // stored in translation unit.
+  std::vector<std::u16string> memory_keywords = {
+      u"memory", u"memory usage", u"ram", u"ram usage", u"activity monitor"};
+  for (std::u16string keyword : memory_keywords) {
+    if (CalculateRelevance(query, keyword) > kRelevanceThreshold) {
+      UpdateMemoryUsage();
+      break;
+    }
+  }
+
+  std::vector<std::u16string> cpu_keywords = {
+      u"cpu", u"cpu usage", u"device slow", u"why is my device slow"};
+  for (std::u16string keyword : cpu_keywords) {
+    if (CalculateRelevance(query, keyword) > kRelevanceThreshold) {
+      UpdateCpuUsage();
+      break;
+    }
+  }
+
+  std::vector<std::u16string> battery_keywords = {u"battery", u"battery life",
+                                                  u"battery health"};
+  for (std::u16string keyword : battery_keywords) {
+    if (CalculateRelevance(query, keyword) > kRelevanceThreshold) {
+      if (!chromeos::PowerManagerClient::Get()->HasObserver(this)) {
+        chromeos::PowerManagerClient::Get()->AddObserver(this);
+      }
+      UpdateBatteryInfo(absl::nullopt);
+      break;
+    }
+  }
+}
+
+void SystemInfoCardProvider::StopQuery() {
+  // Cancel all previous searches.
+  weak_factory_.InvalidateWeakPtrs();
+}
+
+double SystemInfoCardProvider::CalculateRelevance(const std::u16string& query,
+                                                  const std::u16string& title) {
+  const TokenizedString tokenized_title(title, TokenizedString::Mode::kWords);
+  const TokenizedString tokenized_query(query,
+                                        TokenizedString::Mode::kCamelCase);
+
+  if (tokenized_query.text().empty() || tokenized_title.text().empty()) {
+    static constexpr double kDefaultRelevance = 0.0;
+    return kDefaultRelevance;
+  }
+
+  FuzzyTokenizedStringMatch match;
+  return match.Relevance(tokenized_query, tokenized_title,
+                         /*use_weighted_ratio=*/false,
+                         /*strip_diacritics=*/true,
+                         /*use_acronym_matcher=*/true);
+}
+
+void SystemInfoCardProvider::BindCrosHealthdProbeServiceIfNecessary() {
+  if (!probe_service_ || !probe_service_.is_connected()) {
+    ash::cros_healthd::ServiceConnection::GetInstance()->BindProbeService(
+        probe_service_.BindNewPipeAndPassReceiver());
+    probe_service_.set_disconnect_handler(
+        base::BindOnce(&SystemInfoCardProvider::OnProbeServiceDisconnect,
+                       weak_factory_.GetWeakPtr()));
+  }
+}
+
+ash::AppListSearchResultType SystemInfoCardProvider::ResultType() const {
+  return ash::AppListSearchResultType::kAnswerCard;
+}
+
+void SystemInfoCardProvider::OnProbeServiceDisconnect() {
+  probe_service_.reset();
+}
+
+void SystemInfoCardProvider::OnMemoryUsageUpdated(TelemetryInfoPtr info_ptr) {
+  if (info_ptr.is_null()) {
+    LOG(ERROR) << "Null response from croshealthd::ProbeTelemetryInfo.";
+    return;
+  }
+
+  memory_info_ = GetMemoryInfo(*info_ptr);
+}
+
+void SystemInfoCardProvider::UpdateMemoryUsage() {
+  BindCrosHealthdProbeServiceIfNecessary();
+
+  probe_service_->ProbeTelemetryInfo(
+      {ProbeCategories::kMemory},
+      base::BindOnce(&SystemInfoCardProvider::OnMemoryUsageUpdated,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void SystemInfoCardProvider::OnCpuUsageUpdated(TelemetryInfoPtr info_ptr) {
+  if (info_ptr.is_null()) {
+    LOG(ERROR) << "Null response from croshealthd::ProbeTelemetryInfo.";
+    return;
+  }
+
+  const CpuInfo* cpu_info = GetCpuInfo(*info_ptr);
+  if (cpu_info == nullptr) {
+    LOG(ERROR) << "No CpuInfo in response from cros_healthd.";
+    return;
+  }
+
+  if (cpu_info->physical_cpus.empty()) {
+    LOG(ERROR) << "Device reported having zero physical CPUs.";
+    return;
+  }
+
+  if (cpu_info->physical_cpus[0]->logical_cpus.empty()) {
+    LOG(ERROR) << "Device reported having zero logical CPUs.";
+    return;
+  }
+
+  // For simplicity, assume that all devices have just one physical CPU, made
+  // up of one or more virtual CPUs.
+  if (cpu_info->physical_cpus.size() > 1) {
+    VLOG(1) << "Device has more than one physical CPU.";
+  }
+
+  const PhysicalCpuInfoPtr& physical_cpu_ptr = cpu_info->physical_cpus[0];
+
+  CpuUsageData new_cpu_usage_data =
+      CalculateCpuUsage(physical_cpu_ptr->logical_cpus);
+  std::unique_ptr<CpuData> new_cpu_usage = std::make_unique<CpuData>();
+
+  PopulateCpuUsage(new_cpu_usage_data, previous_cpu_usage_data_,
+                   *new_cpu_usage.get());
+  PopulateAverageCpuTemperature(*cpu_info, *new_cpu_usage.get());
+  PopulateAverageScaledClockSpeed(*cpu_info, *new_cpu_usage.get());
+
+  previous_cpu_usage_data_ = new_cpu_usage_data;
+  cpu_usage_ = std::move(new_cpu_usage);
+}
+
+void SystemInfoCardProvider::UpdateCpuUsage() {
+  BindCrosHealthdProbeServiceIfNecessary();
+
+  probe_service_->ProbeTelemetryInfo(
+      {ProbeCategories::kCpu},
+      base::BindOnce(&SystemInfoCardProvider::OnCpuUsageUpdated,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void SystemInfoCardProvider::UpdateBatteryInfo(
+    absl::optional<power_manager::PowerSupplyProperties>
+        power_supply_properties) {
+  BindCrosHealthdProbeServiceIfNecessary();
+
+  probe_service_->ProbeTelemetryInfo(
+      {ProbeCategories::kBattery},
+      base::BindOnce(&SystemInfoCardProvider::OnBatteryInfoUpdated,
+                     weak_factory_.GetWeakPtr(), power_supply_properties));
+}
+
+void SystemInfoCardProvider::OnBatteryInfoUpdated(
+    absl::optional<power_manager::PowerSupplyProperties>
+        power_supply_properties,
+    ash::cros_healthd::mojom::TelemetryInfoPtr info_ptr) {
+  if (info_ptr.is_null()) {
+    LOG(ERROR) << "Null response from croshealthd::ProbeTelemetryInfo.";
+    return;
+  }
+
+  const BatteryInfo* battery_info_ptr = GetBatteryInfo(*info_ptr);
+  if (!battery_info_ptr) {
+    LOG(ERROR) << "BatteryInfo requested by device does not have a battery.";
+    return;
+  }
+
+  std::unique_ptr<BatteryHealth> new_battery_health =
+      std::make_unique<BatteryHealth>();
+
+  PopulateBatteryHealth(*battery_info_ptr, *new_battery_health.get());
+
+  const absl::optional<power_manager::PowerSupplyProperties>& proto =
+      power_supply_properties.has_value()
+          ? power_supply_properties
+          : chromeos::PowerManagerClient::Get()->GetLastStatus();
+  DCHECK(proto);
+
+  PopulatePowerStatus(proto.value(), *new_battery_health.get());
+
+  battery_health_ = std::move(new_battery_health);
+}
+
+void SystemInfoCardProvider::PowerChanged(
+    const power_manager::PowerSupplyProperties& power_supply_properties) {
+  UpdateBatteryInfo(absl::make_optional<power_manager::PowerSupplyProperties>(
+      power_supply_properties));
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ash/app_list/search/system_info/system_info_card_provider.h b/chrome/browser/ash/app_list/search/system_info/system_info_card_provider.h
new file mode 100644
index 0000000..cafd495
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/system_info/system_info_card_provider.h
@@ -0,0 +1,79 @@
+// 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_ASH_APP_LIST_SEARCH_SYSTEM_INFO_SYSTEM_INFO_CARD_PROVIDER_H_
+#define CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_SYSTEM_INFO_CARD_PROVIDER_H_
+
+#include <memory>
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/ash/app_list/search/search_provider.h"
+#include "chrome/browser/ash/app_list/search/system_info/battery_health.h"
+#include "chrome/browser/ash/app_list/search/system_info/cpu_data.h"
+#include "chrome/browser/ash/app_list/search/system_info/cpu_usage_data.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
+#include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
+#include "chromeos/dbus/power/power_manager_client.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace app_list {
+
+/* This Provider intents to return answer cards which surface system-level
+information such as Storage usage, CPU consumption, battery health, current
+version, network information and memory usage. The answer cards link to the
+relevant pages within the Settings and Diagnostics apps.*/
+
+// TODO(b/263994165): Complete the System Info Card Provide to return results.
+// This provider is a work in progress.
+class SystemInfoCardProvider : public SearchProvider,
+                               public chromeos::PowerManagerClient::Observer {
+ public:
+  explicit SystemInfoCardProvider(Profile* profile);
+  ~SystemInfoCardProvider() override;
+
+  SystemInfoCardProvider(const SystemInfoCardProvider&) = delete;
+  SystemInfoCardProvider& operator=(const SystemInfoCardProvider&) = delete;
+  ash::AppListSearchResultType ResultType() const override;
+
+  // SearchProvider:
+  void Start(const std::u16string& query) override;
+  void StopQuery() override;
+
+ private:
+  void BindCrosHealthdProbeServiceIfNecessary();
+  void OnProbeServiceDisconnect();
+  double CalculateRelevance(const std::u16string& query,
+                            const std::u16string& title);
+
+  void UpdateMemoryUsage();
+  void OnMemoryUsageUpdated(
+      ash::cros_healthd::mojom::TelemetryInfoPtr info_ptr);
+
+  void UpdateCpuUsage();
+  void OnCpuUsageUpdated(ash::cros_healthd::mojom::TelemetryInfoPtr info_ptr);
+
+  void UpdateBatteryInfo(absl::optional<power_manager::PowerSupplyProperties>
+                             power_supply_properties);
+  void OnBatteryInfoUpdated(
+      absl::optional<power_manager::PowerSupplyProperties>
+          power_supply_properties,
+      ash::cros_healthd::mojom::TelemetryInfoPtr info_ptr);
+
+  // chromeos::PowerManagerClient::Observer:
+  void PowerChanged(const power_manager::PowerSupplyProperties&
+                        power_supply_properties) override;
+
+  Profile* const profile_;
+  mojo::Remote<ash::cros_healthd::mojom::CrosHealthdProbeService>
+      probe_service_;
+  CpuUsageData previous_cpu_usage_data_{CpuUsageData()};
+  ash::cros_healthd::mojom::MemoryInfo* memory_info_{nullptr};
+  std::unique_ptr<CpuData> cpu_usage_{nullptr};
+  std::unique_ptr<BatteryHealth> battery_health_{nullptr};
+  base::WeakPtrFactory<SystemInfoCardProvider> weak_factory_{this};
+};
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_SYSTEM_INFO_CARD_PROVIDER_H_
diff --git a/chrome/browser/ash/app_list/search/system_info/system_info_util.cc b/chrome/browser/ash/app_list/search/system_info/system_info_util.cc
new file mode 100644
index 0000000..72a7110
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/system_info/system_info_util.cc
@@ -0,0 +1,272 @@
+// 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/ash/app_list/search/system_info/system_info_util.h"
+
+#include "ash/public/cpp/power_utils.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/time/time.h"
+#include "chrome/browser/ash/app_list/search/system_info/cpu_usage_data.h"
+#include "chrome/grit/generated_resources.h"
+#include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
+#include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
+
+namespace app_list {
+namespace {
+namespace healthd = ash::cros_healthd::mojom;
+
+constexpr int kMilliampsInAnAmp = 1000;
+
+// The enums below are used in histograms, do not remove/renumber entries. If
+// you're adding to any of these enums, update the corresponding enum listing in
+// tools/metrics/histograms/enums.xml: CrosDiagnosticsDataError.
+enum class DataError {
+  // Null or nullptr value.
+  kNoData = 0,
+  // For numeric values that are NaN.
+  kNotANumber = 1,
+  // Expectation about data not met. Ex. routing prefix is between zero and
+  // thirty-two.
+  kExpectationNotMet = 2,
+  kMaxValue = kExpectationNotMet,
+};
+
+const std::string GetMetricNameForSourceType(
+    const base::StringPiece source_type) {
+  if (source_type == "cpu info") {
+    return "Apps.AppList.SystemInfoProvider.CrosHealthdProbeError.CpuInfo";
+  }
+  if (source_type == "memory info") {
+    return "Apps.AppList.SystemInfoProvider.CrosHealthdProbeError.MemoryInfo";
+  }
+  if (source_type == "battery info") {
+    return "Apps.AppList.SystemInfoProvider.CrosHealthdProbeError.BatteryInfo";
+  }
+  NOTREACHED();
+  return "";
+}
+
+void EmitCrosHealthdProbeError(const base::StringPiece source_type,
+                               healthd::ErrorType error_type) {
+  const std::string& metric_name = GetMetricNameForSourceType(source_type);
+
+  // `metric_name` may be empty in which case we do not want a metric send
+  // attempted.
+  if (metric_name.empty()) {
+    LOG(WARNING)
+        << "Ignoring request to record metric for ProbeError of error_type: "
+        << error_type << " for unknown source_stuct: " << source_type;
+    return;
+  }
+
+  base::UmaHistogramEnumeration(metric_name, error_type);
+}
+
+void EmitBatteryDataError(DataError error) {
+  base::UmaHistogramEnumeration("Apps.AppList.SystemInfoProvider.Error.Battery",
+                                error);
+}
+
+template <typename TResult, typename TTag>
+
+bool CheckResponse(const TResult& result,
+                   TTag expected_tag,
+                   base::StringPiece type_name) {
+  if (result.is_null()) {
+    LOG(ERROR) << type_name << "not found in croshealthd response.";
+    return false;
+  }
+
+  auto tag = result->which();
+  if (tag == TTag::kError) {
+    EmitCrosHealthdProbeError(type_name, result->get_error()->type);
+    LOG(ERROR) << "Error retrieving " << type_name
+               << "from croshealthd: " << result->get_error()->msg;
+    return false;
+  }
+
+  DCHECK_EQ(tag, expected_tag);
+
+  return true;
+}
+
+}  // namespace
+
+healthd::MemoryInfo* GetMemoryInfo(const healthd::TelemetryInfo& info) {
+  const healthd::MemoryResultPtr& memory_result = info.memory_result;
+  if (!CheckResponse(memory_result, healthd::MemoryResult::Tag::kMemoryInfo,
+                     "memory info")) {
+    return nullptr;
+  }
+
+  return memory_result->get_memory_info().get();
+}
+
+const healthd::BatteryInfo* GetBatteryInfo(const healthd::TelemetryInfo& info) {
+  const healthd::BatteryResultPtr& battery_result = info.battery_result;
+  if (!CheckResponse(battery_result, healthd::BatteryResult::Tag::kBatteryInfo,
+                     "battery info")) {
+    return nullptr;
+  }
+
+  return battery_result->get_battery_info().get();
+}
+
+healthd::CpuInfo* GetCpuInfo(const healthd::TelemetryInfo& info) {
+  const healthd::CpuResultPtr& cpu_result = info.cpu_result;
+  if (!CheckResponse(cpu_result, healthd::CpuResult::Tag::kCpuInfo,
+                     "cpu info")) {
+    return nullptr;
+  }
+
+  return cpu_result->get_cpu_info().get();
+}
+
+CpuUsageData CalculateCpuUsage(
+    const std::vector<healthd::LogicalCpuInfoPtr>& logical_cpu_infos) {
+  CpuUsageData new_usage_data;
+
+  DCHECK_GE(logical_cpu_infos.size(), 1u);
+  for (const auto& logical_cpu_ptr : logical_cpu_infos) {
+    new_usage_data += CpuUsageData(logical_cpu_ptr->user_time_user_hz,
+                                   logical_cpu_ptr->system_time_user_hz,
+                                   logical_cpu_ptr->idle_time_user_hz);
+  }
+
+  return new_usage_data;
+}
+
+void PopulateCpuUsage(CpuUsageData new_cpu_usage_data,
+                      CpuUsageData previous_cpu_usage_data,
+                      CpuData& cpu_usage) {
+  CpuUsageData delta = new_cpu_usage_data - previous_cpu_usage_data;
+
+  const uint64_t total_delta = delta.GetTotalTime();
+  if (total_delta == 0) {
+    LOG(ERROR) << "Device reported having zero logical CPUs.";
+    return;
+  }
+  cpu_usage.SetPercentUsageUser(100 * delta.GetUserTime() / total_delta);
+  cpu_usage.SetPercentUsageSystem(100 * delta.GetSystemTime() / total_delta);
+  cpu_usage.SetPercentUsageFree(100 * delta.GetIdleTime() / total_delta);
+}
+
+void PopulateAverageCpuTemperature(
+    const ash::cros_healthd::mojom::CpuInfo& cpu_info,
+    CpuData& cpu_usage) {
+  if (cpu_info.temperature_channels.empty()) {
+    LOG(ERROR) << "Device reported having 0 temperature channels.";
+    return;
+  }
+
+  uint32_t cumulative_total = 0;
+  for (const auto& temp_channel_ptr : cpu_info.temperature_channels) {
+    cumulative_total += temp_channel_ptr->temperature_celsius;
+  }
+
+  // Integer division.
+  cpu_usage.SetAverageCpuTempCelsius(cumulative_total /
+                                     cpu_info.temperature_channels.size());
+}
+
+void PopulateAverageScaledClockSpeed(const healthd::CpuInfo& cpu_info,
+                                     CpuData& cpu_usage) {
+  if (cpu_info.physical_cpus.empty() ||
+      cpu_info.physical_cpus[0]->logical_cpus.empty()) {
+    LOG(ERROR) << "Device reported having 0 logical CPUs.";
+    return;
+  }
+
+  uint32_t total_scaled_ghz = 0;
+  for (const auto& logical_cpu_ptr : cpu_info.physical_cpus[0]->logical_cpus) {
+    total_scaled_ghz += logical_cpu_ptr->scaling_current_frequency_khz;
+  }
+
+  // Integer division.
+  cpu_usage.SetScalingAverageCurrentFrequencyKhz(
+      total_scaled_ghz / cpu_info.physical_cpus[0]->logical_cpus.size());
+}
+
+void PopulateBatteryHealth(
+    const ash::cros_healthd::mojom::BatteryInfo& battery_info,
+    BatteryHealth& battery_health) {
+  battery_health.SetCycleCount(battery_info.cycle_count);
+
+  if (battery_info.charge_full == 0) {
+    LOG(ERROR) << "charge_full from battery_info should not be zero.";
+    EmitBatteryDataError(DataError::kExpectationNotMet);
+  }
+
+  // Handle values in battery_info which could cause a SIGFPE. See b/227485637.
+  if (isnan(battery_info.charge_full) ||
+      isnan(battery_info.charge_full_design) ||
+      battery_info.charge_full_design == 0) {
+    LOG(ERROR) << "battery_info values could cause SIGFPE crash: { "
+               << "charge_full_design: " << battery_info.charge_full_design
+               << ", charge_full: " << battery_info.charge_full << " }";
+    battery_health.SetBatteryWearPercentage(0);
+    return;
+  }
+
+  double charge_full_now_milliamp_hours =
+      battery_info.charge_full * kMilliampsInAnAmp;
+  double charge_full_design_milliamp_hours =
+      battery_info.charge_full_design * kMilliampsInAnAmp;
+  battery_health.SetBatteryWearPercentage(100 * charge_full_now_milliamp_hours /
+                                          charge_full_design_milliamp_hours);
+}
+
+std::u16string GetBatteryTimeText(base::TimeDelta time_left) {
+  int hour = 0;
+  int min = 0;
+  ash::power_utils::SplitTimeIntoHoursAndMinutes(time_left, &hour, &min);
+
+  std::u16string time_text;
+  if (hour == 0 || min == 0) {
+    // Display only one unit ("2 hours" or "10 minutes").
+    return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
+                                  ui::TimeFormat::LENGTH_LONG, time_left);
+  }
+
+  return ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION,
+                                  ui::TimeFormat::LENGTH_LONG,
+                                  -1,  // force hour and minute output
+                                  time_left);
+}
+
+void PopulatePowerStatus(const power_manager::PowerSupplyProperties& proto,
+                         BatteryHealth& battery_health) {
+  bool charging = proto.battery_state() ==
+                  power_manager::PowerSupplyProperties_BatteryState_CHARGING;
+  bool calculating = proto.is_calculating_battery_time();
+  int percent =
+      ash::power_utils::GetRoundedBatteryPercent(proto.battery_percent());
+  base::TimeDelta time_left;
+  bool show_time = false;
+
+  if (!calculating) {
+    time_left = base::Seconds(charging ? proto.battery_time_to_full_sec()
+                                       : proto.battery_time_to_empty_sec());
+    show_time = ash::power_utils::ShouldDisplayBatteryTime(time_left);
+  }
+
+  std::u16string status_text;
+  if (show_time) {
+    // TODO(b/263994165): Create a new id with a | instead of a -.
+    status_text = l10n_util::GetStringFUTF16(
+        charging ? IDS_SETTINGS_BATTERY_STATUS_CHARGING
+                 : IDS_SETTINGS_BATTERY_STATUS,
+        base::NumberToString16(percent), GetBatteryTimeText(time_left));
+  } else {
+    status_text = l10n_util::GetStringFUTF16(IDS_SETTINGS_BATTERY_STATUS_SHORT,
+                                             base::NumberToString16(percent));
+  }
+
+  battery_health.SetPowerTime(status_text);
+  battery_health.SetBatteryPercentage(percent);
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ash/app_list/search/system_info/system_info_util.h b/chrome/browser/ash/app_list/search/system_info/system_info_util.h
new file mode 100644
index 0000000..53bdcca
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/system_info/system_info_util.h
@@ -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.
+
+#ifndef CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_SYSTEM_INFO_UTIL_H_
+#define CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_SYSTEM_INFO_UTIL_H_
+
+#include "base/time/time.h"
+#include "chrome/browser/ash/app_list/search/system_info/battery_health.h"
+#include "chrome/browser/ash/app_list/search/system_info/cpu_data.h"
+#include "chrome/browser/ash/app_list/search/system_info/cpu_usage_data.h"
+#include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
+#include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
+
+namespace app_list {
+
+// Extracts MemoryInfo from `info`. Logs and returns a nullptr if MemoryInfo
+// in not present.
+ash::cros_healthd::mojom::MemoryInfo* GetMemoryInfo(
+    const ash::cros_healthd::mojom::TelemetryInfo& info);
+
+// Extracts CpuInfo from `info`. Logs and returns a nullptr if CpuInfo
+// in not present.
+ash::cros_healthd::mojom::CpuInfo* GetCpuInfo(
+    const ash::cros_healthd::mojom::TelemetryInfo& info);
+
+// Extracts BatteryInfo from `info`. Logs and returns a nullptr if
+// BatteryInfo in not present.
+const ash::cros_healthd::mojom::BatteryInfo* GetBatteryInfo(
+    const ash::cros_healthd::mojom::TelemetryInfo& info);
+
+CpuUsageData CalculateCpuUsage(
+    const std::vector<ash::cros_healthd::mojom::LogicalCpuInfoPtr>&
+        logical_cpu_infos);
+
+void PopulateCpuUsage(CpuUsageData new_cpu_usage_data,
+                      CpuUsageData previous_cpu_usage_data,
+                      CpuData& cpu_usage);
+void PopulateAverageCpuTemperature(
+    const ash::cros_healthd::mojom::CpuInfo& cpu_info,
+    CpuData& cpu_usage);
+void PopulateAverageScaledClockSpeed(
+    const ash::cros_healthd::mojom::CpuInfo& cpu_info,
+    CpuData& out_cpu_usage);
+
+void PopulateBatteryHealth(
+    const ash::cros_healthd::mojom::BatteryInfo& battery_info,
+    BatteryHealth& battery_health);
+
+void PopulatePowerStatus(
+    const power_manager::PowerSupplyProperties& power_supply_properties,
+    BatteryHealth& battery_health);
+
+std::u16string GetBatteryTimeText(base::TimeDelta time_left);
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_ASH_APP_LIST_SEARCH_SYSTEM_INFO_SYSTEM_INFO_UTIL_H_
diff --git a/chrome/browser/ash/borealis/borealis_security_delegate_unittest.cc b/chrome/browser/ash/borealis/borealis_security_delegate_unittest.cc
index d0ead664..e084e33 100644
--- a/chrome/browser/ash/borealis/borealis_security_delegate_unittest.cc
+++ b/chrome/browser/ash/borealis/borealis_security_delegate_unittest.cc
@@ -23,7 +23,8 @@
 
 }  // namespace
 
-TEST_F(BorealisSecurityDelegateTest, MainAppCanSelfActivate) {
+// TODO(b/244651040): Remove legacy tests when sommelier changes are complete.
+TEST_F(BorealisSecurityDelegateTest, MainAppCanSelfActivateLegacy) {
   CreateFakeMainApp(&profile_);
   std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow(
       "org.chromium.borealis.wmclass.Steam",
@@ -32,7 +33,16 @@
       BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window()));
 }
 
-TEST_F(BorealisSecurityDelegateTest, NormalAppCanNotSelfActivate) {
+TEST_F(BorealisSecurityDelegateTest, MainAppCanSelfActivate) {
+  CreateFakeMainApp(&profile_);
+  std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow(
+      "org.chromium.guest_os.borealis.wmclass.Steam",
+      &BorealisService::GetForProfile(&profile_)->WindowManager());
+  EXPECT_TRUE(
+      BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window()));
+}
+
+TEST_F(BorealisSecurityDelegateTest, NormalAppCanNotSelfActivateLegacy) {
   CreateFakeApp(&profile_, "not_steam", "borealis/123");
   std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow(
       "org.chromium.borealis.wmclass.not_steam",
@@ -46,7 +56,21 @@
       BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window()));
 }
 
-TEST_F(BorealisSecurityDelegateTest, AnonymousAppCanNotSelfActivate) {
+TEST_F(BorealisSecurityDelegateTest, NormalAppCanNotSelfActivate) {
+  CreateFakeApp(&profile_, "not_steam", "borealis/123");
+  std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow(
+      "org.chromium.guest_os.borealis.wmclass.not_steam",
+      &BorealisService::GetForProfile(&profile_)->WindowManager());
+
+  ASSERT_FALSE(BorealisWindowManager::IsAnonymousAppId(
+      BorealisService::GetForProfile(&profile_)->WindowManager().GetShelfAppId(
+          window->window())));
+
+  EXPECT_FALSE(
+      BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window()));
+}
+
+TEST_F(BorealisSecurityDelegateTest, AnonymousAppCanNotSelfActivateLegacy) {
   std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow(
       "org.chromium.borealis.wmclass.anonymous",
       &BorealisService::GetForProfile(&profile_)->WindowManager());
@@ -59,4 +83,17 @@
       BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window()));
 }
 
+TEST_F(BorealisSecurityDelegateTest, AnonymousAppCanNotSelfActivate) {
+  std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow(
+      "org.chromium.guest_os.borealis.wmclass.anonymous",
+      &BorealisService::GetForProfile(&profile_)->WindowManager());
+
+  ASSERT_TRUE(BorealisWindowManager::IsAnonymousAppId(
+      BorealisService::GetForProfile(&profile_)->WindowManager().GetShelfAppId(
+          window->window())));
+
+  EXPECT_FALSE(
+      BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window()));
+}
+
 }  // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_util.cc b/chrome/browser/ash/borealis/borealis_util.cc
index b92b8e8..210b43c3 100644
--- a/chrome/browser/ash/borealis/borealis_util.cc
+++ b/chrome/browser/ash/borealis/borealis_util.cc
@@ -60,8 +60,11 @@
 static constexpr char kJSONSteamKey[] = "steam_runtime_version";
 
 // App IDs prefixed with this are identified with a numeric "Borealis ID".
-const base::StringPiece kBorealisWindowWithIdPrefix(
+// TODO(b/244651040): Remove legacy prefix when sommelier changes are complete.
+const base::StringPiece kBorealisWindowWithIdPrefixLegacy(
     "org.chromium.borealis.xprop.");
+const base::StringPiece kBorealisWindowWithIdPrefix(
+    "org.chromium.guest_os.borealis.xprop.");
 
 // Windows with these app IDs are not games. Don't prompt for feedback for them.
 // Hashed by crx_file::id_util::GenerateId().
@@ -140,9 +143,15 @@
 
 absl::optional<int> GetBorealisAppId(const aura::Window* window) {
   const std::string* id = exo::GetShellApplicationId(window);
-  if (id && base::StartsWith(*id, kBorealisWindowWithIdPrefix)) {
+  if (id) {
     int borealis_id;
-    if (base::StringToInt(id->substr(kBorealisWindowWithIdPrefix.size()),
+    if (base::StartsWith(*id, kBorealisWindowWithIdPrefix) &&
+        base::StringToInt(id->substr(kBorealisWindowWithIdPrefix.size()),
+                          &borealis_id)) {
+      return borealis_id;
+    }
+    if (base::StartsWith(*id, kBorealisWindowWithIdPrefixLegacy) &&
+        base::StringToInt(id->substr(kBorealisWindowWithIdPrefixLegacy.size()),
                           &borealis_id)) {
       return borealis_id;
     }
diff --git a/chrome/browser/ash/borealis/borealis_util_unittest.cc b/chrome/browser/ash/borealis/borealis_util_unittest.cc
index 5e75d7c..d986b62 100644
--- a/chrome/browser/ash/borealis/borealis_util_unittest.cc
+++ b/chrome/browser/ash/borealis/borealis_util_unittest.cc
@@ -51,18 +51,32 @@
   EXPECT_EQ(GetBorealisAppId("steam://rungameid/123").value(), 123);
 }
 
-TEST_F(BorealisUtilTest, GetBorealisAppIdFromWindowReturnsEmptyOnFailure) {
+// TODO(b/244651040): Remove legacy tests when sommelier changes are complete.
+TEST_F(BorealisUtilTest,
+       GetBorealisAppIdFromWindowReturnsEmptyOnFailureLegacy) {
   std::unique_ptr<aura::Window> window =
       MakeWindow("org.chromium.borealis.wmclass.foo");
   EXPECT_EQ(GetBorealisAppId(window.get()), absl::nullopt);
 }
 
-TEST_F(BorealisUtilTest, GetBorealisAppIdFromWindowReturnsId) {
+TEST_F(BorealisUtilTest, GetBorealisAppIdFromWindowReturnsEmptyOnFailure) {
+  std::unique_ptr<aura::Window> window =
+      MakeWindow("org.chromium.guest_os.borealis.wmclass.foo");
+  EXPECT_EQ(GetBorealisAppId(window.get()), absl::nullopt);
+}
+
+TEST_F(BorealisUtilTest, GetBorealisAppIdFromWindowReturnsIdLegacy) {
   std::unique_ptr<aura::Window> window =
       MakeWindow("org.chromium.borealis.xprop.123");
   EXPECT_EQ(GetBorealisAppId(window.get()).value(), 123);
 }
 
+TEST_F(BorealisUtilTest, GetBorealisAppIdFromWindowReturnsId) {
+  std::unique_ptr<aura::Window> window =
+      MakeWindow("org.chromium.guest_os.borealis.xprop.123");
+  EXPECT_EQ(GetBorealisAppId(window.get()).value(), 123);
+}
+
 TEST_F(BorealisUtilTest, FeedbackFormUrlExcludesNonGames) {
   TestingProfile profile;
 
diff --git a/chrome/browser/ash/borealis/borealis_window_manager.cc b/chrome/browser/ash/borealis/borealis_window_manager.cc
index 36d908bb..dfbb11c 100644
--- a/chrome/browser/ash/borealis/borealis_window_manager.cc
+++ b/chrome/browser/ash/borealis/borealis_window_manager.cc
@@ -27,8 +27,13 @@
 
 namespace borealis {
 
-const char kBorealisWindowPrefix[] = "org.chromium.borealis.";
-const char kFullscreenClientShellId[] = "org.chromium.borealis.wmclass.steam";
+// TODO(b/244651040): Remove legacy prefix when sommelier changes are complete.
+const char kBorealisWindowPrefixLegacy[] = "org.chromium.borealis.";
+const char kBorealisWindowPrefix[] = "org.chromium.guest_os.borealis.";
+const char kFullscreenClientShellIdLegacy[] =
+    "org.chromium.borealis.wmclass.steam";
+const char kFullscreenClientShellId[] =
+    "org.chromium.guest_os.borealis.wmclass.steam";
 const char kBorealisClientSuffix[] = "wmclass.Steam";
 const char kBorealisAnonymousPrefix[] = "borealis_anon:";
 
@@ -60,6 +65,10 @@
   return {};
 }
 
+bool IsBorealisWindowIdLegacy(const std::string& window_id) {
+  return base::StartsWith(window_id, borealis::kBorealisWindowPrefixLegacy);
+}
+
 std::string WindowToAppId(Profile* profile, const aura::Window* window) {
   // The Borealis app ID is the most reliable method, if known.
   absl::optional<int> borealis_id = GetBorealisAppId(window);
@@ -77,10 +86,10 @@
   // TODO(b/244651040): remove the string replacement after new window_id format
   // is deployed.
   std::string window_id(*GetWindowId(window));
-  if (borealis::BorealisWindowManager::IsBorealisWindowId(window_id)) {
-    base::ReplaceFirstSubstringAfterOffset(&window_id, 0,
-                                           borealis::kBorealisWindowPrefix,
-                                           "org.chromium.termina.");
+  if (IsBorealisWindowIdLegacy(window_id)) {
+    base::ReplaceFirstSubstringAfterOffset(
+        &window_id, 0, borealis::kBorealisWindowPrefixLegacy,
+        "org.chromium.termina.");
   }
   std::string guest_os_shelf_app_id =
       guest_os::GetGuestOsShelfAppId(profile, &window_id, nullptr);
@@ -109,7 +118,8 @@
 
 // static
 bool BorealisWindowManager::IsBorealisWindowId(const std::string& window_id) {
-  return base::StartsWith(window_id, borealis::kBorealisWindowPrefix);
+  return base::StartsWith(window_id, borealis::kBorealisWindowPrefix) ||
+         base::StartsWith(window_id, borealis::kBorealisWindowPrefixLegacy);
 }
 
 // static
@@ -137,8 +147,10 @@
 
   // If the fullscreen window is the borealis client, then we allow windows to
   // take focus.
-  if (*active_window_id == borealis::kFullscreenClientShellId)
+  if (*active_window_id == borealis::kFullscreenClientShellId ||
+      *active_window_id == borealis::kFullscreenClientShellIdLegacy) {
     return false;
+  }
 
   return true;
 }
@@ -181,8 +193,9 @@
 }
 
 std::string BorealisWindowManager::GetShelfAppId(aura::Window* window) {
-  if (!IsBorealisWindow(window))
+  if (!IsBorealisWindow(window)) {
     return {};
+  }
 
   // We delay the observation until the first time we actually see a borealis
   // window, which prevents unnecessary messages being sent and breaks an
diff --git a/chrome/browser/ash/borealis/borealis_window_manager_unittest.cc b/chrome/browser/ash/borealis/borealis_window_manager_unittest.cc
index f536c53..b89ed78 100644
--- a/chrome/browser/ash/borealis/borealis_window_manager_unittest.cc
+++ b/chrome/browser/ash/borealis/borealis_window_manager_unittest.cc
@@ -60,14 +60,22 @@
   EXPECT_EQ(window_manager.GetShelfAppId(window.get()), "");
 }
 
-TEST_F(BorealisWindowManagerTest, BorealisWindowHasAnId) {
+// TODO(b/244651040): Remove legacy tests when sommelier changes are complete.
+TEST_F(BorealisWindowManagerTest, BorealisWindowHasAnIdLegacy) {
   BorealisWindowManager window_manager(profile());
   std::unique_ptr<aura::Window> window =
       MakeWindow("org.chromium.borealis.foobarbaz");
   EXPECT_NE(window_manager.GetShelfAppId(window.get()), "");
 }
 
-TEST_F(BorealisWindowManagerTest, BorealisWindowHasCorrectId) {
+TEST_F(BorealisWindowManagerTest, BorealisWindowHasAnId) {
+  BorealisWindowManager window_manager(profile());
+  std::unique_ptr<aura::Window> window =
+      MakeWindow("org.chromium.guest_os.borealis.foobarbaz");
+  EXPECT_NE(window_manager.GetShelfAppId(window.get()), "");
+}
+
+TEST_F(BorealisWindowManagerTest, BorealisWindowHasCorrectIdLegacy) {
   BorealisWindowManager window_manager(profile());
   std::unique_ptr<aura::Window> window =
       MakeWindow("org.chromium.borealis.xprop.456789");
@@ -75,10 +83,18 @@
   EXPECT_EQ(window_manager.GetShelfAppId(window.get()), FakeAppId("some_app"));
 }
 
+TEST_F(BorealisWindowManagerTest, BorealisWindowHasCorrectId) {
+  BorealisWindowManager window_manager(profile());
+  std::unique_ptr<aura::Window> window =
+      MakeWindow("org.chromium.guest_os.borealis.xprop.456789");
+  CreateFakeApp(profile(), "some_app", "steam://rungameid/456789");
+  EXPECT_EQ(window_manager.GetShelfAppId(window.get()), FakeAppId("some_app"));
+}
+
 TEST_F(BorealisWindowManagerTest, MismatchedWindowHasDifferentId) {
   BorealisWindowManager window_manager(profile());
   std::unique_ptr<aura::Window> window =
-      MakeWindow("org.chromium.borealis.xprop.2468");
+      MakeWindow("org.chromium.guest_os.borealis.xprop.2468");
   CreateFakeApp(profile(), "some_app", "steam://rungameid/456789");
   EXPECT_NE(window_manager.GetShelfAppId(window.get()), FakeAppId("some_app"));
 }
@@ -92,7 +108,7 @@
   window_manager.AddObserver(&life_observer);
 
   std::unique_ptr<aura::Window> window =
-      MakeWindow("org.chromium.borealis.foobarbaz");
+      MakeWindow("org.chromium.guest_os.borealis.foobarbaz");
   window_manager.GetShelfAppId(window.get());
 
   window_manager.RemoveObserver(&anon_observer);
@@ -125,7 +141,7 @@
   BorealisWindowManager window_manager(profile());
   window_manager.AddObserver(&observer);
   std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow(
-      "org.chromium.borealis.anonymous_app", &window_manager);
+      "org.chromium.guest_os.borealis.anonymous_app", &window_manager);
 
   EXPECT_CALL(observer,
               OnAnonymousAppRemoved(testing::ContainsRegex("anonymous_app")));
@@ -148,18 +164,18 @@
   EXPECT_CALL(observer, OnAppStarted(_));
   EXPECT_CALL(observer, OnWindowStarted(_, _));
   std::unique_ptr<ScopedTestWindow> first_foo =
-      MakeAndTrackWindow("org.chromium.borealis.foo", &window_manager);
+      MakeAndTrackWindow("org.chromium.guest_os.borealis.foo", &window_manager);
 
   // A window for the same app only starts that window.
   EXPECT_CALL(observer, OnWindowStarted(_, _));
   std::unique_ptr<ScopedTestWindow> second_foo =
-      MakeAndTrackWindow("org.chromium.borealis.foo", &window_manager);
+      MakeAndTrackWindow("org.chromium.guest_os.borealis.foo", &window_manager);
 
   // Whereas a new app starts both the app and the window.
   EXPECT_CALL(observer, OnAppStarted(_));
   EXPECT_CALL(observer, OnWindowStarted(_, _));
   std::unique_ptr<ScopedTestWindow> only_bar =
-      MakeAndTrackWindow("org.chromium.borealis.bar", &window_manager);
+      MakeAndTrackWindow("org.chromium.guest_os.borealis.bar", &window_manager);
 
   // Deleting an app window while one still exists does not end the app.
   EXPECT_CALL(observer, OnWindowFinished(_, _));
@@ -190,9 +206,9 @@
   EXPECT_CALL(observer, OnAnonymousAppAdded(_, _)).Times(1);
 
   std::unique_ptr<ScopedTestWindow> window1 = MakeAndTrackWindow(
-      "org.chromium.borealis.anonymous_app", &window_manager);
+      "org.chromium.guest_os.borealis.anonymous_app", &window_manager);
   std::unique_ptr<ScopedTestWindow> window2 = MakeAndTrackWindow(
-      "org.chromium.borealis.anonymous_app", &window_manager);
+      "org.chromium.guest_os.borealis.anonymous_app", &window_manager);
 
   // We only expect to see the app removed after the last window closes.
   window1.reset();
@@ -219,8 +235,8 @@
 
   BorealisWindowManager window_manager(profile());
   window_manager.AddObserver(&observer);
-  std::unique_ptr<ScopedTestWindow> window =
-      MakeAndTrackWindow("org.chromium.borealis.wmclass.foo", &window_manager);
+  std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow(
+      "org.chromium.guest_os.borealis.wmclass.foo", &window_manager);
 
   window_manager.RemoveObserver(&observer);
 }
diff --git a/chrome/browser/ash/bruschetta/bruschetta_launcher.cc b/chrome/browser/ash/bruschetta/bruschetta_launcher.cc
index e19a562..68fe21ed 100644
--- a/chrome/browser/ash/bruschetta/bruschetta_launcher.cc
+++ b/chrome/browser/ash/bruschetta/bruschetta_launcher.cc
@@ -28,7 +28,7 @@
 
 struct BruschettaLauncher::Files {
   base::ScopedFD firmware;
-  base::ScopedFD pflash;
+  absl::optional<base::ScopedFD> pflash;
 };
 
 namespace {
@@ -39,13 +39,27 @@
 // people following the instructions will have (base64 encoded "bru").
 const char kDiskName[] = "YnJ1.img";
 
+const char kOldBiosPath[] = "Downloads/bios";
+
 std::unique_ptr<BruschettaLauncher::Files> OpenFdsBlocking(
     base::FilePath profile_path) {
   base::File firmware(profile_path.Append(kBiosPath),
                       base::File::FLAG_OPEN | base::File::FLAG_READ);
   if (!firmware.IsValid()) {
-    PLOG(ERROR) << "Failed to open firmware";
-    return nullptr;
+    // TODO(b/265096855): In order to not break existing alpha users, keep on
+    // supporting the old BIOS path with no pflash. Remove this fallback once
+    // users are migrated.
+    firmware = base::File(profile_path.Append(kOldBiosPath),
+                          base::File::FLAG_OPEN | base::File::FLAG_READ);
+    if (!firmware.IsValid()) {
+      PLOG(ERROR) << "Failed to open firmware";
+      return nullptr;
+    }
+    BruschettaLauncher::Files files = {
+        .firmware = base::ScopedFD(firmware.TakePlatformFile()),
+        .pflash = absl::nullopt,
+    };
+    return std::make_unique<BruschettaLauncher::Files>(std::move(files));
   }
 
   base::File pflash(profile_path.Append(kPflashPath),
@@ -143,8 +157,13 @@
   std::vector<base::ScopedFD> fds;
   request.add_fds(vm_tools::concierge::StartVmRequest::BIOS);
   fds.push_back(std::move(files->firmware));
-  request.add_fds(vm_tools::concierge::StartVmRequest::PFLASH);
-  fds.push_back(std::move(files->pflash));
+  if (files->pflash) {
+    // TODO(b/265096855): In order to not break existing alpha users, keep on
+    // supporting the old BIOS path with no pflash. Remove this fallback once
+    // users are migrated.
+    request.add_fds(vm_tools::concierge::StartVmRequest::PFLASH);
+    fds.push_back(std::move(*files->pflash));
+  }
   files.reset();
 
   auto* disk = request.mutable_disks()->Add();
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn
index b4afdca..087b4ec0 100644
--- a/chrome/browser/ash/crosapi/BUILD.gn
+++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -20,6 +20,7 @@
     "//base",
     "//chrome/browser:browser_process",
     "//chrome/common",
+    "//chromeos/ash/components/standalone_browser",
     "//chromeos/crosapi/cpp",
     "//chromeos/crosapi/cpp:crosapi_constants",
     "//chromeos/crosapi/mojom",
@@ -463,6 +464,7 @@
     "//chromeos/ash/components/dbus/shill",
     "//chromeos/ash/components/dbus/upstart",
     "//chromeos/ash/components/login/login_state",
+    "//chromeos/ash/components/standalone_browser",
     "//chromeos/ash/components/system",
     "//chromeos/crosapi/cpp:cpp",
     "//chromeos/crosapi/cpp:crosapi_constants",
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_browsertest.cc b/chrome/browser/ash/crosapi/browser_data_migrator_browsertest.cc
index 7f4fc8e..722e12c4 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_browsertest.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_browsertest.cc
@@ -27,6 +27,7 @@
 #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
 #include "chromeos/ash/components/login/auth/public/user_context.h"
+#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/policy/policy_constants.h"
@@ -67,7 +68,7 @@
 }
 
 void SetLacrosAvailability(
-    crosapi::browser_util::LacrosAvailability lacros_availability) {
+    ash::standalone_browser::LacrosAvailability lacros_availability) {
   policy::PolicyMap policy;
   policy.Set(policy::key::kLacrosAvailability, policy::POLICY_LEVEL_MANDATORY,
              policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
@@ -198,7 +199,8 @@
   base::RunLoop run_loop;
   ScopedRestartAttemptForTesting scoped_restart_attempt(
       base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
-  SetLacrosAvailability(crosapi::browser_util::LacrosAvailability::kLacrosOnly);
+  SetLacrosAvailability(
+      ash::standalone_browser::LacrosAvailability::kLacrosOnly);
   ASSERT_TRUE(LoginAsExistingRegularUser());
   run_loop.Run();
   EXPECT_TRUE(
@@ -467,7 +469,8 @@
 };
 
 IN_PROC_BROWSER_TEST_F(BrowserDataMigratorForKiosk, MigrateOnKioskLaunch) {
-  SetLacrosAvailability(crosapi::browser_util::LacrosAvailability::kUserChoice);
+  SetLacrosAvailability(
+      ash::standalone_browser::LacrosAvailability::kUserChoice);
 
   // Call this so that the test app is registered with `KioskAppManager` and
   // thus the `AccountId` can be retrieved.
diff --git a/chrome/browser/ash/crosapi/browser_manager_unittest.cc b/chrome/browser/ash/crosapi/browser_manager_unittest.cc
index 8cc6318d1..c0daad8 100644
--- a/chrome/browser/ash/crosapi/browser_manager_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_manager_unittest.cc
@@ -17,6 +17,7 @@
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
+#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom-test-utils.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
 #include "components/account_id/account_id.h"
@@ -181,7 +182,7 @@
     // been loaded. As such we claim that the Lacros availability is allowed
     // to be set by the user.
     crosapi::browser_util::SetLacrosLaunchSwitchSourceForTest(
-        crosapi::browser_util::LacrosAvailability::kUserChoice);
+        ash::standalone_browser::LacrosAvailability::kUserChoice);
 
     EXPECT_CALL(mock_browser_service_, NewWindow(_, _, _, _)).Times(0);
     EXPECT_CALL(mock_browser_service_, OpenForFullRestore(_)).Times(0);
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc
index 04b380fd..718c350 100644
--- a/chrome/browser/ash/crosapi/browser_util.cc
+++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -24,6 +24,7 @@
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
+#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "chromeos/crosapi/cpp/crosapi_constants.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
 #include "components/component_updater/component_updater_service.h"
@@ -39,6 +40,7 @@
 #include "components/version_info/version_info.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 
+using ash::standalone_browser::LacrosAvailability;
 using user_manager::User;
 using version_info::Channel;
 
@@ -66,17 +68,6 @@
 constexpr char kLacrosMetadataContentKey[] = "content";
 constexpr char kLacrosMetadataVersionKey[] = "version";
 
-// The conversion map for LacrosAvailability policy data. The values must match
-// the ones from LacrosAvailability.yaml.
-constexpr auto kLacrosAvailabilityMap =
-    base::MakeFixedFlatMap<base::StringPiece, LacrosAvailability>({
-        {"user_choice", LacrosAvailability::kUserChoice},
-        {"lacros_disallowed", LacrosAvailability::kLacrosDisallowed},
-        {"side_by_side", LacrosAvailability::kSideBySide},
-        {"lacros_primary", LacrosAvailability::kLacrosPrimary},
-        {"lacros_only", LacrosAvailability::kLacrosOnly},
-    });
-
 // The conversion map for LacrosDataBackwardMigrationMode policy data. The
 // values must match the ones from LacrosDataBackwardMigrationMode.yaml.
 constexpr auto kLacrosDataBackwardMigrationModeMap =
@@ -169,7 +160,7 @@
     return LacrosAvailability::kUserChoice;
   }
 
-  auto result = ParseLacrosAvailability(policy_value);
+  auto result = ash::standalone_browser::ParseLacrosAvailability(policy_value);
   if (!result.has_value())
     return LacrosAvailability::kUserChoice;
 
@@ -1111,16 +1102,6 @@
              : LacrosLaunchSwitchSource::kForcedByPolicy;
 }
 
-absl::optional<LacrosAvailability> ParseLacrosAvailability(
-    base::StringPiece value) {
-  auto* it = kLacrosAvailabilityMap.find(value);
-  if (it != kLacrosAvailabilityMap.end())
-    return it->second;
-
-  LOG(ERROR) << "Unknown LacrosAvailability policy value is passed: " << value;
-  return absl::nullopt;
-}
-
 absl::optional<LacrosSelectionPolicy> ParseLacrosSelectionPolicy(
     base::StringPiece value) {
   auto* it = kLacrosSelectionPolicyMap.find(value);
@@ -1131,16 +1112,6 @@
   return absl::nullopt;
 }
 
-base::StringPiece GetLacrosAvailabilityPolicyName(LacrosAvailability value) {
-  for (const auto& entry : kLacrosAvailabilityMap) {
-    if (entry.second == value)
-      return entry.first;
-  }
-
-  NOTREACHED();
-  return base::StringPiece();
-}
-
 absl::optional<LacrosDataBackwardMigrationMode>
 ParseLacrosDataBackwardMigrationMode(base::StringPiece value) {
   auto* it = kLacrosDataBackwardMigrationModeMap.find(value);
diff --git a/chrome/browser/ash/crosapi/browser_util.h b/chrome/browser/ash/crosapi/browser_util.h
index a87ac77..530ff03e 100644
--- a/chrome/browser/ash/crosapi/browser_util.h
+++ b/chrome/browser/ash/crosapi/browser_util.h
@@ -10,6 +10,7 @@
 #include "base/auto_reset.h"
 #include "base/feature_list.h"
 #include "base/strings/string_piece.h"
+#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 class AccountId;
@@ -62,24 +63,6 @@
   kForcedByPolicy = 3
 };
 
-// Represents the policy indicating how to launch Lacros browser, named
-// LacrosAvailability. The values shall be consistent with the controlling
-// policy.
-enum class LacrosAvailability {
-  // Indicates that the user decides whether to enable Lacros (if allowed) and
-  // make it the primary/only browser.
-  kUserChoice = 0,
-  // Indicates that Lacros is not allowed to be enabled.
-  kLacrosDisallowed = 1,
-  // Indicates that Lacros will be enabled (if allowed). Ash browser is the
-  // primary browser.
-  kSideBySide = 2,
-  // Similar to kSideBySide but Lacros is the primary browser.
-  kLacrosPrimary = 3,
-  // Indicates that Lacros (if allowed) is the only available browser.
-  kLacrosOnly = 4
-};
-
 // Represents the policy indicating which Lacros browser to launch, named
 // LacrosSelection. The values shall be consistent with the controlling
 // policy. Unlike `LacrosSelection` representing which lacros to select,
@@ -294,7 +277,7 @@
 // `IsLacrosPrimaryBrowserAllowed()`.
 bool IsLacrosPrimaryBrowserAllowedForMigration(
     const user_manager::User* user,
-    LacrosAvailability lacros_availability);
+    ash::standalone_browser::LacrosAvailability lacros_availability);
 
 // Returns true if `ash::features::kLacrosPrimary` flag is allowed.
 bool IsLacrosPrimaryFlagAllowed();
@@ -383,11 +366,12 @@
 
 // Exposed for testing. Sets lacros-availability cache for testing.
 void SetCachedLacrosAvailabilityForTesting(
-    LacrosAvailability lacros_availability);
+    ash::standalone_browser::LacrosAvailability lacros_availability);
 
 // Exposed for testing. Returns the lacros integration suggested by the policy
 // lacros-availability, modified by Finch flags and user flags as appropriate.
-LacrosAvailability GetCachedLacrosAvailabilityForTesting();
+ash::standalone_browser::LacrosAvailability
+GetCachedLacrosAvailabilityForTesting();
 
 // GetCachedLacrosDataBackwardMigrationMode returns the cached value of the
 // LacrosDataBackwardMigrationMode policy.
@@ -465,21 +449,14 @@
 
 // Allow unit tests to simulate that the readout of policies has taken place
 // so that later DCHECKs do not fail.
-void SetLacrosLaunchSwitchSourceForTest(LacrosAvailability test_value);
-
-// Parses the string representation of LacrosAvailability policy value into
-// the enum value. Returns nullopt on unknown value.
-absl::optional<LacrosAvailability> ParseLacrosAvailability(
-    base::StringPiece value);
+void SetLacrosLaunchSwitchSourceForTest(
+    ash::standalone_browser::LacrosAvailability test_value);
 
 // Parses the string representation of LacrosSelection policy value into the
 // enum value. Returns nullopt on unknown value.
 absl::optional<LacrosSelectionPolicy> ParseLacrosSelectionPolicy(
     base::StringPiece value);
 
-// Returns the policy value name from the given value.
-base::StringPiece GetLacrosAvailabilityPolicyName(LacrosAvailability value);
-
 // Parses the string representation of LacrosDataBackwardMigrationMode policy
 // value into the enum value. Returns nullopt on unknown value.
 absl::optional<LacrosDataBackwardMigrationMode>
diff --git a/chrome/browser/ash/crosapi/browser_util_unittest.cc b/chrome/browser/ash/crosapi/browser_util_unittest.cc
index c2c328e..70d06a8 100644
--- a/chrome/browser/ash/crosapi/browser_util_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_util_unittest.cc
@@ -23,6 +23,7 @@
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
+#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "chromeos/ash/components/system/fake_statistics_provider.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
 #include "components/account_id/account_id.h"
@@ -32,7 +33,7 @@
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using crosapi::browser_util::LacrosAvailability;
+using ash::standalone_browser::LacrosAvailability;
 using crosapi::browser_util::LacrosLaunchSwitchSource;
 using crosapi::browser_util::LacrosSelection;
 using user_manager::User;
diff --git a/chrome/browser/ash/events/event_rewriter_unittest.cc b/chrome/browser/ash/events/event_rewriter_unittest.cc
index 3749f4a..44459693 100644
--- a/chrome/browser/ash/events/event_rewriter_unittest.cc
+++ b/chrome/browser/ash/events/event_rewriter_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/containers/flat_set.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ash/events/event_rewriter_delegate_impl.h"
 #include "chrome/browser/ash/input_method/input_method_configuration.h"
@@ -387,6 +388,26 @@
   message_center::FakeMessageCenter message_center_;
 };
 
+// TestKeyRewriteLatency checks that the event rewriter
+// publishes a latency metric every time a key is pressed.
+TEST_F(EventRewriterTest, TestKeyRewriteLatency) {
+  base::HistogramTester histogram_tester;
+  CheckKeyTestCase(rewriter(),
+                   {ui::ET_KEY_PRESSED,
+                    {ui::VKEY_B, ui::DomCode::US_B, ui::EF_CONTROL_DOWN,
+                     ui::DomKey::Constant<'b'>::Character},
+                    {ui::VKEY_B, ui::DomCode::US_B, ui::EF_CONTROL_DOWN,
+                     ui::DomKey::Constant<'b'>::Character}});
+  CheckKeyTestCase(rewriter(),
+                   {ui::ET_KEY_PRESSED,
+                    {ui::VKEY_B, ui::DomCode::US_B, ui::EF_CONTROL_DOWN,
+                     ui::DomKey::Constant<'b'>::Character},
+                    {ui::VKEY_B, ui::DomCode::US_B, ui::EF_CONTROL_DOWN,
+                     ui::DomKey::Constant<'b'>::Character}});
+  histogram_tester.ExpectTotalCount(
+      "ChromeOS.Inputs.EventRewriter.KeyRewriteLatency", 2);
+}
+
 TEST_F(EventRewriterTest, TestRewriteCommandToControl) {
   // First, test non Apple keyboards, they should all behave the same.
   TestNonAppleKeyboardVariants({
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index b567b87..da61ae09 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -191,6 +191,11 @@
     return *this;
   }
 
+  TestCase& EnableGoogleOneOfferFilesBanner() {
+    options.enable_google_one_offer_files_banner = true;
+    return *this;
+  }
+
   std::string GetFullName() const {
     std::string full_name = name;
 
@@ -240,6 +245,10 @@
     if (options.enable_os_feedback)
       full_name += "_OsFeedback";
 
+    if (options.enable_google_one_offer_files_banner) {
+      full_name += "_GoogleOneOfferFilesBanner";
+    }
+
     return full_name;
   }
 
@@ -1320,7 +1329,13 @@
         TestCase("driveOfflineInfoBanner"),
         TestCase("driveDeleteDialogDoesntMentionPermanentDelete"),
         TestCase("driveInlineSyncStatusSingleFile").EnableInlineStatusSync(),
-        TestCase("driveInlineSyncStatusParentFolder").EnableInlineStatusSync()
+        TestCase("driveInlineSyncStatusParentFolder").EnableInlineStatusSync(),
+        TestCase("driveGoogleOneOfferBannerEnabled")
+            .EnableGoogleOneOfferFilesBanner(),
+        // Google One offer banner is disabled by default.
+        TestCase("driveGoogleOneOfferBannerDisabled"),
+        TestCase("driveGoogleOneOfferBannerDismiss")
+            .EnableGoogleOneOfferFilesBanner()
         // TODO(b/189173190): Enable
         // TestCase("driveEnableDocsOfflineDialog"),
         // TODO(b/189173190): Enable
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
index 15a1c3a1..8482423 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -1993,6 +1993,12 @@
     disabled_features.push_back(ash::features::kOsFeedback);
   }
 
+  if (options.enable_google_one_offer_files_banner) {
+    enabled_features.push_back(ash::features::kGoogleOneOfferFilesBanner);
+  } else {
+    disabled_features.push_back(ash::features::kGoogleOneOfferFilesBanner);
+  }
+
   // This is destroyed in |TearDown()|. We cannot initialize this in the
   // constructor due to this feature values' above dependence on virtual
   // method calls, but by convention subclasses of this fixture may initialize
@@ -3236,7 +3242,8 @@
   }
 
   FAIL() << "Unknown test message: " << name;
-}
+}  // NOLINT(readability/fn_size): Structure of OnCommand function should be
+   // easy to manage.
 
 bool FileManagerBrowserTestBase::HandleGuestOsCommands(
     const std::string& name,
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
index e5d1736..a9a3f32 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
@@ -136,8 +136,11 @@
     // Whether tests should enable V2 of search.
     bool enable_search_v2 = false;
 
-    // Whether testt should enable OS Feedback.
+    // Whether tests should enable OS Feedback.
     bool enable_os_feedback = false;
+
+    // Whether tests should enable Google One offer Files banner.
+    bool enable_google_one_offer_files_banner = false;
   };
 
   FileManagerBrowserTestBase(const FileManagerBrowserTestBase&) = delete;
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc
index 7df4b033..9811c64 100644
--- a/chrome/browser/ash/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -1034,7 +1034,8 @@
   SET_STRING("DLP_COMPONENT_PLAY", IDS_FILE_BROWSER_DLP_COMPONENT_PLAY);
   SET_STRING("DLP_COMPONENT_LINUX", IDS_FILE_BROWSER_DLP_COMPONENT_LINUX);
   SET_STRING("DLP_COMPONENT_VM", IDS_FILE_BROWSER_DLP_COMPONENT_VM);
-}
+}  // NOLINT(readability/fn_size): Structure of AddStringsGeneric function
+   // should be easy to manage.
 
 #undef SET_STRING
 
@@ -1164,4 +1165,8 @@
   // Lastly, set UI_LOCALE and locale-dependent settings.
   dict->Set("UI_LOCALE", locale);
   dict->Set("WEEK_START_FROM", GetLocaleBasedWeekStart());
+
+  dict->Set(
+      "GOOGLE_ONE_OFFER_FILES_BANNER",
+      base::FeatureList::IsEnabled(ash::features::kGoogleOneOfferFilesBanner));
 }
diff --git a/chrome/browser/ash/floating_workspace/floating_workspace_service.cc b/chrome/browser/ash/floating_workspace/floating_workspace_service.cc
index b4a0138..ec75b39 100644
--- a/chrome/browser/ash/floating_workspace/floating_workspace_service.cc
+++ b/chrome/browser/ash/floating_workspace/floating_workspace_service.cc
@@ -34,9 +34,18 @@
 // Max time floating workspace service can wait after user login.
 // After that even a more recent foreign session change is detected
 // restore will not take place.
+// TODO(b/263417467): let the following parameters be controlled by Finch or
+// policy override.
 constexpr base::TimeDelta kMaxTimeAvaliableForRestoreAfterLogin =
     base::Seconds(3);
 
+constexpr base::TimeDelta kMaxTimeAvaliableForRestoreAfterLoginV2 =
+    base::Seconds(15);
+
+// Time interval to capture current desk as desk template
+// and upload template to server.
+constexpr base::TimeDelta kPeriodicJobIntervalInSeconds = base::Seconds(30);
+
 // Static
 FloatingWorkspaceService* FloatingWorkspaceService::GetForProfile(
     Profile* profile) {
@@ -162,6 +171,16 @@
   desk_sync_service_->GetDeskModel()->RemoveObserver(this);
 }
 
+void FloatingWorkspaceService::EntriesAddedOrUpdatedRemotely(
+    const std::vector<const DeskTemplate*>& new_entries) {
+  for (const DeskTemplate* desk_template : new_entries) {
+    if (desk_template &&
+        desk_template->type() == DeskTemplateType::kFloatingWorkspace) {
+      RestoreFloatingWorkspaceTemplate(desk_template);
+    }
+  }
+}
+
 void FloatingWorkspaceService::InitForV1() {
   session_sync_service_ =
       SessionSyncServiceFactory::GetInstance()->GetForProfile(profile_);
@@ -230,9 +249,6 @@
   timer_.Stop();
 }
 
-// TODO(b/258692868): Add a method in DesksClient to capture but not save
-// current desk for floating workspace; we can attach our own callback with the
-// prev/current comparison method to see if a upload/save is necessary.
 void FloatingWorkspaceService::CaptureAndUploadActiveDesk() {
   DesksClient::Get()->CaptureActiveDeskAndSaveTemplate(
       base::BindOnce(&FloatingWorkspaceService::OnTemplateCaptured,
@@ -240,34 +256,6 @@
       DeskTemplateType::kFloatingWorkspace);
 }
 
-void FloatingWorkspaceService::OnTemplateCaptured(
-    absl::optional<DesksClient::DeskActionError> error,
-    std::unique_ptr<DeskTemplate> desk_template) {
-  // Desk capture was not successful, nothing to upload.
-  if (!desk_template)
-    return;
-
-  // If successfully captured desk, remove old entry and record new uuid.
-  if (!FloatingWorkspaceService::IsCurrentDeskSameAsPrevious(
-          desk_template.get())) {
-    // Upload and save the template.
-    desk_sync_service_->GetDeskModel()->AddOrUpdateEntry(
-        std::move(desk_template),
-        base::BindOnce(&FloatingWorkspaceService::OnTemplateUploaded,
-                       weak_pointer_factory_.GetWeakPtr()));
-  }
-}
-
-void FloatingWorkspaceService::EntriesAddedOrUpdatedRemotely(
-    const std::vector<const DeskTemplate*>& new_entries) {
-  for (const DeskTemplate* desk_template : new_entries) {
-    if (desk_template &&
-        desk_template->type() == DeskTemplateType::kFloatingWorkspace) {
-      RestoreFloatingWorkspaceTemplate(desk_template);
-    }
-  }
-}
-
 void FloatingWorkspaceService::RestoreFloatingWorkspaceTemplate(
     const DeskTemplate* desk_template) {
   // Desk templates have been downloaded.
@@ -275,10 +263,10 @@
     return;
   }
 
-  // Check if template has been downloaded after 3 seconds.
+  // Check if template has been downloaded after 15 seconds (TBD).
   if (base::TimeTicks::Now() >
-      initialization_timestamp_ + kMaxTimeAvaliableForRestoreAfterLogin) {
-    // No need to restore any remote session 3 seconds (TBD) after login.
+      initialization_timestamp_ + kMaxTimeAvaliableForRestoreAfterLoginV2) {
+    // No need to restore any remote session 15 seconds (TBD) after login.
     should_run_restore_ = false;
     return;
   }
@@ -290,17 +278,6 @@
       desk_template->template_name());
 }
 
-void FloatingWorkspaceService::OnTemplateLaunched(
-    absl::optional<DesksClient::DeskActionError> error,
-    const base::GUID& desk_uuid) {
-  // Disable future floating workspace restore.
-  should_run_restore_ = false;
-}
-
-// TODO(b/256874545): Implement comparison where all apps/ browsers are checked.
-// As of right now, a return of false indicates that both templates
-// are different, thus periodic checks will happen every 30 seconds
-// regardless of if no changes exist.
 bool FloatingWorkspaceService::IsCurrentDeskSameAsPrevious(
     DeskTemplate* current_desk_template) const {
   if (!previously_captured_desk_template_) {
@@ -345,6 +322,32 @@
   return true;
 }
 
+void FloatingWorkspaceService::OnTemplateLaunched(
+    absl::optional<DesksClient::DeskActionError> error,
+    const base::GUID& desk_uuid) {
+  // Disable future floating workspace restore.
+  should_run_restore_ = false;
+}
+
+void FloatingWorkspaceService::OnTemplateCaptured(
+    absl::optional<DesksClient::DeskActionError> error,
+    std::unique_ptr<DeskTemplate> desk_template) {
+  // Desk capture was not successful, nothing to upload.
+  if (!desk_template) {
+    return;
+  }
+
+  // If successfully captured desk, remove old entry and record new uuid.
+  if (!FloatingWorkspaceService::IsCurrentDeskSameAsPrevious(
+          desk_template.get())) {
+    // Upload and save the template.
+    desk_sync_service_->GetDeskModel()->AddOrUpdateEntry(
+        std::move(desk_template),
+        base::BindOnce(&FloatingWorkspaceService::OnTemplateUploaded,
+                       weak_pointer_factory_.GetWeakPtr()));
+  }
+}
+
 void FloatingWorkspaceService::OnTemplateUploaded(
     desks_storage::DeskModel::AddOrUpdateEntryStatus status,
     std::unique_ptr<DeskTemplate> new_entry) {
diff --git a/chrome/browser/ash/floating_workspace/floating_workspace_service.h b/chrome/browser/ash/floating_workspace/floating_workspace_service.h
index 269fd0b..8d1021b 100644
--- a/chrome/browser/ash/floating_workspace/floating_workspace_service.h
+++ b/chrome/browser/ash/floating_workspace/floating_workspace_service.h
@@ -111,8 +111,6 @@
   // If no difference is recorded no upload job will be triggered.
   bool IsCurrentDeskSameAsPrevious(DeskTemplate* current_desk_template) const;
 
-  const base::TimeDelta kPeriodicJobIntervalInSeconds = base::Seconds(30);
-
   // Callback function that is run after a floating workspace template
   // is downloaded and launched.
   void OnTemplateLaunched(absl::optional<DesksClient::DeskActionError> error,
@@ -146,11 +144,11 @@
   // null for the duration of `this`.
   raw_ptr<desks_storage::DeskSyncService> desk_sync_service_ = nullptr;
 
+  std::unique_ptr<DeskTemplate> previously_captured_desk_template_;
+
   // Indicate if it is a testing class.
   bool is_testing_ = false;
 
-  std::unique_ptr<DeskTemplate> previously_captured_desk_template_;
-
   // Weak pointer factory used to provide references to this service.
   base::WeakPtrFactory<FloatingWorkspaceService> weak_pointer_factory_{this};
 };
diff --git a/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.cc b/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.cc
index 308af18..5ed8d3b5 100644
--- a/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.cc
+++ b/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.cc
@@ -38,7 +38,7 @@
   }
 }
 
-absl::optional<crosapi::browser_util::LacrosAvailability>
+absl::optional<ash::standalone_browser::LacrosAvailability>
 LacrosAvailabilityPolicyHandler::GetValue(const PolicyMap& policies,
                                           PolicyErrorMap* errors) {
   const base::Value* value;
@@ -47,7 +47,7 @@
     return absl::nullopt;
 
   auto parsed =
-      crosapi::browser_util::ParseLacrosAvailability(value->GetString());
+      ash::standalone_browser::ParseLacrosAvailability(value->GetString());
   if (!parsed.has_value() && errors)
     errors->AddError(policy_name(), IDS_POLICY_INVALID_SELECTION_ERROR,
                      "LacrosAvailabilty value");
diff --git a/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.h b/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.h
index 3e1502e6..c6e0dbe 100644
--- a/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.h
+++ b/chrome/browser/ash/policy/handlers/lacros_availability_policy_handler.h
@@ -7,7 +7,7 @@
 
 #include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "components/policy/core/browser/configuration_policy_handler.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -35,7 +35,7 @@
                            PrefValueMap* prefs) override;
 
  private:
-  absl::optional<crosapi::browser_util::LacrosAvailability> GetValue(
+  absl::optional<ash::standalone_browser::LacrosAvailability> GetValue(
       const PolicyMap& policies,
       PolicyErrorMap* errors);
 };
diff --git a/chrome/browser/ash/preferences.cc b/chrome/browser/ash/preferences.cc
index 0c355a4..6febb32 100644
--- a/chrome/browser/ash/preferences.cc
+++ b/chrome/browser/ash/preferences.cc
@@ -51,6 +51,7 @@
 #include "chromeos/ash/components/dbus/update_engine/update_engine_client.h"
 #include "chromeos/ash/components/peripheral_notification/peripheral_notification_manager.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
+#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "chromeos/ash/components/system/devicemode.h"
 #include "chromeos/ash/components/system/statistics_provider.h"
 #include "chromeos/ash/components/timezone/timezone_resolver.h"
@@ -145,7 +146,8 @@
   registry->RegisterStringPref(::prefs::kMinimumAllowedChromeVersion, "");
   registry->RegisterIntegerPref(
       ::prefs::kLacrosLaunchSwitch,
-      static_cast<int>(crosapi::browser_util::LacrosAvailability::kUserChoice));
+      static_cast<int>(
+          ash::standalone_browser::LacrosAvailability::kUserChoice));
   registry->RegisterIntegerPref(
       ::prefs::kLacrosSelection,
       static_cast<int>(
diff --git a/chrome/browser/ash/settings/about_flags.cc b/chrome/browser/ash/settings/about_flags.cc
index 73fd594..1297f2bb 100644
--- a/chrome/browser/ash/settings/about_flags.cc
+++ b/chrome/browser/ash/settings/about_flags.cc
@@ -209,8 +209,8 @@
   if (lacros_launch_switch_pref->IsManaged()) {
     // If there's the value, convert it into the feature name.
     base::StringPiece value =
-        crosapi::browser_util::GetLacrosAvailabilityPolicyName(
-            static_cast<crosapi::browser_util::LacrosAvailability>(
+        ash::standalone_browser::GetLacrosAvailabilityPolicyName(
+            static_cast<ash::standalone_browser::LacrosAvailability>(
                 lacros_launch_switch_pref->GetValue()->GetInt()));
     DCHECK(!value.empty())
         << "The unexpect value is set to LacrosAvailability: "
diff --git a/chrome/browser/ash/sync/sync_appsync_optin_client.cc b/chrome/browser/ash/sync/sync_appsync_optin_client.cc
index 39f46e3d..a1e367b4 100644
--- a/chrome/browser/ash/sync/sync_appsync_optin_client.cc
+++ b/chrome/browser/ash/sync/sync_appsync_optin_client.cc
@@ -7,6 +7,7 @@
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/task/sequenced_task_runner.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/sync/base/user_selectable_type.h"
@@ -19,6 +20,8 @@
 
 constexpr char kDaemonStorePath[] = "/run/daemon-store/appsync-optin";
 constexpr char kDaemonStoreFileName[] = "opted-in";
+constexpr char kAppsSyncOptinIOHistogram[] =
+    "Cros.AppsSyncOptinFileWriteAttempts";
 
 namespace {
 bool IsAppsSyncEnabledForSyncService(const syncer::SyncService& sync_service) {
@@ -29,9 +32,15 @@
 void WriteOptinFile(base::FilePath filepath, bool opted_in) {
   const std::string file_contents = opted_in ? "1" : "0";
 
+  base::UmaHistogramEnumeration(
+      kAppsSyncOptinIOHistogram,
+      SyncAppsyncOptinClient::AppsSyncOptinFileWrite::kAttempt);
   if (!base::WriteFile(filepath, file_contents)) {
     DLOG(ERROR) << "Failed to persist opt-in change " << file_contents
                 << " to daemon-store. State on disk will be inaccurate!";
+    base::UmaHistogramEnumeration(
+        kAppsSyncOptinIOHistogram,
+        SyncAppsyncOptinClient::AppsSyncOptinFileWrite::kFailure);
   }
 }
 }  // namespace
@@ -94,8 +103,6 @@
   bool new_is_apps_sync_enabled =
       IsAppsSyncEnabledForSyncService(*sync_service_);
   // Don't update file if we have a non-relevant state change reporter.
-  // NOTE: if we end up seeing writes fail for whatever reason, could add a
-  // random chance to update file on any time the function is fired anyhow?
   if (new_is_apps_sync_enabled != is_apps_sync_enabled_) {
     UpdateOptinFile(new_is_apps_sync_enabled, sync_service);
     is_apps_sync_enabled_ = new_is_apps_sync_enabled;
diff --git a/chrome/browser/ash/sync/sync_appsync_optin_client.h b/chrome/browser/ash/sync/sync_appsync_optin_client.h
index 1d900bdb..e60bb8d 100644
--- a/chrome/browser/ash/sync/sync_appsync_optin_client.h
+++ b/chrome/browser/ash/sync/sync_appsync_optin_client.h
@@ -45,6 +45,14 @@
   // syncer::SyncServiceObserver
   void OnStateChanged(syncer::SyncService* sync_service) override;
 
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class AppsSyncOptinFileWrite {
+    kAttempt = 0,
+    kFailure = 1,
+    kMaxValue = kFailure,
+  };
+
  private:
   // Issues a write to the opt-in file, to reflect Profile state.
   void UpdateOptinFile(bool opted_in, const syncer::SyncService* sync_service);
diff --git a/chrome/browser/ash/sync/sync_appsync_optin_client_unittest.cc b/chrome/browser/ash/sync/sync_appsync_optin_client_unittest.cc
index cbae4c0..d9c075e 100644
--- a/chrome/browser/ash/sync/sync_appsync_optin_client_unittest.cc
+++ b/chrome/browser/ash/sync/sync_appsync_optin_client_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/observer_list.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "components/account_id/account_id.h"
@@ -27,6 +28,9 @@
 
 namespace ash {
 
+constexpr char kAppsSyncOptinIOHistogram[] =
+    "Cros.AppsSyncOptinFileWriteAttempts";
+
 namespace {
 
 class FakeSyncService : public syncer::TestSyncService {
@@ -164,24 +168,29 @@
 
 TEST_F(SyncAppsyncOptinClientTest, ServiceCreatesOptInFile) {
   EXPECT_TRUE(base::IsDirectoryEmpty(tmp_dir_path_));
+  base::HistogramTester histogram_tester;
 
+  test_sync_service_->SetAppsyncOptin(false);
   test_appsync_optin_client_ = std::make_unique<SyncAppsyncOptinClient>(
       test_sync_service_.get(), test_user_manager_.get(),
       test_daemon_dir_.GetPath());
-  test_sync_service_->SetAppsyncOptin(false);
 
   // Wait for file IO to finish.
   task_environment_.RunUntilIdle();
 
   EXPECT_FALSE(base::IsDirectoryEmpty(tmp_dir_path_));
   EXPECT_TRUE(base::PathExists(tmp_dir_path_.Append("opted-in")));
+
+  histogram_tester.ExpectUniqueSample(
+      kAppsSyncOptinIOHistogram,
+      SyncAppsyncOptinClient::AppsSyncOptinFileWrite::kAttempt, 1);
 }
 
 TEST_F(SyncAppsyncOptinClientTest, LoggedInUser) {
+  test_sync_service_->SetAppsyncOptin(false);
   test_appsync_optin_client_ = std::make_unique<SyncAppsyncOptinClient>(
       test_sync_service_.get(), test_user_manager_.get(),
       test_daemon_dir_.GetPath());
-  test_sync_service_->SetAppsyncOptin(false);
 
   // Wait for file IO to finish.
   task_environment_.RunUntilIdle();
@@ -195,10 +204,10 @@
 }
 
 TEST_F(SyncAppsyncOptinClientTest, LoggedInUserWithPermission) {
+  test_sync_service_->SetAppsyncOptin(true);
   test_appsync_optin_client_ = std::make_unique<SyncAppsyncOptinClient>(
       test_sync_service_.get(), test_user_manager_.get(),
       test_daemon_dir_.GetPath());
-  test_sync_service_->SetAppsyncOptin(true);
 
   // Wait for file IO to finish.
   task_environment_.RunUntilIdle();
@@ -212,10 +221,12 @@
 }
 
 TEST_F(SyncAppsyncOptinClientTest, UserChangesPermission) {
+  base::HistogramTester histogram_tester;
+
+  test_sync_service_->SetAppsyncOptin(true);
   test_appsync_optin_client_ = std::make_unique<SyncAppsyncOptinClient>(
       test_sync_service_.get(), test_user_manager_.get(),
       test_daemon_dir_.GetPath());
-  test_sync_service_->SetAppsyncOptin(true);
 
   // Wait for file IO to finish.
   task_environment_.RunUntilIdle();
@@ -237,6 +248,29 @@
   EXPECT_TRUE(
       base::ReadFileToString(tmp_dir_path_.Append("opted-in"), &contents));
   EXPECT_EQ("0", contents);
+
+  histogram_tester.ExpectUniqueSample(
+      kAppsSyncOptinIOHistogram,
+      SyncAppsyncOptinClient::AppsSyncOptinFileWrite::kAttempt, 2);
+}
+
+TEST_F(SyncAppsyncOptinClientTest, WriteFails) {
+  base::HistogramTester histogram_tester;
+  test_appsync_optin_client_ = std::make_unique<SyncAppsyncOptinClient>(
+      test_sync_service_.get(), test_user_manager_.get(),
+      test_daemon_dir_.GetPath().Append("NOT-A-REAL-PATH"));
+
+  // Wait for file IO to finish.
+  task_environment_.RunUntilIdle();
+
+  EXPECT_TRUE(base::IsDirectoryEmpty(tmp_dir_path_));
+
+  histogram_tester.ExpectBucketCount(
+      kAppsSyncOptinIOHistogram,
+      SyncAppsyncOptinClient::AppsSyncOptinFileWrite::kAttempt, 1);
+  histogram_tester.ExpectBucketCount(
+      kAppsSyncOptinIOHistogram,
+      SyncAppsyncOptinClient::AppsSyncOptinFileWrite::kFailure, 1);
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ash/sync/synced_session_client_ash.cc b/chrome/browser/ash/sync/synced_session_client_ash.cc
index fbdbd28..e5516d47 100644
--- a/chrome/browser/ash/sync/synced_session_client_ash.cc
+++ b/chrome/browser/ash/sync/synced_session_client_ash.cc
@@ -7,11 +7,45 @@
 #include <utility>
 
 #include "chromeos/crosapi/mojom/synced_session_client.mojom.h"
+#include "components/sync_sessions/synced_session.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 
 namespace ash {
 
+ForeignSyncedSessionAsh::ForeignSyncedSessionAsh() = default;
+ForeignSyncedSessionAsh::ForeignSyncedSessionAsh(
+    const ForeignSyncedSessionAsh&) = default;
+ForeignSyncedSessionAsh::ForeignSyncedSessionAsh(ForeignSyncedSessionAsh&&) =
+    default;
+ForeignSyncedSessionAsh& ForeignSyncedSessionAsh::operator=(
+    const ForeignSyncedSessionAsh&) = default;
+ForeignSyncedSessionAsh& ForeignSyncedSessionAsh::operator=(
+    ForeignSyncedSessionAsh&&) = default;
+ForeignSyncedSessionAsh::~ForeignSyncedSessionAsh() = default;
+
+ForeignSyncedSessionWindowAsh::ForeignSyncedSessionWindowAsh() = default;
+ForeignSyncedSessionWindowAsh::ForeignSyncedSessionWindowAsh(
+    const ForeignSyncedSessionWindowAsh&) = default;
+ForeignSyncedSessionWindowAsh::ForeignSyncedSessionWindowAsh(
+    ForeignSyncedSessionWindowAsh&&) = default;
+ForeignSyncedSessionWindowAsh& ForeignSyncedSessionWindowAsh::operator=(
+    const ForeignSyncedSessionWindowAsh&) = default;
+ForeignSyncedSessionWindowAsh& ForeignSyncedSessionWindowAsh::operator=(
+    ForeignSyncedSessionWindowAsh&&) = default;
+ForeignSyncedSessionWindowAsh::~ForeignSyncedSessionWindowAsh() = default;
+
+ForeignSyncedSessionTabAsh::ForeignSyncedSessionTabAsh() = default;
+ForeignSyncedSessionTabAsh::ForeignSyncedSessionTabAsh(
+    const ForeignSyncedSessionTabAsh&) = default;
+ForeignSyncedSessionTabAsh::ForeignSyncedSessionTabAsh(
+    ForeignSyncedSessionTabAsh&&) = default;
+ForeignSyncedSessionTabAsh& ForeignSyncedSessionTabAsh::operator=(
+    const ForeignSyncedSessionTabAsh&) = default;
+ForeignSyncedSessionTabAsh& ForeignSyncedSessionTabAsh::operator=(
+    ForeignSyncedSessionTabAsh&&) = default;
+ForeignSyncedSessionTabAsh::~ForeignSyncedSessionTabAsh() = default;
+
 SyncedSessionClientAsh::SyncedSessionClientAsh() = default;
 SyncedSessionClientAsh::~SyncedSessionClientAsh() = default;
 
@@ -22,8 +56,39 @@
 
 void SyncedSessionClientAsh::OnForeignSyncedPhoneSessionsUpdated(
     std::vector<crosapi::mojom::SyncedSessionPtr> sessions) {
-  // TODO(b/260599791): implement handling of SyncedSessions upon update.
-  NOTIMPLEMENTED();
+  // TODO(jasonrhee): Implement the deserialization as a Mojom StructTrait as a
+  // fast follow after initial prototype.
+  last_foreign_synced_phone_sessions_.clear();
+  for (const crosapi::mojom::SyncedSessionPtr& session : sessions) {
+    ForeignSyncedSessionAsh current_session;
+    current_session.session_name = session->session_name;
+    current_session.modified_time = session->modified_time;
+    for (const crosapi::mojom::SyncedSessionWindowPtr& window :
+         session->windows) {
+      ForeignSyncedSessionWindowAsh current_window;
+      for (const crosapi::mojom::SyncedSessionTabPtr& tab : window->tabs) {
+        ForeignSyncedSessionTabAsh current_tab;
+        current_tab.current_navigation_title = tab->current_navigation_title;
+        current_tab.last_modified_timestamp = tab->last_modified_timestamp;
+        current_tab.current_navigation_url = tab->current_navigation_url;
+        current_window.tabs.push_back(std::move(current_tab));
+      }
+      current_session.windows.push_back(std::move(current_window));
+    }
+    last_foreign_synced_phone_sessions_.push_back(std::move(current_session));
+  }
+  for (auto& observer : observers_) {
+    observer.OnForeignSyncedPhoneSessionsUpdated(
+        last_foreign_synced_phone_sessions_);
+  }
+}
+
+void SyncedSessionClientAsh::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void SyncedSessionClientAsh::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ash/sync/synced_session_client_ash.h b/chrome/browser/ash/sync/synced_session_client_ash.h
index 54a789f..8342ef7 100644
--- a/chrome/browser/ash/sync/synced_session_client_ash.h
+++ b/chrome/browser/ash/sync/synced_session_client_ash.h
@@ -5,24 +5,87 @@
 #ifndef CHROME_BROWSER_ASH_SYNC_SYNCED_SESSION_CLIENT_ASH_H_
 #define CHROME_BROWSER_ASH_SYNC_SYNCED_SESSION_CLIENT_ASH_H_
 
+#include <memory>
+#include <string>
 #include <vector>
 
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+#include "base/time/time.h"
 #include "chromeos/crosapi/mojom/synced_session_client.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
+#include "url/gurl.h"
 
 namespace ash {
 
+// Represent a subset of SerializedNavigationEntry data available for Ash via
+// crosapi.
+struct ForeignSyncedSessionTabAsh {
+ public:
+  ForeignSyncedSessionTabAsh();
+  ForeignSyncedSessionTabAsh(const ForeignSyncedSessionTabAsh&);
+  ForeignSyncedSessionTabAsh(ForeignSyncedSessionTabAsh&&);
+  ForeignSyncedSessionTabAsh& operator=(const ForeignSyncedSessionTabAsh&);
+  ForeignSyncedSessionTabAsh& operator=(ForeignSyncedSessionTabAsh&&);
+  ~ForeignSyncedSessionTabAsh();
+
+  GURL current_navigation_url;
+  std::u16string current_navigation_title;
+  base::Time last_modified_timestamp;
+};
+
+// Represent subset of SessionWindow data available for Ash via crosapi.
+struct ForeignSyncedSessionWindowAsh {
+ public:
+  ForeignSyncedSessionWindowAsh();
+  ForeignSyncedSessionWindowAsh(const ForeignSyncedSessionWindowAsh&);
+  ForeignSyncedSessionWindowAsh(ForeignSyncedSessionWindowAsh&&);
+  ForeignSyncedSessionWindowAsh& operator=(
+      const ForeignSyncedSessionWindowAsh&);
+  ForeignSyncedSessionWindowAsh& operator=(ForeignSyncedSessionWindowAsh&&);
+  ~ForeignSyncedSessionWindowAsh();
+
+  std::vector<ForeignSyncedSessionTabAsh> tabs;
+};
+
+// Represent subset of SyncedSession data available for Ash via crosapi.
+struct ForeignSyncedSessionAsh {
+ public:
+  ForeignSyncedSessionAsh();
+  ForeignSyncedSessionAsh(const ForeignSyncedSessionAsh&);
+  ForeignSyncedSessionAsh(ForeignSyncedSessionAsh&&);
+  ForeignSyncedSessionAsh& operator=(const ForeignSyncedSessionAsh&);
+  ForeignSyncedSessionAsh& operator=(ForeignSyncedSessionAsh&&);
+  ~ForeignSyncedSessionAsh();
+
+  std::string session_name;
+  base::Time modified_time;
+  std::vector<ForeignSyncedSessionWindowAsh> windows;
+};
+
 // Implements the SyncedSessionClient mojo interface to receive foreign session
 // updates.
 class SyncedSessionClientAsh final
     : public crosapi::mojom::SyncedSessionClient {
  public:
+  class Observer : public base::CheckedObserver {
+   public:
+    // OnForeignSyncedPhoneSessionsUpdated() per observer is called every time
+    // we receive an update of foreign synced phone sessions from Lacros via the
+    // crosapi.
+    virtual void OnForeignSyncedPhoneSessionsUpdated(
+        const std::vector<ForeignSyncedSessionAsh>& sessions) {}
+  };
+
   SyncedSessionClientAsh();
   SyncedSessionClientAsh(const SyncedSessionClientAsh&) = delete;
   SyncedSessionClientAsh& operator=(const SyncedSessionClientAsh&) = delete;
   ~SyncedSessionClientAsh() override;
 
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
   void BindReceiver(
       mojo::PendingReceiver<crosapi::mojom::SyncedSessionClient> receiver);
 
@@ -30,8 +93,15 @@
   void OnForeignSyncedPhoneSessionsUpdated(
       std::vector<crosapi::mojom::SyncedSessionPtr> sessions) override;
 
+  const std::vector<ForeignSyncedSessionAsh>&
+  last_foreign_synced_phone_sessions() const {
+    return last_foreign_synced_phone_sessions_;
+  }
+
  private:
   mojo::ReceiverSet<crosapi::mojom::SyncedSessionClient> receivers_;
+  base::ObserverList<Observer> observers_;
+  std::vector<ForeignSyncedSessionAsh> last_foreign_synced_phone_sessions_;
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ash/sync/synced_session_client_ash_unittest.cc b/chrome/browser/ash/sync/synced_session_client_ash_unittest.cc
new file mode 100644
index 0000000..1688358
--- /dev/null
+++ b/chrome/browser/ash/sync/synced_session_client_ash_unittest.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 "chrome/browser/ash/sync/synced_session_client_ash.h"
+
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "chromeos/crosapi/mojom/synced_session_client.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace ash {
+
+namespace {
+
+constexpr char kTestSessionName[] = "testing";
+constexpr char kTestUrl[] = "www.google.com";
+constexpr char16_t kTestTitle[] = u"helloworld";
+constexpr base::Time kTestModifiedTime = base::Time::FromTimeT(100);
+constexpr base::Time kTestLastModifiedTimestamp = base::Time::FromTimeT(200);
+
+std::vector<crosapi::mojom::SyncedSessionPtr> CreateTestSyncedSessions() {
+  std::vector<crosapi::mojom::SyncedSessionPtr> test_sessions;
+  crosapi::mojom::SyncedSessionPtr test_session =
+      crosapi::mojom::SyncedSession::New();
+  test_session->session_name = kTestSessionName;
+  test_session->modified_time = kTestModifiedTime;
+  crosapi::mojom::SyncedSessionWindowPtr test_window =
+      crosapi::mojom::SyncedSessionWindow::New();
+  crosapi::mojom::SyncedSessionTabPtr test_tab =
+      crosapi::mojom::SyncedSessionTab::New();
+  test_tab->current_navigation_url = GURL(kTestUrl);
+  test_tab->last_modified_timestamp = kTestLastModifiedTimestamp;
+  test_tab->current_navigation_title = kTestTitle;
+  test_window->tabs.push_back(std::move(test_tab));
+  test_session->windows.push_back(std::move(test_window));
+  test_sessions.push_back(std::move(test_session));
+  return test_sessions;
+}
+
+class TestSyncedSessionClientObserver
+    : public SyncedSessionClientAsh::Observer {
+ public:
+  TestSyncedSessionClientObserver() = default;
+  TestSyncedSessionClientObserver(const TestSyncedSessionClientObserver&) =
+      delete;
+  TestSyncedSessionClientObserver& operator=(
+      const TestSyncedSessionClientObserver&) = delete;
+  ~TestSyncedSessionClientObserver() override = default;
+
+  void OnForeignSyncedPhoneSessionsUpdated(
+      const std::vector<ForeignSyncedSessionAsh>& sessions) override {
+    read_sessions_ = sessions;
+  }
+
+  const std::vector<ForeignSyncedSessionAsh>& GetLastReadSessions() const {
+    return read_sessions_;
+  }
+
+ private:
+  std::vector<ForeignSyncedSessionAsh> read_sessions_;
+};
+
+}  // namespace
+
+class SyncedSessionClientAshTest : public testing::Test {
+ public:
+  SyncedSessionClientAshTest() = default;
+  SyncedSessionClientAshTest(const SyncedSessionClientAshTest&) = delete;
+  SyncedSessionClientAshTest& operator=(const SyncedSessionClientAshTest&) =
+      delete;
+  ~SyncedSessionClientAshTest() override = default;
+
+  void SetUp() override {
+    client_ = std::make_unique<SyncedSessionClientAsh>();
+    client_->BindReceiver(client_remote_.BindNewPipeAndPassReceiver());
+    test_observer_ = std::make_unique<TestSyncedSessionClientObserver>();
+    client_->AddObserver(test_observer_.get());
+  }
+
+  SyncedSessionClientAsh* client() {
+    DCHECK(client_);
+    return client_.get();
+  }
+
+  mojo::Remote<crosapi::mojom::SyncedSessionClient>* client_remote() {
+    return &client_remote_;
+  }
+
+  TestSyncedSessionClientObserver* test_observer() {
+    DCHECK(test_observer_);
+    return test_observer_.get();
+  }
+
+ private:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+
+  std::unique_ptr<SyncedSessionClientAsh> client_;
+  mojo::Remote<crosapi::mojom::SyncedSessionClient> client_remote_;
+  std::unique_ptr<TestSyncedSessionClientObserver> test_observer_;
+};
+
+TEST_F(SyncedSessionClientAshTest, OnForeignSyncedPhoneSessionsUpdated) {
+  client()->OnForeignSyncedPhoneSessionsUpdated(CreateTestSyncedSessions());
+  std::vector<ForeignSyncedSessionAsh> observed_sessions =
+      test_observer()->GetLastReadSessions();
+  ASSERT_EQ(observed_sessions.size(), 1u);
+  EXPECT_EQ(observed_sessions[0].session_name, kTestSessionName);
+  EXPECT_EQ(observed_sessions[0].modified_time, kTestModifiedTime);
+  ASSERT_EQ(observed_sessions[0].windows.size(), 1u);
+  ASSERT_EQ(observed_sessions[0].windows[0].tabs.size(), 1u);
+  EXPECT_EQ(observed_sessions[0].windows[0].tabs[0].current_navigation_url,
+            GURL(kTestUrl));
+  EXPECT_EQ(observed_sessions[0].windows[0].tabs[0].last_modified_timestamp,
+            kTestLastModifiedTimestamp);
+  EXPECT_EQ(observed_sessions[0].windows[0].tabs[0].current_navigation_title,
+            kTestTitle);
+}
+
+}  // namespace ash
diff --git a/chrome/browser/component_updater/updater_state.cc b/chrome/browser/component_updater/updater_state.cc
index 5fec8d2b..c15c8f8 100644
--- a/chrome/browser/component_updater/updater_state.cc
+++ b/chrome/browser/component_updater/updater_state.cc
@@ -93,7 +93,8 @@
 
 base::Time UpdaterState::StateReaderChromiumUpdater::FindTimeKey(
     base::StringPiece key) const {
-  return base::ValueToTime(parsed_json_.FindKey(key)).value_or(base::Time());
+  return base::ValueToTime(parsed_json_.GetDict().Find(key))
+      .value_or(base::Time());
 }
 
 std::string UpdaterState::StateReaderChromiumUpdater::GetUpdaterName() const {
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index cadf4fe..1f922a3 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -505,12 +505,12 @@
   {
     "name": "autofill-enable-ranking-formula",
     "owners": [ "alexandertekle@google.com", "koerber@google.com" ],
-    "expiry_milestone": 109
+    "expiry_milestone": 120
   },
   {
     "name": "autofill-enable-ranking-formula-address-profiles",
     "owners": [ "alexandertekle@google.com", "koerber@google.com" ],
-    "expiry_milestone": 112
+    "expiry_milestone": 120
   },
   {
     "name": "autofill-enable-remade-downstream-metrics",
diff --git a/chrome/browser/lacros/sync/crosapi_session_sync_notifier.h b/chrome/browser/lacros/sync/crosapi_session_sync_notifier.h
new file mode 100644
index 0000000..5a414788
--- /dev/null
+++ b/chrome/browser/lacros/sync/crosapi_session_sync_notifier.h
@@ -0,0 +1,19 @@
+// 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_LACROS_SYNC_CROSAPI_SESSION_SYNC_NOTIFIER_H_
+#define CHROME_BROWSER_LACROS_SYNC_CROSAPI_SESSION_SYNC_NOTIFIER_H_
+
+// This class is responsible for sending browser window data to Ash upon changes
+// to foreign browser sessions.
+class CrosapiSessionSyncNotifier {
+ public:
+  CrosapiSessionSyncNotifier(const CrosapiSessionSyncNotifier&) = delete;
+  CrosapiSessionSyncNotifier() = default;
+  CrosapiSessionSyncNotifier& operator=(const CrosapiSessionSyncNotifier&) =
+      delete;
+  ~CrosapiSessionSyncNotifier() = default;
+};
+
+#endif  // CHROME_BROWSER_LACROS_SYNC_CROSAPI_SESSION_SYNC_NOTIFIER_H_
\ No newline at end of file
diff --git a/chrome/browser/lacros/sync/sync_crosapi_manager_lacros.cc b/chrome/browser/lacros/sync/sync_crosapi_manager_lacros.cc
index 0393f8b..3071f36 100644
--- a/chrome/browser/lacros/sync/sync_crosapi_manager_lacros.cc
+++ b/chrome/browser/lacros/sync/sync_crosapi_manager_lacros.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/feature_list.h"
+#include "chrome/browser/lacros/sync/crosapi_session_sync_notifier.h"
 #include "chrome/browser/lacros/sync/sync_explicit_passphrase_client_lacros.h"
 #include "chrome/browser/lacros/sync/sync_user_settings_client_lacros.h"
 #include "chrome/browser/profiles/profile.h"
@@ -88,6 +89,25 @@
       std::move(client_remote), sync_user_settings);
 }
 
+// Detects changes in foreign browser sessions and notify
+// CrosapiSessionSyncNotifier
+std::unique_ptr<CrosapiSessionSyncNotifier>
+MaybeCreateCrosapiSessionSyncNotifier() {
+  if (chromeos::LacrosService::Get()
+          ->GetInterfaceVersion<crosapi::mojom::SyncService>() <
+      static_cast<int>(
+          crosapi::mojom::SyncService::kBindSyncedSessionClientMinVersion)) {
+    return nullptr;
+  }
+  // TODO(b/260599791): in a subsequent CL,
+  // - a CrosapiSessionSyncNotifier will be created and its member function
+  // passed as part of the subscription to foreign browser sessions. Upon a
+  // change in foreign browser sessions, all work will be inside of the
+  // CrosapiSessionSyncNotifier object.
+  // - Check that kSyncedSessionClient flag is enabled
+  return nullptr;
+}
+
 }  // namespace
 
 SyncCrosapiManagerLacros::SyncCrosapiManagerLacros() = default;
@@ -106,6 +126,9 @@
   }
   sync_service->AddObserver(this);
 
+  DCHECK(!crosapi_session_sync_notifier_);
+  crosapi_session_sync_notifier_ = MaybeCreateCrosapiSessionSyncNotifier();
+
   DCHECK(!sync_explicit_passphrase_client_);
   sync_explicit_passphrase_client_ =
       MaybeCreateSyncExplicitPassphraseClient(lacros_service, sync_service);
diff --git a/chrome/browser/lacros/sync/sync_crosapi_manager_lacros.h b/chrome/browser/lacros/sync/sync_crosapi_manager_lacros.h
index 7cc11bd..be5c2c8d 100644
--- a/chrome/browser/lacros/sync/sync_crosapi_manager_lacros.h
+++ b/chrome/browser/lacros/sync/sync_crosapi_manager_lacros.h
@@ -12,6 +12,7 @@
 class Profile;
 class SyncExplicitPassphraseClientLacros;
 class SyncUserSettingsClientLacros;
+class CrosapiSessionSyncNotifier;
 
 namespace syncer {
 class SyncService;
@@ -35,6 +36,7 @@
   std::unique_ptr<SyncExplicitPassphraseClientLacros>
       sync_explicit_passphrase_client_;
   std::unique_ptr<SyncUserSettingsClientLacros> sync_user_settings_client_;
+  std::unique_ptr<CrosapiSessionSyncNotifier> crosapi_session_sync_notifier_;
 };
 
 #endif  // CHROME_BROWSER_LACROS_SYNC_SYNC_CROSAPI_MANAGER_LACROS_H_
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.cc
index 60581cf..d09ca8c 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.cc
@@ -38,12 +38,12 @@
                                 base::Unretained(impl_.get())));
 }
 
-void DialMediaSinkService::OnUserGesture() {
+void DialMediaSinkService::DiscoverSinksNow() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(impl_);
 
   impl_->task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&DialMediaSinkServiceImpl::OnUserGesture,
+      FROM_HERE, base::BindOnce(&DialMediaSinkServiceImpl::DiscoverSinksNow,
                                 base::Unretained(impl_.get())));
 }
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h
index 4f3a6c7..ace1f2db 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h
@@ -43,7 +43,7 @@
   // Marked virtual for tests.
   virtual void Start(const OnSinksDiscoveredCallback& sink_discovery_cb);
 
-  virtual void OnUserGesture();
+  virtual void DiscoverSinksNow();
 
   // Returns a raw pointer to |impl_|. This method is only valid to call after
   // |Start()| has been called. Always returns non-null.
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
index 609a413..2536011 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
@@ -106,7 +106,7 @@
       kLoggerComponent, "DialMediaSinkService has started.", "", "", "");
 }
 
-void DialMediaSinkServiceImpl::OnUserGesture() {
+void DialMediaSinkServiceImpl::DiscoverSinksNow() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(dial_registry_);
   dial_registry_->DiscoverNow();
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
index 9b78a0b5..5fb01878 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
@@ -58,7 +58,7 @@
   virtual void Start();
 
   // MediaSinkServiceBase implementation.
-  void OnUserGesture() override;
+  void DiscoverSinksNow() override;
 
   // Returns the SequencedTaskRunner that should be used to invoke methods on
   // this instance. Can be invoked on any thread.
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
index dc1caa8..d8fa2ad 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
@@ -111,7 +111,7 @@
   return dns_sd_registry_ != nullptr;
 }
 
-void CastMediaSinkService::OnUserGesture() {
+void CastMediaSinkService::DiscoverSinksNow() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (dns_sd_registry_)
     dns_sd_registry_->ResetAndDiscover();
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
index 4d1919c..122c8d4 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
@@ -48,11 +48,7 @@
   virtual void Start(const OnSinksDiscoveredCallback& sinks_discovered_cb,
                      MediaSinkServiceBase* dial_media_sink_service);
 
-  // Initiates discovery immediately in response to a user gesture
-  // (i.e., opening the Media Router dialog).
-  // TODO(imcheng): Rename to ManuallyInitiateDiscovery() or similar.
-  // Marked virtual for tests.
-  virtual void OnUserGesture();
+  virtual void DiscoverSinksNow();
 
   // Marked virtual for tests.
   virtual std::unique_ptr<CastMediaSinkServiceImpl, base::OnTaskRunnerDeleter>
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
index 3088c5c..dff3588 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -291,7 +291,7 @@
                                       known_ip_endpoints_.size());
 }
 
-void CastMediaSinkServiceImpl::OnUserGesture() {
+void CastMediaSinkServiceImpl::DiscoverSinksNow() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!dial_media_sink_service_)
     return;
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
index 92b456c..5533eca 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
@@ -229,7 +229,7 @@
 
   // MediaSinkServiceBase implementation.
   void RecordDeviceCounts() override;
-  void OnUserGesture() override;
+  void DiscoverSinksNow() override;
 
   // MediaSinkServiceBase::Observer implementation.
   void OnSinkAddedOrUpdated(const MediaSinkInternal& sink) override;
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
index 19cc507..f70d2ef 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
@@ -113,9 +113,9 @@
   MockDnsSdRegistry test_dns_sd_registry_;
 };
 
-TEST_F(CastMediaSinkServiceTest, OnUserGesture) {
+TEST_F(CastMediaSinkServiceTest, DiscoverSinksNow) {
   EXPECT_CALL(test_dns_sd_registry_, ResetAndDiscover());
-  media_sink_service_->OnUserGesture();
+  media_sink_service_->DiscoverSinksNow();
 }
 
 TEST_F(CastMediaSinkServiceTest, TestOnDnsSdEvent) {
diff --git a/chrome/browser/media/router/mojo/media_router_desktop.cc b/chrome/browser/media/router/mojo/media_router_desktop.cc
index 1d355bc..a6eacef 100644
--- a/chrome/browser/media/router/mojo/media_router_desktop.cc
+++ b/chrome/browser/media/router/mojo/media_router_desktop.cc
@@ -46,11 +46,8 @@
   if (!media_sink_service_)
     return;
 
-  // Allow MRPM to intelligently update sinks and observers by passing in a
-  // media source.
-  UpdateMediaSinks(MediaSource::ForUnchosenDesktop().id());
-
-  media_sink_service_->OnUserGesture();
+  DiscoverSinksNow();
+  media_sink_service_->DiscoverSinksNow();
   if (!media_sink_service_subscription_) {
     media_sink_service_subscription_ =
         media_sink_service_->AddSinksDiscoveredCallback(
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
index bd00d18..4f6a6791 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -715,9 +715,9 @@
     provider->StartListeningForRouteMessages(it.first);
 }
 
-void MediaRouterMojoImpl::UpdateMediaSinks(const MediaSource::Id& source_id) {
+void MediaRouterMojoImpl::DiscoverSinksNow() {
   for (const auto& provider : media_route_providers_)
-    provider.second->UpdateMediaSinks(source_id);
+    provider.second->DiscoverSinksNow();
 }
 
 void MediaRouterMojoImpl::OnMediaControllerCreated(
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.h b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
index bc356c0..abbaae90 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.h
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
@@ -105,7 +105,7 @@
   void Initialize() override;
 
   // Requests MRPs to update media sinks.
-  void UpdateMediaSinks(const MediaSource::Id& source_id);
+  void DiscoverSinksNow();
 
   // Called when the Mojo pointer for |provider_id| has a connection error.
   // Removes the pointer from |media_route_providers_|.
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
index c53c6a1..35b544da 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
@@ -314,7 +314,7 @@
   NOTIMPLEMENTED();
 }
 
-void CastMediaRouteProvider::UpdateMediaSinks(const std::string& media_source) {
+void CastMediaRouteProvider::DiscoverSinksNow() {
   app_discovery_service_->Refresh();
 }
 
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider.h b/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
index ceec25e..09f4609 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
+++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
@@ -82,7 +82,7 @@
   void StopListeningForRouteMessages(const std::string& route_id) override;
   void DetachRoute(const std::string& route_id) override;
   void EnableMdnsDiscovery() override;
-  void UpdateMediaSinks(const std::string& media_source) override;
+  void DiscoverSinksNow() override;
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
diff --git a/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc b/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc
index 26291db..9902674 100644
--- a/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc
+++ b/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc
@@ -48,14 +48,14 @@
   return sinks_discovered_callbacks_.Add(callback);
 }
 
-void DualMediaSinkService::OnUserGesture() {
+void DualMediaSinkService::DiscoverSinksNow() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // TODO(imcheng): Move this call into CastMediaRouteProvider.
   if (cast_media_sink_service_)
-    cast_media_sink_service_->OnUserGesture();
+    cast_media_sink_service_->DiscoverSinksNow();
 
   if (dial_media_sink_service_)
-    dial_media_sink_service_->OnUserGesture();
+    dial_media_sink_service_->DiscoverSinksNow();
 }
 
 #if BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/media/router/providers/cast/dual_media_sink_service.h b/chrome/browser/media/router/providers/cast/dual_media_sink_service.h
index 45c1711..c517e0a 100644
--- a/chrome/browser/media/router/providers/cast/dual_media_sink_service.h
+++ b/chrome/browser/media/router/providers/cast/dual_media_sink_service.h
@@ -75,7 +75,7 @@
 
   void RemoveLogger(LoggerImpl* logger_impl);
 
-  virtual void OnUserGesture();
+  virtual void DiscoverSinksNow();
 
 #if BUILDFLAG(IS_WIN)
   // Starts mDNS discovery on |cast_media_sink_service_| if it is not already
diff --git a/chrome/browser/media/router/providers/cast/dual_media_sink_service_unittest.cc b/chrome/browser/media/router/providers/cast/dual_media_sink_service_unittest.cc
index 3990e82..0720e8dd9 100644
--- a/chrome/browser/media/router/providers/cast/dual_media_sink_service_unittest.cc
+++ b/chrome/browser/media/router/providers/cast/dual_media_sink_service_unittest.cc
@@ -72,9 +72,9 @@
   content::BrowserTaskEnvironment task_environment;
 };
 
-TEST_F(DualMediaSinkServiceTest, OnUserGesture) {
-  EXPECT_CALL(*cast_media_sink_service_, OnUserGesture());
-  dual_media_sink_service_->OnUserGesture();
+TEST_F(DualMediaSinkServiceTest, DiscoverSinksNow) {
+  EXPECT_CALL(*cast_media_sink_service_, DiscoverSinksNow());
+  dual_media_sink_service_->DiscoverSinksNow();
 }
 
 TEST_F(DualMediaSinkServiceTest, AddSinksDiscoveredCallback) {
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
index 8abac700..7bb2fea9 100644
--- a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
@@ -595,8 +595,8 @@
   NOTIMPLEMENTED();
 }
 
-void DialMediaRouteProvider::UpdateMediaSinks(const std::string& media_source) {
-  media_sink_service_->OnUserGesture();
+void DialMediaRouteProvider::DiscoverSinksNow() {
+  media_sink_service_->DiscoverSinksNow();
 }
 
 void DialMediaRouteProvider::CreateMediaRouteController(
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider.h b/chrome/browser/media/router/providers/dial/dial_media_route_provider.h
index a1c0bf6..79e4d3e 100644
--- a/chrome/browser/media/router/providers/dial/dial_media_route_provider.h
+++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider.h
@@ -97,7 +97,7 @@
   void StopListeningForRouteMessages(const std::string& route_id) override;
   void DetachRoute(const std::string& route_id) override;
   void EnableMdnsDiscovery() override;
-  void UpdateMediaSinks(const std::string& media_source) override;
+  void DiscoverSinksNow() override;
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
diff --git a/chrome/browser/media/router/providers/test/test_media_route_provider.cc b/chrome/browser/media/router/providers/test/test_media_route_provider.cc
index 3473e1eb..20701a7 100644
--- a/chrome/browser/media/router/providers/test/test_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/test/test_media_route_provider.cc
@@ -217,8 +217,7 @@
 
 void TestMediaRouteProvider::EnableMdnsDiscovery() {}
 
-void TestMediaRouteProvider::UpdateMediaSinks(const std::string& media_source) {
-}
+void TestMediaRouteProvider::DiscoverSinksNow() {}
 
 void TestMediaRouteProvider::CreateMediaRouteController(
     const std::string& route_id,
diff --git a/chrome/browser/media/router/providers/test/test_media_route_provider.h b/chrome/browser/media/router/providers/test/test_media_route_provider.h
index 4e421e2..2df3a3a 100644
--- a/chrome/browser/media/router/providers/test/test_media_route_provider.h
+++ b/chrome/browser/media/router/providers/test/test_media_route_provider.h
@@ -60,7 +60,7 @@
   void StopListeningForRouteMessages(const std::string& route_id) override;
   void DetachRoute(const std::string& route_id) override;
   void EnableMdnsDiscovery() override;
-  void UpdateMediaSinks(const std::string& media_source) override;
+  void DiscoverSinksNow() override;
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
diff --git a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
index b38aeeff..4db2829 100644
--- a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.cc
@@ -181,7 +181,7 @@
   if (!display_observer_)
     display_observer_.emplace(this);
   sink_queries_.insert(media_source);
-  UpdateMediaSinks(media_source);
+  DiscoverSinksNow();
 }
 
 void WiredDisplayMediaRouteProvider::StopObservingMediaSinks(
@@ -214,10 +214,8 @@
 
 void WiredDisplayMediaRouteProvider::EnableMdnsDiscovery() {}
 
-void WiredDisplayMediaRouteProvider::UpdateMediaSinks(
-    const std::string& media_source) {
-  if (IsValidStandardPresentationSource(media_source))
-    media_router_->OnSinksReceived(kProviderId, media_source, GetSinks(), {});
+void WiredDisplayMediaRouteProvider::DiscoverSinksNow() {
+  NotifySinkObservers();
 }
 
 void WiredDisplayMediaRouteProvider::CreateMediaRouteController(
diff --git a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h
index cdc654c8..32ab7da 100644
--- a/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h
+++ b/chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h
@@ -85,7 +85,7 @@
   void StopListeningForRouteMessages(const std::string& route_id) override;
   void DetachRoute(const std::string& route_id) override;
   void EnableMdnsDiscovery() override;
-  void UpdateMediaSinks(const std::string& media_source) override;
+  void DiscoverSinksNow() override;
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
diff --git a/chrome/browser/media/router/test/media_router_mojo_test.h b/chrome/browser/media/router/test/media_router_mojo_test.h
index 0dfeb79..90b6a17a 100644
--- a/chrome/browser/media/router/test/media_router_mojo_test.h
+++ b/chrome/browser/media/router/test/media_router_mojo_test.h
@@ -106,7 +106,7 @@
                void(const std::string& route_id));
   MOCK_METHOD0(StartObservingMediaRoutes, void());
   MOCK_METHOD0(EnableMdnsDiscovery, void());
-  MOCK_METHOD1(UpdateMediaSinks, void(const std::string& source));
+  MOCK_METHOD0(DiscoverSinksNow, void());
   void CreateMediaRouteController(
       const std::string& route_id,
       mojo::PendingReceiver<mojom::MediaController> media_controller,
diff --git a/chrome/browser/media/router/test/noop_dual_media_sink_service.h b/chrome/browser/media/router/test/noop_dual_media_sink_service.h
index 2a3e03d..330d33fe 100644
--- a/chrome/browser/media/router/test/noop_dual_media_sink_service.h
+++ b/chrome/browser/media/router/test/noop_dual_media_sink_service.h
@@ -20,7 +20,7 @@
   ~NoopDualMediaSinkService() override;
 
   // DualMediaSinkService
-  void OnUserGesture() override {}
+  void DiscoverSinksNow() override {}
 #if BUILDFLAG(IS_WIN)
   void StartMdnsDiscovery() override {}
 #endif
diff --git a/chrome/browser/media/router/test/provider_test_helpers.h b/chrome/browser/media/router/test/provider_test_helpers.h
index 6b849ce..8cfe3c2 100644
--- a/chrome/browser/media/router/test/provider_test_helpers.h
+++ b/chrome/browser/media/router/test/provider_test_helpers.h
@@ -39,7 +39,7 @@
   ~MockDialMediaSinkService() override;
 
   MOCK_METHOD1(Start, void(const OnSinksDiscoveredCallback&));
-  MOCK_METHOD0(OnUserGesture, void());
+  MOCK_METHOD0(DiscoverSinksNow, void());
 };
 
 class MockCastMediaSinkService : public CastMediaSinkService {
@@ -49,7 +49,7 @@
 
   MOCK_METHOD2(Start,
                void(const OnSinksDiscoveredCallback&, MediaSinkServiceBase*));
-  MOCK_METHOD0(OnUserGesture, void());
+  MOCK_METHOD0(DiscoverSinksNow, void());
   MOCK_METHOD0(StartMdnsDiscovery, void());
 };
 
diff --git a/chrome/browser/net/android_network_service_browsertest.cc b/chrome/browser/net/android_network_service_browsertest.cc
index 887fc02..4620692 100644
--- a/chrome/browser/net/android_network_service_browsertest.cc
+++ b/chrome/browser/net/android_network_service_browsertest.cc
@@ -21,7 +21,7 @@
 
 class AndroidChromeNetworkContextCleanupBrowserTest
     : public AndroidBrowserTest,
-      public testing::WithParamInterface<std::tuple<bool, bool, bool>> {
+      public testing::WithParamInterface<std::tuple<bool, bool>> {
  public:
   AndroidChromeNetworkContextCleanupBrowserTest() = default;
   ~AndroidChromeNetworkContextCleanupBrowserTest() override = default;
@@ -43,10 +43,6 @@
   // initializing the network service.
   bool create_data_directory_;
 
-  // Whether to create the `data_direcory` for the SafeBrowsing network context
-  // or for the regular one. The tests support creating only one.
-  bool data_directory_is_for_safebrowsing_;
-
   // Whether to write protect the `data_directory`. Used to check errors on
   // deletion.
   bool write_protect_data_directory_;
@@ -83,17 +79,9 @@
     // Initialize the parameters.
     create_data_directory_ = std::get<0>(GetParam());
     write_protect_data_directory_ = std::get<1>(GetParam());
-    data_directory_is_for_safebrowsing_ = std::get<2>(GetParam());
-
-    if (data_directory_is_for_safebrowsing_) {
-      data_directory_ = user_data_dir()
-                            .AppendASCII(chrome::kInitialProfile)
-                            .AppendASCII("Safe Browsing Network");
-    } else {
-      data_directory_ = user_data_dir()
-                            .AppendASCII(chrome::kInitialProfile)
-                            .AppendASCII(chrome::kNetworkDataDirname);
-    }
+    data_directory_ = user_data_dir()
+                          .AppendASCII(chrome::kInitialProfile)
+                          .AppendASCII(chrome::kNetworkDataDirname);
 
     // Create the profile directory.
     base::FilePath profile_dir =
@@ -168,8 +156,7 @@
     AndroidChromeNetworkContextCleanupBrowserTest,
     testing::Combine(
         /* create_data_directory_= */ testing::Values(true),
-        /* write_protect_data_directory_= */ testing::Values(false),
-        /* data_directory_is_for_safebrowsing_= */ testing::Bool()));
+        /* write_protect_data_directory_= */ testing::Values(false)));
 
 // Check that when the directories are already cleaned up, the histogram with
 // the corresponding bucket is recorded.
@@ -178,8 +165,7 @@
     AndroidChromeNetworkContextCleanupBrowserTest,
     testing::Combine(
         /* create_data_directory_= */ testing::Values(false),
-        /* write_protect_data_directory_= */ testing::Values(false),
-        /* data_directory_is_for_safebrowsing_= */ testing::Values(false)));
+        /* write_protect_data_directory_= */ testing::Values(false)));
 
 // Check that failure to delete a network context data directory is recorded in
 // UMA.
@@ -188,8 +174,7 @@
     AndroidChromeNetworkContextCleanupBrowserTest,
     testing::Combine(
         /* create_data_directory_= */ testing::Values(true),
-        /* write_protect_data_directory_= */ testing::Values(true),
-        /* data_directory_is_for_safebrowsing_= */ testing::Values(false)));
+        /* write_protect_data_directory_= */ testing::Values(true)));
 
 IN_PROC_BROWSER_TEST_P(AndroidChromeNetworkContextCleanupBrowserTest,
                        NavigateAndCheck) {
diff --git a/chrome/browser/profiles/profile_keyed_service_browsertest.cc b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
index c36ba0d5..55d001d 100644
--- a/chrome/browser/profiles/profile_keyed_service_browsertest.cc
+++ b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
@@ -435,7 +435,6 @@
     "RulesRegistryService",
     "RuntimeAPI",
     "SafeBrowsingMetricsCollector",
-    "SafeBrowsingNetworkContextService",
     "SafeBrowsingPrivateEventRouter",
     "SafeBrowsingTailoredSecurityService",
     "SecurityEventRecorder",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_captions_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_captions_background.js
index 257e4daf..c3ba7cf8 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_captions_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_captions_background.js
@@ -135,7 +135,7 @@
   static setActive(newValue) {
     const oldValue = BrailleCaptionsBackground.isEnabled();
     ChromeVoxPrefs.instance.setPref(
-        BrailleCaptionsBackground.PREF_KEY, String(newValue));
+        BrailleCaptionsBackground.PREF_KEY, newValue);
     if (oldValue !== newValue) {
       BrailleCaptionsBackground.instance.callStateCallback_();
       const msg = newValue ? Msgs.getMsg('braille_captions_enabled') :
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js
index 294b63b..084414d 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js
@@ -19,9 +19,8 @@
      * True if the console TTS is enabled by the user.
      * @private {boolean}
      */
-    this.enabled_ =
-        ChromeVoxPrefs.instance.getPrefs()['enableSpeechLogging'] ===
-        String(true);
+    this.enabled_ = /** @type {boolean} */ (
+        ChromeVoxPrefs.instance.getPrefs()['enableSpeechLogging']);
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js
index 29ee319..dc62bc8 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js
@@ -64,7 +64,7 @@
 
   /**
    * Get the prefs (not including keys).
-   * @return {Object<string, string>} A map of all prefs except the key map from
+   * @return {Object<string, *>} A map of all prefs except the key map from
    *     LocalStorage.
    */
   getPrefs() {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
index d6fc9d2a..c67deb4 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
@@ -386,11 +386,11 @@
   /**
    * Set the html element for a preference to match the given value.
    * @param {Element} element The HTML control.
-   * @param {string} value The new value.
+   * @param {*} value The new value.
    */
   static setValue(element, value) {
     if (element.tagName === 'INPUT' && element.type === 'checkbox') {
-      element.checked = (value === 'true');
+      element.checked = value;
     } else if (element.tagName === 'INPUT' && element.type === 'radio') {
       element.checked = (String(element.value) === value);
     } else {
diff --git a/chrome/browser/resources/chromeos/drive_internals.html b/chrome/browser/resources/chromeos/drive_internals.html
index e1affc10..0d7d086ce 100644
--- a/chrome/browser/resources/chromeos/drive_internals.html
+++ b/chrome/browser/resources/chromeos/drive_internals.html
@@ -119,19 +119,31 @@
           </td>
         <tr>
           <th>Stage</th>
-          <td id="bulk-pinning-setup-stage">?</td>
+          <td id="bulk-pinning-stage">?</td>
         </tr>
         <tr>
           <th>Free Space</th>
-          <td id="bulk-pinning-available-disk-space">?</td>
+          <td id="bulk-pinning-free-space">?</td>
         </tr>
         <tr>
           <th>Required Space</th>
-          <td id="bulk-pinning-required-disk-space">?</td>
+          <td id="bulk-pinning-bytes-to-pin">?</td>
         </tr>
         <tr>
           <th>Pinned Space</th>
-          <td id="bulk-pinning-pinned-disk-space">?</td>
+          <td id="bulk-pinning-pinned-bytes">?</td>
+        </tr>
+        <tr>
+          <th>Files To Pin</th>
+          <td id="bulk-pinning-files-to-pin">?</td>
+        </tr>
+        <tr>
+          <th>Pinned Files</th>
+          <td id="bulk-pinning-pinned-files">?</td>
+        </tr>
+        <tr>
+          <th>Failed Files</th>
+          <td id="bulk-pinning-failed-files">?</td>
         </tr>
       </table>
     </section>
diff --git a/chrome/browser/resources/chromeos/drive_internals.js b/chrome/browser/resources/chromeos/drive_internals.js
index 05d1cb8..f4284d5 100644
--- a/chrome/browser/resources/chromeos/drive_internals.js
+++ b/chrome/browser/resources/chromeos/drive_internals.js
@@ -105,11 +105,13 @@
 }
 
 function onBulkPinningProgress(progress) {
-  $('bulk-pinning-setup-stage').innerText = progress.stage;
-  $('bulk-pinning-available-disk-space').innerText =
-      progress.availableDiskSpace;
-  $('bulk-pinning-required-disk-space').innerText = progress.requiredDiskSpace;
-  $('bulk-pinning-pinned-disk-space').innerText = progress.pinnedDiskSpace;
+  $('bulk-pinning-stage').innerText = progress.stage;
+  $('bulk-pinning-free-space').innerText = progress.free_space;
+  $('bulk-pinning-bytes-to-pin').innerText = progress.bytes_to_pin;
+  $('bulk-pinning-pinned-bytes').innerText = progress.pinned_bytes;
+  $('bulk-pinning-files-to-pin').innerText = progress.files_to_pin;
+  $('bulk-pinning-pinned-files').innerText = progress.pinned_files;
+  $('bulk-pinning-failed-files').innerText = progress.failed_files;
 }
 
 function updateStartupArguments(args) {
diff --git a/chrome/browser/resources/chromeos/emoji_picker/constants.ts b/chrome/browser/resources/chromeos/emoji_picker/constants.ts
index 413e41c..8eb3ae6 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/constants.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/constants.ts
@@ -50,3 +50,6 @@
 export const TAB_BUTTON_MARGIN_PX = `${TAB_BUTTON_MARGIN}px`;
 export const TEXT_GROUP_BUTTON_PADDING_PX = `${TEXT_GROUP_BUTTON_PADDING}px`;
 export const TRENDING = '#TRENDING';
+// 24 hours is equivalent to 86400000 milliseconds.
+export const TWENTY_FOUR_HOURS = 86400000;
+export const GIF_VALIDATION_DATE = 'gifValidationDate';
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
index 3de1e06..bbf6afa 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
@@ -94,6 +94,7 @@
   private highlightBarMoving: boolean;
   private groupTabsMoving: boolean;
   private gifDataInitialised: boolean;
+  private previousGifValidation: Date;
 
   constructor() {
     super();
@@ -112,6 +113,7 @@
     this.autoScrollingToGroup = false;
     this.highlightBarMoving = false;
     this.groupTabsMoving = false;
+    this.previousGifValidation = this.loadPreviousGifValidationTime();
 
     this.addEventListener(
         events.GROUP_BUTTON_CLICK,
@@ -302,6 +304,7 @@
     );
 
     if (this.gifSupport) {
+      this.validateRecentlyUsedGifs();
       const categoriesFetchPromise =
           prevFetchPromise.then(() => this.apiProxy.getCategories());
 
@@ -1194,6 +1197,40 @@
                         }));
   }
 
+  /**
+   * Checks if recently used GIFs are still valid if we open the emoji picker
+   * and it has been 24 hours since the last validation.
+   */
+  async validateRecentlyUsedGifs() {
+    // This check ensures that we don't try and validate recently used GIFs
+    // if the validating process is already currently happening.
+    const currentTime = new Date();
+
+    if ((currentTime.getTime() - this.previousGifValidation.getTime()) >
+        constants.TWENTY_FOUR_HOURS) {
+      const updated = await this.categoriesHistory[CategoryEnum.GIF]?.validate(
+          this.apiProxy);
+
+      this.previousGifValidation = currentTime;
+      window.localStorage.setItem(
+          constants.GIF_VALIDATION_DATE, currentTime.toJSON());
+
+      if (updated) {
+        this.categoryHistoryUpdated(CategoryEnum.GIF);
+      }
+    }
+  }
+
+  private loadPreviousGifValidationTime(): Date {
+    const stored = window.localStorage.getItem(constants.GIF_VALIDATION_DATE);
+    if (!stored) {
+      // First time opening the Emoji Picker so there should be no recently used
+      // GIFs to render.
+      return new Date();
+    }
+    return new Date(stored);
+  }
+
   private getTabs() {
     return this.$['tabs'] as HTMLElement | null;
   }
diff --git a/chrome/browser/resources/chromeos/emoji_picker/store.ts b/chrome/browser/resources/chromeos/emoji_picker/store.ts
index 4786ad51..a8e9b5e 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/store.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/store.ts
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {CategoryEnum, EmojiVariants} from './types.js';
+import {EmojiPickerApiProxy} from 'emoji_picker_api_proxy.js';
 
-const MAX_TEXT_RECENTS = 18;
-const MAX_GIF_RECENTS = 10;
+import {CategoryEnum, EmojiVariants, VisualContent} from './types.js';
+
+const MAX_RECENTS = 10;
 
 /**
  * @param {string} keyName Keyname of the object stored in storage
@@ -93,9 +94,6 @@
           x => (x.base.string && x.base.string === newItem.base.string));
     }
 
-    const MAX_RECENTS =
-        category === CategoryEnum.GIF ? MAX_GIF_RECENTS : MAX_TEXT_RECENTS;
-
     if (oldIndex !== -1) {
       this.data.history.splice(oldIndex, 1);
     }
@@ -108,4 +106,35 @@
     }
     save(this.storeName, this.data);
   }
+
+  /**
+   * Removes invalid GIFs from history.
+   */
+  async validate(apiProxy: EmojiPickerApiProxy): Promise<boolean> {
+    if (this.data.history.length === 0) {
+      // No GIFs to validate.
+      return false;
+    }
+
+    // This function is only called on history items with visual content (i.e.
+    // GIFs) so we can be confident an id will always exist.
+    const ids = this.data.history.map(x => x.base.visualContent!.id);
+
+    const {selectedGifs} = await apiProxy.getGifsByIds(ids);
+    const map = new Map<string, VisualContent>();
+    selectedGifs.forEach(gif => {
+      map.set(gif.id, gif);
+    });
+
+    const validGifHistory =
+        this.data.history.filter(item => map.has(item.base.visualContent!.id));
+    const updated = (validGifHistory.length !== this.data.history.length);
+
+    if (updated) {
+      this.data.history = validGifHistory;
+      save(this.storeName, this.data);
+    }
+
+    return updated;
+  }
 }
diff --git a/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json b/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
index 5ff2413..74af9b2 100644
--- a/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
+++ b/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
@@ -611,19 +611,6 @@
       "options_page": "hmm_options.html?code=xkb:gb:extd:eng"
     },
     {
-      "name": "__MSG_keyboard_english_pakistan__",
-      "id": "xkb:pk::eng",
-      "indicator": "PK",
-      "language": [
-        "en",
-        "en-PK"
-      ],
-      "layouts": [
-        "us"
-      ],
-      "options_page": "hmm_options.html?code=xkb:pk::eng"
-    },
-    {
       "name": "__MSG_keyboard_english_south_africa__",
       "id": "xkb:za:gb:eng",
       "indicator": "ZA",
diff --git a/chrome/browser/resources/downloads/constants.ts b/chrome/browser/resources/downloads/constants.ts
index 839f6c58..e0938ab3 100644
--- a/chrome/browser/resources/downloads/constants.ts
+++ b/chrome/browser/resources/downloads/constants.ts
@@ -35,4 +35,5 @@
   INTERRUPTED = 'INTERRUPTED',
   INSECURE = 'INSECURE',
   ASYNC_SCANNING = 'ASYNC_SCANNING',
+  PROMPT_FOR_SCANNING = 'PROMPT_FOR_SCANNING',
 }
diff --git a/chrome/browser/resources/downloads/item.html b/chrome/browser/resources/downloads/item.html
index 17832840..b0a734b 100644
--- a/chrome/browser/resources/downloads/item.html
+++ b/chrome/browser/resources/downloads/item.html
@@ -277,7 +277,8 @@
 
   #pauseOrResume,
   #dangerous .action-button,
-  #openNow {
+  #openNow,
+  #deepScan {
     margin-inline-end: 8px;
   }
 </style>
@@ -371,6 +372,20 @@
           </cr-button>
         </span>
       </template>
+      <template is="dom-if" if="[[showDeepScan_]]" restamp>
+        <span role="gridcell">
+          <cr-button on-click="onDeepScanTap_" id="deepScan"
+                     class="action-button" focus-row-control focus-type="open">
+            $i18n{controlDeepScan}
+          </cr-button>
+        </span>
+        <span role="gridcell">
+          <cr-button on-click="onBypassDeepScanTap_" id="bypassDeepScan"
+                     focus-row-control focus-type="open">
+            $i18n{controlBypassDeepScan}
+          </cr-button>
+        </span>
+      </template>
       <template is="dom-if" if="[[showCancel_]]">
         <span role="gridcell">
           <cr-button on-click="onCancelTap_" focus-row-control
diff --git a/chrome/browser/resources/downloads/item.ts b/chrome/browser/resources/downloads/item.ts
index dbbd06199..166849f 100644
--- a/chrome/browser/resources/downloads/item.ts
+++ b/chrome/browser/resources/downloads/item.ts
@@ -137,6 +137,12 @@
         value: false,
       },
 
+      showDeepScan_: {
+        computed: 'computeShowDeepScan_(data.state)',
+        type: Boolean,
+        value: false,
+      },
+
       useFileIcon_: Boolean,
     };
   }
@@ -302,7 +308,8 @@
 
       case States.ASYNC_SCANNING:
         return loadTimeData.getString('asyncScanningDownloadDesc');
-
+      case States.PROMPT_FOR_SCANNING:
+        return loadTimeData.getString('promptForScanningDesc');
       case States.IN_PROGRESS:
       case States.PAUSED:  // Fallthrough.
         return data.progressStatusText;
@@ -342,6 +349,10 @@
       if (this.data.state === States.ASYNC_SCANNING) {
         return 'cr:info';
       }
+
+      if (this.data.state === States.PROMPT_FOR_SCANNING) {
+        return 'cr:warning';
+      }
     }
     if (this.isDangerous_) {
       return 'cr:error';
@@ -373,6 +384,10 @@
       if (this.data.state === States.ASYNC_SCANNING) {
         return 'grey';
       }
+
+      if (this.data.state === States.PROMPT_FOR_SCANNING) {
+        return 'yellow';
+      }
     }
     if (this.isDangerous_) {
       return 'red';
@@ -455,7 +470,8 @@
 
   private computeShowProgress_(): boolean {
     return this.showCancel_ && this.data.percent >= -1 &&
-        this.data.state !== States.ASYNC_SCANNING;
+        this.data.state !== States.ASYNC_SCANNING &&
+        this.data.state !== States.PROMPT_FOR_SCANNING;
   }
 
   private computeShowOpenNow_(): boolean {
@@ -463,6 +479,10 @@
     return this.data.state === States.ASYNC_SCANNING && allowOpenNow;
   }
 
+  private computeShowDeepScan_(): boolean {
+    return this.data.state === States.PROMPT_FOR_SCANNING;
+  }
+
   private computeTag_(): string {
     switch (this.data.state) {
       case States.CANCELLED:
@@ -512,6 +532,8 @@
       this.useFileIcon_ = false;
     } else if (this.data.state === States.ASYNC_SCANNING) {
       this.useFileIcon_ = false;
+    } else if (this.data.state === States.PROMPT_FOR_SCANNING) {
+      this.useFileIcon_ = false;
     } else {
       this.$.url.href = this.data.url;
       const path = this.data.filePath;
@@ -539,6 +561,14 @@
     this.mojoHandler_!.openDuringScanningRequiringGesture(this.data.id);
   }
 
+  private onDeepScanTap_() {
+    this.mojoHandler_!.deepScan(this.data.id);
+  }
+
+  private onBypassDeepScanTap_() {
+    this.mojoHandler_!.bypassDeepScanRequiringGesture(this.data.id);
+  }
+
   private onReviewDangerousTap_() {
     this.mojoHandler_!.reviewDangerousRequiringGesture(this.data.id);
   }
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/languages.js b/chrome/browser/resources/settings/chromeos/os_languages_page/languages.js
index 1b910fe..eaf12942 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/languages.js
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/languages.js
@@ -284,10 +284,8 @@
             lists.componentExtensionImes.concat(
                 lists.thirdPartyExtensionImes)));
 
-
-    promises.push(new Promise(resolve => {
-                    this.inputMethodPrivate_.getCurrentInputMethod(resolve);
-                  }).then(result => args.currentInputMethodId = result));
+    promises.push(this.inputMethodPrivate_.getCurrentInputMethod().then(
+        result => args.currentInputMethodId = result));
 
     // Get the list of language-codes to always translate.
     promises.push(
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index 19f9e60..b7a2065 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -166,12 +166,6 @@
   return PasswordReuseLookup::VERDICT_UNSPECIFIED;
 }
 
-// Records changes in the phished status of saved credential.
-void LogCredentialPhishedStatusChanged(CredentialPhishedStatus status) {
-  base::UmaHistogramEnumeration("SafeBrowsing.CredentialPhishedStatusChange",
-                                status);
-}
-
 // Given a |web_contents|, returns the navigation id of its last committed
 // navigation.
 int64_t GetLastCommittedNavigationID(content::WebContents* web_contents) {
@@ -1717,8 +1711,6 @@
     if (!password_store) {
       continue;
     }
-    LogCredentialPhishedStatusChanged(
-        CredentialPhishedStatus::kMarkedAsPhished);
     add_phished_credentials_.Run(password_store, credential);
   }
 }
@@ -1736,8 +1728,6 @@
     if (!password_store) {
       continue;
     }
-    LogCredentialPhishedStatusChanged(
-        CredentialPhishedStatus::kSiteMarkedAsLegitimate);
     remove_phished_credentials_.Run(password_store, credential);
   }
 }
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index 0d3ee367..fc49634 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -96,20 +96,6 @@
 
 namespace {
 
-void OnGotCookies(
-    std::unique_ptr<mojo::Remote<network::mojom::CookieManager>> remote,
-    const std::vector<net::CanonicalCookie>& cookies) {
-  base::UmaHistogramBoolean("SafeBrowsing.HasCookieAtStartup",
-                            !cookies.empty());
-  if (!cookies.empty()) {
-    base::TimeDelta age = base::Time::Now() - cookies[0].CreationDate();
-    // Cookies can be up to 6 months old. Using millisecond precision over such
-    // a long time period overflows numeric limits. Instead, use a counts
-    // histogram and lower granularity.
-    base::UmaHistogramCounts10000("SafeBrowsing.CookieAgeHours", age.InHours());
-  }
-}
-
 #if BUILDFLAG(FULL_SAFE_BROWSING)
 void PopulateDownloadWarningActions(download::DownloadItem* download,
                                     ClientSafeBrowsingReportRequest* report) {
@@ -412,8 +398,6 @@
 
   SafeBrowsingMetricsCollectorFactory::GetForProfile(profile)->StartLogging();
 
-  RecordCookieMetrics(profile);
-
   CreateServicesForProfile(profile);
 }
 
@@ -526,22 +510,6 @@
   return params;
 }
 
-void SafeBrowsingService::RecordCookieMetrics(Profile* profile) {
-  network::mojom::NetworkContext* network_context = GetNetworkContext(profile);
-  if (!network_context)
-    return;
-  auto cookie_manager_remote =
-      std::make_unique<mojo::Remote<network::mojom::CookieManager>>();
-  network_context->GetCookieManager(
-      cookie_manager_remote->BindNewPipeAndPassReceiver());
-
-  mojo::Remote<network::mojom::CookieManager>* cookie_manager_raw =
-      cookie_manager_remote.get();
-  (*cookie_manager_raw)
-      ->GetAllCookies(
-          base::BindOnce(&OnGotCookies, std::move(cookie_manager_remote)));
-}
-
 // The default SafeBrowsingServiceFactory.  Global, made a singleton so we
 // don't leak it.
 class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h
index d32a33a..cd5bdc89 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -274,9 +274,6 @@
   // use.
   network::mojom::NetworkContextParamsPtr CreateNetworkContextParams();
 
-  // Logs metrics related to cookies.
-  void RecordCookieMetrics(Profile* profile);
-
   std::unique_ptr<ProxyConfigMonitor> proxy_config_monitor_;
 
   // Whether SafeBrowsing Extended Reporting is enabled by the current set of
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index eea8489..defc375 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2181,10 +2181,18 @@
       "../ash/app_list/search/search_provider.h",
       "../ash/app_list/search/search_session_metrics_manager.cc",
       "../ash/app_list/search/search_session_metrics_manager.h",
+      "../ash/app_list/search/system_info/battery_health.h",
+      "../ash/app_list/search/system_info/cpu_data.h",
+      "../ash/app_list/search/system_info/cpu_usage_data.cc",
+      "../ash/app_list/search/system_info/cpu_usage_data.h",
       "../ash/app_list/search/system_info/system_info_answer_result.cc",
       "../ash/app_list/search/system_info/system_info_answer_result.h",
+      "../ash/app_list/search/system_info/system_info_card_provider.cc",
+      "../ash/app_list/search/system_info/system_info_card_provider.h",
       "../ash/app_list/search/system_info/system_info_item.cc",
       "../ash/app_list/search/system_info/system_info_item.h",
+      "../ash/app_list/search/system_info/system_info_util.cc",
+      "../ash/app_list/search/system_info/system_info_util.h",
       "../ash/app_list/search/types.cc",
       "../ash/app_list/search/types.h",
       "../ash/app_list/search/util/ftrl_optimizer.cc",
diff --git a/chrome/browser/ui/views/download/bubble/download_dialog_view.cc b/chrome/browser/ui/views/download/bubble/download_dialog_view.cc
index 5c822842..89c2edb 100644
--- a/chrome/browser/ui/views/download/bubble/download_dialog_view.cc
+++ b/chrome/browser/ui/views/download/bubble/download_dialog_view.cc
@@ -17,6 +17,8 @@
 #include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/models/image_model.h"
+#include "ui/color/color_id.h"
 #include "ui/color/color_provider.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/resources/grit/ui_resources.h"
@@ -75,11 +77,20 @@
 }
 
 void DownloadDialogView::AddFooter() {
-  auto* footer = AddChildView(std::make_unique<HoverButton>(
-      base::BindRepeating(&DownloadDialogView::ShowAllDownloads,
-                          base::Unretained(this)),
-      l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_FOOTER_LINK)));
-  footer->SetBorder(views::CreateEmptyBorder(GetLayoutInsets(DOWNLOAD_ROW)));
+  // Do not display an icon in the primary position.
+  auto empty_primary_icon = std::make_unique<views::View>();
+  auto launch_icon_view = std::make_unique<views::ImageView>();
+  launch_icon_view->SetImage(ui::ImageModel::FromVectorIcon(
+      vector_icons::kLaunchIcon, ui::kColorIconSecondary));
+
+  AddChildView(std::make_unique<HoverButton>(
+                   base::BindRepeating(&DownloadDialogView::ShowAllDownloads,
+                                       base::Unretained(this)),
+                   std::move(empty_primary_icon),
+                   l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_FOOTER_LINK),
+                   /*subtitle=*/std::u16string(), std::move(launch_icon_view),
+                   /*resize_row_for_secondary_view=*/false))
+      ->SetBorder(views::CreateEmptyBorder(GetLayoutInsets(DOWNLOAD_ROW)));
 }
 
 DownloadDialogView::DownloadDialogView(
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
index f9a1f13..0d7ccebc 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
@@ -254,6 +254,9 @@
   };
   if (match.type == AutocompleteMatchType::CALCULATOR) {
     apply_vector_icon(omnibox::kAnswerCalculatorIcon);
+    if (OmniboxFieldTrial::IsUniformRowHeightEnabled()) {
+      separator_view_->SetSize(gfx::Size());
+    }
   } else if (!has_image_) {
     answer_image_view_->SetImage(gfx::ImageSkia());
     answer_image_view_->SetSize(gfx::Size());
diff --git a/chrome/browser/ui/webui/ash/drive_internals_ui.cc b/chrome/browser/ui/webui/ash/drive_internals_ui.cc
index 31c76a7..d9141118 100644
--- a/chrome/browser/ui/webui/ash/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/ash/drive_internals_ui.cc
@@ -251,9 +251,10 @@
                                    public DriveFsPinManager::Observer {
  public:
   ~DriveInternalsWebUIHandler() override {
-    VLOG_IF(1, pin_manager_)
-        << "DriveInternalsWebUIHandler dropped before DriveFsPinManager";
-    OnDrop();
+    if (pin_manager_) {
+      VLOG(1) << "DriveInternalsWebUIHandler dropped before DriveFsPinManager";
+      pin_manager_->RemoveObserver(this);
+    }
   }
 
   DriveInternalsWebUIHandler() = default;
@@ -384,17 +385,12 @@
     UpdateDriveRelatedPreferencesSection();
     UpdateGCacheContentsSection();
     UpdatePathConfigurationsSection();
-
     UpdateConnectionStatusSection();
     UpdateAboutResourceSection();
-
     UpdateDeltaUpdateStatusSection();
     UpdateCacheContentsSection();
-
     UpdateInFlightOperationsSection();
-
     UpdateDriveDebugSection();
-
     UpdateMirrorSyncSection();
     UpdateBulkPinningSection();
 
@@ -606,10 +602,13 @@
 
   void UpdateBulkPinningSection() {
     DriveIntegrationService* const service = GetIntegrationService();
-    DCHECK(service);
+    if (!service) {
+      return;
+    }
 
-    OnDrop();
-    DCHECK(!pin_manager_);
+    if (pin_manager_) {
+      pin_manager_->RemoveObserver(this);
+    }
 
     pin_manager_ = service->GetPinManager();
     if (!pin_manager_) {
@@ -629,7 +628,7 @@
 
   void OnDrop() override {
     if (pin_manager_) {
-      pin_manager_->RemoveObserver(this);
+      VLOG(1) << "DriveFsPinManager dropped before DriveInternalsWebUIHandler";
       pin_manager_ = nullptr;
     }
   }
@@ -639,12 +638,12 @@
 
     base::Value::Dict d;
     d.Set("stage", ToString(progress.stage));
-    d.Set("availableDiskSpace",
-          ToString(HumanReadableSize(progress.free_space)));
-    d.Set("requiredDiskSpace",
-          ToString(HumanReadableSize(progress.total_bytes)));
-    d.Set("pinnedDiskSpace",
-          ToString(HumanReadableSize(progress.transferred_bytes)));
+    d.Set("free_space", ToString(HumanReadableSize(progress.free_space)));
+    d.Set("bytes_to_pin", ToString(HumanReadableSize(progress.bytes_to_pin)));
+    d.Set("pinned_bytes", ToString(HumanReadableSize(progress.pinned_bytes)));
+    d.Set("files_to_pin", ToString(progress.files_to_pin));
+    d.Set("pinned_files", ToString(progress.pinned_files));
+    d.Set("failed_files", ToString(progress.failed_files));
     MaybeCallJavascript("onBulkPinningProgress", base::Value(std::move(d)));
   }
 
@@ -848,6 +847,7 @@
 
     const bool enabled = args[0].GetBool();
     GetPrefs()->SetBoolean(drive::prefs::kDriveFsBulkPinningEnabled, enabled);
+    UpdateBulkPinningSection();
   }
 
   // Called when the "Startup Arguments" field on the page is submitted.
diff --git a/chrome/browser/ui/webui/downloads/downloads.mojom b/chrome/browser/ui/webui/downloads/downloads.mojom
index a5aa1fee..721e8f4 100644
--- a/chrome/browser/ui/webui/downloads/downloads.mojom
+++ b/chrome/browser/ui/webui/downloads/downloads.mojom
@@ -71,6 +71,13 @@
   // received a warning deep scanning verdict. This requires a user gesture on
   // the WebUI.
   ReviewDangerousRequiringGesture(string id);
+
+  // Performs deep scan for the download with the given |id|.
+  DeepScan(string id);
+
+  // Bypass deep scan for download with the given |id|. This requires a user
+  // gesture on the WebUI.
+  BypassDeepScanRequiringGesture(string id);
 };
 
 interface Page {
diff --git a/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc b/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc
index b353928..3f380cc 100644
--- a/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc
+++ b/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc
@@ -78,6 +78,8 @@
   DOWNLOADS_DOM_EVENT_RETRY_DOWNLOAD = 12,
   DOWNLOADS_DOM_EVENT_OPEN_DURING_SCANNING = 13,
   DOWNLOADS_DOM_EVENT_REVIEW_DANGEROUS = 14,
+  DOWNLOADS_DOM_EVENT_DEEP_SCAN = 15,
+  DOWNLOADS_DOM_EVENT_BYPASS_DEEP_SCAN = 16,
   DOWNLOADS_DOM_EVENT_MAX
 };
 
@@ -417,6 +419,33 @@
   }
 }
 
+void DownloadsDOMHandler::DeepScan(const std::string& id) {
+  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DEEP_SCAN);
+  download::DownloadItem* download = GetDownloadByStringId(id);
+  if (download) {
+    DownloadItemModel model(download);
+    DownloadCommands commands(model.GetWeakPtr());
+    commands.ExecuteCommand(DownloadCommands::DEEP_SCAN);
+  }
+}
+
+void DownloadsDOMHandler::BypassDeepScanRequiringGesture(
+    const std::string& id) {
+  if (!GetWebUIWebContents()->HasRecentInteraction()) {
+    LOG(ERROR) << "BypassDeepScanRequiringGesture received without recent "
+                  "user interaction";
+    return;
+  }
+
+  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_BYPASS_DEEP_SCAN);
+  download::DownloadItem* download = GetDownloadByStringId(id);
+  if (download) {
+    DownloadItemModel model(download);
+    DownloadCommands commands(model.GetWeakPtr());
+    commands.ExecuteCommand(DownloadCommands::BYPASS_DEEP_SCANNING);
+  }
+}
+
 void DownloadsDOMHandler::ReviewDangerousRequiringGesture(
     const std::string& id) {
   if (!GetWebUIWebContents()->HasRecentInteraction()) {
diff --git a/chrome/browser/ui/webui/downloads/downloads_dom_handler.h b/chrome/browser/ui/webui/downloads/downloads_dom_handler.h
index a30d81ba..b309b677 100644
--- a/chrome/browser/ui/webui/downloads/downloads_dom_handler.h
+++ b/chrome/browser/ui/webui/downloads/downloads_dom_handler.h
@@ -68,6 +68,8 @@
   void OpenDownloadsFolderRequiringGesture() override;
   void OpenDuringScanningRequiringGesture(const std::string& id) override;
   void ReviewDangerousRequiringGesture(const std::string& id) override;
+  void DeepScan(const std::string& id) override;
+  void BypassDeepScanRequiringGesture(const std::string& id) override;
 
  protected:
   // These methods are for mocking so that most of this class does not actually
diff --git a/chrome/browser/ui/webui/downloads/downloads_list_tracker.cc b/chrome/browser/ui/webui/downloads/downloads_list_tracker.cc
index 223774f2..e5bae16 100644
--- a/chrome/browser/ui/webui/downloads/downloads_list_tracker.cc
+++ b/chrome/browser/ui/webui/downloads/downloads_list_tracker.cc
@@ -282,13 +282,16 @@
 
   switch (download_item->GetState()) {
     case download::DownloadItem::IN_PROGRESS: {
-      if (download_item->IsDangerous()) {
-        state = "DANGEROUS";
-      } else if (download_item->IsInsecure()) {
-        state = "INSECURE";
+      if (download_item->GetDangerType() ==
+          download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING) {
+        state = "PROMPT_FOR_SCANNING";
       } else if (download_item->GetDangerType() ==
                  download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING) {
         state = "ASYNC_SCANNING";
+      } else if (download_item->IsDangerous()) {
+        state = "DANGEROUS";
+      } else if (download_item->IsInsecure()) {
+        state = "INSECURE";
       } else if (download_item->IsPaused()) {
         state = "PAUSED";
       } else {
diff --git a/chrome/browser/ui/webui/downloads/downloads_ui.cc b/chrome/browser/ui/webui/downloads/downloads_ui.cc
index 97b282fd..229e958 100644
--- a/chrome/browser/ui/webui/downloads/downloads_ui.cc
+++ b/chrome/browser/ui/webui/downloads/downloads_ui.cc
@@ -107,6 +107,7 @@
       {"blockedTooLargeDesc", IDS_BLOCKED_TOO_LARGE_DESCRIPTION},
       {"blockedPasswordProtectedDesc",
        IDS_BLOCKED_PASSWORD_PROTECTED_DESCRIPTION},
+      {"promptForScanningDesc", IDS_BLOCK_REASON_PROMPT_FOR_SCANNING},
 
       // Controls.
       {"controlPause", IDS_DOWNLOAD_LINK_PAUSE},
@@ -117,6 +118,8 @@
       {"controlRetry", IDS_DOWNLOAD_LINK_RETRY},
       {"controlledByUrl", IDS_DOWNLOAD_BY_EXTENSION_URL},
       {"controlOpenNow", IDS_OPEN_DOWNLOAD_NOW},
+      {"controlDeepScan", IDS_DOWNLOAD_DEEP_SCAN},
+      {"controlBypassDeepScan", IDS_DOWNLOAD_BYPASS_DEEP_SCAN},
       {"toastClearedAll", IDS_DOWNLOAD_TOAST_CLEARED_ALL},
       {"toastRemovedFromList", IDS_DOWNLOAD_TOAST_REMOVED_FROM_LIST},
       {"undo", IDS_DOWNLOAD_UNDO},
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index efb2ab3..f346c7d 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1674151179-444a6c32cc2d887751696630e61a95dc4eedcc59.profdata
+chrome-linux-main-1674172666-17e9e5abb6be1ae06515d73523045700969b577e.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 71c7a02..811480e 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1674151179-0bce2e36940f9e7e886e2cd46ee5baf348785ab6.profdata
+chrome-mac-arm-main-1674172666-b16c2e7404c35b42faef76912fa95cbca84ff4a2.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index b9a95e2d..ef2efd6 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1674151179-5cbdba6fa6d72d0fd35b860ec668d8dac0c6a0e5.profdata
+chrome-mac-main-1674172666-a6b0cdea53a3cb9e4ce243a00ac4f1c0847b3818.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index d68a0f37..2ef9613 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1674151179-8da70f8885145c4bc1c1cf3dcde3cc646de24058.profdata
+chrome-win32-main-1674159413-e68cd0619f904d382d4a01219e4688610d54921f.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 70c31b1..75cc375 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1674151179-ee446dd25764dd835abaff4c8b716fc5551b7fab.profdata
+chrome-win64-main-1674172666-746b6dd38a0be1e72cddfdeb58e1bed8405a5d40.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 184d33d..e53c6083 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2501,6 +2501,7 @@
         "//chrome/browser/ash/system_web_apps/test_support",
         "//chrome/browser/ash/system_web_apps/test_support:test_support_ui",
         "//chrome/browser/ui/ash/system_web_apps",
+        "//chromeos/ash/components/standalone_browser",
       ]
     }
 
@@ -4818,6 +4819,7 @@
     ]
 
     sources = [
+      "../browser/accessibility/live_caption_surface_browsertest.cc",
       "../browser/chromeos/extensions/contact_center_insights/contact_center_insights_extension_manager_lacros_browsertest.cc",
 
       # dlp_content_manager_lacros_browsertest.cc should become a unit test.
@@ -4858,6 +4860,7 @@
     ]
 
     data = [
+      "//content/test/data/",
       "data/media/",
       "data/extensions/api_test/shared_storage_private/",
       "data/extensions/api_test/login_screen_apis/",
@@ -7370,6 +7373,7 @@
       "../browser/ui/window_sizer/window_sizer_unittest.cc",
     ]
     sources += [
+      "../browser/apps/app_deduplication_service/app_deduplication_cache_unittest.cc",
       "../browser/apps/app_deduplication_service/app_deduplication_mapper_unittest.cc",
       "../browser/apps/app_deduplication_service/app_deduplication_server_connector_unittest.cc",
       "../browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc",
@@ -7455,6 +7459,7 @@
       "../browser/ash/app_list/search/search_controller_unittest.cc",
       "../browser/ash/app_list/search/search_metrics_manager_unittest.cc",
       "../browser/ash/app_list/search/search_session_metrics_manager_unittest.cc",
+      "../browser/ash/app_list/search/system_info/cpu_usage_data_unittest.cc",
       "../browser/ash/app_list/search/test/ranking_test_util.cc",
       "../browser/ash/app_list/search/test/ranking_test_util.h",
       "../browser/ash/app_list/search/test/search_controller_test_util.cc",
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js
index 9eb48ad9..d8705bc 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_browsertest.js
@@ -161,4 +161,21 @@
 
 TEST_F('EmojiPickerGifTest', 'All', function() {
   mocha.run();
+});
+
+var EmojiPickerGifValidationTest = class extends PolymerTest {
+  /** @override */
+  get featureList() {
+    return {enabled: ['ash::features::kImeSystemEmojiPickerGIFSupport']};
+  }
+
+  /** @override */
+  get browsePreload() {
+    return 'chrome://emoji-picker/test_loader.html?module=' +
+        'chromeos/emoji_picker/emoji_picker_validation_gif_test.js&host=test';
+  }
+};
+
+TEST_F('EmojiPickerGifValidationTest', 'All', function() {
+  mocha.run();
 });
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_gif.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_gif.js
index 543b96a..429c785f 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_gif.js
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_gif.js
@@ -191,5 +191,33 @@
                   .shadowRoot.querySelectorAll('.emoji-button');
           assertEquals(1, recentlyUsedEmoji.length);
         });
+
+    test(
+        `recently used ${category} group should not contain ` +
+            `duplicate ${category}s.`,
+        async () => {
+          emojiPicker.updateIncognitoState(false);
+
+          const emojiButton =
+              findEmojiFirstButton(categoryGroupSelector(category));
+          emojiButton.click();
+
+          const recentEmojiButton = await waitForCondition(
+              () => findEmojiFirstButton(historyGroupSelector(category)));
+          assert(recentEmojiButton);
+
+          const recentlyUsedEmoji1 =
+              findInEmojiPicker(historyGroupSelector(category))
+                  .shadowRoot.querySelectorAll('.emoji-button');
+          assertEquals(1, recentlyUsedEmoji1.length);
+
+          // Click the same emoji again
+          emojiButton.click();
+
+          const recentlyUsedEmoji2 =
+              findInEmojiPicker(historyGroupSelector(category))
+                  .shadowRoot.querySelectorAll('.emoji-button');
+          assertEquals(1, recentlyUsedEmoji2.length);
+        });
   });
-}
+}
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_validation_gif_test.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_validation_gif_test.js
new file mode 100644
index 0000000..7153b510
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_validation_gif_test.js
@@ -0,0 +1,200 @@
+// 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 {GIF_VALIDATION_DATE} from 'chrome://emoji-picker/constants.js';
+import {EmojiPicker} from 'chrome://emoji-picker/emoji_picker.js';
+import {EmojiPickerApiProxyImpl} from 'chrome://emoji-picker/emoji_picker_api_proxy.js';
+import {EMOJI_PICKER_READY} from 'chrome://emoji-picker/events.js';
+import {assert} from 'chrome://resources/ash/common/assert.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {deepQuerySelector, waitForCondition} from './emoji_picker_test_util.js';
+import {TestEmojiPickerApiProxyImpl} from './test_emoji_picker_api_proxy.js';
+
+function historyGroupSelector(category) {
+  return `[data-group="${category}-history"] > ` +
+      `emoji-group[category="${category}"]`;
+}
+
+suite(`emoji-picker-validation-gif`, () => {
+  /** @type {!EmojiPicker} */
+  let emojiPicker;
+  /** @type {function(...!string): ?HTMLElement} */
+  let findInEmojiPicker;
+  /** @type {function(...!string): ?HTMLElement} */
+  let findEmojiAllButtons;
+  /** @type {Array<string>} */
+  const categoryList = ['emoji', 'symbol', 'emoticon', 'gif'];
+  /** @type {number} */
+  let categoryIndex;
+
+  setup(() => {
+    // Reset DOM state.
+    document.body.innerHTML = '';
+    window.localStorage.clear();
+    window.localStorage.setItem(GIF_VALIDATION_DATE, new Date(0).toJSON());
+
+    const historyGifs = {
+      history: [
+        {
+          base: {
+            visualContent: {
+              id: '0',
+              url: {
+                full: {
+                  url:
+                      'https://media.tenor.com/P0tX6a_nVIkAAAAC/grinch-smile-grinch.gif',
+                },
+                preview: {
+                  url:
+                      'https://media.tenor.com/P0tX6a_nVIkAAAAM/grinch-smile-grinch.gif',
+                },
+              },
+              previewSize: {width: 220, height: 324},
+            },
+            name: 'Grinch Smile Grinch GIF',
+          },
+          alternates: [],
+        },
+        {
+          base: {
+            visualContent: {
+              id: '1',
+              url: {
+                full: {
+                  url: 'https://media.tenor.com/HU6E9HN1dSAAAAAC/head-turn.gif',
+                },
+                preview: {
+                  url: 'https://media.tenor.com/HU6E9HN1dSAAAAAM/head-turn.gif',
+                },
+              },
+              previewSize: {width: 220, height: 224},
+            },
+            name: 'Head Turn GIF',
+          },
+          alternates: [],
+        },
+        {
+          base: {
+            visualContent: {
+              id: '2',
+              url: {
+                full: {
+                  url:
+                      'https://media.tenor.com/OfjkK_lANHsAAAAC/snoopy-dog.gif',
+                },
+                preview: {
+                  url:
+                      'https://media.tenor.com/OfjkK_lANHsAAAAM/snoopy-dog.gif',
+                },
+              },
+              previewSize: {width: 220, height: 164},
+            },
+            name: 'Snoopy Dog GIF',
+          },
+          alternates: [],
+        },
+        {
+          base: {
+            visualContent: {
+              id: 3,
+              url: {
+                full: {
+                  url:
+                      'https://media.tenor.com/lSFT81zyIkMAAAAC/baby-yoda-i-love-you.gif',
+                },
+                preview: {
+                  url:
+                      'https://media.tenor.com/lSFT81zyIkMAAAAM/baby-yoda-i-love-you.gif',
+                },
+              },
+              previewSize: {width: 220, height: 176},
+            },
+            name: 'Baby Yoda I Love You GIF',
+          },
+          alternates: [],
+        },
+        {
+          base: {
+            visualContent: {
+              id: '4',
+              url: {
+                full: {
+                  url:
+                      'https://media.tenor.com/QPapotlLW18AAAAC/dance-cute.gif',
+                },
+                preview: {
+                  url:
+                      'https://media.tenor.com/QPapotlLW18AAAAM/dance-cute.gif',
+                },
+              },
+              previewSize: {width: 220, height: 234},
+            },
+            name: 'Dance Cute GIF',
+          },
+          alternates: [],
+        },
+      ],
+      preference: {},
+    };
+
+    // Set GIF history.
+    window.localStorage.setItem(
+        'gif-recently-used', JSON.stringify(historyGifs));
+
+    EmojiPickerApiProxyImpl.setInstance(new TestEmojiPickerApiProxyImpl());
+
+    // Set default incognito state to False.
+    EmojiPickerApiProxyImpl.getInstance().isIncognitoTextField = () =>
+        new Promise((resolve) => resolve({incognito: false}));
+    EmojiPicker.configs = () => ({
+      'dataUrls': {
+        'emoji': [
+          '/emoji_test_ordering_start.json',
+          '/emoji_test_ordering_remaining.json',
+        ],
+        'emoticon': ['/emoticon_test_ordering.json'],
+        'symbol': ['/symbol_test_ordering.json'],
+        'gif': [],
+      },
+    });
+
+    emojiPicker =
+        /** @type {!EmojiPicker} */ (document.createElement('emoji-picker'));
+
+    findInEmojiPicker = (...path) => deepQuerySelector(emojiPicker, path);
+
+    categoryIndex = categoryList.indexOf('gif');
+
+    // Wait until emoji data is loaded before executing tests.
+    return new Promise((resolve) => {
+      emojiPicker.addEventListener(EMOJI_PICKER_READY, () => {
+        flush();
+        resolve();
+      });
+      document.body.appendChild(emojiPicker);
+    });
+  });
+
+
+  test(
+      `recently used gif group should contain the ` +
+          `correct gifs after it is has been validated.`,
+      async () => {
+        emojiPicker.updateIncognitoState(false);
+
+        // Whilst history originally had 5 GIFs, there should now only be 3
+        // valid GIFs.
+        const recentlyUsedEmoji =
+            findInEmojiPicker(historyGroupSelector('gif'))
+                .shadowRoot.querySelectorAll('.emoji-button');
+
+        assertEquals(3, recentlyUsedEmoji.length);
+
+        // Check that the correct GIFs have been deleted.
+        assert(recentlyUsedEmoji[0].alt === 'Head Turn GIF');
+        assert(recentlyUsedEmoji[1].alt === 'Snoopy Dog GIF');
+        assert(recentlyUsedEmoji[2].alt === 'Dance Cute GIF');
+      });
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/test_emoji_picker_api_proxy.js b/chrome/test/data/webui/chromeos/emoji_picker/test_emoji_picker_api_proxy.js
index 1d5b1b3..1e52bb11 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/test_emoji_picker_api_proxy.js
+++ b/chrome/test/data/webui/chromeos/emoji_picker/test_emoji_picker_api_proxy.js
@@ -60,9 +60,46 @@
   getGifsByIds(ids) {
     return new Promise((resolve) => {
       resolve({
-        selectedGifs: {
-          result: this.gifs.results,
-        },
+        selectedGifs: [
+          {
+            id: '1',
+            url: {
+              full: 'https://media.tenor.com/HU6E9HN1dSAAAAAC/head-turn.gif',
+              preview: 'https://media.tenor.com/HU6E9HN1dSAAAAAM/head-turn.gif',
+            },
+            previewSize: {
+              width: 220,
+              height: 224,
+            },
+            contentDescription: 'Head Turn GIF',
+          },
+          {
+            id: '2',
+            url: {
+              full: 'https://media.tenor.com/OfjkK_lANHsAAAAC/snoopy-dog.gif',
+              preview:
+                  'https://media.tenor.com/OfjkK_lANHsAAAAM/snoopy-dog.gif',
+            },
+            previewSize: {
+              width: 220,
+              height: 164,
+            },
+            contentDescription: 'Snoopy Dog GIF',
+          },
+          {
+            id: '4',
+            url: {
+              full: 'https://media.tenor.com/QPapotlLW18AAAAC/dance-cute.gif',
+              preview:
+                  'https://media.tenor.com/QPapotlLW18AAAAM/dance-cute.gif',
+            },
+            previewSize: {
+              width: 220,
+              height: 234,
+            },
+            contentDescription: 'Dance Cute GIF',
+          },
+        ],
       });
     });
   }
diff --git a/chrome/test/data/webui/downloads/item_tests.ts b/chrome/test/data/webui/downloads/item_tests.ts
index fc72b21..eb478f0 100644
--- a/chrome/test/data/webui/downloads/item_tests.ts
+++ b/chrome/test/data/webui/downloads/item_tests.ts
@@ -114,6 +114,17 @@
     assertEquals(item.shadowRoot!.querySelector('#openNow'), null);
   });
 
+  test('deep scan buttons shown on correct state', async () => {
+    item.set('data', createDownload({
+               filePath: 'unique1',
+               hideDate: false,
+               state: States.PROMPT_FOR_SCANNING,
+             }));
+    flush();
+    assertNotEquals(item.shadowRoot!.querySelector('#deepScan'), null);
+    assertNotEquals(item.shadowRoot!.querySelector('#bypassDeepScan'), null);
+  });
+
   test('undo is shown in toast', () => {
     item.data = createDownload({hideDate: false});
     toastManager.show('', /* hideSlotted= */ true);
diff --git a/chrome/test/data/webui/downloads/test_support.ts b/chrome/test/data/webui/downloads/test_support.ts
index 3ed49fb..08685662 100644
--- a/chrome/test/data/webui/downloads/test_support.ts
+++ b/chrome/test/data/webui/downloads/test_support.ts
@@ -55,6 +55,8 @@
   openDownloadsFolderRequiringGesture() {}
   openDuringScanningRequiringGesture(_id: string) {}
   reviewDangerousRequiringGesture(_id: string) {}
+  deepScan(_id: string) {}
+  bypassDeepScanRequiringGesture(_id: string) {}
 }
 
 export class TestIconLoader extends TestBrowserProxy implements IconLoader {
diff --git a/chrome/test/data/webui/settings/chromeos/fake_input_method_private.js b/chrome/test/data/webui/settings/chromeos/fake_input_method_private.js
index 653d7f2..3301c71 100644
--- a/chrome/test/data/webui/settings/chromeos/fake_input_method_private.js
+++ b/chrome/test/data/webui/settings/chromeos/fake_input_method_private.js
@@ -15,11 +15,9 @@
 export function FakeInputMethodPrivate() {}
 
 FakeInputMethodPrivate.prototype = {
-  getCurrentInputMethod: function(callback) {
-    callback(null);
-  },
+  getCurrentInputMethod: () => Promise.resolve(null),
 
-  setCurrentInputMethod: () => {},
+  setCurrentInputMethod: () => Promise.resolve(),
 
   get onChanged() {
     return {
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index de17e59..f827dea 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -459,6 +459,8 @@
       "-e",
       "HELP_CENTER_URL=\"$help_center_url\"",
       "-e",
+      "APP_LOGO_URL=\"$app_logo_url\"",
+      "-e",
       "KEYSTONE_NAME=\"$keystone_app_name\"",
       "-e",
       "PRIVILEGED_HELPER_NAME=\"$privileged_helper_name\"",
diff --git a/chrome/updater/app/app_install_win.cc b/chrome/updater/app/app_install_win.cc
index 7813486..f091d14 100644
--- a/chrome/updater/app/app_install_win.cc
+++ b/chrome/updater/app/app_install_win.cc
@@ -856,12 +856,23 @@
     progress_wnd->Initialize();
     progress_wnd->Show();
 
-    // TODO(crbug/1406963): Provide the url for the logo here based on the
-    // `app_id_`.
+    // The app logo is expected to be hosted at `{APP_LOGO_URL}{url escaped
+    // app_id_}.bmp`. If `{url escaped app_id_}.bmp` exists, a logo is shown in
+    // the updater UI for that app install.
+    //
+    // For example, if `app_id_` is `{8A69D345-D564-463C-AFF1-A69D9E530F96}`,
+    // the `{url escaped app_id_}.bmp` is
+    // `%7b8A69D345-D564-463C-AFF1-A69D9E530F96%7d.bmp`.
+    //
+    // `APP_LOGO_URL` is specified in chrome/updater/branding.gni.
     base::ThreadPool::CreateCOMSTATaskRunner({base::MayBlock()})
         ->PostTask(FROM_HERE,
-                   base::BindOnce(&AppInstallControllerImpl::LoadLogo, this,
-                                  L"", progress_wnd->m_hWnd));
+                   base::BindOnce(
+                       &AppInstallControllerImpl::LoadLogo, this,
+                       base::SysUTF8ToWide(base::StringPrintf(
+                           "%s%s.bmp", APP_LOGO_URL,
+                           base::EscapeUrlEncodedData(app_id_, false).c_str())),
+                       progress_wnd->m_hWnd));
 
     observer_.reset(progress_wnd.release());
   }
diff --git a/chrome/updater/branding.gni b/chrome/updater/branding.gni
index 48e58ff..0ae9753 100644
--- a/chrome/updater/branding.gni
+++ b/chrome/updater/branding.gni
@@ -10,6 +10,7 @@
   crash_product_name = "Update4"
   crash_upload_url = "https://clients2.google.com/cr/report"
   help_center_url = "http://support.google.com/installer/"
+  app_logo_url = "https://dl.google.com/update2/testing/icons/"
   keystone_app_name = "GoogleSoftwareUpdate"
   mac_browser_bundle_identifier = "com.google.Chrome"
   mac_updater_bundle_identifier = "com.google.GoogleUpdater"
@@ -27,6 +28,7 @@
   crash_product_name = "ChromiumUpdater"
   crash_upload_url = "https://clients2.google.com/cr/staging_report"
   help_center_url = "http://support.google.com/installer/"
+  app_logo_url = "https://dl.google.com/update2/testing/icons/"
   keystone_app_name = "ChromiumSoftwareUpdate"
   mac_browser_bundle_identifier = "org.chromium.Chromium"
   mac_updater_bundle_identifier = "org.chromium.ChromiumUpdater"
diff --git a/chrome/updater/constants.cc b/chrome/updater/constants.cc
index b9c42b79..9a6398bc 100644
--- a/chrome/updater/constants.cc
+++ b/chrome/updater/constants.cc
@@ -109,6 +109,12 @@
 
 const char kUTF8BOM[] = "\xEF\xBB\xBF";
 
+const char kSourceGroupPolicyManager[] = "GroupPolicy";
+const char kSourceDMPolicyManager[] = "DeviceManagement";
+const char kSourceManagedPreferencePolicyManager[] = "ManagedPreference";
+const char kSourceDefaultValuesPolicyManager[] = "default";
+const char kSourceDictValuesPolicyManager[] = "DictValuePolicy";
+
 #if BUILDFLAG(IS_MAC)
 // The user defaults suite name.
 const char kUserDefaultsSuiteName[] = MAC_BUNDLE_IDENTIFIER_STRING ".defaults";
diff --git a/chrome/updater/constants.h b/chrome/updater/constants.h
index 3fb30982..74cb396 100644
--- a/chrome/updater/constants.h
+++ b/chrome/updater/constants.h
@@ -418,6 +418,13 @@
 inline constexpr bool kInstallPolicyDefault = kPolicyEnabled;
 inline constexpr bool kUpdatePolicyDefault = kPolicyEnabled;
 
+// Policy manager `source()` constants.
+extern const char kSourceGroupPolicyManager[];
+extern const char kSourceDMPolicyManager[];
+extern const char kSourceManagedPreferencePolicyManager[];
+extern const char kSourceDefaultValuesPolicyManager[];
+extern const char kSourceDictValuesPolicyManager[];
+
 inline constexpr int kUninstallPingReasonUninstalled = 0;
 inline constexpr int kUninstallPingReasonUserNotAnOwner = 1;
 
diff --git a/chrome/updater/policy/dm_policy_manager.cc b/chrome/updater/policy/dm_policy_manager.cc
index 53cdd84..f303dd0 100644
--- a/chrome/updater/policy/dm_policy_manager.cc
+++ b/chrome/updater/policy/dm_policy_manager.cc
@@ -73,7 +73,7 @@
 }
 
 std::string DMPolicyManager::source() const {
-  return std::string("DeviceManagement");
+  return kSourceDMPolicyManager;
 }
 
 absl::optional<base::TimeDelta> DMPolicyManager::GetLastCheckPeriod() const {
diff --git a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm
index 4c2c6f4..387af2f 100644
--- a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm
+++ b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm
@@ -245,7 +245,8 @@
 }
 
 - (NSString*)source {
-  return @"ManagedPreference";
+  return [NSString
+      stringWithUTF8String:updater::kSourceManagedPreferencePolicyManager];
 }
 
 - (NSString*)downloadPreference {
diff --git a/chrome/updater/policy/manager.cc b/chrome/updater/policy/manager.cc
index 8538947e..9cfcf48 100644
--- a/chrome/updater/policy/manager.cc
+++ b/chrome/updater/policy/manager.cc
@@ -98,7 +98,7 @@
 }
 
 std::string DefaultValuesPolicyManager::source() const {
-  return std::string("default");
+  return kSourceDefaultValuesPolicyManager;
 }
 
 absl::optional<base::TimeDelta> DefaultValuesPolicyManager::GetLastCheckPeriod()
diff --git a/chrome/updater/policy/policy_manager.cc b/chrome/updater/policy/policy_manager.cc
index baa8f43..256e998 100644
--- a/chrome/updater/policy/policy_manager.cc
+++ b/chrome/updater/policy/policy_manager.cc
@@ -85,7 +85,7 @@
 }
 
 std::string PolicyManager::source() const {
-  return std::string("DictValuePolicy");
+  return kSourceDictValuesPolicyManager;
 }
 
 absl::optional<base::TimeDelta> PolicyManager::GetLastCheckPeriod() const {
diff --git a/chrome/updater/policy/service.cc b/chrome/updater/policy/service.cc
index 637116a..7f56d02f 100644
--- a/chrome/updater/policy/service.cc
+++ b/chrome/updater/policy/service.cc
@@ -58,8 +58,8 @@
 }
 
 PolicyService::PolicyManagerVector CreatePolicyManagerVector(
+    bool should_take_policy_critical_section,
     scoped_refptr<ExternalConstants> external_constants,
-    bool is_system_install_scenario,
     scoped_refptr<PolicyManagerInterface> dm_policy_manager) {
   PolicyService::PolicyManagerVector managers;
   if (external_constants) {
@@ -68,12 +68,10 @@
   }
 
 #if BUILDFLAG(IS_WIN)
-  managers.push_back(
-      base::MakeRefCounted<GroupPolicyManager>(is_system_install_scenario));
+  managers.push_back(base::MakeRefCounted<GroupPolicyManager>(
+      should_take_policy_critical_section));
 #endif
 
-  if (!dm_policy_manager)
-    dm_policy_manager = CreateDMPolicyManager();
   if (dm_policy_manager)
     managers.push_back(std::move(dm_policy_manager));
 
@@ -100,51 +98,48 @@
     : policy_managers_(SortManagers(std::move(managers))) {}
 
 // The policy managers are initialized without taking the Group Policy critical
-// section here, by passing `true` for `is_system_install_scenario`.
-// Later, if the scenario is user installs/updates or system updates (but not
-// system installs), the policies are reloaded with the critical section lock.
-// System installs may run under GPO that itself takes the critical section, so
-// to prevent a deadlock, updater does not attempt to take the critical section
-// in that scenario.
+// section here, by passing `false` for `should_take_policy_critical_section`,
+// to avoid blocking the main sequence. Later in `FetchPoliciesDone`, the
+// policies are reloaded with the critical section lock.
 PolicyService::PolicyService(
     scoped_refptr<ExternalConstants> external_constants)
-    : policy_managers_(SortManagers(
-          CreatePolicyManagerVector(external_constants,
-                                    /*is_system_install_scenario*/ true,
-                                    nullptr))),
+    : policy_managers_(SortManagers(CreatePolicyManagerVector(
+          /*should_take_policy_critical_section*/ false,
+          external_constants,
+          CreateDMPolicyManager()))),
       external_constants_(external_constants),
       policy_fetcher_(base::MakeRefCounted<PolicyFetcher>(this)) {}
 
 PolicyService::~PolicyService() = default;
 
-void PolicyService::FetchPolicies(base::OnceCallback<void(int)> callback,
-                                  bool is_system_install_scenario) {
+void PolicyService::FetchPolicies(base::OnceCallback<void(int)> callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  policy_fetcher_->FetchPolicies(
-      base::BindOnce(&PolicyService::FetchPoliciesDone, this,
-                     std::move(callback), is_system_install_scenario));
+  policy_fetcher_->FetchPolicies(base::BindOnce(
+      &PolicyService::FetchPoliciesDone, this, std::move(callback)));
 }
 
 void PolicyService::FetchPoliciesDone(
     base::OnceCallback<void(int)> callback,
-    bool is_system_install_scenario,
     int result,
     scoped_refptr<PolicyManagerInterface> dm_policy_manager) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   VLOG(1) << __func__;
 
   base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()},
+      FROM_HERE, {base::MayBlock(), base::WithBaseSyncPrimitives()},
       base::BindOnce(
           [](scoped_refptr<ExternalConstants> external_constants,
-             bool is_system_install_scenario,
              scoped_refptr<PolicyManagerInterface> dm_policy_manager) {
-            return CreatePolicyManagerVector(external_constants,
-                                             is_system_install_scenario,
-                                             std::move(dm_policy_manager));
+            return CreatePolicyManagerVector(
+                /*should_take_policy_critical_section*/ true,
+                external_constants, dm_policy_manager);
           },
-          external_constants_, is_system_install_scenario, dm_policy_manager),
+          external_constants_,
+          dm_policy_manager ? dm_policy_manager
+          : policy_managers_.name_map.count(kSourceDMPolicyManager)
+              ? policy_managers_.name_map[kSourceDMPolicyManager]
+              : nullptr),
       base::BindOnce(
           [](scoped_refptr<PolicyService> self,
              base::OnceCallback<void(int)> callback, int result,
diff --git a/chrome/updater/policy/service.h b/chrome/updater/policy/service.h
index 13d883b2..b4ca252 100644
--- a/chrome/updater/policy/service.h
+++ b/chrome/updater/policy/service.h
@@ -101,8 +101,7 @@
   // Fetches policies from device management and updates the PolicyService
   // instance. `callback` is passed a result that is `kErrorOk` on success,
   // `kErrorDMRegistrationFailed` if DM registration fails, or any other error.
-  void FetchPolicies(base::OnceCallback<void(int)> callback,
-                     bool is_system_install_scenario);
+  void FetchPolicies(base::OnceCallback<void(int)> callback);
 
   std::string source() const;
 
@@ -141,7 +140,6 @@
   // in a blocking sequence since it needs to do I/O to load policies.
   void FetchPoliciesDone(
       base::OnceCallback<void(int)> callback,
-      bool is_system_install_scenario,
       int result,
       scoped_refptr<PolicyManagerInterface> dm_policy_manager);
 
diff --git a/chrome/updater/policy/win/group_policy_manager.cc b/chrome/updater/policy/win/group_policy_manager.cc
index 6de3f677..f5870c5 100644
--- a/chrome/updater/policy/win/group_policy_manager.cc
+++ b/chrome/updater/policy/win/group_policy_manager.cc
@@ -11,8 +11,17 @@
 
 #include "base/check.h"
 #include "base/enterprise_util.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/scoped_generic.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "base/win/registry.h"
 #include "chrome/updater/win/win_constants.h"
@@ -34,24 +43,47 @@
 using scoped_hpolicy =
     base::ScopedGeneric<HANDLE, updater::ScopedHCriticalPolicySectionTraits>;
 
-base::Value::Dict LoadGroupPolicies(bool is_system_install_scenario) {
-  scoped_hpolicy policy_lock;
+struct PolicySectionEvents
+    : public base::RefCountedThreadSafe<PolicySectionEvents> {
+  base::WaitableEvent enter_policy_section;
+  base::WaitableEvent leave_policy_section;
 
-  if (!is_system_install_scenario && base::IsManagedDevice()) {
-    // GPO rules mandate a call to EnterCriticalPolicySection() before reading
-    // policies (and a matching LeaveCriticalPolicySection() call after read).
-    //
-    // The Group Policy critical section is taken for all user installs and
-    // updates, as well as all system updates. The Group Policy critical section
-    // is not taken for system install scenarios, because system installs could
-    // be running under GPO which takes the critical section, and this can cause
-    // a deadlock.
-    //
-    // Additionally, the Group Policy critical section is only taken for managed
-    // machines because group policies are applied only in this case, and the
-    // lock acquisition can take a long time in the worst case scenarios.
-    policy_lock.reset(::EnterCriticalPolicySection(true));
-    CHECK(policy_lock.is_valid()) << "Failed to get policy lock.";
+ private:
+  friend class base::RefCountedThreadSafe<PolicySectionEvents>;
+  virtual ~PolicySectionEvents() = default;
+};
+
+base::Value::Dict LoadGroupPolicies(bool should_take_policy_critical_section) {
+  base::ScopedClosureRunner leave_policy_section_closure;
+
+  if (should_take_policy_critical_section && base::IsManagedDevice()) {
+    // Only for managed machines, a best effort is made to take the Group Policy
+    // critical section. Lock acquisition can take a long time in the worst case
+    // scenarios, hence a short timed wait is used.
+
+    auto events = base::MakeRefCounted<PolicySectionEvents>();
+    leave_policy_section_closure.ReplaceClosure(base::BindOnce(
+        [](scoped_refptr<PolicySectionEvents> events) {
+          events->leave_policy_section.Signal();
+        },
+        events));
+
+    base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})
+        ->PostTask(FROM_HERE,
+                   base::BindOnce(
+                       [](scoped_refptr<PolicySectionEvents> events) {
+                         scoped_hpolicy policy_lock(
+                             ::EnterCriticalPolicySection(true));
+
+                         events->enter_policy_section.Signal();
+
+                         events->leave_policy_section.Wait();
+                       },
+                       events));
+
+    if (!events->enter_policy_section.TimedWait(base::Seconds(30))) {
+      VLOG(1) << "Timed out trying to get the policy critical section.";
+    }
   }
 
   base::Value::Dict policies;
@@ -80,8 +112,8 @@
 
 }  // namespace
 
-GroupPolicyManager::GroupPolicyManager(bool is_system_install_scenario)
-    : PolicyManager(LoadGroupPolicies(is_system_install_scenario)) {}
+GroupPolicyManager::GroupPolicyManager(bool should_take_policy_critical_section)
+    : PolicyManager(LoadGroupPolicies(should_take_policy_critical_section)) {}
 
 GroupPolicyManager::~GroupPolicyManager() = default;
 
@@ -90,7 +122,7 @@
 }
 
 std::string GroupPolicyManager::source() const {
-  return std::string("GroupPolicy");
+  return kSourceGroupPolicyManager;
 }
 
 }  // namespace updater
diff --git a/chrome/updater/policy/win/group_policy_manager.h b/chrome/updater/policy/win/group_policy_manager.h
index 3a351a6..2a215f6b 100644
--- a/chrome/updater/policy/win/group_policy_manager.h
+++ b/chrome/updater/policy/win/group_policy_manager.h
@@ -14,7 +14,7 @@
 // The GroupPolicyManager returns policies for domain-joined machines.
 class GroupPolicyManager : public PolicyManager {
  public:
-  explicit GroupPolicyManager(bool is_system_install_scenario);
+  explicit GroupPolicyManager(bool should_take_policy_critical_section);
   GroupPolicyManager(const GroupPolicyManager&) = delete;
   GroupPolicyManager& operator=(const GroupPolicyManager&) = delete;
 
diff --git a/chrome/updater/policy/win/group_policy_manager_unittest.cc b/chrome/updater/policy/win/group_policy_manager_unittest.cc
index d9709a3e..f2b1b69 100644
--- a/chrome/updater/policy/win/group_policy_manager_unittest.cc
+++ b/chrome/updater/policy/win/group_policy_manager_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/time/time.h"
 #include "base/win/registry.h"
 #include "base/win/win_util.h"
-#include "chrome/updater/test_scope.h"
 #include "chrome/updater/util/win_util.h"
 #include "chrome/updater/win/win_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -51,7 +50,7 @@
 
 TEST_F(GroupPolicyManagerTests, NoPolicySet) {
   scoped_refptr<PolicyManagerInterface> policy_manager =
-      base::MakeRefCounted<GroupPolicyManager>(IsSystemInstall(GetTestScope()));
+      base::MakeRefCounted<GroupPolicyManager>(true);
   EXPECT_FALSE(policy_manager->HasActiveDevicePolicies());
 
   EXPECT_EQ(policy_manager->source(), "GroupPolicy");
@@ -121,7 +120,7 @@
             key.WriteValue(L"RollbackToTargetVersion" TEST_APP_ID, 1));
 
   scoped_refptr<PolicyManagerInterface> policy_manager =
-      base::MakeRefCounted<GroupPolicyManager>(IsSystemInstall(GetTestScope()));
+      base::MakeRefCounted<GroupPolicyManager>(true);
   EXPECT_EQ(policy_manager->HasActiveDevicePolicies(),
             base::win::IsEnrolledToDomain());
 
@@ -193,7 +192,7 @@
             key.WriteValue(L"RollbackToTargetVersion" TEST_APP_ID, L"1"));
 
   scoped_refptr<PolicyManagerInterface> policy_manager =
-      base::MakeRefCounted<GroupPolicyManager>(IsSystemInstall(GetTestScope()));
+      base::MakeRefCounted<GroupPolicyManager>(true);
 
   EXPECT_EQ(policy_manager->GetLastCheckPeriod(), absl::nullopt);
   EXPECT_EQ(policy_manager->GetUpdatesSuppressedTimes(), absl::nullopt);
diff --git a/chrome/updater/update_service_impl.cc b/chrome/updater/update_service_impl.cc
index e0138b9..d2c6c70 100644
--- a/chrome/updater/update_service_impl.cc
+++ b/chrome/updater/update_service_impl.cc
@@ -237,9 +237,7 @@
   VLOG(1) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  config_->GetPolicyService()->FetchPolicies(
-      std::move(callback),
-      /*is_system_install_scenario*/ IsSystemInstall());
+  config_->GetPolicyService()->FetchPolicies(std::move(callback));
 }
 
 void UpdateServiceImpl::RegisterApp(const RegistrationRequest& request,
@@ -309,16 +307,15 @@
                                          GetUpdaterScope(), persisted_data_)));
 
   new_tasks.push_back(base::BindOnce(
-      [](scoped_refptr<Configurator> config, base::OnceClosure callback) {
-        config->GetPolicyService()->FetchPolicies(
-            base::BindOnce(
-                [](base::OnceClosure callback, int /* ignore_result */) {
-                  std::move(callback).Run();
-                },
-                std::move(callback)),
-            /*is_system_install_scenario*/ false);
+      [](scoped_refptr<UpdateServiceImpl> update_service_impl,
+         base::OnceClosure callback) {
+        update_service_impl->FetchPolicies(base::BindOnce(
+            [](base::OnceClosure callback, int /* ignore_result */) {
+              std::move(callback).Run();
+            },
+            std::move(callback)));
       },
-      config_));
+      base::WrapRefCounted(this)));
   new_tasks.push_back(
       base::BindOnce(&CheckForUpdatesTask::Run,
                      base::MakeRefCounted<CheckForUpdatesTask>(
diff --git a/chrome/updater/updater_branding.h.in b/chrome/updater/updater_branding.h.in
index 1553325..7e68885 100644
--- a/chrome/updater/updater_branding.h.in
+++ b/chrome/updater/updater_branding.h.in
@@ -11,6 +11,7 @@
 #define DEVICE_MANAGEMENT_SERVER_URL "@DEVICE_MANAGEMENT_SERVER_URL@"
 #define KEYSTONE_NAME "@KEYSTONE_NAME@"
 #define HELP_CENTER_URL "@HELP_CENTER_URL@"
+#define APP_LOGO_URL "@APP_LOGO_URL@"
 #define MAC_BROWSER_BUNDLE_IDENTIFIER_STRING "@MAC_BROWSER_BUNDLE_IDENTIFIER@"
 #define MAC_BUNDLE_IDENTIFIER_STRING "@MAC_BUNDLE_IDENTIFIER@"
 #define PRIVILEGED_HELPER_NAME "@PRIVILEGED_HELPER_NAME@"
diff --git a/chrome/updater/win/ui/progress_wnd.cc b/chrome/updater/win/ui/progress_wnd.cc
index 18150248..0fa9ded 100644
--- a/chrome/updater/win/ui/progress_wnd.cc
+++ b/chrome/updater/win/ui/progress_wnd.cc
@@ -28,9 +28,6 @@
 
 namespace {
 
-// TODO(crbug.com/1065588): remove this symbol.
-const char16_t kChromeAppId[] = u"{8A69D345-D564-463C-AFF1-A69D9E530F96}";
-
 // The current UI shows to the user only one completion type, even though
 // there could be multiple applications in a bundle, where each application
 // could have a different completion type. The following array lists the
@@ -323,15 +320,6 @@
                                     const std::u16string& version_string) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  if (base::EqualsCaseInsensitiveASCII(app_id, kChromeAppId)) {
-    HBITMAP app_bitmap = reinterpret_cast<HBITMAP>(
-        ::LoadImage(GetCurrentModuleHandle(), MAKEINTRESOURCE(IDB_CHROME),
-                    IMAGE_BITMAP, 0, 0, LR_SHARED));
-    DCHECK(app_bitmap);
-    SendDlgItemMessage(IDC_APP_BITMAP, STM_SETIMAGE, IMAGE_BITMAP,
-                       reinterpret_cast<LPARAM>(app_bitmap));
-  }
-
   if (!IsWindow())
     return;
 }
diff --git a/chromeos/ash/components/device_activity/BUILD.gn b/chromeos/ash/components/device_activity/BUILD.gn
index 9cff186..b96f588 100644
--- a/chromeos/ash/components/device_activity/BUILD.gn
+++ b/chromeos/ash/components/device_activity/BUILD.gn
@@ -36,6 +36,8 @@
   ]
 
   sources = [
+    "churn_active_status.cc",
+    "churn_active_status.h",
     "daily_use_case_impl.cc",
     "daily_use_case_impl.h",
     "device_active_use_case.cc",
diff --git a/chromeos/ash/components/device_activity/churn_active_status.cc b/chromeos/ash/components/device_activity/churn_active_status.cc
new file mode 100644
index 0000000..7e08b6b
--- /dev/null
+++ b/chromeos/ash/components/device_activity/churn_active_status.cc
@@ -0,0 +1,19 @@
+// 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/device_activity/churn_active_status.h"
+
+namespace ash::device_activity {
+
+ChurnActiveStatus::ChurnActiveStatus() = default;
+
+ChurnActiveStatus::ChurnActiveStatus(int value) : value_(value) {}
+
+ChurnActiveStatus::~ChurnActiveStatus() = default;
+
+int ChurnActiveStatus::GetValueAsInt() const {
+  return static_cast<int>(value_.to_ulong());
+}
+
+}  // namespace ash::device_activity
diff --git a/chromeos/ash/components/device_activity/churn_active_status.h b/chromeos/ash/components/device_activity/churn_active_status.h
new file mode 100644
index 0000000..70d0de8
--- /dev/null
+++ b/chromeos/ash/components/device_activity/churn_active_status.h
@@ -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.
+
+#ifndef CHROMEOS_ASH_COMPONENTS_DEVICE_ACTIVITY_CHURN_ACTIVE_STATUS_H_
+#define CHROMEOS_ASH_COMPONENTS_DEVICE_ACTIVITY_CHURN_ACTIVE_STATUS_H_
+
+#include <bitset>
+
+#include "base/component_export.h"
+
+namespace ash::device_activity {
+
+// The Churn use case maintains an instance of this class to represent
+// which of the past 18 months the device was active.
+class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DEVICE_ACTIVITY)
+    ChurnActiveStatus {
+ public:
+  // First 10 bits represent number months from 01/01/2000 to the current month.
+  // Remaining 18 bits represents past 18 months when device was active from
+  // current month.
+  static constexpr int kChurnBitSize = 28;
+
+  ChurnActiveStatus();
+  explicit ChurnActiveStatus(int value);
+  ChurnActiveStatus(const ChurnActiveStatus&) = delete;
+  ChurnActiveStatus& operator=(const ChurnActiveStatus&) = delete;
+  ~ChurnActiveStatus();
+
+  int GetValueAsInt() const;
+
+ private:
+  std::bitset<kChurnBitSize> value_;
+};
+
+}  // namespace ash::device_activity
+
+#endif  // CHROMEOS_ASH_COMPONENTS_DEVICE_ACTIVITY_CHURN_ACTIVE_STATUS_H_
diff --git a/chromeos/ash/components/device_activity/daily_use_case_impl.cc b/chromeos/ash/components/device_activity/daily_use_case_impl.cc
index 5b94a981..7ccceec 100644
--- a/chromeos/ash/components/device_activity/daily_use_case_impl.cc
+++ b/chromeos/ash/components/device_activity/daily_use_case_impl.cc
@@ -64,4 +64,18 @@
   return base::FeatureList::IsEnabled(
       features::kDeviceActiveClientDailyCheckMembership);
 }
+
+private_computing::ActiveStatus DailyUseCaseImpl::GenerateActiveStatus() {
+  private_computing::ActiveStatus status;
+
+  status.set_use_case(
+      private_computing::PrivateComputingUseCase::CROS_FRESNEL_DAILY);
+
+  std::string last_ping_pt_date =
+      FormatPTDateString(GetLastKnownPingTimestamp());
+  status.set_last_ping_date(last_ping_pt_date);
+
+  return status;
+}
+
 }  // namespace ash::device_activity
diff --git a/chromeos/ash/components/device_activity/daily_use_case_impl.h b/chromeos/ash/components/device_activity/daily_use_case_impl.h
index 1bc5ee6..01ec99d 100644
--- a/chromeos/ash/components/device_activity/daily_use_case_impl.h
+++ b/chromeos/ash/components/device_activity/daily_use_case_impl.h
@@ -42,6 +42,7 @@
  // Whether current device active use case check membership is enabled or not.
   bool IsEnabledCheckMembership() override;
 
+  private_computing::ActiveStatus GenerateActiveStatus() override;
 };
 
 }  // namespace ash::device_activity
diff --git a/chromeos/ash/components/device_activity/device_active_use_case.h b/chromeos/ash/components/device_activity/device_active_use_case.h
index 91ff78e..c0bf8aca 100644
--- a/chromeos/ash/components/device_activity/device_active_use_case.h
+++ b/chromeos/ash/components/device_activity/device_active_use_case.h
@@ -10,6 +10,7 @@
 
 #include "base/component_export.h"
 #include "base/time/time.h"
+#include "chromeos/ash/components/dbus/private_computing/private_computing_service.pb.h"
 #include "chromeos/ash/components/device_activity/fresnel_service.pb.h"
 #include "third_party/private_membership/src/private_membership_rlwe_client.h"
 
@@ -78,6 +79,9 @@
   // Whether current device active use case check membership is enabled or not.
   virtual bool IsEnabledCheckMembership() = 0;
 
+  // Generate status storing the last ping pacific date.
+  virtual private_computing::ActiveStatus GenerateActiveStatus() = 0;
+
   // Method used to reset the non constant saved state of the device active use
   // case. The state should be cleared after reporting device actives.
   void ClearSavedState();
diff --git a/chromeos/ash/components/device_activity/device_activity_client.cc b/chromeos/ash/components/device_activity/device_activity_client.cc
index e1c21a6..41bf58d7 100644
--- a/chromeos/ash/components/device_activity/device_activity_client.cc
+++ b/chromeos/ash/components/device_activity/device_activity_client.cc
@@ -365,30 +365,7 @@
   private_computing::SaveStatusRequest request;
 
   for (auto* use_case : GetUseCases()) {
-    private_computing::ActiveStatus status;
-
-    // TODO: Before submission, check handling a last known ts that is
-    // unset / unix::epoch.
-    std::string last_ping_pt_date =
-        use_case->FormatPTDateString(use_case->GetLastKnownPingTimestamp());
-
-    psm_rlwe::RlweUseCase psm_use_case = use_case->GetPsmUseCase();
-    switch (psm_use_case) {
-      case psm_rlwe::RlweUseCase::CROS_FRESNEL_DAILY:
-        status.set_use_case(
-            private_computing::PrivateComputingUseCase::CROS_FRESNEL_DAILY);
-        status.set_last_ping_date(last_ping_pt_date);
-        break;
-      case psm_rlwe::RlweUseCase::CROS_FRESNEL_28DAY_ACTIVE:
-        status.set_use_case(private_computing::PrivateComputingUseCase::
-                                CROS_FRESNEL_28DAY_ACTIVE);
-        status.set_last_ping_date(last_ping_pt_date);
-        break;
-      default:
-        VLOG(1) << "Use case is not supported yet. "
-                << psm_rlwe::RlweUseCase_Name(use_case->GetPsmUseCase());
-        break;
-    }
+    private_computing::ActiveStatus status = use_case->GenerateActiveStatus();
 
     if (status.has_use_case()) {
       *request.add_active_status() = status;
@@ -532,6 +509,16 @@
   DefaultNetworkChanged(network_state_handler_->DefaultNetwork());
 }
 
+ChurnActiveStatus* DeviceActivityClient::GetChurnActiveStatus() {
+  DCHECK(churn_active_status_);
+  return churn_active_status_.get();
+}
+
+void DeviceActivityClient::SetChurnActiveStatus(int value) {
+  DCHECK(!churn_active_status_);
+  churn_active_status_ = std::make_unique<ChurnActiveStatus>(value);
+}
+
 void DeviceActivityClient::ReportingTriggeredByTimer() {
   RecordDeviceActivityMethodCalled(
       DeviceActivityClient::DeviceActivityMethod::
diff --git a/chromeos/ash/components/device_activity/device_activity_client.h b/chromeos/ash/components/device_activity/device_activity_client.h
index a39f50e..21a40ae 100644
--- a/chromeos/ash/components/device_activity/device_activity_client.h
+++ b/chromeos/ash/components/device_activity/device_activity_client.h
@@ -16,6 +16,7 @@
 #include "base/timer/timer.h"
 #include "chromeos/ash/components/dbus/private_computing/private_computing_client.h"
 #include "chromeos/ash/components/dbus/private_computing/private_computing_service.pb.h"
+#include "chromeos/ash/components/device_activity/churn_active_status.h"
 #include "chromeos/ash/components/device_activity/fresnel_service.pb.h"
 #include "chromeos/ash/components/network/network_state_handler_observer.h"
 #include "third_party/private_membership/src/private_membership_rlwe_client.h"
@@ -180,6 +181,13 @@
   void OnGetLastPingDatesStatusFetched(
       private_computing::GetStatusResponse response);
 
+  // Get the |churn_active_status_| object.
+  ChurnActiveStatus* GetChurnActiveStatus();
+
+  // Set the |churn_active_status_| object with the newest value from either
+  // local state or the preserved files.
+  void SetChurnActiveStatus(int value);
+
  private:
   // |report_timer_| triggers method to retry reporting device actives if
   // necessary.
@@ -300,6 +308,10 @@
   // the chrome-internal repository and is not publicly exposed in Chromium.
   const std::string api_key_;
 
+  // ChurnActiveStatus object stores the active history for the device.
+  // This bit value will be persisted in local state and preserved files.
+  std::unique_ptr<ChurnActiveStatus> churn_active_status_;
+
   // Vector of supported use cases containing the methods and metadata required
   // to counting device actives.
   const std::vector<std::unique_ptr<DeviceActiveUseCase>> use_cases_;
diff --git a/chromeos/ash/components/device_activity/twenty_eight_day_active_use_case_impl.cc b/chromeos/ash/components/device_activity/twenty_eight_day_active_use_case_impl.cc
index f7f83f0..df529af5 100644
--- a/chromeos/ash/components/device_activity/twenty_eight_day_active_use_case_impl.cc
+++ b/chromeos/ash/components/device_activity/twenty_eight_day_active_use_case_impl.cc
@@ -77,6 +77,20 @@
       features::kDeviceActiveClient28DayActiveCheckMembership);
 }
 
+private_computing::ActiveStatus
+TwentyEightDayActiveUseCaseImpl::GenerateActiveStatus() {
+  private_computing::ActiveStatus status;
+
+  status.set_use_case(
+      private_computing::PrivateComputingUseCase::CROS_FRESNEL_28DAY_ACTIVE);
+
+  std::string last_ping_pt_date =
+      FormatPTDateString(GetLastKnownPingTimestamp());
+  status.set_last_ping_date(last_ping_pt_date);
+
+  return status;
+}
+
 bool TwentyEightDayActiveUseCaseImpl::SavePsmIdToDateMap(base::Time cur_ts) {
   // Generate |kRollingWindowSize| days of PSM identifiers to search.
   std::unordered_map<std::string, base::Time> psm_id_to_date_temp;
diff --git a/chromeos/ash/components/device_activity/twenty_eight_day_active_use_case_impl.h b/chromeos/ash/components/device_activity/twenty_eight_day_active_use_case_impl.h
index 38c6b27..ac88ba79 100644
--- a/chromeos/ash/components/device_activity/twenty_eight_day_active_use_case_impl.h
+++ b/chromeos/ash/components/device_activity/twenty_eight_day_active_use_case_impl.h
@@ -38,6 +38,7 @@
 
   // DeviceActiveUseCase:
   FresnelImportDataRequest GenerateImportRequestBody() override;
+  private_computing::ActiveStatus GenerateActiveStatus() override;
 
   // Whether current device active use case check-in is enabled or not.
   bool IsEnabledCheckIn() override;
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
index c862e4be..0e2f574b 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
+++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
@@ -283,14 +283,13 @@
   case SetupStage::k##s: \
     return out << #s;
     PRINT(NotStarted)
-    PRINT(CalculatingFreeSpace)
-    PRINT(CalculatingRequiredSpace)
+    PRINT(GettingFreeSpace)
+    PRINT(ListingFiles)
     PRINT(Syncing)
     PRINT(Success)
-    PRINT(Disabled)
     PRINT(Stopped)
-    PRINT(CannotCalculateFreeSpace)
-    PRINT(CannotRetrieveSearchResults)
+    PRINT(CannotGetFreeSpace)
+    PRINT(CannotListFiles)
     PRINT(NotEnoughSpace)
 #undef PRINT
   }
@@ -299,6 +298,10 @@
              << static_cast<std::underlying_type_t<SetupStage>>(stage) << ")";
 }
 
+SetupProgress::SetupProgress() = default;
+SetupProgress::SetupProgress(const SetupProgress&) = default;
+SetupProgress& SetupProgress::operator=(const SetupProgress&) = default;
+
 // TODO(b/261530666): This was chosen arbitrarily, this should be experimented
 // with and potentially made dynamic depending on feedback of the in progress
 // queue.
@@ -323,8 +326,10 @@
 
   VLOG(3) << "Added " << id << " " << Quote(path) << " with size "
           << HumanReadableSize(size) << " to the files to pin";
-  progress_.total_bytes += size;
+  progress_.bytes_to_pin += size;
   progress_.required_space += RoundToBlockSize(size);
+  progress_.files_to_pin++;
+  DCHECK_EQ(static_cast<size_t>(progress_.files_to_pin), files_to_pin_.size());
   return true;
 }
 
@@ -352,7 +357,7 @@
                << HumanReadableSize(progress.total) << " instead of "
                << HumanReadableSize(bytes_transferred) << " for " << id << " "
                << Quote(path);
-    progress_.total_bytes += bytes_transferred - progress.total;
+    progress_.bytes_to_pin += bytes_transferred - progress.total;
     progress_.required_space +=
         RoundToBlockSize(bytes_transferred) - RoundToBlockSize(progress.total);
   }
@@ -362,7 +367,7 @@
       << HumanReadableSize(progress.transferred) << " to "
       << HumanReadableSize(bytes_transferred) << " for " << id << " "
       << Quote(path);
-  progress_.transferred_bytes += bytes_transferred - progress.transferred;
+  progress_.pinned_bytes += bytes_transferred - progress.transferred;
 
   VLOG(3) << "Stopped tracking " << id << " " << Quote(path);
   return true;
@@ -408,14 +413,14 @@
       << HumanReadableSize(progress.transferred) << " to "
       << HumanReadableSize(transferred) << " for " << id << " " << Quote(path);
 
-  progress_.transferred_bytes += transferred - progress.transferred;
+  progress_.pinned_bytes += transferred - progress.transferred;
   progress.transferred = transferred;
 
   if (total != progress.total) {
     LOG(ERROR) << "Changed expected size of " << id << " " << Quote(path)
                << " from " << HumanReadableSize(progress.total) << " to "
                << HumanReadableSize(total);
-    progress_.total_bytes += total - progress.total;
+    progress_.bytes_to_pin += total - progress.total;
     progress_.required_space +=
         RoundToBlockSize(total) - RoundToBlockSize(progress.total);
     progress.total = total;
@@ -469,6 +474,7 @@
   for (Observer& observer : observers_) {
     observer.OnDrop();
   }
+  observers_.Clear();
 }
 
 void DriveFsPinManager::Start() {
@@ -481,7 +487,7 @@
 
   VLOG(1) << "Calculating free space...";
   timer_ = base::ElapsedTimer();
-  progress_.stage = SetupStage::kCalculatingFreeSpace;
+  progress_.stage = SetupStage::kGettingFreeSpace;
   NotifyProgress();
 
   space_getter_.Run(
@@ -520,7 +526,7 @@
 
   if (free_space < 0) {
     LOG(ERROR) << "Cannot calculate free space";
-    return Complete(SetupStage::kCannotCalculateFreeSpace);
+    return Complete(SetupStage::kCannotGetFreeSpace);
   }
 
   progress_.free_space = free_space;
@@ -529,7 +535,7 @@
 
   VLOG(1) << "Calculating required space...";
   timer_ = base::ElapsedTimer();
-  progress_.stage = SetupStage::kCalculatingRequiredSpace;
+  progress_.stage = SetupStage::kListingFiles;
   NotifyProgress();
 
   drivefs_->StartSearchQuery(search_query_.BindNewPipeAndPassReceiver(),
@@ -545,7 +551,7 @@
 
   if (error != drive::FILE_ERROR_OK || !items) {
     LOG(ERROR) << "Cannot list files: " << error;
-    return Complete(SetupStage::kCannotRetrieveSearchResults);
+    return Complete(SetupStage::kCannotListFiles);
   }
 
   if (items->empty()) {
@@ -587,10 +593,10 @@
   progress_.stage = stage;
   switch (stage) {
     case SetupStage::kSuccess:
-      LOG_IF(ERROR, progress_.errors > 0)
-          << "Failed to pin " << progress_.errors << " files";
+      LOG_IF(ERROR, progress_.failed_files > 0)
+          << "Failed to pin " << progress_.failed_files << " files";
       VLOG(1) << "Pinned " << progress_.pinned_files << " files and downloaded "
-              << HumanReadableSize(progress_.transferred_bytes) << " in "
+              << HumanReadableSize(progress_.pinned_bytes) << " in "
               << timer_.Elapsed().InMilliseconds() << " ms";
       VLOG(2) << "Useful events: " << progress_.useful_events;
       VLOG(2) << "Duplicated events: " << progress_.duplicated_events;
@@ -625,7 +631,7 @@
 
   VLOG(1) << "Free space: " << HumanReadableSize(progress_.free_space);
   VLOG(1) << "Required space: " << HumanReadableSize(progress_.required_space);
-  VLOG(1) << "To download: " << HumanReadableSize(progress_.total_bytes);
+  VLOG(1) << "To download: " << HumanReadableSize(progress_.bytes_to_pin);
   VLOG(1) << "To pin: " << files_to_pin_.size() << " files";
   VLOG(1) << "To track: " << files_to_track_.size() << " files";
 
@@ -695,8 +701,8 @@
   }
 
   VLOG(1) << "Progress "
-          << Percentage(progress_.transferred_bytes, progress_.total_bytes)
-          << "%: synced " << HumanReadableSize(progress_.transferred_bytes)
+          << Percentage(progress_.pinned_bytes, progress_.bytes_to_pin)
+          << "%: synced " << HumanReadableSize(progress_.pinned_bytes)
           << " and " << progress_.pinned_files << " files, syncing "
           << files_to_track_.size() << " files";
 }
@@ -709,7 +715,7 @@
   if (status != drive::FILE_ERROR_OK) {
     LOG(ERROR) << "Cannot pin " << id << " " << Quote(path) << ": " << status;
     if (Remove(id, path, 0)) {
-      progress_.errors++;
+      progress_.failed_files++;
       NotifyProgress();
       PinSomeFiles();
     }
@@ -765,7 +771,7 @@
         if (Remove(id, event->path, 0)) {
           LOG(ERROR) << "Cannot sync " << id << " " << Quote(event->path)
                      << ": " << Quote(*event);
-          progress_.errors++;
+          progress_.failed_files++;
           progress_.useful_events++;
           NotifyProgress();
         } else {
@@ -896,7 +902,7 @@
     }
 
     VLOG(1) << "Stopped tracking " << id << " " << Quote(path);
-    progress_.errors++;
+    progress_.failed_files++;
     NotifyProgress();
     PinSomeFiles();
     return;
@@ -914,7 +920,7 @@
     }
 
     LOG(ERROR) << "Got unexpectedly unpinned: " << id << " " << Quote(path);
-    progress_.errors++;
+    progress_.failed_files++;
     NotifyProgress();
     PinSomeFiles();
     return;
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.h b/chromeos/ash/components/drivefs/drivefs_pin_manager.h
index 8c6244aad..2547830 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager.h
+++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.h
@@ -46,18 +46,17 @@
   kNotStarted,
 
   // In-progress stages.
-  kCalculatingFreeSpace,
-  kCalculatingRequiredSpace,
+  kGettingFreeSpace,
+  kListingFiles,
   kSyncing,
 
   // Final success stage.
   kSuccess,
 
   // Final error stages.
-  kDisabled,
   kStopped,
-  kCannotCalculateFreeSpace,
-  kCannotRetrieveSearchResults,
+  kCannotGetFreeSpace,
+  kCannotListFiles,
   kNotEnoughSpace,
 };
 
@@ -66,7 +65,7 @@
 
 // When the manager is setting up, this struct maintains all the information
 // gathered.
-struct SetupProgress {
+struct COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS) SetupProgress {
   // Number of free bytes on the stateful partition. Estimated at the beginning
   // of the setup process and left unchanged afterwards.
   int64_t free_space = 0;
@@ -80,16 +79,19 @@
   // Estimated number of bytes that are required to download the files to pin.
   // Estimated at the beginning of the setup process and updated if necessary
   // afterwards.
-  int64_t total_bytes = 0;
+  int64_t bytes_to_pin = 0;
 
   // Number of bytes that have been downloaded so far.
-  int64_t transferred_bytes = 0;
+  int64_t pinned_bytes = 0;
+
+  // Total number of files to pin.
+  int32_t files_to_pin = 0;
 
   // Number of pinned and downloaded files so far.
   int32_t pinned_files = 0;
 
   // Number of errors encountered so far.
-  int32_t errors = 0;
+  int32_t failed_files = 0;
 
   // Number of "useful" (ie non-duplicated) events received from DriveFS so far.
   int32_t useful_events = 0;
@@ -99,6 +101,10 @@
 
   // Stage of the setup process.
   SetupStage stage = SetupStage::kNotStarted;
+
+  SetupProgress();
+  SetupProgress(const SetupProgress&);
+  SetupProgress& operator=(const SetupProgress&);
 };
 
 // Manages bulk pinning of items via DriveFS. This class handles the following:
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc b/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
index c1416c4f..4bf21be 100644
--- a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
+++ b/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
@@ -165,6 +165,12 @@
               (const base::FilePath&, DriveFsPinManager::SpaceResult));
 };
 
+class MockObserver : public DriveFsPinManager::Observer {
+ public:
+  MOCK_METHOD(void, OnProgress, (const SetupProgress&), (override));
+  MOCK_METHOD(void, OnDrop, (), (override));
+};
+
 }  // namespace
 
 class DriveFsPinManagerTest : public testing::Test {
@@ -231,8 +237,8 @@
   {
     const SetupProgress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
-    EXPECT_EQ(progress.transferred_bytes, 0);
-    EXPECT_EQ(progress.total_bytes, 0);
+    EXPECT_EQ(progress.pinned_bytes, 0);
+    EXPECT_EQ(progress.bytes_to_pin, 0);
     EXPECT_EQ(progress.required_space, 0);
   }
 
@@ -273,8 +279,8 @@
   {
     const SetupProgress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
-    EXPECT_EQ(progress.transferred_bytes, 0);
-    EXPECT_EQ(progress.total_bytes, size1);
+    EXPECT_EQ(progress.pinned_bytes, 0);
+    EXPECT_EQ(progress.bytes_to_pin, size1);
     EXPECT_EQ(progress.required_space, 698249216);
   }
 
@@ -297,8 +303,8 @@
   {
     const SetupProgress progress = manager.GetProgress();
     EXPECT_EQ(progress.pinned_files, 0);
-    EXPECT_EQ(progress.transferred_bytes, 0);
-    EXPECT_EQ(progress.total_bytes, size1 + size2);
+    EXPECT_EQ(progress.pinned_bytes, 0);
+    EXPECT_EQ(progress.bytes_to_pin, size1 + size2);
     EXPECT_EQ(progress.required_space, 777216000);
   }
 }
@@ -310,7 +316,7 @@
 
   EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(0);
   EXPECT_CALL(mock_drivefs_, OnGetNextPage(_)).Times(0);
-  EXPECT_CALL(mock_callback, Run(SetupStage::kCannotCalculateFreeSpace))
+  EXPECT_CALL(mock_callback, Run(SetupStage::kCannotGetFreeSpace))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
   EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(-1));
@@ -322,10 +328,10 @@
   run_loop.Run();
 
   const SetupProgress progress = manager.GetProgress();
-  EXPECT_EQ(progress.stage, SetupStage::kCannotCalculateFreeSpace);
+  EXPECT_EQ(progress.stage, SetupStage::kCannotGetFreeSpace);
   EXPECT_EQ(progress.free_space, 0);
   EXPECT_EQ(progress.required_space, 0);
-  EXPECT_EQ(progress.transferred_bytes, 0);
+  EXPECT_EQ(progress.pinned_bytes, 0);
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
@@ -338,7 +344,7 @@
   EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
       .WillOnce(DoAll(PopulateNoSearchItems(),
                       Return(drive::FileError::FILE_ERROR_FAILED)));
-  EXPECT_CALL(mock_callback, Run(SetupStage::kCannotRetrieveSearchResults))
+  EXPECT_CALL(mock_callback, Run(SetupStage::kCannotListFiles))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
   EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
@@ -350,10 +356,10 @@
   run_loop.Run();
 
   const SetupProgress progress = manager.GetProgress();
-  EXPECT_EQ(progress.stage, SetupStage::kCannotRetrieveSearchResults);
+  EXPECT_EQ(progress.stage, SetupStage::kCannotListFiles);
   EXPECT_EQ(progress.free_space, 1 << 30);
   EXPECT_EQ(progress.required_space, 0);
-  EXPECT_EQ(progress.transferred_bytes, 0);
+  EXPECT_EQ(progress.pinned_bytes, 0);
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
@@ -365,7 +371,7 @@
   EXPECT_CALL(mock_drivefs_, OnStartSearchQuery(_)).Times(1);
   EXPECT_CALL(mock_drivefs_, OnGetNextPage(_))
       .WillOnce(Return(drive::FileError::FILE_ERROR_OK));
-  EXPECT_CALL(mock_callback, Run(SetupStage::kCannotRetrieveSearchResults))
+  EXPECT_CALL(mock_callback, Run(SetupStage::kCannotListFiles))
       .WillOnce(RunClosure(run_loop.QuitClosure()));
   EXPECT_CALL(mock_free_space_, GetFreeSpace(gcache_dir_, _))
       .WillOnce(RunOnceCallback<1>(1 << 30));  // 1 GB.
@@ -377,10 +383,10 @@
   run_loop.Run();
 
   const SetupProgress progress = manager.GetProgress();
-  EXPECT_EQ(progress.stage, SetupStage::kCannotRetrieveSearchResults);
+  EXPECT_EQ(progress.stage, SetupStage::kCannotListFiles);
   EXPECT_EQ(progress.free_space, 1 << 30);
   EXPECT_EQ(progress.required_space, 0);
-  EXPECT_EQ(progress.transferred_bytes, 0);
+  EXPECT_EQ(progress.pinned_bytes, 0);
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
@@ -415,7 +421,7 @@
   EXPECT_EQ(progress.stage, SetupStage::kNotEnoughSpace);
   EXPECT_EQ(progress.free_space, 1 << 30);
   EXPECT_EQ(progress.required_space, (512 << 20) + (4 << 10));
-  EXPECT_EQ(progress.transferred_bytes, 0);
+  EXPECT_EQ(progress.pinned_bytes, 0);
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
@@ -451,7 +457,7 @@
   EXPECT_EQ(progress.stage, SetupStage::kSuccess);
   EXPECT_EQ(progress.free_space, 1 << 30);
   EXPECT_EQ(progress.required_space, 512 << 20);
-  EXPECT_EQ(progress.transferred_bytes, 0);
+  EXPECT_EQ(progress.pinned_bytes, 0);
   EXPECT_EQ(progress.pinned_files, 0);
 }
 
@@ -648,17 +654,21 @@
   new_run_loop.Run();
 }
 
-class TestBulkPinObserver : public DriveFsPinManager::Observer {
- public:
-  TestBulkPinObserver() = default;
-
-  TestBulkPinObserver(const TestBulkPinObserver&) = delete;
-  TestBulkPinObserver& operator=(const TestBulkPinObserver&) = delete;
-
-  ~TestBulkPinObserver() override = default;
-
-  MOCK_METHOD(void, OnProgress, (const SetupProgress&), (override));
-};
+TEST_F(DriveFsPinManagerTest, OnDrop) {
+  {
+    MockObserver observer;
+    DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+    manager.AddObserver(&observer);
+    EXPECT_CALL(observer, OnDrop()).Times(1);
+  }
+  {
+    MockObserver observer;
+    EXPECT_CALL(observer, OnDrop()).Times(0);
+    DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
+    manager.AddObserver(&observer);
+    manager.RemoveObserver(&observer);
+  }
+}
 
 TEST_F(DriveFsPinManagerTest,
        DISABLED_SyncingStatusUpdateProgressIsReportedBackToObserver) {
@@ -694,12 +704,12 @@
             run_loop.QuitClosure().Run();
           });
 
-  TestBulkPinObserver mock_pin_observer;
-  EXPECT_CALL(mock_pin_observer, OnProgress(_)).Times(AnyNumber());
+  MockObserver observer;
+  EXPECT_CALL(observer, OnProgress(_)).Times(AnyNumber());
 
   DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_);
   manager.SetSpaceGetter(GetSpaceGetter());
-  manager.AddObserver(&mock_pin_observer);
+  manager.AddObserver(&observer);
   manager.SetCompletionCallback(mock_callback.Get());
   manager.Start();
   run_loop.Run();
@@ -714,8 +724,8 @@
   SetState(status->item_events, mojom::ItemEvent::State::kInProgress);
   status->item_events.at(0)->bytes_transferred = 10;
   EXPECT_CALL(
-      mock_pin_observer,
-      OnProgress(AllOf(Field(&SetupProgress::transferred_bytes, 10),
+      observer,
+      OnProgress(AllOf(Field(&SetupProgress::pinned_bytes, 10),
                        Field(&SetupProgress::stage, SetupStage::kSyncing))))
       .Times(1)
       .WillOnce(RunClosure(setup_progress_run_loop.QuitClosure()));
@@ -738,8 +748,8 @@
   SetState(status->item_events, mojom::ItemEvent::State::kCompleted);
   status->item_events.at(0)->bytes_transferred = 128;
   EXPECT_CALL(
-      mock_pin_observer,
-      OnProgress(AllOf(Field(&SetupProgress::transferred_bytes, 128),
+      observer,
+      OnProgress(AllOf(Field(&SetupProgress::pinned_bytes, 128),
                        Field(&SetupProgress::stage, SetupStage::kSuccess))))
       .Times(1)
       .WillOnce(RunClosure(setup_progress_run_loop.QuitClosure()));
diff --git a/chromeos/ash/components/phonehub/fake_message_receiver.h b/chromeos/ash/components/phonehub/fake_message_receiver.h
index 0bb4121..363b8813 100644
--- a/chromeos/ash/components/phonehub/fake_message_receiver.h
+++ b/chromeos/ash/components/phonehub/fake_message_receiver.h
@@ -16,6 +16,7 @@
   FakeMessageReceiver() = default;
   ~FakeMessageReceiver() override = default;
 
+  using MessageReceiver::NotifyAppListIncrementalUpdateReceived;
   using MessageReceiver::NotifyAppListUpdateReceived;
   using MessageReceiver::NotifyAppStreamUpdateReceived;
   using MessageReceiver::NotifyFeatureSetupResponseReceived;
diff --git a/chromeos/ash/components/phonehub/message_receiver.cc b/chromeos/ash/components/phonehub/message_receiver.cc
index 94e3f8b..d2b4fc9 100644
--- a/chromeos/ash/components/phonehub/message_receiver.cc
+++ b/chromeos/ash/components/phonehub/message_receiver.cc
@@ -67,5 +67,12 @@
     observer.OnAppListUpdateReceived(app_list_update);
 }
 
+void MessageReceiver::NotifyAppListIncrementalUpdateReceived(
+    const proto::AppListIncrementalUpdate app_list_incremental_update) {
+  for (auto& observer : observer_list_) {
+    observer.OnAppListIncrementalUpdateReceived(app_list_incremental_update);
+  }
+}
+
 }  // namespace phonehub
 }  // namespace ash
diff --git a/chromeos/ash/components/phonehub/message_receiver.h b/chromeos/ash/components/phonehub/message_receiver.h
index a20cab8..7bbdb01 100644
--- a/chromeos/ash/components/phonehub/message_receiver.h
+++ b/chromeos/ash/components/phonehub/message_receiver.h
@@ -55,6 +55,11 @@
     // Called when there is an update of streamable apps.
     virtual void OnAppListUpdateReceived(
         const proto::AppListUpdate app_list_update) {}
+
+    // Called when there is an incremental update to apps list, i.e. app added
+    // and app removal.
+    virtual void OnAppListIncrementalUpdateReceived(
+        const proto::AppListIncrementalUpdate app_list_incremental_update) {}
   };
 
   MessageReceiver(const MessageReceiver&) = delete;
@@ -80,6 +85,8 @@
   void NotifyAppStreamUpdateReceived(
       const proto::AppStreamUpdate app_stream_update);
   void NotifyAppListUpdateReceived(const proto::AppListUpdate app_list_update);
+  void NotifyAppListIncrementalUpdateReceived(
+      const proto::AppListIncrementalUpdate app_list_incremental_update);
 
  private:
   base::ObserverList<Observer> observer_list_;
diff --git a/chromeos/ash/components/phonehub/message_receiver_impl.cc b/chromeos/ash/components/phonehub/message_receiver_impl.cc
index d905a0cb..7f116c6 100644
--- a/chromeos/ash/components/phonehub/message_receiver_impl.cc
+++ b/chromeos/ash/components/phonehub/message_receiver_impl.cc
@@ -46,6 +46,8 @@
       return "PING_RESPONSE";
     case proto::MessageType::APP_STREAM_UPDATE:
       return "APP_STREAM_UPDATE";
+    case proto::MessageType::APP_LIST_INCREMENTAL_UPDATE:
+      return "APP_LIST_INCREMENTAL_UPDATE";
     default:
       return "UNKOWN_MESSAGE";
   }
@@ -176,6 +178,18 @@
     NotifyAppListUpdateReceived(app_list_update);
     return;
   }
+
+  if (features::IsEcheSWAEnabled() &&
+      message_type == proto::MessageType::APP_LIST_INCREMENTAL_UPDATE) {
+    proto::AppListIncrementalUpdate app_list_incrementalUpdate;
+    if (!app_list_incrementalUpdate.ParseFromString(payload.substr(2))) {
+      PA_LOG(ERROR) << "OnMessageReceived() could not deserialize the "
+                    << "AppListIncrementalUpdate proto message.";
+      return;
+    }
+    NotifyAppListIncrementalUpdateReceived(app_list_incrementalUpdate);
+    return;
+  }
 }
 
 }  // namespace phonehub
diff --git a/chromeos/ash/components/phonehub/message_receiver_unittest.cc b/chromeos/ash/components/phonehub/message_receiver_unittest.cc
index 4465fef..bfa6679 100644
--- a/chromeos/ash/components/phonehub/message_receiver_unittest.cc
+++ b/chromeos/ash/components/phonehub/message_receiver_unittest.cc
@@ -50,6 +50,10 @@
 
   size_t app_list_update_calls() const { return app_list_update_calls_; }
 
+  size_t app_list_incremental_update_calls() const {
+    return app_list_incremental_update_calls_;
+  }
+
   proto::PhoneStatusSnapshot last_snapshot() const { return last_snapshot_; }
 
   proto::PhoneStatusUpdate last_status_update() const {
@@ -68,6 +72,10 @@
     return last_app_list_update_;
   }
 
+  proto::AppListIncrementalUpdate last_app_list_incremental_update() const {
+    return last_app_list_incremental_update_;
+  }
+
   proto::FetchCameraRollItemsResponse last_fetch_camera_roll_items_response()
       const {
     return last_fetch_camera_roll_items_response_;
@@ -122,6 +130,12 @@
     ++app_list_update_calls_;
   }
 
+  void OnAppListIncrementalUpdateReceived(
+      proto::AppListIncrementalUpdate app_list_incremental_update) override {
+    last_app_list_incremental_update_ = app_list_incremental_update;
+    ++app_list_incremental_update_calls_;
+  }
+
  private:
   size_t phone_status_snapshot_updated_num_calls_ = 0;
   size_t phone_status_updated_num_calls_ = 0;
@@ -131,11 +145,13 @@
   size_t ping_response_num_calls_ = 0;
   size_t app_stream_update_calls_ = 0;
   size_t app_list_update_calls_ = 0;
+  size_t app_list_incremental_update_calls_ = 0;
   proto::PhoneStatusSnapshot last_snapshot_;
   proto::PhoneStatusUpdate last_status_update_;
   proto::FeatureSetupResponse last_feature_setup_response_;
   proto::AppStreamUpdate last_app_stream_update_;
   proto::AppListUpdate last_app_list_update_;
+  proto::AppListIncrementalUpdate last_app_list_incremental_update_;
   proto::FetchCameraRollItemsResponse last_fetch_camera_roll_items_response_;
   proto::FetchCameraRollItemDataResponse
       last_fetch_camera_roll_item_data_response_;
@@ -206,6 +222,10 @@
     return fake_observer_.app_list_update_calls();
   }
 
+  size_t GetNumAppListIncrementalUpdateCalls() const {
+    return fake_observer_.app_list_incremental_update_calls();
+  }
+
   proto::PhoneStatusSnapshot GetLastSnapshot() const {
     return fake_observer_.last_snapshot();
   }
@@ -236,6 +256,10 @@
     return fake_observer_.last_app_list_update();
   }
 
+  proto::AppListIncrementalUpdate GetLastAppListIncrementalUpdate() const {
+    return fake_observer_.last_app_list_incremental_update();
+  }
+
   FakeObserver fake_observer_;
   std::unique_ptr<secure_channel::FakeConnectionManager>
       fake_connection_manager_;
@@ -559,5 +583,49 @@
   EXPECT_EQ(0u, GetNumAppListUpdateCalls());
 }
 
+TEST_F(MessageReceiverImplTest, OnAppListIncremenatlUpdateReceived) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kEcheSWA);
+
+  proto::AppListIncrementalUpdate expected_app_list_incremental_update;
+  auto* installed_app =
+      expected_app_list_incremental_update.mutable_installed_apps();
+  installed_app->add_apps();
+
+  // Simulate receiving a message.
+  const std::string expected_message =
+      SerializeMessage(proto::APP_LIST_INCREMENTAL_UPDATE,
+                       &expected_app_list_incremental_update);
+  fake_connection_manager_->NotifyMessageReceived(expected_message);
+
+  proto::AppListIncrementalUpdate actual_app_list_incremental_update =
+      GetLastAppListIncrementalUpdate();
+
+  EXPECT_EQ(1u, GetNumAppListIncrementalUpdateCalls());
+  EXPECT_TRUE(expected_app_list_incremental_update.has_installed_apps());
+  EXPECT_FALSE(expected_app_list_incremental_update.has_removed_apps());
+  EXPECT_EQ(1,
+            expected_app_list_incremental_update.installed_apps().apps_size());
+}
+
+TEST_F(MessageReceiverImplTest,
+       OnAppListIncremenatlUpdateReceivedFlagDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(features::kEcheSWA);
+
+  proto::AppListIncrementalUpdate expected_app_list_incremental_update;
+  auto* installed_app =
+      expected_app_list_incremental_update.mutable_installed_apps();
+  installed_app->add_apps();
+
+  // Simulate receiving a message.
+  const std::string expected_message =
+      SerializeMessage(proto::APP_LIST_INCREMENTAL_UPDATE,
+                       &expected_app_list_incremental_update);
+  fake_connection_manager_->NotifyMessageReceived(expected_message);
+
+  EXPECT_EQ(0u, GetNumAppListIncrementalUpdateCalls());
+}
+
 }  // namespace phonehub
 }  // namespace ash
diff --git a/chromeos/ash/components/phonehub/phone_status_processor.cc b/chromeos/ash/components/phonehub/phone_status_processor.cc
index a098fd2..a7ef8f1 100644
--- a/chromeos/ash/components/phonehub/phone_status_processor.cc
+++ b/chromeos/ash/components/phonehub/phone_status_processor.cc
@@ -203,8 +203,7 @@
 bool ShouldUpdateLauncher(
     PhoneStatusProcessor::AppListUpdateType app_list_update_type) {
   return app_list_update_type ==
-             PhoneStatusProcessor::AppListUpdateType::kOnlyLauncherApps ||
-         app_list_update_type == PhoneStatusProcessor::AppListUpdateType::kBoth;
+         PhoneStatusProcessor::AppListUpdateType::kOnlyLauncherApps;
 }
 
 }  // namespace
diff --git a/chromeos/ash/components/phonehub/phone_status_processor_unittest.cc b/chromeos/ash/components/phonehub/phone_status_processor_unittest.cc
index 0bd3ff36d..12b17e1d 100644
--- a/chromeos/ash/components/phonehub/phone_status_processor_unittest.cc
+++ b/chromeos/ash/components/phonehub/phone_status_processor_unittest.cc
@@ -505,6 +505,7 @@
   expected_snapshot.add_notifications();
   InitializeNotificationProto(expected_snapshot.mutable_notifications(0),
                               /*id=*/0u);
+
   auto* streamable_apps = expected_snapshot.mutable_streamable_apps();
   auto* app = streamable_apps->add_apps();
   app->set_package_name("pkg1");
@@ -522,6 +523,19 @@
   // Simulate receiving a proto message.
   fake_message_receiver_->NotifyPhoneStatusSnapshotReceived(expected_snapshot);
 
+  proto::AppListUpdate expected_all_apps;
+
+  auto* all_apps = expected_all_apps.mutable_all_apps();
+  auto* all_app1 = all_apps->add_apps();
+  all_app1->set_package_name("pkg1");
+  all_app1->set_visible_name("vis");
+
+  auto* all_app2 = all_apps->add_apps();
+  all_app2->set_package_name("pkg2");
+  all_app2->set_visible_name("a_vis");  // Test alphbetical sort.
+
+  fake_message_receiver_->NotifyAppListUpdateReceived(expected_all_apps);
+
   EXPECT_EQ(1u, fake_notification_manager_->num_notifications());
   EXPECT_EQ(base::UTF8ToUTF16(test_remote_device_.name()),
             *mutable_phone_model_->phone_name());
diff --git a/chromeos/ash/components/phonehub/proto/phonehub_api.proto b/chromeos/ash/components/phonehub/proto/phonehub_api.proto
index e2b78044..12464d3 100644
--- a/chromeos/ash/components/phonehub/proto/phonehub_api.proto
+++ b/chromeos/ash/components/phonehub/proto/phonehub_api.proto
@@ -43,6 +43,7 @@
   PING_RESPONSE = 27;
   APP_STREAM_UPDATE = 28;
   APP_LIST_UPDATE = 29;
+  APP_LIST_INCREMENTAL_UPDATE = 30;
 }
 
 enum NotificationSetting {
@@ -410,6 +411,13 @@
   optional StreamableApps recent_apps = 2;
 }
 
+message AppListIncrementalUpdate {
+  // For removed apps, only package_names and user_ids are populated in the
+  // apps.
+  optional StreamableApps removed_apps = 3;
+  optional StreamableApps installed_apps = 4;
+}
+
 // When adding new fields to this message, update CameraRollItem#operator==
 // Located in chromeos/ash/components/phonehub/camera_roll_item.cc.
 message CameraRollItemMetadata {
diff --git a/chromeos/ash/components/phonehub/recent_apps_interaction_handler_impl.cc b/chromeos/ash/components/phonehub/recent_apps_interaction_handler_impl.cc
index 833b1a8..2429896 100644
--- a/chromeos/ash/components/phonehub/recent_apps_interaction_handler_impl.cc
+++ b/chromeos/ash/components/phonehub/recent_apps_interaction_handler_impl.cc
@@ -33,7 +33,7 @@
 using FeatureStatesMap =
     multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap;
 
-const size_t kMaxMostRecentApps = 6;
+const size_t kMaxMostRecentApps = 5;
 const size_t kMaxSavedRecentApps = 10;
 
 // static
diff --git a/chromeos/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc b/chromeos/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc
index b862e24..1730af8 100644
--- a/chromeos/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc
+++ b/chromeos/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc
@@ -438,33 +438,21 @@
                                 /*icon_is_monochrome=*/true, expected_user_id5,
                                 proto::AppStreamabilityStatus::STREAMABLE);
 
-  const char16_t app_visible_name6[] = u"Fake App6";
-  const char package_name6[] = "com.fakeapp6";
-  const int64_t expected_user_id6 = 1;
-  auto app_metadata6 =
-      Notification::AppMetadata(app_visible_name6, package_name6, gfx::Image(),
-                                /*icon_color=*/absl::nullopt,
-                                /*icon_is_monochrome=*/true, expected_user_id6,
-                                proto::AppStreamabilityStatus::STREAMABLE);
-
   const base::Time next_two_hour = base::Time::Now() + base::Hours(2);
   const base::Time next_three_hour = base::Time::Now() + base::Hours(3);
-  const base::Time next_four_hour = base::Time::Now() + base::Hours(4);
 
   handler().NotifyRecentAppAddedOrUpdated(app_metadata4, next_two_hour);
   handler().NotifyRecentAppAddedOrUpdated(app_metadata5, next_three_hour);
-  handler().NotifyRecentAppAddedOrUpdated(app_metadata6, next_four_hour);
 
-  const size_t max_most_recent_apps = 6;
+  const size_t max_most_recent_apps = 5;
   recent_apps_metadata_result = handler().FetchRecentAppMetadataList();
   EXPECT_EQ(max_most_recent_apps, recent_apps_metadata_result.size());
 
-  EXPECT_EQ(package_name6, recent_apps_metadata_result[0].package_name);
-  EXPECT_EQ(package_name5, recent_apps_metadata_result[1].package_name);
-  EXPECT_EQ(package_name4, recent_apps_metadata_result[2].package_name);
-  EXPECT_EQ(package_name3, recent_apps_metadata_result[3].package_name);
-  EXPECT_EQ(package_name2, recent_apps_metadata_result[4].package_name);
-  EXPECT_EQ(package_name1, recent_apps_metadata_result[5].package_name);
+  EXPECT_EQ(package_name5, recent_apps_metadata_result[0].package_name);
+  EXPECT_EQ(package_name4, recent_apps_metadata_result[1].package_name);
+  EXPECT_EQ(package_name3, recent_apps_metadata_result[2].package_name);
+  EXPECT_EQ(package_name2, recent_apps_metadata_result[3].package_name);
+  EXPECT_EQ(package_name1, recent_apps_metadata_result[4].package_name);
 }
 
 TEST_F(RecentAppsInteractionHandlerTest,
diff --git a/chromeos/ash/components/standalone_browser/BUILD.gn b/chromeos/ash/components/standalone_browser/BUILD.gn
new file mode 100644
index 0000000..b573ceb
--- /dev/null
+++ b/chromeos/ash/components/standalone_browser/BUILD.gn
@@ -0,0 +1,17 @@
+# 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("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash,
+       "Non-Chrome-OS builds must not depend on //chromeos/ash")
+
+component("standalone_browser") {
+  defines = [ "IS_CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER_IMPL" ]
+  deps = [ "//base" ]
+  sources = [
+    "lacros_availability.cc",
+    "lacros_availability.h",
+  ]
+}
diff --git a/chromeos/ash/components/standalone_browser/OWNERS b/chromeos/ash/components/standalone_browser/OWNERS
new file mode 100644
index 0000000..71cc0b0
--- /dev/null
+++ b/chromeos/ash/components/standalone_browser/OWNERS
@@ -0,0 +1 @@
+file://chromeos/LACROS_OWNERS
diff --git a/chromeos/ash/components/standalone_browser/lacros_availability.cc b/chromeos/ash/components/standalone_browser/lacros_availability.cc
new file mode 100644
index 0000000..40c6e24a
--- /dev/null
+++ b/chromeos/ash/components/standalone_browser/lacros_availability.cc
@@ -0,0 +1,49 @@
+// 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/standalone_browser/lacros_availability.h"
+
+#include "base/containers/fixed_flat_map.h"
+#include "base/logging.h"
+#include "base/notreached.h"
+
+namespace ash::standalone_browser {
+namespace {
+
+// The conversion map for LacrosAvailability policy data. The values must match
+// the ones from LacrosAvailability.yaml.
+constexpr auto kLacrosAvailabilityMap =
+    base::MakeFixedFlatMap<base::StringPiece, LacrosAvailability>({
+        {"user_choice", LacrosAvailability::kUserChoice},
+        {"lacros_disallowed", LacrosAvailability::kLacrosDisallowed},
+        {"side_by_side", LacrosAvailability::kSideBySide},
+        {"lacros_primary", LacrosAvailability::kLacrosPrimary},
+        {"lacros_only", LacrosAvailability::kLacrosOnly},
+    });
+
+}  // namespace
+
+absl::optional<LacrosAvailability> ParseLacrosAvailability(
+    base::StringPiece value) {
+  auto* it = kLacrosAvailabilityMap.find(value);
+  if (it != kLacrosAvailabilityMap.end()) {
+    return it->second;
+  }
+
+  LOG(ERROR) << "Unknown LacrosAvailability policy value is passed: " << value;
+  return absl::nullopt;
+}
+
+base::StringPiece GetLacrosAvailabilityPolicyName(LacrosAvailability value) {
+  for (const auto& entry : kLacrosAvailabilityMap) {
+    if (entry.second == value) {
+      return entry.first;
+    }
+  }
+
+  NOTREACHED();
+  return base::StringPiece();
+}
+
+}  // namespace ash::standalone_browser
diff --git a/chromeos/ash/components/standalone_browser/lacros_availability.h b/chromeos/ash/components/standalone_browser/lacros_availability.h
new file mode 100644
index 0000000..de5949b
--- /dev/null
+++ b/chromeos/ash/components/standalone_browser/lacros_availability.h
@@ -0,0 +1,44 @@
+// 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_STANDALONE_BROWSER_LACROS_AVAILABILITY_H_
+#define CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER_LACROS_AVAILABILITY_H_
+
+#include "base/component_export.h"
+#include "base/strings/string_piece.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace ash::standalone_browser {
+
+// Represents the policy indicating how to launch Lacros browser, named
+// LacrosAvailability. The values shall be consistent with the controlling
+// policy.
+enum class LacrosAvailability {
+  // Indicates that the user decides whether to enable Lacros (if allowed) and
+  // make it the primary/only browser.
+  kUserChoice = 0,
+  // Indicates that Lacros is not allowed to be enabled.
+  kLacrosDisallowed = 1,
+  // Indicates that Lacros will be enabled (if allowed). Ash browser is the
+  // primary browser.
+  kSideBySide = 2,
+  // Similar to kSideBySide but Lacros is the primary browser.
+  kLacrosPrimary = 3,
+  // Indicates that Lacros (if allowed) is the only available browser.
+  kLacrosOnly = 4
+};
+
+// Parses the string representation of LacrosAvailability policy value into
+// the enum value. Returns nullopt on unknown value.
+COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER)
+absl::optional<LacrosAvailability> ParseLacrosAvailability(
+    base::StringPiece value);
+
+// Returns the policy value name from the given value.
+COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER)
+base::StringPiece GetLacrosAvailabilityPolicyName(LacrosAvailability value);
+
+}  // namespace ash::standalone_browser
+
+#endif  // CHROMEOS_ASH_COMPONENTS_STANDALONE_BROWSER_LACROS_AVAILABILITY_H_
diff --git a/chromeos/ash/services/assistant/assistant_manager_service_impl.cc b/chromeos/ash/services/assistant/assistant_manager_service_impl.cc
index bfdbbc6..ba434ce 100644
--- a/chromeos/ash/services/assistant/assistant_manager_service_impl.cc
+++ b/chromeos/ash/services/assistant/assistant_manager_service_impl.cc
@@ -348,12 +348,6 @@
   conversation_controller().StartEditReminderInteraction(client_id);
 }
 
-void AssistantManagerServiceImpl::StartScreenContextInteraction(
-    const std::vector<uint8_t>& assistant_screenshot) {
-  conversation_controller().StartScreenContextInteraction(nullptr,
-                                                          assistant_screenshot);
-}
-
 void AssistantManagerServiceImpl::StartTextInteraction(
     const std::string& query,
     AssistantQuerySource source,
@@ -719,11 +713,6 @@
   return context_->assistant_notification_controller();
 }
 
-AssistantScreenContextController*
-AssistantManagerServiceImpl::assistant_screen_context_controller() {
-  return context_->assistant_screen_context_controller();
-}
-
 AssistantStateBase* AssistantManagerServiceImpl::assistant_state() {
   return context_->assistant_state();
 }
diff --git a/chromeos/ash/services/assistant/assistant_manager_service_impl.h b/chromeos/ash/services/assistant/assistant_manager_service_impl.h
index a995afa..602c9b7 100644
--- a/chromeos/ash/services/assistant/assistant_manager_service_impl.h
+++ b/chromeos/ash/services/assistant/assistant_manager_service_impl.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "ash/public/cpp/assistant/controller/assistant_screen_context_controller.h"
 #include "base/cancelable_callback.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/observer_list.h"
@@ -74,8 +73,8 @@
   // doesn't know what to do.
   kSearchFallback = 3,
   // Query results in specific actions (e.g. opening a web app such as YouTube
-  // or Facebook, some deeplink actions such as taking a screenshot or opening
-  // chrome settings page), indicating that Assistant knows what to do.
+  // or Facebook, some deeplink actions such as opening chrome settings page),
+  // indicating that Assistant knows what to do.
   kTargetedAction = 4,
   // Special enumerator value used by histogram macros.
   kMaxValue = kTargetedAction
@@ -141,8 +140,6 @@
 
   // Assistant overrides:
   void StartEditReminderInteraction(const std::string& client_id) override;
-  void StartScreenContextInteraction(
-      const std::vector<uint8_t>& assistant_screenshot) override;
   void StartTextInteraction(const std::string& query,
                             AssistantQuerySource source,
                             bool allow_tts) override;
@@ -224,7 +221,6 @@
                                 bool is_user_initiated);
 
   AssistantNotificationController* assistant_notification_controller();
-  AssistantScreenContextController* assistant_screen_context_controller();
   AssistantStateBase* assistant_state();
   DeviceActions* device_actions();
   scoped_refptr<base::SequencedTaskRunner> main_task_runner();
diff --git a/chromeos/ash/services/assistant/public/cpp/assistant_service.h b/chromeos/ash/services/assistant/public/cpp/assistant_service.h
index 75f1347d..7ce1c89 100644
--- a/chromeos/ash/services/assistant/public/cpp/assistant_service.h
+++ b/chromeos/ash/services/assistant/public/cpp/assistant_service.h
@@ -73,13 +73,6 @@
   // to edit the specified reminder.
   virtual void StartEditReminderInteraction(const std::string& client_id) = 0;
 
-  // Starts a screen context interaction. Results related to the screen context
-  // will be returned through the |AssistantInteractionSubscriber| interface to
-  // registered subscribers.
-  // |assistant_screenshot| contains JPEG data.
-  virtual void StartScreenContextInteraction(
-      const std::vector<uint8_t>& assistant_screenshot) = 0;
-
   // Starts a new Assistant text interaction. If |allow_tts| is true, the
   // result will contain TTS. Otherwise TTS will not be present in the
   // generated server response. Results will be returned through registered
diff --git a/chromeos/ash/services/assistant/test_support/fake_assistant_manager_service_impl.cc b/chromeos/ash/services/assistant/test_support/fake_assistant_manager_service_impl.cc
index fdd6c0c..efb2aed 100644
--- a/chromeos/ash/services/assistant/test_support/fake_assistant_manager_service_impl.cc
+++ b/chromeos/ash/services/assistant/test_support/fake_assistant_manager_service_impl.cc
@@ -80,9 +80,6 @@
 void FakeAssistantManagerServiceImpl::StartEditReminderInteraction(
     const std::string& client_id) {}
 
-void FakeAssistantManagerServiceImpl::StartScreenContextInteraction(
-    const std::vector<uint8_t>& assistant_screenshot) {}
-
 void FakeAssistantManagerServiceImpl::StartTextInteraction(
     const std::string& query,
     AssistantQuerySource source,
diff --git a/chromeos/ash/services/assistant/test_support/fake_assistant_manager_service_impl.h b/chromeos/ash/services/assistant/test_support/fake_assistant_manager_service_impl.h
index 2b8e3f1..9b98e5a 100644
--- a/chromeos/ash/services/assistant/test_support/fake_assistant_manager_service_impl.h
+++ b/chromeos/ash/services/assistant/test_support/fake_assistant_manager_service_impl.h
@@ -58,8 +58,6 @@
 
   // Assistant overrides:
   void StartEditReminderInteraction(const std::string& client_id) override;
-  void StartScreenContextInteraction(
-      const std::vector<uint8_t>& assistant_screenshot) override;
   void StartTextInteraction(const std::string& query,
                             AssistantQuerySource source,
                             bool allow_tts) override;
diff --git a/chromeos/ash/services/assistant/test_support/mock_assistant.h b/chromeos/ash/services/assistant/test_support/mock_assistant.h
index 96631fa..88b7ab3 100644
--- a/chromeos/ash/services/assistant/test_support/mock_assistant.h
+++ b/chromeos/ash/services/assistant/test_support/mock_assistant.h
@@ -26,10 +26,6 @@
   MOCK_METHOD1(StartEditReminderInteraction, void(const std::string&));
 
   MOCK_METHOD(void,
-              StartScreenContextInteraction,
-              (const std::vector<uint8_t>&));
-
-  MOCK_METHOD(void,
               StartTextInteraction,
               (const std::string&, AssistantQuerySource, bool));
 
diff --git a/chromeos/ash/services/libassistant/conversation_controller.cc b/chromeos/ash/services/libassistant/conversation_controller.cc
index 5fb1009..07d69749 100644
--- a/chromeos/ash/services/libassistant/conversation_controller.cc
+++ b/chromeos/ash/services/libassistant/conversation_controller.cc
@@ -328,40 +328,6 @@
       /*description=*/std::string(), options, base::DoNothing());
 }
 
-void ConversationController::StartScreenContextInteraction(
-    ax::mojom::AssistantStructurePtr assistant_structure,
-    const std::vector<uint8_t>& screenshot) {
-  DCHECK(requests_are_allowed_)
-      << "Should not receive requests before Libassistant is running";
-  if (!assistant_client_)
-    return;
-
-  MaybeStopPreviousInteraction();
-
-  std::vector<std::string> context_protos;
-  // Screen context can have the |assistant_structure|, or |assistant_extra| and
-  // |assistant_tree| set to nullptr. This happens in the case where the screen
-  // context is coming from the metalayer or there is no active window. For this
-  // scenario, we don't create a context proto for the AssistantBundle that
-  // consists of the |assistant_extra| and |assistant_tree|.
-  if (assistant_structure && assistant_structure->assistant_extra &&
-      assistant_structure->assistant_tree) {
-    // Note: the value of |is_first_query| for screen context query is a no-op
-    // because it is not used for metalayer and "What's on my screen" queries.
-    context_protos.emplace_back(chromeos::assistant::CreateContextProto(
-        chromeos::assistant::AssistantBundle{
-            assistant_structure->assistant_extra.get(),
-            assistant_structure->assistant_tree.get()},
-        /*is_first_query=*/true));
-  }
-
-  // Note: the value of |is_first_query| for screen context query is a no-op.
-  context_protos.emplace_back(
-      chromeos::assistant::CreateContextProto(screenshot,
-                                              /*is_first_query=*/true));
-  assistant_client_->SendScreenContextRequest(context_protos);
-}
-
 void ConversationController::StopActiveInteraction(bool cancel_conversation) {
   if (!assistant_client_) {
     VLOG(1) << "Stopping interaction without assistant manager.";
@@ -473,14 +439,6 @@
 }
 
 // Called from Libassistant thread.
-// Note that we should deprecate this API when the server provides a fallback.
-void ConversationController::OnShowContextualQueryFallback() {
-  // Show fallback message.
-  OnShowText(l10n_util::GetStringUTF8(
-      IDS_ASSISTANT_SCREEN_CONTEXT_QUERY_FALLBACK_TEXT));
-}
-
-// Called from Libassistant thread.
 void ConversationController::OnShowSuggestions(
     const std::vector<chromeos::assistant::action::Suggestion>& suggestions) {
   ENSURE_MOJOM_THREAD(&ConversationController::OnShowSuggestions, suggestions);
diff --git a/chromeos/ash/services/libassistant/conversation_controller.h b/chromeos/ash/services/libassistant/conversation_controller.h
index e4e00f42..081f788 100644
--- a/chromeos/ash/services/libassistant/conversation_controller.h
+++ b/chromeos/ash/services/libassistant/conversation_controller.h
@@ -67,9 +67,6 @@
                      bool allow_tts) override;
   void StartVoiceInteraction() override;
   void StartEditReminderInteraction(const std::string& client_id) override;
-  void StartScreenContextInteraction(
-      ax::mojom::AssistantStructurePtr assistant_structure,
-      const std::vector<uint8_t>& screenshot) override;
   void StopActiveInteraction(bool cancel_conversation) override;
   void RetrieveNotification(AssistantNotification notification,
                             int32_t action_index) override;
@@ -82,7 +79,6 @@
   void OnShowHtml(const std::string& html_content,
                   const std::string& fallback) override;
   void OnShowText(const std::string& text) override;
-  void OnShowContextualQueryFallback() override;
   void OnShowSuggestions(
       const std::vector<chromeos::assistant::action::Suggestion>& suggestions)
       override;
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client.h b/chromeos/ash/services/libassistant/grpc/assistant_client.h
index d499276..f311b51 100644
--- a/chromeos/ash/services/libassistant/grpc/assistant_client.h
+++ b/chromeos/ash/services/libassistant/grpc/assistant_client.h
@@ -159,8 +159,6 @@
       base::OnceCallback<void(bool)> on_done) = 0;
   virtual void RegisterActionModule(
       assistant_client::ActionModule* action_module) = 0;
-  virtual void SendScreenContextRequest(
-      const std::vector<std::string>& context_protos) = 0;
   virtual void StartVoiceInteraction() = 0;
   virtual void StopAssistantInteraction(bool cancel_conversation) = 0;
   virtual void AddConversationStateEventObserver(
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client_impl.cc b/chromeos/ash/services/libassistant/grpc/assistant_client_impl.cc
index 28d7c5c8..3aebd28 100644
--- a/chromeos/ash/services/libassistant/grpc/assistant_client_impl.cc
+++ b/chromeos/ash/services/libassistant/grpc/assistant_client_impl.cc
@@ -236,11 +236,6 @@
   grpc_services_.GetActionService()->RegisterActionModule(action_module);
 }
 
-void AssistantClientImpl::SendScreenContextRequest(
-    const std::vector<std::string>& context_protos) {
-  NOTIMPLEMENTED();
-}
-
 void AssistantClientImpl::StartVoiceInteraction() {
   libassistant_client_.CallServiceMethod(
       ::assistant::api::StartVoiceQueryRequest(),
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client_impl.h b/chromeos/ash/services/libassistant/grpc/assistant_client_impl.h
index 10c6264..201ba0e 100644
--- a/chromeos/ash/services/libassistant/grpc/assistant_client_impl.h
+++ b/chromeos/ash/services/libassistant/grpc/assistant_client_impl.h
@@ -65,8 +65,6 @@
       base::OnceCallback<void(bool)> on_done) override;
   void RegisterActionModule(
       assistant_client::ActionModule* action_module) override;
-  void SendScreenContextRequest(
-      const std::vector<std::string>& context_protos) override;
   void StartVoiceInteraction() override;
   void StopAssistantInteraction(bool cancel_conversation) override;
   void AddConversationStateEventObserver(
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client_v1.cc b/chromeos/ash/services/libassistant/grpc/assistant_client_v1.cc
index d8865c7..e62558c 100644
--- a/chromeos/ash/services/libassistant/grpc/assistant_client_v1.cc
+++ b/chromeos/ash/services/libassistant/grpc/assistant_client_v1.cc
@@ -476,11 +476,6 @@
   assistant_manager_internal()->RegisterActionModule(action_module);
 }
 
-void AssistantClientV1::SendScreenContextRequest(
-    const std::vector<std::string>& context_protos) {
-  assistant_manager_internal()->SendScreenContextRequest(context_protos);
-}
-
 void AssistantClientV1::StartVoiceInteraction() {
   assistant_manager()->StartAssistantInteraction();
 }
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client_v1.h b/chromeos/ash/services/libassistant/grpc/assistant_client_v1.h
index c48b137..72bb325 100644
--- a/chromeos/ash/services/libassistant/grpc/assistant_client_v1.h
+++ b/chromeos/ash/services/libassistant/grpc/assistant_client_v1.h
@@ -68,8 +68,6 @@
       base::OnceCallback<void(bool)> on_done) override;
   void RegisterActionModule(
       assistant_client::ActionModule* action_module) override;
-  void SendScreenContextRequest(
-      const std::vector<std::string>& context_protos) override;
   void StartVoiceInteraction() override;
   void StopAssistantInteraction(bool cancel_conversation) override;
   void AddConversationStateEventObserver(
diff --git a/chromeos/ash/services/libassistant/public/mojom/conversation_controller.mojom b/chromeos/ash/services/libassistant/public/mojom/conversation_controller.mojom
index 148955d..00b5154 100644
--- a/chromeos/ash/services/libassistant/public/mojom/conversation_controller.mojom
+++ b/chromeos/ash/services/libassistant/public/mojom/conversation_controller.mojom
@@ -23,12 +23,6 @@
   // to edit the specified reminder.
   StartEditReminderInteraction(string client_id);
 
-  // Starts a screen context interaction.
-  // |screenshot| contains JPEG data.
-  StartScreenContextInteraction(
-      ax.mojom.AssistantStructure? assistant_structure,
-      array<uint8> screenshot);
-
   // Stops the ongoing interaction with a delay to give buffer time to
   // Libassistant when being forcefully stopped.
   StopActiveInteraction(bool cancel_conversation);
diff --git a/chromeos/ash/services/libassistant/test_support/fake_assistant_client.cc b/chromeos/ash/services/libassistant/test_support/fake_assistant_client.cc
index d218896..7f77d40 100644
--- a/chromeos/ash/services/libassistant/test_support/fake_assistant_client.cc
+++ b/chromeos/ash/services/libassistant/test_support/fake_assistant_client.cc
@@ -84,9 +84,6 @@
 void FakeAssistantClient::RegisterActionModule(
     assistant_client::ActionModule* action_module) {}
 
-void FakeAssistantClient::SendScreenContextRequest(
-    const std::vector<std::string>& context_protos) {}
-
 void FakeAssistantClient::StartVoiceInteraction() {}
 
 void FakeAssistantClient::StopAssistantInteraction(bool cancel_conversation) {}
diff --git a/chromeos/ash/services/libassistant/test_support/fake_assistant_client.h b/chromeos/ash/services/libassistant/test_support/fake_assistant_client.h
index ad4fa9a..b00b959 100644
--- a/chromeos/ash/services/libassistant/test_support/fake_assistant_client.h
+++ b/chromeos/ash/services/libassistant/test_support/fake_assistant_client.h
@@ -69,8 +69,6 @@
       base::OnceCallback<void(bool)> on_done) override;
   void RegisterActionModule(
       assistant_client::ActionModule* action_module) override;
-  void SendScreenContextRequest(
-      const std::vector<std::string>& context_protos) override;
   void StartVoiceInteraction() override;
   void StopAssistantInteraction(bool cancel_conversation) override;
   void AddConversationStateEventObserver(
diff --git a/chromeos/ash/services/network_config/cros_network_config.cc b/chromeos/ash/services/network_config/cros_network_config.cc
index 26a5f03..4c7fee7 100644
--- a/chromeos/ash/services/network_config/cros_network_config.cc
+++ b/chromeos/ash/services/network_config/cros_network_config.cc
@@ -616,23 +616,23 @@
 void SetValueIfKeyPresent(const base::Value* dict,
                           const char* key,
                           base::Value* out) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (v)
     *out = v->Clone();
 }
 
 absl::optional<std::string> GetString(const base::Value* dict,
                                       const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (v && !v->is_string()) {
     NET_LOG(ERROR) << "Expected string, found: " << *v;
     return absl::nullopt;
   }
-  return v ? absl::make_optional<std::string>(v->GetString()) : absl::nullopt;
+  return v ? absl::make_optional(v->GetString()) : absl::nullopt;
 }
 
 std::string GetRequiredString(const base::Value* dict, const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (!v) {
     NOTREACHED() << "Required key missing: " << key;
     return std::string();
@@ -647,7 +647,7 @@
 bool GetBoolean(const base::Value* dict,
                 const char* key,
                 bool value_if_key_missing_from_dict = false) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (v && !v->is_bool()) {
     NET_LOG(ERROR) << "Expected bool, found: " << *v;
     return false;
@@ -656,7 +656,7 @@
 }
 
 int32_t GetInt32(const base::Value* dict, const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (v && !v->is_int()) {
     NET_LOG(ERROR) << "Expected int, found: " << *v;
     return 0;
@@ -666,7 +666,7 @@
 
 std::vector<int32_t> GetInt32List(const base::Value* dict, const char* key) {
   std::vector<int32_t> result;
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (v && !v->is_list()) {
     NET_LOG(ERROR) << "Expected list, found: " << *v;
     return result;
@@ -679,7 +679,7 @@
 }
 
 const base::Value* GetDictionary(const base::Value* dict, const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (v && !v->is_dict()) {
     NET_LOG(ERROR) << "Expected dictionary, found: " << *v;
     return nullptr;
@@ -689,7 +689,7 @@
 
 absl::optional<std::vector<std::string>> GetStringList(const base::Value* dict,
                                                        const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (!v)
     return absl::nullopt;
   if (!v->is_list()) {
@@ -704,7 +704,7 @@
 
 std::vector<std::string> GetRequiredStringList(const base::Value* dict,
                                                const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (!v) {
     NOTREACHED() << "Required key missing: " << key;
     return {};
@@ -839,9 +839,9 @@
   // Set policy properties based on the effective source and policies.
   // NOTE: This does not enforce valid ONC. See onc_merger.cc for details.
   const base::Value* user_policy =
-      onc_dict->FindKey(::onc::kAugmentationUserPolicy);
+      onc_dict->GetDict().Find(::onc::kAugmentationUserPolicy);
   const base::Value* device_policy =
-      onc_dict->FindKey(::onc::kAugmentationDevicePolicy);
+      onc_dict->GetDict().Find(::onc::kAugmentationDevicePolicy);
   bool user_enforced = !GetBoolean(onc_dict, ::onc::kAugmentationUserEditable);
   bool device_enforced =
       !GetBoolean(onc_dict, ::onc::kAugmentationDeviceEditable);
@@ -880,7 +880,7 @@
 
 mojom::ManagedStringPtr GetManagedString(const base::Value* dict,
                                          const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (!v)
     return nullptr;
   if (v->is_string()) {
@@ -917,7 +917,7 @@
 
 mojom::ManagedStringListPtr GetManagedStringList(const base::Value* dict,
                                                  const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (!v)
     return nullptr;
   if (v->is_list()) {
@@ -951,7 +951,7 @@
 
 mojom::ManagedBooleanPtr GetManagedBoolean(const base::Value* dict,
                                            const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (!v)
     return nullptr;
   if (v->is_bool()) {
@@ -978,7 +978,7 @@
 
 mojom::ManagedInt32Ptr GetManagedInt32(const base::Value* dict,
                                        const char* key) {
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (!v)
     return nullptr;
   if (v->is_int()) {
@@ -1026,7 +1026,7 @@
     const base::Value* dict,
     const char* key) {
   auto result = mojom::ManagedSubjectAltNameMatchList::New();
-  const base::Value* value = dict->FindKey(key);
+  const base::Value* value = dict->GetDict().Find(key);
   if (!value)
     return result;
 
@@ -1231,7 +1231,7 @@
 
 mojom::ManagedApnPropertiesPtr GetManagedApnProperties(const base::Value* dict,
                                                        const char* key) {
-  const base::Value* apn_dict = dict->FindKey(key);
+  const base::Value* apn_dict = dict->GetDict().Find(key);
   if (!apn_dict)
     return nullptr;
   if (!apn_dict->is_dict()) {
@@ -1305,7 +1305,7 @@
     const base::Value* dict,
     const char* key) {
   std::vector<mojom::FoundNetworkPropertiesPtr> result;
-  const base::Value* v = dict->FindKey(key);
+  const base::Value* v = dict->GetDict().Find(key);
   if (!v)
     return result;
   if (!v->is_list()) {
@@ -1332,7 +1332,7 @@
 mojom::CellularProviderPropertiesPtr GetCellularProviderProperties(
     const base::Value* dict,
     const char* key) {
-  const base::Value* provider_dict = dict->FindKey(key);
+  const base::Value* provider_dict = dict->GetDict().Find(key);
   if (!provider_dict)
     return nullptr;
   auto provider = mojom::CellularProviderProperties::New();
@@ -1348,7 +1348,7 @@
 mojom::ManagedIssuerSubjectPatternPtr GetManagedIssuerSubjectPattern(
     const base::Value* dict,
     const char* key) {
-  const base::Value* pattern_dict = dict->FindKey(key);
+  const base::Value* pattern_dict = dict->GetDict().Find(key);
   if (!pattern_dict)
     return nullptr;
   if (!pattern_dict->is_dict()) {
@@ -1370,7 +1370,7 @@
 mojom::ManagedCertificatePatternPtr GetManagedCertificatePattern(
     const base::Value* dict,
     const char* key) {
-  const base::Value* pattern_dict = dict->FindKey(key);
+  const base::Value* pattern_dict = dict->GetDict().Find(key);
   if (!pattern_dict)
     return nullptr;
   if (!pattern_dict->is_dict()) {
@@ -1392,7 +1392,7 @@
 mojom::ManagedEAPPropertiesPtr GetManagedEAPProperties(const base::Value* dict,
                                                        const char* key) {
   auto eap = mojom::ManagedEAPProperties::New();
-  const base::Value* eap_dict = dict->FindKey(key);
+  const base::Value* eap_dict = dict->GetDict().Find(key);
   if (!eap_dict)
     return eap;
   if (!eap_dict->is_dict()) {
@@ -1437,7 +1437,7 @@
     const base::Value* dict,
     const char* key) {
   auto ipsec = mojom::ManagedIPSecProperties::New();
-  const base::Value* ipsec_dict = dict->FindKey(key);
+  const base::Value* ipsec_dict = dict->GetDict().Find(key);
   if (!ipsec_dict)
     return ipsec;
   if (!ipsec_dict->is_dict()) {
@@ -1477,7 +1477,7 @@
     const base::Value* dict,
     const char* key) {
   auto l2tp = mojom::ManagedL2TPProperties::New();
-  const base::Value* l2tp_dict = dict->FindKey(key);
+  const base::Value* l2tp_dict = dict->GetDict().Find(key);
   if (!l2tp_dict)
     return l2tp;
   if (!l2tp_dict->is_dict()) {
@@ -1497,7 +1497,7 @@
     const base::Value* dict,
     const char* key) {
   auto openvpn = mojom::ManagedOpenVPNProperties::New();
-  const base::Value* openvpn_dict = dict->FindKey(key);
+  const base::Value* openvpn_dict = dict->GetDict().Find(key);
   if (!openvpn_dict)
     return openvpn;
   if (!openvpn_dict->is_dict()) {
@@ -1568,7 +1568,7 @@
   openvpn->verify_hash =
       GetManagedString(openvpn_dict, ::onc::openvpn::kVerifyHash);
   const base::Value* verify_x509_dict =
-      openvpn_dict->FindKey(::onc::openvpn::kVerifyX509);
+      openvpn_dict->GetDict().Find(::onc::openvpn::kVerifyX509);
   if (verify_x509_dict) {
     auto verify_x509 = mojom::ManagedVerifyX509Properties::New();
     verify_x509->name =
@@ -1596,7 +1596,7 @@
     const base::Value* dict,
     const char* key) {
   auto result = mojom::ManagedWireGuardPeerList::New();
-  const base::Value* value = dict->FindKey(key);
+  const base::Value* value = dict->GetDict().Find(key);
   if (!value)
     return result;
   if (value->is_list()) {
@@ -1630,7 +1630,7 @@
     const base::Value* dict,
     const char* key) {
   auto wg = mojom::ManagedWireGuardProperties::New();
-  const base::Value* wg_dict = dict->FindKey(key);
+  const base::Value* wg_dict = dict->GetDict().Find(key);
   if (!wg_dict) {
     NET_LOG(ERROR) << "Missing WireGuard properties element";
     return wg;
@@ -1687,12 +1687,13 @@
       GetBoolean(properties, ::onc::network_config::kConnectable);
   result->error_state =
       GetString(properties, ::onc::network_config::kErrorState);
-  const base::Value* ip_configs_list =
-      properties->FindKey(::onc::network_config::kIPConfigs);
+  const base::Value::List* ip_configs_list =
+      properties->GetDict().FindList(::onc::network_config::kIPConfigs);
   if (ip_configs_list) {
     std::vector<mojom::IPConfigPropertiesPtr> ip_configs;
-    for (const base::Value& ip_config_value : ip_configs_list->GetList())
+    for (const base::Value& ip_config_value : *ip_configs_list) {
       ip_configs.push_back(GetIPConfig(&ip_config_value));
+    }
     result->ip_configs = std::move(ip_configs);
   }
   result->portal_state = GetMojoPortalState(network_state->GetPortalState());
@@ -1748,8 +1749,8 @@
           GetManagedBoolean(cellular_dict, ::onc::cellular::kAutoConnect);
       cellular->selected_apn =
           GetManagedApnProperties(cellular_dict, ::onc::cellular::kAPN);
-      cellular->apn_list =
-          GetManagedApnList(cellular_dict->FindKey(::onc::cellular::kAPNList));
+      cellular->apn_list = GetManagedApnList(
+          cellular_dict->GetDict().Find(::onc::cellular::kAPNList));
       cellular->allow_roaming =
           GetManagedBoolean(cellular_dict, ::onc::cellular::kAllowRoaming);
       cellular->esn = GetString(cellular_dict, ::onc::cellular::kESN);
@@ -1795,7 +1796,7 @@
       cellular->network_technology =
           GetString(cellular_dict, ::onc::cellular::kNetworkTechnology);
       const base::Value* payment_portal_dict =
-          cellular_dict->FindKey(::onc::cellular::kPaymentPortal);
+          cellular_dict->GetDict().Find(::onc::cellular::kPaymentPortal);
       if (payment_portal_dict) {
         auto payment_portal = mojom::PaymentPortalProperties::New();
         payment_portal->method = GetRequiredString(
@@ -1892,7 +1893,7 @@
         case mojom::VpnType::kExtension:
         case mojom::VpnType::kArc:
           const base::Value* third_party_dict =
-              vpn_dict->FindKey(::onc::vpn::kThirdPartyVpn);
+              vpn_dict->GetDict().Find(::onc::vpn::kThirdPartyVpn);
           if (third_party_dict) {
             vpn->provider_id = GetManagedString(
                 third_party_dict, ::onc::third_party_vpn::kExtensionID);
@@ -1968,12 +1969,13 @@
 
   // Traffic Counter Properties
   auto traffic_counter_properties = mojom::TrafficCounterProperties::New();
-  const base::Value* last_reset_time =
-      properties->FindKey(::onc::network_config::kTrafficCounterResetTime);
-  if (last_reset_time && last_reset_time->is_double()) {
+  const absl::optional<double> last_reset_time =
+      properties->GetDict().FindDouble(
+          ::onc::network_config::kTrafficCounterResetTime);
+  if (last_reset_time) {
     traffic_counter_properties->last_reset_time =
         base::Time::FromDeltaSinceWindowsEpoch(
-            base::Milliseconds(last_reset_time->GetDouble()));
+            base::Milliseconds(last_reset_time.value()));
     traffic_counter_properties->friendly_date =
         base::UTF16ToUTF8(base::TimeFormatFriendlyDate(
             traffic_counter_properties->last_reset_time.value()));
@@ -3369,12 +3371,11 @@
     std::move(callback).Run(result);
     return;
   }
-  const base::Value* value =
-      properties->FindKey(shill::kSupportedVPNTypesProperty);
+  const std::string* value =
+      properties->GetDict().FindString(shill::kSupportedVPNTypesProperty);
   if (value) {
-    result =
-        base::SplitString(*value->GetIfString(), ",", base::TRIM_WHITESPACE,
-                          base::SPLIT_WANT_NONEMPTY);
+    result = base::SplitString(*value, ",", base::TRIM_WHITESPACE,
+                               base::SPLIT_WANT_NONEMPTY);
   }
   std::move(callback).Run(result);
 }
@@ -3414,7 +3415,7 @@
     // uint32_t, we must check whether it was implicitly converted to a double
     // during D-Bus deserialization.
     uint64_t rx_bytes;
-    const base::Value* rb = tc.FindKey("rx_bytes");
+    const base::Value* rb = tc.GetDict().Find("rx_bytes");
     DCHECK(rb);
     if (rb->type() == base::Value::Type::INTEGER) {
       rx_bytes = rb->GetInt();
@@ -3428,7 +3429,7 @@
     // uint32_t, we must check whether it was implicitly converted to a double
     // during D-Bus deserialization.
     uint64_t tx_bytes;
-    const base::Value* tb = tc.FindKey("tx_bytes");
+    const base::Value* tb = tc.GetDict().Find("tx_bytes");
     DCHECK(tb);
     if (tb->type() == base::Value::Type::INTEGER) {
       tx_bytes = tb->GetInt();
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 61eddc6f..91fb22c5 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -322,11 +322,6 @@
       </message>
 
       <if expr="chromeos_ash">
-        <message name="IDS_ASSISTANT_SCREEN_CONTEXT_QUERY_FALLBACK_TEXT" desc="Message shown in Assistant UI when a query for content related to the screen context returns no results.">
-          I can't find anything on your screen I can help with.
-Try tapping the mic to ask me anything.
-        </message>
-
         <!-- 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.">
           Turn on Bluetooth to discover nearby devices
diff --git a/chromeos/crosapi/mojom/synced_session_client.mojom b/chromeos/crosapi/mojom/synced_session_client.mojom
index 084771d..03ea46b 100644
--- a/chromeos/crosapi/mojom/synced_session_client.mojom
+++ b/chromeos/crosapi/mojom/synced_session_client.mojom
@@ -12,7 +12,7 @@
 [Stable]
 struct SyncedSessionTab {
   url.mojom.Url current_navigation_url@0;
-  mojo_base.mojom.String16 title@1;
+  mojo_base.mojom.String16 current_navigation_title@1;
   mojo_base.mojom.Time last_modified_timestamp@2;
 };
 
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index f0e2901..2aa2d33 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-111-5464.0-1672657853-benchmark-111.0.5514.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-111-5481.21-1673865504-benchmark-111.0.5544.0-r1-redacted.afdo.xz
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index fa82b7c2..328206e 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -304,11 +304,6 @@
   # https://crbug.com/1236234
   "lacros.AudioPlay",
 
-  # b/265844024
-  "inputs.PhysicalKeyboardPinyinTyping.traditional",
-  "inputs.PhysicalKeyboardShapeBasedChineseTyping.array",
-  "inputs.PhysicalKeyboardShapeBasedChineseTyping.cangjie",
-
   # READ COMMENT AT TOP BEFORE ADDING NEW TESTS HERE.
 ]
 
diff --git a/components/cast_streaming/renderer/frame_injecting_demuxer.cc b/components/cast_streaming/renderer/frame_injecting_demuxer.cc
index fc260d2..0ece3ca 100644
--- a/components/cast_streaming/renderer/frame_injecting_demuxer.cc
+++ b/components/cast_streaming/renderer/frame_injecting_demuxer.cc
@@ -403,6 +403,10 @@
   std::move(status_cb).Run(media::PIPELINE_OK);
 }
 
+bool FrameInjectingDemuxer::IsSeekable() const {
+  return false;
+}
+
 void FrameInjectingDemuxer::Stop() {
   DVLOG(1) << __func__;
   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
diff --git a/components/cast_streaming/renderer/frame_injecting_demuxer.h b/components/cast_streaming/renderer/frame_injecting_demuxer.h
index c467b69..8984b9f 100644
--- a/components/cast_streaming/renderer/frame_injecting_demuxer.h
+++ b/components/cast_streaming/renderer/frame_injecting_demuxer.h
@@ -54,6 +54,7 @@
   void CancelPendingSeek(base::TimeDelta seek_time) override;
   void Seek(base::TimeDelta time,
             media::PipelineStatusCallback status_cb) override;
+  bool IsSeekable() const override;
   void Stop() override;
   base::TimeDelta GetStartTime() const override;
   base::Time GetTimelineOffset() const override;
diff --git a/components/cast_streaming/test/cast_message_port_sender_impl.cc b/components/cast_streaming/test/cast_message_port_sender_impl.cc
index 06b1b4b7..cf7eab2 100644
--- a/components/cast_streaming/test/cast_message_port_sender_impl.cc
+++ b/components/cast_streaming/test/cast_message_port_sender_impl.cc
@@ -25,6 +25,11 @@
 CastMessagePortSenderImpl::~CastMessagePortSenderImpl() = default;
 
 void CastMessagePortSenderImpl::MaybeClose() {
+  // We may be called multiple times, but only want to close once.
+  if (is_closed_) {
+    return;
+  }
+
   if (message_port_) {
     message_port_.reset();
   }
@@ -35,6 +40,7 @@
       std::move(on_close_).Run();
     }
   }
+  is_closed_ = true;
 }
 
 void CastMessagePortSenderImpl::SetClient(
diff --git a/components/cast_streaming/test/cast_message_port_sender_impl.h b/components/cast_streaming/test/cast_message_port_sender_impl.h
index 61ff245..77cfdb8 100644
--- a/components/cast_streaming/test/cast_message_port_sender_impl.h
+++ b/components/cast_streaming/test/cast_message_port_sender_impl.h
@@ -50,6 +50,7 @@
   std::unique_ptr<cast_api_bindings::MessagePort> message_port_;
   base::OnceClosure on_close_;
   base::OnceClosure on_system_sender_message_received_;
+  bool is_closed_ = false;
 };
 
 }  // namespace cast_streaming
diff --git a/components/cast_streaming/test/cast_streaming_test_sender.cc b/components/cast_streaming/test/cast_streaming_test_sender.cc
index e6597480..9bbfbb77 100644
--- a/components/cast_streaming/test/cast_streaming_test_sender.cc
+++ b/components/cast_streaming/test/cast_streaming_test_sender.cc
@@ -142,10 +142,15 @@
 void CastStreamingTestSender::Stop() {
   VLOG(1) << __func__;
 
-  sender_session_.reset();
-  message_port_.reset();
+  // Senders must be deconstructed before the session that hosts them.
   audio_sender_observer_.reset();
   video_sender_observer_.reset();
+
+  // Disconnect the message port before destructing its client.
+  message_port_->ResetClient();
+  sender_session_.reset();
+  message_port_.reset();
+
   audio_decoder_config_.reset();
   video_decoder_config_.reset();
   has_startup_completed_ = false;
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index 406ec8f..96b349a 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -514,18 +514,6 @@
   }
 
   if (event->IsMouseEvent()) {
-    // Generate motion event if location changed. We need to check location
-    // here as mouse movement can generate both "moved" and "entered" events
-    // but OnPointerMotion should only be called if location changed since
-    // OnPointerEnter was called.
-    // For synthesized events, they typically lack floating point precision
-    // so to avoid generating mouse event jitter we consider the location of
-    // these events to be the same as |location| if floored values match.
-    bool same_location = !event->IsSynthesized()
-                             ? SameLocation(location_in_root, location_in_root_)
-                             : gfx::ToFlooredPoint(location_in_root) ==
-                                   gfx::ToFlooredPoint(location_in_root_);
-
     // Ordinal motion is sent only on platforms that support it, which is
     // indicated by the presence of a flag.
     absl::optional<gfx::Vector2dF> ordinal_motion = absl::nullopt;
@@ -534,7 +522,12 @@
       ordinal_motion = event->movement();
     }
 
-    if (!same_location) {
+    // Generate motion event if location changed. We need to check location
+    // here as mouse movement can generate both "moved" and "entered" events
+    // but OnPointerMotion should only be called if location changed since
+    // OnPointerEnter was called.
+    if (!CheckIfSameLocation(event->IsSynthesized(), location_in_root,
+                             location_in_target)) {
       bool ignore_motion = false;
       if (expected_next_mouse_location_) {
         const gfx::Point& expected = *expected_next_mouse_location_;
@@ -560,6 +553,7 @@
         needs_frame |= true;
       }
       location_in_root_ = location_in_root;
+      location_in_surface_ = location_in_target;
     }
   }
   switch (event->type()) {
@@ -860,6 +854,7 @@
     delegate_->OnPointerEnter(surface, surface_location, button_flags);
     delegate_->OnPointerFrame();
     location_in_root_ = root_location;
+    location_in_surface_ = surface_location;
     focus_surface_ = surface;
     if (!focus_surface_->HasSurfaceObserver(this))
       focus_surface_->AddSurfaceObserver(this);
@@ -1049,4 +1044,27 @@
   }
 }
 
+bool Pointer::CheckIfSameLocation(bool is_synthesized,
+                                  const gfx::PointF& location_in_root,
+                                  const gfx::PointF& location_in_target) {
+  // There is a specific case that location_in_root is the same
+  // but location_in_target is updated with SynthesizeMouseMove
+  // without the actual mouse movement when the window bounds changes.
+  // To handle this case, PointerMotion event should be delievered to
+  // delegate to update the current pointer location properly.
+  // Hence, check either target or root has changed.
+  if (!is_synthesized) {
+    return SameLocation(location_in_root, location_in_root_) &&
+           SameLocation(location_in_target, location_in_surface_);
+  }
+
+  // For synthesized events, they typically lack floating point precision
+  // so to avoid generating mouse event jitter we consider the location of
+  // these events to be the same as |location| if floored values match.
+  return (gfx::ToFlooredPoint(location_in_root) ==
+          gfx::ToFlooredPoint(location_in_root_)) &&
+         (gfx::ToFlooredPoint(location_in_target) ==
+          gfx::ToFlooredPoint(location_in_surface_));
+}
+
 }  // namespace exo
diff --git a/components/exo/pointer.h b/components/exo/pointer.h
index 14a7503..b6a946c0 100644
--- a/components/exo/pointer.h
+++ b/components/exo/pointer.h
@@ -204,6 +204,11 @@
   // Stop observing |surface| if it's no longer relevant.
   void MaybeRemoveSurfaceObserver(Surface* surface);
 
+  // Return true if location is same.
+  bool CheckIfSameLocation(bool is_synthesized,
+                           const gfx::PointF& location_in_root,
+                           const gfx::PointF& location_in_target);
+
   // The delegate instance that all events are dispatched to.
   PointerDelegate* const delegate_;
 
@@ -231,6 +236,9 @@
   // The location of the pointer in the root window.
   gfx::PointF location_in_root_;
 
+  // The location of the pointer converted to the target.
+  gfx::PointF location_in_surface_;
+
   // The location of the pointer when pointer capture is first enabled.
   absl::optional<gfx::Point> location_when_pointer_capture_enabled_;
 
diff --git a/components/media_router/common/discovery/media_sink_service_base.h b/components/media_router/common/discovery/media_sink_service_base.h
index 4e8e695..7f9733b 100644
--- a/components/media_router/common/discovery/media_sink_service_base.h
+++ b/components/media_router/common/discovery/media_sink_service_base.h
@@ -65,9 +65,8 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
-  // Overridden by subclass to initiate action triggered by user gesture, e.g.
-  // start one-off round of discovery.
-  virtual void OnUserGesture() {}
+  // Starts a new round of the discovery process as soon as possible.
+  virtual void DiscoverSinksNow() {}
 
   // Adds or updates, or removes a sink.
   // Notifies |observers_| that the sink has been added, updated, or removed.
diff --git a/components/media_router/common/issue.h b/components/media_router/common/issue.h
index 76062b67..aa34714 100644
--- a/components/media_router/common/issue.h
+++ b/components/media_router/common/issue.h
@@ -23,6 +23,9 @@
 
   // |title|: The title for the issue.
   // |severity|: The severity of the issue.
+  //
+  // TODO(crbug.com/1407333): Add sink_id as a ctor argument, as all issues have
+  // associated sinks.
   IssueInfo(const std::string& title, Severity severity);
   IssueInfo(const IssueInfo&);
   IssueInfo& operator=(const IssueInfo&);
diff --git a/components/media_router/common/mojom/media_router.mojom b/components/media_router/common/mojom/media_router.mojom
index 2d43ba01..2e54e1d 100644
--- a/components/media_router/common/mojom/media_router.mojom
+++ b/components/media_router/common/mojom/media_router.mojom
@@ -77,11 +77,10 @@
   int32 cast_channel_id;
 };
 
-// TODO(crbug.com/993437): Replace the use of this enum with a boolean field.
 enum RouteControllerType {
-  kNone,
-  kGeneric,
-  kMirroring
+  kNone,      // No route controller.
+  kGeneric,   // Route controller for sessions with media controls (apps).
+  kMirroring  // Route controller for Cast mirroring and remoting sessions.
 };
 
 // MediaRoute objects contain the status and metadata of a routing
@@ -101,9 +100,6 @@
   string media_sink_name;
   // Human readable description of the casting activity.  Examples:
   // "Mirroring tab (www.example.com)", "Casting media", "Casting YouTube"
-  //
-  // TODO(crbug.com/786208): Localize this properly by passing it in a way that
-  // permits use of template strings and placeholders.
   string description;
   // Specifies that the route is requested locally.
   bool is_local;
@@ -131,7 +127,6 @@
 
   // The ID of the sink associated with this issue.
   // If this is an empty string (default), then this is a global issue.
-  // TODO(https://crbug.com/554646): Associate all issues with sinks.
   string sink_id;
 
   Severity severity;
@@ -323,14 +318,10 @@
   // already a firewall rule for mDNS.
   EnableMdnsDiscovery();
 
-  // Requests the MediaRouteProvider to update the list of media sinks capable
-  // of displaying |media_source|. This call is made when a user gesture is
-  // detected, so MediaRouteProvider may treat this as a signal to take actions
-  // to become more responsive, e.g., initiate a one-off round of device
-  // discovery.
-  // TODO(https://crbug.com/698940): Rename this to OnUserGesture and remove the
-  // |media_source| parameter.
-  UpdateMediaSinks(string media_source);
+  // Requests the MediaRouteProvider to update its list of media sinks.
+  // This is called when a user gesture occurs, and the MRP is expected to
+  // initiate discovery of media sinks in response.
+  DiscoverSinksNow();
 
   // Creates a controller for the media route with given |route_id| and binds it
   // to |media_controller| for receiving media commands. This method returns
@@ -342,8 +333,6 @@
   // method can be called again with the same |route_id|. This method also sets
   // |observer| to be notified whenever there is a change in the status of the
   // media route.
-  // TODO(takumif): Consider returning an enum instead of a bool to distinguish
-  // between error conditions for metrics/debugging.
   CreateMediaRouteController(string route_id,
                              pending_receiver<MediaController> media_controller,
                              pending_remote<MediaStatusObserver> observer) =>
diff --git a/components/neterror/resources/error_page_controller_ios.js b/components/neterror/resources/error_page_controller_ios.js
index dad7391..73da0b2 100644
--- a/components/neterror/resources/error_page_controller_ios.js
+++ b/components/neterror/resources/error_page_controller_ios.js
@@ -25,20 +25,20 @@
 
   // Track easter egg plays and high scores.
   trackEasterEgg: function() {
-    __gCrWeb.message.invokeOnHost(
-        {'command': 'errorPageController.trackEasterEgg'});
+    window.webkit.messageHandlers['ErrorPageMessage'].postMessage(
+        {'command': 'trackEasterEgg'});
   },
 
   updateEasterEggHighScore: function(highScore) {
-    __gCrWeb.message.invokeOnHost({
-      'command': 'errorPageController.updateEasterEggHighScore',
+    window.webkit.messageHandlers['ErrorPageMessage'].postMessage({
+      'command': 'updateEasterEggHighScore',
       'highScore': highScore.toString(),
     });
   },
 
   resetEasterEggHighScore: function() {
-    __gCrWeb.message.invokeOnHost(
-        {'command': 'errorPageController.resetEasterEggHighScore'});
+    window.webkit.messageHandlers['ErrorPageMessage'].postMessage(
+        {'command': 'resetEasterEggHighScore'});
   },
 };
 
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index cf47625..52bd944 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -153,6 +153,8 @@
     "history_provider.h",
     "history_quick_provider.cc",
     "history_quick_provider.h",
+    "history_scoring_signals_annotator.cc",
+    "history_scoring_signals_annotator.h",
     "history_url_provider.cc",
     "history_url_provider.h",
     "in_memory_url_index.cc",
@@ -656,6 +658,7 @@
     "history_fuzzy_provider_unittest.cc",
     "history_provider_unittest.cc",
     "history_quick_provider_unittest.cc",
+    "history_scoring_signals_annotator_unittest.cc",
     "history_url_provider_unittest.cc",
     "in_memory_url_index_types_unittest.cc",
     "in_memory_url_index_unittest.cc",
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index e64630d..828fa5df 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -17,6 +17,7 @@
 #include "base/feature_list.h"
 #include "base/format_macros.h"
 #include "base/functional/bind.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/observer_list.h"
@@ -41,6 +42,7 @@
 #include "components/omnibox/browser/document_provider.h"
 #include "components/omnibox/browser/history_fuzzy_provider.h"
 #include "components/omnibox/browser/history_quick_provider.h"
+#include "components/omnibox/browser/history_scoring_signals_annotator.h"
 #include "components/omnibox/browser/history_url_provider.h"
 #include "components/omnibox/browser/keyword_provider.h"
 #include "components/omnibox/browser/local_history_zero_suggest_provider.h"
@@ -508,6 +510,16 @@
   }
 #endif
 
+  // Create URL scoring signal annotators.
+  if (OmniboxFieldTrial::IsLogUrlScoringSignalsEnabled() &&
+      base::GetFieldTrialParamByFeatureAsBool(
+          omnibox::kLogUrlScoringSignals, "enable_scoring_signals_annotators",
+          /*default_value=*/false)) {
+    url_scoring_signals_annotators_.push_back(
+        std::make_unique<HistoryScoringSignalsAnnotator>(
+            provider_client_.get()));
+  }
+
   base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
       this, "AutocompleteController",
       base::SingleThreadTaskRunner::GetCurrentDefault());
@@ -1031,7 +1043,7 @@
   // If enabled, update scoring signals of URL suggestions.
   if (OmniboxFieldTrial::IsLogUrlScoringSignalsEnabled()) {
     for (const auto& annotator : url_scoring_signals_annotators_) {
-      annotator->AnnotateResult(&result_);
+      annotator->AnnotateResult(input_, &result_);
     }
   }
 }
diff --git a/components/omnibox/browser/autocomplete_match_classification.cc b/components/omnibox/browser/autocomplete_match_classification.cc
index 734dd00..246da31 100644
--- a/components/omnibox/browser/autocomplete_match_classification.cc
+++ b/components/omnibox/browser/autocomplete_match_classification.cc
@@ -30,20 +30,30 @@
       base::StartsWith(text, find_text, base::CompareCase::SENSITIVE))
     return {{0, 0, find_text.length()}};
 
-  String16Vector find_terms = String16VectorFromString16(find_text, NULL);
+  String16Vector find_terms = String16VectorFromString16(find_text, nullptr);
+  WordStarts word_starts;
+  // `word_starts` is unused if `allow_mid_word_matching` is true.
+  if (!allow_mid_word_matching) {
+    String16VectorFromString16(text, &word_starts);
+  }
+  return FindTermMatchesForTerms(find_terms, WordStarts(find_terms.size(), 0),
+                                 text, word_starts, allow_mid_word_matching);
+}
 
-  TermMatches matches = MatchTermsInString(find_terms, text);
+TermMatches FindTermMatchesForTerms(const String16Vector& find_terms,
+                                    const WordStarts& find_terms_word_starts,
+                                    const std::u16string& cleaned_text,
+                                    const WordStarts& text_word_starts,
+                                    bool allow_mid_word_matching) {
+  TermMatches matches = MatchTermsInString(find_terms, cleaned_text);
   matches = SortMatches(matches);
   matches = DeoverlapMatches(matches);
 
   if (allow_mid_word_matching)
     return matches;
 
-  WordStarts word_starts;
-  String16VectorFromString16(text, &word_starts);
   return ScoredHistoryMatch::FilterTermMatchesByWordStarts(
-      matches, WordStarts(find_terms.size(), 0), word_starts, 0,
-      std::string::npos);
+      matches, find_terms_word_starts, text_word_starts, 0, std::string::npos);
 }
 
 ACMatchClassifications ClassifyTermMatches(TermMatches matches,
diff --git a/components/omnibox/browser/autocomplete_match_classification.h b/components/omnibox/browser/autocomplete_match_classification.h
index adf0d0c..5d6686e 100644
--- a/components/omnibox/browser/autocomplete_match_classification.h
+++ b/components/omnibox/browser/autocomplete_match_classification.h
@@ -27,6 +27,19 @@
                             bool allow_prefix_matching = true,
                             bool allow_mid_word_matching = false);
 
+// A utility function called by `FindTermMatches` to find valid matches in text
+// for the given terms. Matched terms are sorted, deduped, and possibly
+// filtered-by-word-boundary. If `allow_mid_word_matching` is false, the
+// returned terms will be filtered-by-word-boundary. E.g., for `find_text` "ho
+// to ie", `text` "how to tie a tie", and `allow_mid_word_matching` false, this
+// will return "[ho]w [to] tie a tie". On the other hand, for
+// |allow_mid_word_matching| true, this will return "[ho]w [to] t[ie] a t[ie]."
+TermMatches FindTermMatchesForTerms(const String16Vector& find_terms,
+                                    const WordStarts& find_terms_word_starts,
+                                    const std::u16string& cleaned_text,
+                                    const WordStarts& text_word_starts,
+                                    bool allow_mid_word_matching = false);
+
 // Return an ACMatchClassifications structure given the |matches| to highlight.
 // |matches| can be retrieved from calling FindTermMatches. |text_length| should
 // be the full length (not the length of the truncated text clean returns) of
diff --git a/components/omnibox/browser/autocomplete_scoring_signals_annotator.h b/components/omnibox/browser/autocomplete_scoring_signals_annotator.h
index 7639b28..3339fccc 100644
--- a/components/omnibox/browser/autocomplete_scoring_signals_annotator.h
+++ b/components/omnibox/browser/autocomplete_scoring_signals_annotator.h
@@ -5,7 +5,12 @@
 #ifndef COMPONENTS_OMNIBOX_BROWSER_AUTOCOMPLETE_SCORING_SIGNALS_ANNOTATOR_H_
 #define COMPONENTS_OMNIBOX_BROWSER_AUTOCOMPLETE_SCORING_SIGNALS_ANNOTATOR_H_
 
-#include "components/omnibox/browser/autocomplete_result.h"
+#include "third_party/metrics_proto/omnibox_event.pb.h"
+
+class AutocompleteInput;
+class AutocompleteResult;
+
+using ScoringSignals = ::metrics::OmniboxEventProto::Suggestion::ScoringSignals;
 
 // Base class for annotating suggestions in autocomplete results with various
 // signals for ML training and scoring.
@@ -19,7 +24,8 @@
   virtual ~AutocompleteScoringSignalsAnnotator() = default;
 
   // Annotate the autocomplete result.
-  virtual void AnnotateResult(AutocompleteResult* result) = 0;
+  virtual void AnnotateResult(const AutocompleteInput& input,
+                              AutocompleteResult* result) = 0;
 };
 
 #endif  // COMPONENTS_OMNIBOX_BROWSER_AUTOCOMPLETE_SCORING_SIGNALS_ANNOTATOR_H_
diff --git a/components/omnibox/browser/history_scoring_signals_annotator.cc b/components/omnibox/browser/history_scoring_signals_annotator.cc
new file mode 100644
index 0000000..90fed2d
--- /dev/null
+++ b/components/omnibox/browser/history_scoring_signals_annotator.cc
@@ -0,0 +1,116 @@
+// 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/omnibox/browser/history_scoring_signals_annotator.h"
+
+#include <string>
+
+#include "base/i18n/case_conversion.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/time/time.h"
+#include "components/bookmarks/browser/bookmark_utils.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/url_database.h"
+#include "components/history/core/browser/url_row.h"
+#include "components/omnibox/browser/autocomplete_input.h"
+#include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/autocomplete_match_classification.h"
+#include "components/omnibox/browser/autocomplete_match_type.h"
+#include "components/omnibox/browser/autocomplete_provider_client.h"
+#include "components/omnibox/browser/autocomplete_result.h"
+#include "components/omnibox/browser/autocomplete_scoring_signals_annotator.h"
+#include "components/omnibox/browser/in_memory_url_index_types.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
+#include "components/omnibox/browser/scored_history_match.h"
+#include "components/omnibox/browser/tailored_word_break_iterator.h"
+#include "components/omnibox/browser/url_index_private_data.h"
+#include "third_party/metrics_proto/omnibox_event.pb.h"
+
+HistoryScoringSignalsAnnotator::HistoryScoringSignalsAnnotator(
+    AutocompleteProviderClient* client)
+    : client_(client) {
+  num_title_words_to_allow_ = OmniboxFieldTrial::HQPNumTitleWordsToAllow();
+}
+
+void HistoryScoringSignalsAnnotator::AnnotateResult(
+    const AutocompleteInput& input,
+    AutocompleteResult* result) {
+  history::HistoryService* const history_service = client_->GetHistoryService();
+  if (!history_service) {
+    return;
+  }
+  // Get the in-memory URL database.
+  history::URLDatabase* url_db = history_service->InMemoryDatabase();
+  if (!url_db) {
+    return;
+  }
+
+  // Split input text into terms.
+  std::u16string lower_raw_string(base::i18n::ToLower(input.text()));
+  auto [lower_raw_terms, lower_terms_to_word_starts_offsets] =
+      URLIndexPrivateData::GetTermsAndWordStartsOffsets(lower_raw_string);
+
+  for (auto& match : *result) {
+    // Skip non-URL matches.
+    if (!IsEligibleMatch(match)) {
+      continue;
+    }
+
+    // Skip this match if it already has history signals.
+    if (match.scoring_signals.has_typed_count() &&
+        match.scoring_signals.has_total_title_match_length()) {
+      continue;
+    }
+
+    history::URLRow row;
+    // Return if no URL row found.
+    if (url_db->GetRowForURL(match.destination_url, &row) == 0) {
+      return;
+    }
+
+    // Populate scoring signals.
+    if (!match.scoring_signals.has_typed_count()) {
+      match.scoring_signals.set_typed_count(row.typed_count());
+      match.scoring_signals.set_visit_count(row.visit_count());
+      match.scoring_signals.set_elapsed_time_last_visit_secs(
+          (base::Time::Now() - row.last_visit()).InSeconds());
+    }
+    if (!match.scoring_signals.has_total_title_match_length()) {
+      PopulateTitleMatchingSignals(lower_raw_terms,
+                                   lower_terms_to_word_starts_offsets,
+                                   row.title(), &match.scoring_signals);
+    }
+  }
+}
+
+bool HistoryScoringSignalsAnnotator::IsEligibleMatch(
+    const AutocompleteMatch& match) {
+  return match.type == AutocompleteMatchType::URL_WHAT_YOU_TYPED ||
+         match.type == AutocompleteMatchType::HISTORY_URL ||
+         match.type == AutocompleteMatchType::HISTORY_TITLE ||
+         match.type == AutocompleteMatchType::BOOKMARK_TITLE;
+}
+
+void HistoryScoringSignalsAnnotator::PopulateTitleMatchingSignals(
+    const String16Vector& input_terms,
+    const WordStarts& terms_to_word_starts_offsets,
+    const std::u16string& raw_title,
+    ScoringSignals* scoring_signals) {
+  std::u16string title = bookmarks::CleanUpTitleForMatching(raw_title);
+  WordStarts title_word_starts;
+  String16VectorFromString16(title, &title_word_starts);
+  TermMatches title_matches = FindTermMatchesForTerms(
+      input_terms, terms_to_word_starts_offsets, title, title_word_starts,
+      /*allow_mid_word_matching=*/false);
+
+  // Compute total title match length.
+  size_t total_title_match_length = ScoredHistoryMatch::ComputeTotalMatchLength(
+      terms_to_word_starts_offsets, title_matches, title_word_starts,
+      num_title_words_to_allow_);
+  scoring_signals->set_total_title_match_length(total_title_match_length);
+
+  scoring_signals->set_num_input_terms_matched_by_title(
+      ScoredHistoryMatch::CountUniqueMatchTerms(title_matches));
+}
diff --git a/components/omnibox/browser/history_scoring_signals_annotator.h b/components/omnibox/browser/history_scoring_signals_annotator.h
new file mode 100644
index 0000000..363f5e40
--- /dev/null
+++ b/components/omnibox/browser/history_scoring_signals_annotator.h
@@ -0,0 +1,64 @@
+// 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_OMNIBOX_BROWSER_HISTORY_SCORING_SIGNALS_ANNOTATOR_H_
+#define COMPONENTS_OMNIBOX_BROWSER_HISTORY_SCORING_SIGNALS_ANNOTATOR_H_
+
+#include <string>
+
+#include "base/memory/raw_ptr.h"
+#include "components/omnibox/browser/autocomplete_scoring_signals_annotator.h"
+#include "components/omnibox/browser/in_memory_url_index_types.h"
+
+class AutocompleteInput;
+class AutocompleteProviderClient;
+class AutocompleteResult;
+struct AutocompleteMatch;
+
+// History scoring signals annotator for annotating URL suggestions in
+// the autocomplete result with signals derived from history, including:
+// `typed_count`, `visit_count`, `elapsed_time_last_visit_secs`,
+// `total_title_match_length`, and `num_input_terms_matched_by_title`.
+//
+// Currently, only synchronously looks up URLs from the in-memory URL DB.
+// Skips suggestions that already have history signals.
+//
+// Can annotate eligible URL suggesions from various providers, including
+// history, bookmark, and shortcut suggestions.
+class HistoryScoringSignalsAnnotator
+    : public AutocompleteScoringSignalsAnnotator {
+ public:
+  explicit HistoryScoringSignalsAnnotator(AutocompleteProviderClient* client);
+  HistoryScoringSignalsAnnotator(const HistoryScoringSignalsAnnotator&) =
+      delete;
+  HistoryScoringSignalsAnnotator& operator=(
+      const HistoryScoringSignalsAnnotator&) = delete;
+  ~HistoryScoringSignalsAnnotator() override = default;
+
+  // Annotates the URL suggestions of the autocomplete result.
+  void AnnotateResult(const AutocompleteInput& input,
+                      AutocompleteResult* result) override;
+
+ private:
+  // Whether the autocomplete match is eligible to be annotated.
+  // Currently, includes only history and bookmark URLs.
+  bool IsEligibleMatch(const AutocompleteMatch& match);
+
+  // Populates signals based on the matching strings between the input text and
+  // page title.
+  void PopulateTitleMatchingSignals(
+      const String16Vector& input_terms,
+      const WordStarts& terms_to_word_starts_offsets,
+      const std::u16string& title,
+      ScoringSignals* scoring_signals);
+
+  raw_ptr<AutocompleteProviderClient> client_;
+
+  // The number of title words examined when computing matching signals.
+  // Words beyond this number are ignored.
+  // Currently, set by this feature param: http://shortn/_kXE02KOqFR
+  int num_title_words_to_allow_;
+};
+
+#endif  // COMPONENTS_OMNIBOX_BROWSER_HISTORY_SCORING_SIGNALS_ANNOTATOR_H_
diff --git a/components/omnibox/browser/history_scoring_signals_annotator_unittest.cc b/components/omnibox/browser/history_scoring_signals_annotator_unittest.cc
new file mode 100644
index 0000000..b029b059
--- /dev/null
+++ b/components/omnibox/browser/history_scoring_signals_annotator_unittest.cc
@@ -0,0 +1,125 @@
+// 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/omnibox/browser/history_scoring_signals_annotator.h"
+
+#include "base/test/task_environment.h"
+#include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/history/core/browser/url_database.h"
+#include "components/history/core/browser/url_row.h"
+#include "components/history/core/test/history_service_test_util.h"
+#include "components/omnibox/browser/autocomplete_input.h"
+#include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/autocomplete_provider_client.h"
+#include "components/omnibox/browser/autocomplete_result.h"
+#include "components/omnibox/browser/fake_autocomplete_provider_client.h"
+#include "components/omnibox/browser/test_scheme_classifier.h"
+
+using ::history::URLRow;
+
+namespace {
+
+URLRow CreateUrlRow(const std::string& url,
+                    const std::u16string& title,
+                    int typed_count,
+                    int visit_count,
+                    const base::Time& last_visit,
+                    int64_t id) {
+  GURL gurl(url);
+  URLRow row(gurl);
+  row.set_title(title);
+  row.set_typed_count(typed_count);
+  row.set_visit_count(visit_count);
+  row.set_last_visit(last_visit);
+  row.set_hidden(false);
+  row.set_id(id);
+  return row;
+}
+
+}  // namespace
+
+class HistoryScoringSignalsAnnotatorTest : public testing::Test {
+ public:
+  HistoryScoringSignalsAnnotatorTest() = default;
+
+  AutocompleteProviderClient* client() { return client_.get(); }
+  AutocompleteScoringSignalsAnnotator* annotator() { return annotator_.get(); }
+  AutocompleteResult* result() { return result_.get(); }
+
+  void SetUp() override;
+  void TearDown() override;
+
+ private:
+  void FillHistoryDbData();
+  void CreateAutocompleteResult();
+
+  base::ScopedTempDir history_dir_;
+  base::test::TaskEnvironment task_environment_;
+  std::unique_ptr<FakeAutocompleteProviderClient> client_;
+  std::unique_ptr<HistoryScoringSignalsAnnotator> annotator_;
+  std::unique_ptr<AutocompleteResult> result_;
+};
+
+void HistoryScoringSignalsAnnotatorTest::SetUp() {
+  client_ = std::make_unique<FakeAutocompleteProviderClient>();
+  CHECK(history_dir_.CreateUniqueTempDir());
+  client_->set_history_service(history::CreateHistoryService(
+      history_dir_.GetPath(), /*create_db=*/true));
+  client_->set_bookmark_model(bookmarks::TestBookmarkClient::CreateModel());
+  client_->set_template_url_service(
+      std::make_unique<TemplateURLService>(nullptr, 0));
+  annotator_ = std::make_unique<HistoryScoringSignalsAnnotator>(client_.get());
+  FillHistoryDbData();
+  CreateAutocompleteResult();
+}
+
+void HistoryScoringSignalsAnnotatorTest::FillHistoryDbData() {
+  const base::Time now = base::Time::Now();
+  history::URLRow row_1 = CreateUrlRow("http://test.com/", u"A Title", 2, 5,
+                                       now - base::Days(1), 1);
+  history::URLRow row_2 = CreateUrlRow(
+      "http://test.com/path", u"A Title - Path", 1, 1, now - base::Days(2), 2);
+  client_->GetHistoryService()->InMemoryDatabase()->AddURL(row_1);
+  client_->GetHistoryService()->InMemoryDatabase()->AddURL(row_2);
+}
+
+void HistoryScoringSignalsAnnotatorTest::CreateAutocompleteResult() {
+  AutocompleteMatch url_match;
+  url_match.destination_url = GURL("http://test.com/");
+  url_match.type = AutocompleteMatchType::HISTORY_URL;
+
+  // Search matches will be skipped for annotation.
+  AutocompleteMatch search_match;
+  search_match.type = AutocompleteMatchType::SEARCH_HISTORY;
+
+  std::vector<AutocompleteMatch> matches{url_match, search_match};
+  result_ = std::make_unique<AutocompleteResult>();
+  result_->AppendMatches(matches);
+}
+
+void HistoryScoringSignalsAnnotatorTest::TearDown() {
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(HistoryScoringSignalsAnnotatorTest, AnnotateResult) {
+  AutocompleteInput input(u"a ti xyz", std::u16string::npos,
+                          metrics::OmniboxEventProto::OTHER,
+                          TestSchemeClassifier());
+
+  annotator()->AnnotateResult(input, result());
+  EXPECT_EQ(result()->match_at(0)->scoring_signals.typed_count(), 2);
+  EXPECT_EQ(result()->match_at(0)->scoring_signals.visit_count(), 5);
+  EXPECT_TRUE(
+      result()->match_at(0)->scoring_signals.elapsed_time_last_visit_secs() >
+      0);
+  EXPECT_EQ(result()->match_at(0)->scoring_signals.total_title_match_length(),
+            3);
+  EXPECT_EQ(
+      result()->match_at(0)->scoring_signals.num_input_terms_matched_by_title(),
+      2);
+  EXPECT_FALSE(result()->match_at(1)->scoring_signals.has_typed_count());
+  EXPECT_FALSE(result()
+                   ->match_at(1)
+                   ->scoring_signals.has_num_input_terms_matched_by_title());
+}
diff --git a/components/omnibox/browser/scored_history_match.cc b/components/omnibox/browser/scored_history_match.cc
index ca4f5e28..1c4cef8 100644
--- a/components/omnibox/browser/scored_history_match.cc
+++ b/components/omnibox/browser/scored_history_match.cc
@@ -475,6 +475,50 @@
 }
 
 // static
+size_t ScoredHistoryMatch::ComputeTotalMatchLength(
+    const WordStarts& terms_to_word_starts_offsets,
+    const TermMatches& matches,
+    const WordStarts& word_starts,
+    size_t num_words_to_allow) {
+  int total_match_length = 0;
+  auto next_word_starts = word_starts.begin();
+  auto end_word_starts = word_starts.end();
+  size_t word_num = 0;
+  for (const auto& match : matches) {
+    // Calculate the offset in the title string where the meaningful (word) part
+    // of the term starts.  This takes into account times when a term starts
+    // with punctuation such as "/foo".
+    const size_t term_word_offset =
+        match.offset + terms_to_word_starts_offsets[match.term_num];
+    // Advance next_word_starts until it's >= the position of the term we're
+    // considering (adjusted for where the word begins within the term).
+    while ((next_word_starts != end_word_starts) &&
+           (*next_word_starts < term_word_offset)) {
+      ++next_word_starts;
+      ++word_num;
+    }
+
+    // Only count up to the number of allowed words.
+    if (word_num >= num_words_to_allow) {
+      break;
+    }
+    total_match_length += match.length;
+  }
+  return total_match_length;
+}
+
+// static
+size_t ScoredHistoryMatch::CountUniqueMatchTerms(
+    const TermMatches& term_matches) {
+  // Find unique `term_num`s in term_matches
+  std::set<int> unique_term_nums;
+  for (const auto& match : term_matches) {
+    unique_term_nums.insert(match.term_num);
+  }
+  return unique_term_nums.size();
+}
+
+// static
 void ScoredHistoryMatch::Init() {
   static bool initialized = false;
 
@@ -552,7 +596,6 @@
   int32_t total_host_match_length = 0;
   int32_t total_path_match_length = 0;
   int32_t total_query_or_ref_match_length = 0;
-  int32_t total_title_match_length = 0;
 
   for (const auto& url_match : url_matches) {
     // Calculate the offset in the URL string where the meaningful (word) part
@@ -618,30 +661,15 @@
     total_url_match_length += url_match.length;
   }
   // Now do the analogous loop over all matches in the title.
-  next_word_starts = word_starts.title_word_starts_.begin();
-  end_word_starts = word_starts.title_word_starts_.end();
-  size_t word_num = 0;
   title_matches = FilterTermMatchesByWordStarts(
       title_matches, terms_to_word_starts_offsets,
       word_starts.title_word_starts_, 0, std::string::npos, true);
-  for (const auto& title_match : title_matches) {
-    // Calculate the offset in the title string where the meaningful (word) part
-    // of the term starts.  This takes into account times when a term starts
-    // with punctuation such as "/foo".
-    const size_t term_word_offset =
-        title_match.offset + terms_to_word_starts_offsets[title_match.term_num];
-    // Advance next_word_starts until it's >= the position of the term we're
-    // considering (adjusted for where the word begins within the term).
-    while ((next_word_starts != end_word_starts) &&
-           (*next_word_starts < term_word_offset)) {
-      ++next_word_starts;
-      ++word_num;
-    }
-    if (word_num >= num_title_words_to_allow_)
-      break;  // only count the first ten words
-    term_scores[title_match.term_num] += 8;
-    total_title_match_length += title_match.length;
-  }
+
+  size_t total_title_match_length = ComputeTotalMatchLength(
+      terms_to_word_starts_offsets, title_matches,
+      word_starts.title_word_starts_, num_title_words_to_allow_);
+  IncrementTitleMatchTermScores(terms_to_word_starts_offsets,
+                                word_starts.title_word_starts_, &term_scores);
 
   if (OmniboxFieldTrial::IsLogUrlScoringSignalsEnabled()) {
     scoring_signals.set_total_url_match_length(total_url_match_length);
@@ -651,21 +679,10 @@
         total_query_or_ref_match_length);
     scoring_signals.set_total_title_match_length(total_title_match_length);
 
-    // The number of matching input terms is determined by finding the count of
-    // unique `term_num`s in the vector of TermMatches.  This is done after all
-    // filtering of discarded matches is done, and then recorded to
-    // `scoring_signals`.
-    const auto count_unique_term_nums = [&](const TermMatches& term_matches) {
-      std::set<int> unique_term_nums;
-      for (const auto& match : term_matches) {
-        unique_term_nums.insert(match.term_num);
-      }
-      return unique_term_nums.size();
-    };
     scoring_signals.set_num_input_terms_matched_by_title(
-        count_unique_term_nums(title_matches));
+        CountUniqueMatchTerms(title_matches));
     scoring_signals.set_num_input_terms_matched_by_url(
-        count_unique_term_nums(url_matches));
+        CountUniqueMatchTerms(url_matches));
   }
 
   // TODO(mpearson): Restore logic for penalizing out-of-order matches.
@@ -693,6 +710,36 @@
   return final_topicality_score;
 }
 
+void ScoredHistoryMatch::IncrementTitleMatchTermScores(
+    const WordStarts& terms_to_word_starts_offsets,
+    const WordStarts& title_word_starts,
+    std::vector<int>* term_scores) {
+  auto next_word_starts = title_word_starts.begin();
+  auto end_word_starts = title_word_starts.end();
+  size_t word_num = 0;
+  for (const auto& title_match : title_matches) {
+    // Calculate the offset in the title string where the meaningful (word) part
+    // of the term starts.  This takes into account times when a term starts
+    // with punctuation such as "/foo".
+    const size_t term_word_offset =
+        title_match.offset + terms_to_word_starts_offsets[title_match.term_num];
+    // Advance next_word_starts until it's >= the position of the term we're
+    // considering (adjusted for where the word begins within the term).
+    while ((next_word_starts != end_word_starts) &&
+           (*next_word_starts < term_word_offset)) {
+      ++next_word_starts;
+      ++word_num;
+    }
+    if (word_num >= num_title_words_to_allow_) {
+      break;  // only count the first ten words
+    }
+    if (term_scores &&
+        term_scores->size() > static_cast<size_t>(title_match.term_num)) {
+      (*term_scores)[title_match.term_num] += 8;
+    }
+  }
+}
+
 float ScoredHistoryMatch::GetRecencyScore(int last_visit_days_ago) const {
   // Lookup the score in days_ago_to_recency_score, treating
   // everything older than what we've precomputed as the oldest thing
diff --git a/components/omnibox/browser/scored_history_match.h b/components/omnibox/browser/scored_history_match.h
index 341e744..deaefa9 100644
--- a/components/omnibox/browser/scored_history_match.h
+++ b/components/omnibox/browser/scored_history_match.h
@@ -91,6 +91,22 @@
       size_t end_pos,
       bool allow_midword_continuations = false);
 
+  // Computes the total length of term matches for the first max allowed number
+  // of words from the text being matched against.
+  //
+  // `terms_to_word_starts_offsets` contains the offsets of word starts in the
+  // input text being searched for. `matches` are term matches from the text
+  // being searched in (i.e. suggestion title), and `word_starts` contains the
+  // word starts within the text.
+  static size_t ComputeTotalMatchLength(
+      const WordStarts& terms_to_word_starts_offsets,
+      const TermMatches& matches,
+      const WordStarts& word_starts,
+      size_t num_words_to_allow);
+
+  // Count the number of unique matching terms.
+  static size_t CountUniqueMatchTerms(const TermMatches& term_matches);
+
   // An interim score taking into consideration location and completeness
   // of the match.
   int raw_score = 0;
@@ -139,6 +155,13 @@
                            const WordStarts& terms_to_word_starts_offsets,
                            const RowWordStarts& word_starts);
 
+  // Increment term scores based on title matches.
+  // Only uses the first `num_title_words_to_allow_` matches.
+  void IncrementTitleMatchTermScores(
+      const WordStarts& terms_to_word_starts_offsets,
+      const WordStarts& title_word_starts,
+      std::vector<int>* term_scores);
+
   // Returns a recency score based on |last_visit_days_ago|, which is
   // how many days ago the page was last visited.
   float GetRecencyScore(int last_visit_days_ago) const;
diff --git a/components/omnibox/browser/search_suggestion_parser.cc b/components/omnibox/browser/search_suggestion_parser.cc
index 62d5907..df3fdf6 100644
--- a/components/omnibox/browser/search_suggestion_parser.cc
+++ b/components/omnibox/browser/search_suggestion_parser.cc
@@ -31,6 +31,7 @@
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/suggestion_group_util.h"
 #include "components/omnibox/browser/url_prefix.h"
+#include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_fixer.h"
 #include "components/url_formatter/url_formatter.h"
 #include "net/http/http_response_headers.h"
@@ -38,6 +39,7 @@
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/omnibox_proto/entity_info.pb.h"
 #include "ui/base/device_form_factor.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "url/url_constants.h"
 
 namespace {
@@ -785,8 +787,16 @@
             continue;
         }
         if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_DESKTOP) {
-          annotation = has_equals_prefix ? suggestion : match_contents;
-          match_contents = query;
+          if (OmniboxFieldTrial::IsUniformRowHeightEnabled()) {
+            // If calculator results are going to be displayed on 1 line,
+            // keep everything in the match contents
+            match_contents = l10n_util::GetStringFUTF16(
+                IDS_OMNIBOX_ONE_LINE_CALCULATOR_SUGGESTION_TEMPLATE, query,
+                suggestion);
+          } else {
+            annotation = has_equals_prefix ? suggestion : match_contents;
+            match_contents = query;
+          }
         }
       }
 
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc
index 20d192a0..e43f380 100644
--- a/components/omnibox/browser/url_index_private_data.cc
+++ b/components/omnibox/browser/url_index_private_data.cc
@@ -169,10 +169,10 @@
             base::UnescapeRule::SPACES | base::UnescapeRule::PATH_SEPARATORS |
                 base::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS));
 
-    // Extract individual 'words' (as opposed to 'terms'; see comment in
-    // HistoryIdsToScoredMatches()) from the search string. When the user types
-    // "colspec=ID%20Mstone Release" we get four 'words': "colspec", "id",
-    // "mstone" and "release".
+    // Extract individual 'words' (as opposed to 'terms'; see the declaration
+    // comment in `GetTermsAndWordStartsOffsets()`) from the search string. When
+    // the user types "colspec=ID%20Mstone Release" we get four 'words':
+    // "colspec", "id", "mstone" and "release".
     String16Vector lower_words(
         String16VectorFromString16(lower_unescaped_string, nullptr));
     if (lower_words.empty())
@@ -631,15 +631,8 @@
   if (history_ids.empty())
     return;
 
-  // Break up the raw search string (complete with escaped URL elements) into
-  // 'terms' (as opposed to 'words'; see comment in HistoryItemsForTerms()).
-  // We only want to break up the search string on 'true' whitespace rather than
-  // escaped whitespace.  For example, when the user types
-  // "colspec=ID%20Mstone Release" we get two 'terms': "colspec=id%20mstone" and
-  // "release".
-  String16Vector lower_raw_terms =
-      base::SplitString(lower_raw_string, base::kWhitespaceUTF16,
-                        base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  auto [lower_raw_terms, lower_terms_to_word_starts_offsets] =
+      GetTermsAndWordStartsOffsets(lower_raw_string);
 
   // Don't score matches when there are no terms to score against.  (It's
   // possible that the word break iterater that extracts words to search for in
@@ -648,12 +641,9 @@
   // reasonable order to matches when there are no terms (i.e., all the words
   // are some form of whitespace), but this is such a rare edge case that it's
   // not worth the time.
-  if (lower_raw_terms.empty())
+  if (lower_raw_terms.empty()) {
     return;
-
-  WordStarts lower_terms_to_word_starts_offsets;
-  CalculateWordStartsOffsets(lower_raw_terms,
-                             &lower_terms_to_word_starts_offsets);
+  }
 
   // Filter bad matches and other matches we don't want to display.
   base::EraseIf(history_ids, [&](const HistoryID history_id) {
@@ -947,6 +937,23 @@
          base::trace_event::EstimateMemoryUsage(history_id_set_);
 }
 
+// static
+std::pair<String16Vector, WordStarts>
+URLIndexPrivateData::GetTermsAndWordStartsOffsets(
+    const std::u16string& lower_raw_string) {
+  String16Vector lower_raw_terms =
+      base::SplitString(lower_raw_string, base::kWhitespaceUTF16,
+                        base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  if (lower_raw_terms.empty()) {
+    return {{}, {}};
+  }
+
+  WordStarts lower_terms_to_word_starts_offsets;
+  CalculateWordStartsOffsets(lower_raw_terms,
+                             &lower_terms_to_word_starts_offsets);
+  return {lower_raw_terms, lower_terms_to_word_starts_offsets};
+}
+
 URLIndexPrivateData::SearchTermCacheItem::~SearchTermCacheItem() = default;
 
 // URLIndexPrivateData::HistoryItemFactorGreater -------------------------------
diff --git a/components/omnibox/browser/url_index_private_data.h b/components/omnibox/browser/url_index_private_data.h
index a7d05373..5fe94b8c 100644
--- a/components/omnibox/browser/url_index_private_data.h
+++ b/components/omnibox/browser/url_index_private_data.h
@@ -130,6 +130,16 @@
   // See base/trace_event/memory_usage_estimator.h for more info.
   size_t EstimateMemoryUsage() const;
 
+  // Break up the raw search string (complete with escaped URL elements) into
+  // 'terms' (as opposed to 'words'; see comment in HistoryItemsForTerms()).
+  // We only want to break up the search string on 'true' whitespace rather than
+  // escaped whitespace.  For example, when the user types
+  // "colspec=ID%20Mstone Release" we get two 'terms': "colspec=id%20mstone" and
+  // "release".
+  // Also returns word starts in each term.
+  static std::pair<String16Vector, WordStarts> GetTermsAndWordStartsOffsets(
+      const std::u16string& lower_raw_string);
+
  private:
   friend class base::RefCountedThreadSafe<URLIndexPrivateData>;
   ~URLIndexPrivateData();
diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp
index 2aa2ef2..05c94ce 100644
--- a/components/omnibox_strings.grdp
+++ b/components/omnibox_strings.grdp
@@ -247,4 +247,8 @@
   <message name="IDS_OMNIBOX_TAB_SEARCH_NO_RESULTS_FOUND" desc = "The string displayed as the first row in the Omnibox when no results are found in Tab Search mode.">
     No results found
   </message>
+
+  <message name="IDS_OMNIBOX_ONE_LINE_CALCULATOR_SUGGESTION_TEMPLATE" desc = "The string displayed when a calculator answer is suggested.">
+    <ph name="EXPRESSION">$1</ph> = <ph name="ANSWER">$2</ph>
+  </message>
 </grit-part>
diff --git a/components/omnibox_strings_grdp/IDS_OMNIBOX_ONE_LINE_CALCULATOR_SUGGESTION_TEMPLATE.png.sha1 b/components/omnibox_strings_grdp/IDS_OMNIBOX_ONE_LINE_CALCULATOR_SUGGESTION_TEMPLATE.png.sha1
new file mode 100644
index 0000000..a63f72b
--- /dev/null
+++ b/components/omnibox_strings_grdp/IDS_OMNIBOX_ONE_LINE_CALCULATOR_SUGGESTION_TEMPLATE.png.sha1
@@ -0,0 +1 @@
+6f6699b8635f8d6ee392cd330e5e6924b09e80c8
\ No newline at end of file
diff --git a/components/performance_manager/features.cc b/components/performance_manager/features.cc
index f0fcbb6..71cdb9ea 100644
--- a/components/performance_manager/features.cc
+++ b/components/performance_manager/features.cc
@@ -82,7 +82,7 @@
 
 BASE_FEATURE(kBFCachePerformanceManagerPolicy,
              "BFCachePerformanceManagerPolicy",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kUrgentPageDiscarding,
              "UrgentPageDiscarding",
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc
index b2e78f8c..f67dfc4d 100644
--- a/components/viz/service/display/dc_layer_overlay.cc
+++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -314,12 +314,12 @@
   return false;
 }
 
-gfx::Rect CalculateOccludingDamageRect(
+bool HasOccludingDamageRect(
     const SharedQuadState* shared_quad_state,
     const SurfaceDamageRectList& surface_damage_rect_list,
-    const gfx::Rect& quad_rect_in_root_target_space) {
+    const gfx::Rect& quad_rect_in_root_space) {
   if (!shared_quad_state->overlay_damage_index.has_value())
-    return quad_rect_in_root_target_space;
+    return !quad_rect_in_root_space.IsEmpty();
 
   size_t overlay_damage_index = shared_quad_state->overlay_damage_index.value();
   if (overlay_damage_index >= surface_damage_rect_list.size()) {
@@ -334,9 +334,9 @@
   for (size_t i = 0; i < overlay_damage_index; ++i) {
     occluding_damage_rect.Union(surface_damage_rect_list[i]);
   }
-  occluding_damage_rect.Intersect(quad_rect_in_root_target_space);
+  occluding_damage_rect.Intersect(quad_rect_in_root_space);
 
-  return occluding_damage_rect;
+  return !occluding_damage_rect.IsEmpty();
 }
 
 bool IsFullScreenLetterboxing(const QuadList::Iterator& it,
@@ -532,10 +532,7 @@
 }
 
 void DCLayerOverlayProcessor::RemoveOverlayDamageRect(
-    const QuadList::Iterator& it,
-    const gfx::Rect& quad_rectangle,
-    const gfx::Rect& occluding_damage_rect,
-    gfx::Rect* damage_rect) {
+    const QuadList::Iterator& it) {
   // This is done by setting the overlay surface damage rect in the
   // |surface_damage_rect_list_| to zero.
   if (it->shared_quad_state->overlay_damage_index.has_value()) {
@@ -949,22 +946,21 @@
       }
     }
 
-    // Get the occluding damage rect for underlay.
-    gfx::Rect occluding_damage_rect;
-    if (!is_overlay) {
-      occluding_damage_rect = CalculateOccludingDamageRect(
-          it->shared_quad_state, surface_damage_rect_list_,
-          quad_rectangle_in_target_space);
+    gfx::Rect quad_rectangle_in_root_space =
+        cc::MathUtil::MapEnclosingClippedRect(
+            render_pass->transform_to_root_target,
+            quad_rectangle_in_target_space);
 
-      // Used by a histogram.
-      if (!occluding_damage_rect.IsEmpty())
-        this_frame_has_occluding_damage_rect = true;
-    }
+    // Used by a histogram.
+    this_frame_has_occluding_damage_rect =
+        !is_overlay &&
+        HasOccludingDamageRect(it->shared_quad_state, surface_damage_rect_list_,
+                               quad_rectangle_in_root_space);
 
     UpdateDCLayerOverlays(display_rect, render_pass, it,
-                          quad_rectangle_in_target_space, occluding_damage_rect,
-                          is_overlay, &prev_it, &prev_index, damage_rect,
-                          dc_layer_overlays, is_page_fullscreen_mode);
+                          quad_rectangle_in_root_space, is_overlay, &prev_it,
+                          &prev_index, damage_rect, dc_layer_overlays,
+                          is_page_fullscreen_mode);
   }
 
   // Update previous frame state after processing root pass. If there is no
@@ -1050,8 +1046,7 @@
     const gfx::RectF& display_rect,
     AggregatedRenderPass* render_pass,
     const QuadList::Iterator& it,
-    const gfx::Rect& quad_rectangle_in_target_space,
-    const gfx::Rect& occluding_damage_rect,
+    const gfx::Rect& quad_rectangle_in_root_space,
     bool is_overlay,
     QuadList::Iterator* new_it,
     size_t* new_index,
@@ -1081,23 +1076,18 @@
       NOTREACHED();
   }
 
-  // Underlays are less efficient, so attempt regular overlays first. Only
-  // check root render pass because we can only check for occlusion within a
-  // render pass.
+  // Underlays are less efficient, so attempt regular overlays first. We can
+  // only check for occlusion within a render pass.
   if (is_overlay) {
-    *new_it =
-        ProcessForOverlay(display_rect, render_pass,
-                          quad_rectangle_in_target_space, it, damage_rect);
+    *new_it = ProcessForOverlay(display_rect, render_pass, it);
     (*new_index)++;
   } else {
-    ProcessForUnderlay(display_rect, render_pass,
-                       quad_rectangle_in_target_space, occluding_damage_rect,
+    ProcessForUnderlay(display_rect, render_pass, quad_rectangle_in_root_space,
                        it, dc_layer_overlays->size(), damage_rect, &dc_layer);
   }
 
-  gfx::Rect rect_in_root = cc::MathUtil::MapEnclosingClippedRect(
-      render_pass->transform_to_root_target, quad_rectangle_in_target_space);
-  current_frame_overlay_rects_.push_back({rect_in_root, is_overlay});
+  current_frame_overlay_rects_.push_back(
+      {quad_rectangle_in_root_space, is_overlay});
 
   dc_layer_overlays->push_back(dc_layer);
 
@@ -1108,9 +1098,7 @@
 QuadList::Iterator DCLayerOverlayProcessor::ProcessForOverlay(
     const gfx::RectF& display_rect,
     AggregatedRenderPass* render_pass,
-    const gfx::Rect& quad_rectangle,
-    const QuadList::Iterator& it,
-    gfx::Rect* damage_rect) {
+    const QuadList::Iterator& it) {
   // The quad is on top, so promote it to an overlay and remove all damage
   // underneath it.
   const bool display_rect_changed = (display_rect != previous_display_rect_);
@@ -1119,8 +1107,7 @@
   const bool needs_blending = it->ShouldDrawWithBlending();
 
   if (is_axis_aligned && !display_rect_changed && !needs_blending) {
-    RemoveOverlayDamageRect(it, quad_rectangle,
-                            /*occluding_damage_rect=*/gfx::Rect(), damage_rect);
+    RemoveOverlayDamageRect(it);
   }
 
   return render_pass->quad_list.EraseAndInvalidateAllPointers(it);
@@ -1130,7 +1117,6 @@
     const gfx::RectF& display_rect,
     AggregatedRenderPass* render_pass,
     const gfx::Rect& quad_rectangle,
-    const gfx::Rect& occluding_damage_rect,
     const QuadList::Iterator& it,
     size_t processed_overlay_count,
     gfx::Rect* damage_rect,
@@ -1186,8 +1172,7 @@
     // these quads. The output root damage rect might be empty after we remove
     // the damage from the video quad. We can save power if the root damage
     // rect is empty.
-    RemoveOverlayDamageRect(it, quad_rectangle, occluding_damage_rect,
-                            damage_rect);
+    RemoveOverlayDamageRect(it);
   } else {
     // Entire replacement quad must be redrawn.
     damage_rect->Union(quad_rectangle);
diff --git a/components/viz/service/display/dc_layer_overlay.h b/components/viz/service/display/dc_layer_overlay.h
index 82c6908c..f7cde87 100644
--- a/components/viz/service/display/dc_layer_overlay.h
+++ b/components/viz/service/display/dc_layer_overlay.h
@@ -126,8 +126,7 @@
       const gfx::RectF& display_rect,
       AggregatedRenderPass* render_pass,
       const QuadList::Iterator& it,
-      const gfx::Rect& quad_rectangle_in_target_space,
-      const gfx::Rect& occluding_damage_rect,
+      const gfx::Rect& quad_rectangle_in_root_space,
       bool is_overlay,
       QuadList::Iterator* new_it,
       size_t* new_index,
@@ -138,13 +137,10 @@
   // Returns an iterator to the element after |it|.
   QuadList::Iterator ProcessForOverlay(const gfx::RectF& display_rect,
                                        AggregatedRenderPass* render_pass,
-                                       const gfx::Rect& quad_rectangle,
-                                       const QuadList::Iterator& it,
-                                       gfx::Rect* damage_rect);
+                                       const QuadList::Iterator& it);
   void ProcessForUnderlay(const gfx::RectF& display_rect,
                           AggregatedRenderPass* render_pass,
                           const gfx::Rect& quad_rectangle,
-                          const gfx::Rect& occluding_damage_rect,
                           const QuadList::Iterator& it,
                           size_t processed_overlay_count,
                           gfx::Rect* damage_rect,
@@ -153,10 +149,7 @@
   void UpdateRootDamageRect(const gfx::RectF& display_rect,
                             gfx::Rect* damage_rect);
 
-  void RemoveOverlayDamageRect(const QuadList::Iterator& it,
-                               const gfx::Rect& quad_rectangle,
-                               const gfx::Rect& occluding_damage_rect,
-                               gfx::Rect* damage_rect);
+  void RemoveOverlayDamageRect(const QuadList::Iterator& it);
 
   void InsertDebugBorderDrawQuad(
       const std::vector<DCLayerOverlayCandidate>* dc_layer_overlays,
diff --git a/components/viz/service/display/overlay_dc_unittest.cc b/components/viz/service/display/overlay_dc_unittest.cc
index 5f95557a..a3ff967 100644
--- a/components/viz/service/display/overlay_dc_unittest.cc
+++ b/components/viz/service/display/overlay_dc_unittest.cc
@@ -236,6 +236,8 @@
     output_surface_ = nullptr;
   }
 
+  void TestRenderPassRootTransform(bool is_overlay);
+
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<MockDCLayerOutputSurface> output_surface_;
   cc::FakeOutputSurfaceClient output_surface_client_;
@@ -1209,5 +1211,85 @@
   }
 }
 
+TEST_F(DCLayerOverlayTest, RenderPassRootTransformOverlay) {
+  TestRenderPassRootTransform(/*is_overlay*/ true);
+}
+
+TEST_F(DCLayerOverlayTest, RenderPassRootTransformUnderlay) {
+  TestRenderPassRootTransform(/*is_overlay*/ false);
+}
+
+// Tests processing overlays/underlays in a render pass that contains a
+// non-identity transform to root.
+void DCLayerOverlayTest::TestRenderPassRootTransform(bool is_overlay) {
+  const gfx::Rect kOutputRect = gfx::Rect(0, 0, 256, 256);
+  const gfx::Rect kVideoRect = gfx::Rect(0, 0, 100, 100);
+  const gfx::Rect kOpaqueRect = gfx::Rect(90, 80, 15, 30);
+  const gfx::Transform kRenderPassToRootTransform =
+      gfx::Transform::MakeTranslation(27, 45);
+  const SurfaceDamageRectList kSurfaceDamageRectList = {
+      gfx::Rect(25, 20, 10, 10),    // above overlay
+      gfx::Rect(27, 45, 100, 100),  // damage rect of video overlay
+      gfx::Rect(30, 25, 50, 50)};   // below overlay
+  const size_t kOverlayDamageIndex = 1;
+
+  for (size_t frame = 0; frame < 3; frame++) {
+    auto pass = CreateRenderPass();
+    pass->transform_to_root_target = kRenderPassToRootTransform;
+    pass->shared_quad_state_list.back()->overlay_damage_index =
+        kOverlayDamageIndex;
+
+    if (!is_overlay) {
+      // Create a quad that occludes the video to force it to an underlay.
+      CreateOpaqueQuadAt(resource_provider_.get(),
+                         pass->shared_quad_state_list.back(), pass.get(),
+                         kOpaqueRect, SkColors::kWhite);
+    }
+
+    auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
+        resource_provider_.get(), child_resource_provider_.get(),
+        child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
+    video_quad->rect = gfx::Rect(kVideoRect);
+    video_quad->visible_rect = video_quad->rect;
+
+    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+    OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+    AggregatedRenderPassList pass_list;
+    pass_list.push_back(std::move(pass));
+    SurfaceDamageRectList surface_damage_rect_list = kSurfaceDamageRectList;
+
+    damage_rect_ = kOutputRect;
+    overlay_processor_->ProcessForOverlays(
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_backdrop_filters,
+        std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
+        &damage_rect_, &content_bounds_);
+    LOG(INFO) << damage_rect_.ToString();
+
+    EXPECT_EQ(dc_layer_list.size(), 1u);
+    EXPECT_EQ(dc_layer_list[0].transform, kRenderPassToRootTransform);
+    if (is_overlay) {
+      EXPECT_GT(dc_layer_list[0].z_order, 0);
+    } else {
+      EXPECT_LT(dc_layer_list[0].z_order, 0);
+    }
+
+    if (frame == 0) {
+      // On the first frame, the damage rect should be unchanged since the
+      // overlays are being processed for the first time.
+      EXPECT_EQ(gfx::Rect(0, 0, 256, 256), damage_rect_);
+    } else {
+      // With the render pass to root transform, the video overlay should have
+      // been translated to (27,45 100x100). The final damage rect should
+      // include (25,20 10x10), which doesn't intersect the overlay. The
+      // (30,25 50x50) surface damage is partially under the overlay, so the
+      // overlay damage can be subtracted to become (30,25 50x15). The final
+      // damage rect is (25,20 10x10) union (30,25 50x15).
+      EXPECT_EQ(damage_rect_, gfx::Rect(25, 20, 55, 25));
+    }
+  }
+}
+
 }  // namespace
 }  // namespace viz
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 76807a5..3e9cc8c0 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -192,6 +192,10 @@
 #endif
     // Allow BackForwardCache for all devices regardless of their memory.
     DisableFeature(features::kBackForwardCacheMemoryControls);
+    // Disables BackForwardCache cache size overwritten by
+    // `content::kBackForwardCacheSize`, as many browser tests here assume
+    // specific or smaller cache size (e.g. 1) rather than 6.
+    DisableFeature(kBackForwardCacheSize);
 
     SetupFeaturesAndParameters();
 
diff --git a/content/browser/back_forward_cache_no_store_browsertest.cc b/content/browser/back_forward_cache_no_store_browsertest.cc
index 9cf13b9..f1f2209 100644
--- a/content/browser/back_forward_cache_no_store_browsertest.cc
+++ b/content/browser/back_forward_cache_no_store_browsertest.cc
@@ -978,15 +978,16 @@
                                     /*url=*/url_a_2.spec(),
                                     /*reasons=*/{"AuthorizationHeader"},
                                     /*children=*/{}));
-  EXPECT_THAT(current_frame_host()->NotRestoredReasonsForTesting(),
-              MatchesNotRestoredReasons(
-                  blink::mojom::BFCacheBlocked::kYes,
-                  /*id=*/"", /*name=*/"", /*src=*/"",
-                  MatchesSameOriginDetails(
-                      /*url=*/url_a_no_store.spec(),
-                      /*reasons=*/{"MainResourceHasCacheControlNoStore"},
-                      /*children=*/
-                      {subframe_result})));
+  EXPECT_THAT(
+      current_frame_host()->NotRestoredReasonsForTesting(),
+      MatchesNotRestoredReasons(
+          blink::mojom::BFCacheBlocked::kYes,
+          /*id=*/absl::nullopt, /*name=*/absl::nullopt, /*src=*/absl::nullopt,
+          MatchesSameOriginDetails(
+              /*url=*/url_a_no_store.spec(),
+              /*reasons=*/{"MainResourceHasCacheControlNoStore"},
+              /*children=*/
+              {subframe_result})));
 }
 
 // Test that a page with CCNS that makes a request with the "Authorization"
diff --git a/content/browser/back_forward_cache_not_restored_reasons_browsertest.cc b/content/browser/back_forward_cache_not_restored_reasons_browsertest.cc
index 00c1260..3c9f2d6 100644
--- a/content/browser/back_forward_cache_not_restored_reasons_browsertest.cc
+++ b/content/browser/back_forward_cache_not_restored_reasons_browsertest.cc
@@ -22,12 +22,6 @@
 class BackForwardCacheBrowserTestWithNotRestoredReasons
     : public BackForwardCacheBrowserTest {};
 
-namespace {
-// TODO(crbug.com/1402594): Expect |absl::nullopt| instead of an empty string
-// for non existing attributes.
-const std::string kMissingAttribute = "";
-}  // namespace
-
 // NotRestoredReasons are not reported when the page is successfully restored
 // from back/forward cache.
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithNotRestoredReasons,
@@ -72,8 +66,8 @@
                     {}, {}, FROM_HERE);
   // Expect that NotRestoredReasons are reported.
   auto rfh_a_result = MatchesNotRestoredReasons(
-      blink::mojom::BFCacheBlocked::kYes, /*id=*/kMissingAttribute,
-      /*name=*/kMissingAttribute, /*src=*/kMissingAttribute,
+      blink::mojom::BFCacheBlocked::kYes, /*id=*/absl::nullopt,
+      /*name=*/absl::nullopt, /*src=*/absl::nullopt,
       MatchesSameOriginDetails(
           /*url=*/rfh_a_url, /*reasons=*/{"Dummy"}, /*children=*/{}));
   EXPECT_THAT(current_frame_host()->NotRestoredReasonsForTesting(),
@@ -143,8 +137,8 @@
       MatchesSameOriginDetails(
           /*url=*/rfh_a_2_url, /*reasons=*/{}, /*children=*/{}));
   auto rfh_a_1_result = MatchesNotRestoredReasons(
-      blink::mojom::BFCacheBlocked::kNo, /*id=*/kMissingAttribute,
-      /*name=*/kMissingAttribute, /*src=*/kMissingAttribute,
+      blink::mojom::BFCacheBlocked::kNo, /*id=*/absl::nullopt,
+      /*name=*/absl::nullopt, /*src=*/absl::nullopt,
       MatchesSameOriginDetails(
           /*url=*/rfh_a_1_url,
           /*reasons=*/{},
@@ -189,10 +183,13 @@
   ExpectNotRestored({NotRestoredReason::kBlocklistedFeatures},
                     {blink::scheduler::WebSchedulerTrackedFeature::kDummy}, {},
                     {}, {}, FROM_HERE);
-
+  // Frames generated by cross_site_iframe_factory.html have empty names instead
+  // of null.
+  EXPECT_EQ(true, EvalJs(current_frame_host(),
+                         "document.getElementById('child-0').name == ''"));
   auto rfh_a_2_result =
       MatchesNotRestoredReasons(blink::mojom::BFCacheBlocked::kYes,
-                                /*id=*/"child-0", /*name=*/kMissingAttribute,
+                                /*id=*/"child-0", /*name=*/"",
                                 /*src=*/rfh_a_2_url,
                                 MatchesSameOriginDetails(
                                     /*url=*/rfh_a_2_url,
@@ -200,22 +197,24 @@
                                     /*children=*/{}));
   auto rfh_a_4_result =
       MatchesNotRestoredReasons(blink::mojom::BFCacheBlocked::kYes,
-                                /*id=*/"child-0", /*name=*/kMissingAttribute,
+                                /*id=*/"child-0", /*name=*/"",
                                 /*src=*/rfh_a_4_url,
                                 MatchesSameOriginDetails(
                                     /*url=*/rfh_a_4_url,
                                     /*reasons=*/{"Dummy"},
                                     /*children=*/{}));
+  EXPECT_EQ(true, EvalJs(current_frame_host(),
+                         "document.getElementById('child-1').name == ''"));
   auto rfh_a_3_result = MatchesNotRestoredReasons(
       blink::mojom::BFCacheBlocked::kNo, /*id=*/"child-1",
-      /*name=*/kMissingAttribute,
+      /*name=*/"",
       /*src=*/rfh_a_3_url,
       MatchesSameOriginDetails(
           /*url=*/rfh_a_3_url,
           /*reasons=*/{}, /*children=*/{rfh_a_4_result}));
   auto rfh_a_1_result = MatchesNotRestoredReasons(
-      blink::mojom::BFCacheBlocked::kYes, /*id=*/kMissingAttribute,
-      /*name=*/kMissingAttribute, /*src=*/kMissingAttribute,
+      blink::mojom::BFCacheBlocked::kYes, /*id=*/absl::nullopt,
+      /*name=*/absl::nullopt, /*src=*/absl::nullopt,
       MatchesSameOriginDetails(
           /*url=*/rfh_a_1_url,
           /*reasons=*/{"Dummy"},
@@ -318,8 +317,8 @@
   // Both reasons are recorded and sent to the renderer.
   // BrowsingInstanceNotSwapped is masked as internal error.
   auto rfh_a_result = MatchesNotRestoredReasons(
-      blink::mojom::BFCacheBlocked::kYes, /*id=*/kMissingAttribute,
-      /*name=*/kMissingAttribute, /*src=*/kMissingAttribute,
+      blink::mojom::BFCacheBlocked::kYes, /*id=*/absl::nullopt,
+      /*name=*/absl::nullopt, /*src=*/absl::nullopt,
       MatchesSameOriginDetails(
           /*url=*/rfh_a_url,
           /*reasons=*/{"Related active contents", "Internal error"},
@@ -368,14 +367,15 @@
   auto reasons =
       navigation_request->commit_params().not_restored_reasons.Clone();
   // The reasons have not been reset yet.
-  auto rfh_a_result = MatchesNotRestoredReasons(
-      blink::mojom::BFCacheBlocked::kYes,
-      /*id=*/kMissingAttribute, /*name=*/kMissingAttribute,
-      /*src=*/kMissingAttribute,
-      MatchesSameOriginDetails(
-          /*url=*/url_a_redirect.spec(),
-          /*reasons=*/{"JavaScript execution"},
-          /*children=*/{}));
+  auto rfh_a_result =
+      MatchesNotRestoredReasons(blink::mojom::BFCacheBlocked::kYes,
+                                /*id=*/absl::nullopt, /*name=*/absl::nullopt,
+                                /*src=*/absl::nullopt,
+                                MatchesSameOriginDetails(
+                                    /*url=*/url_a_redirect.spec(),
+                                    /*reasons=*/{"JavaScript execution"},
+                                    /*children=*/{}));
+
   EXPECT_THAT(reasons, rfh_a_result);
 
   // Redirect happens, and now the reasons are reset.
diff --git a/content/browser/fenced_frame/fenced_frame_config.cc b/content/browser/fenced_frame/fenced_frame_config.cc
index f3e24d0..6437356 100644
--- a/content/browser/fenced_frame/fenced_frame_config.cc
+++ b/content/browser/fenced_frame/fenced_frame_config.cc
@@ -139,6 +139,10 @@
   RedactProperty(reporting_metadata_, entity,
                  redacted_config.reporting_metadata_);
 
+  // The mode never needs to be redacted, because it is a function of which API
+  // was called to generate the config, rather than any cross-site data.
+  redacted_config.mode_ = mode_;
+
   return redacted_config;
 }
 
@@ -165,7 +169,8 @@
       partition_nonce_(absl::in_place,
                        base::UnguessableToken::Create(),
                        VisibilityToEmbedder::kOpaque,
-                       VisibilityToContent::kOpaque) {
+                       VisibilityToContent::kOpaque),
+      mode_(config.mode_) {
   if (config.shared_storage_budget_metadata_) {
     shared_storage_budget_metadata_.emplace(
         &config.shared_storage_budget_metadata_->GetValueIgnoringVisibility(),
@@ -238,6 +243,10 @@
   RedactProperty(reporting_metadata_, entity,
                  redacted_properties.reporting_metadata_);
 
+  // The mode never needs to be redacted, because it is a function of which API
+  // was called to generate the config, rather than any cross-site data.
+  redacted_properties.mode_ = mode_;
+
   return redacted_properties;
 }
 
diff --git a/content/browser/fenced_frame/fenced_frame_config.h b/content/browser/fenced_frame/fenced_frame_config.h
index 66ec165..353e75bc 100644
--- a/content/browser/fenced_frame/fenced_frame_config.h
+++ b/content/browser/fenced_frame/fenced_frame_config.h
@@ -88,6 +88,7 @@
 GURL CONTENT_EXPORT GenerateUrnUuid();
 
 using AdAuctionData = blink::FencedFrame::AdAuctionData;
+using DeprecatedFencedFrameMode = blink::FencedFrame::DeprecatedFencedFrameMode;
 using ReportingMetadata = blink::FencedFrame::FencedFrameReporting;
 using SharedStorageBudgetMetadata =
     blink::FencedFrame::SharedStorageBudgetMetadata;
@@ -256,6 +257,14 @@
   // If reporting events from fenced frames are registered, then this
   // information gets filled here.
   absl::optional<FencedFrameProperty<ReportingMetadata>> reporting_metadata_;
+
+  // The mode for the resulting fenced frame: `kDefault` or `kOpaqueAds`.
+  // TODO(crbug.com/1347953): This field is currently unused. Replace the
+  // `mode` attribute of HTMLFencedFrameElement with this field in the config.
+  // TODO(crbug.com/1347953): Decompose this field into flags that directly
+  // control the behavior of the frame, e.g. sandbox flags. We do not want
+  // mode to exist as a concept going forward.
+  DeprecatedFencedFrameMode mode_ = DeprecatedFencedFrameMode::kDefault;
 };
 
 // Contains a set of fenced frame properties. These are generated at
@@ -327,6 +336,8 @@
   absl::optional<FencedFrameProperty<ReportingMetadata>> reporting_metadata_;
 
   absl::optional<FencedFrameProperty<base::UnguessableToken>> partition_nonce_;
+
+  DeprecatedFencedFrameMode mode_ = DeprecatedFencedFrameMode::kDefault;
 };
 
 }  // namespace content
diff --git a/content/browser/fenced_frame/redacted_fenced_frame_config_mojom_traits_unittest.cc b/content/browser/fenced_frame/redacted_fenced_frame_config_mojom_traits_unittest.cc
index f16bb002..76d0407 100644
--- a/content/browser/fenced_frame/redacted_fenced_frame_config_mojom_traits_unittest.cc
+++ b/content/browser/fenced_frame/redacted_fenced_frame_config_mojom_traits_unittest.cc
@@ -305,6 +305,42 @@
   }
 }
 
+TEST(FencedFrameConfigMojomTraitsTest, ConfigMojomTraitsModeTest) {
+  std::vector<blink::FencedFrame::DeprecatedFencedFrameMode> modes = {
+      blink::FencedFrame::DeprecatedFencedFrameMode::kDefault,
+      blink::FencedFrame::DeprecatedFencedFrameMode::kOpaqueAds,
+  };
+  std::vector<FencedFrameEntity> entities = {
+      FencedFrameEntity::kEmbedder,
+      FencedFrameEntity::kContent,
+  };
+  GURL test_url("test_url");
+  GURL test_urn = GenerateUrnUuid();
+  for (blink::FencedFrame::DeprecatedFencedFrameMode& mode : modes) {
+    FencedFrameConfig browser_config(test_urn, test_url);
+    browser_config.mode_ = mode;
+    FencedFrameProperties browser_properties(browser_config);
+    for (FencedFrameEntity& entity : entities) {
+      RedactedFencedFrameConfig input_config = browser_config.RedactFor(entity);
+      ASSERT_TRUE(browser_config.mode_ == input_config.mode());
+
+      RedactedFencedFrameConfig output_config;
+      mojo::test::SerializeAndDeserialize<blink::mojom::FencedFrameConfig>(
+          input_config, output_config);
+      ASSERT_TRUE(input_config.mode() == output_config.mode());
+
+      RedactedFencedFrameProperties input_properties =
+          browser_properties.RedactFor(entity);
+      ASSERT_TRUE(browser_properties.mode_ == input_properties.mode());
+
+      RedactedFencedFrameProperties output_properties;
+      mojo::test::SerializeAndDeserialize<blink::mojom::FencedFrameProperties>(
+          input_properties, output_properties);
+      ASSERT_TRUE(input_properties.mode() == output_properties.mode());
+    }
+  }
+}
+
 TEST(FencedFrameConfigMojomTraitsTest, ConfigMojomTraitsNullInternalUrnTest) {
   FencedFrameConfig browser_config;
   RedactedFencedFrameConfig input_config =
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 50ddf39..ab01d16 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -299,7 +299,7 @@
 #endif
 #if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
     switches::kHardwareVideoDecodeFrameRate,
-    switches::kMaxChromeOSDecoderThreads,
+    switches::kChromeOSVideoDecoderTaskRunner,
 #endif
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
     switches::kLacrosEnablePlatformHevc,
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc
index 8e3d0ce4..d579ecb4 100644
--- a/content/browser/preloading/prerender/prerender_browsertest.cc
+++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -8599,8 +8599,16 @@
                   ->has_received_user_gesture_before_nav());
 }
 
+// TODO(https://crbug.com/1408911): This test is flaky on Mac bots.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_CancelPrerenderWhenIsOverridingUserAgentDiffers \
+  DISABLED_CancelPrerenderWhenIsOverridingUserAgentDiffers
+#else
+#define MAYBE_CancelPrerenderWhenIsOverridingUserAgentDiffers \
+  CancelPrerenderWhenIsOverridingUserAgentDiffers
+#endif
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
-                       CancelPrerenderWhenIsOverridingUserAgentDiffers) {
+                       MAYBE_CancelPrerenderWhenIsOverridingUserAgentDiffers) {
   const std::string user_agent_override = "foo";
 
   // Navigate to an initial page.
diff --git a/content/browser/renderer_host/back_forward_cache_impl.cc b/content/browser/renderer_host/back_forward_cache_impl.cc
index 3b856b7..799ef74 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.cc
+++ b/content/browser/renderer_host/back_forward_cache_impl.cc
@@ -49,6 +49,27 @@
 
 class RenderProcessHostInternalObserver;
 
+// Allows overriding the sizes of back/forward cache.
+// Sizes set via this feature's parameters take precedence over others.
+BASE_FEATURE(kBackForwardCacheSize,
+             "BackForwardCacheSize",
+// Sets the BackForwardCache size for desktop.
+// See crbug.com/1291435.
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
+    BUILDFLAG(IS_CHROMEOS)
+             base::FEATURE_ENABLED_BY_DEFAULT
+#else
+             base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+);
+// Sets BackForwardCache cache_size=6 per crbug.com/1291435.
+const base::FeatureParam<int> kBackForwardCacheSizeCacheSize{
+    &kBackForwardCacheSize, "cache_size", 6};
+// Disables EnforceCacheSizeLimitInternal() with foreground_cache_size=0, as
+// the BFCachePolicy manager takes care of pruning for foreground tabs as well.
+const base::FeatureParam<int> kBackForwardCacheSizeForegroundCacheSize{
+    &kBackForwardCacheSize, "foreground_cache_size", 0};
+
 namespace {
 
 using blink::scheduler::WebSchedulerTrackedFeature;
@@ -568,10 +589,9 @@
 size_t BackForwardCacheImpl::GetCacheSize() {
   if (!IsBackForwardCacheEnabled())
     return 0;
-  auto cache_size = GetFieldTrialParamByFeatureAsOptionalInt(
-      kBackForwardCacheSize, "cache_size");
-  if (cache_size.has_value())
-    return cache_size.value();
+  if (base::FeatureList::IsEnabled(kBackForwardCacheSize)) {
+    return kBackForwardCacheSizeCacheSize.Get();
+  }
   return base::GetFieldTrialParamByFeatureAsInt(
       features::kBackForwardCache, "cache_size", kDefaultBackForwardCacheSize);
 }
@@ -580,10 +600,9 @@
 size_t BackForwardCacheImpl::GetForegroundedEntriesCacheSize() {
   if (!IsBackForwardCacheEnabled())
     return 0;
-  auto foreground_cache_size = GetFieldTrialParamByFeatureAsOptionalInt(
-      kBackForwardCacheSize, "foreground_cache_size");
-  if (foreground_cache_size.has_value())
-    return foreground_cache_size.value();
+  if (base::FeatureList::IsEnabled(kBackForwardCacheSize)) {
+    return kBackForwardCacheSizeForegroundCacheSize.Get();
+  }
   return base::GetFieldTrialParamByFeatureAsInt(
       features::kBackForwardCache, "foreground_cache_size",
       kDefaultForegroundBackForwardCacheSize);
diff --git a/content/browser/renderer_host/back_forward_cache_impl.h b/content/browser/renderer_host/back_forward_cache_impl.h
index 6b38d65..e3f7301 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.h
+++ b/content/browser/renderer_host/back_forward_cache_impl.h
@@ -71,11 +71,11 @@
              "BackForwardCacheTimeToLiveControl",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Allows overriding the sizes of back/forward cache.
-// Sizes set via this feature's parameters take precedence over others.
-BASE_FEATURE(kBackForwardCacheSize,
-             "BackForwardCacheSize",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kBackForwardCacheSize);
+CONTENT_EXPORT extern const base::FeatureParam<int>
+    kBackForwardCacheSizeCacheSize;
+CONTENT_EXPORT extern const base::FeatureParam<int>
+    kBackForwardCacheSizeForegroundCacheSize;
 
 // Combines a flattened list and a tree of the reasons why each document cannot
 // enter the back/forward cache (might be empty if it can). The tree saves the
@@ -121,12 +121,11 @@
 //       evicts the outermost frame after
 //       `kDefaultTimeToLiveInBackForwardCacheInSeconds` seconds.
 // 2. In `performance_manager::policies::BFCachePolicy`:
-//    A. (To Launch) [Desktop-only] On moderate memory pressure, the number of
-//       entries in a visible tab's cache is pruned to
+//    A. [Desktop-only] On moderate memory pressure, the number of entries in a
+//       visible tab's cache is pruned to
 //       `ForegroundCacheSizeOnModeratePressure()`. The number in a non-visible
 //       tab is pruned to `BackgroundCacheSizeOnModeratePressure()`.
-//    B. (To Launch) [Desktop-only] On critical memory pressure, the cache is
-//       cleared.
+//    B. [Desktop-only] On critical memory pressure, the cache is cleared.
 class CONTENT_EXPORT BackForwardCacheImpl
     : public BackForwardCache,
       public RenderProcessHostInternalObserver,
diff --git a/content/browser/renderer_host/back_forward_cache_impl_unittest.cc b/content/browser/renderer_host/back_forward_cache_impl_unittest.cc
index 2cce2163..cb4ef03c 100644
--- a/content/browser/renderer_host/back_forward_cache_impl_unittest.cc
+++ b/content/browser/renderer_host/back_forward_cache_impl_unittest.cc
@@ -108,9 +108,18 @@
 };
 
 TEST_F(BackForwardCacheActiveSizeTest, ActiveCacheSize) {
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
+    BUILDFLAG(IS_CHROMEOS)
+  // The default cache sizes specified by kBackForwardCacheSize takes precedence
+  // over kBackForwardCache.
+  EXPECT_EQ(BackForwardCacheImpl::GetCacheSize(), 6u);
+  EXPECT_EQ(BackForwardCacheImpl::GetForegroundedEntriesCacheSize(), 0u);
+  EXPECT_FALSE(BackForwardCacheImpl::UsingForegroundBackgroundCacheSizeLimit());
+#else
   EXPECT_EQ(BackForwardCacheImpl::GetCacheSize(), 6u);
   EXPECT_EQ(BackForwardCacheImpl::GetForegroundedEntriesCacheSize(), 2u);
   EXPECT_TRUE(BackForwardCacheImpl::UsingForegroundBackgroundCacheSizeLimit());
+#endif
 }
 
 // Covers overwriting BackForwardCache's cache size-related values.
@@ -160,9 +169,17 @@
 };
 
 TEST_F(BackForwardCacheDefaultSizeTest, DefaultCacheSize) {
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
+    BUILDFLAG(IS_CHROMEOS)
+  // Default cache sizes are specified by kBackForwardCacheSize.
+  EXPECT_EQ(BackForwardCacheImpl::GetCacheSize(), 6u);
+  EXPECT_EQ(BackForwardCacheImpl::GetForegroundedEntriesCacheSize(), 0u);
+  EXPECT_FALSE(BackForwardCacheImpl::UsingForegroundBackgroundCacheSizeLimit());
+#else
   EXPECT_EQ(BackForwardCacheImpl::GetCacheSize(), 1u);
   EXPECT_EQ(BackForwardCacheImpl::GetForegroundedEntriesCacheSize(), 0u);
   EXPECT_FALSE(BackForwardCacheImpl::UsingForegroundBackgroundCacheSizeLimit());
+#endif
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/frame_tree_browsertest.cc b/content/browser/renderer_host/frame_tree_browsertest.cc
index 6647e58..1bf961e 100644
--- a/content/browser/renderer_host/frame_tree_browsertest.cc
+++ b/content/browser/renderer_host/frame_tree_browsertest.cc
@@ -54,8 +54,8 @@
 // Expect that frame_name, id and src match the node's values.
 void ExpectAttributesEq(FrameTreeNode* node,
                         const std::string& frame_name,
-                        const std::string& id,
-                        const std::string& src) {
+                        const absl::optional<std::string> id,
+                        const absl::optional<std::string> src) {
   EXPECT_EQ(frame_name, node->frame_name());
   EXPECT_EQ(id, node->html_id());
   EXPECT_EQ(src, node->html_src());
@@ -113,7 +113,7 @@
 
   // Check that the root node is properly created.
   ASSERT_EQ(3UL, root->child_count());
-  ExpectAttributesEq(root, std::string(), std::string(), std::string());
+  ExpectAttributesEq(root, std::string(), absl::nullopt, absl::nullopt);
 
   ASSERT_EQ(2UL, root->child_at(0)->child_count());
   ExpectAttributesEq(root->child_at(0), "1-1-name", "1-1-id", "1-1.html");
@@ -132,7 +132,7 @@
 
   root = wc->GetPrimaryFrameTree().root();
   EXPECT_EQ(0UL, root->child_count());
-  ExpectAttributesEq(root, std::string(), std::string(), std::string());
+  ExpectAttributesEq(root, std::string(), absl::nullopt, absl::nullopt);
 }
 
 // Frame attributes of iframe elements are correctly tracked in FrameTree.
@@ -145,7 +145,7 @@
 
   // Check that the root node is properly created.
   ASSERT_EQ(3UL, root->child_count());
-  ExpectAttributesEq(root, std::string(), std::string(), std::string());
+  ExpectAttributesEq(root, std::string(), absl::nullopt, absl::nullopt);
 
   ASSERT_EQ(2UL, root->child_at(0)->child_count());
   ExpectAttributesEq(root->child_at(0), "1-1-name", "1-1-id", "1-1.html");
@@ -174,7 +174,7 @@
 
   // Check that the root node is properly created.
   ASSERT_EQ(3UL, root->child_count());
-  EXPECT_EQ(std::string(), root->html_name());
+  EXPECT_EQ(absl::nullopt, root->html_name());
   EXPECT_EQ(std::string(), root->frame_name());
 
   ASSERT_EQ(2UL, root->child_at(0)->child_count());
@@ -223,9 +223,9 @@
     iframe.src += 'c'.repeat(1200) + '.html';
   )"));
   // Long attribute is cut down to the maximum length.
-  EXPECT_EQ(1024UL, root->child_at(0)->html_id().size());
-  EXPECT_EQ(1024UL, root->child_at(0)->html_name().size());
-  EXPECT_EQ(1024UL, root->child_at(0)->html_src().size());
+  EXPECT_EQ(1024UL, root->child_at(0)->html_id()->size());
+  EXPECT_EQ(1024UL, root->child_at(0)->html_name()->size());
+  EXPECT_EQ(1024UL, root->child_at(0)->html_src()->size());
 }
 
 // Insert a frame into the frame tree and ensure that the inserted frame's
@@ -239,7 +239,7 @@
 
   // Check that the root node is properly created.
   ASSERT_EQ(3UL, root->child_count());
-  ExpectAttributesEq(root, std::string(), std::string(), std::string());
+  ExpectAttributesEq(root, std::string(), absl::nullopt, absl::nullopt);
 
   ASSERT_EQ(2UL, root->child_at(0)->child_count());
   ExpectAttributesEq(root->child_at(0), "1-1-name", "1-1-id", "1-1.html");
diff --git a/content/browser/renderer_host/frame_tree_node.h b/content/browser/renderer_host/frame_tree_node.h
index 9d7c7c83..6940679 100644
--- a/content/browser/renderer_host/frame_tree_node.h
+++ b/content/browser/renderer_host/frame_tree_node.h
@@ -275,12 +275,16 @@
   const network::mojom::ContentSecurityPolicy* csp_attribute() const {
     return attributes_->parsed_csp_attribute.get();
   }
-  const std::string& html_id() const { return attributes_->id; }
+  const absl::optional<std::string> html_id() const { return attributes_->id; }
   // This tracks iframe's 'name' attribute instead of window.name, which is
   // tracked in FrameReplicationState. See the comment for frame_name() for
   // more details.
-  const std::string& html_name() const { return attributes_->name; }
-  const std::string& html_src() const { return attributes_->src; }
+  const absl::optional<std::string> html_name() const {
+    return attributes_->name;
+  }
+  const absl::optional<std::string> html_src() const {
+    return attributes_->src;
+  }
 
   void SetAttributes(blink::mojom::IframeAttributesPtr attributes);
 
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index eec3dca..0ccfdc8e 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -217,7 +217,12 @@
 class NavigationControllerTest : public RenderViewHostImplTestHarness,
                                  public WebContentsObserver {
  public:
-  NavigationControllerTest() = default;
+  NavigationControllerTest() {
+    // Disable BackForward cache size overwritten by
+    // `kBackForwardCacheSize` so that it won't break some tests assumption.
+    scoped_feature_list_.InitWithFeaturesAndParameters({},
+                                                       {kBackForwardCacheSize});
+  }
 
   void SetUp() override {
     RenderViewHostImplTestHarness::SetUp();
@@ -288,6 +293,9 @@
   size_t form_repost_counter_ = 0;
   PrunedDetails last_navigation_entry_pruned_details_;
   ReloadType last_reload_type_;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 class TestWebContentsDelegate : public WebContentsDelegate {
diff --git a/content/browser/renderer_host/pending_beacon_browsertest.cc b/content/browser/renderer_host/pending_beacon_browsertest.cc
index 3648bc5..d9520bf8 100644
--- a/content/browser/renderer_host/pending_beacon_browsertest.cc
+++ b/content/browser/renderer_host/pending_beacon_browsertest.cc
@@ -48,12 +48,18 @@
 class PendingBeaconTimeoutBrowserTestBase : public ContentBrowserTest {
  protected:
   using FeaturesType = std::vector<base::test::FeatureRefAndParams>;
+  using DisabledFeaturesType = std::vector<base::test::FeatureRef>;
 
   void SetUp() override {
-    feature_list_.InitWithFeaturesAndParameters(GetEnabledFeatures(), {});
+    feature_list_.InitWithFeaturesAndParameters(GetEnabledFeatures(),
+                                                GetDisabledFeatures());
     ContentBrowserTest::SetUp();
   }
   virtual const FeaturesType& GetEnabledFeatures() = 0;
+  virtual const DisabledFeaturesType& GetDisabledFeatures() {
+    static const DisabledFeaturesType disabled_features = {};
+    return disabled_features;
+  }
 
   void SetUpOnMainThread() override {
     histogram_tester_ = std::make_unique<base::HistogramTester>();
@@ -337,20 +343,24 @@
 // Tests to cover PendingBeacon's backgroundTimeout & timeout behaviors when
 // BackForwardCache is off.
 //
-// Disables BackForwardCache by setting its cache size to 0 such that a page is
-// discarded right away on user navigating to another page. And on page
-// discard, pending beacons should be sent out no matter what value its
-// backgroundTimeout/timeout is.
+// Disables BackForwardCache such that a page is discarded right away on user
+// navigating to another page.
+// And on page discard, pending beacons should be sent out no matter what value
+// its backgroundTimeout/timeout is.
 class PendingBeaconTimeoutNoBackForwardCacheBrowserTest
     : public PendingBeaconTimeoutBrowserTestBase,
       public testing::WithParamInterface<TestTimeoutType> {
  protected:
   const FeaturesType& GetEnabledFeatures() override {
     static const FeaturesType enabled_features = {
-        {blink::features::kPendingBeaconAPI, {{"send_on_navigation", "true"}}},
-        {features::kBackForwardCache, {{"cache_size", "0"}}}};
+        {blink::features::kPendingBeaconAPI, {{"send_on_navigation", "true"}}}};
     return enabled_features;
   }
+  const DisabledFeaturesType& GetDisabledFeatures() override {
+    static const DisabledFeaturesType disabled_features = {
+        features::kBackForwardCache};
+    return disabled_features;
+  }
 };
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/content/gpu/gpu_service_factory.cc b/content/gpu/gpu_service_factory.cc
index cf7b765..1ac4d19 100644
--- a/content/gpu/gpu_service_factory.cc
+++ b/content/gpu/gpu_service_factory.cc
@@ -15,9 +15,16 @@
 
 #if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
 #include "base/functional/bind.h"
+#include "media/base/media_switches.h"
 #include "media/mojo/services/media_service_factory.h"  // nogncheck
 #endif  // BUILDFLAG(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
 
+#if BUILDFLAG(IS_WIN)
+#include <d3d11_4.h>
+
+#include "ui/gl/gl_angle_util_win.h"
+#endif
+
 namespace content {
 
 GpuServiceFactory::GpuServiceFactory(
@@ -48,16 +55,26 @@
   // This service will host audio/video decoders, and if these decoding
   // operations are blocked, user may hear audio glitch or see video freezing,
   // hence "user blocking".
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner;
+  auto task_runner = task_runner_;
+  if (base::FeatureList::IsEnabled(media::kDedicatedMediaServiceThread)) {
+    // TODO(crbug.com/786169): Check whether this needs to be single threaded.
+    task_runner = base::ThreadPool::CreateSingleThreadTaskRunner(
+        {base::TaskPriority::USER_BLOCKING});
+
 #if BUILDFLAG(IS_WIN)
-  // Run everything on the gpu main thread, since it's required for decode swap
-  // chains. See SwapChainPresenter::TryPresentToDecodeSwapChain().
-  task_runner = task_runner_;
-#else
-  // TODO(crbug.com/786169): Check whether this needs to be single threaded.
-  task_runner = base::ThreadPool::CreateSingleThreadTaskRunner(
-      {base::TaskPriority::USER_BLOCKING});
-#endif  // BUILDFLAG(IS_WIN)
+    // Since the D3D11Device used for decoding is shared with ANGLE, we need
+    // multithread protection turned on to use it from another thread.
+    task_runner_->PostTask(
+        FROM_HERE, base::BindOnce([] {
+          auto device = gl::QueryD3D11DeviceObjectFromANGLE();
+          CHECK(device);
+          Microsoft::WRL::ComPtr<ID3D11Multithread> multi_threaded;
+          auto hr = device->QueryInterface(IID_PPV_ARGS(&multi_threaded));
+          CHECK(SUCCEEDED(hr));
+          multi_threaded->SetMultithreadProtected(TRUE);
+        }));
+#endif
+  }
 
   using FactoryCallback =
       base::OnceCallback<std::unique_ptr<media::MediaService>()>;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
index 44f3a748..af2a0c36 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
@@ -23,7 +23,6 @@
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller;
 import org.chromium.content_public.browser.LoadUrlParams;
@@ -864,10 +863,10 @@
             }
 
             private void method() {};
-        }, "testObject");
+        }, "testObject", null);
         assertRaisesException("testObject.myGetClass().getMethod('method', null)");
-        // getDeclaredMethod() is able to access a private method, but invoke()
-        // throws a Java exception.
+        // getDeclaredMethod() is able to get a reference to a private method, but actually invoking
+        // the method throws.
         assertRaisesException(
                 "testObject.myGetClass().getDeclaredMethod('method', null)."
                 + "invoke(testObject, null)");
@@ -876,7 +875,6 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
-    @DisabledTest(message = "https://crbug.com/795378")
     @UseMethodParameter(JavaBridgeActivityTestRule.LegacyTestParams.class)
     public void testReflectPrivateFieldRaisesException(boolean useMojo) throws Throwable {
         mActivityTestRule.injectObjectAndReload(new Object() {
@@ -886,11 +884,11 @@
             }
 
             private int mField;
-        }, "testObject");
+        }, "testObject", null);
         String fieldName = "mField";
         assertRaisesException("testObject.myGetClass().getField('" + fieldName + "')");
-        // getDeclaredField() is able to access a private field, but getInt()
-        // throws a Java exception.
+        // getDeclaredField() is able to get a reference to a private field, but actually retrieving
+        // the value of the field throws.
         assertNoRaisedException("testObject.myGetClass().getDeclaredField('" + fieldName + "')");
         assertRaisesException(
                 "testObject.myGetClass().getDeclaredField('" + fieldName + "').getInt(testObject)");
diff --git a/content/test/data/forms/form_controls_browsertest_multi_select_chromeos.png b/content/test/data/forms/form_controls_browsertest_multi_select_chromeos.png
index c9d2399b..88732b05 100644
--- a/content/test/data/forms/form_controls_browsertest_multi_select_chromeos.png
+++ b/content/test/data/forms/form_controls_browsertest_multi_select_chromeos.png
Binary files differ
diff --git a/content/test/data/forms/form_controls_browsertest_select_chromeos.png b/content/test/data/forms/form_controls_browsertest_select_chromeos.png
index f0c0ccae..ad7e471 100644
--- a/content/test/data/forms/form_controls_browsertest_select_chromeos.png
+++ b/content/test/data/forms/form_controls_browsertest_select_chromeos.png
Binary files differ
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index 26b6fb29a..689fa629 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -661,6 +661,20 @@
 * This installerdata is not persisted anywhere else, and it is not sent as a
 part of pings to the update server.
 
+#### Application logo shown in the UI
+
+The app logo is expected to be hosted at
+`{APP_LOGO_URL}{url escaped app_id_}.bmp`.
+
+If `{url escaped app_id_}.bmp` exists, a logo is shown in the updater UI for
+that app install.
+
+For example, if `app_id_` is `{8A69D345-D564-463C-AFF1-A69D9E530F96}`, the
+`{url escaped app_id_}.bmp` is `%7b8A69D345-D564-463C-AFF1-A69D9E530F96%7d.bmp`.
+
+`APP_LOGO_URL` is specified in chrome/updater/branding.gni.
+[branding.gni](https://source.chromium.org/chromium/chromium/src/+/main:chrome/updater/branding.gni?q=APP_LOGO_URL)
+
 ### Update Formats
 The updater accepts updates packaged as CRX₃ files. All files are signed with a
 publisher key. The corresponding public key is hardcoded into the updater.
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 3e5de9b..6e38824 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -1008,6 +1008,7 @@
       "//chromeos/ash/components/dbus/upstart",
       "//chromeos/ash/components/login/login_state",
       "//chromeos/ash/components/network:test_support",
+      "//chromeos/ash/components/standalone_browser",
       "//chromeos/dbus/permission_broker",
       "//chromeos/dbus/power",
       "//components/feedback",
diff --git a/extensions/browser/extension_registrar_unittest.cc b/extensions/browser/extension_registrar_unittest.cc
index b073a93..fc6bc181 100644
--- a/extensions/browser/extension_registrar_unittest.cc
+++ b/extensions/browser/extension_registrar_unittest.cc
@@ -27,6 +27,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/common/pref_names.h"  // nogncheck
+#include "chromeos/ash/components/standalone_browser/lacros_availability.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
@@ -576,7 +577,7 @@
       ->RegisterIntegerPref(
           prefs::kLacrosLaunchSwitch,
           static_cast<int>(
-              crosapi::browser_util::LacrosAvailability::kLacrosOnly));
+              ash::standalone_browser::LacrosAvailability::kLacrosOnly));
   EXPECT_FALSE(crosapi::browser_util::IsAshWebBrowserEnabled());
 
   // Prevent the extension from being disabled (by the user).
@@ -598,7 +599,7 @@
       ->RegisterIntegerPref(
           prefs::kLacrosLaunchSwitch,
           static_cast<int>(
-              crosapi::browser_util::LacrosAvailability::kLacrosPrimary));
+              ash::standalone_browser::LacrosAvailability::kLacrosPrimary));
   EXPECT_TRUE(crosapi::browser_util::IsAshWebBrowserEnabled());
 
   // Prevent the extension from being disabled (by the user).
diff --git a/extensions/common/url_pattern_unittest.cc b/extensions/common/url_pattern_unittest.cc
index f530784..0829c8a8 100644
--- a/extensions/common/url_pattern_unittest.cc
+++ b/extensions/common/url_pattern_unittest.cc
@@ -158,6 +158,52 @@
   }
 }
 
+// Verify percent encoding behavior.
+TEST(ExtensionURLPatternTest, PercentEncodedAscii) {
+  {
+    URLPattern pattern(kAllSchemes);
+    ASSERT_EQ(URLPattern::ParseResult::kSuccess,
+              pattern.Parse("http://*/%40*"));
+    EXPECT_EQ("http", pattern.scheme());
+    EXPECT_EQ("", pattern.host());
+    EXPECT_TRUE(pattern.match_subdomains());
+    EXPECT_FALSE(pattern.match_all_urls());
+    EXPECT_EQ("/%40*", pattern.path());
+  }
+  {
+    URLPattern pattern(kAllSchemes);
+    ASSERT_EQ(URLPattern::ParseResult::kSuccess, pattern.Parse("http://*/@*"));
+    EXPECT_EQ("http", pattern.scheme());
+    EXPECT_EQ("", pattern.host());
+    EXPECT_TRUE(pattern.match_subdomains());
+    EXPECT_FALSE(pattern.match_all_urls());
+    EXPECT_EQ("/@*", pattern.path());
+  }
+}
+
+// Verify percent encoding behavior.
+TEST(ExtensionURLPatternTest, PercentEncodedNonAscii) {
+  {
+    URLPattern pattern(kAllSchemes);
+    ASSERT_EQ(URLPattern::ParseResult::kSuccess,
+              pattern.Parse("http://*/%F0%9F%90%B1*"));
+    EXPECT_EQ("http", pattern.scheme());
+    EXPECT_EQ("", pattern.host());
+    EXPECT_TRUE(pattern.match_subdomains());
+    EXPECT_FALSE(pattern.match_all_urls());
+    EXPECT_EQ("/%F0%9F%90%B1*", pattern.path());
+  }
+  {
+    URLPattern pattern(kAllSchemes);
+    ASSERT_EQ(URLPattern::ParseResult::kSuccess, pattern.Parse("http://*/🐱*"));
+    EXPECT_EQ("http", pattern.scheme());
+    EXPECT_EQ("", pattern.host());
+    EXPECT_TRUE(pattern.match_subdomains());
+    EXPECT_FALSE(pattern.match_all_urls());
+    EXPECT_EQ("/🐱*", pattern.path());
+  }
+}
+
 // all pages for a given scheme
 TEST(ExtensionURLPatternTest, Match1) {
   URLPattern pattern(kAllSchemes);
diff --git a/fuchsia_web/webengine/browser/cast_streaming_browsertest.cc b/fuchsia_web/webengine/browser/cast_streaming_browsertest.cc
index 9b4db20..679fb7c 100644
--- a/fuchsia_web/webengine/browser/cast_streaming_browsertest.cc
+++ b/fuchsia_web/webengine/browser/cast_streaming_browsertest.cc
@@ -146,7 +146,7 @@
                                        page_url.spec()));
 
   ASSERT_TRUE(sender.RunUntilActive());
-  frame.navigation_listener().RunUntilTitleEquals("canplay");
+  frame.navigation_listener().RunUntilTitleEquals("loadedmetadata");
 
   EXPECT_TRUE(post_result.Wait());
   EXPECT_NE(sender.audio_decoder_config(), absl::nullopt);
@@ -191,7 +191,7 @@
                                        kPageUrl.spec()));
 
   ASSERT_TRUE(sender.RunUntilActive());
-  frame.navigation_listener().RunUntilTitleEquals("canplay");
+  frame.navigation_listener().RunUntilTitleEquals("loadedmetadata");
 
   EXPECT_TRUE(post_result.Wait());
   EXPECT_EQ(sender.audio_decoder_config(), absl::nullopt);
diff --git a/fuchsia_web/webengine/test/data/cast_streaming_receiver.html b/fuchsia_web/webengine/test/data/cast_streaming_receiver.html
index 59ca565..0f98a3d6 100644
--- a/fuchsia_web/webengine/test/data/cast_streaming_receiver.html
+++ b/fuchsia_web/webengine/test/data/cast_streaming_receiver.html
@@ -13,8 +13,11 @@
     video.onerror = function() {
       document.title = "error";
     }
-    video.oncanplay = function() {
-      document.title = "canplay";
+
+    // We currently don't actually load any video, so just want to make sure
+    // that the web video player has successfully loaded the metadata.
+    video.onloadedmetadata = function() {
+      document.title = "loadedmetadata";
     }
   </script>
 </body>
diff --git a/infra/config/generated/builders/ci/mac12-wpt-content-shell-fyi-rel/properties.json b/infra/config/generated/builders/ci/mac12-wpt-content-shell-fyi-rel/properties.json
index 9aa6cc4..846051c 100644
--- a/infra/config/generated/builders/ci/mac12-wpt-content-shell-fyi-rel/properties.json
+++ b/infra/config/generated/builders/ci/mac12-wpt-content-shell-fyi-rel/properties.json
@@ -34,6 +34,12 @@
           "builder": "mac12-wpt-content-shell-fyi-rel",
           "project": "chromium"
         }
+      ],
+      "mirroring_builder_group_and_names": [
+        {
+          "builder": "mac12-wpt-content-shell-fyi-rel",
+          "group": "tryserver.chromium.mac"
+        }
       ]
     }
   },
diff --git a/infra/config/generated/builders/try/mac12-wpt-content-shell-fyi-rel/properties.json b/infra/config/generated/builders/try/mac12-wpt-content-shell-fyi-rel/properties.json
new file mode 100644
index 0000000..107ce8c
--- /dev/null
+++ b/infra/config/generated/builders/try/mac12-wpt-content-shell-fyi-rel/properties.json
@@ -0,0 +1,57 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "mac12-wpt-content-shell-fyi-rel",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "builder_group": "chromium.fyi",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium",
+                "target_bits": 64,
+                "target_platform": "mac"
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "mac12-wpt-content-shell-fyi-rel",
+          "project": "chromium"
+        }
+      ]
+    }
+  },
+  "$build/goma": {
+    "rpc_extra_params": "?prod",
+    "server_host": "goma.chromium.org"
+  },
+  "$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.mac",
+  "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 5693b791..39a26487 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -3363,6 +3363,10 @@
         includable_only: true
       }
       builders {
+        name: "chromium/try/mac12-wpt-content-shell-fyi-rel"
+        includable_only: true
+      }
+      builders {
         name: "chromium/try/mac12.0-blink-rel"
         includable_only: true
       }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 934fc06c..ef3adc3f 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -85474,6 +85474,103 @@
       }
     }
     builders {
+      name: "mac12-wpt-content-shell-fyi-rel"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Mac"
+      dimensions: "pool:luci.chromium.try"
+      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/try/mac12-wpt-content-shell-fyi-rel/properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "tryserver.chromium.mac",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium_trybot"'
+        '}'
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      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.buildbucket.omit_python2"
+        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: "mac12.0-blink-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 93cf26ca..4fcad4a0 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -17705,6 +17705,9 @@
     name: "buildbucket/luci.chromium.try/mac12-tests"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/mac12-wpt-content-shell-fyi-rel"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/mac12.0-blink-rel"
   }
   builders {
@@ -18842,6 +18845,9 @@
     name: "buildbucket/luci.chromium.try/mac12-tests"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/mac12-wpt-content-shell-fyi-rel"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/mac_chromium_10.13_rel_ng"
   }
   builders {
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
index 370aebf..3a0bd38 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
@@ -187,6 +187,13 @@
     grace_period = 4 * time.minute,
 )
 
+try_.builder(
+    name = "mac12-wpt-content-shell-fyi-rel",
+    mirrors = [
+        "ci/mac12-wpt-content-shell-fyi-rel",
+    ],
+)
+
 # NOTE: the following trybots aren't sensitive to Mac version on which
 # they are built, hence no additional dimension is specified.
 # The 10.xx version translates to which bots will run isolated tests.
diff --git a/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm b/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm
index 4414c86..530f975b 100644
--- a/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm
+++ b/ios/chrome/browser/safe_browsing/chrome_password_protection_service.mm
@@ -82,13 +82,6 @@
 
 namespace {
 
-// Records changes in the phished status of saved credential.
-void LogCredentialPhishedStatusChanged(
-    safe_browsing::CredentialPhishedStatus status) {
-  base::UmaHistogramEnumeration("SafeBrowsing.CredentialPhishedStatusChange",
-                                status);
-}
-
 // Returns true if the command line has an artificial unsafe cached verdict.
 bool HasArtificialCachedVerdict() {
   std::string phishing_url_string =
@@ -273,8 +266,6 @@
     if (!password_store) {
       continue;
     }
-    LogCredentialPhishedStatusChanged(
-        safe_browsing::CredentialPhishedStatus::kMarkedAsPhished);
     add_phished_credentials_.Run(password_store, credential);
   }
 }
@@ -292,8 +283,6 @@
     if (!password_store) {
       continue;
     }
-    LogCredentialPhishedStatusChanged(
-        safe_browsing::CredentialPhishedStatus::kSiteMarkedAsLegitimate);
     remove_phished_credentials_.Run(password_store, credential);
   }
 }
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm
index f8438d22..01adeb09 100644
--- a/ios/chrome/browser/tabs/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -84,7 +84,6 @@
 #import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
 #import "ios/chrome/browser/web/annotations/annotations_tab_helper.h"
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
-#import "ios/chrome/browser/web/error_page_controller_bridge.h"
 #import "ios/chrome/browser/web/font_size/font_size_tab_helper.h"
 #import "ios/chrome/browser/web/image_fetch/image_fetch_tab_helper.h"
 #import "ios/chrome/browser/web/invalid_url_tab_helper.h"
@@ -140,7 +139,6 @@
       web_state);
   password_manager::WellKnownChangePasswordTabHelper::CreateForWebState(
       web_state);
-  ErrorPageControllerBridge::CreateForWebState(web_state);
 
   InvalidUrlTabHelper::CreateForWebState(web_state);
 
diff --git a/ios/chrome/browser/ui/browser_view/key_commands_provider.mm b/ios/chrome/browser/ui/browser_view/key_commands_provider.mm
index 5f046281..e1b0429f 100644
--- a/ios/chrome/browser/ui/browser_view/key_commands_provider.mm
+++ b/ios/chrome/browser/ui/browser_view/key_commands_provider.mm
@@ -169,6 +169,16 @@
 }
 
 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
+  // BVC prevents KeyCommandsProvider from providing key commands when it has
+  // `presentedViewController` set. But there is an interval between presenting
+  // a view controller and having `presentedViewController` set. In that window,
+  // KeyCommandsProvider can register key commands while it shouldn't.
+  // To prevent actions from executing, check again if there is a
+  // `presentedViewController`.
+  if (_viewController.presentedViewController) {
+    return NO;
+  }
+
   if (sel_isEqual(action, @selector(keyCommand_back))) {
     BOOL canPerformBack =
         self.tabsCount > 0 && self.navigationAgent->CanGoBack();
diff --git a/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm b/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm
index 3c6fe13..b944c2d 100644
--- a/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view/key_commands_provider_unittest.mm
@@ -233,6 +233,29 @@
   EXPECT_TRUE(CanPerform(@"keyCommand_clearBrowsingData"));
 }
 
+// Checks whether KeyCommandsProvider can perform the actions that are always
+// available when there is a presented view controller.
+TEST_F(KeyCommandsProviderTest,
+       CanPerform_AlwaysAvailableActions_PresentedViewController) {
+  UIViewController* viewController = [[UIViewController alloc] init];
+  [GetAnyKeyWindow() addSubview:viewController.view];
+  [provider_ respondBetweenViewController:viewController andResponder:nil];
+  UIViewController* presentedViewController = [[UIViewController alloc] init];
+  [viewController presentViewController:presentedViewController
+                               animated:NO
+                             completion:nil];
+
+  EXPECT_FALSE(CanPerform(@"keyCommand_openNewTab"));
+  EXPECT_FALSE(CanPerform(@"keyCommand_openNewRegularTab"));
+  EXPECT_FALSE(CanPerform(@"keyCommand_openNewIncognitoTab"));
+  EXPECT_FALSE(CanPerform(@"keyCommand_openNewWindow"));
+  EXPECT_FALSE(CanPerform(@"keyCommand_openNewIncognitoWindow"));
+  EXPECT_FALSE(CanPerform(@"keyCommand_showSettings"));
+  EXPECT_FALSE(CanPerform(@"keyCommand_showReadingList"));
+  EXPECT_FALSE(CanPerform(@"keyCommand_goToTabGrid"));
+  EXPECT_FALSE(CanPerform(@"keyCommand_clearBrowsingData"));
+}
+
 // Checks whether KeyCommandsProvider can perform the actions that are only
 // available when there are tabs.
 TEST_F(KeyCommandsProviderTest, CanPerform_TabsActions) {
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index 308bcc7..44056a4 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -13,8 +13,6 @@
     "blocked_popup_tab_helper.mm",
     "certificate_policy_app_agent.h",
     "certificate_policy_app_agent.mm",
-    "error_page_controller_bridge.h",
-    "error_page_controller_bridge.mm",
     "error_page_util.h",
     "error_page_util.mm",
     "invalid_url_tab_helper.h",
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm
index b6e12cf7..dba1d3f 100644
--- a/ios/chrome/browser/web/chrome_web_client.mm
+++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -48,7 +48,6 @@
 #import "ios/chrome/browser/url/url_util.h"
 #import "ios/chrome/browser/web/browser_about_rewriter.h"
 #import "ios/chrome/browser/web/chrome_main_parts.h"
-#import "ios/chrome/browser/web/error_page_controller_bridge.h"
 #import "ios/chrome/browser/web/error_page_util.h"
 #import "ios/chrome/browser/web/features.h"
 #import "ios/chrome/browser/web/font_size/font_size_java_script_feature.h"
@@ -373,13 +372,6 @@
   } else {
     std::move(error_html_callback)
         .Run(GetErrorPage(url, error, is_post, is_off_the_record));
-    ErrorPageControllerBridge* error_page_controller =
-        ErrorPageControllerBridge::FromWebState(web_state);
-    if (error_page_controller) {
-      // ErrorPageControllerBridge may not be created for web_state not attached
-      // to a tab.
-      error_page_controller->StartHandlingJavascriptCommands();
-    }
   }
 }
 
diff --git a/ios/chrome/browser/web/chrome_web_client_unittest.mm b/ios/chrome/browser/web/chrome_web_client_unittest.mm
index 59de61c..71ff7e4b 100644
--- a/ios/chrome/browser/web/chrome_web_client_unittest.mm
+++ b/ios/chrome/browser/web/chrome_web_client_unittest.mm
@@ -26,7 +26,6 @@
 #import "ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
 #import "ios/chrome/browser/ssl/captive_portal_tab_helper.h"
 #import "ios/chrome/browser/url/chrome_url_constants.h"
-#import "ios/chrome/browser/web/error_page_controller_bridge.h"
 #import "ios/chrome/browser/web/error_page_util.h"
 #import "ios/chrome/browser/web/features.h"
 #import "ios/components/security_interstitials/https_only_mode/https_only_mode_container.h"
@@ -154,7 +153,6 @@
         page = error_html;
       });
   web::FakeWebState web_state;
-  ErrorPageControllerBridge::CreateForWebState(&web_state);
   web_client.PrepareErrorPage(&web_state, GURL(kTestUrl), error,
                               /*is_post=*/false,
                               /*is_off_the_record=*/false,
@@ -181,7 +179,6 @@
         page = error_html;
       });
   web::FakeWebState web_state;
-  ErrorPageControllerBridge::CreateForWebState(&web_state);
   web_client.PrepareErrorPage(&web_state, GURL(kTestUrl), error,
                               /*is_post=*/true,
                               /*is_off_the_record=*/false,
@@ -208,7 +205,6 @@
         page = error_html;
       });
   web::FakeWebState web_state;
-  ErrorPageControllerBridge::CreateForWebState(&web_state);
   web_client.PrepareErrorPage(&web_state, GURL(kTestUrl), error,
                               /*is_post=*/false,
                               /*is_off_the_record=*/true,
@@ -235,7 +231,6 @@
         page = error_html;
       });
   web::FakeWebState web_state;
-  ErrorPageControllerBridge::CreateForWebState(&web_state);
   web_client.PrepareErrorPage(&web_state, GURL(kTestUrl), error,
                               /*is_post=*/true,
                               /*is_off_the_record=*/true,
diff --git a/ios/chrome/browser/web/error_page_controller_bridge.h b/ios/chrome/browser/web/error_page_controller_bridge.h
deleted file mode 100644
index ec97f4a..0000000
--- a/ios/chrome/browser/web/error_page_controller_bridge.h
+++ /dev/null
@@ -1,54 +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.
-
-#ifndef IOS_CHROME_BROWSER_WEB_ERROR_PAGE_CONTROLLER_BRIDGE_H_
-#define IOS_CHROME_BROWSER_WEB_ERROR_PAGE_CONTROLLER_BRIDGE_H_
-
-#include "ios/web/public/web_state_observer.h"
-#import "ios/web/public/web_state_user_data.h"
-
-namespace web {
-class WebState;
-}
-
-// A class to bridge the JS errorPageController object in the error page.
-// The class receives the JS messages and handle/dispatch them when needed.
-// Messages are sent in
-// components/neterror/resources/error_page_controller_ios.js.
-class ErrorPageControllerBridge
-    : public web::WebStateObserver,
-      public web::WebStateUserData<ErrorPageControllerBridge> {
- public:
-  ~ErrorPageControllerBridge() override;
-
-  // Start observing "errorPageController" commands until next navigation.
-  void StartHandlingJavascriptCommands();
-
-  // WebStateObserver overrides
-  void DidStartNavigation(web::WebState* web_state,
-                          web::NavigationContext* navigation_context) override;
-  void WebStateDestroyed(web::WebState* web_state) override;
-
- private:
-  friend class WebStateUserData<ErrorPageControllerBridge>;
-
-  ErrorPageControllerBridge(web::WebState* web_state);
-
-  // Handler for "errorPageController.*" JavaScript command.
-  void OnErrorPageCommand(const base::Value& message,
-                          const GURL& url,
-                          bool user_is_interacting,
-                          web::WebFrame* sender_frame);
-
-  // The WebState this instance is observing. Will be null after
-  // WebStateDestroyed has been called.
-  web::WebState* web_state_ = nullptr;
-
-  // Subscription for JS message.
-  base::CallbackListSubscription subscription_;
-
-  WEB_STATE_USER_DATA_KEY_DECL();
-};
-
-#endif  // IOS_CHROME_BROWSER_WEB_ERROR_PAGE_CONTROLLER_BRIDGE_H_
diff --git a/ios/chrome/browser/web/error_page_controller_bridge.mm b/ios/chrome/browser/web/error_page_controller_bridge.mm
deleted file mode 100644
index 0c120f4..0000000
--- a/ios/chrome/browser/web/error_page_controller_bridge.mm
+++ /dev/null
@@ -1,91 +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.
-
-#import "ios/chrome/browser/web/error_page_controller_bridge.h"
-
-#import <Foundation/Foundation.h>
-
-#import "base/strings/string_number_conversions.h"
-#import "base/values.h"
-#import "ios/web/public/js_messaging/web_frame.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Prefix for the errorPageController activity event commands.
-// Must be kept in sync with
-// components/neterror/resources/error_page_controller_ios.js.
-const char kCommandPrefix[] = "errorPageController";
-
-// The NSUserDefault key to store the easter egg game on error page high score.
-NSString* const kEasterEggHighScore = @"EasterEggHighScore";
-}  // namespace
-
-ErrorPageControllerBridge::ErrorPageControllerBridge(web::WebState* web_state)
-    : web_state_(web_state) {}
-
-ErrorPageControllerBridge::~ErrorPageControllerBridge() {}
-
-void ErrorPageControllerBridge::StartHandlingJavascriptCommands() {
-  web_state_->AddObserver(this);
-  subscription_ = web_state_->AddScriptCommandCallback(
-      base::BindRepeating(&ErrorPageControllerBridge::OnErrorPageCommand,
-                          base::Unretained(this)),
-      kCommandPrefix);
-}
-
-void ErrorPageControllerBridge::OnErrorPageCommand(
-    const base::Value& message,
-    const GURL& url,
-    bool user_is_interacting,
-    web::WebFrame* sender_frame) {
-  const std::string* command = message.FindStringKey("command");
-  if (!command) {
-    return;
-  }
-  if (*command == "errorPageController.updateEasterEggHighScore") {
-    const std::string* high_score_string = message.FindStringKey("highScore");
-    if (!high_score_string) {
-      return;
-    }
-    int high_score;
-    if (!base::StringToInt(*high_score_string, &high_score)) {
-      return;
-    }
-    [[NSUserDefaults standardUserDefaults] setInteger:high_score
-                                               forKey:kEasterEggHighScore];
-    return;
-  }
-  if (*command == "errorPageController.resetEasterEggHighScore") {
-    [[NSUserDefaults standardUserDefaults]
-        removeObjectForKey:kEasterEggHighScore];
-    return;
-  }
-  if (*command == "errorPageController.trackEasterEgg") {
-    int high_score = [[NSUserDefaults standardUserDefaults]
-        integerForKey:kEasterEggHighScore];
-    std::vector<base::Value> parameters;
-    parameters.push_back(base::Value(high_score));
-    sender_frame->CallJavaScriptFunction(
-        "errorPageController.initializeEasterEggHighScore", parameters);
-    return;
-  }
-}
-
-#pragma mark WebStateObserver
-
-void ErrorPageControllerBridge::DidStartNavigation(
-    web::WebState* web_state,
-    web::NavigationContext* navigation_context) {
-  subscription_ = base::CallbackListSubscription();
-  web_state_->RemoveObserver(this);
-}
-
-void ErrorPageControllerBridge::WebStateDestroyed(web::WebState* web_state) {
-  web_state_->RemoveObserver(this);
-}
-
-WEB_STATE_USER_DATA_KEY_IMPL(ErrorPageControllerBridge)
diff --git a/ios/web/js_features/error_page/BUILD.gn b/ios/web/js_features/error_page/BUILD.gn
new file mode 100644
index 0000000..836a205
--- /dev/null
+++ b/ios/web/js_features/error_page/BUILD.gn
@@ -0,0 +1,19 @@
+# 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("//ios/build/config.gni")
+
+source_set("error_page") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  deps = [
+    "//base",
+    "//ios/web/navigation:wk_navigation_util",
+    "//ios/web/public/js_messaging",
+  ]
+
+  sources = [
+    "error_page_java_script_feature.h",
+    "error_page_java_script_feature.mm",
+  ]
+}
diff --git a/ios/web/js_features/error_page/error_page_java_script_feature.h b/ios/web/js_features/error_page/error_page_java_script_feature.h
new file mode 100644
index 0000000..9885aa5
--- /dev/null
+++ b/ios/web/js_features/error_page/error_page_java_script_feature.h
@@ -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.
+
+#ifndef IOS_WEB_JS_FEATURES_ERROR_PAGE_ERROR_PAGE_JAVA_SCRIPT_FEATURE_H_
+#define IOS_WEB_JS_FEATURES_ERROR_PAGE_ERROR_PAGE_JAVA_SCRIPT_FEATURE_H_
+
+#import "base/no_destructor.h"
+#import "ios/web/public/js_messaging/java_script_feature.h"
+
+namespace web {
+
+// Listens for script command messages from error pages.
+class ErrorPageJavaScriptFeature : public JavaScriptFeature {
+ public:
+  // This feature holds no state, so only a single static instance is ever
+  // needed.
+  static ErrorPageJavaScriptFeature* GetInstance();
+
+  ErrorPageJavaScriptFeature(const ErrorPageJavaScriptFeature&) = delete;
+  ErrorPageJavaScriptFeature& operator=(const ErrorPageJavaScriptFeature&) =
+      delete;
+
+ private:
+  friend class base::NoDestructor<ErrorPageJavaScriptFeature>;
+
+  // JavaScriptFeature overrides
+  absl::optional<std::string> GetScriptMessageHandlerName() const override;
+  void ScriptMessageReceived(WebState* web_state,
+                             const ScriptMessage& script_message) override;
+
+  ErrorPageJavaScriptFeature();
+  ~ErrorPageJavaScriptFeature() override;
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_JS_FEATURES_ERROR_PAGE_ERROR_PAGE_JAVA_SCRIPT_FEATURE_H_
diff --git a/ios/web/js_features/error_page/error_page_java_script_feature.mm b/ios/web/js_features/error_page/error_page_java_script_feature.mm
new file mode 100644
index 0000000..f204462
--- /dev/null
+++ b/ios/web/js_features/error_page/error_page_java_script_feature.mm
@@ -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.
+
+#import "ios/web/js_features/error_page/error_page_java_script_feature.h"
+
+#import "base/values.h"
+#import "ios/web/navigation/crw_error_page_helper.h"
+#import "ios/web/public/js_messaging/script_message.h"
+#import "ios/web/public/js_messaging/web_frame.h"
+#import "ios/web/public/js_messaging/web_frame_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace web {
+
+namespace {
+// The name of the message handler for messages from the error page. Must be
+// kept in sync with components/neterror/resources/error_page_controller_ios.js.
+const char kWebUIMessageHandlerName[] = "ErrorPageMessage";
+
+// The NSUserDefault key to store the easter egg game on error page high score.
+NSString* const kEasterEggHighScore = @"EasterEggHighScore";
+}  // namespace
+
+// static
+ErrorPageJavaScriptFeature* ErrorPageJavaScriptFeature::GetInstance() {
+  static base::NoDestructor<ErrorPageJavaScriptFeature> instance;
+  return instance.get();
+}
+
+ErrorPageJavaScriptFeature::ErrorPageJavaScriptFeature()
+    // This feature must be in the page content world in order to listen for
+    // messages from the Error Page JavaScript.
+    : JavaScriptFeature(ContentWorld::kPageContentWorld, {}) {}
+
+ErrorPageJavaScriptFeature::~ErrorPageJavaScriptFeature() = default;
+
+absl::optional<std::string>
+ErrorPageJavaScriptFeature::GetScriptMessageHandlerName() const {
+  return kWebUIMessageHandlerName;
+}
+
+void ErrorPageJavaScriptFeature::ScriptMessageReceived(
+    WebState* web_state,
+    const ScriptMessage& script_message) {
+  // WebUI messages are only handled if sent from the main frame.
+  if (!script_message.is_main_frame()) {
+    return;
+  }
+
+  absl::optional<GURL> url = script_message.request_url();
+  // Messages must be from an error page.
+  if (!url || ![CRWErrorPageHelper isErrorPageFileURL:url.value()]) {
+    return;
+  }
+
+  if (!script_message.body() || !script_message.body()->is_dict()) {
+    return;
+  }
+
+  const base::Value::Dict& dict = script_message.body()->GetDict();
+
+  const std::string* command = dict.FindString("command");
+  if (!command) {
+    return;
+  }
+
+  if (*command == "updateEasterEggHighScore") {
+    const std::string* high_score_string = dict.FindString("highScore");
+    if (!high_score_string) {
+      return;
+    }
+    int high_score;
+    if (!base::StringToInt(*high_score_string, &high_score)) {
+      return;
+    }
+    [[NSUserDefaults standardUserDefaults] setInteger:high_score
+                                               forKey:kEasterEggHighScore];
+  } else if (*command == "resetEasterEggHighScore") {
+    [[NSUserDefaults standardUserDefaults]
+        removeObjectForKey:kEasterEggHighScore];
+  } else if (*command == "trackEasterEgg") {
+    auto* frame = GetMainFrame(web_state);
+    if (!frame) {
+      return;
+    }
+
+    int high_score = [[NSUserDefaults standardUserDefaults]
+        integerForKey:kEasterEggHighScore];
+    std::vector<base::Value> parameters;
+    parameters.push_back(base::Value(high_score));
+    frame->CallJavaScriptFunction(
+        "errorPageController.initializeEasterEggHighScore", parameters);
+  }
+}
+
+}  // namespace web
diff --git a/ios/web/js_messaging/BUILD.gn b/ios/web/js_messaging/BUILD.gn
index abdfe28..33be392 100644
--- a/ios/web/js_messaging/BUILD.gn
+++ b/ios/web/js_messaging/BUILD.gn
@@ -115,6 +115,7 @@
     "//ios/web/favicon",
     "//ios/web/find_in_page",
     "//ios/web/js_features/context_menu",
+    "//ios/web/js_features/error_page",
     "//ios/web/js_features/scroll_helper",
     "//ios/web/js_features/window_error",
     "//ios/web/navigation:navigation_feature",
diff --git a/ios/web/js_messaging/java_script_feature_util_impl.mm b/ios/web/js_messaging/java_script_feature_util_impl.mm
index cb128d8..eef513a 100644
--- a/ios/web/js_messaging/java_script_feature_util_impl.mm
+++ b/ios/web/js_messaging/java_script_feature_util_impl.mm
@@ -15,6 +15,7 @@
 #import "ios/web/favicon/favicon_java_script_feature.h"
 #import "ios/web/find_in_page/find_in_page_java_script_feature.h"
 #import "ios/web/js_features/context_menu/context_menu_java_script_feature.h"
+#import "ios/web/js_features/error_page/error_page_java_script_feature.h"
 #import "ios/web/js_features/scroll_helper/scroll_helper_java_script_feature.h"
 #import "ios/web/js_features/window_error/window_error_java_script_feature.h"
 #import "ios/web/js_messaging/script_command_java_script_feature.h"
@@ -127,6 +128,7 @@
     BrowserState* browser_state) {
   std::vector<JavaScriptFeature*> features = {
       ContextMenuJavaScriptFeature::FromBrowserState(browser_state),
+      ErrorPageJavaScriptFeature::GetInstance(),
       FindInPageJavaScriptFeature::GetInstance(),
       GetFaviconJavaScriptFeature(),
       GetScrollHelperJavaScriptFeature(),
diff --git a/media/audio/pulse/audio_manager_pulse.cc b/media/audio/pulse/audio_manager_pulse.cc
index f276da549..1efd1cf 100644
--- a/media/audio/pulse/audio_manager_pulse.cc
+++ b/media/audio/pulse/audio_manager_pulse.cc
@@ -45,6 +45,7 @@
       devices_(nullptr),
       native_input_sample_rate_(kDefaultSampleRate),
       native_channel_count_(kDefaultChannelCount),
+      output_sample_rate_(kDefaultSampleRate),
       output_channel_count_(kDefaultChannelCount) {
   DCHECK(input_mainloop_);
   DCHECK(input_context_);
@@ -213,26 +214,24 @@
 AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters(
     const std::string& output_device_id,
     const AudioParameters& input_params) {
-  // TODO(tommi): Support |output_device_id|.
-  // TODO(crbug.com/1408574): Set |sample_rate| from |output_device_id|
-  VLOG_IF(0, !output_device_id.empty()) << "Not implemented!";
-
   int buffer_size = kMinimumOutputBufferSize;
 
   // Query native parameters where applicable; Pulse does not require these to
   // be respected though, so prefer the input parameters for channel count.
   UpdateNativeAudioHardwareInfo();
+  output_sample_rate_ = native_input_sample_rate_ ? native_input_sample_rate_
+                                                  : kDefaultSampleRate;
   output_channel_count_ =
       native_channel_count_ ? native_channel_count_ : kDefaultChannelCount;
-  pa_operation* operation = pa_context_get_sink_info_by_name(
-      input_context_,
-      (output_device_id.empty() ? default_sink_name_ : output_device_id)
-          .c_str(),
-      GetOutputChannelCountCallback, this);
-  WaitForOperationCompletion(input_mainloop_, operation, input_context_);
-
-  int sample_rate = native_input_sample_rate_ ? native_input_sample_rate_
-                                              : kDefaultSampleRate;
+  {
+    AutoPulseLock auto_lock(input_mainloop_);
+    auto* operation = pa_context_get_sink_info_by_name(
+        input_context_,
+        (output_device_id.empty() ? default_sink_name_ : output_device_id)
+            .c_str(),
+        UpdateOutputInfoCallback, this);
+    WaitForOperationCompletion(input_mainloop_, operation, input_context_);
+  }
 
   if ((output_channel_count_ < kMinChannelCount) ||
       (output_channel_count_ > kMaxChannelCount)) {
@@ -266,7 +265,8 @@
     buffer_size = user_buffer_size;
 
   return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
-                         channel_layout_config, sample_rate, buffer_size);
+                         channel_layout_config, output_sample_rate_,
+                         buffer_size);
 }
 
 AudioOutputStream* AudioManagerPulse::MakeOutputStream(
@@ -344,10 +344,10 @@
   manager->devices_->push_back(AudioDeviceName(info->description, info->name));
 }
 
-void AudioManagerPulse::GetOutputChannelCountCallback(pa_context* context,
-                                                      const pa_sink_info* info,
-                                                      int eol,
-                                                      void* user_data) {
+void AudioManagerPulse::UpdateOutputInfoCallback(pa_context* context,
+                                                 const pa_sink_info* info,
+                                                 int eol,
+                                                 void* user_data) {
   AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
 
   if (eol) {
@@ -356,6 +356,7 @@
     return;
   }
 
+  manager->output_sample_rate_ = info->sample_spec.rate;
   manager->output_channel_count_ = info->sample_spec.channels;
 }
 
diff --git a/media/audio/pulse/audio_manager_pulse.h b/media/audio/pulse/audio_manager_pulse.h
index 31b3288..4df70d5 100644
--- a/media/audio/pulse/audio_manager_pulse.h
+++ b/media/audio/pulse/audio_manager_pulse.h
@@ -78,10 +78,10 @@
                                         const pa_sink_info* info,
                                         int eol,
                                         void* user_data);
-  static void GetOutputChannelCountCallback(pa_context* context,
-                                            const pa_sink_info* info,
-                                            int eol,
-                                            void* user_data);
+  static void UpdateOutputInfoCallback(pa_context* context,
+                                       const pa_sink_info* info,
+                                       int eol,
+                                       void* user_data);
 
   // Callback to get the native sample rate of PulseAudio, used by
   // UpdateNativeAudioHardwareInfo().
@@ -112,6 +112,7 @@
   raw_ptr<AudioDeviceNames> devices_;
   int native_input_sample_rate_;
   int native_channel_count_;
+  int output_sample_rate_;
   int output_channel_count_;
   std::string default_source_name_;
   std::string default_sink_name_;
diff --git a/media/base/demuxer.h b/media/base/demuxer.h
index 421b34bb..a392c27 100644
--- a/media/base/demuxer.h
+++ b/media/base/demuxer.h
@@ -144,6 +144,11 @@
   // callback upon completion.
   virtual void Seek(base::TimeDelta time, PipelineStatusCallback status_cb) = 0;
 
+  // Returns whether this demuxer supports seeking and has a timeline. If false,
+  // Seek(), CancelPendingSeek(), StartWaitingForSeek(), and GetTimelineOffset()
+  // should be noops.
+  virtual bool IsSeekable() const = 0;
+
   // Stops this demuxer.
   //
   // After this call the demuxer may be destroyed. It is illegal to call any
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 5b5a9bf7..6ba52a6f 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -258,11 +258,20 @@
 // This provides a mechanism during testing to lock the decoder framerate
 // to a specific value.
 const char kHardwareVideoDecodeFrameRate[] = "hardware-video-decode-framerate";
-// Set the maximum number of decoder threads for hardware video decoders on
-// ChromeOS. This is intended to be used for development only.
+// Set the task runner strategy used for hardware video decoding on ChromeOS.
+// If the option value of --chromeos-decoder-task-runner is
+// * OneThreadPoolSequenceSharedByAllDecoders, then SequencedTaskRunner.
+// * OneThreadPoolThreadSharedByAllDecoders, then SingleThreadTaskRunner
+//   (one of the threads in ThreadPool).
+// * OneDedicatedThreadSharedByAllDecoders, then SingleThreadTaskRunner of
+//   base::Thread("VDdecThread"), which is unique and only used for video
+//   decoders.
+// * OneThreadPoolThreadPerDecoder (default), then SingleThreadTaskRunner
+//   of a dedicated thread newly created in ThreadPool per decoder.
 // TODO(b/195769334): Propagate this to Chrome utility process for
 // Out-of-Process video decoding.
-const char kMaxChromeOSDecoderThreads[] = "max-chromeos-decoder-threads";
+const char kChromeOSVideoDecoderTaskRunner[] =
+    "chromeos-video-decoder-task-runner";
 #endif
 
 const char kCastStreamingForceDisableHardwareH264[] =
@@ -505,6 +514,16 @@
              "D3D11VideoDecoderUseSharedHandle",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Runs the media service in the GPU process on a dedicated thread.
+BASE_FEATURE(kDedicatedMediaServiceThread,
+             "DedicatedMediaServiceThread",
+#if BUILDFLAG(IS_WIN)
+             base::FEATURE_DISABLED_BY_DEFAULT
+#else
+             base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+);
+
 // Falls back to other decoders after audio/video decode error happens. The
 // implementation may choose different strategies on when to fallback. See
 // DecoderStream for details. When disabled, playback will fail immediately
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 43826c5f..e9a6f8f 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -109,7 +109,7 @@
 
 #if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 MEDIA_EXPORT extern const char kHardwareVideoDecodeFrameRate[];
-MEDIA_EXPORT extern const char kMaxChromeOSDecoderThreads[];
+MEDIA_EXPORT extern const char kChromeOSVideoDecoderTaskRunner[];
 #endif
 
 // NOTE: callers should always use the free functions in
@@ -173,6 +173,7 @@
     kChromeWideEchoCancellationAllowAllSampleRates;
 #endif
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kD3D11VideoDecoderUseSharedHandle);
+MEDIA_EXPORT BASE_DECLARE_FEATURE(kDedicatedMediaServiceThread);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kEnableTabMuting);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kExposeSwDecodersToWebRTC);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kExternalClearKeyForTesting);
diff --git a/media/base/media_url_demuxer.cc b/media/base/media_url_demuxer.cc
index 94ff74ff..2fc8d57 100644
--- a/media/base/media_url_demuxer.cc
+++ b/media/base/media_url_demuxer.cc
@@ -72,6 +72,11 @@
                          base::BindOnce(std::move(status_cb), PIPELINE_OK));
 }
 
+bool MediaUrlDemuxer::IsSeekable() const {
+  // While the demuxer itself is not seekable, the underlying player is.
+  return true;
+}
+
 void MediaUrlDemuxer::Stop() {}
 
 void MediaUrlDemuxer::AbortPendingReads() {}
diff --git a/media/base/media_url_demuxer.h b/media/base/media_url_demuxer.h
index 97e3740..f0081e7 100644
--- a/media/base/media_url_demuxer.h
+++ b/media/base/media_url_demuxer.h
@@ -58,6 +58,7 @@
   void StartWaitingForSeek(base::TimeDelta seek_time) override;
   void CancelPendingSeek(base::TimeDelta seek_time) override;
   void Seek(base::TimeDelta time, PipelineStatusCallback status_cb) override;
+  bool IsSeekable() const override;
   void Stop() override;
   void AbortPendingReads() override;
   base::TimeDelta GetStartTime() const override;
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index 43bc904..9a0f822d 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -169,31 +169,43 @@
   void Initialize(DemuxerHost* host, PipelineStatusCallback cb) override {
     OnInitialize(host, cb);
   }
-  MOCK_METHOD2(OnInitialize,
-               void(DemuxerHost* host, PipelineStatusCallback& cb));
-  MOCK_METHOD1(StartWaitingForSeek, void(base::TimeDelta));
-  MOCK_METHOD1(CancelPendingSeek, void(base::TimeDelta));
+  MOCK_METHOD(void,
+              OnInitialize,
+              (DemuxerHost * host, PipelineStatusCallback& cb),
+              ());
+  MOCK_METHOD(void, StartWaitingForSeek, (base::TimeDelta), (override));
+  MOCK_METHOD(void, CancelPendingSeek, (base::TimeDelta), (override));
   void Seek(base::TimeDelta time, PipelineStatusCallback cb) override {
     OnSeek(time, cb);
   }
-  MOCK_METHOD2(OnSeek, void(base::TimeDelta time, PipelineStatusCallback& cb));
-  MOCK_METHOD0(Stop, void());
-  MOCK_METHOD0(AbortPendingReads, void());
-  MOCK_METHOD0(GetAllStreams, std::vector<DemuxerStream*>());
+  MOCK_METHOD(bool, IsSeekable, (), (const override));
+  MOCK_METHOD(void,
+              OnSeek,
+              (base::TimeDelta time, PipelineStatusCallback& cb),
+              ());
+  MOCK_METHOD(void, Stop, (), (override));
+  MOCK_METHOD(void, AbortPendingReads, (), (override));
+  MOCK_METHOD(std::vector<DemuxerStream*>, GetAllStreams, (), (override));
 
-  MOCK_CONST_METHOD0(GetStartTime, base::TimeDelta());
-  MOCK_CONST_METHOD0(GetTimelineOffset, base::Time());
-  MOCK_CONST_METHOD0(GetMemoryUsage, int64_t());
-  MOCK_CONST_METHOD0(GetContainerForMetrics,
-                     absl::optional<container_names::MediaContainerName>());
-  MOCK_METHOD3(OnEnabledAudioTracksChanged,
-               void(const std::vector<MediaTrack::Id>&,
-                    base::TimeDelta,
-                    TrackChangeCB));
-  MOCK_METHOD3(OnSelectedVideoTrackChanged,
-               void(const std::vector<MediaTrack::Id>&,
-                    base::TimeDelta,
-                    TrackChangeCB));
+  MOCK_METHOD(base::TimeDelta, GetStartTime, (), (const, override));
+  MOCK_METHOD(base::Time, GetTimelineOffset, (), (const, override));
+  MOCK_METHOD(int64_t, GetMemoryUsage, (), (const, override));
+  MOCK_METHOD(absl::optional<container_names::MediaContainerName>,
+              GetContainerForMetrics,
+              (),
+              (const, override));
+  MOCK_METHOD(void,
+              OnEnabledAudioTracksChanged,
+              (const std::vector<MediaTrack::Id>&,
+               base::TimeDelta,
+               TrackChangeCB),
+              (override));
+  MOCK_METHOD(void,
+              OnSelectedVideoTrackChanged,
+              (const std::vector<MediaTrack::Id>&,
+               base::TimeDelta,
+               TrackChangeCB),
+              (override));
 };
 
 class MockDemuxerStream : public DemuxerStream {
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 0805876..0f35f352 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -580,6 +580,10 @@
   RunSeekCB_Locked(PIPELINE_OK);
 }
 
+bool ChunkDemuxer::IsSeekable() const {
+  return true;
+}
+
 // Demuxer implementation.
 base::Time ChunkDemuxer::GetTimelineOffset() const {
   return timeline_offset_;
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index c8ce2e5..8241f2f 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -238,6 +238,7 @@
   void Initialize(DemuxerHost* host, PipelineStatusCallback init_cb) override;
   void Stop() override;
   void Seek(base::TimeDelta time, PipelineStatusCallback cb) override;
+  bool IsSeekable() const override;
   base::Time GetTimelineOffset() const override;
   std::vector<DemuxerStream*> GetAllStreams() override;
   base::TimeDelta GetStartTime() const override;
diff --git a/media/filters/demuxer_manager.cc b/media/filters/demuxer_manager.cc
index fd0aa6f..dac32be 100644
--- a/media/filters/demuxer_manager.cc
+++ b/media/filters/demuxer_manager.cc
@@ -354,10 +354,10 @@
   // after metadata is reached - in this case we'll have to do a normal startup.
   if (demuxer_->GetDemuxerType() == DemuxerType::kChunkDemuxer ||
       preload != DataSource::METADATA || client_->CouldPlayIfEnoughData() ||
-      IsStreamingDataSource()) {
+      IsStreaming()) {
     return std::move(on_demuxer_created)
-        .Run(demuxer_.get(), Pipeline::StartType::kNormal,
-             IsStreamingDataSource(), is_static);
+        .Run(demuxer_.get(), Pipeline::StartType::kNormal, IsStreaming(),
+             is_static);
   }
 
   // We can only do a universal suspend for posters, unless the flag is enabled.
@@ -366,7 +366,7 @@
     suspended_mode = Pipeline::StartType::kSuspendAfterMetadata;
   }
   return std::move(on_demuxer_created)
-      .Run(demuxer_.get(), suspended_mode, IsStreamingDataSource(), is_static);
+      .Run(demuxer_.get(), suspended_mode, IsStreaming(), is_static);
 }
 
 #if BUILDFLAG(IS_ANDROID)
@@ -451,8 +451,9 @@
   return data_source_ && data_source_->AssumeFullyBuffered();
 }
 
-bool DemuxerManager::IsStreamingDataSource() const {
-  return data_source_ && data_source_->IsStreaming();
+bool DemuxerManager::IsStreaming() const {
+  return (data_source_ && data_source_->IsStreaming()) ||
+         (demuxer_ && !demuxer_->IsSeekable());
 }
 
 bool DemuxerManager::PassedDataSourceTimingAllowOriginCheck() const {
diff --git a/media/filters/demuxer_manager.h b/media/filters/demuxer_manager.h
index 3425a81..3d411696 100644
--- a/media/filters/demuxer_manager.h
+++ b/media/filters/demuxer_manager.h
@@ -140,7 +140,7 @@
   bool HasDemuxerOverride() const;
   absl::optional<GURL> GetDataSourceUrlAfterRedirects() const;
   bool DataSourceFullyBuffered() const;
-  bool IsStreamingDataSource() const;
+  bool IsStreaming() const;
   bool PassedDataSourceTimingAllowOriginCheck() const;
 
  private:
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 8438d37f..2c1605b 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -1068,6 +1068,10 @@
                                     weak_factory_.GetWeakPtr()));
 }
 
+bool FFmpegDemuxer::IsSeekable() const {
+  return true;
+}
+
 void FFmpegDemuxer::SeekInternal(base::TimeDelta time,
                                  base::OnceClosure seek_cb) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 5ebe7e0..086a7957 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -232,6 +232,7 @@
   void StartWaitingForSeek(base::TimeDelta seek_time) override;
   void CancelPendingSeek(base::TimeDelta seek_time) override;
   void Seek(base::TimeDelta time, PipelineStatusCallback cb) override;
+  bool IsSeekable() const override;
   base::Time GetTimelineOffset() const override;
   std::vector<DemuxerStream*> GetAllStreams() override;
   base::TimeDelta GetStartTime() const override;
diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc
index 9397cb7..0e87d44 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.cc
+++ b/media/gpu/chromeos/video_decoder_pipeline.cc
@@ -4,7 +4,6 @@
 
 #include "media/gpu/chromeos/video_decoder_pipeline.h"
 
-#include <atomic>
 #include <memory>
 
 #include "base/command_line.h"
@@ -93,94 +92,83 @@
     return kExpectedNonLatencyPipelineDepth;
 }
 
-class DecoderThreadPool {
- public:
-  DecoderThreadPool(const DecoderThreadPool&) = delete;
-  DecoderThreadPool& operator=(const DecoderThreadPool&) = delete;
+enum class DecoderTaskRunnerType {
+  kOneThreadPoolSequenceSharedByAllDecoders,
+  kOneThreadPoolThreadSharedByAllDecoders,
+  kOneDedicatedThreadSharedByAllDecoders,
+  kOneThreadPoolThreadPerDecoder,
+  kDefault = kOneThreadPoolThreadPerDecoder,
+};
 
-  static scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner() {
-    static base::NoDestructor<DecoderThreadPool> decoder_thread_pool;
-    return decoder_thread_pool->GetTaskRunner();
+DecoderTaskRunnerType GetDecoderTaskRunnerType() {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (!command_line->HasSwitch(switches::kChromeOSVideoDecoderTaskRunner)) {
+    return DecoderTaskRunnerType::kDefault;
   }
 
- private:
-  friend class base::NoDestructor<DecoderThreadPool>;
-
-  DecoderThreadPool() {
-    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-    if (!command_line->HasSwitch(switches::kMaxChromeOSDecoderThreads))
-      return;
-
-    const std::string& num_threads_switch =
-        command_line->GetSwitchValueASCII(switches::kMaxChromeOSDecoderThreads);
-    if (num_threads_switch.empty()) {
-      LOG(ERROR) << "Failed to read the value of "
-                 << switches::kMaxChromeOSDecoderThreads;
-      return;
-    }
-    size_t num_threads = 0;
-    if (!base::StringToSizeT(num_threads_switch, &num_threads)) {
-      LOG(ERROR) << "Failed to convert the value of "
-                 << switches::kMaxChromeOSDecoderThreads << ", "
-                 << num_threads_switch << ", to integer";
-      return;
-    }
-
-    for (size_t i = 0; i < num_threads; i++) {
-      const std::string thread_name =
-          "VDecThread" +
-          base::NumberToString(base::checked_cast<unsigned int>(i));
-      decoder_threads_.emplace_back(
-          std::make_unique<base::Thread>(thread_name));
-      auto& thread = decoder_threads_.back();
-      if (!thread->Start()) {
-        LOG(ERROR) << "Failed to start thread: " << thread->thread_name();
-        decoder_threads_.clear();
-        task_runners_.clear();
-        return;
-      }
-
-      CHECK(thread->task_runner());
-      task_runners_.emplace_back(thread->task_runner());
-    }
-    VLOGF(2) << decoder_threads_.size() << " VideoDecoder Threads are created";
+  const std::string task_runner_type = command_line->GetSwitchValueASCII(
+      switches::kChromeOSVideoDecoderTaskRunner);
+  if (task_runner_type.empty()) {
+    LOG(ERROR) << "Failed to read the value of "
+               << switches::kChromeOSVideoDecoderTaskRunner;
+    return DecoderTaskRunnerType::kDefault;
   }
 
-  scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() {
-    if (task_runners_.empty()) {
-      // Note that the decoder thread is created with base::MayBlock(). This is
-      // because the underlying |decoder_| may need to allocate a dummy buffer
-      // to discover the most native modifier accepted by the hardware video
-      // decoder; this in turn may need to open the render node, and this is the
-      // operation that may block.
+  if (task_runner_type == "OneThreadPoolSequenceSharedByAllDecoders") {
+    return DecoderTaskRunnerType::kOneThreadPoolSequenceSharedByAllDecoders;
+  }
+  if (task_runner_type == "OneThreadPoolThreadSharedByAllDecoders") {
+    return DecoderTaskRunnerType::kOneThreadPoolThreadSharedByAllDecoders;
+  }
+  if (task_runner_type == "OneDedicatedThreadSharedByAllDecoders") {
+    return DecoderTaskRunnerType::kOneDedicatedThreadSharedByAllDecoders;
+  }
+  if (task_runner_type == "OneThreadPoolThreadPerDecoder") {
+    return DecoderTaskRunnerType::kOneThreadPoolThreadPerDecoder;
+  }
+  return DecoderTaskRunnerType::kDefault;
+}
+
+scoped_refptr<base::SequencedTaskRunner> GetDecoderTaskRunner() {
+  const static DecoderTaskRunnerType type = GetDecoderTaskRunnerType();
+  // Note that the decoder thread is created with base::MayBlock(). This is
+  // because the underlying |decoder_| may need to allocate a dummy buffer
+  // to discover the most native modifier accepted by the hardware video
+  // decoder; this in turn may need to open the render node, and this is the
+  // operation that may block.
+  switch (type) {
+    case DecoderTaskRunnerType::kOneThreadPoolSequenceSharedByAllDecoders:
+      return base::ThreadPool::CreateSequencedTaskRunner(
+          {base::TaskPriority::USER_VISIBLE, base::MayBlock()});
+    case DecoderTaskRunnerType::kOneThreadPoolThreadSharedByAllDecoders:
+      return base::ThreadPool::CreateSingleThreadTaskRunner(
+          {base::TaskPriority::USER_VISIBLE, base::MayBlock()});
+    case DecoderTaskRunnerType::kOneDedicatedThreadSharedByAllDecoders: {
+      class DecoderThread {
+       public:
+        DecoderThread() : thread_("VDecThread") {
+          if (!thread_.Start()) {
+            LOG(FATAL) << "Failed to start the decoder thread";
+          }
+        }
+        scoped_refptr<base::SequencedTaskRunner> task_runner() const {
+          return thread_.task_runner();
+        }
+
+       private:
+        base::Thread thread_;
+      };
+
+      static base::NoDestructor<DecoderThread> decoder_thread;
+      return decoder_thread->task_runner();
+    }
+    case DecoderTaskRunnerType::kOneThreadPoolThreadPerDecoder:
       return base::ThreadPool::CreateSingleThreadTaskRunner(
           {base::WithBaseSyncPrimitives(), base::TaskPriority::USER_VISIBLE,
            base::MayBlock()},
           base::SingleThreadTaskRunnerThreadMode::DEDICATED);
-    }
-
-    // atomic unsigned integer may have undefined behavior on overflow.
-    // Use atomic signed integer, which is stated in the C++ specification;
-    // "Signed integer arithmetic is defined to use two's complement; there are
-    // no undefined results."
-    int atomic_index = counter_.fetch_add(1, std::memory_order_relaxed);
-    size_t index = 0;
-    if (atomic_index == INT_MIN) {
-      // Negating INT_MIN would cause an overflow, so just wrap around to
-      // INT_MAX.
-      atomic_index = INT_MAX;
-    }
-    index = base::checked_cast<size_t>(atomic_index >= 0 ? atomic_index
-                                                         : -atomic_index);
-    index %= task_runners_.size();
-    return task_runners_[index];
   }
-
-  std::vector<std::unique_ptr<base::Thread>> decoder_threads_;
-  std::vector<scoped_refptr<base::SingleThreadTaskRunner>> task_runners_;
-  std::atomic_int counter_{0};
-};
-
+}
 }  //  namespace
 
 VideoDecoderMixin::VideoDecoderMixin(
@@ -289,7 +277,7 @@
     CreateDecoderFunctionCB create_decoder_function_cb)
     : gpu_workarounds_(gpu_workarounds),
       client_task_runner_(std::move(client_task_runner)),
-      decoder_task_runner_(DecoderThreadPool::CreateTaskRunner()),
+      decoder_task_runner_(GetDecoderTaskRunner()),
       main_frame_pool_(std::move(frame_pool)),
       frame_converter_(std::move(frame_converter)),
       media_log_(std::move(media_log)),
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc
index 60c0f80..349967a9 100644
--- a/media/gpu/windows/d3d11_video_decoder.cc
+++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -415,20 +415,10 @@
 
   device_->GetImmediateContext(&device_context_);
 
-  HRESULT hr;
-
   // TODO(liberato): Handle cleanup better.  Also consider being less chatty in
   // the logs, since this will fall back.
 
-  ComD3D11Multithread multi_threaded;
-  hr = device_->QueryInterface(IID_PPV_ARGS(&multi_threaded));
-
-  if (FAILED(hr))
-    return NotifyError({D3D11Status::Codes::kQueryID3D11MultithreadFailed, hr});
-
-  multi_threaded->SetMultithreadProtected(TRUE);
-
-  hr = device_.As(&video_device_);
+  auto hr = device_.As(&video_device_);
   if (FAILED(hr))
     return NotifyError({D3D11Status::Codes::kFailedToGetVideoDevice, hr});
 
diff --git a/media/mojo/mojom/BUILD.gn b/media/mojo/mojom/BUILD.gn
index 660e041..ec8d0ed 100644
--- a/media/mojo/mojom/BUILD.gn
+++ b/media/mojo/mojom/BUILD.gn
@@ -768,6 +768,7 @@
     ":audio_data",
     "//mojo/public/mojom/base",
     "//sandbox/policy/mojom",
+    "//ui/gfx/geometry/mojom",
   ]
 }
 
diff --git a/media/mojo/mojom/speech_recognition.mojom b/media/mojo/mojom/speech_recognition.mojom
index cdb692d0..b720c6a 100644
--- a/media/mojo/mojom/speech_recognition.mojom
+++ b/media/mojo/mojom/speech_recognition.mojom
@@ -6,6 +6,7 @@
 
 import "media/mojo/mojom/audio_data.mojom";
 import "mojo/public/mojom/base/time.mojom";
+import "ui/gfx/geometry/mojom/geometry.mojom";
 
 // Corresponds to the LangIdEvent.ConfidenceInterval defined in
 // http://google3/speech/soda/public/soda_event.proto.
@@ -157,6 +158,34 @@
   SpeechRecognitionLanguageChanged@1(string language);
 };
 
+// The user-facing source of recognized speech; typically a tab. The remote
+// lives in the Ash browser process and is used to trigger behavior in lacros
+// (like focusing the tab). The receiver lives in the lacros browser process.
+[Stable]
+interface SpeechRecognitionSurface {
+  // "Activate" the surface - i.e. bring it to the front and focus it.
+  Activate@0();
+
+  // Fetch the bounds of the surface in screen coordinates. A nullopt is
+  // returned if no bounds could be fetched.
+  GetBounds@1() => (gfx.mojom.Rect? bounds);
+};
+
+// The OS-side observer of a lacros-side speech surface. Used to close or
+// re-render a live caption bubble based on user interaction with the
+// lacros-side surface. The remote lives in the lacros browser process, and the
+// receiver lives in the Ash browser process.
+[Stable]
+interface SpeechRecognitionSurfaceClient {
+  // Called when the user navigates away or refreshes the current tab. This
+  // comprises the end of a live caption "session", after which the caption
+  // bubble can be shown even if it was explicitly dismissed by the user.
+  OnSessionEnded@0();
+
+  // Called when the user fullscreens or un-fullscreens the speech surface.
+  OnFullscreenToggled@1();
+};
+
 // This interface between the speech recognition client and the browser.
 // The remote lives in the renderer process and the receiver lives in the
 // browser process. Not necessary for browser-side features (e.g. CrOS system
diff --git a/media/remoting/stream_provider.cc b/media/remoting/stream_provider.cc
index f6e53c2..7d110e1 100644
--- a/media/remoting/stream_provider.cc
+++ b/media/remoting/stream_provider.cc
@@ -482,6 +482,10 @@
                                base::BindOnce(std::move(seek_cb), PIPELINE_OK));
 }
 
+bool StreamProvider::IsSeekable() const {
+  return false;
+}
+
 void StreamProvider::Stop() {}
 
 base::TimeDelta StreamProvider::GetStartTime() const {
diff --git a/media/remoting/stream_provider.h b/media/remoting/stream_provider.h
index 8fff1b1..69d7242 100644
--- a/media/remoting/stream_provider.h
+++ b/media/remoting/stream_provider.h
@@ -56,6 +56,7 @@
   void StartWaitingForSeek(base::TimeDelta seek_time) override;
   void CancelPendingSeek(base::TimeDelta seek_time) override;
   void Seek(base::TimeDelta time, PipelineStatusCallback status_cb) override;
+  bool IsSeekable() const override;
   void Stop() override;
   base::TimeDelta GetStartTime() const override;
   base::Time GetTimelineOffset() const override;
diff --git a/mojo/core/embedder/embedder.cc b/mojo/core/embedder/embedder.cc
index 59f34a5..b8e39cc2 100644
--- a/mojo/core/embedder/embedder.cc
+++ b/mojo/core/embedder/embedder.cc
@@ -34,12 +34,7 @@
         // BUILDFLAG(IS_ANDROID)
 #endif  // !BUILDFLAG(IS_NACL)
 
-#if BUILDFLAG(IS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
-namespace mojo {
-namespace core {
+namespace mojo::core {
 
 namespace {
 
@@ -80,23 +75,12 @@
       base::FeatureList::IsEnabled(kMojoAvoidRandomPipeId));
 
   if (base::FeatureList::IsEnabled(kMojoIpcz)) {
-    EnableMojoIpczIfSupported();
+    EnableMojoIpcz();
   }
 }
 
-void EnableMojoIpczIfSupported() {
-#if BUILDFLAG(IS_WIN)
-  // TODO(https://crbug.com/1299283): Sandboxed processes on Windows versions
-  // older than 8.1 require some extra (not yet implemented) setup for ipcz to
-  // work properly. This is omitted for early experimentation.
-  const bool kIsIpczSupported =
-      base::win::GetVersion() >= base::win::Version::WIN8_1;
-#else
-  const bool kIsIpczSupported = true;
-#endif
-  if (kIsIpczSupported) {
-    g_mojo_ipcz_enabled.store(true, std::memory_order_release);
-  }
+void EnableMojoIpcz() {
+  g_mojo_ipcz_enabled.store(true, std::memory_order_release);
 }
 
 void Init(const Configuration& configuration) {
@@ -177,5 +161,4 @@
   return ipcz_driver::ObjectBase::ReleaseAsHandle(std::move(transport));
 }
 
-}  // namespace core
-}  // namespace mojo
+}  // namespace mojo::core
diff --git a/mojo/core/embedder/embedder.h b/mojo/core/embedder/embedder.h
index 88645eff..2d31ced8 100644
--- a/mojo/core/embedder/embedder.h
+++ b/mojo/core/embedder/embedder.h
@@ -17,8 +17,7 @@
 #include "mojo/public/cpp/platform/platform_channel_endpoint.h"
 #include "third_party/ipcz/include/ipcz/ipcz.h"
 
-namespace mojo {
-namespace core {
+namespace mojo::core {
 
 // Basic configuration/initialization ------------------------------------------
 
@@ -51,14 +50,13 @@
 // base::Features inside of Mojo.
 COMPONENT_EXPORT(MOJO_CORE_EMBEDDER) void InitFeatures();
 
-// Enables MojoIpcz if it is supported on the current platform. Called before
-// Init() is called. Only call this if the current program doesn't have
-// base::FeatureList integration, since otherwise InitFeatures() will do the
-// work.
+// Enables MojoIpcz. Called before Init() is called. Only call this if the
+// current program doesn't have base::FeatureList integration, since otherwise
+// InitFeatures() will do the work.
 //
 // TODO(crbug.com/1299283): Remove once MojoIpcz becomes the default
 // implementation.
-COMPONENT_EXPORT(MOJO_CORE_EMBEDDER) void EnableMojoIpczIfSupported();
+COMPONENT_EXPORT(MOJO_CORE_EMBEDDER) void EnableMojoIpcz();
 
 // Indicates whether the ipcz-based Mojo implementation is enabled. This can be
 // done by enabling the MojoIpcz feature.
@@ -90,7 +88,6 @@
     const TransportEndpointTypes& endpoint_types,
     base::Process remote_process = base::Process());
 
-}  // namespace core
-}  // namespace mojo
+}  // namespace mojo::core
 
 #endif  // MOJO_CORE_EMBEDDER_EMBEDDER_H_
diff --git a/mojo/public/js/interface_support.js b/mojo/public/js/interface_support.js
index 1f172ee..acd94ac8 100644
--- a/mojo/public/js/interface_support.js
+++ b/mojo/public/js/interface_support.js
@@ -396,8 +396,6 @@
    * @param {!mojo.pipeControl.RunOrClosePipeInput} input
    */
   send(input) {
-    const spec = /** @type {!mojo.internal.StructSpec} */ (
-        mojo.pipeControl.RunOrClosePipeMessageParamsSpec.$.$.structSpec);
     const message = new mojo.internal.Message(
         null, 0xffffffff, 0, mojo.pipeControl.RUN_OR_CLOSE_PIPE_MESSAGE_ID, 0,
         /** @type {!mojo.internal.StructSpec} */
diff --git a/net/websockets/websocket_basic_stream_adapters.cc b/net/websockets/websocket_basic_stream_adapters.cc
index 12c7e5c9..eb50132a 100644
--- a/net/websockets/websocket_basic_stream_adapters.cc
+++ b/net/websockets/websocket_basic_stream_adapters.cc
@@ -75,9 +75,11 @@
   DCHECK(!read_callback_);
   DCHECK_LT(0, buf_len);
 
+  DCHECK(!read_buffer_);
   read_buffer_ = buf;
   // |read_length_| is size_t and |buf_len| is a non-negative int, therefore
   // conversion is always valid.
+  DCHECK(!read_length_);
   read_length_ = buf_len;
 
   if (!read_data_.IsEmpty())
@@ -210,7 +212,11 @@
 }
 
 int WebSocketSpdyStreamAdapter::CopySavedReadDataIntoBuffer() {
+  DCHECK(read_buffer_);
+  DCHECK(read_length_);
   int rv = read_data_.Dequeue(read_buffer_->data(), read_length_);
+  read_buffer_ = nullptr;
+  read_length_ = 0u;
 
   // Stream has been destroyed earlier but delegate_->OnClose() call was
   // delayed until all buffered data are read.  PostTask so that Read() can
diff --git a/net/websockets/websocket_basic_stream_adapters.h b/net/websockets/websocket_basic_stream_adapters.h
index f644b9bf..6c1aebd 100644
--- a/net/websockets/websocket_basic_stream_adapters.h
+++ b/net/websockets/websocket_basic_stream_adapters.h
@@ -131,8 +131,8 @@
 
   // Read buffer and length used for both synchronous and asynchronous
   // read operations.
-  raw_ptr<IOBuffer> read_buffer_;
-  size_t read_length_;
+  raw_ptr<IOBuffer> read_buffer_ = nullptr;
+  size_t read_length_ = 0u;
 
   // Read callback saved for asynchronous reads.
   // Whenever |read_data_| is not empty, |read_callback_| must be null.
diff --git a/remoting/codec/webrtc_video_encoder_av1.cc b/remoting/codec/webrtc_video_encoder_av1.cc
index 4d75f54..b90c4a5 100644
--- a/remoting/codec/webrtc_video_encoder_av1.cc
+++ b/remoting/codec/webrtc_video_encoder_av1.cc
@@ -427,6 +427,13 @@
     LOG(ERROR) << "Encoding error: " << aom_codec_err_to_string(ret) << "\n  "
                << aom_codec_error(codec_.get()) << "\n  "
                << (error_detail ? error_detail : "No error details");
+    // There is an issue where the AV1 codec begins returning AOM_CODEC_ERROR
+    // without any useful error details. This error is not recoverable so no
+    // frames are encoded during this time.  The short-term fix is to reset the
+    // codec while we investigate the root cause (see b/266098558).
+    if (ret == AOM_CODEC_ERROR) {
+      codec_.reset();
+    }
     std::move(done).Run(EncodeResult::UNKNOWN_ERROR, nullptr);
     return;
   }
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 76ed560..8924a19 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -1762,8 +1762,10 @@
         enable_user_interface_);
   }
 
-  // The feature is enabled for all Googlers using a supported platform.
-  desktop_environment_options_.set_enable_remote_open_url(is_googler_);
+  // Always enable remote open URL when the platform supports it. There is an
+  // additional IsRemoteOpenUrlSupported() check that makes sure the capability
+  // won't be advertised if it's missing a registry key or something.
+  desktop_environment_options_.set_enable_remote_open_url(true);
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
   desktop_environment_options_.set_enable_remote_webauthn(is_googler_);
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 234ed68..a18a7d6a 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5839,9 +5839,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_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -5853,8 +5853,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -6010,9 +6010,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -6024,8 +6024,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -6162,9 +6162,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -6176,8 +6176,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fuchsia.json b/testing/buildbot/chromium.fuchsia.json
index bb55022..b86c8617 100644
--- a/testing/buildbot/chromium.fuchsia.json
+++ b/testing/buildbot/chromium.fuchsia.json
@@ -4318,7 +4318,8 @@
         "args": [
           "--test-arg=--disable-gpu",
           "--test-arg=--headless",
-          "--test-arg=--ozone-platform=headless"
+          "--test-arg=--ozone-platform=headless",
+          "--test-arg=--test-launcher-jobs=1"
         ],
         "merge": {
           "args": [],
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 993374ca..a23406e 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -80772,9 +80772,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_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -80786,8 +80786,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -80913,9 +80913,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -80927,8 +80927,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -81040,9 +81040,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -81054,8 +81054,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -82388,9 +82388,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_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -82401,8 +82401,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -82559,9 +82559,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -82572,8 +82572,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -82711,9 +82711,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -82724,8 +82724,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -84249,9 +84249,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_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -84262,8 +84262,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -84420,9 +84420,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -84433,8 +84433,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -84572,9 +84572,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -84585,8 +84585,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -85358,9 +85358,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_v111.0.5547.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -85371,8 +85371,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index f0ea845..edf9927a 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -18532,12 +18532,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_v111.0.5547.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18549,8 +18549,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -18723,12 +18723,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18740,8 +18740,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
@@ -18890,12 +18890,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5547.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 111.0.5547.0",
+        "description": "Run with ash-chrome version 111.0.5548.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18907,8 +18907,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5547.0",
-              "revision": "version:111.0.5547.0"
+              "location": "lacros_version_skew_tests_v111.0.5548.0",
+              "revision": "version:111.0.5548.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 75d53d79..448d5753 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1802,6 +1802,11 @@
         'swarming': {
           'shards': 41,
         },
+        'args': [
+          # TODO(crbug.com/1406693): Remove this when the kernal panic in
+          # fuchsia has been resolved.
+          '--test-arg=--test-launcher-jobs=1',
+        ],
       },
       'linux-chromeos-code-coverage': {
         'swarming': {
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 9f90bde..4899a14f 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_v111.0.5547.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5548.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 111.0.5547.0',
+    'description': 'Run with ash-chrome version 111.0.5548.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_v111.0.5547.0',
-          'revision': 'version:111.0.5547.0',
+          'location': 'lacros_version_skew_tests_v111.0.5548.0',
+          'revision': 'version:111.0.5548.0',
         },
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index a223d3f..3bffad7a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3279,17 +3279,6 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled_20230118",
-                    "params": {
-                        "launch_stage": "prod"
-                    },
-                    "enable_features": [
-                        "FederatedService",
-                        "FederatedServiceScheduleTasks",
-                        "FederatedTimezoneCodePhh"
-                    ]
-                },
-                {
                     "name": "Enabled_Dogfood",
                     "params": {
                         "launch_stage": "dogfood"
@@ -6306,6 +6295,25 @@
             ]
         }
     ],
+    "InnerHTMLParserFastpath": [
+        {
+            "platforms": [
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "InnerHTMLParserFastpath"
+                    ]
+                }
+            ]
+        }
+    ],
     "InstallAndroidUnwindDfm": [
         {
             "platforms": [
diff --git a/third_party/blink/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.cc b/third_party/blink/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.cc
index b88fc40..c520864a 100644
--- a/third_party/blink/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.cc
+++ b/third_party/blink/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.cc
@@ -64,6 +64,38 @@
 }
 
 // static
+blink::mojom::DeprecatedFencedFrameMode
+EnumTraits<blink::mojom::DeprecatedFencedFrameMode,
+           blink::FencedFrame::DeprecatedFencedFrameMode>::
+    ToMojom(blink::FencedFrame::DeprecatedFencedFrameMode input) {
+  switch (input) {
+    case blink::FencedFrame::DeprecatedFencedFrameMode::kDefault:
+      return blink::mojom::DeprecatedFencedFrameMode::kDefault;
+    case blink::FencedFrame::DeprecatedFencedFrameMode::kOpaqueAds:
+      return blink::mojom::DeprecatedFencedFrameMode::kOpaqueAds;
+  }
+  NOTREACHED();
+  return blink::mojom::DeprecatedFencedFrameMode::kDefault;
+}
+
+// static
+bool EnumTraits<blink::mojom::DeprecatedFencedFrameMode,
+                blink::FencedFrame::DeprecatedFencedFrameMode>::
+    FromMojom(blink::mojom::DeprecatedFencedFrameMode input,
+              blink::FencedFrame::DeprecatedFencedFrameMode* out) {
+  switch (input) {
+    case blink::mojom::DeprecatedFencedFrameMode::kDefault:
+      *out = blink::FencedFrame::DeprecatedFencedFrameMode::kDefault;
+      return true;
+    case blink::mojom::DeprecatedFencedFrameMode::kOpaqueAds:
+      *out = blink::FencedFrame::DeprecatedFencedFrameMode::kOpaqueAds;
+      return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
+// static
 bool StructTraits<blink::mojom::FencedFrameReportingDataView,
                   blink::FencedFrame::FencedFrameReporting>::
     Read(blink::mojom::FencedFrameReportingDataView data,
@@ -418,7 +450,7 @@
     Read(blink::mojom::FencedFrameConfigDataView data,
          blink::FencedFrame::RedactedFencedFrameConfig* out_config) {
   GURL urn_uuid;
-  if (!data.ReadUrnUuid(&urn_uuid) ||
+  if (!data.ReadUrnUuid(&urn_uuid) || !data.ReadMode(&out_config->mode_) ||
       !data.ReadMappedUrl(&out_config->mapped_url_) ||
       !data.ReadContentSize(&out_config->content_size_) ||
       !data.ReadContainerSize(&out_config->container_size_) ||
@@ -470,6 +502,7 @@
          blink::FencedFrame::RedactedFencedFrameProperties* out_properties) {
   blink::mojom::PotentiallyOpaqueURNConfigVectorPtr nested_urn_config_pairs;
   if (!data.ReadMappedUrl(&out_properties->mapped_url_) ||
+      !data.ReadMode(&out_properties->mode_) ||
       !data.ReadContentSize(&out_properties->content_size_) ||
       !data.ReadContainerSize(&out_properties->container_size_) ||
       !data.ReadDeprecatedShouldFreezeInitialSize(
diff --git a/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h b/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h
index fa6fb83..125cbb2 100644
--- a/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h
+++ b/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h
@@ -40,6 +40,14 @@
   kSharedStorageSelectUrl,
 };
 
+// TODO(crbug.com/1347953): Decompose this into flags that directly control the
+// behavior of the frame, e.g. sandbox flags. We do not want mode to exist as a
+// concept going forward.
+enum DeprecatedFencedFrameMode {
+  kDefault,
+  kOpaqueAds,
+};
+
 struct BLINK_COMMON_EXPORT FencedFrameReporting {
   // If this is an "opaque-ads" mode fenced frame, there might be an associated
   // reporting metadata. This is a map from destination type to reporting
@@ -130,6 +138,7 @@
   reporting_metadata() const {
     return reporting_metadata_;
   }
+  const DeprecatedFencedFrameMode& mode() const { return mode_; }
 
  private:
   friend struct content::FencedFrameConfig;
@@ -154,6 +163,9 @@
       shared_storage_budget_metadata_;
   absl::optional<RedactedFencedFrameProperty<FencedFrameReporting>>
       reporting_metadata_;
+
+  // TODO(crbug.com/1347953): Not yet used.
+  DeprecatedFencedFrameMode mode_ = DeprecatedFencedFrameMode::kDefault;
 };
 
 // Represents a set of fenced frame properties (instantiated from a config) that
@@ -199,6 +211,7 @@
   reporting_metadata() const {
     return reporting_metadata_;
   }
+  const DeprecatedFencedFrameMode& mode() const { return mode_; }
 
  private:
   friend struct content::FencedFrameProperties;
@@ -222,6 +235,7 @@
       shared_storage_budget_metadata_;
   absl::optional<RedactedFencedFrameProperty<FencedFrameReporting>>
       reporting_metadata_;
+  DeprecatedFencedFrameMode mode_ = DeprecatedFencedFrameMode::kDefault;
 };
 
 }  // namespace blink::FencedFrame
diff --git a/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.h b/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.h
index 4a5cfee..798af82 100644
--- a/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.h
+++ b/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.h
@@ -36,6 +36,16 @@
 
 template <>
 struct BLINK_COMMON_EXPORT
+    EnumTraits<blink::mojom::DeprecatedFencedFrameMode,
+               blink::FencedFrame::DeprecatedFencedFrameMode> {
+  static blink::mojom::DeprecatedFencedFrameMode ToMojom(
+      blink::FencedFrame::DeprecatedFencedFrameMode input);
+  static bool FromMojom(blink::mojom::DeprecatedFencedFrameMode input,
+                        blink::FencedFrame::DeprecatedFencedFrameMode* out);
+};
+
+template <>
+struct BLINK_COMMON_EXPORT
     StructTraits<blink::mojom::FencedFrameReportingDataView,
                  blink::FencedFrame::FencedFrameReporting> {
   static const base::flat_map<blink::FencedFrame::ReportingDestination,
@@ -267,6 +277,11 @@
     return config.reporting_metadata_;
   }
 
+  static const blink::FencedFrame::DeprecatedFencedFrameMode& mode(
+      const blink::FencedFrame::RedactedFencedFrameConfig& config) {
+    return config.mode_;
+  }
+
   static bool Read(blink::mojom::FencedFrameConfigDataView data,
                    blink::FencedFrame::RedactedFencedFrameConfig* out_config);
 };
@@ -311,6 +326,10 @@
       const blink::FencedFrame::RedactedFencedFrameProperties& properties) {
     return properties.reporting_metadata_;
   }
+  static const blink::FencedFrame::DeprecatedFencedFrameMode& mode(
+      const blink::FencedFrame::RedactedFencedFrameProperties& properties) {
+    return properties.mode_;
+  }
 
   static bool Read(
       blink::mojom::FencedFramePropertiesDataView data,
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index 0655bb2..01fdf86 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -552,6 +552,10 @@
           cpp = "::blink::FencedFrame::FencedFrameReporting"
         },
         {
+          mojom = "blink.mojom.DeprecatedFencedFrameMode"
+          cpp = "::blink::FencedFrame::DeprecatedFencedFrameMode"
+        },
+        {
           mojom = "blink.mojom.PotentiallyOpaqueURL"
           cpp = "::blink::FencedFrame::RedactedFencedFrameProperty<GURL>"
         },
diff --git a/third_party/blink/public/mojom/fenced_frame/fenced_frame_config.mojom b/third_party/blink/public/mojom/fenced_frame/fenced_frame_config.mojom
index 943e069..cbd9042 100644
--- a/third_party/blink/public/mojom/fenced_frame/fenced_frame_config.mojom
+++ b/third_party/blink/public/mojom/fenced_frame/fenced_frame_config.mojom
@@ -27,6 +27,18 @@
   map<ReportingDestination, map<string, url.mojom.Url>> metadata;
 };
 
+// The fenced frame config's "mode" describes a set of functionalities that it
+// should have. (In the future, the concept of a "mode" will be removed, and
+// replaced with individual fields controlling each functionality.)
+// The mode is a function of the API that creates the config. FLEDGE and
+// sharedStorage use kOpaqueAds mode, and the WebIDL FencedFrameConfig()
+// constructor uses kDefault mode.
+// https://github.com/WICG/fenced-frame/blob/master/explainer/modes.md
+enum DeprecatedFencedFrameMode {
+  kDefault = 0,
+  kOpaqueAds = 1,
+};
+
 // In order to represent that a value exists in a different process but is
 // hidden from this process, we use a union of a type T and this singleton enum
 // `Opaque`. (This is used by a more privileged process to censor information
@@ -135,6 +147,13 @@
   // represents this instance of this struct. `blink::IsValidUrnUuidURL()` will
   // always be true when called with this urn.
   url.mojom.Url urn_uuid;
+
+  // The fenced frame's mode (default or opaque-ads).
+  // TODO(crbug.com/1347953): This field is not yet used.
+  // TODO(crbug.com/1347953): Decompose this field into flags that directly
+  // control the frame's behavior, e.g. sandbox flags. We don't want the
+  // concept of a mode to stick around in the future.
+  DeprecatedFencedFrameMode mode;
 };
 
 // The `FencedFrameProperties` struct is used to transfer a redacted version
@@ -174,4 +193,6 @@
   // metadata which in turn is a map from the event type to the reporting url.
   // https://github.com/WICG/turtledove/blob/main/Fenced_Frames_Ads_Reporting.md
   PotentiallyOpaqueReportingMetadata? reporting_metadata;
+
+  DeprecatedFencedFrameMode mode;
 };
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom
index 9a33fa3..9c6bfc1 100644
--- a/third_party/blink/public/mojom/frame/frame.mojom
+++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -172,14 +172,13 @@
   network.mojom.ContentSecurityPolicy? parsed_csp_attribute;
   // 'credentialless' attribute of the iframe.
   bool credentialless;
-  // TODO(crbug.com/1402594): Make the attributes optional.
-  // 'id' attribute of the iframe.
-  string id;
+  // 'id' attribute of the iframe. This can be optional because id might not be set.
+  string? id;
   // 'name' attribute of the iframe. This is different from window.name, which is
-  // tracked in FrameReplicationState.
-  string name;
-  // 'src' attribute of the iframe.
-  string src;
+  // tracked in FrameReplicationState. Optional because it might not be set.
+  string? name;
+  // 'src' attribute of the iframe. Optional because it might not be set.
+  string? src;
 };
 
 // An opaque handle that keeps alive the associated render process even after
diff --git a/third_party/blink/public/mojom/frame/frame_policy.mojom b/third_party/blink/public/mojom/frame/frame_policy.mojom
index 365f00c4..ba718c5 100644
--- a/third_party/blink/public/mojom/frame/frame_policy.mojom
+++ b/third_party/blink/public/mojom/frame/frame_policy.mojom
@@ -13,6 +13,9 @@
 // These values represent the `mode` attribute of the fenced frame element. Keep
 // this values in sync with the conditions in `GetModeAttributeValue()` in
 // `html_fenced_frame_element.cc`.
+// TODO(crbug.com/1347953): Remove this type in favor of
+// `DeprecatedFencedFrameMode` in `fenced_frame_config.mojom`, which will
+// itself be removed at a later date.
 enum FencedFrameMode {
   kDefault = 0,
   kOpaqueAds = 1,
diff --git a/third_party/blink/renderer/controller/highest_pmf_reporter_test.cc b/third_party/blink/renderer/controller/highest_pmf_reporter_test.cc
index 2d42181..0cc207d 100644
--- a/third_party/blink/renderer/controller/highest_pmf_reporter_test.cc
+++ b/third_party/blink/renderer/controller/highest_pmf_reporter_test.cc
@@ -184,7 +184,13 @@
   EXPECT_EQ(0U, reporter_->GetReportedPeakRss().size());
 }
 
-TEST_F(HighestPmfReporterTest, ReportMetric) {
+// TODO(https://crbug.com/1408949): This test fails on ASAN bots.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_ReportMetric DISABLED_ReportMetric
+#else
+#define MAYBE_ReportMetric ReportMetric
+#endif
+TEST_F(HighestPmfReporterTest, MAYBE_ReportMetric) {
   EXPECT_TRUE(memory_usage_monitor_->TimerIsActive());
   Page::OrdinaryPages().insert(&GetPage());
   AdvanceClock(base::Seconds(1));
diff --git a/third_party/blink/renderer/core/exported/web_media_player_impl_unittest.cc b/third_party/blink/renderer/core/exported/web_media_player_impl_unittest.cc
index a514bc9..a92ce4af 100644
--- a/third_party/blink/renderer/core/exported/web_media_player_impl_unittest.cc
+++ b/third_party/blink/renderer/core/exported/web_media_player_impl_unittest.cc
@@ -366,10 +366,6 @@
         .WillByDefault(ReturnRef(surface_id_));
   }
 
-  void InitializeWebMediaPlayerImpl() {
-    InitializeWebMediaPlayerImplInternal(nullptr);
-  }
-
   WebMediaPlayerImplTest(const WebMediaPlayerImplTest&) = delete;
   WebMediaPlayerImplTest& operator=(const WebMediaPlayerImplTest&) = delete;
 
@@ -390,8 +386,8 @@
   }
 
  protected:
-  void InitializeWebMediaPlayerImplInternal(
-      std::unique_ptr<media::Demuxer> demuxer_override) {
+  void InitializeWebMediaPlayerImpl(
+      std::unique_ptr<media::Demuxer> demuxer_override = nullptr) {
     auto media_log = std::make_unique<NiceMock<media::MockMediaLog>>();
     InitializeSurfaceLayerBridge();
 
@@ -595,6 +591,8 @@
 
   bool IsSuspended() { return wmpi_->pipeline_controller_->IsSuspended(); }
 
+  bool IsStreaming() const { return wmpi_->IsStreaming(); }
+
   int64_t GetDataSourceMemoryUsage() const {
     return wmpi_->demuxer_manager_->GetDataSourceMemoryUsage();
   }
@@ -748,14 +746,20 @@
     // to the WebAssociatedURLLoaderClient handed out by the DataSource after it
     // requests loading of a resource. We then use that client as if we are the
     // network stack and "serve" an in memory file to the DataSource.
+    const bool should_have_client =
+        !wmpi_->demuxer_manager_->HasDemuxerOverride();
     WebAssociatedURLLoaderClient* client = nullptr;
-    EXPECT_CALL(mock_resource_fetch_context_, CreateUrlLoader(_))
-        .WillRepeatedly(Invoke([&client](const WebAssociatedURLLoaderOptions&) {
-          auto a = std::make_unique<NiceMock<MockWebAssociatedURLLoader>>();
-          EXPECT_CALL(*a, LoadAsynchronously(_, _))
-              .WillRepeatedly(testing::SaveArg<1>(&client));
-          return a;
-        }));
+    if (should_have_client) {
+      EXPECT_CALL(mock_resource_fetch_context_, CreateUrlLoader(_))
+          .WillRepeatedly(
+              Invoke([&client](const WebAssociatedURLLoaderOptions&) {
+                auto a =
+                    std::make_unique<NiceMock<MockWebAssociatedURLLoader>>();
+                EXPECT_CALL(*a, LoadAsynchronously(_, _))
+                    .WillRepeatedly(testing::SaveArg<1>(&client));
+                return a;
+              }));
+    }
 
     wmpi_->Load(WebMediaPlayer::kLoadTypeURL,
                 WebMediaPlayerSource(WebURL(kTestURL)),
@@ -763,6 +767,10 @@
                 /*is_cache_disabled=*/false);
 
     base::RunLoop().RunUntilIdle();
+    if (!should_have_client) {
+      return;
+    }
+    EXPECT_TRUE(client);
 
     // Load a real media file into memory.
     scoped_refptr<media::DecoderBuffer> data =
@@ -1594,6 +1602,24 @@
   EXPECT_FALSE(state.is_memory_reporting_enabled);
 }
 
+TEST_F(WebMediaPlayerImplTest, IsStreamingIfDemuxerDoesntSupportSeeking) {
+  std::unique_ptr<media::MockDemuxer> demuxer =
+      std::make_unique<NiceMock<media::MockDemuxer>>();
+  ON_CALL(*demuxer, IsSeekable()).WillByDefault(Return(false));
+  InitializeWebMediaPlayerImpl(std::move(demuxer));
+  Load(kVideoOnlyTestFile);
+  EXPECT_TRUE(IsStreaming());
+}
+
+TEST_F(WebMediaPlayerImplTest, IsNotStreamingIfDemuxerSupportsSeeking) {
+  std::unique_ptr<media::MockDemuxer> demuxer =
+      std::make_unique<NiceMock<media::MockDemuxer>>();
+  ON_CALL(*demuxer, IsSeekable()).WillByDefault(Return(true));
+  InitializeWebMediaPlayerImpl(std::move(demuxer));
+  Load(kVideoOnlyTestFile);
+  EXPECT_FALSE(IsStreaming());
+}
+
 TEST_F(WebMediaPlayerImplTest, ResumeEnded) {
   media::PipelineMetadata metadata;
   metadata.has_video = true;
@@ -2334,7 +2360,7 @@
   // Called when WebMediaPlayerImpl is destroyed.
   EXPECT_CALL(*demuxer.get(), Stop());
 
-  InitializeWebMediaPlayerImplInternal(std::move(demuxer));
+  InitializeWebMediaPlayerImpl(std::move(demuxer));
 
   EXPECT_FALSE(IsSuspended());
   wmpi_->Load(WebMediaPlayer::kLoadTypeURL,
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc
index 3a5499d..3b79082e 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath.cc
@@ -579,6 +579,7 @@
     pos_ = start;
     attribute_name_buffer_.resize(0);
     Char c;
+    // IsValidAttributeNameChar() returns false if end of input is reached.
     while (c = GetNext(), IsValidAttributeNameChar(c)) {
       if ('A' <= c && c <= 'Z') {
         c = c - ('A' - 'a');
@@ -596,13 +597,17 @@
     const Char* start = pos_;
     if (Char quote_char = GetNext(); quote_char == '"' || quote_char == '\'') {
       start = ++pos_;
-      while (GetNext() != quote_char) {
+      while (pos_ != end_ && GetNext() != quote_char) {
         if (GetNext() == '&' || GetNext() == '\r') {
           pos_ = start - 1;
           return {Span{}, ScanEscapedAttrValue()};
         }
         ++pos_;
       }
+      if (pos_ == end_) {
+        return Fail(HtmlFastPathResult::kFailedParsingQuotedAttributeValue,
+                    std::pair{Span{}, USpan{}});
+      }
       result = Span{start, static_cast<size_t>(pos_ - start)};
       if (ConsumeNext() != quote_char) {
         return Fail(HtmlFastPathResult::kFailedParsingQuotedAttributeValue,
@@ -630,7 +635,7 @@
     const Char* start = pos_;
     if (Char quote_char = GetNext(); quote_char == '"' || quote_char == '\'') {
       start = ++pos_;
-      while (GetNext() != quote_char) {
+      while (pos_ != end_ && GetNext() != quote_char) {
         if (failed_) {
           return USpan{};
         }
@@ -649,6 +654,11 @@
           ++pos_;
         }
       }
+      if (pos_ == end_) {
+        return Fail(
+            HtmlFastPathResult::kFailedParsingQuotedEscapedAttributeValue,
+            USpan());
+      }
       result = Span{start, static_cast<size_t>(pos_ - start)};
       if (ConsumeNext() != quote_char) {
         return Fail(
@@ -767,6 +777,7 @@
   }
 
   Char GetNext() {
+    DCHECK_LE(pos_, end_);
     if (pos_ == end_) {
       Fail(HtmlFastPathResult::kFailedEndOfInputReached);
       return '\0';
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
index 7dc33cc..bb08b6c 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -306,9 +306,9 @@
       builder.AddNull("blocked");
       break;
   }
-  builder.AddString("src", AtomicString(reasons->src));
-  builder.AddString("id", AtomicString(reasons->id));
-  builder.AddString("name", AtomicString(reasons->name));
+  builder.AddStringOrNull("src", AtomicString(reasons->src));
+  builder.AddStringOrNull("id", AtomicString(reasons->id));
+  builder.AddStringOrNull("name", AtomicString(reasons->name));
   Vector<AtomicString> reason_strings;
   Vector<v8::Local<v8::Value>> children_result;
   if (reasons->same_origin_details) {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
index d164ac9..b6ee0a8f 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
@@ -53,7 +53,6 @@
 #include "third_party/blink/renderer/platform/resolution_units.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
-#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "third_party/skia/include/core/SkPoint.h"
@@ -92,30 +91,8 @@
   if (hb_font_data->range_set_ && !hb_font_data->range_set_->Contains(unicode))
     return false;
 
-  hb_bool_t hb_has_glyph = hb_font_get_glyph(
-      hb_font_get_parent(hb_font), unicode, variation_selector, glyph);
-// MacOS CoreText API synthesizes GlyphID for several unicode codepoints,
-// for example, hyphens and separators for some fonts. HarfBuzz does not
-// synthesize such glyphs, and as it's not found from the last resort font, we
-// end up with displaying tofu, see https://crbug.com/1267606 for details.
-// Chrome uses Times as last resort fallback font and in Times the only visible
-// synthesizing characters are hyphen (0x2010) and non-breaking hyphen (0x2011).
-// For performance reasons, we limit this fallback lookup to the specific
-// missing glyphs for hyphens and only to Mac OS, where we're facing this issue.
-#if BUILDFLAG(IS_MAC)
-  if (!hb_has_glyph) {
-    SkTypeface* typeface = hb_font_data->font_.getTypeface();
-    if (!typeface) {
-      return false;
-    }
-    if (unicode == kHyphenCharacter || unicode == kNonBreakingHyphen) {
-      SkGlyphID sk_glyph_id = typeface->unicharToGlyph(unicode);
-      *glyph = sk_glyph_id;
-      return sk_glyph_id;
-    }
-  }
-#endif
-  return hb_has_glyph;
+  return hb_font_get_glyph(hb_font_get_parent(hb_font), unicode,
+                           variation_selector, glyph);
 }
 
 static hb_bool_t HarfBuzzGetNominalGlyph(hb_font_t* hb_font,
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
index c28545c..647a8d7 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
@@ -593,17 +593,13 @@
   // Apply effects.
   result_.StartPaint();
   if (!has_filter) {
-    // TODO(ajuma): This should really be rounding instead of flooring the
-    // alpha value, but that breaks slimming paint reftests.
-    auto alpha = base::ClampFloor<uint8_t>(255 * effect.Opacity());
     if (has_other_effects) {
       cc::PaintFlags flags;
       flags.setBlendMode(effect.BlendMode());
-      flags.setAlphaf(alpha / 255.0f);
+      flags.setAlphaf(effect.Opacity());
       save_layer_id = push<cc::SaveLayerOp>(flags);
     } else {
-      save_layer_id =
-          push<cc::SaveLayerAlphaOp>(static_cast<float>(alpha / 255.0f));
+      save_layer_id = push<cc::SaveLayerAlphaOp>(effect.Opacity());
     }
   } else {
     // Handle filter effect.
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
index 745407c2..99cb93ba 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
@@ -124,10 +124,10 @@
   EXPECT_THAT(
       output,
       ElementsAre(PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(0, 0, 90, 90),
-                                                 127 / 255.f)),  // <e1>
-                  PaintOpIs<cc::DrawRecordOp>(),                 // <p0/>
-                  PaintOpIs<cc::DrawRecordOp>(),                 // <p1/>
-                  PaintOpIs<cc::RestoreOp>()));                  // </e1>
+                                                 0.5f)),  // <e1>
+                  PaintOpIs<cc::DrawRecordOp>(),          // <p0/>
+                  PaintOpIs<cc::DrawRecordOp>(),          // <p1/>
+                  PaintOpIs<cc::RestoreOp>()));           // </e1>
 }
 
 TEST_P(PaintChunksToCcLayerTest, EffectGroupingNested) {
@@ -145,16 +145,16 @@
       output,
       ElementsAre(
           PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(0, 0, 444, 666),
-                                         127 / 255.f)),  // <e1>
+                                         0.5f)),  // <e1>
           PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(0, 0, 100, 100),
-                                         127 / 255.f)),  // <e2>
-          PaintOpIs<cc::DrawRecordOp>(),                 // <p0/>
-          PaintOpIs<cc::RestoreOp>(),                    // </e2>
+                                         0.5f)),  // <e2>
+          PaintOpIs<cc::DrawRecordOp>(),          // <p0/>
+          PaintOpIs<cc::RestoreOp>(),             // </e2>
           PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(111, 222, 333, 444),
-                                         127 / 255.f)),  // <e3>
-          PaintOpIs<cc::DrawRecordOp>(),                 // <p1/>
-          PaintOpIs<cc::RestoreOp>(),                    // </e3>
-          PaintOpIs<cc::RestoreOp>()));                  // </e1>
+                                         0.5f)),  // <e3>
+          PaintOpIs<cc::DrawRecordOp>(),          // <p1/>
+          PaintOpIs<cc::RestoreOp>(),             // </e3>
+          PaintOpIs<cc::RestoreOp>()));           // </e1>
 }
 
 TEST_P(PaintChunksToCcLayerTest, EffectFilterGroupingNestedWithTransforms) {
@@ -184,8 +184,8 @@
               gfx::TransformToSkM44(t1->Matrix() * t2->Matrix()))),  // <t1*t2>
           // chunk1.bounds + e2(t2^-1(chunk2.bounds))
           PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(0, 0, 155, 155),
-                                         127 / 255.f)),  // <e1>
-          PaintOpIs<cc::DrawRecordOp>(),                 // <p1/>
+                                         0.5f)),  // <e1>
+          PaintOpIs<cc::DrawRecordOp>(),          // <p1/>
           // t2^-1(chunk2.bounds)
           PaintOpEq(cc::SaveLayerOp(SkRect::MakeXYWH(70, 70, 70, 70),
                                     expected_flags)),  // <e2>
@@ -231,14 +231,14 @@
                   PaintOpIs<cc::DrawRecordOp>(),  // <p1/>
                   PaintOpIs<cc::RestoreOp>(),     // </c3>
                   PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(0, 0, 90, 90),
-                                                 127 / 255.f)),  // <e1>
+                                                 0.5f)),  // <e1>
                   PaintOpIs<cc::SaveOp>(),
                   PaintOpIs<cc::ClipRectOp>(),  // <c3+c4>
                   PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(0, 0, 50, 50),
-                                                 127 / 255.f)),  // <e2>
-                  PaintOpIs<cc::DrawRecordOp>(),                 // <p2/>
-                  PaintOpIs<cc::RestoreOp>(),                    // </e2>
-                  PaintOpIs<cc::RestoreOp>(),                    // </c3+c4>
+                                                 0.5f)),  // <e2>
+                  PaintOpIs<cc::DrawRecordOp>(),          // <p2/>
+                  PaintOpIs<cc::RestoreOp>(),             // </e2>
+                  PaintOpIs<cc::RestoreOp>(),             // </c3+c4>
                   PaintOpIs<cc::SaveOp>(),
                   PaintOpIs<cc::ClipRectOp>(),    // <c3>
                   PaintOpIs<cc::DrawRecordOp>(),  // <p3/>
@@ -296,7 +296,7 @@
           PaintOpIs<cc::SaveOp>(),
           PaintOpEq(cc::ConcatOp(gfx::TransformToSkM44(t1->Matrix()))),  // <t1>
           PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(0, 0, 100, 100),
-                                         127 / 255.f)),  // <e1>
+                                         0.5f)),  // <e1>
           PaintOpIs<cc::SaveOp>(),
           PaintOpEq(cc::ConcatOp(gfx::TransformToSkM44(
               t1->Matrix().GetCheckedInverse()))),  // <t1^-1>
@@ -388,7 +388,7 @@
       chunks.Build(), PropertyTreeState(t0(), *c1, e0()));
   EXPECT_THAT(output, ElementsAre(PaintOpEq(cc::SaveLayerAlphaOp(
                                       SkRect::MakeXYWH(0, 0, 100, 100),
-                                      127 / 255.f)),  // <e1>
+                                      0.5f)),  // <e1>
                                   PaintOpIs<cc::SaveOp>(),
                                   PaintOpIs<cc::ClipRectOp>(),    // <c2>
                                   PaintOpIs<cc::DrawRecordOp>(),  // <p0/>
@@ -411,9 +411,9 @@
       output,
       ElementsAre(
           PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(0, 0, 100, 100),
-                                         127 / 255.f)),  // <e1>
+                                         0.5f)),  // <e1>
           PaintOpEq(cc::SaveLayerAlphaOp(SkRect::MakeXYWH(0, 0, 100, 100),
-                                         127 / 255.f)),  // <e2>
+                                         0.5f)),  // <e2>
           PaintOpIs<cc::SaveOp>(),
           PaintOpIs<cc::ClipRectOp>(),    // <c1>
           PaintOpIs<cc::DrawRecordOp>(),  // <p0/>
@@ -435,7 +435,7 @@
       chunks.Build(), PropertyTreeState(t0(), c0(), *e1));
   EXPECT_THAT(output, ElementsAre(PaintOpEq(cc::SaveLayerAlphaOp(
                                       SkRect::MakeXYWH(0, 0, 100, 100),
-                                      127 / 255.f)),  // <e2>
+                                      0.5f)),  // <e2>
                                   PaintOpIs<cc::SaveOp>(),
                                   PaintOpIs<cc::ClipRectOp>(),    // <c1>
                                   PaintOpIs<cc::DrawRecordOp>(),  // <p0/>
@@ -456,7 +456,7 @@
       chunks.Build(), PropertyTreeState(t0(), *c1, *e1));
   EXPECT_THAT(output, ElementsAre(PaintOpEq(cc::SaveLayerAlphaOp(
                                       SkRect::MakeXYWH(0, 0, 100, 100),
-                                      127 / 255.f)),              // <e2>
+                                      0.5f)),                     // <e2>
                                   PaintOpIs<cc::DrawRecordOp>(),  // <p0/>
                                   PaintOpIs<cc::RestoreOp>()));   // </e2>
 }
@@ -566,7 +566,7 @@
 
   EXPECT_THAT(output, ElementsAre(PaintOpEq(cc::SaveLayerAlphaOp(
                                       SkRect::MakeXYWH(0, 0, 100, 100),
-                                      127 / 255.f)),          // <e1>
+                                      0.5f)),                 // <e1>
                                   PaintOpIs<cc::RestoreOp>()  // </e1>
                                   ));
 }
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
index 83231b48..a9437168 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
@@ -3378,7 +3378,7 @@
 }
 
 bool WebMediaPlayerImpl::IsStreaming() const {
-  return demuxer_manager_->IsStreamingDataSource();
+  return demuxer_manager_->IsStreaming();
 }
 
 bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.h b/third_party/blink/renderer/platform/media/web_media_player_impl.h
index 04436c9..bd7645a 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.h
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.h
@@ -567,7 +567,8 @@
   // Returns true if the player is hidden.
   bool IsHidden() const;
 
-  // Returns true if the player's source is streaming.
+  // Returns true if the player is in streaming mode, meaning that the source
+  // or the demuxer doesn't support timeline or seeking.
   bool IsStreaming() const;
 
   // Return whether |pipeline_metadata_| is compatible with an overlay. This
diff --git a/third_party/blink/renderer/platform/wtf/text/character_names.h b/third_party/blink/renderer/platform/wtf/text/character_names.h
index bb7827e..66b82dd 100644
--- a/third_party/blink/renderer/platform/wtf/text/character_names.h
+++ b/third_party/blink/renderer/platform/wtf/text/character_names.h
@@ -144,7 +144,6 @@
 const UChar32 kMathItalicUpperAlpha = 0x1D6E2;
 const UChar kMinusSignCharacter = 0x2212;
 const UChar kNewlineCharacter = 0x000A;
-const UChar kNonBreakingHyphen = 0x2011;
 const UChar32 kNonCharacter = 0xFFFF;
 const UChar kFormFeedCharacter = 0x000C;
 const UChar32 kNabla = 0x2207;
@@ -309,7 +308,6 @@
 using WTF::unicode::kNewlineCharacter;
 using WTF::unicode::kNoBreakSpaceCharacter;
 using WTF::unicode::kNominalDigitShapesCharacter;
-using WTF::unicode::kNonBreakingHyphen;
 using WTF::unicode::kNonCharacter;
 using WTF::unicode::kObjectReplacementCharacter;
 using WTF::unicode::kOverlineCharacter;
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 3287ce1..849b89d 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -1747,11 +1747,3 @@
 # which often fails, so skip it on this configuration.
 # Use the same reason as the Mac suppressions to avoid an incorrect presubmit check.
 crbug.com/1378476 [ Win ] virtual/webgl-oversized-printing/printing/webgl-oversized-printing.html [ Skip ]
-
-# This test is Mac specific, since it checks cases when hyphen character is
-# being synthesized in Arial font on Mac and therefore should be skipped on
-# other platforms.
-crbug.com/1267606 [ Linux ] wpt_internal/css/css-fonts/font-glyph-synthesis-mac.html [ Skip ]
-crbug.com/1267606 [ Win ] wpt_internal/css/css-fonts/font-glyph-synthesis-mac.html [ Skip ]
-crbug.com/1267606 [ Fuchsia ] wpt_internal/css/css-fonts/font-glyph-synthesis-mac.html [ Skip ]
-crbug.com/1267606 [ Android ] wpt_internal/css/css-fonts/font-glyph-synthesis-mac.html [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 1783293..ee4a388 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6810,7 +6810,7 @@
 
 # Test is not yet supported in Chrome.
 crbug.com/1382865 external/wpt/storage-access-api/requestStorageAccess-cross-origin-sibling-iframes.sub.https.window.html [ Failure Pass ]
-crbug.com/1382865 external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe-navigation.sub.https.window.html [ Failure Pass ]
+crbug.com/1382865 external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe-navigation.sub.https.window.html [ Failure Pass Timeout ]
 
 # Missing priority hints interfaces.
 crbug.com/1345601 external/wpt/priority-hints/iframe-attr-fetchpriority.tentative.html [ Failure ]
@@ -6937,3 +6937,6 @@
 http/tests/security/cross-frame-access-port-explicit-domain.html [ Failure Pass ]
 http/tests/security/cross-frame-access-protocol-explicit-domain.html [ Failure Pass ]
 http/tests/security/canvas-remote-read-remote-image-document-domain.html [ Failure Pass ]
+
+# Sheriff 2023-01-20
+crbug.com/1408919 [ Mac ] virtual/text-antialias/capitalize-boundaries.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/blink/web_tests/css3/blending/background-blend-mode-tiled-gradient-expected.png
index 29395ca..5bb1019 100644
--- a/third_party/blink/web_tests/css3/blending/background-blend-mode-tiled-gradient-expected.png
+++ b/third_party/blink/web_tests/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/css3/blending/effect-background-blend-mode-stacking-expected.png b/third_party/blink/web_tests/css3/blending/effect-background-blend-mode-stacking-expected.png
index b78828a..e8f3a8b 100644
--- a/third_party/blink/web_tests/css3/blending/effect-background-blend-mode-stacking-expected.png
+++ b/third_party/blink/web_tests/css3/blending/effect-background-blend-mode-stacking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/css3/blending/svg-blend-multiply-alpha-expected.png b/third_party/blink/web_tests/css3/blending/svg-blend-multiply-alpha-expected.png
index 6cc28101..a9b6217 100644
--- a/third_party/blink/web_tests/css3/blending/svg-blend-multiply-alpha-expected.png
+++ b/third_party/blink/web_tests/css3/blending/svg-blend-multiply-alpha-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/css3/filters/css-opacity-with-drop-shadow-expected.png b/third_party/blink/web_tests/css3/filters/css-opacity-with-drop-shadow-expected.png
index 040a92b4..28b6a05 100644
--- a/third_party/blink/web_tests/css3/filters/css-opacity-with-drop-shadow-expected.png
+++ b/third_party/blink/web_tests/css3/filters/css-opacity-with-drop-shadow-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity.html b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity.html
index 4885d805..a8195bc 100644
--- a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity.html
+++ b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity.html
@@ -3,6 +3,7 @@
 <link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
 <link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
 <link rel="match" href="root-element-opacity-ref.html">
+<meta name="fuzzy" content="0-1;0-480000">
 <html style="background: #BBB; opacity: 0.5">
   <div id=spacer style="width: 100px; height: 3000px"></div>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/t32-opacity-offscreen-with-alpha-c.xht b/third_party/blink/web_tests/external/wpt/css/css-color/t32-opacity-offscreen-with-alpha-c.xht
index 57e5e3cc..035609e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/t32-opacity-offscreen-with-alpha-c.xht
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/t32-opacity-offscreen-with-alpha-c.xht
@@ -7,6 +7,7 @@
 		<link rel="help" href="http://www.w3.org/TR/css3-color/#transparency" />
 		<link rel="match" href="t32-opacity-offscreen-with-alpha-c-ref.html" />
 		<meta name="assert" content="That alpha within the offscreen buffer is composited correctly." />
+		<meta name="fuzzy" content="0-1;0-5120" />
 		<style type="text/css"><![CDATA[
 
 		body { background: white; }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/backdrop-animate-002.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/backdrop-animate-002.html
index 6fd153b..910807a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-pseudo/backdrop-animate-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/backdrop-animate-002.html
@@ -5,7 +5,7 @@
 <link rel="match" href="backdrop-animate-002-ref.html">
 <dialog id="target">Dialog contents</dialog>
 <!-- This test fails on WPT.fyi with off-by-one on the green background (Chrome-only): -->
-<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-472272">
+<meta name="fuzzy" content="maxDifference=0-1;totalPixels=0-472500">
 <script>
 const target = document.getElementById("target");
 target.showModal();
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time.html
index efb5ffb..5758ade 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time.html
@@ -4,6 +4,7 @@
 <link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
 <link rel="author" href="mailto:vmpstr@chromium.org">
 <link rel="match" href="set-current-time-ref.html">
+<meta name="fuzzy" content="0-1;0-10000">
 <script src="/common/reftest-wait.js"></script>
 <style>
 :root { view-transition-name: unset; }
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js
new file mode 100644
index 0000000..4d403e1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js
@@ -0,0 +1,56 @@
+// META: title=RemoteContextHelper navigation using BFCache
+// META: script=./test-helper.js
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=/websockets/constants.sub.js
+
+'use strict';
+
+// Ensure that empty attributes are reported as empty strings and missing
+// attributes are reported as null.
+promise_test(async t => {
+  const rcHelper = new RemoteContextHelper();
+  // Open a window with noopener so that BFCache will work.
+  const rc1 = await rcHelper.addWindow(
+      /*config=*/ null, /*options=*/ {features: 'noopener'});
+  const rc1_url = await rc1.executeScript(() => {
+    return location.href;
+  });
+  // Add a cross-origin iframe and use BroadcastChannel.
+  const rc1_child = await rc1.addIframe(
+      /*extraConfig=*/ {
+        origin: 'HTTP_REMOTE_ORIGIN',
+        scripts: [],
+        headers: [],
+      },
+      /*attributes=*/ {id: '', name: ''},
+  );
+  // Use WebSocket to block BFCache.
+  await useWebSocket(rc1);
+  const rc1_child_url = await rc1_child.executeScript(() => {
+    return location.href;
+  });
+  // Check the BFCache result and the reported reasons.
+  await assertBFCache(rc1, /*shouldRestoreFromBFCache=*/ false);
+  await assertNotRestoredReasonsEquals(
+      rc1,
+      /*blocked=*/ true,
+      /*url=*/ rc1_url,
+      /*src=*/ null,
+      /*id=*/ null,
+      /*name=*/ null,
+      /*reasons=*/['WebSocket'],
+      /*children=*/[{
+        'blocked': false,
+        'url': null,
+        'src': rc1_child_url,
+        // Id and name should be empty.
+        'id': '',
+        'name': '',
+        'reasons': [],
+        'children': []
+      }]);
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js
index a39663f..a0f11ab 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js
@@ -27,9 +27,9 @@
       rc1,
       /*blocked=*/ true,
       /*url=*/ rc1_url,
-      /*src=*/ '',
-      /*id=*/ '',
-      /*name=*/ '',
+      /*src=*/ null,
+      /*id=*/ null,
+      /*name=*/ null,
       /*reasons=*/['WebSocket'],
       /*children=*/[]);
 
@@ -40,9 +40,9 @@
       rc1,
       /*blocked=*/ true,
       /*url=*/ rc1_url,
-      /*src=*/ '',
-      /*id=*/ '',
-      /*name=*/ '',
+      /*src=*/ null,
+      /*id=*/ null,
+      /*name=*/ null,
       /*reasons=*/['WebSocket'],
       /*children=*/[]);
 });
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js
index 115ea81d..d1f29eab 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js
@@ -45,15 +45,16 @@
       rc1,
       /*blocked=*/ false,
       /*url=*/ rc1_url,
-      /*src=*/ '',
-      /*id=*/ '',
-      /*name=*/ '',
+      /*src=*/ null,
+      /*id=*/ null,
+      /*name=*/ null,
       /*reasons=*/[],
       /*children=*/[{
         'blocked': true,
         'url': null,
         'src': rc1_child_url,
         'id': 'test-id',
+        // Iframes that are generated by addIframe have an empty name.
         'name': '',
         'reasons': [],
         'children': []
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js
index 7bbc59e9..6367f58 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js
@@ -28,9 +28,9 @@
       rc1,
       /*blocked=*/ true,
       /*url=*/ rc1_url,
-      /*src=*/ '',
-      /*id=*/ '',
-      /*name=*/ '',
+      /*src=*/ null,
+      /*id=*/ null,
+      /*name=*/ null,
       /*reasons=*/['WebSocket'],
       /*children=*/[]);
 });
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js
index a9d9fac..39e9ac9 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-redirect-on-history.tentative.window.js
@@ -27,7 +27,8 @@
         headers: [],
       });
 
-  const redirectUrl = `${ORIGIN}/common/redirect.py?location=${encodeURIComponent(saveUrl)}`;
+  const redirectUrl =
+      `${ORIGIN}/common/redirect.py?location=${encodeURIComponent(saveUrl)}`;
   // Replace the history state.
   await rc1.executeScript((url) => {
     window.history.replaceState(null, '', url);
@@ -43,8 +44,7 @@
     return performance.getEntriesByType('navigation')[0];
   });
   assert_equals(
-    navigation_entry.redirectCount, 1,
-    'Expected redirectCount is 1.');
+      navigation_entry.redirectCount, 1, 'Expected redirectCount is 1.');
   // Becauase of the redirect, notRestoredReasons is reset.
   assert_equals(
       navigation_entry.notRestoredReasons, null,
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js
index 5ee3c30..e8805be6 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js
@@ -38,9 +38,9 @@
       rc1,
       /*blocked=*/ true,
       /*url=*/ rc1_url,
-      /*src=*/ '',
-      /*id=*/ '',
-      /*name=*/ '',
+      /*src=*/ null,
+      /*id=*/ null,
+      /*name=*/ null,
       /*reasons=*/['WebSocket'],
       /*children=*/[]);
 });
diff --git a/third_party/blink/web_tests/fast/backgrounds/svg-as-mask-expected.png b/third_party/blink/web_tests/fast/backgrounds/svg-as-mask-expected.png
index 2cea9b1..9370d2f 100644
--- a/third_party/blink/web_tests/fast/backgrounds/svg-as-mask-expected.png
+++ b/third_party/blink/web_tests/fast/backgrounds/svg-as-mask-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/dynamic/anonymous-block-layer-lost-expected.png b/third_party/blink/web_tests/fast/dynamic/anonymous-block-layer-lost-expected.png
index 16b3506..f87d11b 100644
--- a/third_party/blink/web_tests/fast/dynamic/anonymous-block-layer-lost-expected.png
+++ b/third_party/blink/web_tests/fast/dynamic/anonymous-block-layer-lost-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/layers/add-layer-with-nested-stacking-expected.png b/third_party/blink/web_tests/fast/layers/add-layer-with-nested-stacking-expected.png
index 130b991b..6cda17ad 100644
--- a/third_party/blink/web_tests/fast/layers/add-layer-with-nested-stacking-expected.png
+++ b/third_party/blink/web_tests/fast/layers/add-layer-with-nested-stacking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/layers/opacity-stacking-expected.png b/third_party/blink/web_tests/fast/layers/opacity-stacking-expected.png
index 7832ca71..f04e03df 100644
--- a/third_party/blink/web_tests/fast/layers/opacity-stacking-expected.png
+++ b/third_party/blink/web_tests/fast/layers/opacity-stacking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/multicol/transform-inside-opacity-expected.png b/third_party/blink/web_tests/fast/multicol/transform-inside-opacity-expected.png
index 2d6765af..5e34c7e3 100644
--- a/third_party/blink/web_tests/fast/multicol/transform-inside-opacity-expected.png
+++ b/third_party/blink/web_tests/fast/multicol/transform-inside-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/reflections/reflection-masks-opacity-expected.png b/third_party/blink/web_tests/fast/reflections/reflection-masks-opacity-expected.png
index 8982998..a494426 100644
--- a/third_party/blink/web_tests/fast/reflections/reflection-masks-opacity-expected.png
+++ b/third_party/blink/web_tests/fast/reflections/reflection-masks-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/sub-pixel/save-layer-bounds-should-snap-expected.html b/third_party/blink/web_tests/fast/sub-pixel/save-layer-bounds-should-snap-expected.html
index b5ffb23..9e29dc74 100644
--- a/third_party/blink/web_tests/fast/sub-pixel/save-layer-bounds-should-snap-expected.html
+++ b/third_party/blink/web_tests/fast/sub-pixel/save-layer-bounds-should-snap-expected.html
@@ -1,2 +1,2 @@
 <!DOCTYPE html>
-<div style="width:100px; height:100px; background:rgb(128,192,128);"></div>
+<div style="width:100px; height:100px; background:green; opacity:0.5;"></div>
diff --git a/third_party/blink/web_tests/fast/sub-pixel/save-layer-bounds-should-snap.html b/third_party/blink/web_tests/fast/sub-pixel/save-layer-bounds-should-snap.html
index 8f7db59..d1cd48c 100644
--- a/third_party/blink/web_tests/fast/sub-pixel/save-layer-bounds-should-snap.html
+++ b/third_party/blink/web_tests/fast/sub-pixel/save-layer-bounds-should-snap.html
@@ -1,4 +1,4 @@
 <!DOCTYPE html>
 <div style="transform:scale(2); transform-origin:0 0; width:99px; height:99px;">
-  <div style="width:50%; height:50%; background:green; opacity:0.5;"></div>
+  <div style="width:50%; height:50%; background:green; opacity:0.501;"></div>
 </div>
diff --git a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/fast/sub-pixel/save-layer-bounds-should-snap-expected.png b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/fast/sub-pixel/save-layer-bounds-should-snap-expected.png
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/fast/sub-pixel/save-layer-bounds-should-snap-expected.png
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/fast/block/float/float-in-float-painting-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/fast/block/float/float-in-float-painting-expected.png
index 26ed246..6056e3c 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/fast/block/float/float-in-float-painting-expected.png
+++ b/third_party/blink/web_tests/flag-specific/highdpi/fast/block/float/float-in-float-painting-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/select/basic-selects-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/select/basic-selects-expected.png
index b3668e22..4c1cdcf 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/select/basic-selects-expected.png
+++ b/third_party/blink/web_tests/flag-specific/highdpi/fast/forms/select/basic-selects-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 4b1abbec..9d91a47 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/blink/web_tests/flag-specific/highdpi/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/svg/foreignObject/filter-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/svg/foreignObject/filter-expected.png
index 0c4580e..d126177 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/svg/foreignObject/filter-expected.png
+++ b/third_party/blink/web_tests/flag-specific/highdpi/svg/foreignObject/filter-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/transforms/transform-on-inline-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/transforms/transform-on-inline-expected.png
index b51c39bc..3cb2b6ac 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/transforms/transform-on-inline-expected.png
+++ b/third_party/blink/web_tests/flag-specific/highdpi/transforms/transform-on-inline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/virtual/text-antialias/complex-text-opacity-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/virtual/text-antialias/complex-text-opacity-expected.png
index 89821c0a7..149f4a70 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/virtual/text-antialias/complex-text-opacity-expected.png
+++ b/third_party/blink/web_tests/flag-specific/highdpi/virtual/text-antialias/complex-text-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/css3/blending/effect-background-blend-mode-stacking-expected.png b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/css3/blending/effect-background-blend-mode-stacking-expected.png
index 4b9e61e..186469b 100644
--- a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/css3/blending/effect-background-blend-mode-stacking-expected.png
+++ b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/css3/blending/effect-background-blend-mode-stacking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/devtools/layers/layer-canvas-log-expected.txt b/third_party/blink/web_tests/http/tests/devtools/layers/layer-canvas-log-expected.txt
index c458c28..9a38b0c6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/layers/layer-canvas-log-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/layers/layer-canvas-log-expected.txt
@@ -44,7 +44,7 @@
         method : "drawRect"
         params : {
             paint : {
-                color : "#7F000000"
+                color : "#80000000"
                 flags : "AntiAlias"
                 strokeCap : "Butt"
                 strokeJoin : "Miter"
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/new-stacking-context-expected.png b/third_party/blink/web_tests/paint/invalidation/compositing/new-stacking-context-expected.png
index 32a197c..dc85ee8 100644
--- a/third_party/blink/web_tests/paint/invalidation/compositing/new-stacking-context-expected.png
+++ b/third_party/blink/web_tests/paint/invalidation/compositing/new-stacking-context-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/new-stacking-context-expected.txt b/third_party/blink/web_tests/paint/invalidation/compositing/new-stacking-context-expected.txt
index f289ace..377e689 100644
--- a/third_party/blink/web_tests/paint/invalidation/compositing/new-stacking-context-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/compositing/new-stacking-context-expected.txt
@@ -1,7 +1,7 @@
 {
   "layers": [
     {
-      "name": "Scrolling background of LayoutView #document",
+      "name": "Scrolling background of LayoutNGView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF"
diff --git a/third_party/blink/web_tests/paint/invalidation/multicol/column-float-under-stacked-inline-expected.png b/third_party/blink/web_tests/paint/invalidation/multicol/column-float-under-stacked-inline-expected.png
index c6cabcbb..a92e6a8 100644
--- a/third_party/blink/web_tests/paint/invalidation/multicol/column-float-under-stacked-inline-expected.png
+++ b/third_party/blink/web_tests/paint/invalidation/multicol/column-float-under-stacked-inline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/js-update-bounce-expected.png b/third_party/blink/web_tests/paint/invalidation/svg/js-update-bounce-expected.png
index 7c45db8b..ec6131b 100644
--- a/third_party/blink/web_tests/paint/invalidation/svg/js-update-bounce-expected.png
+++ b/third_party/blink/web_tests/paint/invalidation/svg/js-update-bounce-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/js-update-bounce-expected.txt b/third_party/blink/web_tests/paint/invalidation/svg/js-update-bounce-expected.txt
index 94d1a9a..6f2c37f9 100644
--- a/third_party/blink/web_tests/paint/invalidation/svg/js-update-bounce-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/svg/js-update-bounce-expected.txt
@@ -1,7 +1,7 @@
 {
   "layers": [
     {
-      "name": "Scrolling background of LayoutView #document",
+      "name": "Scrolling background of LayoutNGView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
diff --git a/third_party/blink/web_tests/paint/transparency/compositing-alpha-fold-crash-expected.png b/third_party/blink/web_tests/paint/transparency/compositing-alpha-fold-crash-expected.png
index f9f0ec5c..401c9e0 100644
--- a/third_party/blink/web_tests/paint/transparency/compositing-alpha-fold-crash-expected.png
+++ b/third_party/blink/web_tests/paint/transparency/compositing-alpha-fold-crash-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/compositing/transitions/scale-transition-no-start-expected.png b/third_party/blink/web_tests/platform/linux/compositing/transitions/scale-transition-no-start-expected.png
index 6512bdce..5f93470 100644
--- a/third_party/blink/web_tests/platform/linux/compositing/transitions/scale-transition-no-start-expected.png
+++ b/third_party/blink/web_tests/platform/linux/compositing/transitions/scale-transition-no-start-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/compositing/video/video-controls-layer-creation-expected.png b/third_party/blink/web_tests/platform/linux/compositing/video/video-controls-layer-creation-expected.png
index 08cfc0f..10c5c95b 100644
--- a/third_party/blink/web_tests/platform/linux/compositing/video/video-controls-layer-creation-expected.png
+++ b/third_party/blink/web_tests/platform/linux/compositing/video/video-controls-layer-creation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/blink/web_tests/platform/linux/css3/blending/background-blend-mode-tiled-gradient-expected.png
new file mode 100644
index 0000000..d3e3d2b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/css3/blending/effect-background-blend-mode-expected.png b/third_party/blink/web_tests/platform/linux/css3/blending/effect-background-blend-mode-expected.png
index fb1aa1d..d703a14 100644
--- a/third_party/blink/web_tests/platform/linux/css3/blending/effect-background-blend-mode-expected.png
+++ b/third_party/blink/web_tests/platform/linux/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/css3/blending/effect-background-blend-mode-tiled-expected.png b/third_party/blink/web_tests/platform/linux/css3/blending/effect-background-blend-mode-tiled-expected.png
index c60ce74..d2e9d1e 100644
--- a/third_party/blink/web_tests/platform/linux/css3/blending/effect-background-blend-mode-tiled-expected.png
+++ b/third_party/blink/web_tests/platform/linux/css3/blending/effect-background-blend-mode-tiled-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/backgrounds/opacity-on-document-element-expected.png b/third_party/blink/web_tests/platform/linux/fast/backgrounds/opacity-on-document-element-expected.png
index ea63cff..11d8f13 100644
--- a/third_party/blink/web_tests/platform/linux/fast/backgrounds/opacity-on-document-element-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/backgrounds/opacity-on-document-element-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/block/float/float-in-float-painting-expected.png b/third_party/blink/web_tests/platform/linux/fast/block/float/float-in-float-painting-expected.png
index ca050cb..8cfb9b1 100644
--- a/third_party/blink/web_tests/platform/linux/fast/block/float/float-in-float-painting-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/block/float/float-in-float-painting-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/css/ZeroOpacityLayers-expected.png b/third_party/blink/web_tests/platform/linux/fast/css/ZeroOpacityLayers-expected.png
index 199463e4..317086eb 100644
--- a/third_party/blink/web_tests/platform/linux/fast/css/ZeroOpacityLayers-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/css/ZeroOpacityLayers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/css/ZeroOpacityLayers2-expected.png b/third_party/blink/web_tests/platform/linux/fast/css/ZeroOpacityLayers2-expected.png
index 86e2c30..8fda8f4 100644
--- a/third_party/blink/web_tests/platform/linux/fast/css/ZeroOpacityLayers2-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/css/ZeroOpacityLayers2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/date-picker-month-appearance-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/date-picker-month-appearance-expected.png
index f1f8931..cfa28df9a 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/date-picker-month-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/date-picker-month-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/date-picker-month-selection-changed-appearance-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/date-picker-month-selection-changed-appearance-expected.png
index fbfeaac..d8141490 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/date-picker-month-selection-changed-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/calendar-picker/date-picker-month-selection-changed-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
index 61ae5d3c..f8854bd3 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index a0c45fe..7cf4eee 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
index aa55c445..832e404e 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/indeterminate-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/indeterminate-expected.png
index 4aaed41ca..63ffb59 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/indeterminate-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/indeterminate-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/select/basic-selects-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/select/basic-selects-expected.png
index 212ae019..b8c234f 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/select/basic-selects-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/select/basic-selects-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/select/disabled-select-change-index-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/select/disabled-select-change-index-expected.png
index 90a2c00c..c0964101 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/select/disabled-select-change-index-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/select/disabled-select-change-index-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/select/listbox-appearance-basic-expected.png
index 77b1f27..de1ccc5 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/select/select-disabled-appearance-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/select/select-disabled-appearance-expected.png
index 8cf2461..89ae6b61 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/select/select-disabled-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/select/select-disabled-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/layers/opacity-outline-expected.png b/third_party/blink/web_tests/platform/linux/fast/layers/opacity-outline-expected.png
index a18ab6d..75d08d4 100644
--- a/third_party/blink/web_tests/platform/linux/fast/layers/opacity-outline-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/layers/opacity-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/layers/opacity-transforms-expected.png b/third_party/blink/web_tests/platform/linux/fast/layers/opacity-transforms-expected.png
index 0933ee6..3979ff18 100644
--- a/third_party/blink/web_tests/platform/linux/fast/layers/opacity-transforms-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/layers/opacity-transforms-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/multicol/layers-in-multicol-expected.png b/third_party/blink/web_tests/platform/linux/fast/multicol/layers-in-multicol-expected.png
index ee4d480..cb5d630 100644
--- a/third_party/blink/web_tests/platform/linux/fast/multicol/layers-in-multicol-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/multicol/layers-in-multicol-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/overflow/007-expected.png b/third_party/blink/web_tests/platform/linux/fast/overflow/007-expected.png
index d60f328..6ebcab2 100644
--- a/third_party/blink/web_tests/platform/linux/fast/overflow/007-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/overflow/007-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/overflow/overflow-of-video-outline-expected.png b/third_party/blink/web_tests/platform/linux/fast/overflow/overflow-of-video-outline-expected.png
index e5c635b..433576f 100644
--- a/third_party/blink/web_tests/platform/linux/fast/overflow/overflow-of-video-outline-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/overflow/overflow-of-video-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/table/backgr_layers-opacity-collapsed-border-expected.png b/third_party/blink/web_tests/platform/linux/fast/table/backgr_layers-opacity-collapsed-border-expected.png
index 9f41f1d..89aa8b1a 100644
--- a/third_party/blink/web_tests/platform/linux/fast/table/backgr_layers-opacity-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/table/backgr_layers-opacity-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/table/backgr_layers-opacity-expected.png b/third_party/blink/web_tests/platform/linux/fast/table/backgr_layers-opacity-expected.png
index 9f41f1d..89aa8b1a 100644
--- a/third_party/blink/web_tests/platform/linux/fast/table/backgr_layers-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/table/backgr_layers-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/table/dynamic-caption-add-before-child-expected.png b/third_party/blink/web_tests/platform/linux/fast/table/dynamic-caption-add-before-child-expected.png
index 0e7c8e3..9ed07d15 100644
--- a/third_party/blink/web_tests/platform/linux/fast/table/dynamic-caption-add-before-child-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/table/dynamic-caption-add-before-child-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/table/multiple-captions-display-expected.png b/third_party/blink/web_tests/platform/linux/fast/table/multiple-captions-display-expected.png
index 3a3808f9..a0f7699 100644
--- a/third_party/blink/web_tests/platform/linux/fast/table/multiple-captions-display-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/table/multiple-captions-display-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/table/overflowHidden-expected.png b/third_party/blink/web_tests/platform/linux/fast/table/overflowHidden-expected.png
index d92bf244..a1e978f 100644
--- a/third_party/blink/web_tests/platform/linux/fast/table/overflowHidden-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/table/overflowHidden-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/blink/web_tests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index b9aaf65..65e38142 100644
--- a/third_party/blink/web_tests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/blink/web_tests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/linux/media/audio-controls-rendering-expected.png
index a11bb1a..35bd351 100644
--- a/third_party/blink/web_tests/platform/linux/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/linux/media/audio-repaint-expected.png
index cb995706..0d13811b 100644
--- a/third_party/blink/web_tests/platform/linux/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/linux/media/controls-layout-direction-expected.png
index 80407565..f71f74a 100644
--- a/third_party/blink/web_tests/platform/linux/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/blink/web_tests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.png
index 19d72bc..37844fec 100644
--- a/third_party/blink/web_tests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/linux/media/media-controls-clone-expected.png
index 85f53456..fc7b4d9 100644
--- a/third_party/blink/web_tests/platform/linux/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/linux/media/media-controls-grey-scrubber-expected.png
index 15ac2a0..e09cba5 100644
--- a/third_party/blink/web_tests/platform/linux/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/linux/media/media-document-audio-repaint-expected.png
index 70b8bec8..bb5d327 100644
--- a/third_party/blink/web_tests/platform/linux/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/video-empty-source-expected.png b/third_party/blink/web_tests/platform/linux/media/video-empty-source-expected.png
index ce26faf..094aa3a 100644
--- a/third_party/blink/web_tests/platform/linux/media/video-empty-source-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/video-empty-source-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/media/video-no-audio-expected.png b/third_party/blink/web_tests/platform/linux/media/video-no-audio-expected.png
index 7aece49..a9f955af 100644
--- a/third_party/blink/web_tests/platform/linux/media/video-no-audio-expected.png
+++ b/third_party/blink/web_tests/platform/linux/media/video-no-audio-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/compositing/become-overlay-composited-layer-expected.png b/third_party/blink/web_tests/platform/linux/paint/invalidation/compositing/become-overlay-composited-layer-expected.png
index 363f3b0..6dacadd 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/compositing/become-overlay-composited-layer-expected.png
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/compositing/become-overlay-composited-layer-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index 841db752..39108ea 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index 640a607..ecd2a38b 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -1,7 +1,7 @@
 {
   "layers": [
     {
-      "name": "Scrolling background of LayoutView #document",
+      "name": "Scrolling background of LayoutNGView #document",
       "bounds": [1026, 1012],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
@@ -27,7 +27,7 @@
       "contentsOpaque": true
     },
     {
-      "name": "Scroll corner of LayoutView #document",
+      "name": "Scroll corner of LayoutNGView #document",
       "position": [785, 585],
       "bounds": [15, 15],
       "contentsOpaque": true
diff --git a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png
index ec3b0cdb..afc9adc 100644
--- a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
index bcd57c4b..4fed618e 100644
--- a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
index b4067043..48fc93fd 100644
--- a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
index 7b4591b..6e683abc 100644
--- a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/text-text-08-b-expected.png b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/text-text-08-b-expected.png
index e98d4af5..fa202d9 100644
--- a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/text-text-08-b-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/text-text-08-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png b/third_party/blink/web_tests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png
index 29c48dd..bcb28ef 100644
--- a/third_party/blink/web_tests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/as-background-image/svg-as-background-6-expected.png b/third_party/blink/web_tests/platform/linux/svg/as-background-image/svg-as-background-6-expected.png
index 93b9d5e..62fb5ae9c 100644
--- a/third_party/blink/web_tests/platform/linux/svg/as-background-image/svg-as-background-6-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/as-background-image/svg-as-background-6-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/batik/text/smallFonts-expected.png b/third_party/blink/web_tests/platform/linux/svg/batik/text/smallFonts-expected.png
index 24f7389..0232567d 100644
--- a/third_party/blink/web_tests/platform/linux/svg/batik/text/smallFonts-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/batik/text/smallFonts-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/batik/text/textAnchor-expected.png b/third_party/blink/web_tests/platform/linux/svg/batik/text/textAnchor-expected.png
index 3a0cfa4e..87797f6f 100644
--- a/third_party/blink/web_tests/platform/linux/svg/batik/text/textAnchor-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/batik/text/textAnchor-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/batik/text/textFeatures-expected.png b/third_party/blink/web_tests/platform/linux/svg/batik/text/textFeatures-expected.png
index c3c206a3..97278b2 100644
--- a/third_party/blink/web_tests/platform/linux/svg/batik/text/textFeatures-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/batik/text/textFeatures-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/batik/text/textProperties-expected.png b/third_party/blink/web_tests/platform/linux/svg/batik/text/textProperties-expected.png
index b1f102c7..a41f0d2 100644
--- a/third_party/blink/web_tests/platform/linux/svg/batik/text/textProperties-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/batik/text/textProperties-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/batik/text/verticalText-expected.png b/third_party/blink/web_tests/platform/linux/svg/batik/text/verticalText-expected.png
index afa4d9a1..6357454d 100644
--- a/third_party/blink/web_tests/platform/linux/svg/batik/text/verticalText-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/batik/text/verticalText-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/container-opacity-clip-viewBox-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/container-opacity-clip-viewBox-expected.png
index f54ebb7..c0d3597 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/container-opacity-clip-viewBox-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/container-opacity-clip-viewBox-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/dominant-baseline-hanging-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/dominant-baseline-hanging-expected.png
index 344727b..a90f818936 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/dominant-baseline-hanging-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/dominant-baseline-hanging-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/non-opaque-filters-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/non-opaque-filters-expected.png
index 8e9e093..65f63e5 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/non-opaque-filters-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/non-opaque-filters-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/text-image-opacity-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/text-image-opacity-expected.png
index 1c26e2b..6a1bcfe 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/text-image-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/text-image-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/use-modify-container-in-target-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/use-modify-container-in-target-expected.png
index b7083b4e..ad3fec3 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/use-modify-container-in-target-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/use-modify-container-in-target-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/use-modify-target-container-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/use-modify-target-container-expected.png
index 9e78d7a..6c22953 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/use-modify-target-container-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/use-modify-target-container-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/use-on-g-containing-use-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/use-on-g-containing-use-expected.png
index 3d0e84f..e8ab952c 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/use-on-g-containing-use-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/use-on-g-containing-use-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/use-on-g-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/use-on-g-expected.png
index 6b37f1c..a3a4fa85 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/use-on-g-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/use-on-g-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/use-on-use-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/use-on-use-expected.png
index 6b37f1c..a3a4fa85 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/use-on-use-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/use-on-use-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/custom/use-transform-expected.png b/third_party/blink/web_tests/platform/linux/svg/custom/use-transform-expected.png
index ceba02a..9d2d04c 100644
--- a/third_party/blink/web_tests/platform/linux/svg/custom/use-transform-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/custom/use-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/text/text-selection-text-08-b-expected.png b/third_party/blink/web_tests/platform/linux/svg/text/text-selection-text-08-b-expected.png
index 22f2ef29..d0659a68 100644
--- a/third_party/blink/web_tests/platform/linux/svg/text/text-selection-text-08-b-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/text/text-selection-text-08-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/transforms/2d/hindi-rotated-expected.png b/third_party/blink/web_tests/platform/linux/transforms/2d/hindi-rotated-expected.png
index 64a946b..480a081 100644
--- a/third_party/blink/web_tests/platform/linux/transforms/2d/hindi-rotated-expected.png
+++ b/third_party/blink/web_tests/platform/linux/transforms/2d/hindi-rotated-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/transforms/transform-on-inline-expected.png b/third_party/blink/web_tests/platform/linux/transforms/transform-on-inline-expected.png
index 3dfbe67..cd821ed 100644
--- a/third_party/blink/web_tests/platform/linux/transforms/transform-on-inline-expected.png
+++ b/third_party/blink/web_tests/platform/linux/transforms/transform-on-inline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/transforms/transform-table-row-expected.png b/third_party/blink/web_tests/platform/linux/transforms/transform-table-row-expected.png
index 64e3a69..82a65c77 100644
--- a/third_party/blink/web_tests/platform/linux/transforms/transform-table-row-expected.png
+++ b/third_party/blink/web_tests/platform/linux/transforms/transform-table-row-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/transforms/transforms-with-opacity-expected.png b/third_party/blink/web_tests/platform/linux/transforms/transforms-with-opacity-expected.png
index 1a338261..0816f9b1 100644
--- a/third_party/blink/web_tests/platform/linux/transforms/transforms-with-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/linux/transforms/transforms-with-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png
index 0c6f599..a93a6c4 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png
index 0f7228d..522b29f 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
index ba4a32eed..e39f8308 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index 5d12efd..9e3db5b9 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-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/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
index 5034705..d18985a 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index 70629127..51d5267 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index 3a5a617..f3be14b44 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/video-focus-ring-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/video-focus-ring-expected.png
index bb8ea03..3d1c4e4 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/video-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/media/video-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/complex-text-opacity-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/complex-text-opacity-expected.png
index 60e20707..2adb925 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/complex-text-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/complex-text-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/letter-spacing-negative-opacity-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
index 983c618..2fcdc57 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png b/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
index 61ae5d3c..f8854bd3 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
deleted file mode 100644
index a0c45fe..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
deleted file mode 100644
index aa55c445..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/compositing/video/video-controls-layer-creation-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/compositing/video/video-controls-layer-creation-expected.png
index 80922ca7..644cbe67 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/compositing/video/video-controls-layer-creation-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/compositing/video/video-controls-layer-creation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
index a67653f..bb8f4b7 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index ef39896d..689f2d7 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
index da00da5..704cdab98 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/basic-selects-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/basic-selects-expected.png
index 9c8ace3..cbe3a457 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/basic-selects-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/basic-selects-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/disabled-select-change-index-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/disabled-select-change-index-expected.png
index 2a2d3d37..309c038 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/disabled-select-change-index-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/disabled-select-change-index-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/listbox-appearance-basic-expected.png
index 32ccd9a..da98ad2b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/select-disabled-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/select-disabled-appearance-expected.png
index fd3a3704..f6cd1e06 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/select-disabled-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/forms/select/select-disabled-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/layers/opacity-outline-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/layers/opacity-outline-expected.png
index d717d8cc..85a18b6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/layers/opacity-outline-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/layers/opacity-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/fast/overflow/overflow-of-video-outline-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/fast/overflow/overflow-of-video-outline-expected.png
index 3ade45d7..002d2d7 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/fast/overflow/overflow-of-video-outline-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/fast/overflow/overflow-of-video-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index cb8803f6..e94bdd3 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/audio-controls-rendering-expected.png
index 4fcf781..a0f5476 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/controls-layout-direction-expected.png
index 08041b1..f558ddfa 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-clone-expected.png
index 4ed86f0..f3d69ab 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-grey-scrubber-expected.png
index 3c487c3..7c5097a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-document-audio-repaint-expected.png
index 421f698..8eac3f0 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/media/video-empty-source-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/media/video-empty-source-expected.png
index 661420c..9b3d7c4 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/media/video-empty-source-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/media/video-empty-source-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index 26f668ac..7a4ee54 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
index 4b0c88a..61cd13d 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/svg/batik/text/verticalText-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/svg/batik/text/verticalText-expected.png
index 57fe3d0..efe07cf 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/svg/batik/text/verticalText-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/svg/batik/text/verticalText-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/svg/custom/container-opacity-clip-viewBox-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/svg/custom/container-opacity-clip-viewBox-expected.png
index ac0e003..014d5c6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/svg/custom/container-opacity-clip-viewBox-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/svg/custom/container-opacity-clip-viewBox-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/svg/text/text-selection-text-08-b-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/svg/text/text-selection-text-08-b-expected.png
index a2f0148..50b94f82 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/svg/text/text-selection-text-08-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/svg/text/text-selection-text-08-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/transforms/2d/hindi-rotated-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/transforms/2d/hindi-rotated-expected.png
index ce866d95..664764b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/transforms/2d/hindi-rotated-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/transforms/2d/hindi-rotated-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
index 04e7c6b..36b02d6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index bb1ee73..3d9caab 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index a69c195..560e82f 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/video-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/video-focus-ring-expected.png
index 96e7947..8551786 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/video-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/media/video-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..4fcf781
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..4fcf781
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/complex-text-opacity-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/complex-text-opacity-expected.png
index 444d132a..1962968 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/complex-text-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/complex-text-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/letter-spacing-negative-opacity-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
index bbd70e5..9480313b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
index a67653f..bb8f4b7 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index ef39896d..689f2d7 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
index da00da5..704cdab98 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/compositing/video/video-controls-layer-creation-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/compositing/video/video-controls-layer-creation-expected.png
index d15ea22..8db83934 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/compositing/video/video-controls-layer-creation-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/compositing/video/video-controls-layer-creation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/fast/overflow/overflow-of-video-outline-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/fast/overflow/overflow-of-video-outline-expected.png
index 01a68aab..6318de1d 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/fast/overflow/overflow-of-video-outline-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/fast/overflow/overflow-of-video-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 5266e67..c2e0432 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-controls-rendering-expected.png
index 7f4d45d2..b176d868 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png
index a34023c56..bb37ef2 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/controls-layout-direction-expected.png
index 59af3c57..7630524 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/controls/paint-controls-webkit-appearance-none-expected.png
index 556f6ae9..34f04d6 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/controls/paint-controls-webkit-appearance-none-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/controls/paint-controls-webkit-appearance-none-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-clone-expected.png
index b0fedd4..99de66a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-grey-scrubber-expected.png
index 7d4a240..3d19053 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-document-audio-repaint-expected.png
index e525e33..9177533 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/video-empty-source-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/video-empty-source-expected.png
index d10f5ab..4705938 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/video-empty-source-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/video-empty-source-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/video-no-audio-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/video-no-audio-expected.png
index 60f4a63..efbefe7 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/media/video-no-audio-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/video-no-audio-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index 0c704c7..bc68c56e 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index f5cf1e4..630b4e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/video-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/video-focus-ring-expected.png
index b1f3a84..31bd24e5 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/video-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/video-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..7f4d45d2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-dcomp/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-dcomp/media/audio-repaint-expected.png
new file mode 100644
index 0000000..a34023c56
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-dcomp/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-dcomp/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-dcomp/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..e525e33
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-dcomp/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..7f4d45d2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-frameserver/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-frameserver/media/audio-repaint-expected.png
new file mode 100644
index 0000000..a34023c56
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-frameserver/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-frameserver/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-frameserver/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..e525e33
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/media-foundation-for-clear-frameserver/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/background-blend-mode-tiled-gradient-expected.png
index edc719a..02cce93c 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/background-blend-mode-tiled-gradient-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-expected.png
index 9231b63..336b69e 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-stacking-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-stacking-expected.png
index 4c98dca..e09a109 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-stacking-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-stacking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-tiled-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-tiled-expected.png
index d2fec75..bfb8d65a2 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-tiled-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/effect-background-blend-mode-tiled-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/svg-blend-multiply-alpha-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/svg-blend-multiply-alpha-expected.png
index 180fdc3..bc15d4b 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/svg-blend-multiply-alpha-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/css3/blending/svg-blend-multiply-alpha-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index fabf60d..49cc223 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/reflections/opacity-reflection-transform-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/reflections/opacity-reflection-transform-expected.png
index 37295a3..57c4e15 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/reflections/opacity-reflection-transform-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/reflections/opacity-reflection-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 1250a3f..18c7f11 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/audio-controls-rendering-expected.png
index cfa241e..2eb1e6f 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/audio-repaint-expected.png
index f7b44c5f..6ca9546 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/controls-layout-direction-expected.png
index 2d8285e..046bacd 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/media-controls-clone-expected.png
index 83bf7f7..492d145 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/media-document-audio-repaint-expected.png
index 8874a70..9a12ca95 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
index 8b9af94..67bb53f 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/as-background-image/svg-as-background-6-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/as-background-image/svg-as-background-6-expected.png
index b5b4ac0..a65a271 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/as-background-image/svg-as-background-6-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/as-background-image/svg-as-background-6-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/custom/marker-opacity-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/custom/marker-opacity-expected.png
index baf71a09..f1b0d96 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/custom/marker-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/custom/marker-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png
new file mode 100644
index 0000000..97cc331
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png
new file mode 100644
index 0000000..97cc331
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index 38adcf5..b3f7a4e 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
deleted file mode 100644
index 3bd95da..0000000
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index 1f391b8..a75e60f 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index f371cbb..2fe5baf 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..cfa241e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-repaint-expected.png
new file mode 100644
index 0000000..f7b44c5f
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-dcomp/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-dcomp/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..8874a70
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-dcomp/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..cfa241e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-repaint-expected.png
new file mode 100644
index 0000000..f7b44c5f
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-frameserver/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-frameserver/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..8874a70
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/media-foundation-for-clear-frameserver/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index fabf60d..49cc223 100644
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/background-blend-mode-tiled-gradient-expected.png
index edc719a..02cce93c 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/background-blend-mode-tiled-gradient-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-expected.png
index 9231b63..336b69e 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-stacking-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-stacking-expected.png
index 4c98dca..e09a109 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-stacking-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-stacking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-tiled-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-tiled-expected.png
index d2fec75..bfb8d65a2 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-tiled-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/effect-background-blend-mode-tiled-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/svg-blend-multiply-alpha-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/svg-blend-multiply-alpha-expected.png
index 180fdc3..bc15d4b 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/svg-blend-multiply-alpha-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/css3/blending/svg-blend-multiply-alpha-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index fabf60d..49cc223 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/reflections/opacity-reflection-transform-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/reflections/opacity-reflection-transform-expected.png
index 37295a3..57c4e15 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/reflections/opacity-reflection-transform-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/reflections/opacity-reflection-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 1250a3f..18c7f11 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/audio-controls-rendering-expected.png
index cfa241e..2eb1e6f 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/audio-repaint-expected.png
index f7b44c5f..6ca9546 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/controls-layout-direction-expected.png
index 2d8285e..046bacd 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/media-controls-clone-expected.png
index 83bf7f7..492d145 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/media-document-audio-repaint-expected.png
index 8874a70..9a12ca95 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
index 8b9af94..67bb53f 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/as-background-image/svg-as-background-6-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/as-background-image/svg-as-background-6-expected.png
index b5b4ac0..a65a271 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/as-background-image/svg-as-background-6-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/as-background-image/svg-as-background-6-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/custom/marker-opacity-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/custom/marker-opacity-expected.png
index baf71a09..f1b0d96 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/custom/marker-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/custom/marker-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
index 55cd33a..1dc65e3 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png
new file mode 100644
index 0000000..97cc331
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png
new file mode 100644
index 0000000..97cc331
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png
new file mode 100644
index 0000000..e62a63c2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index 38adcf5..b3f7a4e 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
deleted file mode 100644
index 3bd95da..0000000
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index 1f391b8..a75e60f 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index f371cbb..2fe5baf 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..cfa241e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-repaint-expected.png
new file mode 100644
index 0000000..f7b44c5f
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-dcomp/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-dcomp/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-dcomp/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..8874a70
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-dcomp/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png
new file mode 100644
index 0000000..cfa241e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-repaint-expected.png
new file mode 100644
index 0000000..f7b44c5f
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-frameserver/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-frameserver/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-frameserver/media/media-document-audio-repaint-expected.png
new file mode 100644
index 0000000..8874a70
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/media-foundation-for-clear-frameserver/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index fabf60d..49cc223 100644
--- a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/use-common-select-popup/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/compositing/transitions/scale-transition-no-start-expected.png b/third_party/blink/web_tests/platform/mac/compositing/transitions/scale-transition-no-start-expected.png
index 0067925..d8b394d 100644
--- a/third_party/blink/web_tests/platform/mac/compositing/transitions/scale-transition-no-start-expected.png
+++ b/third_party/blink/web_tests/platform/mac/compositing/transitions/scale-transition-no-start-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/compositing/video/video-controls-layer-creation-expected.png b/third_party/blink/web_tests/platform/mac/compositing/video/video-controls-layer-creation-expected.png
index 0141e0a7..7c9cfaa0 100644
--- a/third_party/blink/web_tests/platform/mac/compositing/video/video-controls-layer-creation-expected.png
+++ b/third_party/blink/web_tests/platform/mac/compositing/video/video-controls-layer-creation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/blink/web_tests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png
new file mode 100644
index 0000000..d3e3d2b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/css3/blending/effect-background-blend-mode-expected.png b/third_party/blink/web_tests/platform/mac/css3/blending/effect-background-blend-mode-expected.png
index fb1aa1d..d703a14 100644
--- a/third_party/blink/web_tests/platform/mac/css3/blending/effect-background-blend-mode-expected.png
+++ b/third_party/blink/web_tests/platform/mac/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/css3/blending/effect-background-blend-mode-tiled-expected.png b/third_party/blink/web_tests/platform/mac/css3/blending/effect-background-blend-mode-tiled-expected.png
index c60ce74..d2e9d1e 100644
--- a/third_party/blink/web_tests/platform/mac/css3/blending/effect-background-blend-mode-tiled-expected.png
+++ b/third_party/blink/web_tests/platform/mac/css3/blending/effect-background-blend-mode-tiled-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/backgrounds/opacity-on-document-element-expected.png b/third_party/blink/web_tests/platform/mac/fast/backgrounds/opacity-on-document-element-expected.png
index c5aca45..eadc5cc 100644
--- a/third_party/blink/web_tests/platform/mac/fast/backgrounds/opacity-on-document-element-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/backgrounds/opacity-on-document-element-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/block/float/float-in-float-painting-expected.png b/third_party/blink/web_tests/platform/mac/fast/block/float/float-in-float-painting-expected.png
index f56bd7a4..44d4b5a 100644
--- a/third_party/blink/web_tests/platform/mac/fast/block/float/float-in-float-painting-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/block/float/float-in-float-painting-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/css/ZeroOpacityLayers-expected.png b/third_party/blink/web_tests/platform/mac/fast/css/ZeroOpacityLayers-expected.png
index acc49674..8651d9a2 100644
--- a/third_party/blink/web_tests/platform/mac/fast/css/ZeroOpacityLayers-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/css/ZeroOpacityLayers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/css/ZeroOpacityLayers2-expected.png b/third_party/blink/web_tests/platform/mac/fast/css/ZeroOpacityLayers2-expected.png
index 65d9d831..52000bc2 100644
--- a/third_party/blink/web_tests/platform/mac/fast/css/ZeroOpacityLayers2-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/css/ZeroOpacityLayers2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
index e58bdf2f..13ca99d 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index 9e1970d2..de599ca 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
index 0b0d8db..a6372d3 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/indeterminate-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/indeterminate-expected.png
index 5a8c3fa4..e36236e9 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/indeterminate-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/indeterminate-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/select/basic-selects-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/select/basic-selects-expected.png
index ef801e8..36678f03 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/select/basic-selects-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/select/basic-selects-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/select/disabled-select-change-index-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/select/disabled-select-change-index-expected.png
index 352f206..f138c8c 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/select/disabled-select-change-index-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/select/disabled-select-change-index-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/select/listbox-appearance-basic-expected.png
index 0aa04df..27bb60b 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/select/select-disabled-appearance-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/select/select-disabled-appearance-expected.png
index 2d042fe..22a5036f 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/select/select-disabled-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/select/select-disabled-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/layers/opacity-outline-expected.png b/third_party/blink/web_tests/platform/mac/fast/layers/opacity-outline-expected.png
index 14b3afc..d8a2a2263 100644
--- a/third_party/blink/web_tests/platform/mac/fast/layers/opacity-outline-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/layers/opacity-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/layers/opacity-transforms-expected.png b/third_party/blink/web_tests/platform/mac/fast/layers/opacity-transforms-expected.png
index 08af2ff..86338cad 100644
--- a/third_party/blink/web_tests/platform/mac/fast/layers/opacity-transforms-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/layers/opacity-transforms-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/multicol/layers-in-multicol-expected.png b/third_party/blink/web_tests/platform/mac/fast/multicol/layers-in-multicol-expected.png
index 9243efa..5ef8f01 100644
--- a/third_party/blink/web_tests/platform/mac/fast/multicol/layers-in-multicol-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/multicol/layers-in-multicol-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/overflow/007-expected.png b/third_party/blink/web_tests/platform/mac/fast/overflow/007-expected.png
index fc661192..ac3b288a 100644
--- a/third_party/blink/web_tests/platform/mac/fast/overflow/007-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/overflow/007-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/overflow/overflow-of-video-outline-expected.png b/third_party/blink/web_tests/platform/mac/fast/overflow/overflow-of-video-outline-expected.png
index 013178c..f61ee3b 100644
--- a/third_party/blink/web_tests/platform/mac/fast/overflow/overflow-of-video-outline-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/overflow/overflow-of-video-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/reflections/opacity-reflection-transform-expected.png b/third_party/blink/web_tests/platform/mac/fast/reflections/opacity-reflection-transform-expected.png
index 00e3acd..cf8f69a 100644
--- a/third_party/blink/web_tests/platform/mac/fast/reflections/opacity-reflection-transform-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/reflections/opacity-reflection-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/table/backgr_layers-opacity-collapsed-border-expected.png b/third_party/blink/web_tests/platform/mac/fast/table/backgr_layers-opacity-collapsed-border-expected.png
index 1ef4432..012e4c6f 100644
--- a/third_party/blink/web_tests/platform/mac/fast/table/backgr_layers-opacity-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/table/backgr_layers-opacity-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/table/backgr_layers-opacity-expected.png b/third_party/blink/web_tests/platform/mac/fast/table/backgr_layers-opacity-expected.png
index 1ef4432..012e4c6f 100644
--- a/third_party/blink/web_tests/platform/mac/fast/table/backgr_layers-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/table/backgr_layers-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/table/dynamic-caption-add-before-child-expected.png b/third_party/blink/web_tests/platform/mac/fast/table/dynamic-caption-add-before-child-expected.png
index 59715b19..e29ab70e 100644
--- a/third_party/blink/web_tests/platform/mac/fast/table/dynamic-caption-add-before-child-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/table/dynamic-caption-add-before-child-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/table/multiple-captions-display-expected.png b/third_party/blink/web_tests/platform/mac/fast/table/multiple-captions-display-expected.png
index ab164595..25c18fd 100644
--- a/third_party/blink/web_tests/platform/mac/fast/table/multiple-captions-display-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/table/multiple-captions-display-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/table/overflowHidden-expected.png b/third_party/blink/web_tests/platform/mac/fast/table/overflowHidden-expected.png
index d21e749..017447e7 100644
--- a/third_party/blink/web_tests/platform/mac/fast/table/overflowHidden-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/table/overflowHidden-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/blink/web_tests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index b3936e83..1a661790 100644
--- a/third_party/blink/web_tests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/blink/web_tests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac/media/audio-controls-rendering-expected.png
index e89c20c1..b7ecf363 100644
--- a/third_party/blink/web_tests/platform/mac/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac/media/audio-repaint-expected.png
index 7695770..65d103b8a 100644
--- a/third_party/blink/web_tests/platform/mac/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/mac/media/controls-layout-direction-expected.png
index e8b3f44..c6c98d403 100644
--- a/third_party/blink/web_tests/platform/mac/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/blink/web_tests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.png
index 57f567f..fa740de 100644
--- a/third_party/blink/web_tests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/mac/media/media-controls-clone-expected.png
index 2aefb5f..487499a 100644
--- a/third_party/blink/web_tests/platform/mac/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/mac/media/media-controls-grey-scrubber-expected.png
index f8171f4..e8477f3 100644
--- a/third_party/blink/web_tests/platform/mac/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac/media/media-document-audio-repaint-expected.png
index 3231d6e8..72b51c8 100644
--- a/third_party/blink/web_tests/platform/mac/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/video-empty-source-expected.png b/third_party/blink/web_tests/platform/mac/media/video-empty-source-expected.png
index fb63ea40..bf010383 100644
--- a/third_party/blink/web_tests/platform/mac/media/video-empty-source-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/video-empty-source-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/media/video-no-audio-expected.png b/third_party/blink/web_tests/platform/mac/media/video-no-audio-expected.png
index 3da9638..7e37038 100644
--- a/third_party/blink/web_tests/platform/mac/media/video-no-audio-expected.png
+++ b/third_party/blink/web_tests/platform/mac/media/video-no-audio-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/compositing/become-overlay-composited-layer-expected.png b/third_party/blink/web_tests/platform/mac/paint/invalidation/compositing/become-overlay-composited-layer-expected.png
index 693ca5f..dd46ae6 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/compositing/become-overlay-composited-layer-expected.png
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/compositing/become-overlay-composited-layer-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/blink/web_tests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index 824bc653..3fe60b5 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png
index 00326e9..93032e4b 100644
--- a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
index 154c0132..c01eec9 100644
--- a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
index b75ddac..9e7c1912 100644
--- a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
index 5b147da..613d88a4 100644
--- a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/text-text-08-b-expected.png b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/text-text-08-b-expected.png
index 20709a0..f297698 100644
--- a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/text-text-08-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/text-text-08-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png b/third_party/blink/web_tests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png
index a7019dc9..9506892 100644
--- a/third_party/blink/web_tests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/as-background-image/svg-as-background-6-expected.png b/third_party/blink/web_tests/platform/mac/svg/as-background-image/svg-as-background-6-expected.png
index 124199a..5acd36a 100644
--- a/third_party/blink/web_tests/platform/mac/svg/as-background-image/svg-as-background-6-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/as-background-image/svg-as-background-6-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/batik/text/smallFonts-expected.png b/third_party/blink/web_tests/platform/mac/svg/batik/text/smallFonts-expected.png
index 94189aa..e3839ac 100644
--- a/third_party/blink/web_tests/platform/mac/svg/batik/text/smallFonts-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/batik/text/smallFonts-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/batik/text/textAnchor-expected.png b/third_party/blink/web_tests/platform/mac/svg/batik/text/textAnchor-expected.png
index db5aa346..e18c9e3 100644
--- a/third_party/blink/web_tests/platform/mac/svg/batik/text/textAnchor-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/batik/text/textAnchor-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/batik/text/textFeatures-expected.png b/third_party/blink/web_tests/platform/mac/svg/batik/text/textFeatures-expected.png
index 6ae10a6..e2235e5 100644
--- a/third_party/blink/web_tests/platform/mac/svg/batik/text/textFeatures-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/batik/text/textFeatures-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/batik/text/textProperties-expected.png b/third_party/blink/web_tests/platform/mac/svg/batik/text/textProperties-expected.png
index cfedc3c..3a67a598 100644
--- a/third_party/blink/web_tests/platform/mac/svg/batik/text/textProperties-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/batik/text/textProperties-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/batik/text/verticalText-expected.png b/third_party/blink/web_tests/platform/mac/svg/batik/text/verticalText-expected.png
index ca30a27..a8d3484 100644
--- a/third_party/blink/web_tests/platform/mac/svg/batik/text/verticalText-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/batik/text/verticalText-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/container-opacity-clip-viewBox-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/container-opacity-clip-viewBox-expected.png
index 172e1de..5a97bf1 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/container-opacity-clip-viewBox-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/container-opacity-clip-viewBox-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/dominant-baseline-hanging-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/dominant-baseline-hanging-expected.png
index 81f57ff..915cbe98 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/dominant-baseline-hanging-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/dominant-baseline-hanging-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/non-opaque-filters-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/non-opaque-filters-expected.png
index 86d7115..9155e6e 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/non-opaque-filters-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/non-opaque-filters-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/text-image-opacity-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/text-image-opacity-expected.png
index 0587824..264c19c 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/text-image-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/text-image-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/use-modify-container-in-target-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/use-modify-container-in-target-expected.png
index 8d73aa6..6e44302 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/use-modify-container-in-target-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/use-modify-container-in-target-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/use-modify-target-container-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/use-modify-target-container-expected.png
index e752c114..ed65e53 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/use-modify-target-container-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/use-modify-target-container-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/use-on-g-containing-use-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/use-on-g-containing-use-expected.png
index c9ba215c..c74116a 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/use-on-g-containing-use-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/use-on-g-containing-use-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/use-on-g-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/use-on-g-expected.png
index ea32bd1..a8b32e6 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/use-on-g-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/use-on-g-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/use-on-use-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/use-on-use-expected.png
index ea32bd1..a8b32e6 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/use-on-use-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/use-on-use-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/custom/use-transform-expected.png b/third_party/blink/web_tests/platform/mac/svg/custom/use-transform-expected.png
index 7d14180..40af6944 100644
--- a/third_party/blink/web_tests/platform/mac/svg/custom/use-transform-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/custom/use-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/text/text-selection-text-08-b-expected.png b/third_party/blink/web_tests/platform/mac/svg/text/text-selection-text-08-b-expected.png
index 610ae77..1ad277dc 100644
--- a/third_party/blink/web_tests/platform/mac/svg/text/text-selection-text-08-b-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/text/text-selection-text-08-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/transforms/2d/hindi-rotated-expected.png b/third_party/blink/web_tests/platform/mac/transforms/2d/hindi-rotated-expected.png
index 1ce9b39..bc17ac2 100644
--- a/third_party/blink/web_tests/platform/mac/transforms/2d/hindi-rotated-expected.png
+++ b/third_party/blink/web_tests/platform/mac/transforms/2d/hindi-rotated-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/transforms/transform-on-inline-expected.png b/third_party/blink/web_tests/platform/mac/transforms/transform-on-inline-expected.png
index bd5999b..9885212 100644
--- a/third_party/blink/web_tests/platform/mac/transforms/transform-on-inline-expected.png
+++ b/third_party/blink/web_tests/platform/mac/transforms/transform-on-inline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/transforms/transform-table-row-expected.png b/third_party/blink/web_tests/platform/mac/transforms/transform-table-row-expected.png
index 61d19bf..3292044d 100644
--- a/third_party/blink/web_tests/platform/mac/transforms/transform-table-row-expected.png
+++ b/third_party/blink/web_tests/platform/mac/transforms/transform-table-row-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/transforms/transforms-with-opacity-expected.png b/third_party/blink/web_tests/platform/mac/transforms/transforms-with-opacity-expected.png
index b6ad1bc..5147027 100644
--- a/third_party/blink/web_tests/platform/mac/transforms/transforms-with-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/mac/transforms/transforms-with-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png
index cb8efa6..d39e1dca 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png
index 4a32480..038c7c3 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index 188e8b3..b9e4613 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-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/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
index 3bd95da..59581e1 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index 5da3c2f..17d0760b 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index 5946bb7..9173ea0 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/video-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/video-focus-ring-expected.png
index 2fd291d..52a0595 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/video-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/media/video-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/capitalize-boundaries-expected.png b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/capitalize-boundaries-expected.png
index ebce3b5d..58617080 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/capitalize-boundaries-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/capitalize-boundaries-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/complex-text-opacity-expected.png b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/complex-text-opacity-expected.png
index befe4c2d..3bb9fd1e 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/complex-text-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/complex-text-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/letter-spacing-negative-opacity-expected.png b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
index 2a6aeab2..20a43e9 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/compositing/transitions/scale-transition-no-start-expected.png b/third_party/blink/web_tests/platform/win/compositing/transitions/scale-transition-no-start-expected.png
index ba342f9..5ec2f87 100644
--- a/third_party/blink/web_tests/platform/win/compositing/transitions/scale-transition-no-start-expected.png
+++ b/third_party/blink/web_tests/platform/win/compositing/transitions/scale-transition-no-start-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/backgrounds/opacity-on-document-element-expected.png b/third_party/blink/web_tests/platform/win/fast/backgrounds/opacity-on-document-element-expected.png
index 9747f57..5a673e14 100644
--- a/third_party/blink/web_tests/platform/win/fast/backgrounds/opacity-on-document-element-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/backgrounds/opacity-on-document-element-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/block/float/float-in-float-painting-expected.png b/third_party/blink/web_tests/platform/win/fast/block/float/float-in-float-painting-expected.png
index bdf0d1d..64cf90b 100644
--- a/third_party/blink/web_tests/platform/win/fast/block/float/float-in-float-painting-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/block/float/float-in-float-painting-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/css/ZeroOpacityLayers-expected.png b/third_party/blink/web_tests/platform/win/fast/css/ZeroOpacityLayers-expected.png
index bdb3ec29..e74c8df4 100644
--- a/third_party/blink/web_tests/platform/win/fast/css/ZeroOpacityLayers-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/css/ZeroOpacityLayers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/css/ZeroOpacityLayers2-expected.png b/third_party/blink/web_tests/platform/win/fast/css/ZeroOpacityLayers2-expected.png
index 8b2342f..b0fdea8 100644
--- a/third_party/blink/web_tests/platform/win/fast/css/ZeroOpacityLayers2-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/css/ZeroOpacityLayers2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
index a1f4c8a4..f2940d3 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index add7f3e..7f3c21ef 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
index 826fe95..60cbf92 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/indeterminate-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/indeterminate-expected.png
index 200990c..13839c3 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/indeterminate-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/indeterminate-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/select/basic-selects-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/select/basic-selects-expected.png
index f1acb10..2d49530 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/select/basic-selects-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/select/basic-selects-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/select/disabled-select-change-index-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/select/disabled-select-change-index-expected.png
index c4b6024..68d5b87b 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/select/disabled-select-change-index-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/select/disabled-select-change-index-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/select/listbox-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/select/listbox-appearance-basic-expected.png
index 106ca1dc..40487c0 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/select/listbox-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/select/listbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/select/select-disabled-appearance-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/select/select-disabled-appearance-expected.png
index dcf5405..adb6ab47 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/select/select-disabled-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/select/select-disabled-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/layers/opacity-outline-expected.png b/third_party/blink/web_tests/platform/win/fast/layers/opacity-outline-expected.png
index 0665e08..8b65132 100644
--- a/third_party/blink/web_tests/platform/win/fast/layers/opacity-outline-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/layers/opacity-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/layers/opacity-transforms-expected.png b/third_party/blink/web_tests/platform/win/fast/layers/opacity-transforms-expected.png
index e8c858a..bb3e23ce 100644
--- a/third_party/blink/web_tests/platform/win/fast/layers/opacity-transforms-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/layers/opacity-transforms-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/multicol/layers-in-multicol-expected.png b/third_party/blink/web_tests/platform/win/fast/multicol/layers-in-multicol-expected.png
index 62b98ea..c4448e1 100644
--- a/third_party/blink/web_tests/platform/win/fast/multicol/layers-in-multicol-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/multicol/layers-in-multicol-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/overflow/007-expected.png b/third_party/blink/web_tests/platform/win/fast/overflow/007-expected.png
index 58f301d..282116cb 100644
--- a/third_party/blink/web_tests/platform/win/fast/overflow/007-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/overflow/007-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/overflow/overflow-of-video-outline-expected.png b/third_party/blink/web_tests/platform/win/fast/overflow/overflow-of-video-outline-expected.png
index b00fcf7..882072bf 100644
--- a/third_party/blink/web_tests/platform/win/fast/overflow/overflow-of-video-outline-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/overflow/overflow-of-video-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/reflections/opacity-reflection-transform-expected.png b/third_party/blink/web_tests/platform/win/fast/reflections/opacity-reflection-transform-expected.png
index 49eb015..beeff6d 100644
--- a/third_party/blink/web_tests/platform/win/fast/reflections/opacity-reflection-transform-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/reflections/opacity-reflection-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/table/backgr_layers-opacity-collapsed-border-expected.png b/third_party/blink/web_tests/platform/win/fast/table/backgr_layers-opacity-collapsed-border-expected.png
index ec6a410..baaa365 100644
--- a/third_party/blink/web_tests/platform/win/fast/table/backgr_layers-opacity-collapsed-border-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/table/backgr_layers-opacity-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/table/backgr_layers-opacity-expected.png b/third_party/blink/web_tests/platform/win/fast/table/backgr_layers-opacity-expected.png
index ec6a410..baaa365 100644
--- a/third_party/blink/web_tests/platform/win/fast/table/backgr_layers-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/table/backgr_layers-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/table/dynamic-caption-add-before-child-expected.png b/third_party/blink/web_tests/platform/win/fast/table/dynamic-caption-add-before-child-expected.png
index a3ad924..9635330 100644
--- a/third_party/blink/web_tests/platform/win/fast/table/dynamic-caption-add-before-child-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/table/dynamic-caption-add-before-child-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/table/multiple-captions-display-expected.png b/third_party/blink/web_tests/platform/win/fast/table/multiple-captions-display-expected.png
index 5d42064..89a602de 100644
--- a/third_party/blink/web_tests/platform/win/fast/table/multiple-captions-display-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/table/multiple-captions-display-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/table/overflowHidden-expected.png b/third_party/blink/web_tests/platform/win/fast/table/overflowHidden-expected.png
index 03e045c..c1958c4 100644
--- a/third_party/blink/web_tests/platform/win/fast/table/overflowHidden-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/table/overflowHidden-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/blink/web_tests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 6b9ac5e..fc802cf 100644
--- a/third_party/blink/web_tests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/blink/web_tests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/win/media/audio-controls-rendering-expected.png
index 844fb6a..da02658 100644
--- a/third_party/blink/web_tests/platform/win/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/win/media/audio-repaint-expected.png
index 762754e..25b07db4 100644
--- a/third_party/blink/web_tests/platform/win/media/audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/controls-layout-direction-expected.png b/third_party/blink/web_tests/platform/win/media/controls-layout-direction-expected.png
index 9fdf0d0a..e2e05d38 100644
--- a/third_party/blink/web_tests/platform/win/media/controls-layout-direction-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/blink/web_tests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.png
index 9250d78c..45523bbc 100644
--- a/third_party/blink/web_tests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/media-controls-clone-expected.png b/third_party/blink/web_tests/platform/win/media/media-controls-clone-expected.png
index a47ccc3..b6a87a6 100644
--- a/third_party/blink/web_tests/platform/win/media/media-controls-clone-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/media-controls-grey-scrubber-expected.png b/third_party/blink/web_tests/platform/win/media/media-controls-grey-scrubber-expected.png
index ce318fd1..e4f0e7d3 100644
--- a/third_party/blink/web_tests/platform/win/media/media-controls-grey-scrubber-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/media-controls-grey-scrubber-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/media-document-audio-repaint-expected.png b/third_party/blink/web_tests/platform/win/media/media-document-audio-repaint-expected.png
index ce5124d..474da4b4 100644
--- a/third_party/blink/web_tests/platform/win/media/media-document-audio-repaint-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/video-empty-source-expected.png b/third_party/blink/web_tests/platform/win/media/video-empty-source-expected.png
index f6ee66b..cb6e108 100644
--- a/third_party/blink/web_tests/platform/win/media/video-empty-source-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/video-empty-source-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/media/video-no-audio-expected.png b/third_party/blink/web_tests/platform/win/media/video-no-audio-expected.png
index 65d4ce7..e819ae4d 100644
--- a/third_party/blink/web_tests/platform/win/media/video-no-audio-expected.png
+++ b/third_party/blink/web_tests/platform/win/media/video-no-audio-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/compositing/become-overlay-composited-layer-expected.png b/third_party/blink/web_tests/platform/win/paint/invalidation/compositing/become-overlay-composited-layer-expected.png
index e19b323a..ba54015 100644
--- a/third_party/blink/web_tests/platform/win/paint/invalidation/compositing/become-overlay-composited-layer-expected.png
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/compositing/become-overlay-composited-layer-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/blink/web_tests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index 1b5bd12..a798712 100644
--- a/third_party/blink/web_tests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png
index c38d4928..c463bf4 100644
--- a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/animate-elem-22-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
index e359034..dacee76 100644
--- a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
index fea2c473..14767ab 100644
--- a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/masking-opacity-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
index 8d88bae6..649f0b9f 100644
--- a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/text-text-08-b-expected.png b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/text-text-08-b-expected.png
index 1c68e42d..61210efa 100644
--- a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/text-text-08-b-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/text-text-08-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/as-background-image/svg-as-background-5-expected.png b/third_party/blink/web_tests/platform/win/svg/as-background-image/svg-as-background-5-expected.png
index 23c82431..6092be3 100644
--- a/third_party/blink/web_tests/platform/win/svg/as-background-image/svg-as-background-5-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/as-background-image/svg-as-background-5-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/as-background-image/svg-as-background-6-expected.png b/third_party/blink/web_tests/platform/win/svg/as-background-image/svg-as-background-6-expected.png
index 7aa5733..cc268560 100644
--- a/third_party/blink/web_tests/platform/win/svg/as-background-image/svg-as-background-6-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/as-background-image/svg-as-background-6-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/batik/text/smallFonts-expected.png b/third_party/blink/web_tests/platform/win/svg/batik/text/smallFonts-expected.png
index c34cad7..c0f8338f 100644
--- a/third_party/blink/web_tests/platform/win/svg/batik/text/smallFonts-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/batik/text/smallFonts-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/batik/text/textAnchor-expected.png b/third_party/blink/web_tests/platform/win/svg/batik/text/textAnchor-expected.png
index b59653eb..d4075d0 100644
--- a/third_party/blink/web_tests/platform/win/svg/batik/text/textAnchor-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/batik/text/textAnchor-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/batik/text/textFeatures-expected.png b/third_party/blink/web_tests/platform/win/svg/batik/text/textFeatures-expected.png
index 0d4a2f7..3b37f36 100644
--- a/third_party/blink/web_tests/platform/win/svg/batik/text/textFeatures-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/batik/text/textFeatures-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/batik/text/textProperties-expected.png b/third_party/blink/web_tests/platform/win/svg/batik/text/textProperties-expected.png
index c84989f..f57a321 100644
--- a/third_party/blink/web_tests/platform/win/svg/batik/text/textProperties-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/batik/text/textProperties-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/batik/text/verticalText-expected.png b/third_party/blink/web_tests/platform/win/svg/batik/text/verticalText-expected.png
index 625163d..dae9fba 100644
--- a/third_party/blink/web_tests/platform/win/svg/batik/text/verticalText-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/batik/text/verticalText-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/container-opacity-clip-viewBox-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/container-opacity-clip-viewBox-expected.png
index a4baca7..6aaa787 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/container-opacity-clip-viewBox-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/container-opacity-clip-viewBox-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/dominant-baseline-hanging-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/dominant-baseline-hanging-expected.png
index c6478373..92a59e9b 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/dominant-baseline-hanging-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/dominant-baseline-hanging-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/non-opaque-filters-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/non-opaque-filters-expected.png
index f09068f8..6d6b443 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/non-opaque-filters-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/non-opaque-filters-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/text-image-opacity-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/text-image-opacity-expected.png
index b139a65..e840fe6 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/text-image-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/text-image-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/use-modify-container-in-target-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/use-modify-container-in-target-expected.png
index 2481e20..752cbf31 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/use-modify-container-in-target-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/use-modify-container-in-target-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/use-modify-target-container-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/use-modify-target-container-expected.png
index 7a22566b..a44a7f6c 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/use-modify-target-container-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/use-modify-target-container-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/use-on-g-containing-use-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/use-on-g-containing-use-expected.png
index 95940b8..9fb95a6 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/use-on-g-containing-use-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/use-on-g-containing-use-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/use-on-g-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/use-on-g-expected.png
index be2f09d..9a138a9 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/use-on-g-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/use-on-g-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/use-on-use-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/use-on-use-expected.png
index be2f09d..9a138a9 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/use-on-use-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/use-on-use-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/custom/use-transform-expected.png b/third_party/blink/web_tests/platform/win/svg/custom/use-transform-expected.png
index c07b5335..20f1d7d 100644
--- a/third_party/blink/web_tests/platform/win/svg/custom/use-transform-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/custom/use-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/text/text-selection-text-08-b-expected.png b/third_party/blink/web_tests/platform/win/svg/text/text-selection-text-08-b-expected.png
index 396b36a0..4df2bed 100644
--- a/third_party/blink/web_tests/platform/win/svg/text/text-selection-text-08-b-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/text/text-selection-text-08-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/transforms/2d/hindi-rotated-expected.png b/third_party/blink/web_tests/platform/win/transforms/2d/hindi-rotated-expected.png
index 7a9bba8..8a89787 100644
--- a/third_party/blink/web_tests/platform/win/transforms/2d/hindi-rotated-expected.png
+++ b/third_party/blink/web_tests/platform/win/transforms/2d/hindi-rotated-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/transforms/transform-on-inline-expected.png b/third_party/blink/web_tests/platform/win/transforms/transform-on-inline-expected.png
index 363f65ba..5aa1e5c 100644
--- a/third_party/blink/web_tests/platform/win/transforms/transform-on-inline-expected.png
+++ b/third_party/blink/web_tests/platform/win/transforms/transform-on-inline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/transforms/transform-table-row-expected.png b/third_party/blink/web_tests/platform/win/transforms/transform-table-row-expected.png
index 0400927..b672010 100644
--- a/third_party/blink/web_tests/platform/win/transforms/transform-table-row-expected.png
+++ b/third_party/blink/web_tests/platform/win/transforms/transform-table-row-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/transforms/transforms-with-opacity-expected.png b/third_party/blink/web_tests/platform/win/transforms/transforms-with-opacity-expected.png
index eb1301c..905bc920 100644
--- a/third_party/blink/web_tests/platform/win/transforms/transforms-with-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/win/transforms/transforms-with-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png
index 4f6e863..6b21f0f 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/date/date-picker-month-year-selector-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png
index ef2ec41..57edcb9 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/datetimelocal-picker/datetimelocal-month-year-selector-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
index 5301e48..9ec54d7e 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-disabled-multiple-hover-focused-unselected-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
index 05647eac..49f20260 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-inpage-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/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
index 4e616fa..2f0714b1 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/select/select-multiple-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
index 3191694..046cf3ec 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
index c0cea46..8f26a75 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/audio-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/video-focus-ring-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/video-focus-ring-expected.png
index dd749e9..e04cd5aa 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/video-focus-ring-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/media/video-focus-ring-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/text-antialias/complex-text-opacity-expected.png b/third_party/blink/web_tests/platform/win/virtual/text-antialias/complex-text-opacity-expected.png
index 31a16b7..9fa8e1f 100644
--- a/third_party/blink/web_tests/platform/win/virtual/text-antialias/complex-text-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/text-antialias/complex-text-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/text-antialias/letter-spacing-negative-opacity-expected.png b/third_party/blink/web_tests/platform/win/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
index 8f41d22..d2b040dc 100644
--- a/third_party/blink/web_tests/platform/win/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/text-antialias/letter-spacing-negative-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/custom/group-opacity-expected.png b/third_party/blink/web_tests/svg/custom/group-opacity-expected.png
index f1a5b9d3..eca9f5c3 100644
--- a/third_party/blink/web_tests/svg/custom/group-opacity-expected.png
+++ b/third_party/blink/web_tests/svg/custom/group-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/custom/marker-opacity-expected.png b/third_party/blink/web_tests/svg/custom/marker-opacity-expected.png
index 29aad87..cea8b9a 100644
--- a/third_party/blink/web_tests/svg/custom/marker-opacity-expected.png
+++ b/third_party/blink/web_tests/svg/custom/marker-opacity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/custom/marker-zero-length-linecaps-expected.png b/third_party/blink/web_tests/svg/custom/marker-zero-length-linecaps-expected.png
index 5952106d..9210d18 100644
--- a/third_party/blink/web_tests/svg/custom/marker-zero-length-linecaps-expected.png
+++ b/third_party/blink/web_tests/svg/custom/marker-zero-length-linecaps-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/custom/root-container-opacity-clip-viewBox-expected.png b/third_party/blink/web_tests/svg/custom/root-container-opacity-clip-viewBox-expected.png
index b506046..74c7211 100644
--- a/third_party/blink/web_tests/svg/custom/root-container-opacity-clip-viewBox-expected.png
+++ b/third_party/blink/web_tests/svg/custom/root-container-opacity-clip-viewBox-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
index a7602b0..d3083ae7 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
index a7602b0..d3083ae7 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
index a7602b0..d3083ae7 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
index a7602b0..d3083ae7 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
index a7602b0..d3083ae7 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
index a7602b0..d3083ae7 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-height-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-maskContentUnits-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png
index 2292c99..4bf20c1 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-maskUnits-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-width-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-x-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-dom-y-attr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-height-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-maskContentUnits-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png
index 2292c99..4bf20c1 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-maskUnits-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-width-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-x-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png
index 2b62614..c7f575b 100644
--- a/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png
+++ b/third_party/blink/web_tests/svg/dynamic-updates/SVGMaskElement-svgdom-y-prop-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/foreignObject/clip-expected.png b/third_party/blink/web_tests/svg/foreignObject/clip-expected.png
index 2ad1e2d..f42980c 100644
--- a/third_party/blink/web_tests/svg/foreignObject/clip-expected.png
+++ b/third_party/blink/web_tests/svg/foreignObject/clip-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/foreignObject/filter-expected.png b/third_party/blink/web_tests/svg/foreignObject/filter-expected.png
index ef4492f..6927d79 100644
--- a/third_party/blink/web_tests/svg/foreignObject/filter-expected.png
+++ b/third_party/blink/web_tests/svg/foreignObject/filter-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/foreignObject/mask-expected.png b/third_party/blink/web_tests/svg/foreignObject/mask-expected.png
index ef4492f..6927d79 100644
--- a/third_party/blink/web_tests/svg/foreignObject/mask-expected.png
+++ b/third_party/blink/web_tests/svg/foreignObject/mask-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/plz-dedicated-worker/http/tests/devtools/layers/layer-canvas-log-expected.txt b/third_party/blink/web_tests/virtual/plz-dedicated-worker/http/tests/devtools/layers/layer-canvas-log-expected.txt
deleted file mode 100644
index c458c28..0000000
--- a/third_party/blink/web_tests/virtual/plz-dedicated-worker/http/tests/devtools/layers/layer-canvas-log-expected.txt
+++ /dev/null
@@ -1,177 +0,0 @@
-Tests layer command log
-
-Canvas log:
-{
-    0 : {
-        commandIndex : 0
-        method : "drawPaint"
-        params : {
-            paint : {
-                blendMode : "Src"
-                color : "#00000000"
-                flags : "none"
-                strokeCap : "Butt"
-                strokeJoin : "Miter"
-                strokeMiter : 4
-                strokeWidth : 0
-                styleName : "Fill"
-            }
-        }
-    }
-    1 : {
-        commandIndex : 1
-        method : "drawRect"
-        params : {
-            paint : {
-                color : "#FF0000FF"
-                flags : "AntiAlias"
-                strokeCap : "Butt"
-                strokeJoin : "Miter"
-                strokeMiter : 4
-                strokeWidth : 0
-                styleName : "Fill"
-            }
-            rect : {
-                bottom : 100
-                left : 0
-                right : 100
-                top : 0
-            }
-        }
-    }
-    10 : {
-        commandIndex : 10
-        method : "drawRect"
-        params : {
-            paint : {
-                color : "#7F000000"
-                flags : "AntiAlias"
-                strokeCap : "Butt"
-                strokeJoin : "Miter"
-                strokeMiter : 4
-                strokeWidth : 0
-                styleName : "Fill"
-            }
-            rect : {
-                bottom : 10
-                left : 0
-                right : 10
-                top : 0
-            }
-        }
-    }
-    11 : {
-        commandIndex : 11
-        method : "restore"
-        params : undefined
-    }
-    2 : {
-        commandIndex : 2
-        method : "drawRect"
-        params : {
-            paint : {
-                color : "#FFFF0000"
-                flags : "AntiAlias"
-                strokeCap : "Butt"
-                strokeJoin : "Miter"
-                strokeMiter : 4
-                strokeWidth : 0
-                styleName : "Fill"
-            }
-            rect : {
-                bottom : 50
-                left : 0
-                right : 50
-                top : 0
-            }
-        }
-    }
-    3 : {
-        commandIndex : 3
-        method : "save"
-        params : undefined
-    }
-    4 : {
-        commandIndex : 4
-        method : "concat44"
-        params : {
-            matrix44 : [
-                1
-                0
-                0
-                0
-                0
-                1
-                0
-                0
-                0
-                0
-                1
-                0
-                0
-                50
-                0
-                1
-            ]
-        }
-    }
-    5 : {
-        commandIndex : 5
-        method : "drawImage"
-        params : {
-            image : {
-                height : 21
-                opaque : false
-                width : 19
-            }
-            left : 0
-            paint : {
-                color : "#FF000000"
-                flags : "AntiAlias"
-                strokeCap : "Butt"
-                strokeJoin : "Miter"
-                strokeMiter : 4
-                strokeWidth : 0
-                styleName : "Fill"
-            }
-            sampling : {
-                filter : "kLinear"
-                mipmap : "kNearest"
-            }
-            top : 0
-        }
-    }
-    6 : {
-        commandIndex : 6
-        method : "restore"
-        params : undefined
-    }
-    7 : {
-        commandIndex : 7
-        method : "save"
-        params : undefined
-    }
-    8 : {
-        commandIndex : 8
-        method : "translate"
-        params : {
-            dx : 0
-            dy : 71
-        }
-    }
-    9 : {
-        commandIndex : 9
-        method : "clipRect"
-        params : {
-            SkRegion::Op : "kIntersect_Op"
-            rect : {
-                bottom : 150
-                left : 0
-                right : 300
-                top : 0
-            }
-            softClipEdgeStyle : true
-        }
-    }
-}
-
diff --git a/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/css-opacity-with-drop-shadow-expected.png b/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/css-opacity-with-drop-shadow-expected.png
index 5cd9b2b7..02399e8 100644
--- a/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/css-opacity-with-drop-shadow-expected.png
+++ b/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/css-opacity-with-drop-shadow-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-fonts/font-glyph-synthesis-mac-expected.html b/third_party/blink/web_tests/wpt_internal/css/css-fonts/font-glyph-synthesis-mac-expected.html
deleted file mode 100644
index e0f6443..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-fonts/font-glyph-synthesis-mac-expected.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<meta charset="utf-8" />
-<title>CSS Test: MacOS synthesizing glyphs</title>
-
-<body>
-  <p style="font-family: Arial;">&#x002D</p>
-  <p style="font-family: Arial;">&#x002D</p>
-  <p style="font-family: Arial;">&#x002D</p>
-</body>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-fonts/font-glyph-synthesis-mac.html b/third_party/blink/web_tests/wpt_internal/css/css-fonts/font-glyph-synthesis-mac.html
deleted file mode 100644
index 35807d3..0000000
--- a/third_party/blink/web_tests/wpt_internal/css/css-fonts/font-glyph-synthesis-mac.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<meta charset="utf-8" />
-<title>CSS Test: MacOS synthesizing glyphs</title>
-<link rel="match" href="font-glyph-synthesis-mac-expected.html">
-<meta name="assert"
-  content="This test is Mac specific, it checks cases when hyphen character is being synthesized in Arial font on Mac">
-
-<body>
-  <p style="font-family: Arial;">&#x002D</p>
-  <p style="font-family: Arial;">&#x2010</p>
-  <p style="font-family: Arial;">&#x2011</p>
-</body>
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium
index a80a167..a0fb072 100644
--- a/third_party/libaom/README.chromium
+++ b/third_party/libaom/README.chromium
@@ -2,8 +2,8 @@
 Short Name: libaom
 URL: https://aomedia.googlesource.com/aom/
 Version: 0
-Date: Saturday January 14 2023
-Revision: 0b76cc07c5a3a5bfcb737cddc7452137d58197d9
+Date: Thursday January 19 2023
+Revision: 5115747345e7de18fdbafc333e078604f39ba932
 CPEPrefix: cpe:/a:aomedia:aomedia:3.5.0
 License: BSD
 License File: source/libaom/LICENSE
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h
index 5592534..0587f7f9 100644
--- a/third_party/libaom/source/config/config/aom_version.h
+++ b/third_party/libaom/source/config/config/aom_version.h
@@ -12,8 +12,8 @@
 #define VERSION_MAJOR 3
 #define VERSION_MINOR 5
 #define VERSION_PATCH 0
-#define VERSION_EXTRA "673-g0b76cc07c"
+#define VERSION_EXTRA "693-g511574734"
 #define VERSION_PACKED \
   ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH))
-#define VERSION_STRING_NOSP "3.5.0-673-g0b76cc07c"
-#define VERSION_STRING " 3.5.0-673-g0b76cc07c"
+#define VERSION_STRING_NOSP "3.5.0-693-g511574734"
+#define VERSION_STRING " 3.5.0-693-g511574734"
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index d12a8b73..009ee02 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -454,7 +454,7 @@
       'mac-hermetic-upgrade-rel': 'release_bot_reclient',
       'mac-perfetto-rel': 'perfetto_release_bot_reclient',
       'mac-upload-perfetto': 'release_bot_perfetto_zlib_reclient',
-      'mac12-wpt-content-shell-fyi-rel': 'release_bot_reclient',
+      'mac12-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient',
       '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',
@@ -1266,6 +1266,7 @@
       'mac11-arm64-rel': 'mac_arm64_gpu_tests_release_trybot_no_symbols_reclient',
       'mac12-arm64-rel': 'mac_arm64_gpu_tests_release_trybot_no_symbols',
       'mac12-tests': 'release_trybot',
+      'mac12-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient',
       'mac_chromium_10.13_rel_ng': 'release_trybot',
       'mac_chromium_10.14_rel_ng': 'release_trybot',
       'mac_chromium_10.15_rel_ng': 'release_trybot_no_nacl',
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 1212cf5..87cdb5dd 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -1407,9 +1407,10 @@
   },
   "mac12-wpt-content-shell-fyi-rel": {
     "gn_args": {
-      "dcheck_always_on": false,
+      "dcheck_always_on": true,
       "is_component_build": false,
       "is_debug": false,
+      "symbol_level": 1,
       "use_remoteexec": true
     }
   },
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json
index 71b7fce..3103373 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json
@@ -584,6 +584,15 @@
       "use_goma": true
     }
   },
+  "mac12-wpt-content-shell-fyi-rel": {
+    "gn_args": {
+      "dcheck_always_on": true,
+      "is_component_build": false,
+      "is_debug": false,
+      "symbol_level": 1,
+      "use_remoteexec": true
+    }
+  },
   "mac_chromium_10.13_rel_ng": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 39e1fbe..13c0772 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -8975,6 +8975,30 @@
   </description>
 </action>
 
+<action name="FileBrowser.GoogleOneOffer.Dismiss">
+  <owner>yawano@google.com</owner>
+  <owner>src/ui/file_manager/OWNERS</owner>
+  <description>
+    Google One offer files banner gets dismissed by the user.
+  </description>
+</action>
+
+<action name="FileBrowser.GoogleOneOffer.GetPerk">
+  <owner>yawano@google.com</owner>
+  <owner>src/ui/file_manager/OWNERS</owner>
+  <description>
+    Get perk button of Google One offer files banner gets activated.
+  </description>
+</action>
+
+<action name="FileBrowser.GoogleOneOffer.Shown">
+  <owner>yawano@google.com</owner>
+  <owner>src/ui/file_manager/OWNERS</owner>
+  <description>
+    Google One offer files banner gets shown on Files app.
+  </description>
+</action>
+
 <action name="FileBrowser.PhotoEditor.Edit">
   <obsolete>Removed in M92.</obsolete>
   <owner>simmonsjosh@google.com</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d960bd8..d212ba3 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3961,6 +3961,11 @@
   <int value="4" label="Outside of NTP (e.g. bookmarks bar)"/>
 </enum>
 
+<enum name="AppsSyncOptinFileWrite">
+  <int value="0" label="Attempt"/>
+  <int value="1" label="Failure"/>
+</enum>
+
 <enum name="AppStreamLaunchEntryPoint">
   <int value="0" label="Launched from full apps list"/>
   <int value="1" label="Launched from a notification"/>
@@ -28509,6 +28514,9 @@
   <int value="11" label="Resume"/>
   <int value="12" label="RetryDownload"/>
   <int value="13" label="OpenDuringScanning"/>
+  <int value="14" label="ReviewDangerous"/>
+  <int value="15" label="DeepScan"/>
+  <int value="16" label="BypassDeepScan"/>
 </enum>
 
 <enum name="DownloadedFileAction">
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index c128af9..fdac0d2 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -1088,6 +1088,41 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Apps.AppList.SystemInfoProvider.CrosHealthdProbeError.{ProbeErrorSourceStruct}"
+    enum="CrosDiagnosticsCrosHealthdProbeError" expires_after="2023-10-15">
+  <owner>laurencom@google.com</owner>
+  <owner>wrong@chromium.org</owner>
+  <owner>tby@google.com</owner>
+  <summary>
+    Records the ProbeError::ErrorType returned on request for
+    {ProbeErrorSourceStruct}. Recorded on the event a request to cros_healthd
+    probe service returns a ProbeError. This can occur when a request is made to
+    the CrosHealthdProbeService within the System Info Provider.
+  </summary>
+  <token key="ProbeErrorSourceStruct">
+    <variant name="BatteryInfo"/>
+    <variant name="CpuInfo"/>
+    <variant name="MemoryInfo"/>
+  </token>
+</histogram>
+
+<histogram name="Apps.AppList.SystemInfoProvider.Error.{ErrorSource}"
+    enum="CrosDiagnosticsDataError" expires_after="2023-10-15">
+  <owner>laurencom@google.com</owner>
+  <owner>wrong@google.com</owner>
+  <owner>tby@google.com</owner>
+  <summary>
+    Records error type such as no data error, not a number error and expectation
+    not met error when receiving system information including battery info,
+    network info and system info. All errors are recorded.
+  </summary>
+  <token key="ErrorSource">
+    <variant name="Battery"/>
+    <variant name="Network"/>
+  </token>
+</histogram>
+
 <histogram name="Apps.AppList.TimeToUserAction{TabletOrClamshell}" units="ms"
     expires_after="2023-06-19">
   <owner>gzadina@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index b1fa106..e9801d3 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -4410,6 +4410,9 @@
 
 <histogram name="Ash.Shelf.Palette.Assistant.CircledPercentage" units="%"
     expires_after="2021-12-12">
+  <obsolete>
+    Deprecated in M111. No longer needed since metalayer was deprecated in M110.
+  </obsolete>
   <owner>amehfooz@chromium.org</owner>
   <owner>cros-status-area@google.com</owner>
   <owner>gzadina@chromium.org</owner>
@@ -4436,6 +4439,9 @@
 
 <histogram name="Ash.Shelf.Palette.Assistant.GestureDuration" units="ms"
     expires_after="2021-12-12">
+  <obsolete>
+    Deprecated in M111. No longer needed since metalayer was deprecated in M110.
+  </obsolete>
   <owner>amehfooz@chromium.org</owner>
   <owner>cros-status-area@google.com</owner>
   <owner>gzadina@chromium.org</owner>
@@ -4447,6 +4453,9 @@
 
 <histogram name="Ash.Shelf.Palette.Assistant.GestureInterval" units="ms"
     expires_after="2021-12-12">
+  <obsolete>
+    Deprecated in M111. No longer needed since metalayer was deprecated in M110.
+  </obsolete>
   <owner>amehfooz@chromium.org</owner>
   <owner>cros-status-area@google.com</owner>
   <owner>gzadina@chromium.org</owner>
@@ -4460,6 +4469,9 @@
 
 <histogram name="Ash.Shelf.Palette.Assistant.GesturesPerSession" units="units"
     expires_after="2021-12-12">
+  <obsolete>
+    Deprecated in M111. No longer needed since metalayer was deprecated in M110.
+  </obsolete>
   <owner>amehfooz@chromium.org</owner>
   <owner>cros-status-area@google.com</owner>
   <owner>gzadina@chromium.org</owner>
@@ -4472,6 +4484,9 @@
 
 <histogram name="Ash.Shelf.Palette.Assistant.GesturesPerSession.Recognized"
     units="units" expires_after="2021-12-12">
+  <obsolete>
+    Deprecated in M111. No longer needed since metalayer was deprecated in M110.
+  </obsolete>
   <owner>amehfooz@chromium.org</owner>
   <owner>cros-status-area@google.com</owner>
   <owner>gzadina@chromium.org</owner>
@@ -4484,6 +4499,9 @@
 
 <histogram name="Ash.Shelf.Palette.Assistant.GestureType"
     enum="AssistantGestureType" expires_after="2023-05-01">
+  <obsolete>
+    Deprecated in M111. No longer needed since metalayer was deprecated in M110.
+  </obsolete>
   <owner>amehfooz@chromium.org</owner>
   <owner>cros-status-area@google.com</owner>
   <owner>gzadina@chromium.org</owner>
@@ -4494,6 +4512,9 @@
 
 <histogram name="Ash.Shelf.Palette.Assistant.HighlighterLength" units="dp"
     expires_after="2021-12-12">
+  <obsolete>
+    Deprecated in M111. No longer needed since metalayer was deprecated in M110.
+  </obsolete>
   <owner>amehfooz@chromium.org</owner>
   <owner>cros-status-area@google.com</owner>
   <owner>gzadina@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index 38c0e5b..add1976 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1335,6 +1335,16 @@
   </token>
 </histogram>
 
+<histogram name="ChromeOS.Inputs.EventRewriter.KeyRewriteLatency" units="ms"
+    expires_after="2024-01-05">
+  <owner>wangdanny@chromium.org</owner>
+  <owner>dpad@chromium.org</owner>
+  <owner>cros-peripherals@google.com</owner>
+  <summary>
+    Records the event rewriter latency metric every time a key is pressed.
+  </summary>
+</histogram>
+
 <histogram name="ChromeOS.Intents.IntentPickerAction"
     enum="IntentPickerDialogAction" expires_after="2023-07-02">
   <owner>tsergeant@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/cros/histograms.xml b/tools/metrics/histograms/metadata/cros/histograms.xml
index 587dae5..73ef2cd 100644
--- a/tools/metrics/histograms/metadata/cros/histograms.xml
+++ b/tools/metrics/histograms/metadata/cros/histograms.xml
@@ -22,6 +22,16 @@
 
 <histograms>
 
+<histogram name="Cros.AppsSyncOptinFileWriteAttempts"
+    enum="AppsSyncOptinFileWrite" expires_after="2024-01-30">
+  <owner>drmasquatch@google.com</owner>
+  <owner>clumptini@google.com</owner>
+  <summary>
+    Logs attempts to write a user's opt-in status for Apps Sync to disk, as well
+    as failures.
+  </summary>
+</histogram>
+
 <histogram name="Cros.CrOSActionRecorderEvent" enum="CrOSActionRecorderEvent"
     expires_after="2022-05-01">
   <owner>charleszhao@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
index 9418cbd..c018968 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -429,27 +429,6 @@
   </summary>
 </histogram>
 
-<histogram name="SafeBrowsing.CookieAgeHours" units="hours"
-    expires_after="2023-06-04">
-  <owner>drubery@chromium.org</owner>
-  <owner>chrome-counter-abuse-alerts@google.com</owner>
-  <summary>
-    Records whether the age of the Safe Browsing cookie at startup or when a new
-    profile is created.
-  </summary>
-</histogram>
-
-<histogram name="SafeBrowsing.CredentialPhishedStatusChange"
-    enum="CredentialPhishedStatus" expires_after="2023-02-19">
-  <owner>drubery@chromium.org</owner>
-  <owner>chrome-counter-abuse-alerts@google.com</owner>
-  <summary>
-    Recorded when the phished status of a saved credential changes. Records when
-    a credential is marked phished or when a phished insecure credential entry
-    is removed because the site was marked as legitimate.
-  </summary>
-</histogram>
-
 <histogram
     name="SafeBrowsing.Daily.BypassCountLast28Days.{UserState}.{EventType}"
     units="events" expires_after="2024-01-04">
@@ -847,16 +826,6 @@
   </summary>
 </histogram>
 
-<histogram name="SafeBrowsing.HasCookieAtStartup" enum="Boolean"
-    expires_after="2023-02-12">
-  <owner>drubery@chromium.org</owner>
-  <owner>chrome-counter-abuse-alerts@google.com</owner>
-  <summary>
-    Records whether a Safe Browsing cookie exists at startup or when a new
-    profile is created.
-  </summary>
-</histogram>
-
 <histogram name="SafeBrowsing.LocalBinaryUploadRequest.DlpResult"
     enum="BooleanSuccess" expires_after="2023-10-20">
   <owner>rogerta@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index d40fb93..f0d599d58 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,16 +5,16 @@
             "full_remote_path": "perfetto-luci-artifacts/v31.0/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "0be9ae17456beffc25940507d40177c05922ef48",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/0d57f4770c40738e610deac22a59efc71ea4f329/trace_processor_shell.exe"
+            "hash": "c15018ebfa18305e77591643500530cf82bc6ab5",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/53971a4039d33587dcf88762c85c92b0faab412b/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "6373f26144aad58f230d11d6a91efda5a09c9873",
             "full_remote_path": "perfetto-luci-artifacts/v31.0/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "622120a168180957b3f08aba2edd6120e75da8f3",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/95b5b758ffac469fba8cda6cbbbffaea060d4c47/trace_processor_shell"
+            "hash": "23ebd3be5e889a7bed6a5452e5baf031095f963e",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/53971a4039d33587dcf88762c85c92b0faab412b/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "5f47ee79e59d00bf3889d30ca52315522c158040",
diff --git a/ui/base/x/x11_shm_image_pool.cc b/ui/base/x/x11_shm_image_pool.cc
index 856ab4e..c1e1515 100644
--- a/ui/base/x/x11_shm_image_pool.cc
+++ b/ui/base/x/x11_shm_image_pool.cc
@@ -291,7 +291,7 @@
 void XShmImagePool::Cleanup() {
   for (FrameState& state : frame_states_) {
     if (state.shmaddr)
-      shmdt(state.shmaddr);
+      shmdt(state.shmaddr.ExtractAsDangling());
     if (state.shmem_attached_to_server)
       connection_->shm().Detach({state.shmseg});
     state.shmem_attached_to_server = false;
diff --git a/ui/chromeos/events/event_rewriter_chromeos.cc b/ui/chromeos/events/event_rewriter_chromeos.cc
index d607435..c02aff54 100644
--- a/ui/chromeos/events/event_rewriter_chromeos.cc
+++ b/ui/chromeos/events/event_rewriter_chromeos.cc
@@ -12,11 +12,13 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/time/time.h"
 #include "device/udev_linux/scoped_udev.h"
 #include "ui/base/ime/ash/ime_keyboard.h"
 #include "ui/base/ime/ash/input_method_manager.h"
@@ -769,11 +771,17 @@
     const Continuation continuation) {
   if ((event.type() == ET_KEY_PRESSED) || (event.type() == ET_KEY_RELEASED)) {
     std::unique_ptr<Event> rewritten_event;
-    EventRewriteStatus status =
+    const base::Time key_rewrite_start_time = base::Time::Now();
+    const EventRewriteStatus status =
         RewriteKeyEvent(*((&event)->AsKeyEvent()), &rewritten_event);
-    return RewriteKeyEventInContext(*((&event)->AsKeyEvent()),
-                                    std::move(rewritten_event), status,
-                                    continuation);
+    const EventDispatchDetails details = RewriteKeyEventInContext(
+        *((&event)->AsKeyEvent()), std::move(rewritten_event), status,
+        continuation);
+    UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+        "ChromeOS.Inputs.EventRewriter.KeyRewriteLatency",
+        base::Time::Now() - key_rewrite_start_time, base::Microseconds(1),
+        base::Milliseconds(100), 100);
+    return details;
   }
   if ((event.type() == ET_MOUSE_PRESSED) ||
       (event.type() == ET_MOUSE_RELEASED)) {
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index 40751d2f..f9cd433 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1148,6 +1148,10 @@
   return loadTimeData.getBoolean('FILES_SEARCH_V2');
 };
 
+util.isGoogleOneOfferFilesBannerEnabled = () => {
+  return loadTimeData.getBoolean('GOOGLE_ONE_OFFER_FILES_BANNER');
+};
+
 /**
  * Returns true if FilesSinglePartitionFormat flag is enabled.
  * @return {boolean}
diff --git a/ui/file_manager/file_manager/externs/banner.js b/ui/file_manager/file_manager/externs/banner.js
index 48262f8..309dbed 100644
--- a/ui/file_manager/file_manager/externs/banner.js
+++ b/ui/file_manager/file_manager/externs/banner.js
@@ -119,6 +119,17 @@
 };
 
 /**
+ * Event source for BANNER_DISMISSED_FOREVER event.
+ * @enum {string}
+ * @const
+ */
+Banner.DismissedForeverEventSource = {
+  EXTRA_BUTTON: 'extra-button',
+  DEFAULT_DISMISS_BUTTON: 'default-dismiss-button',
+  OVERRIDEN_DISMISS_BUTTON: 'overriden-dismiss-button',
+};
+
+/**
  * Used to denote a banner that shows has an infinite time limit.
  * @const {number}
  */
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index 63e1c25..9147c5e 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -201,6 +201,7 @@
     "ui/banners:drive_out_of_individual_space_banner",
     "ui/banners:drive_out_of_organization_space_banner",
     "ui/banners:drive_welcome_banner",
+    "ui/banners:google_one_offer_banner",
     "ui/banners:holding_space_welcome_banner",
     "ui/banners:invalid_usb_filesystem_banner",
     "ui/banners:local_disk_low_space_banner",
diff --git a/ui/file_manager/file_manager/foreground/js/banner_controller.js b/ui/file_manager/file_manager/foreground/js/banner_controller.js
index 4744ac9..a9bb224 100644
--- a/ui/file_manager/file_manager/foreground/js/banner_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/banner_controller.js
@@ -27,6 +27,7 @@
 import {TAG_NAME as DriveOutOfIndividualSpaceBanner} from './ui/banners/drive_out_of_individual_space_banner.js';
 import {TAG_NAME as DriveOutOfOrganizationSpaceBanner} from './ui/banners/drive_out_of_organization_space_banner.js';
 import {TAG_NAME as DriveWelcomeBannerTagName} from './ui/banners/drive_welcome_banner.js';
+import {TAG_NAME as GoogleOneOfferBannerTagName} from './ui/banners/google_one_offer_banner.js';
 import {TAG_NAME as HoldingSpaceWelcomeBannerTagName} from './ui/banners/holding_space_welcome_banner.js';
 import {TAG_NAME as InvalidUSBFileSystemBanner} from './ui/banners/invalid_usb_filesystem_banner.js';
 import {TAG_NAME as LocalDiskLowSpaceBannerTagName} from './ui/banners/local_disk_low_space_banner.js';
@@ -311,12 +312,15 @@
         DriveOutOfIndividualSpaceBanner,
         DriveLowIndividualSpaceBanner,
       ]);
-      this.setEducationalBannersInOrder([
-        DriveWelcomeBannerTagName,
-        HoldingSpaceWelcomeBannerTagName,
-        DriveOfflinePinningBannerTagName,
-        PhotosWelcomeBannerTagName,
-      ]);
+
+      const educationalBanners = util.isGoogleOneOfferFilesBannerEnabled() ?
+          [GoogleOneOfferBannerTagName] :
+          [DriveWelcomeBannerTagName];
+      educationalBanners.push(
+          HoldingSpaceWelcomeBannerTagName, DriveOfflinePinningBannerTagName,
+          PhotosWelcomeBannerTagName);
+      this.setEducationalBannersInOrder(educationalBanners);
+
       this.setStateBannersInOrder([
         DlpRestrictedBannerName,
         InvalidUSBFileSystemBanner,
@@ -446,6 +450,10 @@
         this.volumeSizeObservers_[this.currentVolume_.volumeType]) {
       this.pendingVolumeSizeUpdates_.add(this.currentVolume_);
       this.updateVolumeSizeStatsDebounced_.runImmediately();
+
+      // updateVolumeSizeStats will call reconcile at its end. Return here to
+      // avoid calling showBanner_ twice for a banner.
+      return;
     }
 
     /** @type {?Banner} */
@@ -573,7 +581,7 @@
 
   /**
    * Check if the banner exists (add to DOM if not) and ensure it's visible.
-   * @param {!Banner} banner The banner to hide.
+   * @param {!Banner} banner The banner to show.
    * @private
    */
   async showBanner_(banner) {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/banners/BUILD.gn
index 3253da4..ae0a53e 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/BUILD.gn
@@ -27,6 +27,7 @@
     "drive_out_of_organization_space_banner.js",
     "drive_offline_pinning_banner.js",
     "drive_welcome_banner.js",
+    "google_one_offer_banner.js",
     "educational_banner.js",
     "holding_space_welcome_banner.js",
     "invalid_usb_filesystem_banner.js",
@@ -58,6 +59,7 @@
     ":drive_out_of_organization_space_banner",
     ":drive_welcome_banner",
     ":educational_banner",
+    ":google_one_offer_banner",
     ":holding_space_welcome_banner",
     ":invalid_usb_filesystem_banner",
     ":local_disk_low_space_banner",
@@ -149,6 +151,15 @@
   ]
 }
 
+js_library("google_one_offer_banner") {
+  deps = [
+    ":educational_banner",
+    "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
+    "//ui/file_manager/file_manager/externs:banner",
+  ]
+}
+
 js_library("drive_welcome_banner") {
   deps = [
     ":educational_banner",
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/educational_banner.js b/ui/file_manager/file_manager/foreground/js/ui/banners/educational_banner.js
index ad43225..c0275a5 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/educational_banner.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/educational_banner.js
@@ -100,10 +100,16 @@
         this.shadowRoot.querySelector('#dismiss-button');
     if (overridenDismissButton) {
       overridenDismissButton.addEventListener(
-          'click', event => this.onDismissClickHandler_(event));
+          'click',
+          event => this.onDismissClickHandler_(
+              event,
+              Banner.DismissedForeverEventSource.OVERRIDEN_DISMISS_BUTTON));
     } else if (defaultDismissButton) {
       defaultDismissButton.addEventListener(
-          'click', event => this.onDismissClickHandler_(event));
+          'click',
+          event => this.onDismissClickHandler_(
+              event,
+              Banner.DismissedForeverEventSource.DEFAULT_DISMISS_BUTTON));
     }
 
     // Attach an onclick handler to the extra-button slot. This enables a new
@@ -119,7 +125,10 @@
               new CustomEvent(Banner.Event.BANNER_DISMISSED_FOREVER, {
                 bubbles: true,
                 composed: true,
-                detail: {banner: this.getBannerInstance_()},
+                detail: {
+                  banner: this.getBannerInstance_(),
+                  eventSource: Banner.DismissedForeverEventSource.EXTRA_BUTTON,
+                },
               }));
         }
         e.preventDefault();
@@ -150,13 +159,18 @@
    * Handler for the dismiss button on click, switches to the custom banner
    * dismissal event to ensure the controller can catch the event.
    * @param {!Event} event The click event.
+   * @param {!Banner.DismissedForeverEventSource} dismissedForeverEventSource A
+   *     source of this event.
    * @private
    */
-  onDismissClickHandler_(event) {
+  onDismissClickHandler_(event, dismissedForeverEventSource) {
     this.dispatchEvent(new CustomEvent(Banner.Event.BANNER_DISMISSED_FOREVER, {
       bubbles: true,
       composed: true,
-      detail: {banner: this.getBannerInstance_()},
+      detail: {
+        banner: this.getBannerInstance_(),
+        eventSource: dismissedForeverEventSource,
+      },
     }));
   }
 }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/google_one_offer_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/google_one_offer_banner.html
new file mode 100644
index 0000000..a58bfc9
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/google_one_offer_banner.html
@@ -0,0 +1,11 @@
+<style>
+    educational-banner {
+        --feature-icon-bg: url(/foreground/images/files/ui/drive_logo.svg);
+    }
+</style>
+<educational-banner>
+    <!-- Google One Offer banner is enabled only for en-*. It will be configured by the server. -->
+    <span slot="title">Get 100GB of Google Drive cloud storage</span>
+    <span slot="subtitle">Your Chromebook comes with 100GB of cloud storage free of charge for 12 months. All files saved in this folder will be backed up online automatically.</span>
+    <cr-button slot="extra-button" href="https://www.google.com/chromebook/perks/?id=google.one.2019" dismiss-banner-when-clicked>Get storage</cr-button>
+</educational-banner>
\ No newline at end of file
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/google_one_offer_banner.js b/ui/file_manager/file_manager/foreground/js/ui/banners/google_one_offer_banner.js
new file mode 100644
index 0000000..9d8af7bb
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/google_one_offer_banner.js
@@ -0,0 +1,107 @@
+// 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 {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {metrics} from '../../../../common/js/metrics.js';
+import {VolumeManagerCommon} from '../../../../common/js/volume_manager_types.js';
+import {Banner} from '../../../../externs/banner.js';
+
+import {EducationalBanner} from './educational_banner.js';
+
+/**
+ * The custom element tag name.
+ * @type {string}
+ */
+export const TAG_NAME = 'google-one-offer-banner';
+
+/** @const {!HTMLTemplateElement} */
+const htmlTemplate = html`{__html_template__}`;
+
+/**
+ * GoogleOneOfferBanner shows when the user navigates to the Google Drive
+ * volume. This banner will be shown instead of DriveWelcomeBanner if
+ * GoogleOneOfferFilesBanner flag is on.
+ */
+export class GoogleOneOfferBanner extends EducationalBanner {
+  /**
+   * Returns the HTML template for the Google One offer educational banner.
+   * @returns {!Node}
+   */
+  getTemplate() {
+    return htmlTemplate.content.cloneNode(true);
+  }
+
+  /**
+   * Only show the banner when the user has navigated to the Drive volume type.
+   * @returns {!Array<!Banner.AllowedVolume>}
+   */
+  allowedVolumes() {
+    return [{
+      type: VolumeManagerCommon.VolumeType.DRIVE,
+      root: VolumeManagerCommon.RootType.DRIVE,
+    }];
+  }
+
+  /**
+   * Called when the banner gets connected to the DOM.
+   */
+  connectedCallback() {
+    const getPerkButton =
+        this.shadowRoot.querySelector('[slot="extra-button"]');
+    if (getPerkButton) {
+      getPerkButton.addEventListener(
+          'click', event => this.onGetPerkButtonClickHandler_());
+    }
+
+    this.addEventListener(
+        Banner.Event.BANNER_DISMISSED_FOREVER,
+        event => this.onBannerDismissedForever_(
+            /** @type {!CustomEvent} */ (event)));
+  }
+
+  /**
+   * Called when the banner gets shown in the UI.
+   */
+  onShow() {
+    metrics.recordUserAction(GoogleOneOfferBanner.UserActions.SHOWN);
+  }
+
+  /**
+   * Called when the get perk button gets clicked.
+   */
+  onGetPerkButtonClickHandler_() {
+    metrics.recordUserAction(GoogleOneOfferBanner.UserActions.GET_PERK);
+  }
+
+  /**
+   * Called when DismissedForeverEvent gets dispatched for this banner. Note
+   * that the event can gets dispatched for dismiss caused by a click of get
+   * perk button.
+   * @param {!CustomEvent} event
+   */
+  onBannerDismissedForever_(event) {
+    // UserActions.DISMISS should not be recorded for dismiss caused by a click
+    // of the get perk button.
+    if (event.detail.eventSource ===
+        Banner.DismissedForeverEventSource.EXTRA_BUTTON) {
+      return;
+    }
+
+    metrics.recordUserAction(GoogleOneOfferBanner.UserActions.DISMISS);
+  }
+}
+
+/**
+ * User actions of GoogleOneOfferBanner.
+ * @enum {string}
+ * @const
+ */
+GoogleOneOfferBanner.UserActions = {
+  SHOWN: 'GoogleOneOffer.Shown',
+  GET_PERK: 'GoogleOneOffer.GetPerk',
+  DISMISS: 'GoogleOneOffer.Dismiss',
+};
+
+customElements.define(TAG_NAME, GoogleOneOfferBanner);
\ No newline at end of file
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni
index 367d775..de8e6a92 100644
--- a/ui/file_manager/file_names.gni
+++ b/ui/file_manager/file_names.gni
@@ -399,6 +399,7 @@
   "file_manager/foreground/js/ui/banners/drive_out_of_organization_space_banner.js",
   "file_manager/foreground/js/ui/banners/drive_offline_pinning_banner.js",
   "file_manager/foreground/js/ui/banners/drive_welcome_banner.js",
+  "file_manager/foreground/js/ui/banners/google_one_offer_banner.js",
   "file_manager/foreground/js/ui/banners/educational_banner.js",
   "file_manager/foreground/js/ui/banners/holding_space_welcome_banner.js",
   "file_manager/foreground/js/ui/banners/invalid_usb_filesystem_banner.js",
diff --git a/ui/file_manager/integration_tests/file_manager/drive_specific.js b/ui/file_manager/integration_tests/file_manager/drive_specific.js
index c0ab04f..573e3d6 100644
--- a/ui/file_manager/integration_tests/file_manager/drive_specific.js
+++ b/ui/file_manager/integration_tests/file_manager/drive_specific.js
@@ -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 {ENTRIES, EntryType, getCaller, pending, repeatUntil, RootPath, sendTestMessage, TestEntryInfo} from '../test_util.js';
+import {ENTRIES, EntryType, expectHistogramTotalCount, getCaller, getUserActionCount, pending, repeatUntil, RootPath, sendTestMessage, TestEntryInfo} from '../test_util.js';
 import {testcase} from '../testcase.js';
 
 import {navigateWithDirectoryTree, remoteCall, setupAndWaitUntilReady, waitForMediaApp} from './background.js';
@@ -1197,3 +1197,72 @@
   // Wait for completion of file deletion.
   await remoteCall.waitForElementLost(appId, helloTxtSelector);
 };
+
+/**
+ * Tests that Google One offer banner appears if a user navigates to Drive
+ * volume.
+ */
+testcase.driveGoogleOneOfferBannerEnabled = async () => {
+  const userActionShown = 'FileBrowser.GoogleOneOffer.Shown';
+  const userActionGetPerk = 'FileBrowser.GoogleOneOffer.GetPerk';
+  const userActionDismiss = 'FileBrowser.GoogleOneOffer.Dismiss';
+
+  const appId = await setupAndWaitUntilReady(RootPath.DRIVE);
+
+  // Visibility of a banner is controlled with hidden attribute once it gets
+  // attached to the DOM.
+  await remoteCall.waitForElement(
+      appId, 'google-one-offer-banner:not([hidden])');
+  chrome.test.assertEq(1, await getUserActionCount(userActionShown));
+
+  // extra-button (get perk button) is provided by google-one-offer-banner.
+  await remoteCall.waitAndClickElement(
+      appId, ['google-one-offer-banner', '[slot="extra-button"]']);
+  chrome.test.assertEq(1, await getUserActionCount(userActionGetPerk));
+  // Check: dismiss event should not be recorded for dismiss caused by the get
+  // perk button click.
+  chrome.test.assertEq(0, await getUserActionCount(userActionDismiss));
+  await remoteCall.waitForLastOpenedBrowserTabUrl(
+      'https://www.google.com/chromebook/perks/?id=google.one.2019');
+  await remoteCall.waitForElement(appId, 'google-one-offer-banner[hidden]');
+  // Check: If Google One offer banner is shown, Drive welcome banner should not
+  // be shown. Holding space welcome banner is the next one after the Drive
+  // welcome banner.
+  await remoteCall.waitForElement(
+      appId, 'holding-space-welcome-banner:not([hidden])');
+};
+
+/**
+ * Tests that Google One offer banner does not appear if the flag is off, which
+ * is the default.
+ */
+testcase.driveGoogleOneOfferBannerDisabled = async () => {
+  const appId = await setupAndWaitUntilReady(RootPath.DRIVE);
+
+  // If Google One offer banner is not shown, Drive welcome banner should be
+  // shown. We cannot test google-one-offer-banner[hidden] here as it should not
+  // be in the DOM tree.
+  await remoteCall.waitForElement(appId, 'drive-welcome-banner:not([hidden])');
+};
+
+/**
+ * Test that Google One offer banner can get dismissed with a click of Dismiss
+ * button.
+ */
+testcase.driveGoogleOneOfferBannerDismiss = async () => {
+  const userActionDismiss = 'FileBrowser.GoogleOneOffer.Dismiss';
+
+  const appId = await setupAndWaitUntilReady(RootPath.DRIVE);
+
+  // Visibility of a banner is controlled with hidden attribute once it gets
+  // attached to the DOM.
+  await remoteCall.waitForElement(
+      appId, 'google-one-offer-banner:not([hidden])');
+
+  // dismiss-button is provided by educational-banner.
+  await remoteCall.waitAndClickElement(
+      appId,
+      ['google-one-offer-banner', 'educational-banner', '#dismiss-button']);
+  chrome.test.assertEq(1, await getUserActionCount(userActionDismiss));
+  await remoteCall.waitForElement(appId, 'google-one-offer-banner[hidden]');
+};
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h
index 0f3939d8..2759b56 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -129,6 +129,9 @@
   }
   xdg_wm_base* shell() const { return shell_.get(); }
   wp_presentation* presentation() const { return presentation_.get(); }
+  zcr_keyboard_extension_v1* keyboard_extension_v1() const {
+    return keyboard_extension_v1_.get();
+  }
   zwp_keyboard_shortcuts_inhibit_manager_v1*
   keyboard_shortcuts_inhibit_manager_v1() const {
     return keyboard_shortcuts_inhibit_manager_v1_.get();
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
index 204a01b..5d95f544 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -727,14 +727,16 @@
   apply_state_immediately_ = true;
 }
 
-void WaylandSurface::InhibitKeyboardShortcuts() {
-  if (auto* keyboard_shortcuts_inhibit_manager =
-          connection_->keyboard_shortcuts_inhibit_manager_v1()) {
+void WaylandSurface::SetKeyboardShortcutsInhibition(bool enabled) {
+  if (!enabled) {
+    keyboard_shortcuts_inhibitor_.reset();
+    return;
+  }
+  if (auto* manager = connection_->keyboard_shortcuts_inhibit_manager_v1()) {
     keyboard_shortcuts_inhibitor_ =
         wl::Object<zwp_keyboard_shortcuts_inhibitor_v1>(
             zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(
-                keyboard_shortcuts_inhibit_manager, surface_.get(),
-                connection_->seat()->wl_object()));
+                manager, surface_.get(), connection_->seat()->wl_object()));
   }
 }
 
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h
index 0f00196..1193fd98 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -216,9 +216,10 @@
   // effect immediately.
   void ForceImmediateStateApplication();
 
-  // Requests to wayland compositor to send key events even if it matches
-  // with the compositor's accelerator keys.
-  void InhibitKeyboardShortcuts();
+  // Asks the Wayland compositor to enable or disable the keyboard shortcuts
+  // inhibition for this surface. i.e: to receive key events even if they match
+  // compositor accelerators, e.g: Alt+Tab, etc.
+  void SetKeyboardShortcutsInhibition(bool enabled);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(WaylandWindowTest,
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
index 80296b4..8ff55562 100644
--- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -489,9 +489,19 @@
   // Thus, we must store previous bounds to restore later.
   SetOrResetRestoredBounds();
 
-  if (old_state != state_ && !did_send_delegate_notification) {
-    previous_state_ = old_state;
-    delegate()->OnWindowStateChanged(previous_state_, state_);
+  if (old_state != state_) {
+    if (!did_send_delegate_notification) {
+      previous_state_ = old_state;
+      delegate()->OnWindowStateChanged(previous_state_, state_);
+    }
+
+    if (keyboard_shortcuts_inhibition_mode() ==
+            KeyboardShortcutsInhibitionMode::kFullscreenOnly &&
+        (state_ == PlatformWindowState::kFullScreen ||
+         old_state == PlatformWindowState::kFullScreen)) {
+      root_surface()->SetKeyboardShortcutsInhibition(
+          state_ == PlatformWindowState::kFullScreen);
+    }
   }
 
   if (did_active_change)
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index 068537e..b9901c9 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -655,10 +655,6 @@
     return false;
   }
 
-  if (properties.inhibit_keyboard_shortcuts) {
-    root_surface_->InhibitKeyboardShortcuts();
-  }
-
   State state;
   state.bounds_dip = properties.bounds;
   // Properties contain DIP bounds but the buffer scale is initially 1 so it's
@@ -669,6 +665,10 @@
   opacity_ = properties.opacity;
   type_ = properties.type;
 
+  if (properties.inhibit_keyboard_shortcuts) {
+    InitKeyboardShortcutsInhibition();
+  }
+
   connection_->window_manager()->AddWindow(GetWidget(), this);
 
   if (!OnInitialize(std::move(properties), &state)) {
@@ -699,6 +699,40 @@
   return true;
 }
 
+// When upper layer requests to 'inhibit keyboard shortcuts', two different
+// behaviors are currently implemented:
+//
+// 1. If `zcr_keyboard_extension_v1` extension is available (typically meaning
+// it is running under Exo compositor), shortcuts are kept inhibited since the
+// window initialization. That is required to keep Lacros behaving just like
+// Ash Chrome's classic browser.
+//
+// 2. Otherwise, keyboard shortcuts will be inhibited only when in fullscreen.
+// See KeyboardLock spec for more details: https://wicg.github.io/keyboard-lock
+//
+// The main technical difference here is that keyboard-extension-v1 extension
+// allows ozone/wayland to report back to the Wayland compositor that a given
+// key was not processed by the client, giving it a chance of processing global
+// shortcuts (even with a shortcuts inhibitor in place), which is not currently
+// possible with standard Wayland protocol and extensions.
+//
+// TODO(crbug.com/1338554): Revisit and update when/if this scenario changes.
+void WaylandWindow::InitKeyboardShortcutsInhibition() {
+  DCHECK_EQ(keyboard_shortcuts_inhibition_mode_,
+            KeyboardShortcutsInhibitionMode::kDisabled);
+  if (!connection_->keyboard_extension_v1()) {
+    // Only set inhibition mode to kFullscreenOnly and defer the actual handling
+    // to the subsequent shell surface configure events, where window state is
+    // applied/updated. See WaylandToplevelWindow::HandleAuraToplevelConfigure.
+    keyboard_shortcuts_inhibition_mode_ =
+        KeyboardShortcutsInhibitionMode::kFullscreenOnly;
+    return;
+  }
+  keyboard_shortcuts_inhibition_mode_ =
+      KeyboardShortcutsInhibitionMode::kAlwaysEnabled;
+  root_surface()->SetKeyboardShortcutsInhibition(/*enabled=*/true);
+}
+
 void WaylandWindow::SetWindowGeometry(gfx::Size size_dip) {}
 
 gfx::Vector2d WaylandWindow::GetWindowGeometryOffsetInDIP() const {
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 3031056..ab9e386fea 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -362,6 +362,12 @@
 #endif
 
  protected:
+  enum class KeyboardShortcutsInhibitionMode {
+    kDisabled,
+    kAlwaysEnabled,
+    kFullscreenOnly
+  };
+
   WaylandWindow(PlatformWindowDelegate* delegate,
                 WaylandConnection* connection);
 
@@ -397,6 +403,10 @@
 
   const gfx::Size& restored_size_dip() const { return restored_size_dip_; }
 
+  KeyboardShortcutsInhibitionMode keyboard_shortcuts_inhibition_mode() const {
+    return keyboard_shortcuts_inhibition_mode_;
+  }
+
   // Configure related:
 
   // Processes the currently pending State. This may generate a new in-flight
@@ -465,6 +475,10 @@
   virtual bool OnInitialize(PlatformWindowInitProperties properties,
                             State* state) = 0;
 
+  // Determines which keyboard shortcuts inhibition mode to be used and perform
+  // required initialization steps, if any.
+  void InitKeyboardShortcutsInhibition();
+
   // WaylandWindowDragController might need to take ownership of the wayland
   // surface whether the window that originated the DND session gets destroyed
   // in the middle of that session (e.g: when it is snapped into a tab strip).
@@ -632,6 +646,9 @@
 
   base::OnceClosure drag_loop_quit_closure_;
 
+  KeyboardShortcutsInhibitionMode keyboard_shortcuts_inhibition_mode_{
+      KeyboardShortcutsInhibitionMode::kDisabled};
+
 #if DCHECK_IS_ON()
   bool disable_null_target_dcheck_for_test_ = false;
 #endif