diff --git a/DEPS b/DEPS
index 1ed31a1..8ea0118 100644
--- a/DEPS
+++ b/DEPS
@@ -314,15 +314,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': 'eff8446c42f8a260eae298c67322cce684ec9669',
+  'skia_revision': 'aa208c8a2d60b087ef74d35737b037cfe85a4fc4',
   # 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': 'ad0956c177c9a6990e78dc061c9b8d83a6320b1a',
+  'v8_revision': '40cb2f6d823b5dc2c8a5e920574932cce2ea7af1',
   # 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': '27836f2181738a69543f657898f4cd6994c4c4d7',
+  'angle_revision': '823de3a30c4fccae5f67aa99f4ee9f4847e3b2e3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -385,7 +385,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': '19ad1237e35315125d897f6f438b3cd2798fc133',
+  'catapult_revision': 'e8ae187c6dbdb2de0c4c673307c1c259ef6eb0e8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
@@ -445,11 +445,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '1244719685f0df31ffecea8cad822540cc9d96bf',
+  'dawn_revision': '092f3f12f369fe3d894f17bca1e9ed40a98bf3f5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': 'ed310679f2d91e0908e9f898ac4995d1e1eb0102',
+  'quiche_revision': 'ba658fc677a78c2515fd1851526be5bea8fc74c4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -837,12 +837,12 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'ce4f375bbbfa4e53c4a7aee65f0025ca475a2064',
+    '446cc4c9eea2d0582c8e0900c4a73e4b9a38d1dc',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '4816910e134254e7155c90dcbf9f5055ce8b4099',
+    'url': Var('chromium_git') + '/website.git' + '@' + '27038fe25a6108105f3d923d11044574152f901e',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -1032,7 +1032,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'QMx7KoZ2HCGl36cSVOPb3d3ye56TrMPDi4RwOdTA7UQC',
+          'version': '0jZE2CS4pOwZI_V9z1wPVlX8BC0SZAJW7Q8EqaMtObsC',
       },
     ],
     'condition': 'checkout_android',
@@ -1276,7 +1276,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2c3875ea1c41b98c8e5467bb7a56d27c97f30ae8',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'a1cfc693af3505461fea2a59eaf484720c897c4f',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index f38b6a2..11ffa2ea 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -4013,6 +4013,8 @@
     "//ash/public/cpp",
     "//ash/public/cpp:test_support",
     "//base/test:test_support",
+    "//chromeos/ash/components/audio",
+    "//chromeos/ash/components/dbus/audio",
     "//chromeos/ash/services/assistant/public/cpp",
     "//chromeos/ash/services/bluetooth_config:test_support",
     "//chromeos/dbus/power:power",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index cef8a568..b3fa78c 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2519,17 +2519,14 @@
         Last desk can't be removed.
       </message>
       <message name="IDS_ASH_DESKS_ACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP" desc="The accessibility tooltip read by screen readers for a highlighted active desk mini_view.">
-        active desk
+        Active desk.
       </message>
       <message name="IDS_ASH_DESKS_INACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP" desc="The accessibility tooltip read by screen readers for a highlighted inactive desk mini_view.">
-        inactive desk
+        Inactive desk.
       </message>
       <message name="IDS_ASH_DESKS_DESK_ACCESSIBLE_NAME" desc="The full accessible desk name">
         Desk: <ph name="DESK_NAME">$1</ph>
       </message>
-      <message name="IDS_ASH_DESKS_DESK_PREVIEW_A11Y_NAME" desc="The full accessible desk name">
-        Go to <ph name="ACTIVE_STATE">$1</ph> <ph name="DESK_NAME">$2</ph> button.
-      </message>
       <message name="IDS_ASH_DESKS_DESK_NAME_COMMIT" desc="Alert when the desk name is committed">
         Desk name was changed to <ph name="DESK_NAME">$1</ph>
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_ACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_ACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP.png.sha1
deleted file mode 100644
index b9e56f1..0000000
--- a/ash/ash_strings_grd/IDS_ASH_DESKS_ACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-f0ab6cae002646d549b453d8462bb660fa4f46b2
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_PREVIEW_A11Y_NAME.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_PREVIEW_A11Y_NAME.png.sha1
deleted file mode 100644
index 9b94ed2..0000000
--- a/ash/ash_strings_grd/IDS_ASH_DESKS_DESK_PREVIEW_A11Y_NAME.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-828c0f8080f2886b58e92b5ce5de44366924f884
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_INACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_INACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP.png.sha1
index c61e9381..13f2b42 100644
--- a/ash/ash_strings_grd/IDS_ASH_DESKS_INACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP.png.sha1
+++ b/ash/ash_strings_grd/IDS_ASH_DESKS_INACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP.png.sha1
@@ -1 +1 @@
-052eae4fae5a6f4cfec48cce64759f0a3e615d7d
\ No newline at end of file
+c0011f1a7d59d0e49a62cc6be9fe822a6a1cd403
\ No newline at end of file
diff --git a/ash/components/arc/chrome_feature_flags/arc_chrome_feature_flags_bridge.cc b/ash/components/arc/chrome_feature_flags/arc_chrome_feature_flags_bridge.cc
index 181a2b1..e54831d8 100644
--- a/ash/components/arc/chrome_feature_flags/arc_chrome_feature_flags_bridge.cc
+++ b/ash/components/arc/chrome_feature_flags/arc_chrome_feature_flags_bridge.cc
@@ -91,6 +91,7 @@
           : mojom::RoundedWindowCompatStrategy::kDisabled;
   flags->rounded_window_radius = chromeos::features::RoundedWindowsRadius();
   flags->xdg_mode = base::FeatureList::IsEnabled(kXdgMode);
+  flags->enable_pip_double_tap = ash::features::IsPipDoubleTapToResizeEnabled();
 
   chrome_feature_flags_instance->NotifyFeatureFlags(std::move(flags));
 }
diff --git a/ash/components/arc/chrome_feature_flags/arc_chrome_feature_flags_bridge_unittest.cc b/ash/components/arc/chrome_feature_flags/arc_chrome_feature_flags_bridge_unittest.cc
index 6f20f8f..b71cbc5 100644
--- a/ash/components/arc/chrome_feature_flags/arc_chrome_feature_flags_bridge_unittest.cc
+++ b/ash/components/arc/chrome_feature_flags/arc_chrome_feature_flags_bridge_unittest.cc
@@ -184,5 +184,19 @@
   EXPECT_FALSE(instance()->flags_called_value()->xdg_mode);
 }
 
+TEST_F(ArcChromeFeatureFlagsBridgeTest, NotifyPipDoubleTapToResize_Enabled) {
+  scoped_feature_list()->InitAndEnableFeature(
+      ash::features::kPipDoubleTapToResize);
+  Connect();
+  EXPECT_TRUE(instance()->flags_called_value()->enable_pip_double_tap);
+}
+
+TEST_F(ArcChromeFeatureFlagsBridgeTest, NotifyPipDoubleTapToResize_Disabled) {
+  scoped_feature_list()->InitAndDisableFeature(
+      ash::features::kPipDoubleTapToResize);
+  Connect();
+  EXPECT_FALSE(instance()->flags_called_value()->enable_pip_double_tap);
+}
+
 }  // namespace
 }  // namespace arc
diff --git a/ash/components/arc/mojom/chrome_feature_flags.mojom b/ash/components/arc/mojom/chrome_feature_flags.mojom
index bd292045..ab47ab88 100644
--- a/ash/components/arc/mojom/chrome_feature_flags.mojom
+++ b/ash/components/arc/mojom/chrome_feature_flags.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 5
+// Next MinVersion: 6
 
 module arc.mojom;
 
@@ -31,6 +31,8 @@
   [MinVersion=3] int32 rounded_window_radius;
   // chrome://flags#arc-xdg-mode
   [MinVersion=4] bool xdg_mode;
+  // chrome://flags#enable-pip-double-tap-to-resize;
+  [MinVersion=5] bool enable_pip_double_tap;
 };
 
 // This interface provides methods to propagate the feature flag status to
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 8b32c0c4..9e6c8fe 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -2230,11 +2230,6 @@
              "ScreenSaverDuration",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enables the "Preview" button for screensaver.
-BASE_FEATURE(kScreenSaverPreview,
-             "ScreenSaverPreview",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Enables the system tray to show more information in larger screen.
 BASE_FEATURE(kSeamlessRefreshRateSwitching,
              "SeamlessRefreshRateSwitching",
@@ -3337,10 +3332,6 @@
   return base::FeatureList::IsEnabled(kScreenSaverDuration);
 }
 
-bool IsScreenSaverPreviewEnabled() {
-  return base::FeatureList::IsEnabled(kScreenSaverPreview);
-}
-
 bool IsSnoopingProtectionEnabled() {
   return base::FeatureList::IsEnabled(kSnoopingProtection) &&
          switches::HasHps();
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 79d824c9..1c18609 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -665,7 +665,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kScalableIph);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kScanningAppJelly);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kScreenSaverDuration);
-COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kScreenSaverPreview);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kSeamlessRefreshRateSwitching);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSeparateNetworkIcons);
@@ -1077,7 +1076,6 @@
 bool IsSamlNotificationOnPasswordChangeSuccessEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsScalableIphEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsScreenSaverDurationEnabled();
-COMPONENT_EXPORT(ASH_CONSTANTS) bool IsScreenSaverPreviewEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsSeparateNetworkIconsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsSettingsAppNotificationSettingsEnabled();
diff --git a/ash/constants/ash_switches.cc b/ash/constants/ash_switches.cc
index e86ffae..d39e66d 100644
--- a/ash/constants/ash_switches.cc
+++ b/ash/constants/ash_switches.cc
@@ -337,6 +337,10 @@
 // file).
 const char kDefaultWallpaperSmall[] = "default-wallpaper-small";
 
+// Interval in seconds to wait for a display to reconnect while unlocking or
+// logging in with a closed lid.
+const char kDeferExternalDisplayTimeout[] = "defer-external-display-timeout";
+
 // Test Organization Unit (OU) user to use for demo mode. Only pass the part
 // before "@cros-demo-mode.com".
 const char kDemoModeEnrollingUsername[] = "demo-mode-enrolling-username";
diff --git a/ash/constants/ash_switches.h b/ash/constants/ash_switches.h
index d03ba30ce..b45a7c5 100644
--- a/ash/constants/ash_switches.h
+++ b/ash/constants/ash_switches.h
@@ -107,6 +107,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kDefaultWallpaperLarge[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kDefaultWallpaperSmall[];
 COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const char kDeferExternalDisplayTimeout[];
+COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const char kDemoModeEnrollingUsername[];
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const char kDemoModeForceArcOfflineProvision[];
diff --git a/ash/fast_ink/cursor/cursor_view.cc b/ash/fast_ink/cursor/cursor_view.cc
index 03634539..949db6e 100644
--- a/ash/fast_ink/cursor/cursor_view.cc
+++ b/ash/fast_ink/cursor/cursor_view.cc
@@ -399,11 +399,8 @@
                        bool is_motion_blur_enabled)
     : painter_(std::make_unique<Painter>(this,
                                          initial_location,
-                                         is_motion_blur_enabled)),
-      ui_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
+                                         is_motion_blur_enabled)) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
-
-  ui::CursorController::GetInstance()->AddCursorObserver(this);
 }
 
 CursorView::~CursorView() {
@@ -419,10 +416,17 @@
 views::UniqueWidgetPtr CursorView::Create(const gfx::Point& initial_location,
                                           bool is_motion_blur_enabled,
                                           aura::Window* container) {
-  return FastInkView::CreateWidgetWithContents(
-      base::WrapUnique(
-          new CursorView(initial_location, is_motion_blur_enabled)),
-      container);
+  CursorView* cursor_view =
+      new CursorView(initial_location, is_motion_blur_enabled);
+  auto widget = FastInkView::CreateWidgetWithContents(
+      base::WrapUnique(cursor_view), container);
+
+  // Initialize after FaskInkHost is set on `cursor_view` and it is attached to
+  // a widget. So that it could get `buffer_to_screen_transform_` and be able to
+  // initialize `painter_`.
+  cursor_view->Init();
+
+  return widget;
 }
 
 void CursorView::SetCursorImage(const gfx::ImageSkia& cursor_image,
@@ -437,20 +441,7 @@
 // ui::CursorController::CursorObserver overrides:
 
 void CursorView::OnCursorLocationChanged(const gfx::PointF& location) {
-  if (!buffer_to_screen_transform_) {
-    if (!ui_task_runner_->BelongsToCurrentThread()) {
-      // If it is not called from ui thread, post it to ui thread.
-      ui_task_runner_->PostTask(
-          FROM_HERE, base::BindOnce(&CursorView::OnCursorLocationChanged,
-                                    weak_ptr_factory_.GetWeakPtr(), location));
-      return;
-    }
-    // Create transform used to convert cursor controller coordinates to screen
-    // coordinates.
-    buffer_to_screen_transform_ =
-        this->host()->window_to_buffer_transform().GetCheckedInverse();
-  }
-  gfx::PointF new_location_f = buffer_to_screen_transform_->MapPoint(location);
+  gfx::PointF new_location_f = buffer_to_screen_transform_.MapPoint(location);
   gfx::Point new_location = gfx::ToRoundedPoint(new_location_f);
 
   painter_->SetCursorLocation(new_location);
@@ -465,15 +456,17 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// views::View overrides:
+// CursorView, private:
 
-void CursorView::AddedToWidget() {
+void CursorView::Init() {
+  buffer_to_screen_transform_ =
+      host()->window_to_buffer_transform().GetCheckedInverse();
+
   painter_->Init(base::BindRepeating(&CursorView::UpdateSurface,
                                      weak_ptr_factory_.GetWeakPtr()));
-}
 
-////////////////////////////////////////////////////////////////////////////////
-// CursorView, private:
+  ui::CursorController::GetInstance()->AddCursorObserver(this);
+}
 
 void CursorView::DidPresentCompositorFrame(
     const gfx::PresentationFeedback& feedback) {
diff --git a/ash/fast_ink/cursor/cursor_view.h b/ash/fast_ink/cursor/cursor_view.h
index 9341d1c..ed40c7a 100644
--- a/ash/fast_ink/cursor/cursor_view.h
+++ b/ash/fast_ink/cursor/cursor_view.h
@@ -47,26 +47,26 @@
   // ash::FastInkView overrides:
   FastInkHost::PresentationCallback GetPresentationCallback() override;
 
-  // views::View overrides:
-  void AddedToWidget() override;
-
  private:
   // Paints cursor on the paint thread.
   class Painter;
 
   CursorView(const gfx::Point& initial_location, bool is_motion_blur_enabled);
 
+  // Initialize CursorView after FaskInkHost is setup.
+  void Init();
+
+  // Invoked when a frame is presented.
   void DidPresentCompositorFrame(const gfx::PresentationFeedback& feedback);
 
   // Constants that can be used on any thread.
-  absl::optional<gfx::Transform> buffer_to_screen_transform_;
+  gfx::Transform buffer_to_screen_transform_;
 
   std::unique_ptr<Painter> painter_;
 
   // UI thread state.
   raw_ptr<ui::Compositor, ExperimentalAsh> compositor_ = nullptr;
   SEQUENCE_CHECKER(ui_sequence_checker_);
-  const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
   base::WeakPtrFactory<CursorView> weak_ptr_factory_{this};
 };
 
diff --git a/ash/system/audio/audio_detailed_view.cc b/ash/system/audio/audio_detailed_view.cc
index 0aaa156..240d3114 100644
--- a/ash/system/audio/audio_detailed_view.cc
+++ b/ash/system/audio/audio_detailed_view.cc
@@ -75,7 +75,7 @@
 constexpr auto kLiveCaptionContainerMargins = gfx::Insets::TLBR(0, 0, 8, 0);
 constexpr auto kToggleButtonRowLabelPadding = gfx::Insets::TLBR(16, 0, 15, 0);
 constexpr auto kToggleButtonRowViewPadding = gfx::Insets::TLBR(0, 56, 8, 0);
-constexpr auto kQsToggleButtonRowViewPadding = gfx::Insets::VH(0, 32);
+constexpr auto kQsToggleButtonRowViewPadding = gfx::Insets::TLBR(0, 32, 0, 24);
 constexpr auto kQsToggleButtonRowPreferredSize = gfx::Size(0, 32);
 constexpr auto kQsToggleButtonRowLabelPadding = gfx::Insets::VH(8, 12);
 constexpr auto kQsToggleButtonRowMargins = gfx::Insets::VH(4, 0);
diff --git a/ash/system/audio/audio_detailed_view_pixeltest.cc b/ash/system/audio/audio_detailed_view_pixeltest.cc
index 1dfefecc..4906b87 100644
--- a/ash/system/audio/audio_detailed_view_pixeltest.cc
+++ b/ash/system/audio/audio_detailed_view_pixeltest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <vector>
+
 #include "ash/constants/ash_features.h"
 #include "ash/system/tray/tray_detailed_view.h"
 #include "ash/system/unified/unified_system_tray.h"
@@ -10,12 +12,17 @@
 #include "ash/test/pixel/ash_pixel_differ.h"
 #include "ash/test/pixel/ash_pixel_test_init_params.h"
 #include "base/test/scoped_feature_list.h"
+#include "chromeos/ash/components/audio/cras_audio_handler.h"
+#include "chromeos/ash/components/dbus/audio/audio_node.h"
+#include "chromeos/ash/components/dbus/audio/fake_cras_audio_client.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
 
+constexpr uint64_t kInternalMicId = 10003;
+
 // Pixel tests for the quick settings audio detailed view.
 class AudioDetailedViewPixelTest : public AshTestBase {
  public:
@@ -52,4 +59,37 @@
       /*revision_number=*/6, detailed_view));
 }
 
+TEST_F(AudioDetailedViewPixelTest, ShowNoiseCancellationButton) {
+  // Setup for showing noise cancellation button.
+  auto* client = FakeCrasAudioClient::Get();
+  auto* audio_handler = CrasAudioHandler::Get();
+  auto internal_mic_node = AudioNode(
+      true, kInternalMicId, false, kInternalMicId, 0, "Fake Mic",
+      "INTERNAL_MIC", "Internal Mic", false /* is_active*/, 0 /* pluged_time */,
+      1, cras::EFFECT_TYPE_NOISE_CANCELLATION, 0);
+  AudioNodeList node_list;
+  node_list.push_back(internal_mic_node);
+  client->SetAudioNodesAndNotifyObserversForTesting(node_list);
+  client->SetNoiseCancellationSupported(true);
+  audio_handler->RequestNoiseCancellationSupported(base::DoNothing());
+  audio_handler->SwitchToDevice(AudioDevice(internal_mic_node), true,
+                                CrasAudioHandler::ACTIVATE_BY_USER);
+
+  UnifiedSystemTray* system_tray = GetPrimaryUnifiedSystemTray();
+  system_tray->ShowBubble();
+  ASSERT_TRUE(system_tray->bubble());
+
+  system_tray->bubble()
+      ->unified_system_tray_controller()
+      ->ShowAudioDetailedView();
+
+  TrayDetailedView* detailed_view =
+      system_tray->bubble()->quick_settings_view()->GetDetailedViewForTest();
+  ASSERT_TRUE(detailed_view);
+
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "qs_audio_detailed_view",
+      /*revision_number=*/0, detailed_view));
+}
+
 }  // namespace ash
diff --git a/ash/system/audio/audio_effects_controller.cc b/ash/system/audio/audio_effects_controller.cc
index abf16f9..2218ee9 100644
--- a/ash/system/audio/audio_effects_controller.cc
+++ b/ash/system/audio/audio_effects_controller.cc
@@ -139,6 +139,14 @@
 }
 
 void AudioEffectsController::OnActiveInputNodeChanged() {
+  RefreshNoiseCancellationSupported();
+}
+
+void AudioEffectsController::OnAudioNodesChanged() {
+  RefreshNoiseCancellationSupported();
+}
+
+void AudioEffectsController::RefreshNoiseCancellationSupported() {
   const bool noise_cancellation_supported = IsNoiseCancellationSupported();
 
   if (noise_cancellation_supported_ == noise_cancellation_supported) {
diff --git a/ash/system/audio/audio_effects_controller.h b/ash/system/audio/audio_effects_controller.h
index d37aa3e..d4d85ca8 100644
--- a/ash/system/audio/audio_effects_controller.h
+++ b/ash/system/audio/audio_effects_controller.h
@@ -44,6 +44,10 @@
  private:
   // CrasAudioHandler::AudioObserver:
   void OnActiveInputNodeChanged() override;
+  void OnAudioNodesChanged() override;
+
+  // Refresh noise cancellation supported status.
+  void RefreshNoiseCancellationSupported();
 
   // Construct effect for noise cancellation.
   void AddNoiseCancellationEffect();
@@ -62,4 +66,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_AUDIO_AUDIO_EFFECTS_CONTROLLER_H_
\ No newline at end of file
+#endif  // ASH_SYSTEM_AUDIO_AUDIO_EFFECTS_CONTROLLER_H_
diff --git a/ash/system/message_center/ash_message_popup_collection.cc b/ash/system/message_center/ash_message_popup_collection.cc
index 8b73fc4..cf37093 100644
--- a/ash/system/message_center/ash_message_popup_collection.cc
+++ b/ash/system/message_center/ash_message_popup_collection.cc
@@ -117,6 +117,8 @@
   DCHECK_GE(baseline_offset_, 0);
   if (baseline_offset_ != 0) {
     baseline_offset_ += message_center::kMarginBetweenPopups;
+
+    RecordPopupOnTopOfBubbleCount();
   }
 
   if (old_baseline_offset != baseline_offset_) {
@@ -517,4 +519,15 @@
   }
 }
 
+void AshMessagePopupCollection::RecordPopupOnTopOfBubbleCount() {
+  int popup_items_count = popup_items().size();
+  if (!features::IsNotifierCollisionEnabled() || popup_items_count == 0) {
+    return;
+  }
+
+  // Record the number of popups that are moved up.
+  base::UmaHistogramCounts100("Ash.NotificationPopup.OnTopOfBubbleCount",
+                              popup_items_count);
+}
+
 }  // namespace ash
diff --git a/ash/system/message_center/ash_message_popup_collection.h b/ash/system/message_center/ash_message_popup_collection.h
index dde7b8a..a12e2afd 100644
--- a/ash/system/message_center/ash_message_popup_collection.h
+++ b/ash/system/message_center/ash_message_popup_collection.h
@@ -170,6 +170,9 @@
   void UpdateExpandCollapseEnabledForPopups(bool shelf_bubble_open,
                                             int available_space_above_popups);
 
+  // Records the metric for the count of popups that are on top of a bubble.
+  void RecordPopupOnTopOfBubbleCount();
+
   absl::optional<display::ScopedDisplayObserver> display_observer_;
 
   raw_ptr<display::Screen, ExperimentalAsh> screen_;
diff --git a/ash/system/message_center/ash_message_popup_collection_unittest.cc b/ash/system/message_center/ash_message_popup_collection_unittest.cc
index 236d559..8184a3ec 100644
--- a/ash/system/message_center/ash_message_popup_collection_unittest.cc
+++ b/ash/system/message_center/ash_message_popup_collection_unittest.cc
@@ -35,6 +35,7 @@
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/command_line.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chromeos/ash/components/phonehub/fake_phone_hub_manager.h"
 #include "chromeos/ash/components/phonehub/feature_status.h"
@@ -992,6 +993,56 @@
   }
 }
 
+TEST_P(AshMessagePopupCollectionTest, AdjustBaselineHistogramRecorded) {
+  base::HistogramTester histogram_tester;
+  auto* unified_system_tray = GetPrimaryUnifiedSystemTray();
+  unified_system_tray->ShowBubble();
+
+  AddNotification();
+  auto* popup = GetLastPopUpAdded();
+
+  const std::string histogram_name = "Ash.NotificationPopup.OnTopOfBubbleCount";
+
+  if (!IsQsRevampEnabled()) {
+    EXPECT_FALSE(popup);
+    histogram_tester.ExpectBucketCount(histogram_name, 1, 0);
+    return;
+  }
+
+  ASSERT_TRUE(popup);
+
+  auto* bubble_view = unified_system_tray->bubble()->GetBubbleView();
+  auto* popup_collection = GetPrimaryPopupCollection();
+
+  if (IsNotifierCollisionEnabled()) {
+    // The added popup should appears on top of the tray bubble and histogram is
+    // recorded.
+    EXPECT_EQ(bubble_view->height() + message_center::kMarginBetweenPopups,
+              popup_collection->baseline_offset_for_test());
+    histogram_tester.ExpectBucketCount(histogram_name, 1, 1);
+  } else {
+    // The popup stays the same if the feature is disabled.
+    EXPECT_EQ(0, popup_collection->baseline_offset_for_test());
+    histogram_tester.ExpectBucketCount(histogram_name, 1, 0);
+  }
+
+  // Add another notification. Histogram should also be recorded with the
+  // correct bucket for 2 notifications.
+  AddNotification();
+  AnimateUntilIdle();
+
+  histogram_tester.ExpectBucketCount(histogram_name, 2,
+                                     IsNotifierCollisionEnabled() ? 1 : 0);
+
+  // Close and re-open the bubble. Histogram should be recorded again.
+  auto* bubble_widget = unified_system_tray->bubble()->GetBubbleWidget();
+  bubble_widget->CloseNow();
+  unified_system_tray->ShowBubble();
+
+  histogram_tester.ExpectBucketCount(histogram_name, 2,
+                                     IsNotifierCollisionEnabled() ? 2 : 0);
+}
+
 TEST_P(AshMessagePopupCollectionTest, NotificationAddedOnTrayBubbleOpen) {
   if (!IsQsRevampEnabled()) {
     return;
diff --git a/ash/system/power/power_event_observer.cc b/ash/system/power/power_event_observer.cc
index ada456fa..f094e82 100644
--- a/ash/system/power/power_event_observer.cc
+++ b/ash/system/power/power_event_observer.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_switches.h"
 #include "ash/display/projecting_observer.h"
 #include "ash/login_status.h"
 #include "ash/root_window_controller.h"
@@ -18,6 +19,7 @@
 #include "ash/wallpaper/views/wallpaper_widget_controller.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/lock_state_observer.h"
+#include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/scoped_multi_source_observation.h"
@@ -256,6 +258,19 @@
 
   if (Shell::Get()->session_controller()->CanLockScreen())
     lock_on_suspend_usage_ = std::make_unique<LockOnSuspendUsage>();
+
+  const std::string flag_value =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kDeferExternalDisplayTimeout);
+  if (!flag_value.empty()) {
+    int seconds = -1;
+    if (base::StringToInt(flag_value, &seconds) && seconds > 0) {
+      defer_external_display_timeout_s_ = seconds;
+    } else {
+      LOG(WARNING) << "Ignoring bad value \"" << flag_value << "\" in --"
+                   << switches::kDeferExternalDisplayTimeout;
+    }
+  }
 }
 
 PowerEventObserver::~PowerEventObserver() {
@@ -369,6 +384,11 @@
 }
 
 void PowerEventObserver::SetIsProjecting(bool is_projecting) {
+  // If we know we're projecting successfully, we no longer
+  // need to wait for external displays.
+  if (is_projecting) {
+    wait_for_external_display_timer_.Stop();
+  }
   MaybeLockOnLidClose(is_projecting);
 }
 
@@ -382,14 +402,15 @@
   if (lid_state_ == chromeos::PowerManagerClient::LidState::CLOSED &&
       lock_state_ == LockState::kUnlocked && !is_projecting &&
       controller->ShouldLockScreenAutomatically() &&
-      controller->CanLockScreen()) {
+      controller->CanLockScreen() &&
+      !wait_for_external_display_timer_.IsRunning()) {
     VLOG(1) << "Screen locked due to lid close";
     lock_state_ = LockState::kLocking;
     Shell::Get()->lock_state_controller()->LockWithoutAnimation();
   }
 }
 
-void PowerEventObserver::OnLoginStatusChanged(LoginStatus) {
+void PowerEventObserver::OnLoginStatusChanged(LoginStatus login_status) {
   VLOG(1) << "PowerEventObserver::OnLoginStatusChanged";
   // Bail if usage tracker is already created.
   if (lock_on_suspend_usage_)
@@ -398,6 +419,11 @@
   if (!ash::Shell::Get()->session_controller()->CanLockScreen())
     return;
   lock_on_suspend_usage_ = std::make_unique<LockOnSuspendUsage>();
+
+  if (login_status != LoginStatus::NOT_LOGGED_IN &&
+      login_status != LoginStatus::LOCKED) {
+    StartExternalDisplayTimer();
+  }
 }
 
 void PowerEventObserver::OnLockStateChanged(bool locked) {
@@ -432,6 +458,8 @@
       } else if (block_suspend_token_) {
         StopCompositingAndSuspendDisplays();
       }
+    } else {
+      StartExternalDisplayTimer();
     }
   }
   VLOG(1) << "PowerEventObserver::OnLockStateChanged finished, new lock_state="
@@ -484,4 +512,16 @@
     StopCompositingAndSuspendDisplays();
 }
 
+void PowerEventObserver::StartExternalDisplayTimer() {
+  // If the Lid is closed during a unlock/login, give a bit more time for
+  // displays to re-enumerate (as a result of a DisplayPort -> Thunderbolt mode
+  // switch).
+  if (lid_state_ == chromeos::PowerManagerClient::LidState::CLOSED &&
+      defer_external_display_timeout_s_ > 0) {
+    wait_for_external_display_timer_.Start(
+        FROM_HERE, base::Seconds(defer_external_display_timeout_s_),
+        base::DoNothing());
+  }
+}
+
 }  // namespace ash
diff --git a/ash/system/power/power_event_observer.h b/ash/system/power/power_event_observer.h
index 0a16a855..044cde61 100644
--- a/ash/system/power/power_event_observer.h
+++ b/ash/system/power/power_event_observer.h
@@ -11,6 +11,7 @@
 #include "ash/login_status.h"
 #include "ash/public/cpp/session/session_observer.h"
 #include "base/compiler_specific.h"
+#include "base/timer/timer.h"
 #include "base/unguessable_token.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 
@@ -116,6 +117,9 @@
   // can be stopped for all root windows when device suspends.
   void OnCompositorsReadyForSuspend();
 
+  // Starts |wait_for_external_display_timer_|.
+  void StartExternalDisplayTimer();
+
   LockState lock_state_ = LockState::kUnlocked;
   chromeos::PowerManagerClient::LidState lid_state_ =
       chromeos::PowerManagerClient::LidState::OPEN;
@@ -139,6 +143,11 @@
 
   std::unique_ptr<LockOnSuspendUsage> lock_on_suspend_usage_;
 
+  // Amount of time (in seconds) to wait for external displays when a display
+  // mode change occurs and the lid is closed.
+  int defer_external_display_timeout_s_ = 0;
+  base::OneShotTimer wait_for_external_display_timer_;
+
   base::WeakPtrFactory<PowerEventObserver> weak_factory_{this};
 };
 
diff --git a/ash/system/unified/date_tray.h b/ash/system/unified/date_tray.h
index acee21e..db66847 100644
--- a/ash/system/unified/date_tray.h
+++ b/ash/system/unified/date_tray.h
@@ -65,6 +65,7 @@
  private:
   friend class DateTrayTest;
   friend class GlanceablesPixelTest;
+  friend class GlanceablesV2BrowserTest;
 
   // Owned by the views hierarchy.
   raw_ptr<TimeTrayItemView, ExperimentalAsh> time_view_ = nullptr;
diff --git a/ash/webui/personalization_app/personalization_app_ui.cc b/ash/webui/personalization_app/personalization_app_ui.cc
index feab0370..66c9ddf 100644
--- a/ash/webui/personalization_app/personalization_app_ui.cc
+++ b/ash/webui/personalization_app/personalization_app_ui.cc
@@ -486,9 +486,6 @@
   source->AddBoolean("isScreenSaverDurationEnabled",
                      features::IsScreenSaverDurationEnabled());
 
-  source->AddBoolean("isScreenSaverPreviewEnabled",
-                     features::IsScreenSaverPreviewEnabled());
-
   source->AddBoolean("isPersonalizationJellyEnabled",
                      features::IsPersonalizationJellyEnabled());
 
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.html b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.html
index 1808543..0697697d 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.html
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.html
@@ -126,7 +126,7 @@
             [[getAlbumDescription_(topicSource_, previewAlbums_)]]
           </span>
         </h3>
-        <div id="buttonContainer" hidden$="[[!isScreenSaverPreviewEnabled_]]">
+        <div id="buttonContainer">
           <cr-button
               class$="[[getScreenSaverPreviewClass_(ambientUiVisibility_)]]"
               aria-label$="[[getScreenSaverPreviewAriaLabel_(ambientUiVisibility_)]]"
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.ts
index e906df0c..2c325c0 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.ts
@@ -18,7 +18,7 @@
 import {assert} from 'chrome://resources/js/assert_ts.js';
 
 import {AmbientUiVisibility} from '../../personalization_app.mojom-webui.js';
-import {isAmbientModeAllowed, isScreenSaverPreviewEnabled} from '../load_time_booleans.js';
+import {isAmbientModeAllowed} from '../load_time_booleans.js';
 
 import {startScreenSaverPreview} from './ambient_controller.js';
 import {getAmbientProvider} from './ambient_interface_provider.js';
@@ -50,18 +50,11 @@
         type: Number,
         value: null,
       },
-      isScreenSaverPreviewEnabled_: {
-        type: Boolean,
-        value() {
-          return isScreenSaverPreviewEnabled();
-        },
-      },
     };
   }
 
   private screenSaverPreviewActive_: boolean;
   private ambientUiVisibility_: AmbientUiVisibility|null;
-  private isScreenSaverPreviewEnabled_: boolean;
 
   override connectedCallback() {
     assert(
diff --git a/ash/webui/personalization_app/resources/js/load_time_booleans.ts b/ash/webui/personalization_app/resources/js/load_time_booleans.ts
index 17f7e83d3..c3a4ef8 100644
--- a/ash/webui/personalization_app/resources/js/load_time_booleans.ts
+++ b/ash/webui/personalization_app/resources/js/load_time_booleans.ts
@@ -31,10 +31,6 @@
   return loadTimeData.getBoolean('isScreenSaverDurationEnabled');
 }
 
-export function isScreenSaverPreviewEnabled() {
-  return loadTimeData.getBoolean('isScreenSaverPreviewEnabled');
-}
-
 export function isPersonalizationJellyEnabled() {
   return loadTimeData.getBoolean('isPersonalizationJellyEnabled');
 }
diff --git a/ash/wm/desks/desk_mini_view.cc b/ash/wm/desks/desk_mini_view.cc
index f1dd6c5..3f23410 100644
--- a/ash/wm/desks/desk_mini_view.cc
+++ b/ash/wm/desks/desk_mini_view.cc
@@ -505,6 +505,39 @@
                        desk_name_view_->GetPreferredSize().height()};
 }
 
+void DeskMiniView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  desk_preview_->GetAccessibleNodeData(node_data);
+
+  // Note that the desk may have already been destroyed.
+  if (desk_) {
+    // Announce desk name.
+    node_data->AddStringAttribute(
+        ax::mojom::StringAttribute::kName,
+        l10n_util::GetStringFUTF8(IDS_ASH_DESKS_DESK_ACCESSIBLE_NAME,
+                                  desk_->name()));
+
+    node_data->AddStringAttribute(
+        ax::mojom::StringAttribute::kValue,
+        l10n_util::GetStringUTF8(
+            desk_->is_active()
+                ? IDS_ASH_DESKS_ACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP
+                : IDS_ASH_DESKS_INACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP));
+  }
+
+  // If the desk can be combined or closed, add a tip to let the user know they
+  // can use an accelerator.
+  if (!DesksController::Get()->CanRemoveDesks())
+    return;
+
+  const std::u16string target_desk_name =
+      DesksController::Get()->GetCombineDesksTargetName(desk_);
+  const std::string extra_tip = l10n_util::GetStringFUTF8(
+      IDS_ASH_OVERVIEW_CLOSABLE_DESK_MINIVIEW_A11Y_EXTRA_TIP, target_desk_name);
+
+  node_data->AddStringAttribute(ax::mojom::StringAttribute::kDescription,
+                                extra_tip);
+}
+
 void DeskMiniView::OnThemeChanged() {
   views::View::OnThemeChanged();
   UpdateFocusColor();
diff --git a/ash/wm/desks/desk_mini_view.h b/ash/wm/desks/desk_mini_view.h
index 652a4f5..a7d58aaa 100644
--- a/ash/wm/desks/desk_mini_view.h
+++ b/ash/wm/desks/desk_mini_view.h
@@ -138,6 +138,7 @@
   const char* GetClassName() const override;
   void Layout() override;
   gfx::Size CalculatePreferredSize() const override;
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   void OnThemeChanged() override;
 
   // Desk::Observer:
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc
index 4496207..4d67d933 100644
--- a/ash/wm/desks/desk_preview_view.cc
+++ b/ash/wm/desks/desk_preview_view.cc
@@ -10,7 +10,6 @@
 
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
-#include "ash/strings/grit/ash_strings.h"
 #include "ash/style/style_util.h"
 #include "ash/wallpaper/views/wallpaper_base_view.h"
 #include "ash/wm/desks/desk.h"
@@ -34,7 +33,6 @@
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/wm/features.h"
 #include "ui/accessibility/ax_node_data.h"
-#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/color/color_provider.h"
 #include "ui/compositor/layer.h"
@@ -506,35 +504,6 @@
   views::Button::GetAccessibleNodeData(node_data);
   if (GetAccessibleName().empty())
     node_data->SetNameExplicitlyEmpty();
-
-  // Note that the desk may have already been destroyed.
-  Desk* desk = mini_view_->desk();
-  if (desk) {
-    // Announce desk name.
-    node_data->AddStringAttribute(
-        ax::mojom::StringAttribute::kRoleDescription,
-        l10n_util::GetStringFUTF8(
-            IDS_ASH_DESKS_DESK_PREVIEW_A11Y_NAME,
-            l10n_util::GetStringUTF16(
-                desk->is_active()
-                    ? IDS_ASH_DESKS_ACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP
-                    : IDS_ASH_DESKS_INACTIVE_DESK_MINIVIEW_A11Y_EXTRA_TIP),
-            desk->name()));
-  }
-
-  // If the desk can be combined or closed, add a tip to let the user know they
-  // can use an accelerator.
-  if (!DesksController::Get()->CanRemoveDesks()) {
-    return;
-  }
-
-  const std::u16string target_desk_name =
-      DesksController::Get()->GetCombineDesksTargetName(desk);
-  const std::string extra_tip = l10n_util::GetStringFUTF8(
-      IDS_ASH_OVERVIEW_CLOSABLE_DESK_MINIVIEW_A11Y_EXTRA_TIP, target_desk_name);
-
-  node_data->AddStringAttribute(ax::mojom::StringAttribute::kDescription,
-                                extra_tip);
 }
 
 void DeskPreviewView::Layout() {
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc
index ce7deb2..fde9079a 100644
--- a/ash/wm/snap_group/snap_group_unittest.cc
+++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -32,6 +32,7 @@
 #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
 #include "ash/wm/window_cycle/window_cycle_controller.h"
 #include "ash/wm/window_cycle/window_cycle_list.h"
+#include "ash/wm/window_cycle/window_cycle_view.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
@@ -494,6 +495,7 @@
     WindowCycleController* window_cycle_controller =
         Shell::Get()->window_cycle_controller();
     window_cycle_controller->CompleteCycling();
+    EXPECT_FALSE(window_cycle_controller->IsCycling());
   }
 
   void CycleWindow(WindowCyclingDirection direction, int steps) {
@@ -1098,8 +1100,6 @@
   // Test that the two windows in a snap group are reordered to be adjacent
   // with each other to reflect the window layout with the revised order as :
   // window2 --> window0--> window1.
-  // TODO(b/293365678): `cycle_list` should contain two items, update the test
-  // when the container view is implemented.
   ASSERT_EQ(windows.size(), 3u);
   EXPECT_EQ(windows.at(0), window2.get());
   EXPECT_EQ(windows.at(1), window0.get());
@@ -1116,6 +1116,65 @@
   EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
 }
 
+// Tests that the number of views to be cycled through inside the mirror
+// container view of window cycle view will be the number of free-form windows
+// plus snap groups.
+TEST_F(SnapGroupEntryPointArm1Test, WindowCycleViewTest) {
+  std::unique_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
+  std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
+  std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(2));
+  SnapTwoTestWindowsInArm1(window0.get(), window1.get());
+
+  WindowCycleController* window_cycle_controller =
+      Shell::Get()->window_cycle_controller();
+  CycleWindow(WindowCyclingDirection::kForward, /*steps=*/3);
+  const auto* window_cycle_list = window_cycle_controller->window_cycle_list();
+  const auto& windows = window_cycle_list->windows_for_testing();
+  EXPECT_EQ(windows.size(), 3u);
+
+  const WindowCycleView* cycle_view = window_cycle_list->cycle_view();
+  ASSERT_TRUE(cycle_view);
+  EXPECT_EQ(cycle_view->mirror_container_for_testing()->children().size(), 2u);
+  CompleteWindowCycling();
+}
+
+// Tests that on window that belongs to a snap group destroying while cycling
+// the window list with Alt + Tab, there will be no crash. The corresponding
+// child mini view hosted by the group container view will be destroyed, the
+// group container view will host the other child mini view.
+TEST_F(SnapGroupEntryPointArm1Test, WindowInSnapGroupDestructionInAltTab) {
+  std::unique_ptr<aura::Window> window0(CreateTestWindowInShellWithId(0));
+  std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
+  std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(2));
+  SnapTwoTestWindowsInArm1(window0.get(), window1.get());
+
+  WindowCycleController* window_cycle_controller =
+      Shell::Get()->window_cycle_controller();
+  CycleWindow(WindowCyclingDirection::kForward, /*steps=*/3);
+  const auto* window_cycle_list = window_cycle_controller->window_cycle_list();
+  const auto& windows = window_cycle_list->windows_for_testing();
+  EXPECT_EQ(windows.size(), 3u);
+
+  const WindowCycleView* cycle_view = window_cycle_list->cycle_view();
+  ASSERT_TRUE(cycle_view);
+  // Verify that the number of child views hosted by mirror container is two at
+  // the beginning.
+  EXPECT_EQ(cycle_view->mirror_container_for_testing()->children().size(), 2u);
+
+  // Destroy `window0` which belongs to a snap group.
+  window0.reset();
+  const auto* updated_window_cycle_list =
+      window_cycle_controller->window_cycle_list();
+  const auto& updated_windows =
+      updated_window_cycle_list->windows_for_testing();
+  // Verify that the updated windows list size decreased.
+  EXPECT_EQ(updated_windows.size(), 2u);
+
+  // Verify that the number of child views hosted by mirror container will still
+  // be two.
+  EXPECT_EQ(cycle_view->mirror_container_for_testing()->children().size(), 2u);
+}
+
 // Tests that after creating a snap group in clamshell, transition to tablet
 // mode won't crash (b/288179725).
 TEST_F(SnapGroupEntryPointArm1Test, NoCrashWhenRemovingGroupInTabletMode) {
diff --git a/ash/wm/window_cycle/window_cycle_controller.cc b/ash/wm/window_cycle/window_cycle_controller.cc
index 0fe6a8b..707e8f1 100644
--- a/ash/wm/window_cycle/window_cycle_controller.cc
+++ b/ash/wm/window_cycle/window_cycle_controller.cc
@@ -4,15 +4,12 @@
 
 #include "ash/wm/window_cycle/window_cycle_controller.h"
 
-#include "ash/accelerators/accelerator_controller_impl.h"
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/constants/ash_pref_names.h"
 #include "ash/events/event_rewriter_controller_impl.h"
 #include "ash/metrics/task_switch_metrics_recorder.h"
 #include "ash/metrics/task_switch_source.h"
 #include "ash/metrics/user_metrics_recorder.h"
-#include "ash/public/cpp/accelerators.h"
-#include "ash/public/cpp/window_properties.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -25,7 +22,6 @@
 #include "ash/wm/snap_group/snap_group.h"
 #include "ash/wm/window_cycle/window_cycle_event_filter.h"
 #include "ash/wm/window_cycle/window_cycle_list.h"
-#include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/check.h"
 #include "base/containers/contains.h"
diff --git a/ash/wm/window_cycle/window_cycle_item_view.cc b/ash/wm/window_cycle/window_cycle_item_view.cc
index fff8da0..fcad3b3 100644
--- a/ash/wm/window_cycle/window_cycle_item_view.cc
+++ b/ash/wm/window_cycle/window_cycle_item_view.cc
@@ -144,7 +144,7 @@
 BEGIN_METADATA(WindowCycleItemView, WindowMiniView)
 END_METADATA
 
-GroupContainerView::GroupContainerView(SnapGroup* snap_group) {
+GroupContainerCycleView::GroupContainerCycleView(SnapGroup* snap_group) {
   mini_view1_ = AddChildView(
       std::make_unique<WindowCycleItemView>(snap_group->window1()));
   mini_view2_ = AddChildView(
@@ -153,7 +153,6 @@
   SetFocusBehavior(FocusBehavior::ALWAYS);
   SetPaintToLayer();
   layer()->SetFillsBoundsOpaquely(false);
-  SetAccessibleName(u"Group container view");
 
   // TODO(michelefan@): Orientation should correspond to the window layout.
   views::BoxLayout* layout =
@@ -164,15 +163,19 @@
       views::BoxLayout::CrossAxisAlignment::kCenter);
 }
 
-GroupContainerView::~GroupContainerView() = default;
+GroupContainerCycleView::~GroupContainerCycleView() = default;
 
-bool GroupContainerView::Contains(aura::Window* window) const {
-  return mini_view1_->Contains(window) || mini_view2_->Contains(window);
+bool GroupContainerCycleView::Contains(aura::Window* window) const {
+  return (mini_view1_ && mini_view1_->Contains(window)) ||
+         (mini_view2_ && mini_view2_->Contains(window));
 }
 
-aura::Window* GroupContainerView::GetWindowAtPoint(
+aura::Window* GroupContainerCycleView::GetWindowAtPoint(
     const gfx::Point& screen_point) const {
   for (auto mini_view : {mini_view1_, mini_view2_}) {
+    if (!mini_view) {
+      continue;
+    }
     if (auto* window = mini_view->GetWindowAtPoint(screen_point)) {
       return window;
     }
@@ -180,7 +183,42 @@
   return nullptr;
 }
 
-BEGIN_METADATA(GroupContainerView, WindowMiniViewBase)
+void GroupContainerCycleView::RefreshItemVisuals() {
+  for (auto mini_view : {mini_view1_, mini_view2_}) {
+    if (mini_view) {
+      mini_view->RefreshItemVisuals();
+    }
+  }
+}
+
+int GroupContainerCycleView::TryRemovingChildItem(
+    aura::Window* destroying_window) {
+  std::vector<raw_ptr<WindowCycleItemView>*> mini_views_ptrs = {&mini_view1_,
+                                                                &mini_view2_};
+  for (auto* mini_view_ptr : mini_views_ptrs) {
+    if (auto& mini_view = *mini_view_ptr;
+        mini_view && mini_view->Contains(destroying_window)) {
+      auto* temp = mini_view.get();
+      // Explicitly reset the `mini_view` to avoid dangling pointer detection.
+      mini_view = nullptr;
+      RemoveChildViewT(temp);
+    }
+  }
+
+  return base::ranges::count_if(
+      mini_views_ptrs,
+      [](raw_ptr<WindowCycleItemView>* ptr) { return *ptr != nullptr; });
+}
+
+void GroupContainerCycleView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  views::View::GetAccessibleNodeData(node_data);
+  node_data->role = ax::mojom::Role::kGroup;
+  // TODO(b/297062026): Update the string after been finalized by consulting
+  // with a11y team.
+  node_data->SetName(u"Group container view");
+}
+
+BEGIN_METADATA(GroupContainerCycleView, WindowMiniViewBase)
 END_METADATA
 
 }  // namespace ash
diff --git a/ash/wm/window_cycle/window_cycle_item_view.h b/ash/wm/window_cycle/window_cycle_item_view.h
index 62055bb2..d0e6558 100644
--- a/ash/wm/window_cycle/window_cycle_item_view.h
+++ b/ash/wm/window_cycle/window_cycle_item_view.h
@@ -10,12 +10,15 @@
 #include "base/memory/raw_ptr.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/events/event.h"
-#include "ui/gfx/geometry/size.h"
 
 namespace aura {
 class Window;
 }  // namespace aura
 
+namespace gfx {
+class Size;
+}  // namespace gfx
+
 namespace ash {
 
 class SnapGroup;
@@ -49,22 +52,29 @@
 
 // Container view used to host multiple `WindowCycleItemView`s and be the focus
 // target for window groups while tabbing in window cycle view.
-class GroupContainerView : public WindowMiniViewBase {
+class GroupContainerCycleView : public WindowMiniViewBase {
  public:
-  METADATA_HEADER(GroupContainerView);
+  METADATA_HEADER(GroupContainerCycleView);
 
-  explicit GroupContainerView(SnapGroup* snap_group);
-  GroupContainerView(const GroupContainerView&) = delete;
-  GroupContainerView& operator=(const GroupContainerView&) = delete;
-  ~GroupContainerView() override;
+  explicit GroupContainerCycleView(SnapGroup* snap_group);
+  GroupContainerCycleView(const GroupContainerCycleView&) = delete;
+  GroupContainerCycleView& operator=(const GroupContainerCycleView&) = delete;
+  ~GroupContainerCycleView() override;
 
   // WindowMiniViewBase:
   bool Contains(aura::Window* window) const override;
   aura::Window* GetWindowAtPoint(const gfx::Point& screen_point) const override;
+  void RefreshItemVisuals() override;
+  int TryRemovingChildItem(aura::Window* destroying_window) override;
+
+  // views::View:
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
 
  private:
-  raw_ptr<WindowCycleItemView, ExperimentalAsh> mini_view1_;
-  raw_ptr<WindowCycleItemView, ExperimentalAsh> mini_view2_;
+  // TODO(b/297070130): Use vector store the child `WindowCycleItemView` hosted
+  // by this.
+  raw_ptr<WindowCycleItemView> mini_view1_;
+  raw_ptr<WindowCycleItemView> mini_view2_;
 };
 
 }  // namespace ash
diff --git a/ash/wm/window_cycle/window_cycle_list.cc b/ash/wm/window_cycle/window_cycle_list.cc
index 49e5624..04d0634 100644
--- a/ash/wm/window_cycle/window_cycle_list.cc
+++ b/ash/wm/window_cycle/window_cycle_list.cc
@@ -6,7 +6,6 @@
 
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/app_list/app_list_controller_impl.h"
-#include "ash/constants/ash_features.h"
 #include "ash/frame_throttler/frame_throttling_controller.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
@@ -16,12 +15,12 @@
 #include "ash/system/tray/tray_background_view.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/window_cycle/window_cycle_view.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/check.h"
 #include "base/location.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/metrics/user_metrics.h"
 #include "base/ranges/algorithm.h"
 #include "ui/aura/scoped_window_targeter.h"
 #include "ui/aura/window.h"
@@ -283,7 +282,6 @@
   window->RemoveObserver(this);
 
   WindowList::iterator i = base::ranges::find(windows_, window);
-  // TODO(oshima): Change this back to DCHECK once crbug.com/483491 is fixed.
   CHECK(i != windows_.end());
   int removed_index = static_cast<int>(i - windows_.begin());
   windows_.erase(i);
diff --git a/ash/wm/window_cycle/window_cycle_list.h b/ash/wm/window_cycle/window_cycle_list.h
index 836059d..970c6864 100644
--- a/ash/wm/window_cycle/window_cycle_list.h
+++ b/ash/wm/window_cycle/window_cycle_list.h
@@ -10,14 +10,11 @@
 
 #include "ash/ash_export.h"
 #include "ash/wm/window_cycle/window_cycle_controller.h"
-#include "ash/wm/window_cycle/window_cycle_view.h"
 #include "base/memory/raw_ptr.h"
 #include "base/timer/timer.h"
 #include "ui/aura/window_observer.h"
 #include "ui/display/display_observer.h"
-#include "ui/display/screen.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/view.h"
+#include "ui/events/event.h"
 
 namespace aura {
 class ScopedWindowTargeter;
@@ -30,6 +27,8 @@
 
 namespace ash {
 
+class WindowCycleView;
+
 // Tracks a set of Windows that can be stepped through. This class is used by
 // the WindowCycleController.
 class ASH_EXPORT WindowCycleList : public aura::WindowObserver,
diff --git a/ash/wm/window_cycle/window_cycle_view.cc b/ash/wm/window_cycle/window_cycle_view.cc
index 086b7c8..c0610dd 100644
--- a/ash/wm/window_cycle/window_cycle_view.cc
+++ b/ash/wm/window_cycle/window_cycle_view.cc
@@ -16,6 +16,8 @@
 #include "ash/style/system_shadow.h"
 #include "ash/style/tab_slider.h"
 #include "ash/style/tab_slider_button.h"
+#include "ash/wm/snap_group/snap_group.h"
+#include "ash/wm/snap_group/snap_group_controller.h"
 #include "ash/wm/window_cycle/window_cycle_controller.h"
 #include "ash/wm/window_cycle/window_cycle_item_view.h"
 #include "ash/wm/window_mini_view.h"
@@ -105,6 +107,34 @@
 // modes.
 constexpr base::TimeDelta kToggleModeScaleDuration = base::Milliseconds(150);
 
+// Builds the item view for window cycling for the given `window` with the
+// correct parent. If the given `window` is a free-form window, the direct
+// parent will be `mirror_container`. For `window` that belongs to a snap group,
+// however, a `GroupContainerCycleView` will be added.
+WindowMiniViewBase* BuildAndConfigureCycleView(
+    aura::Window* window,
+    views::View* mirror_container,
+    std::vector<WindowMiniViewBase*>& cycle_views) {
+  if (auto* snap_group_controller = SnapGroupController::Get()) {
+    if (auto* snap_group =
+            snap_group_controller->GetSnapGroupForGivenWindow(window)) {
+      // Create `GroupContainerCycleView` if `window` is primary snapped,
+      // which adds two child views subsequently. Skip adding
+      // `GroupContainerCycleView` if `window` is secondary snapped since the
+      // corresponding container view has been built.
+      return window == snap_group->window1()
+                 ? mirror_container->AddChildView(
+                       std::make_unique<GroupContainerCycleView>(snap_group))
+                 : nullptr;
+    }
+  }
+
+  // `mirror_container_` owns `view`. The `preview_view_` in `view` will use
+  // trilinear filtering in InitLayerOwner().
+  return mirror_container->AddChildView(
+      std::make_unique<WindowCycleItemView>(window));
+}
+
 }  // namespace
 
 WindowCycleView::WindowCycleView(aura::Window* root_window,
@@ -228,12 +258,11 @@
   }
 
   for (auto* window : windows) {
-    // |mirror_container_| owns |view|. The |preview_view_| in |view| will
-    // use trilinear filtering in InitLayerOwner().
-    auto* view = mirror_container_->AddChildView(
-        std::make_unique<WindowCycleItemView>(window));
-    cycle_views_.push_back(view);
-    no_previews_list_.push_back(view);
+    if (auto* view = BuildAndConfigureCycleView(window, mirror_container_,
+                                                cycle_views_)) {
+      cycle_views_.push_back(view);
+      no_previews_list_.push_back(view);
+    }
   }
 
   // The insets in the WindowCycleItemView are coming from its border, which
@@ -328,10 +357,11 @@
     return;
 
   for (auto* window : windows) {
-    auto* view = mirror_container_->AddChildView(
-        std::make_unique<WindowCycleItemView>(window));
-    cycle_views_.push_back(view);
-    no_previews_list_.push_back(view);
+    if (auto* view = BuildAndConfigureCycleView(window, mirror_container_,
+                                                cycle_views_)) {
+      cycle_views_.push_back(view);
+      no_previews_list_.push_back(view);
+    }
   }
 
   // If there was an ongoing drag session, it's now been completed so reset
@@ -376,7 +406,7 @@
     Layout();
 }
 
-void WindowCycleView::SetTargetWindow(aura::Window* target) {
+void WindowCycleView::SetTargetWindow(aura::Window* new_target) {
   // Hide the focus border of the previous target window and show the focus
   // border of the new one.
   if (target_window_) {
@@ -385,7 +415,7 @@
     }
   }
 
-  target_window_ = target;
+  target_window_ = new_target;
   if (auto* view = GetCycleViewForWindow(target_window_)) {
     view->UpdateFocusState(/*focus=*/true);
   }
@@ -428,11 +458,16 @@
   CHECK(preview);
   views::View* parent = preview->parent();
   CHECK_EQ(mirror_container_, parent);
-  base::Erase(cycle_views_, preview);
-  base::Erase(no_previews_list_, preview);
-  delete preview;
 
-  // With one of its children now gone, we must re-layout |mirror_container_|.
+  if (preview->TryRemovingChildItem(destroying_window) == 0) {
+    // With no remaining child mini views contained in `preview`, we need to
+    // remove `preview` and clean up the `preview` in `cycle_views_` and
+    // `no_previews_list_`.
+    base::Erase(cycle_views_, preview);
+    base::Erase(no_previews_list_, preview);
+    parent->RemoveChildViewT(preview);
+  }
+  // With one of its children now gone, we must re-layout `mirror_container_`.
   // This must happen before ScrollToWindow() to make sure our own Layout()
   // works correctly when it's calculating highlight bounds.
   parent->Layout();
diff --git a/ash/wm/window_cycle/window_cycle_view.h b/ash/wm/window_cycle/window_cycle_view.h
index ef6ac200..c1c8178 100644
--- a/ash/wm/window_cycle/window_cycle_view.h
+++ b/ash/wm/window_cycle/window_cycle_view.h
@@ -26,6 +26,7 @@
 
 namespace views {
 class Label;
+class View;
 }  // namespace views
 
 namespace ash {
@@ -66,7 +67,7 @@
   // the root window's bounds.
   gfx::Rect GetTargetBounds() const;
 
-  // Recreates the `WindowCycleView` with the provided `windows`.
+  // Recreates the `WindowCycleView` with the given `windows`.
   void UpdateWindows(const WindowList& windows);
 
   // Fades the `WindowCycleView` in.
@@ -75,9 +76,12 @@
   // Scrolls the `WindowCycleView` to `target`.
   void ScrollToWindow(aura::Window* target);
 
-  // Makes `target` the new `target_window_`, moving the focus ring to its
-  // respective `WindowCycleItemView`.
-  void SetTargetWindow(aura::Window* target);
+  // Refreshes the `target_window_` with the `new_target`. Updates the focus
+  // state of the focus ring by hiding the focus ring on the previously
+  // focused item and painting the focus ring on the currently focused item.
+  // The focus target will be a single `WindowCycleItemView` for free-form
+  // window and a `GroupContainerCycleView` for snap group.
+  void SetTargetWindow(aura::Window* new_target);
 
   // Removes the `destroying_window`'s respective `WindowCycleItemView` and sets
   // `new_target` as the new `target_window_`.
@@ -129,6 +133,10 @@
   // Returns the maximum width of the cycle view.
   int CalculateMaxWidth() const;
 
+  const views::View* mirror_container_for_testing() const {
+    return mirror_container_;
+  }
+
  private:
   friend class WindowCycleListTestApi;
 
diff --git a/ash/wm/window_mini_view.cc b/ash/wm/window_mini_view.cc
index 54227abe..3fbc0f3d 100644
--- a/ash/wm/window_mini_view.cc
+++ b/ash/wm/window_mini_view.cc
@@ -207,6 +207,10 @@
   return GetBoundsInScreen().Contains(screen_point) ? source_window_ : nullptr;
 }
 
+int WindowMiniView::TryRemovingChildItem(aura::Window* destroying_window) {
+  return 0;
+}
+
 gfx::Rect WindowMiniView::GetHeaderBounds() const {
   gfx::Rect header_bounds = GetContentsBounds();
   header_bounds.set_height(kHeaderHeightDp);
diff --git a/ash/wm/window_mini_view.h b/ash/wm/window_mini_view.h
index 3a0a24e..fa80e122 100644
--- a/ash/wm/window_mini_view.h
+++ b/ash/wm/window_mini_view.h
@@ -27,7 +27,7 @@
 
 // Defines the interface that extracts the window, visual updates, focus
 // installation and update logic to be used or implemented by `WindowMiniView`
-// and `GroupContainerView`.
+// and `GroupContainerCycleView`.
 class WindowMiniViewBase : public views::View {
  public:
   METADATA_HEADER(WindowMiniViewBase);
@@ -49,6 +49,12 @@
   // of `this`.
   virtual void RefreshItemVisuals() = 0;
 
+  // Try removing the mini view representation of the `destroying_window`.
+  // Returns the number of remaining child items that represent windows within
+  // `this`. Returns 0, if `destroying_window` is represented by `this` itself
+  // rather than a child item.
+  virtual int TryRemovingChildItem(aura::Window* destroying_window) = 0;
+
   // Shows or hides a focus ring around this.
   void UpdateFocusState(bool focus);
 
@@ -106,6 +112,7 @@
   // WindowMiniViewBase:
   bool Contains(aura::Window* window) const override;
   aura::Window* GetWindowAtPoint(const gfx::Point& screen_point) const override;
+  int TryRemovingChildItem(aura::Window* destroying_window) override;
 
  protected:
   explicit WindowMiniView(aura::Window* source_window);
diff --git a/cc/test/DEPS b/cc/test/DEPS
index 8941ec0b..1a2bc067 100644
--- a/cc/test/DEPS
+++ b/cc/test/DEPS
@@ -25,5 +25,9 @@
   ],
   "pixel_test\.cc": [
     "+gpu/command_buffer/service/service_utils.h",
+    "+gpu/config/gpu_switches.h",
+  ],
+  "layer_tree_test\.cc": [
+    "+gpu/config/gpu_switches.h",
   ],
 }
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 52a0f67..280e3f1 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -51,6 +51,7 @@
 #include "components/viz/test/test_context_provider.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "gpu/config/gpu_finch_features.h"
+#include "gpu/config/gpu_switches.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/gfx/animation/keyframe/timing_function.h"
@@ -58,6 +59,11 @@
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_switches.h"
 
+#if BUILDFLAG(SKIA_USE_DAWN)
+#include "third_party/dawn/include/dawn/dawn_proc.h"
+#include "third_party/dawn/include/dawn/native/DawnNative.h"  // nogncheck
+#endif
+
 namespace cc {
 namespace {
 
@@ -718,11 +724,16 @@
 
   // Check if the graphics backend needs to initialize Vulkan.
   bool init_vulkan = false;
+  bool init_dawn = false;
   if (renderer_type_ == viz::RendererType::kSkiaVk) {
     scoped_feature_list_.InitAndEnableFeature(features::kVulkan);
     init_vulkan = true;
   } else if (renderer_type_ == viz::RendererType::kSkiaGraphite) {
     scoped_feature_list_.InitAndEnableFeature(features::kSkiaGraphite);
+    // Force the use of Graphite even if disallowed for other reasons e.g. ANGLE
+    // Metal is not enabled on Mac.
+    command_line->AppendSwitch(::switches::kSkiaGraphiteBackend);
+    init_dawn = true;
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
     init_vulkan = true;
 #endif
@@ -735,6 +746,12 @@
         use_gpu ? ::switches::kVulkanImplementationNameNative
                 : ::switches::kVulkanImplementationNameSwiftshader);
   }
+
+  if (init_dawn) {
+#if BUILDFLAG(SKIA_USE_DAWN)
+    dawnProcSetProcs(&dawn::native::GetProcs());
+#endif
+  }
 }
 
 LayerTreeTest::~LayerTreeTest() {
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 47dd797..6801925 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -75,6 +75,12 @@
     init_vulkan = true;
   } else if (backend == kSkiaGraphite) {
     scoped_feature_list_.InitAndEnableFeature(features::kSkiaGraphite);
+
+    // Force the use of Graphite even if disallowed for other reasons e.g. ANGLE
+    // Metal is not enabled on Mac.
+    auto* command_line = base::CommandLine::ForCurrentProcess();
+    command_line->AppendSwitch(::switches::kSkiaGraphiteBackend);
+
     init_dawn = true;
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
     init_vulkan = true;
@@ -82,7 +88,8 @@
   } else {
     // Ensure that we don't accidentally have vulkan or graphite enabled.
     scoped_feature_list_.InitWithFeatures(
-        {}, {features::kVulkan, features::kSkiaGraphite});
+        /*enabled_features=*/{},
+        /*disabled_features=*/{features::kVulkan, features::kSkiaGraphite});
   }
 
   if (init_vulkan) {
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 5a1bb18..6ed06c14 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -261,7 +261,6 @@
       "//chrome/browser/readaloud/android:hooks_public_impl_java",
       "//chrome/browser/supervised_user:parent_auth_delegate_impl_java",
       "//chrome/browser/touch_to_fill/android/internal:resource_provider_public_impl_java",
-      "//chrome/browser/ui/android/cars:delegate_public_impl_java",
       "//chrome/browser/ui/android/hats/internal:provider_public_impl_java",
       "//chrome/browser/xsurface_provider:hooks_public_impl_java",
       "//components/environment_integrity/android:integrity_service_bridge_public_impl_java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReadingListSectionHeader.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReadingListSectionHeader.java
index 41c98b1..6be2af79f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReadingListSectionHeader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReadingListSectionHeader.java
@@ -80,11 +80,11 @@
 
             // Sort by read status first.
             if (lhsItem.isRead() != rhsItem.isRead()) {
-                return lhsItem.isRead() ? 1 : -1;
+                return Boolean.compare(lhsItem.isRead(), rhsItem.isRead());
             }
 
             // Sort by creation timestamp descending for items with the same read status.
-            return lhsItem.getDateAdded() <= rhsItem.getDateAdded() ? 1 : -1;
+            return Long.compare(rhsItem.getDateAdded(), lhsItem.getDateAdded());
         });
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
index 98f008a..0398dca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -447,6 +447,7 @@
     protected boolean handleBackPressed() {
         if (!BackPressManager.isEnabled() && getTabModalLifetimeHandler() != null
                 && getTabModalLifetimeHandler().onBackPressed()) {
+            BackPressManager.record(BackPressHandler.Type.TAB_MODAL_HANDLER);
             return true;
         }
         if (BackPressManager.correctTabNavigationOnFallback()) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 442ce29..371f921 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -105,6 +105,7 @@
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.HistogramWatcher;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.AppHooks;
@@ -115,6 +116,7 @@
 import org.chromium.chrome.browser.LaunchIntentDispatcher;
 import org.chromium.chrome.browser.TabsOpenedFromExternalAppTest;
 import org.chromium.chrome.browser.WarmupManager;
+import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.browserservices.SessionDataHolder;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.verification.ChromeOriginVerifier;
@@ -161,6 +163,7 @@
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.chrome.test.util.browser.contextmenu.ContextMenuUtils;
 import org.chromium.components.browser_ui.widget.CoordinatorLayoutForPointer;
+import org.chromium.components.browser_ui.widget.gesture.BackPressHandler;
 import org.chromium.components.content_settings.CookieControlsMode;
 import org.chromium.components.embedder_support.util.Origin;
 import org.chromium.components.prefs.PrefService;
@@ -2522,6 +2525,11 @@
         });
         CriteriaHelper.pollUiThread(() -> dialogManager.isShowing(), "Dialog should be displayed");
 
+        HistogramWatcher histogramWatcher =
+                HistogramWatcher.newSingleRecordWatcher("Android.BackPress.Intercept",
+                        BackPressManager.getHistogramValueForTesting(
+                                BackPressHandler.Type.TAB_MODAL_HANDLER));
+
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mCustomTabActivityTestRule.getActivity().getOnBackPressedDispatcher().onBackPressed();
         });
@@ -2534,6 +2542,7 @@
                     is(mTestPage2));
         });
 
+        histogramWatcher.assertExpected("Dialog should be dismissed by back press");
         CriteriaHelper.pollUiThread(
                 () -> !dialogManager.isShowing(), "Dialog should be dismissed by back press");
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrPermissionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrPermissionTest.java
index 1690855..28f85fa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrPermissionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrPermissionTest.java
@@ -24,6 +24,7 @@
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisableIf;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.vr.rules.XrActivityRestriction;
 import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils;
@@ -130,10 +131,8 @@
     @Test
     @MediumTest
     @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
-    @DisableIf.Build(message = "crbug.com/1429697", hardware_is = "marlin",
-            sdk_is_greater_than = 28, sdk_is_less_than = 30)
-    public void
-    testPermissionPersistsAfterReload() {
+    @DisabledTest(message = "crbug.com/1429697")
+    public void testPermissionPersistsAfterReload() {
         mWebXrVrPermissionTestFramework.loadFileAndAwaitInitialization(
                 "generic_webxr_page", PAGE_LOAD_TIMEOUT_S);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrCardboardPermissionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrCardboardPermissionTest.java
index 98d467e..6201453 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrCardboardPermissionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrCardboardPermissionTest.java
@@ -22,6 +22,7 @@
 import org.chromium.base.test.params.ParameterSet;
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.vr.rules.XrActivityRestriction;
@@ -133,6 +134,7 @@
     @MediumTest
     @Restriction({RESTRICTION_TYPE_VIEWER_NON_DAYDREAM})
     @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    @DisabledTest(message = "crbug.com/1429697")
     public void testPermissionPersistsAfterReload() {
         mWebXrVrPermissionTestFramework.loadFileAndAwaitInitialization(
                 "generic_webxr_page", PAGE_LOAD_TIMEOUT_S);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/ReadingListSectionHeaderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/ReadingListSectionHeaderTest.java
index 3caa5f7..7d92f5de 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/ReadingListSectionHeaderTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/ReadingListSectionHeaderTest.java
@@ -160,4 +160,19 @@
         assertSectionHeader(listItems.get(1), R.string.reading_list_read,
                 R.dimen.bookmark_reading_list_section_header_padding_top);
     }
+
+    @Test
+    public void testReadAndUnreadItems_equalCreationTime() {
+        List<BookmarkListEntry> listItems = new ArrayList<>();
+        listItems.add(createReadingListEntry(1, false, OLDER_CREATION_TIMESTAMP));
+        listItems.add(createReadingListEntry(2, false, OLDER_CREATION_TIMESTAMP));
+        listItems.add(createReadingListEntry(3, true, OLDER_CREATION_TIMESTAMP));
+        listItems.add(createReadingListEntry(4, true, OLDER_CREATION_TIMESTAMP));
+        ReadingListSectionHeader.maybeSortAndInsertSectionHeaders(listItems);
+
+        assertEquals("Incorrect number of items in the adapter", 6, listItems.size());
+        assertSectionHeader(listItems.get(0), R.string.reading_list_unread, 0);
+        assertSectionHeader(listItems.get(3), R.string.reading_list_read,
+                R.dimen.bookmark_reading_list_section_header_padding_top);
+    }
 }
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 358ab0bb..5fcce3f2 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-117.0.5911.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-118.0.5963.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 2ebd4f7..6f1b5e53 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4439,9 +4439,6 @@
     {"screen-saver-duration", flag_descriptions::kScreenSaverDurationName,
      flag_descriptions::kScreenSaverDurationDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kScreenSaverDuration)},
-    {"screen-saver-preview", flag_descriptions::kScreenSaverPreviewName,
-     flag_descriptions::kScreenSaverPreviewDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kScreenSaverPreview)},
     {"multi-zone-rgb-keyboard", flag_descriptions::kMultiZoneRgbKeyboardName,
      flag_descriptions::kMultiZoneRgbKeyboardDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kMultiZoneRgbKeyboard)},
@@ -8126,11 +8123,6 @@
      FEATURE_VALUE_TYPE(ash::features::kUseWallpaperStagingUrl)},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-    {"autofill-enable-virtual-card",
-     flag_descriptions::kAutofillEnableVirtualCardName,
-     flag_descriptions::kAutofillEnableVirtualCardDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(autofill::features::kAutofillEnableVirtualCard)},
-
 #if BUILDFLAG(IS_ANDROID)
     {"autofill-enable-manual-fallback-for-virtual-cards",
      flag_descriptions::kAutofillEnableManualFallbackForVirtualCardsName,
@@ -10840,6 +10832,13 @@
      FEATURE_VALUE_TYPE(ash::features::kFloatingWorkspaceV2)},
 #endif
 
+#if BUILDFLAG(IS_ANDROID)
+    {"draw-immediately-when-interactive",
+     flag_descriptions::kDrawImmediatelyWhenInteractiveName,
+     flag_descriptions::kDrawImmediatelyWhenInteractiveDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(features::kDrawImmediatelyWhenInteractive)},
+#endif
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     {"almanac-game-migration", flag_descriptions::kAlmanacGameMigrationName,
      flag_descriptions::kAlmanacGameMigrationDescription, kOsCrOS,
diff --git a/chrome/browser/ash/app_list/app_service/app_service_shortcut_context_menu.cc b/chrome/browser/ash/app_list/app_service/app_service_shortcut_context_menu.cc
index 168bba3..1609d7c5 100644
--- a/chrome/browser/ash/app_list/app_service/app_service_shortcut_context_menu.cc
+++ b/chrome/browser/ash/app_list/app_service/app_service_shortcut_context_menu.cc
@@ -59,6 +59,11 @@
       ui::ImageModel::FromVectorIcon(vector_icons::kLaunchIcon,
                                      ui::kColorAshSystemUIMenuIcon,
                                      ash::kAppContextMenuIconSize));
+
+  AddContextMenuOption(menu_model.get(),
+                       static_cast<ash::CommandId>(ash::CommandId::TOGGLE_PIN),
+                       IDS_APP_LIST_CONTEXT_MENU_PIN);
+
   std::move(callback).Run(std::move(menu_model));
 }
 
@@ -67,5 +72,8 @@
   switch (command_id) {
     case ash::LAUNCH_NEW:
       delegate()->ExecuteLaunchCommand(event_flags);
+      break;
+    default:
+      AppContextMenu::ExecuteCommand(command_id, event_flags);
   }
 }
diff --git a/chrome/browser/ash/app_list/app_service/app_service_shortcut_item_browsertest.cc b/chrome/browser/ash/app_list/app_service/app_service_shortcut_item_browsertest.cc
index cf9c619b..c8ce840 100644
--- a/chrome/browser/ash/app_list/app_service/app_service_shortcut_item_browsertest.cc
+++ b/chrome/browser/ash/app_list/app_service/app_service_shortcut_item_browsertest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/app_constants/constants.h"
 #include "components/services/app_service/public/cpp/app_types.h"
@@ -34,6 +35,8 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/views/vector_icons.h"
 
 namespace apps {
 
@@ -186,4 +189,52 @@
   url_observer.Wait();
 }
 
+IN_PROC_BROWSER_TEST_F(AppServiceShortcutItemBrowserTest,
+                       ContextMenuTooglePin) {
+  GURL app_url = GURL("https://example.org/");
+  std::u16string shortcut_name = u"Example";
+  apps::ShortcutId shortcut_id =
+      CreateWebAppBasedShortcut(app_url, shortcut_name);
+
+  AppListClientImpl* client = AppListClientImpl::GetInstance();
+  AppListModelUpdater* model_updater = test::GetModelUpdater(client);
+  ChromeAppListItem* item = model_updater->FindItem(shortcut_id.value());
+  ASSERT_TRUE(item);
+
+  base::test::TestFuture<std::unique_ptr<ui::SimpleMenuModel>> future;
+  item->GetContextMenuModel(ash::AppListItemContext::kNone,
+                            future.GetCallback());
+
+  std::unique_ptr<ui::SimpleMenuModel> menu_model = future.Take();
+
+  auto tootle_pin_command_index =
+      menu_model->GetIndexOfCommandId(ash::CommandId::TOGGLE_PIN);
+  ASSERT_TRUE(tootle_pin_command_index);
+  EXPECT_EQ(tootle_pin_command_index.value(), 1u);
+
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_PIN),
+            menu_model->GetLabelAt(tootle_pin_command_index.value()));
+  EXPECT_EQ(&views::kPinIcon,
+            menu_model->GetIconAt(tootle_pin_command_index.value())
+                .GetVectorIcon()
+                .vector_icon());
+
+  menu_model->ActivatedAt(tootle_pin_command_index.value());
+
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_UNPIN),
+            menu_model->GetLabelAt(tootle_pin_command_index.value()));
+  EXPECT_EQ(&views::kUnpinIcon,
+            menu_model->GetIconAt(tootle_pin_command_index.value())
+                .GetVectorIcon()
+                .vector_icon());
+
+  menu_model->ActivatedAt(tootle_pin_command_index.value());
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_PIN),
+            menu_model->GetLabelAt(tootle_pin_command_index.value()));
+  EXPECT_EQ(&views::kPinIcon,
+            menu_model->GetIconAt(tootle_pin_command_index.value())
+                .GetVectorIcon()
+                .vector_icon());
+}
+
 }  // namespace apps
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc
index d6267e35..9442e9a9 100644
--- a/chrome/browser/ash/crosapi/browser_manager.cc
+++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -161,9 +161,16 @@
 constexpr char kLacrosLauncherNotifierID[] = "lacros_launcher";
 
 base::FilePath LacrosLogDirectory() {
+  // When pre-launching Lacros at login screen is enabled:
+  // - In test images, we always save Lacros logs in /var/log/lacros.
+  // - In non-test images, we save Lacros logs in /var/log/lacros
+  //   only when Lacros is running at login screen. Lacros will
+  //   redirect user-specific logs to the cryptohome after login.
   if (base::FeatureList::IsEnabled(kLacrosLaunchAtLoginScreen) &&
-      session_manager::SessionManager::Get()->session_state() ==
-          session_manager::SessionState::LOGIN_PRIMARY) {
+      (base::CommandLine::ForCurrentProcess()->HasSwitch(
+           switches::kDisableLoggingRedirect) ||
+       session_manager::SessionManager::Get()->session_state() ==
+           session_manager::SessionState::LOGIN_PRIMARY)) {
     return base::FilePath("/var/log/lacros");
   }
   return browser_util::GetUserDataDir();
diff --git a/chrome/browser/ash/device_sync/device_sync_client_factory.cc b/chrome/browser/ash/device_sync/device_sync_client_factory.cc
index 324413f..776dfc6e 100644
--- a/chrome/browser/ash/device_sync/device_sync_client_factory.cc
+++ b/chrome/browser/ash/device_sync/device_sync_client_factory.cc
@@ -143,12 +143,13 @@
   return instance.get();
 }
 
-KeyedService* DeviceSyncClientFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+DeviceSyncClientFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   // TODO(crbug.com/848347): Check prohibited by policy in services that depend
   // on this Factory, not here.
   if (IsEnrollmentAllowedByPolicy(context))
-    return new DeviceSyncClientHolder(context);
+    return std::make_unique<DeviceSyncClientHolder>(context);
 
   return nullptr;
 }
diff --git a/chrome/browser/ash/device_sync/device_sync_client_factory.h b/chrome/browser/ash/device_sync/device_sync_client_factory.h
index 50e1c21..effc5a73 100644
--- a/chrome/browser/ash/device_sync/device_sync_client_factory.h
+++ b/chrome/browser/ash/device_sync/device_sync_client_factory.h
@@ -33,7 +33,7 @@
   ~DeviceSyncClientFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsNULLWhileTesting() const override;
 };
diff --git a/chrome/browser/ash/drive/file_system_util.cc b/chrome/browser/ash/drive/file_system_util.cc
index 856e051..6c19216 100644
--- a/chrome/browser/ash/drive/file_system_util.cc
+++ b/chrome/browser/ash/drive/file_system_util.cc
@@ -216,6 +216,7 @@
     }
     running_size += file_info.GetSize();
   }
+  LOG(ERROR) << "ComputeDriveFsContentCacheSize: " << running_size;
   return running_size;
 }
 
diff --git a/chrome/browser/ash/extensions/install_limiter_factory.cc b/chrome/browser/ash/extensions/install_limiter_factory.cc
index 951454f0..9e39e0e 100644
--- a/chrome/browser/ash/extensions/install_limiter_factory.cc
+++ b/chrome/browser/ash/extensions/install_limiter_factory.cc
@@ -37,9 +37,10 @@
 
 InstallLimiterFactory::~InstallLimiterFactory() = default;
 
-KeyedService* InstallLimiterFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+InstallLimiterFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* profile) const {
-  return new InstallLimiter();
+  return std::make_unique<InstallLimiter>();
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/ash/extensions/install_limiter_factory.h b/chrome/browser/ash/extensions/install_limiter_factory.h
index c625a71..5dc9a13 100644
--- a/chrome/browser/ash/extensions/install_limiter_factory.h
+++ b/chrome/browser/ash/extensions/install_limiter_factory.h
@@ -31,7 +31,7 @@
   ~InstallLimiterFactory() override;
 
   // BrowserContextKeyedServiceFactory overrides:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
 };
 
diff --git a/chrome/browser/ash/file_manager/file_manager_jstest.cc b/chrome/browser/ash/file_manager/file_manager_jstest.cc
index 2c95f19..39bd9ee 100644
--- a/chrome/browser/ash/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_jstest.cc
@@ -352,7 +352,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ReducerUiEntries) {
-  RunTestURL("state/reducers/ui_entries_unittest.js");
+  RunTestURL("state/ducks/ui_entries_unittest.js");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ReducerVolumes) {
diff --git a/chrome/browser/ash/multidevice_setup/auth_token_validator_factory.cc b/chrome/browser/ash/multidevice_setup/auth_token_validator_factory.cc
index 2297aa0..da61708f5 100644
--- a/chrome/browser/ash/multidevice_setup/auth_token_validator_factory.cc
+++ b/chrome/browser/ash/multidevice_setup/auth_token_validator_factory.cc
@@ -37,9 +37,10 @@
 
 AuthTokenValidatorFactory::~AuthTokenValidatorFactory() = default;
 
-KeyedService* AuthTokenValidatorFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+AuthTokenValidatorFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new AuthTokenValidatorImpl(
+  return std::make_unique<AuthTokenValidatorImpl>(
       quick_unlock::QuickUnlockFactory::GetForProfile(
           Profile::FromBrowserContext(context)));
 }
diff --git a/chrome/browser/ash/multidevice_setup/auth_token_validator_factory.h b/chrome/browser/ash/multidevice_setup/auth_token_validator_factory.h
index f3250d7..d563c9f 100644
--- a/chrome/browser/ash/multidevice_setup/auth_token_validator_factory.h
+++ b/chrome/browser/ash/multidevice_setup/auth_token_validator_factory.h
@@ -34,7 +34,7 @@
   ~AuthTokenValidatorFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/ash/multidevice_setup/multidevice_setup_client_factory.cc b/chrome/browser/ash/multidevice_setup/multidevice_setup_client_factory.cc
index c55be4e..e8ba140 100644
--- a/chrome/browser/ash/multidevice_setup/multidevice_setup_client_factory.cc
+++ b/chrome/browser/ash/multidevice_setup/multidevice_setup_client_factory.cc
@@ -122,12 +122,13 @@
   return instance.get();
 }
 
-KeyedService* MultiDeviceSetupClientFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+MultiDeviceSetupClientFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   if (IsAllowedByPolicy(context)) {
     PA_LOG(INFO)
         << "Allowed by policy. Returning new MultiDeviceSetupClientHolder";
-    return new MultiDeviceSetupClientHolder(context);
+    return std::make_unique<MultiDeviceSetupClientHolder>(context);
   }
 
   PA_LOG(INFO) << "NOT allowed by policy. Unable to return "
diff --git a/chrome/browser/ash/multidevice_setup/multidevice_setup_client_factory.h b/chrome/browser/ash/multidevice_setup/multidevice_setup_client_factory.h
index 4197745c..91abc7b 100644
--- a/chrome/browser/ash/multidevice_setup/multidevice_setup_client_factory.h
+++ b/chrome/browser/ash/multidevice_setup/multidevice_setup_client_factory.h
@@ -45,7 +45,7 @@
   }
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsNULLWhileTesting() const override;
   bool service_is_null_while_testing_ = true;
diff --git a/chrome/browser/ash/printing/cups_printers_manager_factory.cc b/chrome/browser/ash/printing/cups_printers_manager_factory.cc
index 27aa1b6c..4afd80b 100644
--- a/chrome/browser/ash/printing/cups_printers_manager_factory.cc
+++ b/chrome/browser/ash/printing/cups_printers_manager_factory.cc
@@ -47,7 +47,8 @@
   return proxy_.get();
 }
 
-KeyedService* CupsPrintersManagerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+CupsPrintersManagerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   auto* profile = Profile::FromBrowserContext(context);
   // This condition still needs to be explicitly stated here despite having
@@ -61,11 +62,12 @@
     return nullptr;
   }
 
-  auto manager = CupsPrintersManager::Create(profile);
+  std::unique_ptr<CupsPrintersManager> manager =
+      CupsPrintersManager::Create(profile);
   if (ProfileHelper::IsPrimaryProfile(profile)) {
     proxy_->SetManager(manager.get());
   }
-  return manager.release();
+  return manager;
 }
 
 void CupsPrintersManagerFactory::BrowserContextShutdown(
diff --git a/chrome/browser/ash/printing/cups_printers_manager_factory.h b/chrome/browser/ash/printing/cups_printers_manager_factory.h
index 862a5c919a7..b8a1832 100644
--- a/chrome/browser/ash/printing/cups_printers_manager_factory.h
+++ b/chrome/browser/ash/printing/cups_printers_manager_factory.h
@@ -43,7 +43,7 @@
   ~CupsPrintersManagerFactory() override;
 
   // BrowserContextKeyedServiceFactory overrides:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   void BrowserContextShutdown(content::BrowserContext* context) override;
   bool ServiceIsCreatedWithBrowserContext() const override;
diff --git a/chrome/browser/ash/printing/cups_proxy_service_manager_factory.cc b/chrome/browser/ash/printing/cups_proxy_service_manager_factory.cc
index 9df2bd3..c5b413a 100644
--- a/chrome/browser/ash/printing/cups_proxy_service_manager_factory.cc
+++ b/chrome/browser/ash/printing/cups_proxy_service_manager_factory.cc
@@ -37,7 +37,8 @@
 
 CupsProxyServiceManagerFactory::~CupsProxyServiceManagerFactory() = default;
 
-KeyedService* CupsProxyServiceManagerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+CupsProxyServiceManagerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   // Only create the service for the primary user.
   Profile* profile = Profile::FromBrowserContext(context);
@@ -47,7 +48,7 @@
     return nullptr;
   }
 
-  return new CupsProxyServiceManager(profile);
+  return std::make_unique<CupsProxyServiceManager>(profile);
 }
 
 bool CupsProxyServiceManagerFactory::ServiceIsCreatedWithBrowserContext()
diff --git a/chrome/browser/ash/printing/cups_proxy_service_manager_factory.h b/chrome/browser/ash/printing/cups_proxy_service_manager_factory.h
index ff273e7c..ef896599 100644
--- a/chrome/browser/ash/printing/cups_proxy_service_manager_factory.h
+++ b/chrome/browser/ash/printing/cups_proxy_service_manager_factory.h
@@ -34,7 +34,7 @@
   ~CupsProxyServiceManagerFactory() override;
 
   // BrowserContextKeyedServiceFactory overrides:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsCreatedWithBrowserContext() const override;
   bool ServiceIsNULLWhileTesting() const override;
diff --git a/chrome/browser/ash/printing/history/print_job_reporting_service_factory.cc b/chrome/browser/ash/printing/history/print_job_reporting_service_factory.cc
index 966ddc5..eab7d4a 100644
--- a/chrome/browser/ash/printing/history/print_job_reporting_service_factory.cc
+++ b/chrome/browser/ash/printing/history/print_job_reporting_service_factory.cc
@@ -35,11 +35,10 @@
 
 PrintJobReportingServiceFactory::~PrintJobReportingServiceFactory() = default;
 
-KeyedService* PrintJobReportingServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+PrintJobReportingServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  auto reporting_service = PrintJobReportingService::Create();
-
-  return reporting_service.release();
+  return PrintJobReportingService::Create();
 }
 
 bool PrintJobReportingServiceFactory::ServiceIsNULLWhileTesting() const {
diff --git a/chrome/browser/ash/printing/history/print_job_reporting_service_factory.h b/chrome/browser/ash/printing/history/print_job_reporting_service_factory.h
index 49b6dd2..965ee772 100644
--- a/chrome/browser/ash/printing/history/print_job_reporting_service_factory.h
+++ b/chrome/browser/ash/printing/history/print_job_reporting_service_factory.h
@@ -37,7 +37,7 @@
   ~PrintJobReportingServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsNULLWhileTesting() const override;
 };
diff --git a/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.cc b/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.cc
index d025528..575d907 100644
--- a/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.cc
+++ b/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.cc
@@ -39,10 +39,11 @@
 
 AuthorizationZonesManagerFactory::~AuthorizationZonesManagerFactory() = default;
 
-KeyedService* AuthorizationZonesManagerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+AuthorizationZonesManagerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return AuthorizationZonesManager::Create(Profile::FromBrowserContext(context))
-      .release();
+  return AuthorizationZonesManager::Create(
+      Profile::FromBrowserContext(context));
 }
 
 }  // namespace oauth2
diff --git a/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.h b/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.h
index c8e157f1..94e45a2 100644
--- a/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.h
+++ b/chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.h
@@ -36,7 +36,7 @@
   ~AuthorizationZonesManagerFactory() override;
 
   // BrowserContextKeyedServiceFactory overrides:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/ash/printing/print_management/printing_manager_factory.cc b/chrome/browser/ash/printing/print_management/printing_manager_factory.cc
index d7b2858..e3fcf3e 100644
--- a/chrome/browser/ash/printing/print_management/printing_manager_factory.cc
+++ b/chrome/browser/ash/printing/print_management/printing_manager_factory.cc
@@ -53,10 +53,10 @@
 PrintingManagerFactory::~PrintingManagerFactory() = default;
 
 // static
-KeyedService* PrintingManagerFactory::BuildInstanceFor(
+std::unique_ptr<KeyedService> PrintingManagerFactory::BuildInstanceFor(
     content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
-  return new PrintingManager(
+  return std::make_unique<PrintingManager>(
       PrintJobHistoryServiceFactory::GetForBrowserContext(context),
       HistoryServiceFactory::GetForProfile(profile,
                                            ServiceAccessType::EXPLICIT_ACCESS),
@@ -88,7 +88,8 @@
       std::make_unique<ash::print_management::PrintManagementDelegateImpl>());
 }
 
-KeyedService* PrintingManagerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+PrintingManagerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   return BuildInstanceFor(context);
 }
diff --git a/chrome/browser/ash/printing/print_management/printing_manager_factory.h b/chrome/browser/ash/printing/print_management/printing_manager_factory.h
index b3166cf..0c4403f4 100644
--- a/chrome/browser/ash/printing/print_management/printing_manager_factory.h
+++ b/chrome/browser/ash/printing/print_management/printing_manager_factory.h
@@ -33,7 +33,8 @@
  public:
   static PrintingManager* GetForProfile(Profile* profile);
   static PrintingManagerFactory* GetInstance();
-  static KeyedService* BuildInstanceFor(content::BrowserContext* profile);
+  static std::unique_ptr<KeyedService> BuildInstanceFor(
+      content::BrowserContext* profile);
   static void MaybeBindPrintManagementForWebUI(
       Profile* profile,
       mojo::PendingReceiver<
@@ -52,7 +53,7 @@
   PrintingManagerFactory& operator=(const PrintingManagerFactory&) = delete;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   void RegisterProfilePrefs(
       user_prefs::PrefRegistrySyncable* registry) override;
diff --git a/chrome/browser/ash/printing/print_management/printing_manager_factory_unittest.cc b/chrome/browser/ash/printing/print_management/printing_manager_factory_unittest.cc
index 25a8427..7270f6e5 100644
--- a/chrome/browser/ash/printing/print_management/printing_manager_factory_unittest.cc
+++ b/chrome/browser/ash/printing/print_management/printing_manager_factory_unittest.cc
@@ -23,8 +23,7 @@
 
 std::unique_ptr<KeyedService> BuildPrintingManager(
     content::BrowserContext* context) {
-  return std::unique_ptr<KeyedService>(
-      PrintingManagerFactory::BuildInstanceFor(context));
+  return PrintingManagerFactory::BuildInstanceFor(context);
 }
 
 std::unique_ptr<Profile> CreateProfile(std::string file_path) {
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc b/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
index 41813714..a8b7d850 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
+++ b/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
@@ -167,9 +167,9 @@
   event_router->BroadcastEvent(std::move(extension_event));
 }
 
-SettingsPrivateEventRouter* SettingsPrivateEventRouter::Create(
+std::unique_ptr<SettingsPrivateEventRouter> SettingsPrivateEventRouter::Create(
     content::BrowserContext* context) {
-  return new SettingsPrivateEventRouter(context);
+  return std::make_unique<SettingsPrivateEventRouter>(context);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_event_router.h b/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
index 7d2c5543..a16221f 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
+++ b/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
@@ -35,9 +35,10 @@
       public EventRouter::Observer,
       public settings_private::GeneratedPref::Observer {
  public:
-  static SettingsPrivateEventRouter* Create(
+  static std::unique_ptr<SettingsPrivateEventRouter> Create(
       content::BrowserContext* browser_context);
 
+  explicit SettingsPrivateEventRouter(content::BrowserContext* context);
   SettingsPrivateEventRouter(const SettingsPrivateEventRouter&) = delete;
   SettingsPrivateEventRouter& operator=(const SettingsPrivateEventRouter&) =
       delete;
@@ -50,8 +51,6 @@
   content::BrowserContext* context_for_test() { return context_; }
 
  protected:
-  explicit SettingsPrivateEventRouter(content::BrowserContext* context);
-
   // KeyedService overrides:
   void Shutdown() override;
 
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.cc b/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.cc
index bf49f8d..24c742f 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.cc
+++ b/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.cc
@@ -46,7 +46,8 @@
 SettingsPrivateEventRouterFactory::~SettingsPrivateEventRouterFactory() =
     default;
 
-KeyedService* SettingsPrivateEventRouterFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SettingsPrivateEventRouterFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   return SettingsPrivateEventRouter::Create(context);
 }
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h b/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h
index a16216ac..d831a361 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h
+++ b/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h
@@ -42,7 +42,7 @@
   ~SettingsPrivateEventRouterFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
 };
 
diff --git a/chrome/browser/extensions/chrome_app_icon_service_factory.cc b/chrome/browser/extensions/chrome_app_icon_service_factory.cc
index f6921e9..864a7cd 100644
--- a/chrome/browser/extensions/chrome_app_icon_service_factory.cc
+++ b/chrome/browser/extensions/chrome_app_icon_service_factory.cc
@@ -36,9 +36,10 @@
 
 ChromeAppIconServiceFactory::~ChromeAppIconServiceFactory() = default;
 
-KeyedService* ChromeAppIconServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ChromeAppIconServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new ChromeAppIconService(context);
+  return std::make_unique<ChromeAppIconService>(context);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_app_icon_service_factory.h b/chrome/browser/extensions/chrome_app_icon_service_factory.h
index 477d273..bfec8cf 100644
--- a/chrome/browser/extensions/chrome_app_icon_service_factory.h
+++ b/chrome/browser/extensions/chrome_app_icon_service_factory.h
@@ -31,7 +31,7 @@
   ChromeAppIconServiceFactory();
   ~ChromeAppIconServiceFactory() override;
 
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/feed/android/BUILD.gn b/chrome/browser/feed/android/BUILD.gn
index 2d43ffc..7b65c8f 100644
--- a/chrome/browser/feed/android/BUILD.gn
+++ b/chrome/browser/feed/android/BUILD.gn
@@ -25,6 +25,7 @@
     "java/src/org/chromium/chrome/browser/feed/FeedProcessScopeDependencyProvider.java",
     "java/src/org/chromium/chrome/browser/feed/FeedReliabilityLogger.java",
     "java/src/org/chromium/chrome/browser/feed/FeedReliabilityLoggingBridge.java",
+    "java/src/org/chromium/chrome/browser/feed/FeedResourceFetcher.java",
     "java/src/org/chromium/chrome/browser/feed/FeedScrollState.java",
     "java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java",
     "java/src/org/chromium/chrome/browser/feed/FeedServiceDependencyProviderFactory.java",
diff --git a/chrome/browser/feed/android/feed_surface_renderer_bridge.cc b/chrome/browser/feed/android/feed_surface_renderer_bridge.cc
index 26c08a2..1e5babc 100644
--- a/chrome/browser/feed/android/feed_surface_renderer_bridge.cc
+++ b/chrome/browser/feed/android/feed_surface_renderer_bridge.cc
@@ -46,6 +46,23 @@
   return feed::SurfaceId::FromUnsafeValue(surface_id);
 }
 
+ScopedJavaLocalRef<jobject> ToJava(JNIEnv* env,
+                                   const NetworkResponse& response) {
+  return Java_NetworkResponse_Constructor(
+      env, response.status_code == 200, response.status_code,
+      base::android::ToJavaArrayOfStrings(
+          env, response.response_header_names_and_values),
+      base::android::ToJavaByteArray(
+          env, reinterpret_cast<const uint8_t*>(response.response_bytes.data()),
+          response.response_bytes.size()));
+}
+
+void OnFetchResourceFinished(JNIEnv* env,
+                             const JavaRef<jobject>& callback,
+                             NetworkResponse response) {
+  base::android::RunObjectCallbackAndroid(callback, ToJava(env, response));
+}
+
 }  // namespace
 
 static jlong JNI_FeedSurfaceRendererBridge_Init(
@@ -167,6 +184,30 @@
                                   ScopedJavaGlobalRef<jobject>(callback_obj)));
 }
 
+void FeedSurfaceRendererBridge::FetchResource(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& j_url,
+    const JavaParamRef<jstring>& j_method,
+    const JavaParamRef<jobjectArray>& j_header_name_and_values,
+    const JavaParamRef<jbyteArray>& j_post_data,
+    const base::android::JavaParamRef<jobject>& callback_obj) {
+  if (!feed_stream_api_) {
+    return;
+  }
+  std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url);
+  std::vector<std::string> header_name_and_values;
+  AppendJavaStringArrayToStringVector(env, j_header_name_and_values,
+                                      &header_name_and_values);
+  std::string post_data;
+  base::android::JavaByteArrayToString(env, j_post_data, &post_data);
+  feed_stream_api_->FetchResource(
+      url ? *url : GURL(),
+      base::android::ConvertJavaStringToUTF8(env, j_method),
+      header_name_and_values, post_data,
+      base::BindOnce(&OnFetchResourceFinished, env,
+                     ScopedJavaGlobalRef<jobject>(callback_obj)));
+}
+
 static void JNI_FeedSurfaceRendererBridge_ProcessThereAndBackAgain(
     JNIEnv* env,
     const JavaParamRef<jbyteArray>& data,
diff --git a/chrome/browser/feed/android/feed_surface_renderer_bridge.h b/chrome/browser/feed/android/feed_surface_renderer_bridge.h
index 87e901b..fa8f81ae 100644
--- a/chrome/browser/feed/android/feed_surface_renderer_bridge.h
+++ b/chrome/browser/feed/android/feed_surface_renderer_bridge.h
@@ -52,6 +52,13 @@
 
   void ManualRefresh(JNIEnv* env,
                      const base::android::JavaParamRef<jobject>& callback_obj);
+  void FetchResource(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& j_url,
+      const base::android::JavaParamRef<jstring>& j_method,
+      const base::android::JavaParamRef<jobjectArray>& j_header_name_and_values,
+      const base::android::JavaParamRef<jbyteArray>& j_post_data,
+      const base::android::JavaParamRef<jobject>& callback_obj);
 
   void SurfaceOpened(JNIEnv* env);
   void SurfaceClosed(JNIEnv* env);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedResourceFetcher.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedResourceFetcher.java
new file mode 100644
index 0000000..20b4983
--- /dev/null
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedResourceFetcher.java
@@ -0,0 +1,88 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.feed;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.chrome.browser.feed.FeedSurfaceRendererBridge.NetworkResponse;
+import org.chromium.chrome.browser.xsurface.feed.ResourceFetcher;
+import org.chromium.chrome.browser.xsurface.feed.ResourceFetcher.Header;
+import org.chromium.chrome.browser.xsurface.feed.ResourceFetcher.Request;
+import org.chromium.chrome.browser.xsurface.feed.ResourceFetcher.Response;
+import org.chromium.chrome.browser.xsurface.feed.ResourceFetcher.ResponseCallback;
+import org.chromium.url.GURL;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of ResourceFetcher methods.
+ */
+public class FeedResourceFetcher implements ResourceFetcher {
+    @JNINamespace("feed::android")
+    public static class FeedResponse implements Response {
+        private final @Nullable byte[] mRawData;
+        private final boolean mSuccess;
+        private final int mStatusCode;
+        private final List<Header> mHeaders;
+
+        public FeedResponse(
+                boolean success, int statusCode, List<Header> headers, @Nullable byte[] rawData) {
+            mSuccess = success;
+            mStatusCode = statusCode;
+            mHeaders = headers;
+            mRawData = rawData;
+        }
+
+        @Override
+        public boolean getSuccess() {
+            return mSuccess;
+        }
+
+        @Override
+        public int getStatusCode() {
+            return mStatusCode;
+        }
+
+        @Override
+        public List<Header> getHeaders() {
+            return mHeaders;
+        }
+
+        @Override
+        public @Nullable byte[] getRawData() {
+            return mRawData;
+        }
+
+        @CalledByNative
+        static FeedResponse create(
+                boolean success, int statusCode, List<Header> headers, @Nullable byte[] rawData) {
+            return new FeedResponse(success, statusCode, headers, rawData);
+        }
+    }
+
+    private FeedSurfaceRendererBridge mBridge;
+
+    public FeedResourceFetcher(FeedSurfaceRendererBridge bridge) {
+        mBridge = bridge;
+    }
+
+    @Override
+    public void fetch(Request request, ResponseCallback responseCallback) {
+        List<String> headerNamesAndValues = new ArrayList<String>(request.headers.size() * 2);
+        for (Header header : request.headers) {
+            headerNamesAndValues.add(header.name);
+            headerNamesAndValues.add(header.value);
+        }
+        mBridge.fetchResource(new GURL(request.uri), request.method,
+                headerNamesAndValues.toArray(new String[headerNamesAndValues.size()]),
+                request.postData, (NetworkResponse response) -> {
+                    responseCallback.onResponse(new FeedResponse(
+                            response.success, response.statusCode, null, response.rawData));
+                });
+    }
+}
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
index ab23592..a8b6e119 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
@@ -54,6 +54,7 @@
 import org.chromium.chrome.browser.xsurface.feed.FeedActionsHandler;
 import org.chromium.chrome.browser.xsurface.feed.FeedSurfaceScope;
 import org.chromium.chrome.browser.xsurface.feed.FeedUserInteractionReliabilityLogger.ClosedReason;
+import org.chromium.chrome.browser.xsurface.feed.ResourceFetcher;
 import org.chromium.chrome.browser.xsurface.feed.StreamType;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
@@ -549,6 +550,11 @@
             mBridge.reportOtherUserAction(FeedUserActionType.NON_SWIPE_MANUAL_REFRESH);
             mStreamsMediator.refreshStream();
         }
+
+        @Override
+        public ResourceFetcher getAsyncDataFetcher() {
+            return new FeedResourceFetcher(mBridge);
+        }
     }
 
     private class RotationObserver implements DisplayAndroid.DisplayAndroidObserver {
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceRendererBridge.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceRendererBridge.java
index bf587dd..02c24576 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceRendererBridge.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceRendererBridge.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.feed;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
@@ -39,6 +40,22 @@
         }
     }
 
+    public static class NetworkResponse {
+        public boolean success;
+        public int statusCode;
+        public String[] headerNameAndValues;
+        public @Nullable byte[] rawData;
+
+        @CalledByNative("NetworkResponse")
+        public NetworkResponse(boolean success, int statusCode, String[] headerNameAndValues,
+                @Nullable byte[] rawData) {
+            this.success = success;
+            this.statusCode = statusCode;
+            this.headerNameAndValues = headerNameAndValues;
+            this.rawData = rawData;
+        }
+    }
+
     public FeedSurfaceRendererBridge(Renderer renderer,
             FeedReliabilityLoggingBridge reliabilityLoggingBridge, @StreamKind int streamKind,
             SingleWebFeedParameters webFeedParameters) {
@@ -108,6 +125,16 @@
         }
         FeedSurfaceRendererBridgeJni.get().manualRefresh(mNativeSurfaceRenderer, callback);
     }
+    void fetchResource(GURL url, String method, String[] headerNameAndValues, byte[] postData,
+            Callback<NetworkResponse> callback) {
+        // Cancel if destroyed.
+        if (mRenderer == null) {
+            return;
+        }
+        FeedSurfaceRendererBridgeJni.get().fetchResource(
+                mNativeSurfaceRenderer, url, method, headerNameAndValues, postData, callback);
+    }
+
     void surfaceOpened() {
         // Cancel if destroyed.
         if (mRenderer == null) {
@@ -122,7 +149,6 @@
         }
         FeedSurfaceRendererBridgeJni.get().surfaceClosed(mNativeSurfaceRenderer);
     }
-
     //
     // Methods which may be called after destroy().
     //
@@ -210,6 +236,8 @@
         void destroy(long nativeFeedSurfaceRendererBridge);
         void loadMore(long nativeFeedSurfaceRendererBridge, Callback<Boolean> callback);
         void manualRefresh(long nativeFeedSurfaceRendererBridge, Callback<Boolean> callback);
+        void fetchResource(long nativeFeedSurfaceRendererBridge, GURL url, String method,
+                String[] headerNameAndValues, byte[] postData, Callback<NetworkResponse> callback);
         int getSurfaceId(long nativeFeedSurfaceRendererBridge);
         void surfaceOpened(long nativeFeedSurfaceRendererBridge);
         void surfaceClosed(long nativeFeedSurfaceRendererBridge);
diff --git a/chrome/browser/feedback/show_feedback_page_lacros_browsertest.cc b/chrome/browser/feedback/show_feedback_page_lacros_browsertest.cc
index 55b8719..22c4abbe 100644
--- a/chrome/browser/feedback/show_feedback_page_lacros_browsertest.cc
+++ b/chrome/browser/feedback/show_feedback_page_lacros_browsertest.cc
@@ -20,16 +20,13 @@
 
  protected:
   void SetUp() override {
-    // TODO(crbug.com/1473375): Check against the exact ash version with ash
-    // browser window API support in crosapi::mojom::TestController once the
-    // implementation cl has landed.
-    if (IsRunningAgainstOlderAsh()) {
+    if (GetAshChromeVersion() < base::Version({118, 0, 5962})) {
       // For the older ash version without the ash browser window API
       // support in crosapi::mojom::TestController, we can't verify and close
       // feedback SWA in ash. Therefore, it still needs to run against the
       // unique ash.
-      // TODO(crbug/1446083): Remove the unique ash code once ash browser window
-      // API is supported in stable ash.
+      // TODO(crbug/1446083): Remove the unique ash code once ash stable
+      // version >= 118.0.5962.0.
       StartUniqueAshChrome(
           {}, {}, {}, "crbug.com/1446083 The test leaves Ash windows behind");
     }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 6d8ac2a1..207e3581 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -667,11 +667,6 @@
     "expiry_milestone": 120
   },
   {
-    "name": "autofill-enable-virtual-card",
-    "owners": [ "siyua", "jsaul@google.com", "aneeshali@google.com" ],
-    "expiry_milestone": 112
-  },
-    {
     "name": "autofill-enable-virtual-card-fido-enrollment",
     "owners": [ "siyua", "jsaul@google.com"],
     "expiry_milestone": 120
@@ -1877,6 +1872,11 @@
     "expiry_milestone": 120
   },
   {
+    "name": "draw-immediately-when-interactive",
+    "owners": [ "vollick" ],
+    "expiry_milestone": 125
+  },
+  {
     "name": "draw-predicted-ink-point",
     "owners": [ "joalmei@microsoft.com" ],
     "expiry_milestone": 98
@@ -7164,11 +7164,6 @@
     "expiry_milestone": 122
   },
   {
-    "name": "screen-saver-preview",
-    "owners": [ "safarli", "assistive-eng@google.com" ],
-    "expiry_milestone": 116
-  },
-  {
     "name": "screen-time-integration-ios",
     "owners": [ "edchin", "bling-flags@google.com" ],
     "expiry_milestone": 92
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index df53300..a32e6b2 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -548,12 +548,6 @@
     "card is FIDO eligible the user will be prompted to register the virtual "
     "card into FIDO.";
 
-const char kAutofillEnableVirtualCardName[] =
-    "Offer to use cloud token virtual card in Autofill";
-const char kAutofillEnableVirtualCardDescription[] =
-    "When enabled, if all requirements are met, Autofill will offer to use "
-    "virtual credit cards in form filling.";
-
 const char kAutofillEnableNewSaveCardBubbleUiName[] =
     "Update UI messaging and banner image for credit card upload save";
 const char kAutofillEnableNewSaveCardBubbleUiDescription[] =
@@ -1713,6 +1707,11 @@
 const char kFillingAcrossAffiliatedWebsitesDescription[] =
     "Enables filling password on a website when there is saved "
     "password on affiliated website.";
+const char kDrawImmediatelyWhenInteractiveName[] =
+    "Enable Immediate Draw When Interactive";
+const char kDrawImmediatelyWhenInteractiveDescription[] =
+    "Causes viz to activate and draw frames immediately during a touch "
+    "interaction or scroll.";
 #endif
 
 const char kFillingAcrossGroupedSitesName[] =
@@ -3011,11 +3010,6 @@
 const char kScreenSaverDurationDescription[] =
     "Allow users to customize screen saver running time.";
 
-const char kScreenSaverPreviewName[] = "Screen saver preview";
-const char kScreenSaverPreviewDescription[] =
-    "Enables the screen saver preview feature which allows the users to "
-    "preview current screen saver.";
-
 const char kScrollableTabStripFlagId[] = "scrollable-tabstrip";
 const char kScrollableTabStripName[] = "Tab Scrolling";
 const char kScrollableTabStripDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index e7c04e8..17fd2931 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -313,9 +313,6 @@
 extern const char kAutofillEnableVirtualCardFidoEnrollmentName[];
 extern const char kAutofillEnableVirtualCardFidoEnrollmentDescription[];
 
-extern const char kAutofillEnableVirtualCardName[];
-extern const char kAutofillEnableVirtualCardDescription[];
-
 extern const char kAutofillEnableNewSaveCardBubbleUiName[];
 extern const char kAutofillEnableNewSaveCardBubbleUiDescription[];
 
@@ -966,6 +963,9 @@
 #if BUILDFLAG(IS_ANDROID)
 extern const char kFillingAcrossAffiliatedWebsitesName[];
 extern const char kFillingAcrossAffiliatedWebsitesDescription[];
+
+extern const char kDrawImmediatelyWhenInteractiveName[];
+extern const char kDrawImmediatelyWhenInteractiveDescription[];
 #endif
 
 extern const char kFillingAcrossGroupedSitesName[];
@@ -1722,9 +1722,6 @@
 extern const char kScreenSaverDurationName[];
 extern const char kScreenSaverDurationDescription[];
 
-extern const char kScreenSaverPreviewName[];
-extern const char kScreenSaverPreviewDescription[];
-
 extern const char kScrollableTabStripFlagId[];
 extern const char kScrollableTabStripName[];
 extern const char kScrollableTabStripDescription[];
diff --git a/chrome/browser/ip_protection/blind_sign_http_impl.cc b/chrome/browser/ip_protection/blind_sign_http_impl.cc
index a30e296..362a739 100644
--- a/chrome/browser/ip_protection/blind_sign_http_impl.cc
+++ b/chrome/browser/ip_protection/blind_sign_http_impl.cc
@@ -9,6 +9,7 @@
 #include "base/strings/strcat.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "net/base/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
@@ -57,7 +58,11 @@
 BlindSignHttpImpl::BlindSignHttpImpl(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
     : url_loader_factory_(std::move(url_loader_factory)),
-      ip_protection_server_url_(BlindSignHttpImpl::kIpProtectionServerUrl) {
+      ip_protection_server_url_(net::features::kIpPrivacyTokenServer.Get()),
+      ip_protection_server_get_initial_data_path_(
+          net::features::kIpPrivacyTokenServerGetInitialDataPath.Get()),
+      ip_protection_server_get_tokens_path_(
+          net::features::kIpPrivacyTokenServerGetTokensPath.Get()) {
   CHECK(url_loader_factory_);
 }
 
@@ -72,18 +77,24 @@
   GURL::Replacements replacements;
   switch (request_type) {
     case quiche::BlindSignHttpRequestType::kGetInitialData:
-      replacements.SetPathStr(kIpProtectionServerGetInitialDataPath);
+      replacements.SetPathStr(ip_protection_server_get_initial_data_path_);
       break;
     case quiche::BlindSignHttpRequestType::kAuthAndSign:
-      replacements.SetPathStr(kIpProtectionServerAuthAndSignPath);
+      replacements.SetPathStr(ip_protection_server_get_tokens_path_);
       break;
     case quiche::BlindSignHttpRequestType::kUnknown:
       NOTREACHED_NORETURN();
   }
 
+  GURL request_url = ip_protection_server_url_.ReplaceComponents(replacements);
+  if (!request_url.is_valid()) {
+    std::move(callback_)(
+        absl::InternalError("Invalid IP Protection Token URL"));
+    return;
+  }
+
   auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->url =
-      ip_protection_server_url_.ReplaceComponents(replacements);
+  resource_request->url = std::move(request_url);
   resource_request->method = net::HttpRequestHeaders::kPostMethod;
   resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
   resource_request->headers.SetHeader(
diff --git a/chrome/browser/ip_protection/blind_sign_http_impl.h b/chrome/browser/ip_protection/blind_sign_http_impl.h
index 9625cbd..aa567c3 100644
--- a/chrome/browser/ip_protection/blind_sign_http_impl.h
+++ b/chrome/browser/ip_protection/blind_sign_http_impl.h
@@ -18,14 +18,6 @@
 }  // namespace network
 class BlindSignHttpImpl : public quiche::BlindSignHttpInterface {
  public:
-  // TODO(https://crbug.com/1444621): Make these configurable via Finch.
-  static constexpr char kIpProtectionServerUrl[] =
-      "https://autopush-phosphor-pa.sandbox.googleapis.com";
-  static constexpr char kIpProtectionServerGetInitialDataPath[] =
-      "/v1/getInitialData";
-  static constexpr char kIpProtectionServerAuthAndSignPath[] =
-      "/v1/authWithHeaderCreds";
-
   explicit BlindSignHttpImpl(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
   ~BlindSignHttpImpl() override;
@@ -42,6 +34,8 @@
   quiche::BlindSignHttpCallback callback_;
 
   const GURL ip_protection_server_url_;
+  const std::string ip_protection_server_get_initial_data_path_;
+  const std::string ip_protection_server_get_tokens_path_;
 
   base::WeakPtrFactory<BlindSignHttpImpl> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/ip_protection/blind_sign_http_impl_unittest.cc b/chrome/browser/ip_protection/blind_sign_http_impl_unittest.cc
index 85a790e5..1797b96 100644
--- a/chrome/browser/ip_protection/blind_sign_http_impl_unittest.cc
+++ b/chrome/browser/ip_protection/blind_sign_http_impl_unittest.cc
@@ -5,11 +5,13 @@
 
 #include "base/strings/strcat.h"
 #include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "net/base/features.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
@@ -23,6 +25,14 @@
     http_fetcher_ = std::make_unique<BlindSignHttpImpl>(
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_));
+    token_server_get_initial_data_url_ = GURL(base::StrCat(
+        {net::features::kIpPrivacyTokenServer.Get(),
+         net::features::kIpPrivacyTokenServerGetInitialDataPath.Get()}));
+    ASSERT_TRUE(token_server_get_initial_data_url_.is_valid());
+    token_server_get_tokens_url_ = GURL(base::StrCat(
+        {net::features::kIpPrivacyTokenServer.Get(),
+         net::features::kIpPrivacyTokenServerGetTokensPath.Get()}));
+    ASSERT_TRUE(token_server_get_tokens_url_.is_valid());
   }
 
   base::test::TaskEnvironment task_environment_;
@@ -30,6 +40,8 @@
   std::unique_ptr<BlindSignHttpImpl> http_fetcher_;
   std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
       identity_test_env_adaptor_;
+  GURL token_server_get_initial_data_url_;
+  GURL token_server_get_tokens_url_;
 };
 
 TEST_F(BlindSignHttpImplTest, DoRequestSendsCorrectRequest) {
@@ -40,11 +52,8 @@
   // Set up the response to return from the mock.
   auto head = network::mojom::URLResponseHead::New();
   std::string response_body = "Response body";
-  GURL test_url = GURL(
-      base::StrCat({BlindSignHttpImpl::kIpProtectionServerUrl,
-                    BlindSignHttpImpl::kIpProtectionServerGetInitialDataPath}));
   test_url_loader_factory_.AddResponse(
-      test_url, std::move(head), response_body,
+      token_server_get_initial_data_url_, std::move(head), response_body,
       network::URLLoaderCompletionStatus(net::OK));
 
   base::test::TestFuture<absl::StatusOr<quiche::BlindSignHttpResponse>>
@@ -75,11 +84,8 @@
   // Mock no response from Authentication Server (such as a network error).
   std::string response_body;
   auto head = network::mojom::URLResponseHead::New();
-  GURL test_url = GURL(
-      base::StrCat({BlindSignHttpImpl::kIpProtectionServerUrl,
-                    BlindSignHttpImpl::kIpProtectionServerAuthAndSignPath}));
   test_url_loader_factory_.AddResponse(
-      test_url, std::move(head), response_body,
+      token_server_get_tokens_url_, std::move(head), response_body,
       network::URLLoaderCompletionStatus(net::ERR_FAILED));
 
   base::test::TestFuture<absl::StatusOr<quiche::BlindSignHttpResponse>>
@@ -99,6 +105,41 @@
   EXPECT_EQ(absl::StatusCode::kInternal, result.status().code());
 }
 
+TEST_F(BlindSignHttpImplTest, DoRequestInvalidFinchParametersFailsGracefully) {
+  std::map<std::string, std::string> parameters;
+  parameters["IpPrivacyTokenServer"] = "<(^_^)>";
+  parameters["IpPrivacyTokenServerGetInitialDataPath"] = "(>_<)";
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeatureWithParameters(
+      net::features::kEnableIpProtectionProxy, std::move(parameters));
+
+  // Create a new BlindSignHttpImpl for this test so that the new FeatureParams
+  // get used.
+  std::unique_ptr<BlindSignHttpImpl> http_fetcher =
+      std::make_unique<BlindSignHttpImpl>(
+          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+              &test_url_loader_factory_));
+
+  auto request_type = quiche::BlindSignHttpRequestType::kGetInitialData;
+  std::string authorization_header = "token";
+  std::string body = "body";
+
+  base::test::TestFuture<absl::StatusOr<quiche::BlindSignHttpResponse>>
+      result_future;
+  auto callback =
+      [&result_future](absl::StatusOr<quiche::BlindSignHttpResponse> response) {
+        result_future.SetValue(std::move(response));
+      };
+
+  http_fetcher->DoRequest(request_type, authorization_header, body,
+                          std::move(callback));
+
+  absl::StatusOr<quiche::BlindSignHttpResponse> result = result_future.Get();
+
+  EXPECT_EQ("Invalid IP Protection Token URL", result.status().message());
+  EXPECT_EQ(absl::StatusCode::kInternal, result.status().code());
+}
+
 TEST_F(BlindSignHttpImplTest, DoRequestHttpFailureStatus) {
   auto request_type = quiche::BlindSignHttpRequestType::kAuthAndSign;
   std::string authorization_header = "token";
@@ -107,11 +148,8 @@
   // Mock a non-200 HTTP response from Authentication Server.
   std::string response_body;
   auto head = network::mojom::URLResponseHead::New();
-  GURL test_url = GURL(
-      base::StrCat({BlindSignHttpImpl::kIpProtectionServerUrl,
-                    BlindSignHttpImpl::kIpProtectionServerAuthAndSignPath}));
-  test_url_loader_factory_.AddResponse(test_url.spec(), response_body,
-                                       net::HTTP_BAD_REQUEST);
+  test_url_loader_factory_.AddResponse(token_server_get_tokens_url_.spec(),
+                                       response_body, net::HTTP_BAD_REQUEST);
 
   base::test::TestFuture<absl::StatusOr<quiche::BlindSignHttpResponse>>
       result_future;
diff --git a/chrome/browser/lacros/lacros_extension_apps_publisher.cc b/chrome/browser/lacros/lacros_extension_apps_publisher.cc
index 10a33a7..7eff9752 100644
--- a/chrome/browser/lacros/lacros_extension_apps_publisher.cc
+++ b/chrome/browser/lacros/lacros_extension_apps_publisher.cc
@@ -17,13 +17,18 @@
 #include "chrome/browser/extensions/extension_ui_util.h"
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/lacros/lacros_extensions_util.h"
+#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/lacros/window_utility.h"
+#include "chrome/browser/web_applications/web_app_tab_helper.h"
 #include "chromeos/crosapi/mojom/app_window_tracker.mojom.h"
 #include "chromeos/lacros/lacros_service.h"
+#include "components/app_constants/constants.h"
+#include "components/services/app_service/public/cpp/app_capability_access_cache.h"
 #include "components/services/app_service/public/cpp/app_types.h"
 #include "components/services/app_service/public/cpp/icon_types.h"
 #include "components/services/app_service/public/cpp/intent_filter.h"
+#include "content/public/browser/web_contents.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/extension_prefs.h"
@@ -403,6 +408,13 @@
     profile_trackers_[profile] =
         std::make_unique<ProfileTracker>(profile, this, which_type_);
   }
+
+  // Only track the media usage for the chrome apps.
+  if (which_type_.IsChromeApps()) {
+    media_dispatcher_.Observe(MediaCaptureDevicesDispatcher::GetInstance()
+                                  ->GetMediaStreamCaptureIndicator()
+                                  .get());
+  }
 }
 
 bool LacrosExtensionAppsPublisher::InitializeCrosapi() {
@@ -442,6 +454,11 @@
   publisher_->OnApps(std::move(apps));
 }
 
+void LacrosExtensionAppsPublisher::PublishCapabilityAccesses(
+    std::vector<apps::CapabilityAccessPtr> accesses) {
+  publisher_->OnCapabilityAccesses(std::move(accesses));
+}
+
 void LacrosExtensionAppsPublisher::OnAppWindowAdded(
     const std::string& app_id,
     const std::string& window_id) {
@@ -501,3 +518,63 @@
   DCHECK(matched != profile_trackers_.end());
   matched->second->Publish(extension, apps::Readiness::kReady);
 }
+
+void LacrosExtensionAppsPublisher::OnIsCapturingVideoChanged(
+    content::WebContents* web_contents,
+    bool is_capturing_video) {
+  auto app_id = MaybeGetAppId(web_contents);
+  if (!app_id.has_value()) {
+    return;
+  }
+
+  auto result = media_requests_.UpdateCameraState(app_id.value(), web_contents,
+                                                  is_capturing_video);
+  ModifyCapabilityAccess(app_id.value(), result.camera, result.microphone);
+}
+
+void LacrosExtensionAppsPublisher::OnIsCapturingAudioChanged(
+    content::WebContents* web_contents,
+    bool is_capturing_audio) {
+  auto app_id = MaybeGetAppId(web_contents);
+  if (!app_id.has_value()) {
+    return;
+  }
+
+  auto result = media_requests_.UpdateMicrophoneState(
+      app_id.value(), web_contents, is_capturing_audio);
+  ModifyCapabilityAccess(app_id.value(), result.camera, result.microphone);
+}
+
+absl::optional<std::string> LacrosExtensionAppsPublisher::MaybeGetAppId(
+    content::WebContents* web_contents) {
+  // The web app publisher is responsible to handle `web_contents` for web
+  // apps.
+  const web_app::AppId* web_app_id =
+      web_app::WebAppTabHelper::GetAppId(web_contents);
+  if (web_app_id) {
+    return absl::nullopt;
+  }
+
+  const auto* extension =
+      lacros_extensions_util::MaybeGetExtension(web_contents);
+  return (extension && which_type_.Matches(extension))
+             ? absl::make_optional<std::string>(extension->id())
+             : absl::nullopt;
+}
+
+void LacrosExtensionAppsPublisher::ModifyCapabilityAccess(
+    const std::string& app_id,
+    absl::optional<bool> accessing_camera,
+    absl::optional<bool> accessing_microphone) {
+  if (!accessing_camera.has_value() && !accessing_microphone.has_value()) {
+    return;
+  }
+
+  std::vector<apps::CapabilityAccessPtr> capability_accesses;
+  auto capability_access = std::make_unique<apps::CapabilityAccess>(app_id);
+  capability_access->camera = accessing_camera;
+  capability_access->microphone = accessing_microphone;
+  capability_accesses.push_back(std::move(capability_access));
+
+  PublishCapabilityAccesses(std::move(capability_accesses));
+}
diff --git a/chrome/browser/lacros/lacros_extension_apps_publisher.h b/chrome/browser/lacros/lacros_extension_apps_publisher.h
index 3f13ae4..a4e125d 100644
--- a/chrome/browser/lacros/lacros_extension_apps_publisher.h
+++ b/chrome/browser/lacros/lacros_extension_apps_publisher.h
@@ -10,13 +10,21 @@
 #include <vector>
 
 #include "base/scoped_observation.h"
+#include "chrome/browser/apps/app_service/media_requests.h"
 #include "chrome/browser/lacros/for_which_extension_type.h"
+#include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_manager_observer.h"
 #include "chrome/browser/profiles/profile_observer.h"
 #include "chromeos/crosapi/mojom/app_service.mojom.h"
+#include "components/services/app_service/public/cpp/app_capability_access_cache.h"
 #include "components/services/app_service/public/cpp/app_types.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
 
 // This class tracks Chrome apps [i.e. extension-based apps, AKA v2 packaged
 // apps] or extensions running in Lacros, and forwards metadata about these
@@ -39,7 +47,9 @@
 //
 // See LacrosExtensionAppsController for the class responsible for receiving
 // events from Ash.
-class LacrosExtensionAppsPublisher : public ProfileManagerObserver {
+class LacrosExtensionAppsPublisher
+    : public ProfileManagerObserver,
+      public MediaStreamCaptureIndicator::Observer {
  public:
   static std::unique_ptr<LacrosExtensionAppsPublisher> MakeForChromeApps();
   static std::unique_ptr<LacrosExtensionAppsPublisher> MakeForExtensions();
@@ -71,6 +81,11 @@
   // Virtual for testing.
   virtual void Publish(std::vector<apps::AppPtr> apps);
 
+  // Publishes differential CapabilityAccess updates to the App_Service in Ash
+  // via crosapi. Virtual for testing.
+  virtual void PublishCapabilityAccesses(
+      std::vector<apps::CapabilityAccessPtr> accesses);
+
   // Notifies Ash's app window tracker of an app window construction. For Chrome
   // apps only. Virtual for testing.
   virtual void OnAppWindowAdded(const std::string& app_id,
@@ -95,6 +110,18 @@
   void OnProfileMarkedForPermanentDeletion(Profile* profile) override;
   void OnProfileManagerDestroying() override;
 
+  // MediaStreamCaptureIndicator::Observer
+  void OnIsCapturingVideoChanged(content::WebContents* web_contents,
+                                 bool is_capturing_video) override;
+  void OnIsCapturingAudioChanged(content::WebContents* web_contents,
+                                 bool is_capturing_audio) override;
+
+  absl::optional<std::string> MaybeGetAppId(content::WebContents* web_contents);
+
+  void ModifyCapabilityAccess(const std::string& app_id,
+                              absl::optional<bool> accessing_camera,
+                              absl::optional<bool> accessing_microphone);
+
   // State to decide which extension type (e.g., Chrome Apps vs. Extensions)
   // to support.
   const ForWhichExtensionType which_type_;
@@ -108,6 +135,15 @@
   // Scoped observer for the ProfileManager.
   base::ScopedObservation<ProfileManager, ProfileManagerObserver>
       profile_manager_observation_{this};
+
+  // Scoped observer for the MediaStreamCaptureIndicator.
+  base::ScopedObservation<MediaStreamCaptureIndicator,
+                          MediaStreamCaptureIndicator::Observer>
+      media_dispatcher_{this};
+
+  // Tracks the media usage for each app (e.g. accessing camera, microphone) on
+  // a per-WebContents basis.
+  apps::MediaRequests media_requests_;
 };
 
 #endif  // CHROME_BROWSER_LACROS_LACROS_EXTENSION_APPS_PUBLISHER_H_
diff --git a/chrome/browser/lacros/lacros_extension_apps_publisher_browsertest.cc b/chrome/browser/lacros/lacros_extension_apps_publisher_browsertest.cc
index aa1fcde..32ee0384 100644
--- a/chrome/browser/lacros/lacros_extension_apps_publisher_browsertest.cc
+++ b/chrome/browser/lacros/lacros_extension_apps_publisher_browsertest.cc
@@ -11,9 +11,14 @@
 #include "chrome/browser/extensions/extension_keeplist_chromeos.h"
 #include "chrome/browser/lacros/for_which_extension_type.h"
 #include "chrome/browser/lacros/lacros_extensions_util.h"
+#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
+#include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/browser/ui/lacros/window_utility.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/crosapi/mojom/app_service_types.mojom.h"
+#include "components/app_constants/constants.h"
+#include "components/services/app_service/public/cpp/app_capability_access_cache.h"
 #include "components/services/app_service/public/cpp/app_types.h"
 #include "content/public/test/browser_test.h"
 #include "extensions/browser/app_window/app_window.h"
@@ -21,11 +26,15 @@
 #include "extensions/browser/app_window/native_app_window.h"
 #include "extensions/common/constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/mediastream/media_stream_request.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/aura/window.h"
 
 namespace {
 
 using Apps = std::vector<apps::AppPtr>;
+using Accesses = std::vector<apps::CapabilityAccessPtr>;
 
 // This fake intercepts and tracks all calls to Publish().
 class LacrosExtensionAppsPublisherFake : public LacrosExtensionAppsPublisher {
@@ -45,14 +54,45 @@
   LacrosExtensionAppsPublisherFake& operator=(
       const LacrosExtensionAppsPublisherFake&) = delete;
 
+  void VerifyAppCapabilityAccess(const std::string& app_id,
+                                 size_t count,
+                                 absl::optional<bool> accessing_camera,
+                                 absl::optional<bool> accessing_microphone) {
+    ASSERT_EQ(count, accesses_history().size());
+    Accesses& accesses = accesses_history().back();
+    ASSERT_EQ(1u, accesses.size());
+    EXPECT_EQ(app_id, accesses[0]->app_id);
+
+    if (accessing_camera.has_value()) {
+      ASSERT_TRUE(accesses[0]->camera.has_value());
+      EXPECT_EQ(accessing_camera.value(), accesses[0]->camera.value());
+    } else {
+      ASSERT_FALSE(accesses[0]->camera.has_value());
+    }
+
+    if (accessing_microphone.has_value()) {
+      ASSERT_TRUE(accesses[0]->microphone.has_value());
+      EXPECT_EQ(accessing_microphone.value(), accesses[0]->microphone.value());
+    } else {
+      ASSERT_FALSE(accesses[0]->microphone.has_value());
+    }
+  }
+
   std::vector<Apps>& apps_history() { return apps_history_; }
 
+  std::vector<Accesses>& accesses_history() { return accesses_history_; }
+
   std::map<std::string, std::string>& app_windows() { return app_windows_; }
 
  private:
   // Override to intercept calls to Publish().
   void Publish(Apps apps) override { apps_history_.push_back(std::move(apps)); }
 
+  // Override to intercept calls to PublishCapabilityAccesses().
+  void PublishCapabilityAccesses(Accesses accesses) override {
+    accesses_history_.push_back(std::move(accesses));
+  }
+
   // Override to intercept calls to OnAppWindowAdded().
   void OnAppWindowAdded(const std::string& app_id,
                         const std::string& window_id) override {
@@ -73,6 +113,10 @@
   // Holds the contents of all calls to Publish() in chronological order.
   std::vector<Apps> apps_history_;
 
+  // Holds the contents of all calls to PublishCapabilityAccesses() in
+  // chronological order.
+  std::vector<Accesses> accesses_history_;
+
   // Holds the list of currently showing app windows, as seen by
   // OnAppWindowAdded() and OnAppWindowRemoved(). The key is the window_id and
   // the value is the app_id.
@@ -103,6 +147,34 @@
   ASSERT_FALSE(default_app->is_platform_app.value());
 }
 
+// Adds a fake media device with the specified `stream_type` and starts
+// capturing. Returns a closure to stop the capturing.
+base::OnceClosure StartMediaCapture(content::WebContents* web_contents,
+                                    blink::mojom::MediaStreamType stream_type) {
+  blink::mojom::StreamDevices fake_devices;
+  blink::MediaStreamDevice device(stream_type, "fake_device", "fake_device");
+
+  if (blink::IsAudioInputMediaType(stream_type)) {
+    fake_devices.audio_device = device;
+  } else {
+    fake_devices.video_device = device;
+  }
+
+  std::unique_ptr<content::MediaStreamUI> ui =
+      MediaCaptureDevicesDispatcher::GetInstance()
+          ->GetMediaStreamCaptureIndicator()
+          ->RegisterMediaStream(web_contents, fake_devices);
+
+  ui->OnStarted(base::RepeatingClosure(),
+                content::MediaStreamUI::SourceCallback(),
+                /*label=*/std::string(), /*screen_capture_ids=*/{},
+                content::MediaStreamUI::StateChangeCallback());
+
+  return base::BindOnce(
+      [](std::unique_ptr<content::MediaStreamUI> ui) { ui.reset(); },
+      std::move(ui));
+}
+
 using LacrosExtensionAppsPublisherTest = extensions::ExtensionBrowserTest;
 
 // When publisher is created and initialized, only chrome default apps
@@ -302,4 +374,44 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(LacrosExtensionAppsPublisherTest,
+                       RequestAccessingForPlatformApp) {
+  const extensions::Extension* extension =
+      LoadAndLaunchApp(test_data_dir_.AppendASCII("platform_apps/minimal"));
+  ASSERT_TRUE(extension);
+
+  std::unique_ptr<LacrosExtensionAppsPublisherFake> publisher =
+      std::make_unique<LacrosExtensionAppsPublisherFake>();
+  publisher->Initialize();
+
+  auto* registry = extensions::AppWindowRegistry::Get(profile());
+  extensions::AppWindow* app_window =
+      registry->GetCurrentAppWindowForApp(extension->id());
+  ASSERT_TRUE(app_window);
+  content::WebContents* web_contents = app_window->web_contents();
+  ASSERT_TRUE(web_contents);
+
+  // Request accessing the camera for `web_contents`.
+  base::OnceClosure video_closure = StartMediaCapture(
+      web_contents, blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE);
+  publisher->VerifyAppCapabilityAccess(extension->id(), 1u, true,
+                                       absl::nullopt);
+
+  // Request accessing the microphone for `web_contents`.
+  base::OnceClosure audio_closure = StartMediaCapture(
+      web_contents, blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE);
+  publisher->VerifyAppCapabilityAccess(extension->id(), 2u, absl::nullopt,
+                                       true);
+
+  // Stop accessing the microphone for `web_contents`.
+  std::move(audio_closure).Run();
+  publisher->VerifyAppCapabilityAccess(extension->id(), 3u, absl::nullopt,
+                                       false);
+
+  // Stop accessing the camera for `web_contents`.
+  std::move(video_closure).Run();
+  publisher->VerifyAppCapabilityAccess(extension->id(), 4u, false,
+                                       absl::nullopt);
+}
+
 }  // namespace
diff --git a/chrome/browser/lacros/lacros_extensions_util.cc b/chrome/browser/lacros/lacros_extensions_util.cc
index 1f8d2fad..77336d24 100644
--- a/chrome/browser/lacros/lacros_extensions_util.cc
+++ b/chrome/browser/lacros/lacros_extensions_util.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_features.h"
+#include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 
@@ -35,6 +36,19 @@
   return registry->GetInstalledExtension(extension_id);
 }
 
+const extensions::Extension* MaybeGetExtension(
+    content::WebContents* web_contents) {
+  if (!web_contents) {
+    return nullptr;
+  }
+
+  extensions::ExtensionRegistry* registry = extensions::ExtensionRegistry::Get(
+      Profile::FromBrowserContext(web_contents->GetBrowserContext()));
+  DCHECK(registry);
+  const extensions::ExtensionSet& extensions = registry->enabled_extensions();
+  return extensions.GetAppByURL(web_contents->GetVisibleURL());
+}
+
 bool GetProfileAndExtension(const std::string& extension_id,
                             Profile** output_profile,
                             const extensions::Extension** output_extension) {
diff --git a/chrome/browser/lacros/lacros_extensions_util.h b/chrome/browser/lacros/lacros_extensions_util.h
index f01dc18..f71f737 100644
--- a/chrome/browser/lacros/lacros_extensions_util.h
+++ b/chrome/browser/lacros/lacros_extensions_util.h
@@ -9,6 +9,10 @@
 
 class Profile;
 
+namespace content {
+class WebContents;
+}  // namespace content
+
 namespace extensions {
 class Extension;
 }  // namespace extensions
@@ -26,6 +30,10 @@
 const extensions::Extension* MaybeGetExtension(Profile* profile,
                                                const std::string& extension_id);
 
+// Returns the extension pointer for |web_contents|, or null if nonexistent.
+const extensions::Extension* MaybeGetExtension(
+    content::WebContents* web_contents);
+
 // Gets the profile and extension from |extension_id|. On success, returns true
 // and populates variables |output_profile| and |output_extension|. We pass a
 // Profile** and an Extension** instead of Profile*& and Extension*& for clarity
diff --git a/chrome/browser/media/router/chrome_media_router_factory.cc b/chrome/browser/media/router/chrome_media_router_factory.cc
index 4b4568f5..28f1f34 100644
--- a/chrome/browser/media/router/chrome_media_router_factory.cc
+++ b/chrome/browser/media/router/chrome_media_router_factory.cc
@@ -67,14 +67,15 @@
              : chrome::GetBrowserContextRedirectedInIncognito(context);
 }
 
-KeyedService* ChromeMediaRouterFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ChromeMediaRouterFactory::BuildServiceInstanceForBrowserContext(
     BrowserContext* context) const {
   CHECK(MediaRouterEnabled(context));
-  MediaRouterBase* media_router = nullptr;
+  std::unique_ptr<MediaRouterBase> media_router = nullptr;
 #if BUILDFLAG(IS_ANDROID)
-  media_router = new MediaRouterAndroid();
+  media_router = std::make_unique<MediaRouterAndroid>();
 #else
-  media_router = new MediaRouterDesktop(context);
+  media_router = std::make_unique<MediaRouterDesktop>(context);
 #endif  // BUILDFLAG(IS_ANDROID)
   media_router->Initialize();
   return media_router;
diff --git a/chrome/browser/media/router/chrome_media_router_factory.h b/chrome/browser/media/router/chrome_media_router_factory.h
index c185b9d5..09f718de9 100644
--- a/chrome/browser/media/router/chrome_media_router_factory.h
+++ b/chrome/browser/media/router/chrome_media_router_factory.h
@@ -36,7 +36,7 @@
   // BrowserContextKeyedServiceFactory interface.
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/metrics/ukm_background_recorder_service.cc b/chrome/browser/metrics/ukm_background_recorder_service.cc
index b2588d28..8356f8d 100644
--- a/chrome/browser/metrics/ukm_background_recorder_service.cc
+++ b/chrome/browser/metrics/ukm_background_recorder_service.cc
@@ -83,9 +83,11 @@
 
 UkmBackgroundRecorderFactory::~UkmBackgroundRecorderFactory() = default;
 
-KeyedService* UkmBackgroundRecorderFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+UkmBackgroundRecorderFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new UkmBackgroundRecorderService(Profile::FromBrowserContext(context));
+  return std::make_unique<UkmBackgroundRecorderService>(
+      Profile::FromBrowserContext(context));
 }
 
 }  // namespace ukm
diff --git a/chrome/browser/metrics/ukm_background_recorder_service.h b/chrome/browser/metrics/ukm_background_recorder_service.h
index a24ff05..3b8b470 100644
--- a/chrome/browser/metrics/ukm_background_recorder_service.h
+++ b/chrome/browser/metrics/ukm_background_recorder_service.h
@@ -91,7 +91,7 @@
   UkmBackgroundRecorderFactory();
   ~UkmBackgroundRecorderFactory() override;
 
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/nearby_sharing/OWNERS b/chrome/browser/nearby_sharing/OWNERS
index 82175ada..f195cc3 100644
--- a/chrome/browser/nearby_sharing/OWNERS
+++ b/chrome/browser/nearby_sharing/OWNERS
@@ -1,7 +1,8 @@
+cclem@google.com
 crisrael@google.com
+dclasson@google.com
 hansberry@chromium.org
 hansenmichael@google.com
-pushi@google.com
-cclem@google.com
 jackshira@google.com
-dclasson@google.com
+julietlevesque@google.com
+pushi@google.com
diff --git a/chrome/browser/new_tab_page/modules/v2/history_clusters/history_clusters_page_handler_v2.cc b/chrome/browser/new_tab_page/modules/v2/history_clusters/history_clusters_page_handler_v2.cc
index e795108a..df6d68d 100644
--- a/chrome/browser/new_tab_page/modules/v2/history_clusters/history_clusters_page_handler_v2.cc
+++ b/chrome/browser/new_tab_page/modules/v2/history_clusters/history_clusters_page_handler_v2.cc
@@ -42,7 +42,7 @@
 // visit.
 constexpr int kMinRequiredVisits = 3;
 
-constexpr int kMinRequiredRelatedSearches = 2;
+constexpr int kMinRequiredRelatedSearches = 0;
 
 }  // namespace
 
diff --git a/chrome/browser/new_tab_page/one_google_bar/one_google_bar_service_factory.cc b/chrome/browser/new_tab_page/one_google_bar/one_google_bar_service_factory.cc
index 1728403..a442a4f 100644
--- a/chrome/browser/new_tab_page/one_google_bar/one_google_bar_service_factory.cc
+++ b/chrome/browser/new_tab_page/one_google_bar/one_google_bar_service_factory.cc
@@ -49,7 +49,8 @@
 
 OneGoogleBarServiceFactory::~OneGoogleBarServiceFactory() = default;
 
-KeyedService* OneGoogleBarServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+OneGoogleBarServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
   signin::IdentityManager* identity_manager =
@@ -58,7 +59,7 @@
       CookieSettingsFactory::GetForProfile(profile);
   auto url_loader_factory = context->GetDefaultStoragePartition()
                                 ->GetURLLoaderFactoryForBrowserProcess();
-  return new OneGoogleBarService(
+  return std::make_unique<OneGoogleBarService>(
       identity_manager,
       std::make_unique<OneGoogleBarLoaderImpl>(
           url_loader_factory, g_browser_process->GetApplicationLocale(),
diff --git a/chrome/browser/new_tab_page/one_google_bar/one_google_bar_service_factory.h b/chrome/browser/new_tab_page/one_google_bar/one_google_bar_service_factory.h
index 84c3e5b8..7517907 100644
--- a/chrome/browser/new_tab_page/one_google_bar/one_google_bar_service_factory.h
+++ b/chrome/browser/new_tab_page/one_google_bar/one_google_bar_service_factory.h
@@ -29,7 +29,7 @@
   ~OneGoogleBarServiceFactory() override;
 
   // Overridden from BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
 };
 
diff --git a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc
index 5279f44..8a92f60 100644
--- a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc
@@ -63,14 +63,15 @@
 OfflinePageAutoFetcherServiceFactory::~OfflinePageAutoFetcherServiceFactory() =
     default;
 
-KeyedService* OfflinePageAutoFetcherServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+OfflinePageAutoFetcherServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   RequestCoordinator* coordinator =
       RequestCoordinatorFactory::GetForBrowserContext(context);
   OfflinePageModel* model =
       OfflinePageModelFactory::GetForBrowserContext(context);
-  return new OfflinePageAutoFetcherService(coordinator, model,
-                                           service_delegate_.get());
+  return std::make_unique<OfflinePageAutoFetcherService>(
+      coordinator, model, service_delegate_.get());
 }
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h
index 22f3b85..0f5973d9 100644
--- a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h
@@ -36,7 +36,7 @@
   OfflinePageAutoFetcherServiceFactory();
   ~OfflinePageAutoFetcherServiceFactory() override;
 
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 
   std::unique_ptr<ServiceDelegate> service_delegate_;
diff --git a/chrome/browser/offline_pages/android/request_coordinator_factory.cc b/chrome/browser/offline_pages/android/request_coordinator_factory.cc
index 10cf16f..f8927982 100644
--- a/chrome/browser/offline_pages/android/request_coordinator_factory.cc
+++ b/chrome/browser/offline_pages/android/request_coordinator_factory.cc
@@ -89,7 +89,8 @@
       GetInstance()->GetServiceForBrowserContext(context, true));
 }
 
-KeyedService* RequestCoordinatorFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+RequestCoordinatorFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   std::unique_ptr<OfflinerPolicy> policy(new OfflinerPolicy());
   std::unique_ptr<Offliner> offliner;
@@ -115,12 +116,10 @@
       scheduler(new android::BackgroundSchedulerBridge());
   network::NetworkQualityTracker* network_quality_tracker =
       g_browser_process->network_quality_tracker();
-  RequestCoordinator* request_coordinator = new RequestCoordinator(
+  return std::make_unique<RequestCoordinator>(
       std::move(policy), std::move(offliner), std::move(queue),
       std::move(scheduler), network_quality_tracker,
       std::make_unique<ActiveTabInfo>(profile));
-
-  return request_coordinator;
 }
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/request_coordinator_factory.h b/chrome/browser/offline_pages/request_coordinator_factory.h
index 7d68579..b9e9e90 100644
--- a/chrome/browser/offline_pages/request_coordinator_factory.h
+++ b/chrome/browser/offline_pages/request_coordinator_factory.h
@@ -34,7 +34,7 @@
   RequestCoordinatorFactory();
   ~RequestCoordinatorFactory() override {}
 
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/password_manager/affiliation_service_factory.cc b/chrome/browser/password_manager/affiliation_service_factory.cc
index 79fe9652..5f7f24a 100644
--- a/chrome/browser/password_manager/affiliation_service_factory.cc
+++ b/chrome/browser/password_manager/affiliation_service_factory.cc
@@ -34,7 +34,8 @@
       GetInstance()->GetServiceForBrowserContext(profile, true));
 }
 
-KeyedService* AffiliationServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+AffiliationServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory =
@@ -42,8 +43,9 @@
           ->GetURLLoaderFactoryForBrowserProcess();
   auto backend_task_runner = base::ThreadPool::CreateSequencedTaskRunner(
       {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
-  auto* affiliation_service = new password_manager::AffiliationServiceImpl(
-      url_loader_factory, backend_task_runner);
+  auto affiliation_service =
+          std::make_unique<password_manager::AffiliationServiceImpl>(
+              url_loader_factory, backend_task_runner);
 
   base::FilePath database_path =
       profile->GetPath().Append(password_manager::kAffiliationDatabaseFileName);
diff --git a/chrome/browser/password_manager/affiliation_service_factory.h b/chrome/browser/password_manager/affiliation_service_factory.h
index 027900f..7fcc731 100644
--- a/chrome/browser/password_manager/affiliation_service_factory.h
+++ b/chrome/browser/password_manager/affiliation_service_factory.h
@@ -27,7 +27,7 @@
   static password_manager::AffiliationService* GetForProfile(Profile* profile);
 
  private:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/recovery/recovery_install_global_error_factory.cc b/chrome/browser/recovery/recovery_install_global_error_factory.cc
index d827844..0e4da97 100644
--- a/chrome/browser/recovery/recovery_install_global_error_factory.cc
+++ b/chrome/browser/recovery/recovery_install_global_error_factory.cc
@@ -39,10 +39,12 @@
   return instance.get();
 }
 
-KeyedService* RecoveryInstallGlobalErrorFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+RecoveryInstallGlobalErrorFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
-  return new RecoveryInstallGlobalError(static_cast<Profile*>(context));
+  return std::make_unique<RecoveryInstallGlobalError>(
+      static_cast<Profile*>(context));
 #else
   return NULL;
 #endif
diff --git a/chrome/browser/recovery/recovery_install_global_error_factory.h b/chrome/browser/recovery/recovery_install_global_error_factory.h
index 5b07b79..72dc4953 100644
--- a/chrome/browser/recovery/recovery_install_global_error_factory.h
+++ b/chrome/browser/recovery/recovery_install_global_error_factory.h
@@ -35,7 +35,7 @@
   ~RecoveryInstallGlobalErrorFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
 };
 
diff --git a/chrome/browser/resources/ash/settings/date_time_page/date_time_card.html b/chrome/browser/resources/ash/settings/date_time_page/date_time_card.html
index 1b03774..e917388 100644
--- a/chrome/browser/resources/ash/settings/date_time_page/date_time_card.html
+++ b/chrome/browser/resources/ash/settings/date_time_page/date_time_card.html
@@ -23,7 +23,6 @@
         label="$i18n{timeZoneButton}"
         sub-label="[[timeZoneSettingSublabel_]]"
         role-description="$i18n{subpageArrowRoleDescription}">
-      <div class="flex"></div>
       <cr-policy-pref-indicator
           pref="[[prefs.generated.resolve_timezone_by_geolocation_on_off]]">
       </cr-policy-pref-indicator>
diff --git a/chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_page.ts b/chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_page.ts
index ab60a76dd..0c24444c 100644
--- a/chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_page.ts
+++ b/chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_page.ts
@@ -32,7 +32,8 @@
 
 const SettingsBluetoothPageElementBase = PrefsMixin(I18nMixin(PolymerElement));
 
-class SettingsBluetoothPageElement extends SettingsBluetoothPageElementBase {
+export class SettingsBluetoothPageElement extends
+    SettingsBluetoothPageElementBase {
   static get is() {
     return 'os-settings-bluetooth-page' as const;
   }
diff --git a/chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_pairing_dialog.ts b/chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_pairing_dialog.ts
index 3eb8a22e..e5e710f 100644
--- a/chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_pairing_dialog.ts
+++ b/chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_pairing_dialog.ts
@@ -16,11 +16,11 @@
 
 import {getTemplate} from './os_bluetooth_pairing_dialog.html.js';
 
-interface SettingsBluetoothPairingDialogElement {
+export interface SettingsBluetoothPairingDialogElement {
   $: {dialog: CrDialogElement};
 }
 
-class SettingsBluetoothPairingDialogElement extends PolymerElement {
+export class SettingsBluetoothPairingDialogElement extends PolymerElement {
   static get is() {
     return 'os-settings-bluetooth-pairing-dialog' as const;
   }
diff --git a/chrome/browser/resources/ash/settings/os_files_page/google_drive_subpage.ts b/chrome/browser/resources/ash/settings/os_files_page/google_drive_subpage.ts
index 2ed5490..945d745 100644
--- a/chrome/browser/resources/ash/settings/os_files_page/google_drive_subpage.ts
+++ b/chrome/browser/resources/ash/settings/os_files_page/google_drive_subpage.ts
@@ -459,7 +459,8 @@
   private shouldEnableCleanUpStorageButton_() {
     return !this.getPref(GOOGLE_DRIVE_BULK_PINNING_PREF).value &&
         this.contentCacheSize_ !== ContentCacheSizeType.UNKNOWN &&
-        this.contentCacheSize_ !== ContentCacheSizeType.CALCULATING;
+        this.contentCacheSize_ !== ContentCacheSizeType.CALCULATING &&
+        this.contentCacheSize_ !== '0 B';
   }
 
   /**
diff --git a/chrome/browser/resources/ash/settings/os_settings.ts b/chrome/browser/resources/ash/settings/os_settings.ts
index 6cdb4c5..82bf926 100644
--- a/chrome/browser/resources/ash/settings/os_settings.ts
+++ b/chrome/browser/resources/ash/settings/os_settings.ts
@@ -121,6 +121,7 @@
 export {PaperTooltipElement} from 'chrome://resources/polymer/v3_0/paper-tooltip/paper-tooltip.js';
 export {LacrosExtensionControlBrowserProxy, LacrosExtensionControlBrowserProxyImpl} from './common/lacros_extension_control_browser_proxy.js';
 export {LacrosExtensionControlledIndicatorElement} from './common/lacros_extension_controlled_indicator.js';
+export {PrefsState} from './common/types.js';
 export {SettingsAudioElement} from './device_page/audio.js';
 export {setCrosAudioConfigForTesting} from './device_page/cros_audio_config.js';
 export {DevicePageBrowserProxy, DevicePageBrowserProxyImpl, IdleBehavior, LidClosedBehavior, NoteAppInfo, NoteAppLockScreenSupport, setDisplayApiForTesting, StorageSpaceState} from './device_page/device_page_browser_proxy.js';
@@ -189,6 +190,8 @@
 export {AppManagementStoreMixin} from './os_apps_page/app_management_page/store_mixin.js';
 export {setAppNotificationProviderForTesting} from './os_apps_page/app_notifications_page/mojo_interface_provider.js';
 export {OsBluetoothDevicesSubpageBrowserProxy, OsBluetoothDevicesSubpageBrowserProxyImpl} from './os_bluetooth_page/os_bluetooth_devices_subpage_browser_proxy.js';
+export {SettingsBluetoothPageElement} from './os_bluetooth_page/os_bluetooth_page.js';
+export {SettingsBluetoothPairingDialogElement} from './os_bluetooth_page/os_bluetooth_pairing_dialog.js';
 export {FastPairSavedDevice, FastPairSavedDevicesOptInStatus} from './os_bluetooth_page/settings_fast_pair_constants.js';
 export {GoogleDriveBrowserProxy, GoogleDrivePageCallbackRouter, GoogleDrivePageHandlerRemote, GoogleDrivePageRemote, Stage} from './os_files_page/google_drive_browser_proxy.js';
 export {ConfirmationDialogType, SettingsGoogleDriveSubpageElement} from './os_files_page/google_drive_subpage.js';
diff --git a/chrome/browser/resources/settings/safety_hub/unused_site_permissions_module.ts b/chrome/browser/resources/settings/safety_hub/unused_site_permissions_module.ts
index 26c09c4..78a3b0b 100644
--- a/chrome/browser/resources/settings/safety_hub/unused_site_permissions_module.ts
+++ b/chrome/browser/resources/settings/safety_hub/unused_site_permissions_module.ts
@@ -168,8 +168,7 @@
     const permissionsI18n = permissions.map(permission => {
       const localizationString =
           getLocalizationStringForContentType(permission);
-      assert(localizationString !== null);
-      return this.i18n(localizationString);
+      return localizationString ? this.i18n(localizationString) : '';
     });
 
     switch (permissionsI18n.length) {
diff --git a/chrome/browser/resources/settings/site_settings_page/unused_site_permissions.ts b/chrome/browser/resources/settings/site_settings_page/unused_site_permissions.ts
index d9fbe17..1757c375 100644
--- a/chrome/browser/resources/settings/site_settings_page/unused_site_permissions.ts
+++ b/chrome/browser/resources/settings/site_settings_page/unused_site_permissions.ts
@@ -213,8 +213,7 @@
     const permissionsI18n = permissions.map(permission => {
       const localizationString =
           getLocalizationStringForContentType(permission);
-      assert(localizationString !== null);
-      return this.i18n(localizationString);
+      return localizationString ? this.i18n(localizationString) : '';
     });
 
     if (permissionsI18n.length === 1) {
diff --git a/chrome/browser/search/instant_service_factory.cc b/chrome/browser/search/instant_service_factory.cc
index 0b32940d..630b0dfa 100644
--- a/chrome/browser/search/instant_service_factory.cc
+++ b/chrome/browser/search/instant_service_factory.cc
@@ -55,10 +55,11 @@
 
 InstantServiceFactory::~InstantServiceFactory() = default;
 
-KeyedService* InstantServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+InstantServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   DCHECK(search::IsInstantExtendedAPIEnabled());
-  return new InstantService(Profile::FromBrowserContext(context));
+  return std::make_unique<InstantService>(Profile::FromBrowserContext(context));
 }
 
 void InstantServiceFactory::BrowserContextDestroyed(
diff --git a/chrome/browser/search/instant_service_factory.h b/chrome/browser/search/instant_service_factory.h
index deb9a777..427b2f22 100644
--- a/chrome/browser/search/instant_service_factory.h
+++ b/chrome/browser/search/instant_service_factory.h
@@ -34,7 +34,7 @@
   ~InstantServiceFactory() override;
 
   // Overridden from BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   void BrowserContextDestroyed(
       content::BrowserContext* browser_context) override;
diff --git a/chrome/browser/segmentation_platform/segmentation_platform_service_factory_unittest.cc b/chrome/browser/segmentation_platform/segmentation_platform_service_factory_unittest.cc
new file mode 100644
index 0000000..cf2264de
--- /dev/null
+++ b/chrome/browser/segmentation_platform/segmentation_platform_service_factory_unittest.cc
@@ -0,0 +1,244 @@
+// 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/segmentation_platform/segmentation_platform_service_factory.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/functional/bind.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/test/scoped_command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/prefs/pref_observer.h"
+#include "components/prefs/pref_service.h"
+#include "components/segmentation_platform/internal/constants.h"
+#include "components/segmentation_platform/internal/database/client_result_prefs.h"
+#include "components/segmentation_platform/public/constants.h"
+#include "components/segmentation_platform/public/features.h"
+#include "components/segmentation_platform/public/prediction_options.h"
+#include "components/segmentation_platform/public/result.h"
+#include "components/segmentation_platform/public/segment_selection_result.h"
+#include "components/segmentation_platform/public/segmentation_platform_service.h"
+#include "components/segmentation_platform/public/service_proxy.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace segmentation_platform {
+namespace {
+
+// Observer that waits for service_ initialization.
+class WaitServiceInitializedObserver : public ServiceProxy::Observer {
+ public:
+  explicit WaitServiceInitializedObserver(base::OnceClosure closure)
+      : closure_(std::move(closure)) {}
+  void OnServiceStatusChanged(bool initialized, int status_flags) override {
+    if (initialized) {
+      std::move(closure_).Run();
+    }
+  }
+
+ private:
+  base::OnceClosure closure_;
+};
+
+}  // namespace
+
+class SegmentationPlatformServiceFactoryTest : public testing::Test {
+ protected:
+  SegmentationPlatformServiceFactoryTest() {
+    scoped_command_line_.GetProcessCommandLine()->AppendSwitch(
+        kSegmentationPlatformRefreshResultsSwitch);
+  }
+
+  ~SegmentationPlatformServiceFactoryTest() override = default;
+
+  void TearDown() override {
+    service_ = nullptr;
+    testing_profile_.reset();
+    task_environment_.RunUntilIdle();
+  }
+
+  void InitServiceAndCacheResults(const std::string& segmentation_key) {
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {{optimization_guide::features::kOptimizationTargetPrediction, {}},
+         {features::kSegmentationPlatformFeature, {}},
+         {features::kSegmentationPlatformUkmEngine, {}}},
+        {});
+
+    // Creating profile and initialising segmentation service.
+    TestingProfile::Builder profile_builder;
+    testing_profile_ = profile_builder.Build();
+    service_ = SegmentationPlatformServiceFactory::GetForProfile(
+        testing_profile_.get());
+    WaitForServiceInit();
+    WaitForClientResultPrefUpdate(segmentation_key);
+    // Getting the updated prefs from this session to be copied to the next
+    // session. In the test environment, new session doesn't have prefs from
+    // previous session, hence copying is required to get the cached result from
+    // last session.
+    const std::string output =
+        testing_profile_->GetPrefs()->GetString(kSegmentationClientResultPrefs);
+
+    // TODO(b/297091996): Remove this when leak is fixed.
+    task_environment_.RunUntilIdle();
+
+    service_ = nullptr;
+    testing_profile_ = nullptr;
+
+    // Creating profile and initialising segmentation service again with prefs
+    // from the last session.
+    TestingProfile::Builder profile_builder1;
+    testing_profile_ = profile_builder1.Build();
+    // Copying the prefs from last session.
+    testing_profile_->GetPrefs()->SetString(kSegmentationClientResultPrefs,
+                                            output);
+    service_ = SegmentationPlatformServiceFactory::GetForProfile(
+        testing_profile_.get());
+    WaitForServiceInit();
+    // TODO(b/297091996): Remove this when leak is fixed.
+    task_environment_.RunUntilIdle();
+  }
+
+  void ExpectGetClassificationResult(
+      const std::string& segmentation_key,
+      const PredictionOptions& prediction_options,
+      scoped_refptr<InputContext> input_context,
+      segmentation_platform::PredictionStatus expected_status,
+      absl::optional<std::vector<std::string>> expected_labels) {
+    base::RunLoop loop;
+    service_->GetClassificationResult(
+        segmentation_key, prediction_options, input_context,
+        base::BindOnce(
+            &SegmentationPlatformServiceFactoryTest::OnGetClassificationResult,
+            base::Unretained(this), loop.QuitClosure(), expected_status,
+            expected_labels));
+    loop.Run();
+  }
+
+  void OnGetClassificationResult(
+      base::RepeatingClosure closure,
+      segmentation_platform::PredictionStatus expected_status,
+      absl::optional<std::vector<std::string>> expected_labels,
+      const ClassificationResult& actual_result) {
+    ASSERT_EQ(expected_status, actual_result.status);
+    if (expected_labels.has_value()) {
+      ASSERT_EQ(expected_labels.value().size(),
+                actual_result.ordered_labels.size());
+      ASSERT_EQ(expected_labels.value(), actual_result.ordered_labels);
+    }
+    std::move(closure).Run();
+  }
+
+  void WaitForServiceInit() {
+    base::RunLoop wait_for_init;
+    WaitServiceInitializedObserver wait_observer(wait_for_init.QuitClosure());
+    service_->GetServiceProxy()->AddObserver(&wait_observer);
+
+    wait_for_init.Run();
+    ASSERT_TRUE(service_->IsPlatformInitialized());
+    service_->GetServiceProxy()->RemoveObserver(&wait_observer);
+  }
+
+  bool HasClientResultPref(const std::string& segmentation_key) {
+    PrefService* pref_service_ = testing_profile_->GetPrefs();
+    std::unique_ptr<ClientResultPrefs> result_prefs_ =
+        std::make_unique<ClientResultPrefs>(pref_service_);
+    return result_prefs_->ReadClientResultFromPrefs(segmentation_key)
+        .has_value();
+  }
+
+  void OnClientResultPrefUpdated(const std::string& segmentation_key) {
+    if (!wait_for_pref_callback_.is_null() &&
+        HasClientResultPref(segmentation_key)) {
+      std::move(wait_for_pref_callback_).Run();
+    }
+  }
+
+  void WaitForClientResultPrefUpdate(const std::string& segmentation_key) {
+    if (HasClientResultPref(segmentation_key)) {
+      return;
+    }
+
+    base::RunLoop wait_for_pref;
+    wait_for_pref_callback_ = wait_for_pref.QuitClosure();
+    pref_registrar_.Init(testing_profile_->GetPrefs());
+    pref_registrar_.Add(
+        kSegmentationClientResultPrefs,
+        base::BindRepeating(
+            &SegmentationPlatformServiceFactoryTest::OnClientResultPrefUpdated,
+            base::Unretained(this), segmentation_key));
+    wait_for_pref.Run();
+
+    pref_registrar_.RemoveAll();
+  }
+
+  content::BrowserTaskEnvironment task_environment_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+  base::test::ScopedCommandLine scoped_command_line_;
+  PrefChangeRegistrar pref_registrar_;
+  base::OnceClosure wait_for_pref_callback_;
+  std::unique_ptr<TestingProfile> testing_profile_;
+  raw_ptr<SegmentationPlatformService> service_;
+};
+
+TEST_F(SegmentationPlatformServiceFactoryTest, TestPasswordManagerUserSegment) {
+  InitServiceAndCacheResults(segmentation_platform::kPasswordManagerUserKey);
+
+  segmentation_platform::PredictionOptions prediction_options;
+
+  ExpectGetClassificationResult(
+      segmentation_platform::kPasswordManagerUserKey, prediction_options,
+      nullptr,
+      /*expected_status=*/segmentation_platform::PredictionStatus::kSucceeded,
+      /*expected_labels=*/
+      std::vector<std::string>(1, "Not_PasswordManagerUser"));
+}
+
+TEST_F(SegmentationPlatformServiceFactoryTest, TestSearchUserModel) {
+  InitServiceAndCacheResults(segmentation_platform::kSearchUserKey);
+
+  segmentation_platform::PredictionOptions prediction_options;
+
+  ExpectGetClassificationResult(
+      segmentation_platform::kSearchUserKey, prediction_options, nullptr,
+      /*expected_status=*/segmentation_platform::PredictionStatus::kSucceeded,
+      /*expected_labels=*/
+      std::vector<std::string>(
+          1, segmentation_platform::kSearchUserModelLabelNone));
+}
+
+#if BUILDFLAG(IS_ANDROID)
+// Tests for models in android platform.
+TEST_F(SegmentationPlatformServiceFactoryTest, TestDeviceTierSegment) {
+  InitServiceAndCacheResults(segmentation_platform::kDeviceTierKey);
+
+  segmentation_platform::PredictionOptions prediction_options;
+
+  ExpectGetClassificationResult(
+      segmentation_platform::kDeviceTierKey, prediction_options, nullptr,
+      /*expected_status=*/segmentation_platform::PredictionStatus::kSucceeded,
+      /*expected_labels=*/absl::nullopt);
+}
+
+TEST_F(SegmentationPlatformServiceFactoryTest,
+       TestTabletProductivityUserModel) {
+  InitServiceAndCacheResults(segmentation_platform::kTabletProductivityUserKey);
+
+  segmentation_platform::PredictionOptions prediction_options;
+
+  ExpectGetClassificationResult(
+      segmentation_platform::kTabletProductivityUserKey, prediction_options,
+      nullptr,
+      /*expected_status=*/segmentation_platform::PredictionStatus::kSucceeded,
+      /*expected_labels=*/
+      std::vector<std::string>(
+          1, segmentation_platform::kTabletProductivityUserModelLabelNone));
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+
+}  // namespace segmentation_platform
diff --git a/chrome/browser/sharing/sharing_service_factory.cc b/chrome/browser/sharing/sharing_service_factory.cc
index b5142370..7e00ff3 100644
--- a/chrome/browser/sharing/sharing_service_factory.cc
+++ b/chrome/browser/sharing/sharing_service_factory.cc
@@ -91,7 +91,8 @@
 
 SharingServiceFactory::~SharingServiceFactory() = default;
 
-KeyedService* SharingServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SharingServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
   syncer::SyncService* sync_service =
@@ -153,7 +154,7 @@
   auto fcm_handler = std::make_unique<SharingFCMHandler>(
       gcm_driver, device_info_tracker, fcm_sender_ptr, handler_registry.get());
 
-  return new SharingService(
+  return std::make_unique<SharingService>(
       std::move(sync_prefs), std::move(vapid_key_manager),
       std::move(sharing_device_registration), std::move(sharing_message_sender),
       std::move(device_source), std::move(handler_registry),
diff --git a/chrome/browser/sharing/sharing_service_factory.h b/chrome/browser/sharing/sharing_service_factory.h
index 5a210bbd..cd775df2 100644
--- a/chrome/browser/sharing/sharing_service_factory.h
+++ b/chrome/browser/sharing/sharing_service_factory.h
@@ -37,7 +37,7 @@
   ~SharingServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory overrides:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsNULLWhileTesting() const override;
 };
diff --git a/chrome/browser/sync_file_system/sync_file_system_service.h b/chrome/browser/sync_file_system/sync_file_system_service.h
index 60323f5..06e1529 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service.h
+++ b/chrome/browser/sync_file_system/sync_file_system_service.h
@@ -63,6 +63,9 @@
   using ExtensionStatusMapCallback =
       base::OnceCallback<void(const RemoteFileSyncService::OriginStatusMap&)>;
 
+  // Uses SyncFileSystemServiceFactory instead.
+  explicit SyncFileSystemService(Profile* profile);
+  ~SyncFileSystemService() override;
   SyncFileSystemService(const SyncFileSystemService&) = delete;
   SyncFileSystemService& operator=(const SyncFileSystemService&) = delete;
 
@@ -108,9 +111,6 @@
   friend class LocalSyncRunner;
   friend class RemoteSyncRunner;
 
-  explicit SyncFileSystemService(Profile* profile);
-  ~SyncFileSystemService() override;
-
   void Initialize(std::unique_ptr<LocalFileSyncService> local_file_service,
                   std::unique_ptr<RemoteFileSyncService> remote_file_service);
 
diff --git a/chrome/browser/sync_file_system/sync_file_system_service_factory.cc b/chrome/browser/sync_file_system/sync_file_system_service_factory.cc
index 26c1fdc8..b93d8c9 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service_factory.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service_factory.cc
@@ -66,11 +66,13 @@
 
 SyncFileSystemServiceFactory::~SyncFileSystemServiceFactory() = default;
 
-KeyedService* SyncFileSystemServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SyncFileSystemServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
 
-  SyncFileSystemService* service = new SyncFileSystemService(profile);
+  std::unique_ptr<SyncFileSystemService> service =
+      std::make_unique<SyncFileSystemService>(profile);
   service->Initialize(LocalFileSyncService::Create(profile),
                       RemoteFileSyncService::CreateForBrowserContext(
                           context, service->task_logger()));
diff --git a/chrome/browser/sync_file_system/sync_file_system_service_factory.h b/chrome/browser/sync_file_system/sync_file_system_service_factory.h
index b5c7bd9..7796593 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service_factory.h
+++ b/chrome/browser/sync_file_system/sync_file_system_service_factory.h
@@ -33,7 +33,7 @@
   ~SyncFileSystemServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory overrides.
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/ui/android/cars/BUILD.gn b/chrome/browser/ui/android/cars/BUILD.gn
index 56a2f62e..8851af9 100644
--- a/chrome/browser/ui/android/cars/BUILD.gn
+++ b/chrome/browser/ui/android/cars/BUILD.gn
@@ -5,33 +5,12 @@
 import("//build/config/android/rules.gni")
 
 android_library("java") {
-  sources = [ "java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManager.java" ]
-
-  deps = [ "//base:base_java" ]
-
-  public_deps = [ ":delegate_java" ]
-}
-
-android_library("delegate_java") {
   sources = [
     "java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsDelegate.java",
-    "java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsDelegateImpl.java",
+    "java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManager.java",
   ]
 
   deps = [ "//base:base_java" ]
-
-  # Add the actual implementation where necessary so that downstream targets
-  # can provide their own implementations.
-  jar_excluded_patterns = [ "*/DrivingRestrictionsDelegateImpl.class" ]
-}
-
-android_library("delegate_public_impl_java") {
-  sources = [ "java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsDelegateImpl.java" ]
-
-  deps = [
-    ":delegate_java",
-    "//base:base_java",
-  ]
 }
 
 robolectric_library("junit") {
diff --git a/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsDelegateImpl.java b/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsDelegateImpl.java
deleted file mode 100644
index f209ac7a..0000000
--- a/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsDelegateImpl.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.ui.cars;
-
-import org.chromium.base.Callback;
-
-/**
- * Instantiable version of {@link DrivingRestrictionsDelegate}, don't add anything to this class.
- * Downstream targets may provide a different implementation. In GN, we specify that
- * {@link DrivingRestrictionsDelegate} is compiled separately from its implementation; other
- * projects may specify a different DrivingRestrictionsDelegate via GN.
- */
-class DrivingRestrictionsDelegateImpl extends DrivingRestrictionsDelegate {
-    DrivingRestrictionsDelegateImpl(Callback<Boolean> requiresDrivingOptimizationsCallback) {
-        super(requiresDrivingOptimizationsCallback);
-    }
-}
diff --git a/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManager.java b/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManager.java
index 0c7b759..bb02d3b 100644
--- a/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManager.java
+++ b/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManager.java
@@ -15,7 +15,7 @@
 public class DrivingRestrictionsManager {
     private static DrivingRestrictionsManager sInstance;
 
-    private DrivingRestrictionsDelegateImpl mDelegate;
+    private DrivingRestrictionsDelegate mDelegate;
     private boolean mMonitoring;
 
     /**
@@ -26,8 +26,7 @@
     }
 
     DrivingRestrictionsManager() {
-        mDelegate =
-                new DrivingRestrictionsDelegateImpl(this::onRequiresDistractionOptimizationChanged);
+        mDelegate = new DrivingRestrictionsDelegate(this::onRequiresDistractionOptimizationChanged);
 
         updateMonitoring(ApplicationStatus.getStateForApplication());
         ApplicationStatus.registerApplicationStateListener(newState -> updateMonitoring(newState));
@@ -51,15 +50,11 @@
         }
     }
 
-    void setDelegateForTesting(DrivingRestrictionsDelegateImpl delegate) {
+    void setDelegateForTesting(DrivingRestrictionsDelegate delegate) {
         mDelegate = delegate;
     }
 
-    DrivingRestrictionsDelegateImpl getDelegateForTesting() {
+    DrivingRestrictionsDelegate getDelegateForTesting() {
         return mDelegate;
     }
-
-    static DrivingRestrictionsManager getInstanceForTesting() {
-        return sInstance;
-    }
 }
diff --git a/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManagerTest.java b/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManagerTest.java
index 6aa3145d..1edea52e 100644
--- a/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManagerTest.java
+++ b/chrome/browser/ui/android/cars/java/src/org/chromium/chrome/browser/ui/cars/DrivingRestrictionsManagerTest.java
@@ -28,7 +28,7 @@
 public class DrivingRestrictionsManagerTest {
     private DrivingRestrictionsManager mManager;
     @Spy
-    private DrivingRestrictionsDelegateImpl mSpyDelegate;
+    private DrivingRestrictionsDelegate mSpyDelegate;
 
     @Before
     public void setUp() {
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc b/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc
index 4666657..ca02ad0d 100644
--- a/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc
+++ b/chrome/browser/ui/ash/glanceables/glanceables_browsertest.cc
@@ -8,11 +8,22 @@
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_switches.h"
 #include "ash/glanceables/classroom/glanceables_classroom_client.h"
+#include "ash/glanceables/common/glanceables_view_id.h"
 #include "ash/glanceables/glanceables_controller.h"
 #include "ash/glanceables/glanceables_v2_controller.h"
+#include "ash/glanceables/tasks/fake_glanceables_tasks_client.h"
+#include "ash/glanceables/tasks/glanceables_task_view.h"
+#include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
+#include "ash/style/combobox.h"
+#include "ash/system/status_area_widget_test_helper.h"
+#include "ash/system/unified/date_tray.h"
+#include "ash/system/unified/glanceable_tray_bubble.h"
+#include "ash/system/unified/tasks_bubble_view.h"
+#include "ash/test/ash_test_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/types/cxx23_to_underlying.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -32,13 +43,60 @@
 #include "components/user_manager/user_manager.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/view_utils.h"
 #include "url/gurl.h"
 
+namespace ash {
 namespace {
 
 constexpr char kTestUserName[] = "test@test.test";
 constexpr char kTestUserGaiaId[] = "123456";
 
+constexpr char kDueDate[] = "2 Aug 2025 10:00 GMT";
+
+views::Label* FindViewWithLabel(views::View* search_root,
+                                const std::u16string& label) {
+  if (views::Label* const label_view =
+          views::AsViewClass<views::Label>(search_root);
+      label_view && label_view->GetText() == label) {
+    return label_view;
+  }
+
+  // Keep searching in children views.
+  for (views::View* const child : search_root->children()) {
+    if (views::Label* const found = FindViewWithLabel(child, label)) {
+      return found;
+    }
+  }
+
+  return nullptr;
+}
+
+views::Label* FindViewWithLabelFromWindow(aura::Window* search_root,
+                                          const std::u16string& label) {
+  if (views::Widget* const root_widget =
+          views::Widget::GetWidgetForNativeWindow(search_root)) {
+    return FindViewWithLabel(root_widget->GetRootView(), label);
+  }
+
+  for (aura::Window* const child : search_root->children()) {
+    if (auto* found = FindViewWithLabelFromWindow(child, label)) {
+      return found;
+    }
+  }
+
+  return nullptr;
+}
+
+views::Label* FindMenuItemLabelWithString(const std::u16string& label) {
+  return FindViewWithLabelFromWindow(
+      Shell::GetContainer(Shell::GetPrimaryRootWindow(),
+                          kShellWindowId_MenuContainer),
+      label);
+}
+
 }  // namespace
 
 // Tests for the glanceables feature, which adds a "welcome back" screen on
@@ -49,16 +107,16 @@
     InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
 
     // The test harness adds --no-first-run. Remove it so glanceables show up.
-    command_line->RemoveSwitch(switches::kNoFirstRun);
+    command_line->RemoveSwitch(::switches::kNoFirstRun);
 
     // Don't open a browser window, because doing so would hide glanceables.
     // Note that InProcessBrowserTest::browser() will be null.
-    command_line->AppendSwitch(switches::kNoStartupWindow);
+    command_line->AppendSwitch(::switches::kNoStartupWindow);
 
-    command_line->AppendSwitch(ash::switches::kLoginManager);
-    command_line->AppendSwitchASCII(ash::switches::kLoginProfile,
+    command_line->AppendSwitch(switches::kLoginManager);
+    command_line->AppendSwitchASCII(switches::kLoginProfile,
                                     TestingProfile::kTestUserProfileDir);
-    command_line->AppendSwitch(ash::switches::kAllowFailedPolicyFetchForTest);
+    command_line->AppendSwitch(switches::kAllowFailedPolicyFetchForTest);
   }
 
   void CreateAndStartUserSession() {
@@ -69,7 +127,7 @@
 
     profile_ = &profiles::testing::CreateProfileSync(
         g_browser_process->profile_manager(),
-        ash::ProfileHelper::GetProfilePathByUserIdHash(
+        ProfileHelper::GetProfilePathByUserIdHash(
             user_manager::UserManager::Get()
                 ->FindUser(account_id)
                 ->username_hash()));
@@ -78,8 +136,8 @@
     session_manager->SessionStarted();
   }
 
-  ash::GlanceablesController* glanceables_controller() {
-    return ash::Shell::Get()->glanceables_controller();
+  GlanceablesController* glanceables_controller() {
+    return Shell::Get()->glanceables_controller();
   }
 
   signin::IdentityManager* identity_manager() {
@@ -87,7 +145,7 @@
   }
 
  protected:
-  base::test::ScopedFeatureList features_{ash::features::kGlanceables};
+  base::test::ScopedFeatureList features_{features::kGlanceables};
   raw_ptr<Profile, ExperimentalAsh> profile_ = nullptr;
 };
 
@@ -117,12 +175,90 @@
 
 class GlanceablesV2BrowserTest : public InProcessBrowserTest {
  public:
-  ash::GlanceablesV2Controller* glanceables_controller() {
-    return ash::Shell::Get()->glanceables_v2_controller();
+  GlanceablesV2Controller* glanceables_controller() {
+    return Shell::Get()->glanceables_v2_controller();
+  }
+
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+
+    base::Time date;
+    ASSERT_TRUE(base::Time::FromString(kDueDate, &date));
+    fake_glanceables_tasks_client_ =
+        std::make_unique<FakeGlanceablesTasksClient>(date);
+    Shell::Get()->glanceables_v2_controller()->UpdateClientsRegistration(
+        account_id_,
+        GlanceablesV2Controller::ClientsRegistration{
+            .classroom_client = glanceables_controller()->GetClassroomClient(),
+            .tasks_client = fake_glanceables_tasks_client_.get()});
+    Shell::Get()->glanceables_v2_controller()->OnActiveUserSessionChanged(
+        account_id_);
+
+    date_tray_ = StatusAreaWidgetTestHelper::GetStatusAreaWidget()->date_tray();
+    event_generator_ = std::make_unique<ui::test::EventGenerator>(
+        Shell::GetPrimaryRootWindow());
+  }
+
+  DateTray* GetDateTray() const { return date_tray_; }
+
+  ui::test::EventGenerator* GetEventGenerator() const {
+    return event_generator_.get();
+  }
+
+  GlanceableTrayBubble* GetGlanceableTrayBubble() const {
+    return date_tray_->bubble_.get();
+  }
+
+  FakeGlanceablesTasksClient* fake_glanceables_tasks_client() const {
+    return fake_glanceables_tasks_client_.get();
+  }
+
+  TasksBubbleView* GetTasksView() const {
+    return GetGlanceableTrayBubble()->GetTasksView();
+  }
+
+  Combobox* GetTasksComboBoxView() const {
+    return views::AsViewClass<Combobox>(GetTasksView()->GetViewByID(
+        base::to_underlying(GlanceablesViewId::kTasksBubbleComboBox)));
+  }
+
+  views::View* GetTasksItemContainerView() const {
+    return views::AsViewClass<views::View>(GetTasksView()->GetViewByID(
+        base::to_underlying(GlanceablesViewId::kTasksBubbleListContainer)));
+  }
+
+  views::LabelButton* GetTaskListFooterSeeAllButton() const {
+    return views::AsViewClass<views::LabelButton>(GetTasksView()->GetViewByID(
+        base::to_underlying(GlanceablesViewId::kListFooterSeeAllButton)));
+  }
+
+  std::vector<std::string> GetCurrentTaskListItemTitles() const {
+    std::vector<std::string> current_items;
+    for (views::View* child : GetTasksItemContainerView()->children()) {
+      if (views::View* task_item = views::AsViewClass<views::View>(child)) {
+        current_items.push_back(
+            base::UTF16ToUTF8(views::AsViewClass<views::Label>(
+                                  task_item->GetViewByID(base::to_underlying(
+                                      GlanceablesViewId::kTaskItemTitleLabel)))
+                                  ->GetText()));
+      }
+    }
+    return current_items;
+  }
+
+  GlanceablesTaskView* GetTaskItemView(int item_index) {
+    return views::AsViewClass<GlanceablesTaskView>(
+        GetTasksItemContainerView()->children()[item_index]);
   }
 
  private:
-  base::test::ScopedFeatureList features_{ash::features::kGlanceablesV2};
+  raw_ptr<DateTray, ExperimentalAsh> date_tray_;
+  std::unique_ptr<ui::test::EventGenerator> event_generator_;
+  AccountId account_id_ =
+      AccountId::FromUserEmailGaiaId(kTestUserName, kTestUserGaiaId);
+  std::unique_ptr<FakeGlanceablesTasksClient> fake_glanceables_tasks_client_;
+
+  base::test::ScopedFeatureList features_{features::kGlanceablesV2};
 };
 
 IN_PROC_BROWSER_TEST_F(GlanceablesV2BrowserTest, OpensClassroomUrlInBrowser) {
@@ -135,3 +271,125 @@
       browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL(),
       classroom_url);
 }
+
+IN_PROC_BROWSER_TEST_F(GlanceablesV2BrowserTest, ViewAndSwitchTaskLists) {
+  ASSERT_TRUE(glanceables_controller()->GetTasksClient());
+  EXPECT_FALSE(GetGlanceableTrayBubble());
+
+  GetEventGenerator()->MoveMouseTo(
+      GetDateTray()->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+
+  EXPECT_TRUE(GetGlanceableTrayBubble());
+  EXPECT_TRUE(GetTasksView());
+
+  // Check that the tasks glanceable is completely shown on the primary screen.
+  EXPECT_TRUE(
+      Shell::Get()->GetPrimaryRootWindow()->GetBoundsInScreen().Contains(
+          GetTasksView()->GetBoundsInScreen()));
+
+  // Check that task list items from the first list are shown.
+  EXPECT_EQ(GetCurrentTaskListItemTitles(),
+            std::vector<std::string>(
+                {"Task List 1 Item 1 Title", "Task List 1 Item 2 Title"}));
+
+  // Click on the combo box to show the task lists.
+  GetEventGenerator()->MoveMouseTo(
+      GetTasksComboBoxView()->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+
+  views::Label* second_menu_item_label =
+      FindMenuItemLabelWithString(u"Task List 2 Title");
+
+  // Click on the second menu item label to switch to the second task list.
+  ASSERT_TRUE(second_menu_item_label);
+  GetEventGenerator()->MoveMouseTo(
+      second_menu_item_label->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+
+  // Make sure that task list items from the second list are shown.
+  EXPECT_EQ(GetCurrentTaskListItemTitles(),
+            std::vector<std::string>({"Task List 2 Item 1 Title",
+                                      "Task List 2 Item 2 Title",
+                                      "Task List 2 Item 3 Title"}));
+}
+
+IN_PROC_BROWSER_TEST_F(GlanceablesV2BrowserTest, ClickSeeAllTasksButton) {
+  ASSERT_TRUE(glanceables_controller()->GetTasksClient());
+  EXPECT_FALSE(GetGlanceableTrayBubble());
+
+  // Click the date tray to show the glanceable bubbles.
+  GetEventGenerator()->MoveMouseTo(
+      GetDateTray()->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+
+  EXPECT_TRUE(GetGlanceableTrayBubble());
+  EXPECT_TRUE(GetTasksView());
+
+  // Check that the tasks glanceable is completely shown on the primary screen.
+  EXPECT_TRUE(
+      Shell::Get()->GetPrimaryRootWindow()->GetBoundsInScreen().Contains(
+          GetTasksView()->GetBoundsInScreen()));
+
+  // Check that task list items from the first list are shown.
+  EXPECT_EQ(GetCurrentTaskListItemTitles(),
+            std::vector<std::string>(
+                {"Task List 1 Item 1 Title", "Task List 1 Item 2 Title"}));
+
+  // Click the "See All" button in the tasks glanceable footer, and check that
+  // the correct URL is opened.
+  GetEventGenerator()->MoveMouseTo(
+      GetTaskListFooterSeeAllButton()->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+  EXPECT_EQ(
+      browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec(),
+      "https://calendar.google.com/calendar/u/0/r/week?opentasks=1");
+}
+
+IN_PROC_BROWSER_TEST_F(GlanceablesV2BrowserTest, CheckOffTaskItems) {
+  ASSERT_TRUE(glanceables_controller()->GetTasksClient());
+  EXPECT_FALSE(GetGlanceableTrayBubble());
+
+  // Click the date tray to show the glanceable bubbles.
+  GetEventGenerator()->MoveMouseTo(
+      GetDateTray()->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+
+  EXPECT_TRUE(GetGlanceableTrayBubble());
+  EXPECT_TRUE(GetTasksView());
+
+  // Check that the tasks glanceable is completely shown on the primary screen.
+  EXPECT_TRUE(
+      Shell::Get()->GetPrimaryRootWindow()->GetBoundsInScreen().Contains(
+          GetTasksView()->GetBoundsInScreen()));
+
+  // Check that task list items from the first list are shown.
+  EXPECT_EQ(GetCurrentTaskListItemTitles(),
+            std::vector<std::string>(
+                {"Task List 1 Item 1 Title", "Task List 1 Item 2 Title"}));
+
+  EXPECT_FALSE(GetTaskItemView(/*item_index=*/0)->GetCompletedForTest());
+  EXPECT_FALSE(GetTaskItemView(/*item_index=*/1)->GetCompletedForTest());
+
+  // Click to check off the first task item and check that it has been marked
+  // complete.
+  GetEventGenerator()->MoveMouseTo(GetTaskItemView(/*item_index=*/0)
+                                       ->GetButtonForTest()
+                                       ->GetBoundsInScreen()
+                                       .CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+  EXPECT_TRUE(GetTaskItemView(/*item_index=*/0)->GetCompletedForTest());
+  EXPECT_FALSE(GetTaskItemView(/*item_index=*/1)->GetCompletedForTest());
+
+  // Click to check off the second task item and check that it has been marked
+  // complete.
+  GetEventGenerator()->MoveMouseTo(GetTaskItemView(/*item_index=*/1)
+                                       ->GetButtonForTest()
+                                       ->GetBoundsInScreen()
+                                       .CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+  EXPECT_TRUE(GetTaskItemView(/*item_index=*/0)->GetCompletedForTest());
+  EXPECT_TRUE(GetTaskItemView(/*item_index=*/1)->GetCompletedForTest());
+}
+
+}  // namespace ash
diff --git a/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.cc b/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.cc
index c34d7790..ec207f9 100644
--- a/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.cc
+++ b/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.cc
@@ -43,13 +43,13 @@
       GetInstance()->GetServiceForBrowserContext(profile, true));
 }
 
-KeyedService*
-CastMediaNotificationProducerKeyedServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
+std::unique_ptr<KeyedService> CastMediaNotificationProducerKeyedServiceFactory::
+    BuildServiceInstanceForBrowserContext(
+        content::BrowserContext* context) const {
   if (!media_router::MediaRouterEnabled(context)) {
     return nullptr;
   }
-  return new CastMediaNotificationProducerKeyedService(
+  return std::make_unique<CastMediaNotificationProducerKeyedService>(
       Profile::FromBrowserContext(context));
 }
 
diff --git a/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.h b/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.h
index 06bdd2a..5edc4882 100644
--- a/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.h
+++ b/chrome/browser/ui/ash/global_media_controls/cast_media_notification_producer_keyed_service_factory.h
@@ -30,7 +30,7 @@
 
  private:
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsCreatedWithBrowserContext() const override;
   bool ServiceIsNULLWhileTesting() const override;
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc
index 07c85d6..e166d55 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.cc
@@ -38,7 +38,7 @@
 BrowserContextKeyedServiceFactory::TestingFactory
 HoldingSpaceKeyedServiceFactory::GetDefaultTestingFactory() {
   return base::BindRepeating([](content::BrowserContext* context) {
-    return base::WrapUnique(BuildServiceInstanceForInternal(context));
+    return BuildServiceInstanceForInternal(context);
   });
 }
 
@@ -77,15 +77,17 @@
   return profile->IsOffTheRecord() ? nullptr : context;
 }
 
-KeyedService* HoldingSpaceKeyedServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+HoldingSpaceKeyedServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   TestingFactory* testing_factory = GetTestingFactory();
   return testing_factory->is_null() ? BuildServiceInstanceForInternal(context)
-                                    : testing_factory->Run(context).release();
+                                    : testing_factory->Run(context);
 }
 
 // static
-KeyedService* HoldingSpaceKeyedServiceFactory::BuildServiceInstanceForInternal(
+std::unique_ptr<KeyedService>
+HoldingSpaceKeyedServiceFactory::BuildServiceInstanceForInternal(
     content::BrowserContext* context) {
   Profile* const profile = Profile::FromBrowserContext(context);
   DCHECK_EQ(profile->IsGuestSession(), profile->IsOffTheRecord());
@@ -97,7 +99,8 @@
   if (user->GetType() == user_manager::USER_TYPE_KIOSK_APP)
     return nullptr;
 
-  return new HoldingSpaceKeyedService(profile, user->GetAccountId());
+  return std::make_unique<HoldingSpaceKeyedService>(profile,
+                                                    user->GetAccountId());
 }
 
 void HoldingSpaceKeyedServiceFactory::RegisterProfilePrefs(
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h
index ef283b0..f4e899d4 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h
@@ -31,7 +31,7 @@
   // BrowserContextKeyedServiceFactory:
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   void RegisterProfilePrefs(
       user_prefs::PrefRegistrySyncable* registry) override;
@@ -45,7 +45,7 @@
   HoldingSpaceKeyedServiceFactory& operator=(
       const HoldingSpaceKeyedServiceFactory& other) = delete;
 
-  static KeyedService* BuildServiceInstanceForInternal(
+  static std::unique_ptr<KeyedService> BuildServiceInstanceForInternal(
       content::BrowserContext* context);
 };
 
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
index 8b69b0b..de0c0e6 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
@@ -200,6 +200,13 @@
   if (current_bubble_type_ == BubbleType::FAILURE)
     return l10n_util::GetStringUTF16(IDS_AUTOFILL_FAILURE_BUBBLE_EXPLANATION);
 
+  if (current_bubble_type_ == BubbleType::LOCAL_SAVE &&
+      base::FeatureList::IsEnabled(
+          features::kAutofillEnableCvcStorageAndFilling)) {
+    return l10n_util::GetStringUTF16(
+        IDS_AUTOFILL_SAVE_CARD_PROMPT_EXPLANATION_LOCAL);
+  }
+
   if (current_bubble_type_ == BubbleType::LOCAL_CVC_SAVE) {
     return l10n_util::GetStringUTF16(
         IDS_AUTOFILL_SAVE_CVC_PROMPT_EXPLANATION_LOCAL);
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
index 76d6ab2..bb77a30a 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
@@ -624,6 +624,56 @@
       autofill_metrics::SaveCardPromptResult::kUnknown, 1);
 }
 
+TEST_F(SaveCardBubbleControllerImplTest, LocalCardSaveDialogContent) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillEnableCvcStorageAndFilling);
+
+  // Show the local card save bubble.
+  ShowLocalBubble(
+      /*card=*/nullptr,
+      /*options=*/AutofillClient::SaveCreditCardOptions()
+          .with_cvc_save_only(false)
+          .with_show_prompt(true));
+
+  ASSERT_EQ(BubbleType::LOCAL_SAVE, controller()->GetBubbleType());
+  ASSERT_NE(nullptr, controller()->GetPaymentBubbleView());
+  EXPECT_EQ(controller()->GetWindowTitle(), u"Save card?");
+  EXPECT_EQ(controller()->GetExplanatoryMessage(),
+            u"To pay faster next time, save your card to your device");
+}
+
+TEST_F(SaveCardBubbleControllerImplTest, LocalCvcOnlySaveDialogContent) {
+  // Show the local CVC save bubble.
+  ShowLocalBubble(
+      /*card=*/nullptr,
+      /*options=*/AutofillClient::SaveCreditCardOptions()
+          .with_cvc_save_only(true)
+          .with_show_prompt(true));
+
+  ASSERT_EQ(BubbleType::LOCAL_CVC_SAVE, controller()->GetBubbleType());
+  ASSERT_NE(nullptr, controller()->GetPaymentBubbleView());
+  EXPECT_EQ(controller()->GetWindowTitle(), u"Save security code?");
+  EXPECT_EQ(controller()->GetExplanatoryMessage(),
+            u"For faster checkout, save the CVC for this card to your device");
+}
+
+TEST_F(SaveCardBubbleControllerImplTest, UploadCardSaveDialogContent) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillEnableNewSaveCardBubbleUi);
+
+  // Show the server card save bubble.
+  ShowUploadBubble(
+      /*options=*/AutofillClient::SaveCreditCardOptions().with_show_prompt(
+          true));
+
+  ASSERT_EQ(BubbleType::UPLOAD_SAVE, controller()->GetBubbleType());
+  ASSERT_NE(nullptr, controller()->GetPaymentBubbleView());
+  EXPECT_EQ(controller()->GetWindowTitle(), u"Save card?");
+  EXPECT_EQ(controller()->GetExplanatoryMessage(),
+            u"Pay faster next time and protect your card with Google’s "
+            u"industry-leading security.");
+}
+
 TEST_F(SaveCardBubbleControllerImplTest,
        LocalCard_FirstShow_SaveButton_SigninPromo_Close_Reshow_ManageCards) {
   EXPECT_CALL(*mock_sentiment_service_, SavedCard()).Times(1);
@@ -638,8 +688,8 @@
   // After closing the sign-in promo, clicking the icon should bring up the
   // Manage cards bubble. Verify that the icon tooltip, the title for the
   // bubble, and the save animation reflect the correct info.
-  EXPECT_EQ(BubbleType::MANAGE_CARDS, controller()->GetBubbleType());
-  EXPECT_NE(nullptr, controller()->GetPaymentBubbleView());
+  ASSERT_EQ(BubbleType::MANAGE_CARDS, controller()->GetBubbleType());
+  ASSERT_NE(nullptr, controller()->GetPaymentBubbleView());
   EXPECT_EQ(controller()->GetWindowTitle(), u"Card saved");
   EXPECT_EQ(controller()->GetSavePaymentIconTooltipText(), u"Save card");
   EXPECT_EQ(controller()->GetSaveSuccessAnimationStringId(),
@@ -660,8 +710,8 @@
   // After closing the sign-in promo, clicking the icon should bring up the
   // Manage cards bubble. Verify that the icon tooltip, the title for the
   // bubble, and the save animation reflect the correct info.
-  EXPECT_EQ(BubbleType::MANAGE_CARDS, controller()->GetBubbleType());
-  EXPECT_NE(nullptr, controller()->GetPaymentBubbleView());
+  ASSERT_EQ(BubbleType::MANAGE_CARDS, controller()->GetBubbleType());
+  ASSERT_NE(nullptr, controller()->GetPaymentBubbleView());
   EXPECT_EQ(controller()->GetWindowTitle(), u"CVC saved");
   EXPECT_EQ(controller()->GetSavePaymentIconTooltipText(), u"Save CVC");
   EXPECT_EQ(controller()->GetSaveSuccessAnimationStringId(),
@@ -675,7 +725,7 @@
   ShowLocalBubble();
   ClickSaveButton();
   CloseAndReshowBubble();
-  EXPECT_EQ(BubbleType::MANAGE_CARDS, controller()->GetBubbleType());
+  ASSERT_EQ(BubbleType::MANAGE_CARDS, controller()->GetBubbleType());
 
   ClickSaveButton();
   EXPECT_THAT(
diff --git a/chrome/browser/ui/cocoa/screentime/history_bridge_factory.h b/chrome/browser/ui/cocoa/screentime/history_bridge_factory.h
index 6ae32ed84..cf2cd8a 100644
--- a/chrome/browser/ui/cocoa/screentime/history_bridge_factory.h
+++ b/chrome/browser/ui/cocoa/screentime/history_bridge_factory.h
@@ -25,7 +25,7 @@
   static bool IsEnabled();
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsCreatedWithBrowserContext() const override;
   bool ServiceIsNULLWhileTesting() const override;
diff --git a/chrome/browser/ui/cocoa/screentime/history_bridge_factory.mm b/chrome/browser/ui/cocoa/screentime/history_bridge_factory.mm
index c8617c30..a2cefb3 100644
--- a/chrome/browser/ui/cocoa/screentime/history_bridge_factory.mm
+++ b/chrome/browser/ui/cocoa/screentime/history_bridge_factory.mm
@@ -28,7 +28,8 @@
   return base::FeatureList::IsEnabled(kScreenTime);
 }
 
-KeyedService* HistoryBridgeFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+HistoryBridgeFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   auto* profile = Profile::FromBrowserContext(context);
   auto* service = HistoryServiceFactory::GetForProfile(
@@ -36,7 +37,7 @@
 
   auto deleter = HistoryDeleterImpl::Create();
 
-  return new HistoryBridge(service, std::move(deleter));
+  return std::make_unique<HistoryBridge>(service, std::move(deleter));
 }
 
 bool HistoryBridgeFactory::ServiceIsCreatedWithBrowserContext() const {
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 1073123..42a4d919 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include "apps/launcher.h"
 #include "base/command_line.h"
@@ -59,10 +60,6 @@
 #include "ui/display/scoped_display_for_new_windows.h"
 #include "ui/gfx/geometry/rect.h"
 
-#if BUILDFLAG(IS_MAC)
-#include "chrome/browser/ui/browser_commands_mac.h"
-#endif
-
 using content::WebContents;
 using extensions::Extension;
 using extensions::ExtensionPrefs;
@@ -89,7 +86,7 @@
   EnableViaDialogFlow(const EnableViaDialogFlow&) = delete;
   EnableViaDialogFlow& operator=(const EnableViaDialogFlow&) = delete;
 
-  ~EnableViaDialogFlow() override {}
+  ~EnableViaDialogFlow() override = default;
 
   void Run() {
     DCHECK(!service_->IsExtensionEnabled(extension_id_));
@@ -111,9 +108,9 @@
 
   void ExtensionEnableFlowAborted(bool user_initiated) override { delete this; }
 
-  raw_ptr<ExtensionService> service_;
-  raw_ptr<ExtensionRegistry> registry_;
-  raw_ptr<Profile> profile_;
+  const raw_ptr<ExtensionService> service_;
+  const raw_ptr<ExtensionRegistry> registry_;
+  const raw_ptr<Profile> profile_;
   extensions::ExtensionId extension_id_;
   base::OnceClosure callback_;
   std::unique_ptr<ExtensionEnableFlow> flow_;
@@ -183,10 +180,12 @@
   // LAUNCH_TYPE_WINDOW launches in a default app window.
   extensions::LaunchType launch_type =
       extensions::GetLaunchType(ExtensionPrefs::Get(profile), extension);
-  if (launch_type == extensions::LAUNCH_TYPE_FULLSCREEN)
+  if (launch_type == extensions::LAUNCH_TYPE_FULLSCREEN) {
     return ui::SHOW_STATE_MAXIMIZED;
-  else if (launch_type == extensions::LAUNCH_TYPE_WINDOW)
+  }
+  if (launch_type == extensions::LAUNCH_TYPE_WINDOW) {
     return ui::SHOW_STATE_DEFAULT;
+  }
 #endif
 
   return ui::SHOW_STATE_DEFAULT;
@@ -569,13 +568,12 @@
   if (!service->IsExtensionEnabled(extension->id()) ||
       registry->GetExtensionById(extension->id(),
                                  ExtensionRegistry::TERMINATED)) {
-    // TODO(pkotwicz): Figure out which window should be used as the parent for
-    // the "enable application" dialog in Athena.
-    (new EnableViaDialogFlow(
-         service, registry, profile, extension->id(),
-         base::BindOnce(base::IgnoreResult(OpenEnabledApplication), profile,
-                        std::move(params))))
-        ->Run();
+    // Self deleting.
+    auto* flow = new EnableViaDialogFlow(
+        service, registry, profile, extension->id(),
+        base::BindOnce(base::IgnoreResult(OpenEnabledApplication), profile,
+                       std::move(params)));
+    flow->Run();
     return;
   }
 
@@ -589,12 +587,7 @@
       WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromCommandLine);
   launch_params.override_url = url;
 
-  WebContents* tab = OpenApplicationWindow(profile, launch_params, url);
-
-  if (!tab)
-    return nullptr;
-
-  return tab;
+  return OpenApplicationWindow(profile, launch_params, url);
 }
 
 bool CanLaunchViaEvent(const extensions::Extension* extension) {
@@ -628,20 +621,22 @@
 bool ShowBrowserForProfile(Profile* profile,
                            const apps::AppLaunchParams& params) {
   Browser* browser = chrome::FindTabbedBrowser(
-      profile, /*match_original_profiles*/ false, params.display_id);
+      profile, /*match_original_profiles=*/false, params.display_id);
   if (browser) {
     // For existing browser, ensure its window is shown and activated.
     browser->window()->Show();
     browser->window()->Activate();
-  } else {
-    // No browser for this profile, need to open a new one.
-    if (Browser::GetCreationStatusForProfile(profile) !=
-        Browser::CreationStatus::kOk) {
-      return false;
-    }
+    return true;
+  }
+
+  // No browser for this profile, need to open a new one.
+  if (Browser::GetCreationStatusForProfile(profile) ==
+      Browser::CreationStatus::kOk) {
     browser = Browser::Create(
         Browser::CreateParams(Browser::TYPE_NORMAL, profile, true));
     browser->window()->Show();
+    return true;
   }
-  return true;
+
+  return false;
 }
diff --git a/chrome/browser/ui/safety_hub/unused_site_permissions_service.cc b/chrome/browser/ui/safety_hub/unused_site_permissions_service.cc
index feaff77..029b567 100644
--- a/chrome/browser/ui/safety_hub/unused_site_permissions_service.cc
+++ b/chrome/browser/ui/safety_hub/unused_site_permissions_service.cc
@@ -362,7 +362,9 @@
       }
 
       DCHECK_EQ(entry.source.primary_pattern, primary_pattern);
-      DCHECK_EQ(entry.source.secondary_pattern, secondary_pattern);
+      DCHECK(entry.source.secondary_pattern ==
+                 ContentSettingsPattern::Wildcard() ||
+             entry.source.secondary_pattern == entry.source.primary_pattern);
 
       // Reset the permission to default if the site is visited before
       // threshold. Also, the secondary pattern should be wildcard.
diff --git a/chrome/browser/ui/safety_hub/unused_site_permissions_service_browsertest.cc b/chrome/browser/ui/safety_hub/unused_site_permissions_service_browsertest.cc
index 6d0bd47..84c7036 100644
--- a/chrome/browser/ui/safety_hub/unused_site_permissions_service_browsertest.cc
+++ b/chrome/browser/ui/safety_hub/unused_site_permissions_service_browsertest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/safety_hub/unused_site_permissions_service_factory.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/content_settings/core/browser/content_settings_registry.h"
 #include "components/content_settings/core/browser/content_settings_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
@@ -138,3 +139,52 @@
   EXPECT_EQ(CONTENT_SETTING_ASK,
             map->GetContentSetting(url, url, ContentSettingsType::GEOLOCATION));
 }
+
+// Test that revocation happens correctly for all content setting types.
+IN_PROC_BROWSER_TEST_F(UnusedSitePermissionsServiceBrowserTest,
+                       RevokeAllContentSettingTypes) {
+  auto* map =
+      HostContentSettingsMapFactory::GetForProfile(browser()->profile());
+  auto* service =
+      UnusedSitePermissionsServiceFactory::GetForProfile(browser()->profile());
+
+  base::Time time;
+  ASSERT_TRUE(base::Time::FromString("2022-09-07 13:00", &time));
+  base::SimpleTestClock clock;
+  clock.SetNow(time);
+  map->SetClockForTesting(&clock);
+  service->SetClockForTesting(&clock);
+
+  // Allow all content settings in the content setting registry.
+  auto* content_settings_registry =
+      content_settings::ContentSettingsRegistry::GetInstance();
+  for (const content_settings::ContentSettingsInfo* info :
+       *content_settings_registry) {
+    ContentSettingsType type = info->website_settings_info()->type();
+
+    // Add last visited timestamp if the setting can be tracked.
+    content_settings::ContentSettingConstraints constraint;
+    if (content_settings::CanTrackLastVisit(type)) {
+      constraint.set_track_last_visit_for_autoexpiration(true);
+    }
+
+    if (!content_settings_registry->Get(type)->IsSettingValid(
+            ContentSetting::CONTENT_SETTING_ALLOW)) {
+      continue;
+    }
+
+    const GURL url("https://example1.com");
+    map->SetContentSettingDefaultScope(GURL(url), GURL(url), type,
+                                       ContentSetting::CONTENT_SETTING_ALLOW,
+                                       constraint);
+  }
+
+  // Travel through time for 70 days to make permissions be revoked.
+  clock.Advance(base::Days(70));
+  service->UpdateUnusedPermissionsForTesting();
+  ASSERT_EQ(GetRevokedUnusedPermissions(map).size(), 1u);
+
+  // Navigate to content settings page.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(),
+                                           GURL("chrome://settings/content")));
+}
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
index 56a76c1..51e219c 100644
--- a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
+++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
@@ -551,7 +551,6 @@
     case PopupItemId::kPasswordAccountStorageReSignin:
     case PopupItemId::kPasswordAccountStorageOptInAndGenerate:
     case PopupItemId::kShowAccountCards:
-    case PopupItemId::kUseVirtualCard:
     case PopupItemId::kAllSavedPasswordsEntry:
     case PopupItemId::kFillEverythingFromAddressProfile:
     case PopupItemId::kClearForm:
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
index f8356be..135da3cd 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
+#include "chrome/browser/ui/sad_tab_helper.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
@@ -23,6 +24,7 @@
 #include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/profiles/profile_indicator_icon.h"
+#include "chrome/browser/ui/views/sad_tab_view.h"
 #include "chrome/browser/ui/views/side_panel/side_panel.h"
 #include "chrome/browser/ui/views/tab_icon_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
@@ -1051,11 +1053,31 @@
           ? 0
           : corner_radius);
 
+  // SideTabView is shown when the renderer crashes. Initially the SabTabView
+  // gets the same corners as the contents webview it gets attached to but its
+  // radii needs to be updated as it is unaware of the client view layout
+  // changes.
+  bool sad_tab_showing = false;
+  if (contents_webview->web_contents()) {
+    if (auto* sad_tab_helper =
+            SadTabHelper::FromWebContents(contents_webview->web_contents());
+        sad_tab_helper->sad_tab()) {
+      static_cast<SadTabView*>(sad_tab_helper->sad_tab())
+          ->SetBackgroundRadii(contents_webview_radii);
+      sad_tab_showing = true;
+    }
+  }
+
   CHECK(contents_webview);
   CHECK(contents_webview->holder());
 
   contents_webview->SetBackgroundRadii(contents_webview_radii);
-  contents_webview->holder()->SetCornerRadii(contents_webview_radii);
+
+  // We do not need to round contents_webview, if SadTabView is shown instead of
+  // contents_webview.
+  if (!sad_tab_showing) {
+    contents_webview->holder()->SetCornerRadii(contents_webview_radii);
+  }
 }
 
 void BrowserNonClientFrameViewChromeOS::LayoutProfileIndicator() {
diff --git a/chrome/browser/ui/views/frame/contents_web_view.h b/chrome/browser/ui/views/frame/contents_web_view.h
index 399109e..c454b81 100644
--- a/chrome/browser/ui/views/frame/contents_web_view.h
+++ b/chrome/browser/ui/views/frame/contents_web_view.h
@@ -38,6 +38,9 @@
   // Toggles whether the background is visible.
   void SetBackgroundVisible(bool background_visible);
 
+  const gfx::RoundedCornersF& background_radii() const {
+    return background_radii_;
+  }
   void SetBackgroundRadii(const gfx::RoundedCornersF& radii);
 
   // WebView overrides:
diff --git a/chrome/browser/ui/views/sad_tab_view.cc b/chrome/browser/ui/views/sad_tab_view.cc
index 36e1077..b6b07ee 100644
--- a/chrome/browser/ui/views/sad_tab_view.cc
+++ b/chrome/browser/ui/views/sad_tab_view.cc
@@ -6,7 +6,6 @@
 
 #include <string>
 
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -22,6 +21,7 @@
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/color/color_id.h"
+#include "ui/compositor/layer.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/native_theme/common_theme.h"
@@ -571,9 +571,15 @@
   // Needed to ensure this View is drawn even if a sibling (such as dev tools)
   // has a z-order.
   SetPaintToLayer();
-
   AttachToWebView();
 
+  if (owner_) {
+    // If the `owner_` ContentsWebView has a rounded background, the sad tab
+    // should also have matching rounded corners as well.
+    SetBackgroundRadii(
+        static_cast<ContentsWebView*>(owner_)->background_radii());
+  }
+
   // Make the accessibility role of this view an alert dialog, and
   // put focus on the action button. This causes screen readers to
   // immediately announce the text of this view.
@@ -595,6 +601,15 @@
   AttachToWebView();
 }
 
+void SadTabView::SetBackgroundRadii(const gfx::RoundedCornersF& radii) {
+  // Since SadTabView paints onto its own layer and it is leaf layer, we can
+  // round the background by applying rounded corners to the layer without
+  // clipping any other browser content.
+  CHECK(layer());
+  layer()->SetRoundedCornerRadius(radii);
+  layer()->SetIsFastRoundedCorner(/*enable=*/true);
+}
+
 void SadTabView::OnPaint(gfx::Canvas* canvas) {
   if (!painted_) {
     RecordFirstPaint();
diff --git a/chrome/browser/ui/views/sad_tab_view.h b/chrome/browser/ui/views/sad_tab_view.h
index cd168c1..656c336 100644
--- a/chrome/browser/ui/views/sad_tab_view.h
+++ b/chrome/browser/ui/views/sad_tab_view.h
@@ -22,7 +22,11 @@
 
 namespace test {
 class SadTabViewTestApi;
-}
+}  // namespace test
+
+namespace gfx {
+class RoundedCornersF;
+}  // namespace gfx
 
 ///////////////////////////////////////////////////////////////////////////////
 //
@@ -43,6 +47,8 @@
 
   ~SadTabView() override;
 
+  void SetBackgroundRadii(const gfx::RoundedCornersF& radii);
+
   // Overridden from SadTab:
   void ReinstallInWebView() override;
 
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
index c42edcb..d12c86a 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
@@ -865,9 +865,6 @@
 void NewTabPageHandler::MaybeShowCustomizeChromeFeaturePromo() {
   CHECK(profile_);
   CHECK(profile_->GetPrefs());
-  const auto customize_chrome_button_open_count =
-      profile_->GetPrefs()->GetInteger(
-          prefs::kNtpCustomizeChromeButtonOpenCount);
 
   // If a sign-in dialog is being currently displayed, the promo should not be
   // shown to avoid conflict. The sign-in dialog would be shown as soon as the
@@ -875,9 +872,22 @@
   bool is_signin_modal_dialog_open =
       customize_chrome_feature_promo_helper_->IsSigninModalDialogOpen(
           web_contents_.get());
-  if (customize_chrome_button_open_count == 0 && !is_signin_modal_dialog_open) {
+  if (is_signin_modal_dialog_open) {
+    return;
+  }
+
+  if (features::IsChromeRefresh2023()) {
     customize_chrome_feature_promo_helper_
         ->MaybeShowCustomizeChromeFeaturePromo(web_contents_.get());
+  } else {
+    const auto customize_chrome_button_open_count =
+        profile_->GetPrefs()->GetInteger(
+            prefs::kNtpCustomizeChromeButtonOpenCount);
+
+    if (customize_chrome_button_open_count == 0) {
+      customize_chrome_feature_promo_helper_
+          ->MaybeShowCustomizeChromeFeaturePromo(web_contents_.get());
+    }
   }
 }
 
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.cc
index d00d56c..ed4ce701 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.cc
@@ -36,7 +36,8 @@
 
 NTPResourceCacheFactory::~NTPResourceCacheFactory() = default;
 
-KeyedService* NTPResourceCacheFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+NTPResourceCacheFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* profile) const {
-  return new NTPResourceCache(static_cast<Profile*>(profile));
+  return std::make_unique<NTPResourceCache>(static_cast<Profile*>(profile));
 }
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h b/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h
index ec61148b..6925580 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h
@@ -27,7 +27,7 @@
   ~NTPResourceCacheFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
 };
 
diff --git a/chrome/browser/ui/webui/settings/ash/files_page/google_drive_handler_browsertest.cc b/chrome/browser/ui/webui/settings/ash/files_page/google_drive_handler_browsertest.cc
index 2fc7551..e70dfc0 100644
--- a/chrome/browser/ui/webui/settings/ash/files_page/google_drive_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/ash/files_page/google_drive_handler_browsertest.cc
@@ -129,6 +129,29 @@
         });
   }
 
+  base::FilePath CreateFileInContentCache(int file_size_in_bytes) {
+    auto* const service =
+        drive::util::GetIntegrationServiceByProfile(browser()->profile());
+    {
+      // Ensure the content cache directory exists.
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      if (!base::DirectoryExists(service->GetDriveFsContentCachePath())) {
+        EXPECT_TRUE(
+            base::CreateDirectory(service->GetDriveFsContentCachePath()));
+      }
+    }
+    std::string foo_contents = base::RandBytesAsString(file_size_in_bytes);
+    const base::FilePath file_path =
+        service->GetDriveFsContentCachePath().Append("foo.txt");
+    {
+      // Create a file of 32 bytes in the content_cache directory.
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      EXPECT_TRUE(base::WriteFile(file_path, foo_contents));
+    }
+
+    return file_path;
+  }
+
  protected:
   OSSettingsBrowserTestMixin os_settings_mixin_{&mixin_host_};
   FakeSearchQuery fake_search_query_;
@@ -145,10 +168,6 @@
   SetUpSearchResultExpectations();
   fake_search_query_.SetSearchResults({});
 
-  auto* fake_drivefs = GetFakeDriveFsForProfile(browser()->profile());
-  EXPECT_CALL(*fake_drivefs, GetOfflineFilesSpaceUsage(_))
-      .WillRepeatedly(RunOnceCallback<0>(drive::FILE_ERROR_OK, 1));
-
   // Expect the free space to be 1 GB (1,073,741,824 bytes), the required space
   // to be 0 KB (0 items).
   int64_t free_space = 1024 * 1024 * 1024;
@@ -167,9 +186,6 @@
                        OnlyUnpinnedResultsUpdateTheSpaceRequirements) {
   SetUpSearchResultExpectations();
 
-  auto* fake_drivefs = GetFakeDriveFsForProfile(browser()->profile());
-  EXPECT_CALL(*fake_drivefs, GetOfflineFilesSpaceUsage(_))
-      .WillRepeatedly(RunOnceCallback<0>(drive::FILE_ERROR_OK, 1));
 
   // Each item is 125 MB in size, total required space should be 500 MB.
   int64_t file_size = 125 * 1024 * 1024;
@@ -196,21 +212,7 @@
   ash::FakeSpacedClient::Get()->set_free_disk_space(int64_t(3) << 30);
 
   constexpr int file_size_in_bytes = 32;
-  auto* const service =
-      drive::util::GetIntegrationServiceByProfile(browser()->profile());
-  {
-    // Ensure the content cache directory exists.
-    base::ScopedAllowBlockingForTesting allow_blocking;
-    ASSERT_TRUE(base::CreateDirectory(service->GetDriveFsContentCachePath()));
-  }
-  std::string foo_contents = base::RandBytesAsString(file_size_in_bytes);
-  const base::FilePath file_path =
-      service->GetDriveFsContentCachePath().Append("foo.txt");
-  {
-    // Create a file of 32 bytes in the content_cache directory.
-    base::ScopedAllowBlockingForTesting allow_blocking;
-    ASSERT_TRUE(base::WriteFile(file_path, foo_contents));
-  }
+  CreateFileInContentCache(file_size_in_bytes);
 
   auto google_drive_settings = OpenGoogleDriveSettings();
   google_drive_settings.AssertBulkPinningPinnedSize(
@@ -219,13 +221,25 @@
 
 IN_PROC_BROWSER_TEST_F(GoogleDriveHandlerTest,
                        ClearingOfflineFilesCallsProperMethods) {
-  SetUpSearchResultExpectations();
-
   // Mock no search results are returned (this avoids the call to
   // `CalculateRequiredSpace` from being ran here).
   fake_search_query_.SetSearchResults({});
   ash::FakeSpacedClient::Get()->set_free_disk_space(int64_t(3) << 30);
 
+  const base::FilePath file_path = CreateFileInContentCache(32);
+
+  auto* fake_drivefs = GetFakeDriveFsForProfile(browser()->profile());
+  EXPECT_CALL(*fake_drivefs, ClearOfflineFiles(_))
+      .WillOnce(
+          [&file_path](
+              drivefs::mojom::DriveFs::ClearOfflineFilesCallback callback) {
+            {
+              base::ScopedAllowBlockingForTesting allow_blocking;
+              ASSERT_TRUE(base::DeleteFile(file_path));
+            }
+            std::move(callback).Run(drive::FILE_ERROR_OK);
+          });
+
   auto google_drive_settings = OpenGoogleDriveSettings();
   google_drive_settings.ClickClearOfflineFilesAndAssertNewSize(
       FormatBytesToString(0));
diff --git a/chrome/browser/ui/webui/settings/ash/os_settings_password_setup_browsertest.cc b/chrome/browser/ui/webui/settings/ash/os_settings_password_setup_browsertest.cc
deleted file mode 100644
index c9883ed..0000000
--- a/chrome/browser/ui/webui/settings/ash/os_settings_password_setup_browsertest.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/ash/settings/test_support/os_settings_lock_screen_browser_test_base.h"
-#include "chrome/test/data/webui/settings/chromeos/os_people_page/password_settings_api.test-mojom-test-utils.h"
-#include "chrome/test/data/webui/settings/chromeos/test_api.test-mojom-test-utils.h"
-#include "content/public/test/browser_test.h"
-
-namespace ash::settings {
-
-class OSSettingsPasswordSetupTest : public OSSettingsLockScreenBrowserTestBase {
-  using OSSettingsLockScreenBrowserTestBase::
-      OSSettingsLockScreenBrowserTestBase;
-
- public:
-  mojom::PasswordSettingsApiAsyncWaiter GoToPasswordSettings(
-      mojom::LockScreenSettingsAsyncWaiter& lock_screen_settings) {
-    password_settings_remote_ =
-        mojo::Remote(lock_screen_settings.GoToPasswordSettings());
-    return mojom::PasswordSettingsApiAsyncWaiter(
-        password_settings_remote_.get());
-  }
-
- private:
-  mojo::Remote<mojom::PasswordSettingsApi> password_settings_remote_;
-};
-
-class OSSettingsPasswordSetupTestWithGaiaPassword
-    : public OSSettingsPasswordSetupTest {
- public:
-  OSSettingsPasswordSetupTestWithGaiaPassword()
-      : OSSettingsPasswordSetupTest(PasswordType::kGaia) {}
-};
-class OSSettingsPasswordSetupTestWithLocalPassword
-    : public OSSettingsPasswordSetupTest {
- public:
-  OSSettingsPasswordSetupTestWithLocalPassword()
-      : OSSettingsPasswordSetupTest(PasswordType::kLocal) {}
-};
-
-IN_PROC_BROWSER_TEST_F(OSSettingsPasswordSetupTestWithGaiaPassword, NotShown) {
-  mojom::LockScreenSettingsAsyncWaiter lock_screen_settings =
-      OpenLockScreenSettingsAndAuthenticate();
-  lock_screen_settings.AssertPasswordControlVisibility(false);
-}
-
-IN_PROC_BROWSER_TEST_F(OSSettingsPasswordSetupTestWithLocalPassword, Selected) {
-  mojom::LockScreenSettingsAsyncWaiter lock_screen_settings =
-      OpenLockScreenSettingsAndAuthenticate();
-  mojom::PasswordSettingsApiAsyncWaiter password_settings =
-      GoToPasswordSettings(lock_screen_settings);
-
-  password_settings.AssertSelectedPasswordType(mojom::PasswordType::kLocal);
-}
-
-}  // namespace ash::settings
diff --git a/chrome/browser/ui/webui/settings/safety_hub_handler.cc b/chrome/browser/ui/webui/settings/safety_hub_handler.cc
index 0c3854ee..345dc34 100644
--- a/chrome/browser/ui/webui/settings/safety_hub_handler.cc
+++ b/chrome/browser/ui/webui/settings/safety_hub_handler.cc
@@ -209,9 +209,21 @@
         stored_value.GetDict().FindList(permissions::kRevokedKey)->Clone();
     base::Value::List permissions_value_list;
     for (base::Value& type : type_list) {
-      permissions_value_list.Append(
+      base::StringPiece permission_str =
           site_settings::ContentSettingsTypeToGroupName(
-              static_cast<ContentSettingsType>(type.GetInt())));
+              static_cast<ContentSettingsType>(type.GetInt()));
+      if (!permission_str.empty()) {
+        permissions_value_list.Append(permission_str);
+      }
+    }
+
+    // Some permissions have no readable name, although Safety Hub revokes them.
+    // To prevent crashes, if there is no permission to be shown in the UI, the
+    // origin will not be added to the revoked permissions list.
+    // TODO(crbug.com/1459305): Remove this after adding check for
+    // ContentSettingsTypeToGroupName.
+    if (permissions_value_list.empty()) {
+      continue;
     }
 
     revoked_permission_value.Set(
diff --git a/chrome/browser/ui/webui/settings/safety_hub_handler.h b/chrome/browser/ui/webui/settings/safety_hub_handler.h
index c09f3d64..2d9b928 100644
--- a/chrome/browser/ui/webui/settings/safety_hub_handler.h
+++ b/chrome/browser/ui/webui/settings/safety_hub_handler.h
@@ -64,6 +64,7 @@
   FRIEND_TEST_ALL_PREFIXES(
       SafetyHubHandlerTest,
       SendNotificationPermissionReviewList_FeatureDisabled);
+  FRIEND_TEST_ALL_PREFIXES(SafetyHubHandlerTest, RevokeAllContentSettingTypes);
 
   // SettingsPageUIHandler implementation.
   void OnJavascriptAllowed() override;
diff --git a/chrome/browser/ui/webui/settings/safety_hub_handler_unittest.cc b/chrome/browser/ui/webui/settings/safety_hub_handler_unittest.cc
index de6a1f7d..e55124f 100644
--- a/chrome/browser/ui/webui/settings/safety_hub_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/safety_hub_handler_unittest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/webui/settings/site_settings_helper.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/content_settings/core/browser/content_settings_registry.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
@@ -424,3 +425,58 @@
   SetPrefsForSafeBrowsing(false, true, SettingManager::USER);
   ValidateHandleSafeBrowsingState(SafeBrowsingState::kDisabledByUser);
 }
+
+// Test that revocation is happen correctly for all content setting types.
+TEST_F(SafetyHubHandlerTest, RevokeAllContentSettingTypes) {
+  // TODO(crbug.com/1459305): Remove this after adding names for those
+  // types.
+  std::list<ContentSettingsType> no_name_types = {
+      ContentSettingsType::MIDI,
+      ContentSettingsType::DURABLE_STORAGE,
+      ContentSettingsType::ACCESSIBILITY_EVENTS,
+      ContentSettingsType::NFC,
+      ContentSettingsType::FILE_SYSTEM_READ_GUARD,
+      ContentSettingsType::CAMERA_PAN_TILT_ZOOM,
+      ContentSettingsType::TOP_LEVEL_STORAGE_ACCESS};
+
+  // Add all content settings in the content setting registry to revoked
+  // permissions list.
+  auto* content_settings_registry =
+      content_settings::ContentSettingsRegistry::GetInstance();
+  for (const content_settings::ContentSettingsInfo* info :
+       *content_settings_registry) {
+    ContentSettingsType type = info->website_settings_info()->type();
+
+    // If the permission can not be tracked, then also can not be revoked.
+    if (!content_settings::CanTrackLastVisit(type)) {
+      continue;
+    }
+
+    // If the permission can not set to ALLOW, then also can not be revoked.
+    if (!content_settings_registry->Get(type)->IsSettingValid(
+            ContentSetting::CONTENT_SETTING_ALLOW)) {
+      continue;
+    }
+
+    // Add the permission to revoked permission list.
+    auto dict = base::Value::Dict().Set(
+        permissions::kRevokedKey,
+        base::Value::List().Append(static_cast<int32_t>(type)));
+    hcsm()->SetWebsiteSettingDefaultScope(
+        GURL(kUnusedTestSite), GURL(kUnusedTestSite),
+        ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS,
+        base::Value(dict.Clone()));
+
+    // Unless the permission in no_name_types, it should be shown on the UI.
+    const auto& revoked_permissions =
+        handler()->PopulateUnusedSitePermissionsData();
+    bool is_no_name_type =
+        (std::find(no_name_types.begin(), no_name_types.end(), type) !=
+         no_name_types.end());
+    if (is_no_name_type) {
+      EXPECT_EQ(revoked_permissions.size(), 0U);
+    } else {
+      EXPECT_EQ(revoked_permissions.size(), 1U);
+    }
+  }
+}
diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chrome/browser/ui/webui/settings/site_settings_helper.cc
index c0ffb1b..e1f9f394 100644
--- a/chrome/browser/ui/webui/settings/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_helper.cc
@@ -474,12 +474,18 @@
 }
 
 base::StringPiece ContentSettingsTypeToGroupName(ContentSettingsType type) {
-  for (size_t i = 0; i < std::size(kContentSettingsTypeGroupNames); ++i) {
-    if (type == kContentSettingsTypeGroupNames[i].type) {
-      const char* name = kContentSettingsTypeGroupNames[i].name;
-      if (name)
-        return name;
-      break;
+  for (const auto& entry : kContentSettingsTypeGroupNames) {
+    if (type == entry.type) {
+      // Content setting types that aren't represented in the settings UI
+      // will have `nullptr` as their `name`. Although they are valid content
+      // settings types, they don't have a readable name.
+      // TODO(crbug.com/1459305): Replace LOG with CHECK.
+      if (!entry.name) {
+        LOG(ERROR) << static_cast<int32_t>(type)
+                   << " does not have a readable name.";
+      }
+
+      return entry.name ? entry.name : base::StringPiece();
     }
   }
 
diff --git a/chrome/browser/usb/usb_connection_tracker_factory.cc b/chrome/browser/usb/usb_connection_tracker_factory.cc
index 627386f8..598ed588 100644
--- a/chrome/browser/usb/usb_connection_tracker_factory.cc
+++ b/chrome/browser/usb/usb_connection_tracker_factory.cc
@@ -37,9 +37,11 @@
 
 UsbConnectionTrackerFactory::~UsbConnectionTrackerFactory() = default;
 
-KeyedService* UsbConnectionTrackerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+UsbConnectionTrackerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new UsbConnectionTracker(Profile::FromBrowserContext(context));
+  return std::make_unique<UsbConnectionTracker>(
+      Profile::FromBrowserContext(context));
 }
 
 void UsbConnectionTrackerFactory::BrowserContextShutdown(
diff --git a/chrome/browser/usb/usb_connection_tracker_factory.h b/chrome/browser/usb/usb_connection_tracker_factory.h
index db14652..39ccebb 100644
--- a/chrome/browser/usb/usb_connection_tracker_factory.h
+++ b/chrome/browser/usb/usb_connection_tracker_factory.h
@@ -26,7 +26,7 @@
   ~UsbConnectionTrackerFactory() override;
 
   // BrowserContextKeyedBaseFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
   void BrowserContextShutdown(content::BrowserContext* context) override;
 };
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 7c72f82..2a7ebf9 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1692727167-dc84bea84ee06c549525c89af7566751f980169a.profdata
+chrome-android32-main-1692748490-c06965b816013a4530a30c49c3ef6541b61e2179.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 5d03925..953d934 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1692727167-55886d71ecef8bda4393c4413b8017b9ff68c0f2.profdata
+chrome-android64-main-1692748490-b387ab6f3f76466e74b286346b2717c68fd7add7.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 68e35fe..94e5e4f 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1692734385-f8b5079f20fb00dbba55ed2baea8500132f74f1e.profdata
+chrome-mac-arm-main-1692741483-70c10d25884f445c21d557791fa3d363734ac012.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 1288bc5c..a617603 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1692727167-c621730366ff87856ecd365d1b271cfe13482c28.profdata
+chrome-win64-main-1692737847-5f2e9348dec0a0a0ca265724b1abb08da009c83e.profdata
diff --git a/chrome/services/printing/public/mojom/pdf_nup_converter.mojom b/chrome/services/printing/public/mojom/pdf_nup_converter.mojom
index 1546899..da290f2 100644
--- a/chrome/services/printing/public/mojom/pdf_nup_converter.mojom
+++ b/chrome/services/printing/public/mojom/pdf_nup_converter.mojom
@@ -8,20 +8,9 @@
 import "ui/gfx/geometry/mojom/geometry.mojom";
 import "url/mojom/url.mojom";
 
-// This set of interfaces is used to do Nup PDF conversion.
-// Usage:
-// - generate a PdfNupConverter.
-//
-// - call PdfNupConverter.NupPageConvert() to import N PDF pages into one N-up
-//   PDF page.
-//
-// - call PdfNupConverter.NupDocumentConvert() to convert a PDF document to a
-//   N-up PDF document.
-//
-// - call PdfNupConverter.SetWebContentsURL() to set the URL that is committed
-//   in the main frame of the WebContents for crash diagnosis.
+// Used by the browser process to perform N-up PDF conversion in a separate
+// sandboxed service process, as the PDF data is untrusted user input.
 interface PdfNupConverter {
-
   // The status of PDF conversion execution.
   enum Status {
     SUCCESS = 0,
@@ -29,7 +18,7 @@
     HANDLE_MAP_ERROR = 2,
   };
 
-  // Convert a list of PDF pages to a N-up PDF.
+  // Converts a list of PDF pages to a N-up PDF.
   // `pages_per_sheet` is the number of pages to put on a single sheet.
   // `page_size` is the output page size, measured in PDF "user space" units.
   // `printable_area` is the printable area of the output page, measured in
@@ -45,7 +34,7 @@
       array<mojo_base.mojom.ReadOnlySharedMemoryRegion> pdf_page_regions)
    => (Status status, mojo_base.mojom.ReadOnlySharedMemoryRegion? pdf_region);
 
-  // Convert a PDF document to a N-up PDF document.
+  // Converts a PDF document to a N-up PDF document.
   // `pages_per_sheet` is the number of pages to put on a single sheet.
   // `page_size` is the output page size, measured in PDF "user space" units.
   // `printable_area` is the printable area of the output page, measured in
@@ -56,8 +45,8 @@
                      mojo_base.mojom.ReadOnlySharedMemoryRegion src_pdf_region)
    => (Status status, mojo_base.mojom.ReadOnlySharedMemoryRegion? pdf_region);
 
-  // Sets the URL which is committed in the main frame of the WebContents,
-  // for use in crash diagnosis.
+  // Tells the service what URL is committed in the main frame of the
+  // WebContents that is printing, for use in crash diagnosis.
   SetWebContentsURL(url.mojom.Url url);
 
   // Sets the status for enterprise policy `kPdfUseSkiaRendererEnabled`. It
diff --git a/chrome/services/sharing/nearby/platform/BUILD.gn b/chrome/services/sharing/nearby/platform/BUILD.gn
index 74aaf5d..5fb40f4 100644
--- a/chrome/services/sharing/nearby/platform/BUILD.gn
+++ b/chrome/services/sharing/nearby/platform/BUILD.gn
@@ -69,6 +69,7 @@
   ]
 
   public_deps = [
+    "//third_party/nearby:connections_local_credential_proto",
     "//third_party/nearby:platform_api_platform",
     "//third_party/nearby:platform_impl_shared_file",
   ]
@@ -77,6 +78,7 @@
     "//ash/constants",
     "//base",
     "//chrome/services/sharing/webrtc",
+    "//chromeos/ash/components/nearby/presence/conversions:conversions",
     "//chromeos/ash/services/nearby/public/cpp:tcp_server_socket_port",
     "//chromeos/ash/services/nearby/public/mojom",
     "//chromeos/services/network_config/public/mojom",
diff --git a/chrome/services/sharing/nearby/platform/DEPS b/chrome/services/sharing/nearby/platform/DEPS
index c2af5ef..936d5a33 100644
--- a/chrome/services/sharing/nearby/platform/DEPS
+++ b/chrome/services/sharing/nearby/platform/DEPS
@@ -8,12 +8,14 @@
   '+services/network/public',
   '+third_party/abseil-cpp/absl/strings/string_view.h',
   '+third_party/abseil-cpp/absl/time/time.h',
+  '+third_party/nearby',
   '+unicode/locid.h',
   '+chromeos/ash/components/login/login_state/login_state.h',
   '+chromeos/ash/components/network/proxy/ui_proxy_config_service.h',
   '+chromeos/ash/components/network/managed_network_configuration_handler.h',
   '+chromeos/ash/components/network/network_configuration_handler.h',
   '+chromeos/ash/components/network/network_profile_handler.h',
+  '+chromeos/ash/components/nearby/presence/conversions/proto_conversions.h',
   '+components/onc/onc_constants.h',
   '+components/onc/onc_pref_names.h',
   '+components/prefs/testing_pref_service.h',
diff --git a/chrome/services/sharing/nearby/platform/credential_storage.cc b/chrome/services/sharing/nearby/platform/credential_storage.cc
index d38c659..c85cd93 100644
--- a/chrome/services/sharing/nearby/platform/credential_storage.cc
+++ b/chrome/services/sharing/nearby/platform/credential_storage.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "chrome/services/sharing/nearby/platform/credential_storage.h"
+#include "chromeos/ash/components/nearby/presence/conversions/proto_conversions.h"
+#include "chromeos/ash/services/nearby/public/mojom/nearby_presence.mojom.h"
 
 namespace nearby::chrome {
 
@@ -21,7 +23,19 @@
     const std::vector<LocalCredential>& private_credentials,
     const std::vector<SharedCredential>& public_credentials,
     PublicCredentialType public_credential_type,
-    SaveCredentialsResultCallback callback) {}
+    SaveCredentialsResultCallback callback) {
+  std::vector<ash::nearby::presence::mojom::LocalCredentialPtr>
+      local_credentials_mojom;
+  for (const auto& local_credential : private_credentials) {
+    local_credentials_mojom.push_back(
+        ash::nearby::presence::proto::LocalCredentialToMojom(local_credential));
+  }
+
+  nearby_presence_credential_storage_->SaveCredentials(
+      std::move(local_credentials_mojom),
+      base::BindOnce(&CredentialStorage::OnCredentialsSaved,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
 
 // TODO(b/287334012): Implement.
 void CredentialStorage::UpdateLocalCredential(
@@ -41,4 +55,20 @@
     PublicCredentialType public_credential_type,
     GetPublicCredentialsResultCallback callback) {}
 
+void CredentialStorage::OnCredentialsSaved(
+    nearby::presence::SaveCredentialsResultCallback
+        on_credentials_saved_callback,
+    ash::nearby::presence::mojom::StatusCode credential_save_result) {
+  // TODO(b/297097956): Use AbslStatusCode in callback rather than StatusCode
+  // once NP migration to this type lands.
+  if (credential_save_result == ash::nearby::presence::mojom::StatusCode::kOk) {
+    std::move(on_credentials_saved_callback)
+        .credentials_saved_cb(absl::OkStatus());
+  } else {
+    std::move(on_credentials_saved_callback)
+        .credentials_saved_cb(absl::Status(absl::StatusCode::kUnknown,
+                                           "Failed to save to database."));
+  }
+}
+
 }  // namespace nearby::chrome
diff --git a/chrome/services/sharing/nearby/platform/credential_storage.h b/chrome/services/sharing/nearby/platform/credential_storage.h
index f2ac3949..e84d125 100644
--- a/chrome/services/sharing/nearby/platform/credential_storage.h
+++ b/chrome/services/sharing/nearby/platform/credential_storage.h
@@ -46,9 +46,15 @@
       GetPublicCredentialsResultCallback callback) override;
 
  private:
+  void OnCredentialsSaved(
+      nearby::presence::SaveCredentialsResultCallback
+          on_credentials_saved_callback,
+      ash::nearby::presence::mojom::StatusCode credential_save_result);
+
   const mojo::SharedRemote<
       ash::nearby::presence::mojom::NearbyPresenceCredentialStorage>
       nearby_presence_credential_storage_;
+  base::WeakPtrFactory<CredentialStorage> weak_ptr_factory_{this};
 };
 
 }  // namespace nearby::chrome
diff --git a/chrome/services/sharing/nearby/platform/credential_storage_unittest.cc b/chrome/services/sharing/nearby/platform/credential_storage_unittest.cc
index e26ff8a4..87c16284 100644
--- a/chrome/services/sharing/nearby/platform/credential_storage_unittest.cc
+++ b/chrome/services/sharing/nearby/platform/credential_storage_unittest.cc
@@ -3,9 +3,114 @@
 // found in the LICENSE file.
 
 #include "chrome/services/sharing/nearby/platform/credential_storage.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
 #include "chromeos/ash/services/nearby/public/mojom/nearby_presence_credential_storage.mojom.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "mojo/public/cpp/bindings/shared_remote.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/nearby/internal/proto/local_credential.pb.h"
+#include "third_party/nearby/src/internal/platform/implementation/credential_callbacks.h"
+
+namespace {
+
+const char kManagerAppName[] = "test_manager_app_id";
+const char kAccountName[] = "test_account_name";
+
+const std::vector<uint8_t> kSecretId_1 = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
+const std::vector<uint8_t> kKeySeed_1 = {0x21, 0x22, 0x23, 0x24, 0x25, 0x26};
+const std::vector<uint8_t> kMetadataEncryptionKeyV0_1 = {
+    0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e};
+constexpr int64_t kStartTimeMillis_1 = 255486129307;
+const char AdvertisementSigningKeyCertificateAlias_1[] =
+    "NearbySharingABCDEF123456";
+const std::vector<uint8_t> kAdvertisementPrivateKey_1 = {0x41, 0x42, 0x43,
+                                                         0x44, 0x45, 0x46};
+const char ConnectionSigningKeyCertificateAlias_1[] = "NearbySharingXYZ789";
+const std::vector<uint8_t> kConnectionPrivateKey_1 = {0x51, 0x52, 0x53,
+                                                      0x54, 0x55, 0x56};
+const std::vector<uint8_t> kMetadataEncryptionKeyV1_1 = {
+    0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+    0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70};
+const base::flat_map<uint32_t, bool> kConsumedSalts_1 = {{0xb412, true},
+                                                         {0x34b2, false},
+                                                         {0x5171, false}};
+
+::nearby::internal::LocalCredential CreateLocalCredentialProto(
+    const std::vector<uint8_t>& secret_id,
+    const std::vector<uint8_t>& key_seed,
+    int64_t start_time_millis,
+    const std::vector<uint8_t>& metadata_encryption_key_v0,
+    const std::string& advertisement_signing_key_certificate_alias,
+    const std::vector<uint8_t>& advertisement_private_key,
+    const std::string& connection_signing_key_certificate_alias,
+    const std::vector<uint8_t>& connection_private_key,
+    const base::flat_map<uint32_t, bool>& consumed_salts,
+    const std::vector<uint8_t>& metadata_encryption_key_v1) {
+  ::nearby::internal::LocalCredential proto;
+
+  proto.set_secret_id(std::string(secret_id.begin(), secret_id.end()));
+  proto.set_key_seed(std::string(key_seed.begin(), key_seed.end()));
+  proto.set_start_time_millis(start_time_millis);
+  proto.set_metadata_encryption_key_v0(std::string(
+      metadata_encryption_key_v0.begin(), metadata_encryption_key_v0.end()));
+
+  proto.mutable_advertisement_signing_key()->set_certificate_alias(
+      advertisement_signing_key_certificate_alias);
+  proto.mutable_advertisement_signing_key()->set_key(std::string(
+      advertisement_private_key.begin(), advertisement_private_key.end()));
+
+  proto.mutable_connection_signing_key()->set_certificate_alias(
+      connection_signing_key_certificate_alias);
+  proto.mutable_connection_signing_key()->set_key(std::string(
+      connection_private_key.begin(), connection_private_key.end()));
+
+  // All local credentials have IdentityType of kIdentityTypePrivate.
+  proto.set_identity_type(
+      ::nearby::internal::IdentityType::IDENTITY_TYPE_PRIVATE);
+
+  for (const auto& pair : consumed_salts) {
+    auto map_pair =
+        ::google::protobuf::MapPair<uint32_t, bool>(pair.first, pair.second);
+    proto.mutable_consumed_salts()->insert(map_pair);
+  }
+
+  proto.set_metadata_encryption_key_v1(std::string(
+      metadata_encryption_key_v1.begin(), metadata_encryption_key_v1.end()));
+
+  return proto;
+}
+
+class FakeNearbyPresenceCredentialStorage
+    : public ash::nearby::presence::mojom::NearbyPresenceCredentialStorage {
+ public:
+  FakeNearbyPresenceCredentialStorage() = default;
+  ~FakeNearbyPresenceCredentialStorage() override = default;
+
+  // mojom::NearbyPresenceCredentialStorage:
+  void SaveCredentials(
+      std::vector<ash::nearby::presence::mojom::LocalCredentialPtr>
+          local_credentials,
+      ash::nearby::presence::mojom::NearbyPresenceCredentialStorage::
+          SaveCredentialsCallback callback) override {
+    if (should_credentials_successfully_save_) {
+      std::move(callback).Run(ash::nearby::presence::mojom::StatusCode::kOk);
+    } else {
+      std::move(callback).Run(
+          ash::nearby::presence::mojom::StatusCode::kFailure);
+    }
+  }
+
+  void SetShouldCredentialsSuccessfullySave(bool should_succeed) {
+    should_credentials_successfully_save_ = should_succeed;
+  }
+
+ private:
+  bool should_credentials_successfully_save_ = true;
+};
+
+}  // namespace
 
 namespace nearby::chrome {
 
@@ -17,19 +122,106 @@
 
   // testing::Test:
   void SetUp() override {
+    auto fake_credential_storage =
+        std::make_unique<FakeNearbyPresenceCredentialStorage>();
+    fake_credential_storage_ = fake_credential_storage.get();
+
+    mojo::PendingRemote<
+        ash::nearby::presence::mojom::NearbyPresenceCredentialStorage>
+        pending_remote;
+    mojo::MakeSelfOwnedReceiver(
+        std::move(fake_credential_storage),
+        pending_remote.InitWithNewPipeAndPassReceiver());
+
+    remote_credential_storage_.Bind(std::move(pending_remote),
+                                    /*bind_task_runner=*/nullptr);
+
     credential_storage_ =
-        std::make_unique<CredentialStorage>(remote_credential_storage);
+        std::make_unique<CredentialStorage>(remote_credential_storage_);
+  }
+
+  void TearDown() override {
+    // Prevent dangling raw pointer once 'remote_credential_storage_' is
+    // deconstructed.
+    fake_credential_storage_ = nullptr;
   }
 
  protected:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+
   mojo::SharedRemote<
       ash::nearby::presence::mojom::NearbyPresenceCredentialStorage>
-      remote_credential_storage;
+      remote_credential_storage_;
   std::unique_ptr<CredentialStorage> credential_storage_;
+  raw_ptr<FakeNearbyPresenceCredentialStorage> fake_credential_storage_;
 };
 
 TEST_F(CredentialStorageTest, Initialize) {
   EXPECT_TRUE(credential_storage_);
 }
 
+TEST_F(CredentialStorageTest, SaveCredentials_Succeed) {
+  std::vector<::nearby::internal::LocalCredential> local_credentials;
+
+  local_credentials.emplace_back(CreateLocalCredentialProto(
+      kSecretId_1, kKeySeed_1, kStartTimeMillis_1, kMetadataEncryptionKeyV0_1,
+      AdvertisementSigningKeyCertificateAlias_1, kAdvertisementPrivateKey_1,
+      ConnectionSigningKeyCertificateAlias_1, kConnectionPrivateKey_1,
+      kConsumedSalts_1, kMetadataEncryptionKeyV1_1));
+
+  // TODO(b/287334195): Populate and save public credentials once
+  // CredentialStorage has public credential support.
+  std::vector<::nearby::internal::SharedCredential> shared_credentials;
+
+  base::RunLoop run_loop;
+
+  nearby::presence::SaveCredentialsResultCallback callback;
+  callback.credentials_saved_cb =
+      absl::AnyInvocable<void(absl::Status)>([&](const absl::Status& status) {
+        EXPECT_TRUE(status.ok());
+        run_loop.Quit();
+      });
+
+  fake_credential_storage_->SetShouldCredentialsSuccessfullySave(
+      /*should_succeed=*/true);
+  credential_storage_->SaveCredentials(
+      kManagerAppName, kAccountName, local_credentials, shared_credentials,
+      ::nearby::presence::PublicCredentialType::kLocalPublicCredential,
+      std::move(callback));
+
+  run_loop.Run();
+}
+
+TEST_F(CredentialStorageTest, SaveCredentials_Fail) {
+  std::vector<::nearby::internal::LocalCredential> local_credentials;
+
+  local_credentials.emplace_back(CreateLocalCredentialProto(
+      kSecretId_1, kKeySeed_1, kStartTimeMillis_1, kMetadataEncryptionKeyV0_1,
+      AdvertisementSigningKeyCertificateAlias_1, kAdvertisementPrivateKey_1,
+      ConnectionSigningKeyCertificateAlias_1, kConnectionPrivateKey_1,
+      kConsumedSalts_1, kMetadataEncryptionKeyV1_1));
+
+  // TODO(b/287334195): Populate and save public credentials once
+  // CredentialStorage has public credential support.
+  std::vector<::nearby::internal::SharedCredential> shared_credentials;
+
+  base::RunLoop run_loop;
+
+  nearby::presence::SaveCredentialsResultCallback callback;
+  callback.credentials_saved_cb =
+      absl::AnyInvocable<void(absl::Status)>([&](const absl::Status& status) {
+        EXPECT_FALSE(status.ok());
+        run_loop.Quit();
+      });
+
+  fake_credential_storage_->SetShouldCredentialsSuccessfullySave(
+      /*should_succeed=*/false);
+  credential_storage_->SaveCredentials(
+      kManagerAppName, kAccountName, local_credentials, shared_credentials,
+      ::nearby::presence::PublicCredentialType::kLocalPublicCredential,
+      std::move(callback));
+
+  run_loop.Run();
+}
+
 }  // namespace nearby::chrome
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 7aa0a83..8580574 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3058,6 +3058,7 @@
         "//chromeos/ui/base",
         "//chromeos/ui/frame:test_support",
         "//components/account_manager_core:test_support",
+        "//components/app_constants",
         "//components/services/app_service",
         "//components/webapk:proto",
         "//ui/wm:wm",
@@ -4525,7 +4526,6 @@
         "../browser/ui/webui/settings/ash/os_settings_auto_screen_lock_browsertest.cc",
         "../browser/ui/webui/settings/ash/os_settings_lock_screen_authentication_browsertest.cc",
         "../browser/ui/webui/settings/ash/os_settings_notification_settings_browsertest.cc",
-        "../browser/ui/webui/settings/ash/os_settings_password_setup_browsertest.cc",
         "../browser/ui/webui/settings/ash/os_settings_pin_setup_browsertest.cc",
         "../browser/ui/webui/settings/ash/os_settings_recovery_browsertest.cc",
         "../browser/ui/webui/signin/ash/inline_login_dialog_browsertest.cc",
@@ -5209,7 +5209,6 @@
       "../browser/accessibility/live_caption/live_caption_surface_browsertest.cc",
       "../browser/chromeos/extensions/contact_center_insights/contact_center_insights_extension_manager_lacros_browsertest.cc",
       "../browser/chromeos/reporting/network/network_bandwidth_sampler_lacros_browsertest.cc",
-      "../browser/ui/autofill/autofill_context_menu_manager_lacros_browsertest.cc",
 
       # dlp_content_manager_lacros_browsertest.cc should become a unit test.
       "../browser/chromeos/policy/dlp/dlp_content_manager_lacros_browsertest.cc",
@@ -5341,6 +5340,7 @@
       "../browser/metrics/structured/lacros_structured_metrics_recorder_browsertest.cc",
       "../browser/payments/webapps/payment_request_lacros_browsertest.cc",
       "../browser/speech/extension_api/tts_extension_api_lacros_browsertest.cc",
+      "../browser/ui/autofill/autofill_context_menu_manager_lacros_browsertest.cc",
       "../browser/ui/browser_navigator_browsertest.cc",
       "../browser/ui/browser_navigator_browsertest.h",
       "../browser/ui/browser_navigator_browsertest_chromeos.cc",
@@ -6056,6 +6056,7 @@
     "../browser/security_events/security_event_recorder_impl_unittest.cc",
     "../browser/segmentation_platform/segmentation_platform_config_unittest.cc",
     "../browser/segmentation_platform/segmentation_platform_profile_observer_unittest.cc",
+    "../browser/segmentation_platform/segmentation_platform_service_factory_unittest.cc",
     "../browser/signin/e2e_tests/test_accounts_util_unittest.cc",
 
     # TODO(hashimoto): those tests should be componentized and moved to
diff --git a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
index 509becf9..c1ea169 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
@@ -44,7 +44,6 @@
     loadTimeData.overrideValues({
       isAmbientModeAllowed: true,
       isPersonalizationJellyEnabled: true,
-      isScreenSaverPreviewEnabled: true,
       isScreenSaverDurationEnabled: true,
     });
     const mocks = baseSetup();
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn
index 1d7cf13..1ab5664 100644
--- a/chrome/test/data/webui/settings/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -9,7 +9,6 @@
 mojom("test_api_mojom") {
   testonly = true
   sources = [
-    "os_people_page/password_settings_api.test-mojom",
     "os_people_page/pin_settings_api.test-mojom",
     "test_api.test-mojom",
   ]
@@ -91,6 +90,7 @@
     "app_management/test_util.js",
     "app_management/toggle_row_test.ts",
 
+    "date_time_page/date_time_card_test.ts",
     "date_time_page/date_time_page_test.ts",
     "date_time_page/test_timezone_browser_proxy.ts",
     "date_time_page/timezone_selector_test.ts",
@@ -205,8 +205,8 @@
     "os_bluetooth_page/os_bluetooth_change_device_name_dialog_test.ts",
     "os_bluetooth_page/os_bluetooth_device_detail_subpage_tests.js",
     "os_bluetooth_page/os_bluetooth_devices_subpage_tests.js",
-    "os_bluetooth_page/os_bluetooth_page_tests.js",
-    "os_bluetooth_page/os_bluetooth_pairing_dialog_tests.js",
+    "os_bluetooth_page/os_bluetooth_page_test.ts",
+    "os_bluetooth_page/os_bluetooth_pairing_dialog_test.ts",
     "os_bluetooth_page/os_bluetooth_summary_tests.js",
     "os_bluetooth_page/os_bluetooth_true_wireless_images_tests.js",
     "os_bluetooth_page/os_paired_bluetooth_list_test.ts",
@@ -232,7 +232,6 @@
     "os_people_page/os_people_page_test.ts",
     "os_people_page/os_sync_controls_subpage_test.ts",
     "os_people_page/personalization_options_test.ts",
-    "os_people_page/password_settings_api.ts",
     "os_people_page/pin_dialog_api.ts",
     "os_people_page/pin_settings_api.ts",
     "os_people_page/test_account_manager_browser_proxy.ts",
@@ -293,7 +292,6 @@
 
   mojo_files = [
     "$root_gen_dir/mojom-webui/chrome/test/data/webui/settings/chromeos/test_api.test-mojom-webui.js",
-    "$root_gen_dir/mojom-webui/chrome/test/data/webui/settings/chromeos/os_people_page/password_settings_api.test-mojom-webui.js",
     "$root_gen_dir/mojom-webui/chrome/test/data/webui/settings/chromeos/os_people_page/pin_settings_api.test-mojom-webui.js",
   ]
 
diff --git a/chrome/test/data/webui/settings/chromeos/date_time_page/date_time_card_test.ts b/chrome/test/data/webui/settings/chromeos/date_time_page/date_time_card_test.ts
new file mode 100644
index 0000000..0ce77ab
--- /dev/null
+++ b/chrome/test/data/webui/settings/chromeos/date_time_page/date_time_card_test.ts
@@ -0,0 +1,293 @@
+// 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 'chrome://os-settings/lazy_load.js';
+
+import {SettingsDateTimeCardElement, TimeZoneAutoDetectMethod, TimeZoneBrowserProxyImpl, TimezoneSelectorElement} from 'chrome://os-settings/lazy_load.js';
+import {CrLinkRowElement, CrSettingsPrefs, PrefsState, Router, routes, settingMojom, SettingsDropdownMenuElement, SettingsToggleButtonElement} from 'chrome://os-settings/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
+import {eventToPromise, isVisible} from 'chrome://webui-test/test_util.js';
+
+import {TestTimeZoneBrowserProxy} from './test_timezone_browser_proxy.js';
+
+// CrOS sends time zones as [id, friendly name] pairs.
+const FAKE_TIMEZONES = [
+  ['Westeros/Highgarden', '(KNG-2:00) The Reach Time (Highgarden)'],
+  ['Westeros/Winterfell', '(KNG-1:00) The North Time (Winterfell)'],
+  [
+    'Westeros/Kings_Landing',
+    '(KNG+0:00) Westeros Standard Time (King\'s Landing)',
+  ],
+  ['Westeros/TheEyrie', '(KNG+1:00) The Vale Time (The Eyrie)'],
+  ['Westeros/Sunspear', '(KNG+2:00) Dorne Time (Sunspear)'],
+  ['FreeCities/Pentos', '(KNG+6:00) Pentos Time (Pentos)'],
+  ['FreeCities/Volantis', '(KNG+9:00) Volantis Time (Volantis)'],
+  ['BayOfDragons/Daenerys', '(KNG+14:00) Daenerys Free Time (Meereen)'],
+];
+
+function getFakePrefs() {
+  return {
+    cros: {
+      system: {
+        timezone: {
+          key: 'cros.system.timezone',
+          type: chrome.settingsPrivate.PrefType.STRING,
+          value: 'Westeros/Kings_Landing',
+        },
+      },
+      flags: {
+        // TODO(alemate): This test should be run for all possible
+        // combinations of values of these options.
+        per_user_timezone_enabled: {
+          key: 'cros.flags.per_user_timezone_enabled',
+          type: chrome.settingsPrivate.PrefType.BOOLEAN,
+          value: true,
+        },
+        fine_grained_time_zone_detection_enabled: {
+          key: 'cros.flags.fine_grained_time_zone_detection_enabled',
+          type: chrome.settingsPrivate.PrefType.BOOLEAN,
+          value: true,
+        },
+      },
+    },
+    settings: {
+      clock: {
+        use_24hour_clock: {
+          key: 'settings.clock.use_24hour_clock',
+          type: chrome.settingsPrivate.PrefType.BOOLEAN,
+          value: false,
+        },
+      },
+      timezone: {
+        key: 'settings.timezone',
+        type: chrome.settingsPrivate.PrefType.STRING,
+        value: 'Westeros/Kings_Landing',
+      },
+    },
+    generated: {
+      resolve_timezone_by_geolocation_method_short: {
+        key: 'generated.resolve_timezone_by_geolocation_method_short',
+        type: chrome.settingsPrivate.PrefType.NUMBER,
+        value: TimeZoneAutoDetectMethod.IP_ONLY,
+      },
+      resolve_timezone_by_geolocation_on_off: {
+        key: 'generated.resolve_timezone_by_geolocation_on_off',
+        type: chrome.settingsPrivate.PrefType.BOOLEAN,
+        value: true,
+      },
+    },
+  };
+}
+
+suite('<settings-date-time-card>', () => {
+  const isRevampWayfindingEnabled =
+      loadTimeData.getBoolean('isRevampWayfindingEnabled');
+  const route =
+      isRevampWayfindingEnabled ? routes.SYSTEM_PREFERENCES : routes.DATETIME;
+
+  let dateTimeCard: SettingsDateTimeCardElement;
+  let testBrowserProxy: TestTimeZoneBrowserProxy;
+
+  setup(() => {
+    testBrowserProxy = new TestTimeZoneBrowserProxy();
+    testBrowserProxy.setTimeZones(FAKE_TIMEZONES);
+    TimeZoneBrowserProxyImpl.setInstanceForTesting(testBrowserProxy);
+    CrSettingsPrefs.resetForTesting();
+  });
+
+  teardown(() => {
+    dateTimeCard.remove();
+    testBrowserProxy.reset();
+    Router.getInstance().resetRouteForTesting();
+  });
+
+  function createDateTimeCard(prefs: PrefsState): void {
+    const initialTimezoneDisplayName = prefs['cros'].system.timezone.value;
+
+    // Find the desired initial timezone by ID.
+    const timeZone = FAKE_TIMEZONES.find(
+        (timeZonePair) => timeZonePair[0] === initialTimezoneDisplayName);
+    assertTrue(!!timeZone);
+    const [timeZoneID, timeZoneName] = timeZone;
+    loadTimeData.overrideValues({
+      timeZoneID,
+      timeZoneName,
+    });
+
+    dateTimeCard = document.createElement('settings-date-time-card');
+    dateTimeCard.prefs = prefs;
+    dateTimeCard.activeTimeZoneDisplayName = initialTimezoneDisplayName;
+    CrSettingsPrefs.setInitialized();
+    document.body.appendChild(dateTimeCard);
+    flush();
+  }
+
+  function getTimezoneAutoDetectToggle(): SettingsToggleButtonElement {
+    const element =
+        dateTimeCard.shadowRoot!.querySelector<SettingsToggleButtonElement>(
+            '#timeZoneAutoDetectToggle');
+    assertTrue(!!element);
+    return element;
+  }
+
+  function getTimeZoneSelector(): TimezoneSelectorElement {
+    const timezoneSelector =
+        dateTimeCard.shadowRoot!.querySelector('timezone-selector');
+    assertTrue(!!timezoneSelector);
+    return timezoneSelector;
+  }
+
+  function getUserTimezoneDropdown(): SettingsDropdownMenuElement {
+    const timezoneSelector = getTimeZoneSelector();
+    const userTimezoneDropdown =
+        timezoneSelector.shadowRoot!.querySelector<SettingsDropdownMenuElement>(
+            '#userTimeZoneSelector');
+    assertTrue(!!userTimezoneDropdown);
+    return userTimezoneDropdown;
+  }
+
+  function assertTimezonesPopulated(isPopulated: boolean): void {
+    const timezoneDropdown = getUserTimezoneDropdown();
+    const numExpected = isPopulated ? FAKE_TIMEZONES.length : 1;
+    assertEquals(numExpected, timezoneDropdown.menuOptions.length);
+  }
+
+  test('Set date and time row only shows if editable', async () => {
+    const prefs = getFakePrefs();
+    createDateTimeCard(prefs);
+
+    const setDateTimeRow =
+        dateTimeCard.shadowRoot!.querySelector<CrLinkRowElement>(
+            '#setDateTimeRow');
+    assertFalse(isVisible(setDateTimeRow));
+
+    // Make the date and time editable.
+    webUIListenerCallback('can-set-date-time-changed', true);
+    await flushTasks();
+    assertTrue(isVisible(setDateTimeRow));
+
+    assertEquals(0, testBrowserProxy.getCallCount('showSetDateTimeUi'));
+    setDateTimeRow!.click();
+    assertEquals(1, testBrowserProxy.getCallCount('showSetDateTimeUi'));
+
+    // Make the date and time not editable.
+    webUIListenerCallback('can-set-date-time-changed', false);
+    assertFalse(isVisible(setDateTimeRow));
+  });
+
+  suite('When timezone detection is enabled', () => {
+    setup(() => {
+      const prefs = getFakePrefs();
+      prefs.cros.flags.fine_grained_time_zone_detection_enabled.value = true;
+      createDateTimeCard(prefs);
+    });
+
+    test('Timezone selector is hidden', () => {
+      const timezoneSelector =
+          dateTimeCard.shadowRoot!.querySelector('timezone-selector');
+      assertFalse(isVisible(timezoneSelector));
+    });
+
+    test('Timezone auto-detect toggle is hidden', () => {
+      const toggle =
+          dateTimeCard.shadowRoot!.querySelector<SettingsToggleButtonElement>(
+              '#timeZoneAutoDetectToggle');
+      assertFalse(isVisible(toggle));
+    });
+
+    test('Timezone subpage row is visible', () => {
+      const rowElement = dateTimeCard.shadowRoot!.querySelector<HTMLElement>(
+          '#timeZoneSettingsTrigger');
+      assertTrue(isVisible(rowElement));
+    });
+
+    test(
+        'Timezone subpage row is focused after returning from subpage',
+        async () => {
+          const triggerSelector = '#timeZoneSettingsTrigger';
+          const rowElement =
+              dateTimeCard.shadowRoot!.querySelector<HTMLElement>(
+                  triggerSelector);
+          assertTrue(!!rowElement);
+          rowElement.click();
+          flush();
+
+          const popStateEventPromise = eventToPromise('popstate', window);
+          Router.getInstance().navigateToPreviousRoute();
+          await popStateEventPromise;
+          await waitAfterNextRender(dateTimeCard);
+
+          assertEquals(
+              rowElement, dateTimeCard.shadowRoot!.activeElement,
+              `${triggerSelector} should be focused.`);
+        });
+  });
+
+  suite('When timezone detection is disabled', () => {
+    setup(() => {
+      const prefs = getFakePrefs();
+      prefs.cros.flags.fine_grained_time_zone_detection_enabled.value = false;
+      createDateTimeCard(prefs);
+    });
+
+    test('Timezone selector is visible', () => {
+      const timezoneSelector =
+          dateTimeCard.shadowRoot!.querySelector('timezone-selector');
+      assertTrue(isVisible(timezoneSelector));
+    });
+
+    test('Timezone auto-detect toggle is visible', () => {
+      const toggle = getTimezoneAutoDetectToggle();
+      assertTrue(isVisible(toggle));
+    });
+
+    test('Timezone detect toggle is deep linkable', async () => {
+      const params = new URLSearchParams();
+      const settingId = settingMojom.Setting.kChangeTimeZone.toString();
+      params.append('settingId', settingId);
+      Router.getInstance().navigateTo(route, params);
+      flush();
+
+      const toggle = getTimezoneAutoDetectToggle();
+      await waitAfterNextRender(toggle);
+      assertEquals(
+          toggle, dateTimeCard.shadowRoot!.activeElement,
+          `Auto set time zone toggle should be focused for settingId=${
+              settingId}.`);
+    });
+
+    test('Turning off timezone auto-detection loads timezones', async () => {
+      assertEquals(0, testBrowserProxy.getCallCount('getTimeZones'));
+
+      const autodetectToggle = getTimezoneAutoDetectToggle();
+      assertTrue(
+          autodetectToggle.checked, 'Expected auto-detect toggle to be on');
+      assertTimezonesPopulated(false);
+
+      autodetectToggle.click();
+      assertFalse(
+          autodetectToggle.checked, 'Expected auto-detect toggle to be off');
+      await testBrowserProxy.whenCalled('getTimeZones');
+      assertTimezonesPopulated(true);
+    });
+
+    test('Auto-detect toggle controls pref', () => {
+      const autodetectToggle = getTimezoneAutoDetectToggle();
+      assertTrue(
+          autodetectToggle.checked, 'Expected auto-detect toggle to be on');
+      assertTrue(dateTimeCard.get(
+          'prefs.generated.resolve_timezone_by_geolocation_on_off.value'));
+
+      autodetectToggle.click();
+      assertFalse(
+          autodetectToggle.checked, 'Expected auto-detect toggle to be off');
+      assertFalse(dateTimeCard.get(
+          'prefs.generated.resolve_timezone_by_geolocation_on_off.value'));
+    });
+  });
+});
diff --git a/chrome/test/data/webui/settings/chromeos/date_time_page/date_time_page_test.ts b/chrome/test/data/webui/settings/chromeos/date_time_page/date_time_page_test.ts
index 992d21b..aaf9abb 100644
--- a/chrome/test/data/webui/settings/chromeos/date_time_page/date_time_page_test.ts
+++ b/chrome/test/data/webui/settings/chromeos/date_time_page/date_time_page_test.ts
@@ -5,14 +5,11 @@
 import 'chrome://os-settings/lazy_load.js';
 
 import {SettingsDateTimeCardElement, SettingsDateTimePageElement, TimeZoneAutoDetectMethod, TimeZoneBrowserProxyImpl, TimezoneSubpageElement} from 'chrome://os-settings/lazy_load.js';
-import {ControlledRadioButtonElement, CrLinkRowElement, CrSettingsPrefs, Router, routes, SettingsDropdownMenuElement, SettingsToggleButtonElement} from 'chrome://os-settings/os_settings.js';
+import {ControlledRadioButtonElement, CrSettingsPrefs, Router, routes, SettingsDropdownMenuElement, SettingsToggleButtonElement} from 'chrome://os-settings/os_settings.js';
 import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
-import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {assertEquals, assertFalse, assertGT, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
-import {eventToPromise} from 'chrome://webui-test/test_util.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 
 import {TestTimeZoneBrowserProxy} from './test_timezone_browser_proxy.js';
 
@@ -349,28 +346,6 @@
     assertFalse(resolveMethodDropdown.disabled);
   });
 
-  test('Deep link to auto set time zone on main page', async () => {
-    const prefs = getFakePrefs();
-    // Set fine grained time zone off so that toggle appears on this page.
-    prefs.cros.flags.fine_grained_time_zone_detection_enabled.value = false;
-    dateTime = initializeDateTime(prefs, false);
-
-    const params = new URLSearchParams();
-    params.append('settingId', '1001');
-    Router.getInstance().navigateTo(routes.DATETIME, params);
-
-    flush();
-
-    const timeZoneAutoDetectToggle = getTimeZoneAutoDetectToggle();
-    const deepLinkElement =
-        timeZoneAutoDetectToggle.shadowRoot!.querySelector('cr-toggle');
-    assertTrue(!!deepLinkElement);
-    await waitAfterNextRender(deepLinkElement);
-    assertEquals(
-        deepLinkElement, getDeepActiveElement(),
-        'Auto set time zone toggle should be focused for settingId=1001.');
-  });
-
   test('auto-detect forced on', async () => {
     testBrowserProxy.setTimeZones(fakeTimeZones);
     const prefs = getFakePrefs();
@@ -530,65 +505,4 @@
     assertFalse(timeZoneAutoDetectOff.disabled);
     assertFalse(timezoneSelector.disabled);
   });
-
-  test('set date and time button', async () => {
-    const prefs = getFakePrefs();
-    // Set fine grained time zone off so that toggle appears on this page.
-    prefs.cros.flags.fine_grained_time_zone_detection_enabled.value = false;
-    dateTime = initializeDateTime(prefs, false);
-
-    const setDateTimeButton =
-        getDateTimeCard().shadowRoot!.querySelector<CrLinkRowElement>(
-            '#setDateTimeRow');
-    assertTrue(!!setDateTimeButton);
-    assertEquals(0, setDateTimeButton.offsetHeight);
-
-    // Make the date and time editable.
-    webUIListenerCallback('can-set-date-time-changed', true);
-    await flushTasks();
-    assertGT(setDateTimeButton.offsetHeight, 0);
-
-    assertEquals(0, testBrowserProxy.getCallCount('showSetDateTimeUi'));
-    setDateTimeButton.click();
-
-    assertEquals(1, testBrowserProxy.getCallCount('showSetDateTimeUi'));
-
-    // Make the date and time not editable.
-    webUIListenerCallback('can-set-date-time-changed', false);
-    assertEquals(0, setDateTimeButton.offsetHeight);
-  });
-
-  test(
-      'Timezone subpage trigger is focused after returning from subpage',
-      async () => {
-        // Create settings-date-time-page element
-        Router.getInstance().navigateTo(routes.DATETIME);
-        const prefs = getFakePrefs();
-        prefs.cros.flags.fine_grained_time_zone_detection_enabled.value = false;
-        dateTime = initializeDateTime(prefs, false);
-        flush();
-
-        // Show timezone subpage trigger element
-        dateTime.set(
-            'prefs.cros.flags.fine_grained_time_zone_detection_enabled.value',
-            true);
-        flush();
-
-        const triggerSelector = '#timeZoneSettingsTrigger';
-        const dateTimeCard = getDateTimeCard();
-        const triggerEl = dateTimeCard.shadowRoot!.querySelector<HTMLElement>(
-            triggerSelector);
-        assertTrue(!!triggerEl);
-        triggerEl.click();
-        flush();
-
-        const popStateEventPromise = eventToPromise('popstate', window);
-        Router.getInstance().navigateToPreviousRoute();
-        await popStateEventPromise;
-        await waitAfterNextRender(dateTime);
-
-        assertEquals(
-            triggerEl, dateTimeCard.shadowRoot!.activeElement,
-            `${triggerSelector} should be focused.`);
-      });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_page_tests.js b/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_page_test.ts
similarity index 61%
rename from chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_page_tests.js
rename to chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_page_test.ts
index c8a4e3e..f99838a4 100644
--- a/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_page_test.ts
@@ -2,33 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://os-settings/strings.m.js';
+import 'chrome://os-settings/os_settings.js';
 
-import {OsBluetoothDevicesSubpageBrowserProxyImpl, Router, routes} from 'chrome://os-settings/os_settings.js';
+import {OsBluetoothDevicesSubpageBrowserProxyImpl, Router, routes, SettingsBluetoothPageElement} from 'chrome://os-settings/os_settings.js';
 import {setBluetoothConfigForTesting} from 'chrome://resources/ash/common/bluetooth/cros_bluetooth_config.js';
 import {BluetoothSystemState} from 'chrome://resources/mojo/chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-webui.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {assertEquals, assertNull, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {FakeBluetoothConfig} from 'chrome://webui-test/cr_components/chromeos/bluetooth/fake_bluetooth_config.js';
+import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 
 import {TestOsBluetoothDevicesSubpageBrowserProxy} from './test_os_bluetooth_subpage_browser_proxy.js';
 
-suite('OsBluetoothPageTest', function() {
-  /** @type {!FakeBluetoothConfig} */
-  let bluetoothConfig;
+suite('<os-settings-bluetooth-page>', () => {
+  let bluetoothConfig: FakeBluetoothConfig;
+  let bluetoothPage: SettingsBluetoothPageElement;
+  let browserProxy: TestOsBluetoothDevicesSubpageBrowserProxy;
 
-  /** @type {!SettingsBluetoothPageElement|undefined} */
-  let bluetoothPage;
-
-  /** @type {?OsBluetoothDevicesSubpageBrowserProxy} */
-  let browserProxy = null;
-
-  function flushAsync() {
-    flush();
-    return new Promise(resolve => setTimeout(resolve));
-  }
-
-  setup(function() {
+  setup(() => {
     browserProxy = new TestOsBluetoothDevicesSubpageBrowserProxy();
     OsBluetoothDevicesSubpageBrowserProxyImpl.setInstanceForTesting(
         browserProxy);
@@ -40,55 +31,62 @@
     flush();
   });
 
-  test('Show bluetooth pairing UI', async function() {
-    const getBluetoothPairingUi = () => bluetoothPage.shadowRoot.querySelector(
+  teardown(() => {
+    bluetoothPage.remove();
+    browserProxy.reset();
+    Router.getInstance().resetRouteForTesting();
+  });
+
+  test('Show bluetooth pairing UI', async () => {
+    const getBluetoothPairingUi = () => bluetoothPage.shadowRoot!.querySelector(
         'os-settings-bluetooth-pairing-dialog');
-    const bluetoothSummary =
-        bluetoothPage.shadowRoot.querySelector('os-settings-bluetooth-summary');
+    const bluetoothSummary = bluetoothPage.shadowRoot!.querySelector(
+        'os-settings-bluetooth-summary');
 
     const getPairNewDevice = () =>
-        bluetoothPage.shadowRoot.querySelector('#pairNewDevice');
+        bluetoothPage.shadowRoot!.querySelector<HTMLButtonElement>(
+            '#pairNewDevice');
 
     assertTrue(!!bluetoothSummary);
-    assertFalse(!!getBluetoothPairingUi());
+    assertNull(getBluetoothPairingUi());
     assertEquals(0, browserProxy.getShowBluetoothRevampHatsSurveyCount());
 
     bluetoothSummary.dispatchEvent(new CustomEvent('start-pairing'));
 
-    await flushAsync();
+    await flushTasks();
     assertTrue(!!getBluetoothPairingUi());
     assertEquals(
         1, browserProxy.getShowBluetoothRevampHatsSurveyCount(),
         'Count failed to increase');
 
-    getBluetoothPairingUi().dispatchEvent(new CustomEvent('close'));
+    getBluetoothPairingUi()!.dispatchEvent(new CustomEvent('close'));
 
-    await flushAsync();
-    assertFalse(!!getBluetoothPairingUi());
+    await flushTasks();
+    assertNull(getBluetoothPairingUi());
 
-    Router.getInstance().navigateTo(routes.BLUETOOTH_DEVICES, null);
+    Router.getInstance().navigateTo(routes.BLUETOOTH_DEVICES);
 
     bluetoothConfig.setSystemState(BluetoothSystemState.kEnabled);
-    await flushAsync();
+    await flushTasks();
     assertTrue(!!getPairNewDevice());
 
     // Simulate Bluetooth disabled
     bluetoothConfig.setSystemState(BluetoothSystemState.kDisabled);
-    await flushAsync();
-    assertFalse(!!getPairNewDevice());
+    await flushTasks();
+    assertNull(getPairNewDevice());
 
     // Simulate Bluetooth unavailable
     bluetoothConfig.setSystemState(BluetoothSystemState.kUnavailable);
-    await flushAsync();
-    assertFalse(!!getPairNewDevice());
+    await flushTasks();
+    assertNull(getPairNewDevice());
 
     // Simulate Bluetooth enabled
     bluetoothConfig.setSystemState(BluetoothSystemState.kEnabling);
-    await flushAsync();
+    await flushTasks();
     assertTrue(!!getPairNewDevice());
-    getPairNewDevice().click();
+    getPairNewDevice()!.click();
 
-    await flushAsync();
+    await flushTasks();
     assertTrue(!!getBluetoothPairingUi());
   });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_pairing_dialog_tests.js b/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_pairing_dialog_test.ts
similarity index 69%
rename from chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_pairing_dialog_tests.js
rename to chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_pairing_dialog_test.ts
index f3c2c5e5..599fd4a 100644
--- a/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_pairing_dialog_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/os_bluetooth_page/os_bluetooth_pairing_dialog_test.ts
@@ -3,22 +3,19 @@
 // found in the LICENSE file.
 
 import 'chrome://os-settings/os_settings.js';
-import 'chrome://os-settings/strings.m.js';
 
+import {SettingsBluetoothPairingDialogElement} from 'chrome://os-settings/os_settings.js';
 import {setBluetoothConfigForTesting} from 'chrome://resources/ash/common/bluetooth/cros_bluetooth_config.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {FakeBluetoothConfig} from 'chrome://webui-test/cr_components/chromeos/bluetooth/fake_bluetooth_config.js';
 import {eventToPromise} from 'chrome://webui-test/test_util.js';
 
-suite('OsBluetoothPairingDialogTest', function() {
-  /** @type {?SettingsBluetoothPairingDialogElement} */
-  let bluetoothPairingDialog;
+suite('<os-settings-bluetooth-pairing-dialog>', () => {
+  let bluetoothPairingDialog: SettingsBluetoothPairingDialogElement;
+  let bluetoothConfig: FakeBluetoothConfig;
 
-  /** @type {!FakeBluetoothConfig} */
-  let bluetoothConfig;
-
-  setup(function() {
+  setup(() => {
     bluetoothConfig = new FakeBluetoothConfig();
     setBluetoothConfigForTesting(bluetoothConfig);
 
@@ -28,9 +25,13 @@
     flush();
   });
 
-  test('Finished event is fired on close', async function() {
-    const pairingDialog =
-        bluetoothPairingDialog.shadowRoot.querySelector('bluetooth-pairing-ui');
+  teardown(() => {
+    bluetoothPairingDialog.remove();
+  });
+
+  test('Finished event is fired on close', async () => {
+    const pairingDialog = bluetoothPairingDialog.shadowRoot!.querySelector(
+        'bluetooth-pairing-ui');
     assertTrue(!!pairingDialog);
 
     const closeBluetoothPairingUiPromise =
diff --git a/chrome/test/data/webui/settings/chromeos/os_files_page/google_drive_page_test.ts b/chrome/test/data/webui/settings/chromeos/os_files_page/google_drive_page_test.ts
index cee18e6..2fa62df1 100644
--- a/chrome/test/data/webui/settings/chromeos/os_files_page/google_drive_page_test.ts
+++ b/chrome/test/data/webui/settings/chromeos/os_files_page/google_drive_page_test.ts
@@ -141,7 +141,7 @@
           'Remove Drive access', connectDisconnectButton!.textContent!.trim());
     });
 
-    test('confirming drive disconnect updates pref', async function() {
+    test('confirming drive disconnect updates pref', async () => {
       page.setPrefValue('gdata.disabled', false);
       flush();
 
@@ -158,7 +158,7 @@
 
     test(
         'cancelling drive disconnect confirmation dialog doesnt update pref',
-        async function() {
+        async () => {
           page.setPrefValue('gdata.disabled', false);
           flush();
 
@@ -173,7 +173,7 @@
         });
 
 
-    test('free space shows the offline value returned', async function() {
+    test('free space shows the offline value returned', async () => {
       // Send back a normal pinned size result.
       testBrowserProxy.handler.setResultFor(
           'getContentCacheSize', {size: '100 MB'});
@@ -188,7 +188,7 @@
     });
 
 
-    test('when clear offline files clicked show dialog', async function() {
+    test('when clear offline files clicked show dialog', async () => {
       page.setPrefValue('drivefs.bulk_pinning_enabled', false);
       testBrowserProxy.handler.setResultFor(
           'getContentCacheSize', {size: '100 MB'});
@@ -214,6 +214,23 @@
           () =>
               testBrowserProxy.handler.getCallCount('clearPinnedFiles') === 1);
     });
+
+    test('clean up storage button is disabled at 0 B', async () => {
+      testBrowserProxy.handler.setResultFor(
+          'getContentCacheSize', {size: '0 B'});
+      page.onNavigated();
+      await assertAsync(() => clearOfflineStorageButton.disabled);
+
+      testBrowserProxy.handler.setResultFor(
+          'getContentCacheSize', {size: '100 MB'});
+      page.onNavigated();
+      await assertAsync(() => !clearOfflineStorageButton.disabled);
+
+      testBrowserProxy.handler.setResultFor(
+          'getContentCacheSize', {size: '0 B'});
+      page.onNavigated();
+      await assertAsync(() => clearOfflineStorageButton.disabled);
+    });
   });
 
   suite('with bulk pinning enabled', () => {
@@ -224,7 +241,7 @@
       });
     });
 
-    test('removing drive access also disables bulk pinning', async function() {
+    test('removing drive access also disables bulk pinning', async () => {
       page.setPrefValue('gdata.disabled', false);
       page.setPrefValue('drivefs.bulk_pinning_enabled', true);
       flush();
@@ -242,8 +259,7 @@
     });
 
     test(
-        'clicking the toggle updates the bulk pinning preference',
-        async function() {
+        'clicking the toggle updates the bulk pinning preference', async () => {
           page.setPrefValue('drivefs.bulk_pinning_enabled', false);
           flush();
 
@@ -257,7 +273,7 @@
 
     test(
         'progress sent via the browser proxy updates the sub title text',
-        async function() {
+        async () => {
           page.setPrefValue('drivefs.bulk_pinning_enabled', false);
 
           /**
@@ -311,7 +327,7 @@
               subTitle => !subTitle.includes(requiredSpaceText));
         });
 
-    test('disabling bulk pinning shows confirmation dialog', async function() {
+    test('disabling bulk pinning shows confirmation dialog', async () => {
       page.setPrefValue('drivefs.bulk_pinning_enabled', true);
       flush();
 
@@ -345,7 +361,7 @@
 
     test(
         'atempting to enable bulk pinning when no free space shows dialog',
-        async function() {
+        async () => {
           page.setPrefValue('drivefs.bulk_pinning_enabled', false);
 
           // Mock space values and the `kNotEnoughSpace` stage via the browser
@@ -389,7 +405,7 @@
 
     test(
         'attempting to enable bulk pinning when no free space shows dialog',
-        async function() {
+        async () => {
           page.setPrefValue('drivefs.bulk_pinning_enabled', false);
 
           // Mock space values and the `kNotEnoughSpace` stage via the browser
@@ -431,34 +447,32 @@
               'Pinning toggle should not be toggled');
         });
 
-    test(
-        'clear offline files disabled when bulk pinning enabled',
-        async function() {
-          page.setPrefValue('drivefs.bulk_pinning_enabled', false);
-          testBrowserProxy.handler.setResultFor(
-              'getContentCacheSize', {size: '100 MB'});
-          page.onNavigated();
-          testBrowserProxy.observerRemote.onProgress({
-            freeSpace: 'x',
-            requiredSpace: 'y',
-            stage: Stage.kStopped,
-            isError: false,
-          });
-          testBrowserProxy.observerRemote.$.flushForTesting();
-          await assertAsync(() => !clearOfflineStorageButton.disabled);
+    test('clear offline files disabled when bulk pinning enabled', async () => {
+      page.setPrefValue('drivefs.bulk_pinning_enabled', false);
+      testBrowserProxy.handler.setResultFor(
+          'getContentCacheSize', {size: '100 MB'});
+      page.onNavigated();
+      testBrowserProxy.observerRemote.onProgress({
+        freeSpace: 'x',
+        requiredSpace: 'y',
+        stage: Stage.kStopped,
+        isError: false,
+      });
+      testBrowserProxy.observerRemote.$.flushForTesting();
+      await assertAsync(() => !clearOfflineStorageButton.disabled);
 
-          page.setPrefValue('drivefs.bulk_pinning_enabled', true);
-          testBrowserProxy.handler.setResultFor(
-              'getContentCacheSize', {size: '100 MB'});
-          page.onNavigated();
-          testBrowserProxy.observerRemote.onProgress({
-            freeSpace: 'x',
-            requiredSpace: 'y',
-            stage: Stage.kSyncing,
-            isError: false,
-          });
-          testBrowserProxy.observerRemote.$.flushForTesting();
-          await assertAsync(() => clearOfflineStorageButton.disabled);
-        });
+      page.setPrefValue('drivefs.bulk_pinning_enabled', true);
+      testBrowserProxy.handler.setResultFor(
+          'getContentCacheSize', {size: '100 MB'});
+      page.onNavigated();
+      testBrowserProxy.observerRemote.onProgress({
+        freeSpace: 'x',
+        requiredSpace: 'y',
+        stage: Stage.kSyncing,
+        isError: false,
+      });
+      testBrowserProxy.observerRemote.$.flushForTesting();
+      await assertAsync(() => clearOfflineStorageButton.disabled);
+    });
   });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/os_people_page/password_settings_api.test-mojom b/chrome/test/data/webui/settings/chromeos/os_people_page/password_settings_api.test-mojom
deleted file mode 100644
index 670d8713..0000000
--- a/chrome/test/data/webui/settings/chromeos/os_people_page/password_settings_api.test-mojom
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module ash.settings.mojom;
-
-enum PasswordType {
-  kGaia,
-  kLocal,
-};
-
-// The test API for the settings-password-settings element.
-interface PasswordSettingsApi {
-  // Verifies that the given password type is selected.
-  AssertSelectedPasswordType(PasswordType? password_type) => ();
-};
diff --git a/chrome/test/data/webui/settings/chromeos/os_people_page/password_settings_api.ts b/chrome/test/data/webui/settings/chromeos/os_people_page/password_settings_api.ts
deleted file mode 100644
index d01c58e..0000000
--- a/chrome/test/data/webui/settings/chromeos/os_people_page/password_settings_api.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {assertTrue} from 'chrome://webui-test/chai_assert.js';
-
-import {PasswordSettingsApiInterface, PasswordSettingsApiReceiver, PasswordSettingsApiRemote, PasswordType} from '../password_settings_api.test-mojom-webui.js';
-import {assertAsync, assertForDuration, hasBooleanProperty} from '../utils.js';
-
-// The test API for the settings-password-settings element.
-export class PasswordSettingsApi implements PasswordSettingsApiInterface {
-  private element: HTMLElement;
-
-  constructor(element: HTMLElement) {
-    this.element = element;
-    assertTrue(this.element.shadowRoot !== null);
-  }
-
-  public newRemote(): PasswordSettingsApiRemote {
-    const receiver = new PasswordSettingsApiReceiver(this);
-    return receiver.$.bindNewPipeAndPassRemote();
-  }
-
-  private shadowRoot(): ShadowRoot {
-    const shadowRoot = this.element.shadowRoot;
-    assertTrue(shadowRoot !== null);
-    return shadowRoot;
-  }
-
-  private queryGaiaRadio(): {checked: boolean}&HTMLElement {
-    const el = this.shadowRoot().querySelector('*[name="gaia"]');
-    assertTrue(el instanceof HTMLElement);
-    assertTrue(hasBooleanProperty(el, 'checked'));
-    return el;
-  }
-
-  private queryLocalRadio(): {checked: boolean}&HTMLElement {
-    const el = this.shadowRoot().querySelector('*[name="local"]');
-    assertTrue(el instanceof HTMLElement);
-    assertTrue(hasBooleanProperty(el, 'checked'));
-    return el;
-  }
-
-  selectedPasswordType(): PasswordType|null {
-    const gaiaRadio = this.queryGaiaRadio();
-    const localRadio = this.queryLocalRadio();
-
-    assertTrue(
-        !(gaiaRadio.checked && localRadio.checked),
-        'There must be at most one selected password type');
-
-    if (gaiaRadio.checked) {
-      return PasswordType.kGaia;
-    }
-    if (localRadio.checked) {
-      return PasswordType.kLocal;
-    }
-
-    return null;
-  }
-
-  async assertSelectedPasswordType(passwordType: PasswordType|
-                                   null): Promise<void> {
-    const isSelected = () => this.selectedPasswordType() === passwordType;
-    await assertAsync(isSelected);
-    await assertForDuration(isSelected);
-  }
-}
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index c127ab68..7efc6b9 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -195,6 +195,11 @@
  ['CellularNetworksList', 'cellular_networks_list_test.js'],
  ['CellularRoamingToggleButton', 'cellular_roaming_toggle_button_test.js'],
  ['DateTimePage', 'date_time_page/date_time_page_test.js'],
+ [
+   'DateTimePageDateTimeCard',
+   'date_time_page/date_time_card_test.js',
+   {disabled: ['ash::features::kOsSettingsRevampWayfinding']},
+ ],
  ['DateTimePageTimezoneSelector', 'date_time_page/timezone_selector_test.js'],
  ['DateTimePageTimezoneSubpage', 'date_time_page/timezone_subpage_test.js'],
  ['DevicePageAudioPage', 'device_page/audio_page_test.js'],
@@ -600,7 +605,7 @@
    'OsAppsPageAppNotificationsPageAppNotificationsSubpage',
    'os_apps_page/app_notifications_page/app_notifications_subpage_test.js'
  ],
- ['OsBluetoothPage', 'os_bluetooth_page/os_bluetooth_page_tests.js'],
+ ['OsBluetoothPage', 'os_bluetooth_page/os_bluetooth_page_test.js'],
  [
    'OsBluetoothPageOsBluetoothChangeDeviceNameDialog',
    'os_bluetooth_page/os_bluetooth_change_device_name_dialog_test.js',
@@ -612,7 +617,7 @@
  ],
  [
    'OsBluetoothPageOsBluetoothPairingDialog',
-   'os_bluetooth_page/os_bluetooth_pairing_dialog_tests.js'
+   'os_bluetooth_page/os_bluetooth_pairing_dialog_test.js'
  ],
  [
    'OsBluetoothPageOsBluetoothSummary',
@@ -836,6 +841,11 @@
    },
  ],
  [
+   'SystemPreferencesPageDateTimeCard',
+   'date_time_page/date_time_card_test.js',
+   {enabled: ['ash::features::kOsSettingsRevampWayfinding']},
+ ],
+ [
    'SystemPreferencesPageResetCard',
    'os_reset_page/reset_card_test.js',
    {enabled: ['ash::features::kOsSettingsRevampWayfinding']},
diff --git a/chrome/test/data/webui/settings/chromeos/test_api.test-mojom b/chrome/test/data/webui/settings/chromeos/test_api.test-mojom
index 98f2781d..fd6ca41 100644
--- a/chrome/test/data/webui/settings/chromeos/test_api.test-mojom
+++ b/chrome/test/data/webui/settings/chromeos/test_api.test-mojom
@@ -4,7 +4,6 @@
 
 module ash.settings.mojom;
 
-import "chrome/test/data/webui/settings/chromeos/os_people_page/password_settings_api.test-mojom";
 import "chrome/test/data/webui/settings/chromeos/os_people_page/pin_settings_api.test-mojom";
 
 // This file contains the definition of the mojo service that can be used in
@@ -30,14 +29,6 @@
   // Crashes if authentication succeeds.
   AuthenticateIncorrectly(string password) => ();
 
-  // Checks whether a control for changing passwords is visible or not.
-  AssertPasswordControlVisibility(bool is_visible) => ();
-
-  // Navigates to password settings. Crashes if no password settings control is
-  // visible. The return value can be used to interact with password settings.
-  GoToPasswordSettings() =>
-      (pending_remote<PasswordSettingsApi> password_settings);
-
   // Checks whether a control for recovery is available or not.
   AssertRecoveryControlAvailability(bool is_available) => ();
 
diff --git a/chrome/test/data/webui/settings/chromeos/test_api.ts b/chrome/test/data/webui/settings/chromeos/test_api.ts
index 948f73a7..eef42f1 100644
--- a/chrome/test/data/webui/settings/chromeos/test_api.ts
+++ b/chrome/test/data/webui/settings/chromeos/test_api.ts
@@ -9,9 +9,7 @@
 import {CrButtonElement, SettingsGoogleDriveSubpageElement, SettingsToggleButtonElement} from 'chrome://os-settings/os_settings.js';
 import {assertTrue} from 'chrome://webui-test/chai_assert.js';
 
-import {PasswordSettingsApi} from './os_people_page/password_settings_api.js';
 import {PinSettingsApi} from './os_people_page/pin_settings_api.js';
-import {PasswordSettingsApiRemote} from './password_settings_api.test-mojom-webui.js';
 import {PinSettingsApiRemote} from './pin_settings_api.test-mojom-webui.js';
 import {GoogleDriveSettingsInterface, GoogleDriveSettingsReceiver, GoogleDriveSettingsRemote, LockScreenSettings_RecoveryDialogAction as RecoveryDialogAction, LockScreenSettingsInterface, LockScreenSettingsReceiver, LockScreenSettingsRemote, OSSettingsBrowserProcess, OSSettingsDriverInterface, OSSettingsDriverReceiver} from './test_api.test-mojom-webui.js';
 import {assertAsync, assertForDuration, hasBooleanProperty, hasProperty, Lazy, querySelectorShadow, retry, retryUntilSome} from './utils.js';
@@ -130,35 +128,6 @@
     await this.authenticate(password, false);
   }
 
-  private queryPasswordSettings(): PasswordSettingsApi|null {
-    const el = this.shadowRoot().getElementById('passwordSettings');
-    if (!(el instanceof HTMLElement)) {
-      return null;
-    }
-    if (el.hidden) {
-      return null;
-    }
-
-    return new PasswordSettingsApi(el);
-  }
-
-  async assertPasswordControlVisibility(isVisible: boolean): Promise<void> {
-    const property = () => {
-      const settings = this.queryPasswordSettings();
-      return (settings !== null) === isVisible;
-    };
-
-    await assertAsync(property);
-    await assertForDuration(property);
-  }
-
-  public async goToPasswordSettings():
-      Promise<{passwordSettings: PasswordSettingsApiRemote}> {
-    const passwordSettings =
-        await retryUntilSome(() => this.queryPasswordSettings());
-    return {passwordSettings: passwordSettings.newRemote()};
-  }
-
   private recoveryToggle(): HTMLElement&{checked: boolean}|null {
     const toggle = this.shadowRoot().getElementById('recoveryToggle');
     if (toggle === null) {
diff --git a/chrome/updater/policy/service.cc b/chrome/updater/policy/service.cc
index 15436b8..c8903ad 100644
--- a/chrome/updater/policy/service.cc
+++ b/chrome/updater/policy/service.cc
@@ -82,6 +82,7 @@
       should_take_policy_critical_section,
       external_constants->IsMachineManaged());
   if (group_policy_manager->CloudPolicyOverridesPlatformPolicy()) {
+    VLOG(1) << __func__ << ": CloudPolicyOverridesPlatformPolicy=1";
     managers.push_back(std::move(group_policy_manager));
   } else {
     managers.insert(managers.begin(), std::move(group_policy_manager));
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index cf1742df..eb1d165 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -111,6 +111,8 @@
 
  protected:
   void SetUp() override {
+    VLOG(2) << __func__ << " entered.";
+
     ASSERT_NO_FATAL_FAILURE(CleanProcesses());
     ASSERT_TRUE(WaitForUpdaterExit());
     ASSERT_NO_FATAL_FAILURE(Clean());
@@ -139,9 +141,13 @@
     // Mark the device as de-registered. This stops sending DM requests
     // that mess up the request expectations in the mock server.
     ASSERT_NO_FATAL_FAILURE(DMDeregisterDevice());
+
+    VLOG(2) << __func__ << "completed.";
   }
 
   void TearDown() override {
+    VLOG(2) << __func__ << " entered.";
+
     ExitTestMode();
     if (!HasFailure()) {
       ExpectClean();
@@ -156,6 +162,8 @@
     // Updater process must not be running for `Clean()` to succeed.
     ASSERT_TRUE(WaitForUpdaterExit());
     Clean();
+
+    VLOG(2) << __func__ << "completed.";
   }
 
   void ExpectNoCrashes() { test_commands_->ExpectNoCrashes(); }
@@ -531,7 +539,6 @@
   ASSERT_NO_FATAL_FAILURE(InstallApp("test"));
 
   ASSERT_TRUE(WaitForUpdaterExit());
-  ASSERT_NO_FATAL_FAILURE(ExpectInstalled());
   ASSERT_NO_FATAL_FAILURE(ExpectVersionActive(kUpdaterVersion));
   ASSERT_NO_FATAL_FAILURE(ExpectRegistered("test"));
 
@@ -1572,6 +1579,32 @@
                                                  &exit_code));
       EXPECT_EQ(0, exit_code);
     });
+
+    ExpectAppInstalled(app_id, version);
+  }
+
+  void SetUpdateDefaultGroupPolicy(int policy) {
+    EXPECT_EQ(ERROR_SUCCESS,
+              base::win::RegKey(HKEY_LOCAL_MACHINE, UPDATER_POLICIES_KEY,
+                                Wow6432(KEY_WRITE))
+                  .WriteValue(L"UpdateDefault", policy));
+  }
+
+  void SetAppUpdateGroupPolicy(const std::string& appid, int policy) {
+    EXPECT_EQ(ERROR_SUCCESS,
+              base::win::RegKey(HKEY_LOCAL_MACHINE, UPDATER_POLICIES_KEY,
+                                Wow6432(KEY_WRITE))
+                  .WriteValue(base::ASCIIToWide(
+                                  base::StringPrintf("Update%s", appid.c_str()))
+                                  .c_str(),
+                              policy));
+  }
+
+  void SetCloudPolicyOverridesPlatformPolicy() {
+    EXPECT_EQ(ERROR_SUCCESS,
+              base::win::RegKey(HKEY_LOCAL_MACHINE, UPDATER_POLICIES_KEY,
+                                Wow6432(KEY_WRITE))
+                  .WriteValue(L"CloudPolicyOverridesPlatformPolicy", 1));
   }
 
   void ExpectAppInstalled(const std::string& appid,
@@ -1642,22 +1675,11 @@
   const base::Version kApp3UpdatedVersion = base::Version("1.1");
 
   ASSERT_NO_FATAL_FAILURE(Install());
+  ASSERT_NO_FATAL_FAILURE(ExpectInstalled());
   ASSERT_NO_FATAL_FAILURE(InstallAppWithVersion(kAppId1, kApp1InitialVersion));
   ASSERT_NO_FATAL_FAILURE(InstallAppWithVersion(kAppId2, kApp2InitialVersion));
   ASSERT_NO_FATAL_FAILURE(InstallAppWithVersion(kAppId3, kApp3InitialVersion));
-  ASSERT_NO_FATAL_FAILURE(ExpectInstalled());
-  ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kAppId1, kApp1InitialVersion));
-  ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kAppId2, kApp2InitialVersion));
-  ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kAppId3, kApp3InitialVersion));
-
-  // Group policy sets app2 to auto-update.
-  base::win::RegKey key(HKEY_LOCAL_MACHINE, UPDATER_POLICIES_KEY,
-                        Wow6432(KEY_WRITE));
-  EXPECT_EQ(
-      ERROR_SUCCESS,
-      key.WriteValue(
-          base::ASCIIToWide(base::StringPrintf("Update%s", kAppId2)).c_str(),
-          kPolicyEnabled));
+  ASSERT_NO_FATAL_FAILURE(SetAppUpdateGroupPolicy(kAppId2, kPolicyEnabled));
 
   // Cloud policy sets update default to disabled, app1 to auto-update, and
   // app2 to manual-update.
@@ -1696,7 +1718,66 @@
   ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kAppId1, kApp1UpdatedVersion));
   ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kAppId2, kApp2UpdatedVersion));
   ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kAppId3, kApp3InitialVersion));
+  ASSERT_NO_FATAL_FAILURE(ExpectUninstallPing(test_server_.get()));
+  ASSERT_NO_FATAL_FAILURE(Uninstall());
+}
 
+TEST_F(IntegrationTestDeviceManagement, CloudPolicyOverridesPlatformPolicy) {
+  ASSERT_NO_FATAL_FAILURE(SetCloudPolicyOverridesPlatformPolicy());
+
+  const base::Version kApp1InitialVersion = base::Version("1.2.3.4");
+  const base::Version kApp1UpdatedVersion = base::Version("2.3.4.5");
+  const base::Version kApp2InitialVersion = base::Version("100.0.0.0");
+  const base::Version kApp2UpdatedVersion = base::Version("101.0.0.0");
+  const base::Version kApp3InitialVersion = base::Version("1.0");
+  const base::Version kApp3UpdatedVersion = base::Version("1.1");
+
+  ASSERT_NO_FATAL_FAILURE(Install());
+  ASSERT_NO_FATAL_FAILURE(ExpectInstalled());
+  ASSERT_NO_FATAL_FAILURE(InstallAppWithVersion(kAppId1, kApp1InitialVersion));
+  ASSERT_NO_FATAL_FAILURE(InstallAppWithVersion(kAppId2, kApp2InitialVersion));
+  ASSERT_NO_FATAL_FAILURE(InstallAppWithVersion(kAppId3, kApp3InitialVersion));
+
+  ASSERT_NO_FATAL_FAILURE(SetUpdateDefaultGroupPolicy(kPolicyDisabled));
+  ASSERT_NO_FATAL_FAILURE(SetAppUpdateGroupPolicy(kAppId1, kPolicyDisabled));
+  ASSERT_NO_FATAL_FAILURE(SetAppUpdateGroupPolicy(kAppId2, kPolicyEnabled));
+  ASSERT_NO_FATAL_FAILURE(SetAppUpdateGroupPolicy(kAppId3, kPolicyEnabled));
+
+  // Overrides app1 to auto-update, app2 to manual-update with cloud policy.
+  PushEnrollmentToken(kEnrollmentToken);
+  ExpectDeviceManagementRegistrationRequest(test_server_.get(),
+                                            kEnrollmentToken, kDMToken);
+  OmahaSettingsClientProto omaha_settings;
+  ApplicationSettings app1;
+  app1.set_app_guid(kAppId1);
+  app1.set_update(enterprise_management::AUTOMATIC_UPDATES_ONLY);
+  omaha_settings.mutable_application_settings()->Add(std::move(app1));
+  ApplicationSettings app2;
+  app2.set_app_guid(kAppId2);
+  app2.set_update(enterprise_management::MANUAL_UPDATES_ONLY);
+  omaha_settings.mutable_application_settings()->Add(std::move(app2));
+  ExpectDeviceManagementPolicyFetchRequest(test_server_.get(), kDMToken,
+                                           omaha_settings);
+
+  const base::FilePath crx_path = GetInstallerPath(kAppCRX);
+  ExpectAppsUpdateSequence(
+      UpdaterScope::kSystem, test_server_.get(),
+      {
+          AppUpdateExpectation({kAppId1, kApp1InitialVersion,
+                                kApp1UpdatedVersion,
+                                /*should_update=*/true, false, "", crx_path}),
+          AppUpdateExpectation({kAppId2, kApp2InitialVersion,
+                                kApp2InitialVersion,
+                                /*should_update=*/false, false, "", crx_path}),
+          AppUpdateExpectation({kAppId3, kApp3InitialVersion,
+                                kApp3UpdatedVersion,
+                                /*should_update=*/true, false, "", crx_path}),
+      });
+  ASSERT_NO_FATAL_FAILURE(RunWake(0));
+  ASSERT_TRUE(WaitForUpdaterExit());
+  ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kAppId1, kApp1UpdatedVersion));
+  ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kAppId2, kApp2InitialVersion));
+  ASSERT_NO_FATAL_FAILURE(ExpectAppInstalled(kAppId3, kApp3UpdatedVersion));
   ASSERT_NO_FATAL_FAILURE(ExpectUninstallPing(test_server_.get()));
   ASSERT_NO_FATAL_FAILURE(Uninstall());
 }
diff --git a/chromeos/ash/components/drivefs/fake_drivefs.cc b/chromeos/ash/components/drivefs/fake_drivefs.cc
index 007dd7de8..95c3ccb 100644
--- a/chromeos/ash/components/drivefs/fake_drivefs.cc
+++ b/chromeos/ash/components/drivefs/fake_drivefs.cc
@@ -710,11 +710,6 @@
   std::move(callback).Run(drive::FILE_ERROR_OK);
 }
 
-void FakeDriveFs::ClearOfflineFiles(
-    drivefs::mojom::DriveFs::ClearOfflineFilesCallback callback) {
-  std::move(callback).Run(drive::FILE_ERROR_OK);
-}
-
 void FakeDriveFs::GetDocsOfflineStats(
     drivefs::mojom::DriveFs::GetDocsOfflineStatsCallback callback) {
   drivefs::mojom::DocsOfflineStatsPtr stats =
diff --git a/chromeos/ash/components/drivefs/fake_drivefs.h b/chromeos/ash/components/drivefs/fake_drivefs.h
index fa3e46d..c4d24ec 100644
--- a/chromeos/ash/components/drivefs/fake_drivefs.h
+++ b/chromeos/ash/components/drivefs/fake_drivefs.h
@@ -107,6 +107,11 @@
       (override));
 
   MOCK_METHOD(void,
+              ClearOfflineFiles,
+              (drivefs::mojom::DriveFs::ClearOfflineFilesCallback callback),
+              (override));
+
+  MOCK_METHOD(void,
               ImmediatelyUpload,
               (const base::FilePath& path,
                drivefs::mojom::DriveFs::ImmediatelyUploadCallback callback),
@@ -260,9 +265,6 @@
       bool enabled,
       drivefs::mojom::DriveFs::SetDocsOfflineEnabledCallback callback) override;
 
-  void ClearOfflineFiles(
-      drivefs::mojom::DriveFs::ClearOfflineFilesCallback) override;
-
   void GetDocsOfflineStats(
       drivefs::mojom::DriveFs::GetDocsOfflineStatsCallback) override;
 
diff --git a/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl.cc b/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl.cc
index 32c31d232..0af4362 100644
--- a/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl.cc
+++ b/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl.cc
@@ -680,7 +680,8 @@
       request,
       base::BindOnce(
           &NearbyPresenceCredentialManagerImpl::OnUploadCredentialsSuccess,
-          weak_ptr_factory_.GetWeakPtr(), upload_credentials_result_callback),
+          weak_ptr_factory_.GetWeakPtr(), upload_credentials_result_callback,
+          /*upload_request_start_time=*/base::TimeTicks::Now()),
       base::BindOnce(
           &NearbyPresenceCredentialManagerImpl::OnUploadCredentialsFailure,
           weak_ptr_factory_.GetWeakPtr(), upload_credentials_result_callback));
@@ -734,11 +735,15 @@
 
 void NearbyPresenceCredentialManagerImpl::OnUploadCredentialsSuccess(
     base::RepeatingCallback<void(bool)> upload_credentials_callback,
+    base::TimeTicks upload_request_start_time,
     const ash::nearby::proto::UpdateDeviceResponse& response) {
   // TODO(b/276307539): Log response and check for changes in user name and
   // image url returned from the server.
 
   server_response_timer_.Stop();
+  base::TimeDelta upload_request_duration =
+      base::TimeTicks::Now() - upload_request_start_time;
+  metrics::RecordSharedCredentialUploadDuration(upload_request_duration);
   HandleUploadCredentialsResult(
       upload_credentials_callback,
       /*result=*/ash::nearby::NearbyHttpResult::kSuccess);
@@ -779,7 +784,8 @@
       request,
       base::BindOnce(
           &NearbyPresenceCredentialManagerImpl::OnDownloadCredentialsSuccess,
-          weak_ptr_factory_.GetWeakPtr(), download_credentials_result_callback),
+          weak_ptr_factory_.GetWeakPtr(), download_credentials_result_callback,
+          /*download_request_start_time=*/base::TimeTicks::Now()),
       base::BindOnce(
           &NearbyPresenceCredentialManagerImpl::OnDownloadCredentialsFailure,
           weak_ptr_factory_.GetWeakPtr(),
@@ -843,8 +849,12 @@
     base::RepeatingCallback<
         void(std::vector<::nearby::internal::SharedCredential>, bool)>
         download_credentials_result_callback,
+    base::TimeTicks download_request_start_time,
     const ash::nearby::proto::ListPublicCertificatesResponse& response) {
   server_response_timer_.Stop();
+  base::TimeDelta download_request_duration =
+      base::TimeTicks::Now() - download_request_start_time;
+  metrics::RecordSharedCredentialDownloadDuration(download_request_duration);
 
   std::vector<::nearby::internal::SharedCredential> remote_credentials;
   for (auto public_certificate : response.public_certificates()) {
diff --git a/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl.h b/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl.h
index 5637082..4c8bcaf 100644
--- a/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl.h
+++ b/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/no_destructor.h"
+#include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chromeos/ash/components/nearby/common/client/nearby_http_result.h"
 #include "chromeos/ash/components/nearby/presence/metrics/nearby_presence_metrics.h"
@@ -220,6 +221,7 @@
       base::RepeatingCallback<void(bool)> upload_credentials_callback);
   void OnUploadCredentialsSuccess(
       base::RepeatingCallback<void(bool)> upload_credentials_callback,
+      base::TimeTicks upload_request_start_time,
       const ash::nearby::proto::UpdateDeviceResponse& response);
   void OnUploadCredentialsFailure(
       base::RepeatingCallback<void(bool)> upload_credentials_callback,
@@ -242,6 +244,7 @@
       base::RepeatingCallback<
           void(std::vector<::nearby::internal::SharedCredential>, bool)>
           download_credentials_result_callback,
+      base::TimeTicks download_request_start_time,
       const ash::nearby::proto::ListPublicCertificatesResponse& response);
   void OnDownloadCredentialsFailure(
       base::RepeatingCallback<
diff --git a/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl_unittest.cc b/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl_unittest.cc
index 2aea932..982e198 100644
--- a/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl_unittest.cc
+++ b/chromeos/ash/components/nearby/presence/credentials/nearby_presence_credential_manager_impl_unittest.cc
@@ -405,6 +405,8 @@
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Upload.AttemptsNeededCount",
       /*bucket: attempt_count=*/1, 1);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Upload.ServerRequestDuration", 1);
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Download.Result", /*bucket: success=*/true,
       1);
@@ -413,6 +415,8 @@
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Download.AttemptsNeededCount",
       /*bucket: attempt_count=*/1, 1);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Download.ServerRequestDuration", 1);
 }
 
 TEST_F(NearbyPresenceCredentialManagerImplTest, ServerRegistrationTimeout) {
@@ -525,6 +529,8 @@
       "Nearby.Presence.Credentials.Upload.FailureReason",
       /*bucket: NearbyHttpResult::kTimeout*/
       ash::nearby::NearbyHttpResult::kTimeout, 1);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Upload.ServerRequestDuration", 0);
 }
 
 TEST_F(NearbyPresenceCredentialManagerImplTest, UploadCredentialsFailure) {
@@ -565,6 +571,8 @@
       "Nearby.Presence.Credentials.Upload.FailureReason",
       /*bucket: NearbyHttpResult::kHttpErrorInternalServerError*/
       ash::nearby::NearbyHttpResult::kHttpErrorInternalServerError, 1);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Upload.ServerRequestDuration", 0);
 }
 
 TEST_F(NearbyPresenceCredentialManagerImplTest, DownloadCredentialsFailure) {
@@ -718,6 +726,8 @@
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Upload.AttemptsNeededCount",
       /*bucket: attempt_count=*/1, 1);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Upload.ServerRequestDuration", 1);
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Download.Result", /*bucket: success=*/true,
       1);
@@ -726,6 +736,8 @@
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Download.AttemptsNeededCount",
       /*bucket: attempt_count=*/1, 1);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Download.ServerRequestDuration", 1);
 }
 
 TEST_F(NearbyPresenceCredentialManagerImplTest,
@@ -765,6 +777,8 @@
       "Nearby.Presence.Credentials.Upload.FailureReason", 0);
   histogram_tester_.ExpectTotalCount(
       "Nearby.Presence.Credentials.Upload.AttemptsNeededCount", 0);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Upload.ServerRequestDuration", 0);
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Download.Result", /*bucket: success=*/true,
       1);
@@ -773,6 +787,8 @@
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Download.AttemptsNeededCount",
       /*bucket: attempt_count=*/1, 1);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Download.ServerRequestDuration", 1);
 }
 
 TEST_F(NearbyPresenceCredentialManagerImplTest,
@@ -826,6 +842,8 @@
       ash::nearby::NearbyHttpResult::kHttpErrorInternalServerError, 1);
   histogram_tester_.ExpectTotalCount(
       "Nearby.Presence.Credentials.Upload.AttemptsNeededCount", 0);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Upload.ServerRequestDuration", 0);
 }
 
 TEST_F(NearbyPresenceCredentialManagerImplTest,
@@ -861,6 +879,8 @@
       ash::nearby::NearbyHttpResult::kHttpErrorInternalServerError, 1);
   histogram_tester_.ExpectTotalCount(
       "Nearby.Presence.Credentials.Download.AttemptsNeededCount", 0);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Download.ServerRequestDuration", 0);
 }
 
 TEST_F(NearbyPresenceCredentialManagerImplTest,
@@ -920,6 +940,8 @@
       "Nearby.Presence.Credentials.Upload.FailureReason", 0);
   histogram_tester_.ExpectTotalCount(
       "Nearby.Presence.Credentials.Upload.AttemptsNeededCount", 0);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Upload.ServerRequestDuration", 0);
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Download.Result", /*bucket: success=*/true,
       7);
@@ -928,6 +950,8 @@
   histogram_tester_.ExpectBucketCount(
       "Nearby.Presence.Credentials.Download.AttemptsNeededCount",
       /*bucket: attempt_count=*/1, 7);
+  histogram_tester_.ExpectTotalCount(
+      "Nearby.Presence.Credentials.Download.ServerRequestDuration", 7);
 }
 
 }  // namespace ash::nearby::presence
diff --git a/chromeos/ash/components/nearby/presence/metrics/nearby_presence_metrics.cc b/chromeos/ash/components/nearby/presence/metrics/nearby_presence_metrics.cc
index 50165885..5faa05e 100644
--- a/chromeos/ash/components/nearby/presence/metrics/nearby_presence_metrics.cc
+++ b/chromeos/ash/components/nearby/presence/metrics/nearby_presence_metrics.cc
@@ -25,6 +25,12 @@
                             success);
 }
 
+void RecordSharedCredentialUploadDuration(base::TimeDelta upload_duration) {
+  base::UmaHistogramTimes(
+      "Nearby.Presence.Credentials.Upload.ServerRequestDuration",
+      upload_duration);
+}
+
 void RecordSharedCredentialDownloadFailureReason(
     ash::nearby::NearbyHttpResult failure_reason) {
   base::UmaHistogramEnumeration(
@@ -47,6 +53,12 @@
       "Nearby.Presence.Credentials.FirstTimeRegistration.Result", result);
 }
 
+void RecordSharedCredentialDownloadDuration(base::TimeDelta download_duration) {
+  base::UmaHistogramTimes(
+      "Nearby.Presence.Credentials.Download.ServerRequestDuration",
+      download_duration);
+}
+
 void RecordFirstTimeServerRegistrationFailureReason(
     ash::nearby::NearbyHttpResult failure_reason) {
   base::UmaHistogramEnumeration(
diff --git a/chromeos/ash/components/nearby/presence/metrics/nearby_presence_metrics.h b/chromeos/ash/components/nearby/presence/metrics/nearby_presence_metrics.h
index 093fb95..895b3c4 100644
--- a/chromeos/ash/components/nearby/presence/metrics/nearby_presence_metrics.h
+++ b/chromeos/ash/components/nearby/presence/metrics/nearby_presence_metrics.h
@@ -5,6 +5,7 @@
 #ifndef CHROMEOS_ASH_COMPONENTS_NEARBY_PRESENCE_METRICS_NEARBY_PRESENCE_METRICS_H_
 #define CHROMEOS_ASH_COMPONENTS_NEARBY_PRESENCE_METRICS_NEARBY_PRESENCE_METRICS_H_
 
+#include "base/time/time.h"
 #include "chromeos/ash/components/nearby/common/client/nearby_http_result.h"
 
 namespace ash::nearby::presence::metrics {
@@ -13,15 +14,22 @@
     ash::nearby::NearbyHttpResult failure_reason);
 void RecordSharedCredentialUploadTotalAttemptsNeededCount(int attempt_count);
 void RecordSharedCredentialUploadResult(bool success);
-
+void RecordSharedCredentialUploadDuration(base::TimeDelta upload_duration);
 void RecordSharedCredentialDownloadFailureReason(
     ash::nearby::NearbyHttpResult failure_reason);
 void RecordSharedCredentialDownloadTotalAttemptsNeededCount(int attempt_count);
 void RecordSharedCredentialDownloadResult(bool success);
+void RecordSharedCredentialDownloadDuration(base::TimeDelta download_duration);
+void RecordFirstTimeRegistrationFlowResult(bool success);
+void RecordFirstTimeServerRegistrationFailureReason(
+    ash::nearby::NearbyHttpResult failure_reason);
+void RecordFirstTimeServerRegistrationTotalAttemptsNeededCount(
+    int attempt_count);
 
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused. This enum should be kept in sync with
-// the FastPairPairFailure enum in src/tools/metrics/histograms/enums.xml.
+// the FirstTimeRegistrationResult enum in
+// src/tools/metrics/histograms/enums.xml.
 enum class FirstTimeRegistrationResult {
   kSuccess = 0,
   kRegistrationWithServerFailure = 1,
diff --git a/components/autofill/core/browser/autofill_browser_util.cc b/components/autofill/core/browser/autofill_browser_util.cc
index 55af9f2..013511c8 100644
--- a/components/autofill/core/browser/autofill_browser_util.cc
+++ b/components/autofill/core/browser/autofill_browser_util.cc
@@ -51,20 +51,4 @@
   return !IsFormOrClientNonSecure(client, form);
 }
 
-bool IsCompleteCreditCardFormIncludingCvcField(
-    const FormStructure& form_structure) {
-  // If card number field or expiration date field is not detected, return
-  // false.
-  if (!form_structure.IsCompleteCreditCardForm())
-    return false;
-
-  // If CVC field is detected, then all requirements are met, otherwise return
-  // false.
-  for (auto& field : form_structure) {
-    if (field->Type().GetStorableType() == CREDIT_CARD_VERIFICATION_CODE)
-      return true;
-  }
-  return false;
-}
-
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_browser_util.h b/components/autofill/core/browser/autofill_browser_util.h
index eca5f33..a933408 100644
--- a/components/autofill/core/browser/autofill_browser_util.h
+++ b/components/autofill/core/browser/autofill_browser_util.h
@@ -31,11 +31,6 @@
 bool ShouldAllowCreditCardFallbacks(const AutofillClient& client,
                                     const FormData& form);
 
-// Returns whether the form is a complete credit card form with card number
-// field, card expiration date field and card CVC field detected.
-bool IsCompleteCreditCardFormIncludingCvcField(
-    const FormStructure& form_structure);
-
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_BROWSER_UTIL_H_
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc
index 8b92adf..8ca2e37 100644
--- a/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -356,13 +356,6 @@
     case PopupItemId::kShowAccountCards:
       manager_->OnUserAcceptedCardsFromAccountOption();
       break;
-    case PopupItemId::kUseVirtualCard:
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-      manager_->FetchVirtualCardCandidates();
-#else
-      NOTREACHED();
-#endif
-      break;
     case PopupItemId::kVirtualCreditCardEntry:
       // There can be multiple virtual credit cards that all rely on
       // PopupItemId::kVirtualCreditCardEntry as a `popup_item_id`. In this
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index 78d34a7f..a84f2ad3 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -267,7 +267,6 @@
     case PopupItemId::kGeneratePasswordEntry:
     case PopupItemId::kShowAccountCards:
     case PopupItemId::kPasswordAccountStorageOptIn:
-    case PopupItemId::kUseVirtualCard:
     case PopupItemId::kPasswordAccountStorageOptInAndGenerate:
     case PopupItemId::kAccountStoragePasswordEntry:
     case PopupItemId::kAccountStorageUsernameEntry:
@@ -459,39 +458,6 @@
   });
 }
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-// Retrieves all valid credit card candidates for virtual card selection. A
-// valid candidate must have exactly one cloud token.
-std::vector<CreditCard*> GetVirtualCardCandidates(
-    PersonalDataManager* personal_data_manager) {
-  DCHECK(personal_data_manager);
-  std::vector<CreditCard*> candidates =
-      personal_data_manager->GetServerCreditCards();
-  const std::vector<CreditCardCloudTokenData*> cloud_token_data =
-      personal_data_manager->GetCreditCardCloudTokenData();
-
-  // Constructs map.
-  std::unordered_map<std::string, int> id_count;
-  for (CreditCardCloudTokenData* data : cloud_token_data) {
-    const auto& iterator = id_count.find(data->masked_card_id);
-    if (iterator == id_count.end())
-      id_count.emplace(data->masked_card_id, 1);
-    else
-      iterator->second += 1;
-  }
-
-  // Remove the card from the vector that either has multiple cloud token data
-  // or has no cloud token data.
-  base::EraseIf(candidates, [&](const auto& card) {
-    const auto& iterator = id_count.find(card->server_id());
-    return iterator == id_count.end() || iterator->second > 1;
-  });
-
-  // Returns the remaining valid cards.
-  return candidates;
-}
-#endif
-
 const char* SubmissionSourceToString(SubmissionSource source) {
   switch (source) {
     case SubmissionSource::NONE:
@@ -760,29 +726,6 @@
       should_display_gpay_logo);
 }
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-void BrowserAutofillManager::FetchVirtualCardCandidates() {
-  const std::vector<CreditCard*>& candidates =
-      GetVirtualCardCandidates(client().GetPersonalDataManager());
-  // Make sure the |candidates| is not empty, otherwise the check in
-  // ShouldShowVirtualCardOption() should fail.
-  DCHECK(!candidates.empty());
-
-  client().OfferVirtualCardOptions(
-      candidates,
-      base::BindOnce(&BrowserAutofillManager::OnVirtualCardCandidateSelected,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void BrowserAutofillManager::OnVirtualCardCandidateSelected(
-    const std::string& selected_card_id) {
-  // TODO(crbug.com/1020740): Implement this and the following flow in a
-  // separate CL. The following flow will be sending a request to Payments
-  // to fetched the up-to-date cloud token data for the selected card and fill
-  // the information in the form.
-}
-#endif
-
 bool BrowserAutofillManager::ShouldParseForms() {
   bool autofill_enabled = IsAutofillEnabled();
   // If autofill is disabled but the password manager is enabled, we still
@@ -3634,16 +3577,6 @@
   if (suggestions->empty() || !context->is_filling_credit_card)
     return;
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-  // This section adds the "Use a virtual card number" option in the autofill
-  // dropdown menu, if applicable.
-  if (ShouldShowVirtualCardOption(context->form_structure)) {
-    suggestions->emplace_back(l10n_util::GetStringUTF16(
-        IDS_AUTOFILL_CLOUD_TOKEN_DROPDOWN_OPTION_LABEL));
-    suggestions->back().popup_item_id = PopupItemId::kUseVirtualCard;
-  }
-#endif
-
   // Don't provide credit card suggestions for non-secure pages, but do
   // provide them for secure pages with passive mixed content (see
   // implementation of IsContextSecure).
@@ -3659,40 +3592,6 @@
   }
 }
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-// TODO(crbug.com/1020740): Add metrics logging.
-bool BrowserAutofillManager::ShouldShowVirtualCardOption(
-    FormStructure* form_structure) {
-  // If experiment is disabled, return false.
-  if (!base::FeatureList::IsEnabled(features::kAutofillEnableVirtualCard))
-    return false;
-
-  // If credit card upload is disabled, return false.
-  if (!IsAutofillCreditCardEnabled())
-    return false;
-
-  // If merchant is not allowed, return false.
-  std::vector<std::string> allowed_merchants =
-      client().GetAllowedMerchantsForVirtualCards();
-  if (!base::Contains(allowed_merchants, form_structure->source_url().spec())) {
-    return false;
-  }
-
-  // If no credit card candidate has related cloud token data available,
-  // return false.
-  if (GetVirtualCardCandidates(client().GetPersonalDataManager()).empty()) {
-    return false;
-  }
-
-  // If not all of card number field, expiration date field and CVC field are
-  // detected, return false.
-  if (!IsCompleteCreditCardFormIncludingCvcField(*form_structure))
-    return false;
-
-  return true;
-}
-#endif
-
 autofill_metrics::FormEventLoggerBase*
 BrowserAutofillManager::GetEventFormLogger(const AutofillField& field) const {
   if (field.ShouldSuppressSuggestionsAndFillingByDefault()) {
diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h
index a20e40c..920b1d2 100644
--- a/components/autofill/core/browser/browser_autofill_manager.h
+++ b/components/autofill/core/browser/browser_autofill_manager.h
@@ -135,20 +135,6 @@
   virtual void RefetchCardsAndUpdatePopup(const FormData& form,
                                           const FormFieldData& field_data);
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-  // Returns the list of credit cards that have associated cloud token data.
-  virtual void FetchVirtualCardCandidates();
-
-  // Callback invoked when an actual card is selected. |selected_card_id| will
-  // be used to identify the card. The selected card's cloud token data will be
-  // fetched from the server.
-  // TODO(crbug.com/1020740): Passes card server id for now. In the future when
-  // one actual credit card can have multiple virtual cards, passes instrument
-  // token instead. Design TBD.
-  virtual void OnVirtualCardCandidateSelected(
-      const std::string& selected_card_id);
-#endif
-
   // Called from our external delegate so they cannot be private.
   // TODO(crbug.com/1330108): Clean up the API.
   virtual void FillOrPreviewForm(
@@ -703,11 +689,6 @@
       const std::vector<AutofillProfile>& profiles,
       FormStructure* form_structure);
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-  // Whether to show the option to use virtual card in the autofill popup.
-  bool ShouldShowVirtualCardOption(FormStructure* form_structure);
-#endif
-
   // Returns an appropriate EventFormLogger, depending on the given `field`'s
   // type. May return nullptr.
   autofill_metrics::FormEventLoggerBase* GetEventFormLogger(
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index 9a27db2..80dfedd 100644
--- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -10166,258 +10166,6 @@
       Suggestion("theking@gmail.com", "", "", PopupItemId::kAddressEntry));
 }
 
-// Desktop only tests.
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-class BrowserAutofillManagerTestForVirtualCardOption
-    : public BrowserAutofillManagerTest {
- protected:
-  BrowserAutofillManagerTestForVirtualCardOption() = default;
-  ~BrowserAutofillManagerTestForVirtualCardOption() override = default;
-
-  void SetUp() override {
-    BrowserAutofillManagerTest::SetUp();
-
-    // The URL should always match the form URL in
-    // CreateTestCreditCardFormData() to have the allowlist work correctly.
-    autofill_client_.set_allowed_merchants({"https://myform.com/form.html"});
-
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kAutofillEnableVirtualCard);
-
-    // Add only one server card so the second suggestion (if any) must be the
-    // "Use a virtual card number" option.
-    personal_data().ClearCreditCards();
-    CreditCard masked_server_card(CreditCard::RecordType::kMaskedServerCard,
-                                  /*server_id=*/"a123");
-    // TODO(crbug.com/1020740): Replace all the hard-coded expiration year in
-    // this file with NextYear().
-    test::SetCreditCardInfo(&masked_server_card, "Elvis Presley",
-                            "4234567890123456",  // Visa
-                            "04", "2999", "1");
-    masked_server_card.SetNetworkForMaskedCard(kVisaCard);
-    masked_server_card.set_guid(MakeGuid(7));
-    personal_data().AddServerCreditCard(masked_server_card);
-  }
-
-  FieldGlobalId CreateCompleteFormAndGetSuggestions() {
-    FormData form;
-    CreateTestCreditCardFormData(&form, /*is_https=*/true,
-                                 /*use_month_type=*/false);
-    FormsSeen({form});
-    GetAutofillSuggestions(form, form.fields[1]);  // Card number field.
-    return form.fields[1].global_id();
-  }
-
-  // Adds a CreditCardCloudTokenData to PersonalDataManager. This needs to be
-  // called before suggestions are fetched.
-  void CreateCloudTokenDataForDefaultCard() {
-    personal_data().ClearCloudTokenData();
-    CreditCardCloudTokenData data1 = test::GetCreditCardCloudTokenData1();
-    data1.masked_card_id = "a123";
-    personal_data().AddCloudTokenData(data1);
-  }
-
-  void VerifyNoVirtualCardSuggestions(FieldGlobalId field_id) {
-    external_delegate()->CheckSuggestionCount(field_id, 1);
-    // Suggestion details need to match the credit card added in the SetUp()
-    // above.
-    CheckSuggestions(field_id, Suggestion(std::string("Visa  ") +
-                                              test::ObfuscatedCardDigitsAsUTF8(
-                                                  "3456", ObfuscationLength()),
-                                          "Expires on 04/99", kVisaCard,
-                                          PopupItemId::kCreditCardEntry));
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-// Ensures the "Use a virtual card number" option should not be shown when
-// experiment is disabled.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldNotShowDueToExperimentDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      features::kAutofillEnableVirtualCard);
-  FieldGlobalId field_id = CreateCompleteFormAndGetSuggestions();
-  VerifyNoVirtualCardSuggestions(field_id);
-}
-
-// Ensures the "Use a virtual card number" option should not be shown when the
-// preference for credit card upload is set to disabled.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldNotShowDueToCreditCardUploadPrefDisabled) {
-  browser_autofill_manager_->SetAutofillCreditCardEnabled(autofill_client_,
-                                                          false);
-  FieldGlobalId field_id = CreateCompleteFormAndGetSuggestions();
-  external_delegate()->CheckSuggestionCount(field_id, 0);
-}
-
-// Ensures the "Use a virtual card number" option should not be shown when
-// merchant is not allowlisted.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldNotShowDueToMerchantNotAllowlisted) {
-  // Adds a different URL in the allowlist.
-  autofill_client_.set_allowed_merchants(
-      {"https://myform.anotherallowlist.com/form.html"});
-  FieldGlobalId field_id = CreateCompleteFormAndGetSuggestions();
-  VerifyNoVirtualCardSuggestions(field_id);
-}
-
-// Ensures the "Use a virtual card number" option should not be shown when card
-// number field is not detected.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldNotShowDueToFormNotHavingCardNumberField) {
-  // Creates an incomplete form without card number field.
-  FormData form;
-  form.name = u"MyForm";
-  form.url = GURL("https://myform.com/form.html");
-  form.action = GURL("https://myform.com/submit.html");
-  form.main_frame_origin =
-      url::Origin::Create(GURL("https://myform_root.com/form.html"));
-  form.fields = {CreateTestFormField("Name on Card", "nameoncard", "", "text"),
-                 CreateTestFormField("Expiration Date", "ccmonth", "", "text"),
-                 CreateTestFormField("", "ccyear", "", "text"),
-                 CreateTestFormField("CVC", "cvc", "", "text")};
-
-  FormsSeen({form});
-  GetAutofillSuggestions(form, form.fields[0]);  // Cardholder name field.
-
-  external_delegate()->CheckSuggestionCount(form.fields[0].global_id(), 1);
-  const std::string visa_label = base::JoinString(
-      {"Visa  ", test::ObfuscatedCardDigitsAsUTF8("3456", ObfuscationLength()),
-       ", expires on 04/99"},
-      "");
-  CheckSuggestions(form.fields[0].global_id(),
-                   Suggestion("Elvis Presley", visa_label, kVisaCard,
-                              PopupItemId::kCreditCardEntry));
-}
-
-// Ensures the "Use a virtual card number" option should not be shown when there
-// is no cloud token data for the card.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldNotShowDueToNoCloudTokenData) {
-  FieldGlobalId field_id = CreateCompleteFormAndGetSuggestions();
-  VerifyNoVirtualCardSuggestions(field_id);
-}
-
-// Ensures the "Use a virtual card number" option should not be shown when there
-// is multiple cloud token data for the card.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldNotShowDueToMultipleCloudTokenData) {
-  CreateCloudTokenDataForDefaultCard();
-  CreditCardCloudTokenData data2 = test::GetCreditCardCloudTokenData2();
-  data2.masked_card_id = "a123";
-  personal_data().AddCloudTokenData(data2);
-  FieldGlobalId field_id = CreateCompleteFormAndGetSuggestions();
-  VerifyNoVirtualCardSuggestions(field_id);
-}
-
-// Ensures the "Use a virtual card number" option should not be shown when card
-// expiration date field is not detected.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldNotShowDueToFormNotHavingExpirationDateField) {
-  // Creates an incomplete form without expiration date field.
-  FormData form;
-  form.name = u"MyForm";
-  form.url = GURL("https://myform.com/form.html");
-  form.action = GURL("https://myform.com/submit.html");
-  form.main_frame_origin =
-      url::Origin::Create(GURL("https://myform_root.com/form.html"));
-  form.fields = {CreateTestFormField("Name on Card", "nameoncard", "", "text"),
-                 CreateTestFormField("Card Number", "cardnumber", "", "text"),
-                 CreateTestFormField("CVC", "cvc", "", "text")};
-
-  FormsSeen({form});
-  GetAutofillSuggestions(form, form.fields[1]);  // Card number field.
-
-  VerifyNoVirtualCardSuggestions(form.fields[1].global_id());
-}
-
-// Ensures the "Use a virtual card number" option should not be shown when card
-// cvc field is not detected.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldNotShowDueToFormNotHavingCvcField) {
-  // Creates an incomplete form without cvc field.
-  FormData form;
-  form.name = u"MyForm";
-  form.url = GURL("https://myform.com/form.html");
-  form.action = GURL("https://myform.com/submit.html");
-  form.main_frame_origin =
-      url::Origin::Create(GURL("https://myform_root.com/form.html"));
-  form.fields = {CreateTestFormField("Name on Card", "nameoncard", "", "text"),
-                 CreateTestFormField("Card Number", "cardnumber", "", "text"),
-                 CreateTestFormField("Expiration Date", "ccmonth", "", "text"),
-                 CreateTestFormField("", "ccyear", "", "text")};
-
-  FormsSeen({form});
-  GetAutofillSuggestions(form, form.fields[1]);  // Card number field.
-
-  VerifyNoVirtualCardSuggestions(form.fields[1].global_id());
-}
-
-// Ensures the "Use a virtual card number" option should be shown when all
-// requirements are met.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldShowVirtualCardOption_OneCard) {
-  CreateCloudTokenDataForDefaultCard();
-  FieldGlobalId field_id = CreateCompleteFormAndGetSuggestions();
-
-  // Ensures the card suggestion and the virtual card suggestion are shown.
-  external_delegate()->CheckSuggestionCount(field_id, 2);
-  CheckSuggestions(
-      field_id,
-      Suggestion(std::string("Visa  ") + test::ObfuscatedCardDigitsAsUTF8(
-                                             "3456", ObfuscationLength()),
-                 "Expires on 04/99", kVisaCard, PopupItemId::kCreditCardEntry),
-      Suggestion(l10n_util::GetStringUTF8(
-                     IDS_AUTOFILL_CLOUD_TOKEN_DROPDOWN_OPTION_LABEL),
-                 "", "", PopupItemId::kUseVirtualCard));
-}
-
-// Ensures the "Use a virtual card number" option should be shown when there are
-// multiple cards and at least one card meets requirements.
-TEST_F(BrowserAutofillManagerTestForVirtualCardOption,
-       ShouldShowVirtualCardOption_MultipleCards) {
-  CreateCloudTokenDataForDefaultCard();
-
-  // Adds another card which does not meet the requirements (has two cloud
-  // tokens).
-  CreditCard masked_server_card(CreditCard::RecordType::kMaskedServerCard,
-                                /*server_id=*/"a456");
-  // TODO(crbug.com/1020740): Replace all the hard-coded expiration year in
-  // this file with NextYear().
-  test::SetCreditCardInfo(&masked_server_card, "Elvis Presley",
-                          "4111111111111111",  // Visa
-                          "04", "2999", "1");
-  masked_server_card.SetNetworkForMaskedCard(kVisaCard);
-  masked_server_card.set_guid(MakeGuid(8));
-  personal_data().AddServerCreditCard(masked_server_card);
-  CreditCardCloudTokenData data1 = test::GetCreditCardCloudTokenData1();
-  data1.masked_card_id = "a456";
-  personal_data().AddCloudTokenData(data1);
-  CreditCardCloudTokenData data2 = test::GetCreditCardCloudTokenData2();
-  data2.masked_card_id = "a456";
-  personal_data().AddCloudTokenData(data2);
-
-  FieldGlobalId field_id = CreateCompleteFormAndGetSuggestions();
-
-  // Ensures the card suggestion and the virtual card suggestion are shown.
-  external_delegate()->CheckSuggestionCount(field_id, 3);
-  CheckSuggestions(
-      field_id,
-      Suggestion(std::string("Visa  ") + test::ObfuscatedCardDigitsAsUTF8(
-                                             "1111", ObfuscationLength()),
-                 "Expires on 04/99", kVisaCard, PopupItemId::kCreditCardEntry),
-      Suggestion(std::string("Visa  ") + test::ObfuscatedCardDigitsAsUTF8(
-                                             "3456", ObfuscationLength()),
-                 "Expires on 04/99", kVisaCard, PopupItemId::kCreditCardEntry),
-      Suggestion(l10n_util::GetStringUTF8(
-                     IDS_AUTOFILL_CLOUD_TOKEN_DROPDOWN_OPTION_LABEL),
-                 "", "", PopupItemId::kUseVirtualCard));
-}
-#endif
-
 // Test param indicates if there is an active screen reader.
 class OnFocusOnFormFieldTest : public BrowserAutofillManagerTest,
                                public testing::WithParamInterface<bool> {
diff --git a/components/autofill/core/browser/ui/popup_item_ids.h b/components/autofill/core/browser/ui/popup_item_ids.h
index 3ce4988..9bcc31e 100644
--- a/components/autofill/core/browser/ui/popup_item_ids.h
+++ b/components/autofill/core/browser/ui/popup_item_ids.h
@@ -43,7 +43,6 @@
   kGeneratePasswordEntry,
   kShowAccountCards,
   kPasswordAccountStorageOptIn,
-  kUseVirtualCard,
   kPasswordAccountStorageOptInAndGenerate,
   kAccountStoragePasswordEntry,
   kAccountStorageUsernameEntry,
diff --git a/components/autofill/core/common/autofill_payments_features.cc b/components/autofill/core/common/autofill_payments_features.cc
index 8a4e09f..efe5cc1 100644
--- a/components/autofill/core/common/autofill_payments_features.cc
+++ b/components/autofill/core/common/autofill_payments_features.cc
@@ -167,12 +167,6 @@
 #endif
 );
 
-// When enabled, the option of using cloud token virtual card will be offered
-// when all requirements are met.
-BASE_FEATURE(kAutofillEnableVirtualCard,
-             "AutofillEnableVirtualCard",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // When enabled, after a successful authentication to autofill a virtual card,
 // the user will be prompted to opt-in to FIDO if the user is not currently
 // opted-in, and if the user is opted-in already and the virtual card is FIDO
diff --git a/components/autofill/core/common/autofill_payments_features.h b/components/autofill/core/common/autofill_payments_features.h
index d69e661a..90f95896 100644
--- a/components/autofill/core/common/autofill_payments_features.h
+++ b/components/autofill/core/common/autofill_payments_features.h
@@ -39,7 +39,6 @@
 BASE_DECLARE_FEATURE(kAutofillEnableServerIban);
 BASE_DECLARE_FEATURE(kAutofillEnableStickyManualFallbackForCards);
 BASE_DECLARE_FEATURE(kAutofillEnableUpdateVirtualCardEnrollment);
-BASE_DECLARE_FEATURE(kAutofillEnableVirtualCard);
 BASE_DECLARE_FEATURE(kAutofillEnableVirtualCardFidoEnrollment);
 BASE_DECLARE_FEATURE(kAutofillEnableVirtualCardManagementInDesktopSettingsPage);
 BASE_DECLARE_FEATURE(kAutofillEnableVirtualCardMetadata);
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp
index 823fc29..e807a85 100644
--- a/components/autofill_payments_strings.grdp
+++ b/components/autofill_payments_strings.grdp
@@ -112,9 +112,12 @@
       </message>
     </else>
   </if>
-  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt when the card is to be saved locally. The prompt can be either a bubble or an infobar.">
+  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt to save a card locally. It is shown when a new card is used during checkout, and Chrome sync is not enabled. This prompt title is shown on both the Desktop bubble and the Android infobar.">
     Save card?
   </message>
+  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_EXPLANATION_LOCAL" desc="Explanation text for the Autofill save card prompt to save a card locally. It is shown when a new card is used during checkout, and Chrome sync is not enabled. This prompt title is shown on both the Desktop bubble and the Android infobar.">
+    To pay faster next time, save your card to your device
+  </message>
   <message name="IDS_AUTOFILL_SAVE_CVC_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save CVC prompt that offers to save CVC for existing local cards. This prompt is shown if a CVC is detected for an existing local card on form submission.">
     Save security code?
   </message>
@@ -624,9 +627,6 @@
 
   <!-- virtual cards related strings - start -->
   <if expr="not is_ios and not is_android">
-    <message name="IDS_AUTOFILL_CLOUD_TOKEN_DROPDOWN_OPTION_LABEL" desc="Text shown in the button in the Autofill dropdown menu when a credit card form field is queried, to offer the option to use a virtual card.">
-      Use a virtual card number...
-    </message>
     <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_FALLBACK_ICON_TOOLTIP" desc="The tooltip message for the omnibox icon for the virtual card enroll bubble on Desktop. This bubble prompts users if they would like to enroll in a virtual card.">
       Add virtual card
     </message>
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_CARD_PROMPT_EXPLANATION_LOCAL.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_CARD_PROMPT_EXPLANATION_LOCAL.png.sha1
new file mode 100644
index 0000000..69f92cb
--- /dev/null
+++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_SAVE_CARD_PROMPT_EXPLANATION_LOCAL.png.sha1
@@ -0,0 +1 @@
+095cf3325bcf917ac1bd516fe23fc50579295b46
\ No newline at end of file
diff --git a/components/feature_engagement/public/feature_configurations.cc b/components/feature_engagement/public/feature_configurations.cc
index 3d48652b..1b587b9 100644
--- a/components/feature_engagement/public/feature_configurations.cc
+++ b/components/feature_engagement/public/feature_configurations.cc
@@ -376,13 +376,12 @@
     config->availability = Comparator(ANY, 0);
     config->session_rate = Comparator(ANY, 0);
     config->session_rate_impact.type = SessionRateImpact::Type::NONE;
-    // Used to increase the usage of Customize Chrome for users who have opened
-    // it 0 times in the last 360 days.
+    // Show IPH regardless of customize_chrome usage
     config->used =
-        EventConfig("customize_chrome_opened", Comparator(EQUAL, 0), 360, 360);
-    // Triggered when IPH hasn't been shown in the past day.
-    config->trigger = EventConfig("iph_customize_chrome_triggered",
-                                  Comparator(EQUAL, 0), 1, 360);
+        EventConfig("customize_chrome_opened", Comparator(ANY, 0), 360, 360);
+    // Triggered when IPH has been shown less than twice this year.
+    config->trigger = EventConfig("iph_customize_chrome_refresh_triggered",
+                                  Comparator(LESS_THAN, 2), 360, 360);
     config->snooze_params.max_limit = 4;
     return config;
   }
diff --git a/components/feed/core/v2/api_test/feed_api_test.cc b/components/feed/core/v2/api_test/feed_api_test.cc
index 440c012..b33e7588 100644
--- a/components/feed/core/v2/api_test/feed_api_test.cc
+++ b/components/feed/core/v2/api_test/feed_api_test.cc
@@ -1013,7 +1013,7 @@
   chrome_info.start_surface = start_surface;
   stream_ = std::make_unique<FeedStream>(
       &refresh_scheduler_, metrics_reporter_.get(), this, &profile_prefs_,
-      &network_, image_fetcher_.get(), store_.get(),
+      &network_, image_fetcher_.get(), nullptr, store_.get(),
       persistent_key_value_store_.get(), template_url_service_.get(),
       chrome_info);
   stream_->SetWireResponseTranslatorForTesting(&response_translator_);
diff --git a/components/feed/core/v2/feed_stream.cc b/components/feed/core/v2/feed_stream.cc
index e55f1f4..05bc4e3 100644
--- a/components/feed/core/v2/feed_stream.cc
+++ b/components/feed/core/v2/feed_stream.cc
@@ -50,6 +50,7 @@
 #include "components/feed/core/v2/public/stream_type.h"
 #include "components/feed/core/v2/public/types.h"
 #include "components/feed/core/v2/public/unread_content_observer.h"
+#include "components/feed/core/v2/resource_fetcher.h"
 #include "components/feed/core/v2/scheduling.h"
 #include "components/feed/core/v2/stream/unread_content_notifier.h"
 #include "components/feed/core/v2/stream_model.h"
@@ -139,6 +140,7 @@
                        PrefService* profile_prefs,
                        FeedNetwork* feed_network,
                        ImageFetcher* image_fetcher,
+                       ResourceFetcher* resource_fetcher,
                        FeedStore* feed_store,
                        PersistentKeyValueStoreImpl* persistent_key_value_store,
                        TemplateURLService* template_url_service,
@@ -149,6 +151,7 @@
       profile_prefs_(profile_prefs),
       feed_network_(feed_network),
       image_fetcher_(image_fetcher),
+      resource_fetcher_(resource_fetcher),
       store_(feed_store),
       persistent_key_value_store_(persistent_key_value_store),
       template_url_service_(template_url_service),
@@ -721,6 +724,19 @@
                                      stream.content_ids);
 }
 
+void FeedStream::FetchResource(
+    const GURL& url,
+    const std::string& method,
+    const std::vector<std::string>& header_name_and_values,
+    const std::string& post_data,
+    base::OnceCallback<void(NetworkResponse)> callback) {
+  if (!resource_fetcher_) {
+    return;
+  }
+  resource_fetcher_->Fetch(url, method, header_name_and_values, post_data,
+                           std::move(callback));
+}
+
 void FeedStream::ExecuteOperations(
     SurfaceId surface_id,
     std::vector<feedstore::DataOperation> operations) {
diff --git a/components/feed/core/v2/feed_stream.h b/components/feed/core/v2/feed_stream.h
index a5ccb3a..7623367 100644
--- a/components/feed/core/v2/feed_stream.h
+++ b/components/feed/core/v2/feed_stream.h
@@ -63,6 +63,7 @@
 class MetricsReporter;
 class RefreshTaskScheduler;
 class PersistentKeyValueStoreImpl;
+class ResourceFetcher;
 class StreamModel;
 class SurfaceUpdater;
 
@@ -101,6 +102,7 @@
              PrefService* profile_prefs,
              FeedNetwork* feed_network,
              ImageFetcher* image_fetcher,
+             ResourceFetcher* resource_fetcher,
              FeedStore* feed_store,
              PersistentKeyValueStoreImpl* persistent_key_value_store,
              TemplateURLService* template_url_service,
@@ -138,6 +140,12 @@
                 base::OnceCallback<void(bool)> callback) override;
   void ManualRefresh(SurfaceId surface_id,
                      base::OnceCallback<void(bool)> callback) override;
+  void FetchResource(
+      const GURL& url,
+      const std::string& method,
+      const std::vector<std::string>& header_name_and_values,
+      const std::string& post_data,
+      base::OnceCallback<void(NetworkResponse)> callback) override;
   void ExecuteOperations(
       SurfaceId surface_id,
       std::vector<feedstore::DataOperation> operations) override;
@@ -459,6 +467,7 @@
   raw_ptr<PrefService> profile_prefs_;  // May be null.
   raw_ptr<FeedNetwork> feed_network_;
   raw_ptr<ImageFetcher> image_fetcher_;
+  raw_ptr<ResourceFetcher> resource_fetcher_;
   raw_ptr<FeedStore, DanglingUntriaged> store_;
   raw_ptr<PersistentKeyValueStoreImpl, DanglingUntriaged>
       persistent_key_value_store_;
diff --git a/components/feed/core/v2/public/feed_api.h b/components/feed/core/v2/public/feed_api.h
index d9b038e1..c86799a 100644
--- a/components/feed/core/v2/public/feed_api.h
+++ b/components/feed/core/v2/public/feed_api.h
@@ -108,6 +108,15 @@
   virtual void ManualRefresh(SurfaceId surface_id,
                              base::OnceCallback<void(bool)> callback) = 0;
 
+  // Request to fetch a URL resource. Calls |callback| with the network response
+  // when complete.
+  virtual void FetchResource(
+      const GURL& url,
+      const std::string& method,
+      const std::vector<std::string>& header_name_and_values,
+      const std::string& post_data,
+      base::OnceCallback<void(NetworkResponse)> callback) = 0;
+
   // Request to fetch and image for use in the feed. Calls |callback|
   // with the network response when complete. The returned ImageFetchId can be
   // passed to CancelImageFetch() to cancel the request.
diff --git a/components/feed/core/v2/public/feed_service.cc b/components/feed/core/v2/public/feed_service.cc
index 530dde3..7f2f6e1 100644
--- a/components/feed/core/v2/public/feed_service.cc
+++ b/components/feed/core/v2/public/feed_service.cc
@@ -25,6 +25,7 @@
 #include "components/feed/core/v2/persistent_key_value_store_impl.h"
 #include "components/feed/core/v2/prefs.h"
 #include "components/feed/core/v2/public/refresh_task_scheduler.h"
+#include "components/feed/core/v2/resource_fetcher.h"
 #include "components/feed/feed_feature_list.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_service_observer.h"
@@ -257,6 +258,7 @@
       network_delegate_.get(), identity_manager, api_key, url_loader_factory,
       profile_prefs);
   image_fetcher_ = std::make_unique<ImageFetcher>(url_loader_factory);
+  resource_fetcher_ = std::make_unique<ResourceFetcher>(url_loader_factory);
   store_ = std::make_unique<FeedStore>(std::move(database));
   persistent_key_value_store_ = std::make_unique<PersistentKeyValueStoreImpl>(
       std::move(key_value_store_database));
@@ -264,8 +266,8 @@
   stream_ = std::make_unique<FeedStream>(
       refresh_task_scheduler_.get(), metrics_reporter_.get(),
       stream_delegate_.get(), profile_prefs, feed_network_.get(),
-      image_fetcher_.get(), store_.get(), persistent_key_value_store_.get(),
-      template_url_service, chrome_info);
+      image_fetcher_.get(), resource_fetcher_.get(), store_.get(),
+      persistent_key_value_store_.get(), template_url_service, chrome_info);
   api_ = stream_.get();
 
   history_observer_ = std::make_unique<HistoryObserverImpl>(
diff --git a/components/feed/core/v2/public/feed_service.h b/components/feed/core/v2/public/feed_service.h
index 15c006a7..ff0ed7d 100644
--- a/components/feed/core/v2/public/feed_service.h
+++ b/components/feed/core/v2/public/feed_service.h
@@ -52,6 +52,7 @@
 class FeedStream;
 class PersistentKeyValueStoreImpl;
 class ImageFetcher;
+class ResourceFetcher;
 
 namespace internal {
 bool ShouldClearFeed(bool is_signed_in,
@@ -151,6 +152,7 @@
   std::unique_ptr<NetworkDelegateImpl> network_delegate_;
   std::unique_ptr<FeedNetwork> feed_network_;
   std::unique_ptr<ImageFetcher> image_fetcher_;
+  std::unique_ptr<ResourceFetcher> resource_fetcher_;
   std::unique_ptr<FeedStore> store_;
   std::unique_ptr<PersistentKeyValueStoreImpl> persistent_key_value_store_;
   std::unique_ptr<RefreshTaskScheduler> refresh_task_scheduler_;
diff --git a/components/feed/core/v2/public/test/stub_feed_api.h b/components/feed/core/v2/public/test/stub_feed_api.h
index ae76161..79870cb4 100644
--- a/components/feed/core/v2/public/test/stub_feed_api.h
+++ b/components/feed/core/v2/public/test/stub_feed_api.h
@@ -51,6 +51,12 @@
                 base::OnceCallback<void(bool)> callback) override {}
   void ManualRefresh(SurfaceId surface_id,
                      base::OnceCallback<void(bool)> callback) override {}
+  void FetchResource(
+      const GURL& url,
+      const std::string& method,
+      const std::vector<std::string>& header_name_and_values,
+      const std::string& post_data,
+      base::OnceCallback<void(NetworkResponse)> callback) override {}
   ImageFetchId FetchImage(
       const GURL& url,
       base::OnceCallback<void(NetworkResponse)> callback) override;
diff --git a/components/media_router/browser/presentation/local_presentation_manager.h b/components/media_router/browser/presentation/local_presentation_manager.h
index d52f8a7..c3c362ec 100644
--- a/components/media_router/browser/presentation/local_presentation_manager.h
+++ b/components/media_router/browser/presentation/local_presentation_manager.h
@@ -110,6 +110,9 @@
 // thread.
 class LocalPresentationManager : public KeyedService {
  public:
+  // Used by
+  // LocalPresentationManagerFactory::BuildServiceInstanceForBrowserContext.
+  LocalPresentationManager();
   LocalPresentationManager(const LocalPresentationManager&) = delete;
   LocalPresentationManager& operator=(const LocalPresentationManager&) = delete;
 
@@ -251,15 +254,11 @@
   };
 
  private:
-  friend class LocalPresentationManagerFactory;
   friend class LocalPresentationManagerTest;
   friend class MockLocalPresentationManager;
   FRIEND_TEST_ALL_PREFIXES(PresentationServiceDelegateImplTest,
                            ConnectToLocalPresentation);
 
-  // Used by LocalPresentationManagerFactory::GetOrCreateForBrowserContext.
-  LocalPresentationManager();
-
   using LocalPresentationMap =
       std::map<std::string, std::unique_ptr<LocalPresentation>>;
 
diff --git a/components/media_router/browser/presentation/local_presentation_manager_factory.cc b/components/media_router/browser/presentation/local_presentation_manager_factory.cc
index e891605..1f34594 100644
--- a/components/media_router/browser/presentation/local_presentation_manager_factory.cc
+++ b/components/media_router/browser/presentation/local_presentation_manager_factory.cc
@@ -46,9 +46,10 @@
   g_instance = nullptr;
 }
 
-KeyedService* LocalPresentationManagerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+LocalPresentationManagerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new LocalPresentationManager;
+  return std::make_unique<LocalPresentationManager>();
 }
 
 }  // namespace media_router
diff --git a/components/media_router/browser/presentation/local_presentation_manager_factory.h b/components/media_router/browser/presentation/local_presentation_manager_factory.h
index c52320e..13fd0e0 100644
--- a/components/media_router/browser/presentation/local_presentation_manager_factory.h
+++ b/components/media_router/browser/presentation/local_presentation_manager_factory.h
@@ -39,7 +39,7 @@
   ~LocalPresentationManagerFactory() override;
 
   // BrowserContextKeyedServiceFactory interface.
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/components/pdf/renderer/pdf_accessibility_tree.h b/components/pdf/renderer/pdf_accessibility_tree.h
index 52f2f723..aa36140e 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.h
+++ b/components/pdf/renderer/pdf_accessibility_tree.h
@@ -130,9 +130,7 @@
     }
 
    private:
-    // TODO(crbug.com/1443341): Increase initial value after batching issue is
-    // fixed.
-    uint32_t pages_per_batch_ = 1u;
+    uint32_t pages_per_batch_ = 20u;
 
     void OcrNextImage();
     void ReceiveOcrResultsForImage(PdfOcrRequest request,
diff --git a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
index d2ea6507..2f3ed0e3 100644
--- a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
@@ -151,6 +151,10 @@
 
   return child_tree_update;
 }
+
+uint32_t CalculateBatchCount(uint32_t page_count, uint32_t batch_size) {
+  return (page_count + batch_size - 1) / batch_size;
+}
 #endif  // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
 
 // This class overrides PdfAccessibilityActionHandler to record received
@@ -2304,8 +2308,7 @@
   ASSERT_NO_FATAL_FAILURE(CreateInaccessiblePdfAndOcrService(
       page_count, is_ocr_service_started_before_pdf_loads, kPagesPerBatch,
       /*create_empty_results=*/false));
-  const uint32_t kBatchCount = (page_count / kPagesPerBatch) +
-                               ((page_count % kPagesPerBatch == 0u) ? 0u : 1u);
+  const uint32_t kBatchCount = CalculateBatchCount(page_count, kPagesPerBatch);
 
   ui::AXNode* root_node = pdf_accessibility_tree_->GetRoot();
   // The first node of the root node's children is a status node. There
@@ -2406,7 +2409,7 @@
 TEST_P(PdfOcrServiceTest, UMAMetrics) {
   CreatePdfAccessibilityTree();
 
-  constexpr uint32_t kPagesPerBatch = 1u;
+  constexpr uint32_t kPagesPerBatch = 20u;
   base::HistogramTester histograms;
   bool is_ocr_service_started_before_pdf_loads;
   uint32_t page_count;
@@ -2443,11 +2446,9 @@
     WaitForThreadTasks();
   }
 
-  ASSERT_EQ(pdf_accessibility_tree_->GetTreeUpdates().size(), page_count);
-  for (uint32_t i = 0; i < page_count; ++i) {
-    // There are two mock images per page.
-    ASSERT_EQ(pdf_accessibility_tree_->GetTreeUpdates()[i].size(), 2u);
-  }
+  const auto& tree_updates = pdf_accessibility_tree_->GetTreeUpdates();
+  const uint32_t kBatchCount = CalculateBatchCount(page_count, kPagesPerBatch);
+  ASSERT_EQ(kBatchCount, tree_updates.size());
 
   histograms.ExpectBucketCount(
       "Accessibility.PdfOcr.ActiveWhenInaccessiblePdfOpened",
diff --git a/components/segmentation_platform/components_unittests.filter b/components/segmentation_platform/components_unittests.filter
index fba20d9..6c748df 100644
--- a/components/segmentation_platform/components_unittests.filter
+++ b/components/segmentation_platform/components_unittests.filter
@@ -6,7 +6,6 @@
 CrossDeviceUserModelTest.*
 CustomInputProcessorTest.*
 DatabaseMaintenanceImplTest.*
-DefaultModelManagerTest.*
 DeviceSwitcherModelTest.*
 DeviceSwitcherResultDispatcherTest.*
 DeviceTierSegmentTest.*
diff --git a/components/segmentation_platform/internal/BUILD.gn b/components/segmentation_platform/internal/BUILD.gn
index 6170c69e..ea427bc7 100644
--- a/components/segmentation_platform/internal/BUILD.gn
+++ b/components/segmentation_platform/internal/BUILD.gn
@@ -71,8 +71,6 @@
     "dummy_segmentation_platform_service.h",
     "dummy_ukm_data_manager.cc",
     "dummy_ukm_data_manager.h",
-    "execution/default_model_manager.cc",
-    "execution/default_model_manager.h",
     "execution/execution_request.cc",
     "execution/execution_request.h",
     "execution/model_execution_status.h",
@@ -267,7 +265,6 @@
     "database/ukm_metrics_table_unittest.cc",
     "database/ukm_url_table_unittest.cc",
     "dummy_segmentation_platform_service_unittest.cc",
-    "execution/default_model_manager_unittest.cc",
     "execution/model_executor_impl_unittest.cc",
     "execution/model_manager_impl_unittest.cc",
     "execution/processing/custom_input_processor_unittest.cc",
diff --git a/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc b/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
index f72d26f..49fa06ac 100644
--- a/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
+++ b/components/segmentation_platform/internal/data_collection/training_data_collector_impl_unittest.cc
@@ -177,8 +177,6 @@
     storage_service_ = std::make_unique<StorageService>(
         std::move(test_segment_info_db), nullptr,
         std::move(signal_storage_config),
-        std::make_unique<DefaultModelManager>(nullptr,
-                                              base::flat_set<SegmentId>()),
         std::make_unique<MockModelManager>(),
         std::make_unique<ConfigHolder>(std::move(configs_)),
         &ukm_data_manager_);
diff --git a/components/segmentation_platform/internal/database/segment_info_cache.cc b/components/segmentation_platform/internal/database/segment_info_cache.cc
index 3794959..203e31323 100644
--- a/components/segmentation_platform/internal/database/segment_info_cache.cc
+++ b/components/segmentation_platform/internal/database/segment_info_cache.cc
@@ -64,8 +64,12 @@
     segment_info_cache_[std::make_pair(segment_id, model_source)] =
         std::move(segment_info.value());
   } else {
-    segment_info_cache_.erase(
-        segment_info_cache_.find(std::make_pair(segment_id, model_source)));
+    auto iter =
+        segment_info_cache_.find(std::make_pair(segment_id, model_source));
+    if (iter == segment_info_cache_.end()) {
+      return;
+    }
+    segment_info_cache_.erase(iter);
   }
 }
 
diff --git a/components/segmentation_platform/internal/database/segment_info_cache_unittest.cc b/components/segmentation_platform/internal/database/segment_info_cache_unittest.cc
index 0b207d8..da25455 100644
--- a/components/segmentation_platform/internal/database/segment_info_cache_unittest.cc
+++ b/components/segmentation_platform/internal/database/segment_info_cache_unittest.cc
@@ -281,6 +281,9 @@
   EXPECT_TRUE(segment_info_.has_value());
   EXPECT_EQ(kSegmentId, segment_info_.value().segment_id());
   EXPECT_EQ(2, segment_info_.value().model_version());
+  // Deleting a non existing entry.
+  segment_info_cache_->UpdateSegmentInfo(kSegmentId3, kServerModelSource,
+                                         absl::nullopt);
 }
 
 TEST_F(SegmentInfoCacheTest, GetSegmentInfoForBothModelsWithEmptyDatabase) {
diff --git a/components/segmentation_platform/internal/database/storage_service.cc b/components/segmentation_platform/internal/database/storage_service.cc
index 4cd2d8a..3ef0438 100644
--- a/components/segmentation_platform/internal/database/storage_service.cc
+++ b/components/segmentation_platform/internal/database/storage_service.cc
@@ -83,15 +83,11 @@
       signal_storage_config_(std::make_unique<SignalStorageConfig>(
           std::move(signal_storage_config_db),
           clock)),
-      default_model_manager_(std::make_unique<DefaultModelManager>(
-          model_provider_factory,
-          config_holder_->all_segment_ids())),
       model_manager_(
           std::make_unique<ModelManagerImpl>(config_holder_->all_segment_ids(),
                                              model_provider_factory,
                                              clock,
                                              segment_info_database_.get(),
-                                             default_model_manager_.get(),
                                              model_updated_callback)),
       ukm_data_manager_(ukm_data_manager),
       database_maintenance_(std::make_unique<DatabaseMaintenanceImpl>(
@@ -108,7 +104,6 @@
     std::unique_ptr<SegmentInfoDatabase> segment_info_database,
     std::unique_ptr<SignalDatabase> signal_database,
     std::unique_ptr<SignalStorageConfig> signal_storage_config,
-    std::unique_ptr<DefaultModelManager> default_model_manager,
     std::unique_ptr<ModelManager> model_manager,
     std::unique_ptr<ConfigHolder> config_holder,
     UkmDataManager* ukm_data_manager)
@@ -116,7 +111,6 @@
       segment_info_database_(std::move(segment_info_database)),
       signal_database_(std::move(signal_database)),
       signal_storage_config_(std::move(signal_storage_config)),
-      default_model_manager_(std::move(default_model_manager)),
       model_manager_(std::move(model_manager)),
       ukm_data_manager_(ukm_data_manager) {}
 
diff --git a/components/segmentation_platform/internal/database/storage_service.h b/components/segmentation_platform/internal/database/storage_service.h
index 69f125a..022ef5bb 100644
--- a/components/segmentation_platform/internal/database/storage_service.h
+++ b/components/segmentation_platform/internal/database/storage_service.h
@@ -41,7 +41,6 @@
 }  // namespace proto
 
 class DatabaseMaintenanceImpl;
-class DefaultModelManager;
 class ModelManager;
 class ModelProviderFactory;
 class SegmentInfoDatabase;
@@ -98,7 +97,6 @@
   StorageService(std::unique_ptr<SegmentInfoDatabase> segment_info_database,
                  std::unique_ptr<SignalDatabase> signal_database,
                  std::unique_ptr<SignalStorageConfig> signal_storage_config,
-                 std::unique_ptr<DefaultModelManager> default_model_manager,
                  std::unique_ptr<ModelManager> model_manager,
                  std::unique_ptr<ConfigHolder> config_holder,
                  UkmDataManager* ukm_data_manager);
@@ -130,11 +128,6 @@
     return cached_result_writer_.get();
   }
 
-  DefaultModelManager* default_model_manager() {
-    DCHECK(default_model_manager_);
-    return default_model_manager_.get();
-  }
-
   ModelManager* model_manager() {
     DCHECK(model_manager_);
     return model_manager_.get();
@@ -182,8 +175,6 @@
   std::unique_ptr<SignalDatabase> signal_database_;
   std::unique_ptr<SignalStorageConfig> signal_storage_config_;
 
-  // Default models.
-  std::unique_ptr<DefaultModelManager> default_model_manager_;
   // Provides provider for default and server models.
   std::unique_ptr<ModelManager> model_manager_;
 
diff --git a/components/segmentation_platform/internal/execution/default_model_manager.cc b/components/segmentation_platform/internal/execution/default_model_manager.cc
deleted file mode 100644
index 89a5c3a..0000000
--- a/components/segmentation_platform/internal/execution/default_model_manager.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
-
-#include "base/task/single_thread_task_runner.h"
-#include "components/segmentation_platform/internal/database/segment_info_database.h"
-
-namespace segmentation_platform {
-
-DefaultModelManager::SegmentInfoWrapper::SegmentInfoWrapper() = default;
-DefaultModelManager::SegmentInfoWrapper::~SegmentInfoWrapper() = default;
-
-DefaultModelManager::DefaultModelManager(
-    ModelProviderFactory* model_provider_factory,
-    const base::flat_set<SegmentId>& segment_ids)
-    : model_provider_factory_(model_provider_factory) {
-  for (SegmentId segment_id : segment_ids) {
-    std::unique_ptr<DefaultModelProvider> provider =
-        model_provider_factory->CreateDefaultProvider(segment_id);
-    if (!provider)
-      continue;
-    default_model_providers_.emplace(segment_id, std::move(provider));
-  }
-}
-
-DefaultModelManager::~DefaultModelManager() = default;
-
-DefaultModelProvider* DefaultModelManager::GetDefaultProvider(
-    SegmentId segment_id) {
-  auto it = default_model_providers_.find(segment_id);
-  if (it != default_model_providers_.end())
-    return it->second.get();
-  return nullptr;
-}
-
-void DefaultModelManager::GetAllSegmentInfoFromBothModels(
-    const base::flat_set<SegmentId>& segment_ids,
-    SegmentInfoDatabase* segment_database,
-    MultipleSegmentInfoCallback callback) {
-  std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> available_segments =
-      segment_database->GetSegmentInfoForBothModels(segment_ids);
-
-  SegmentInfoList results;
-  for (auto it : *available_segments) {
-    results.push_back(std::make_unique<SegmentInfoWrapper>());
-    results.back()->segment_source =
-        it.second.model_source() == proto::ModelSource::DEFAULT_MODEL_SOURCE
-            ? SegmentSource::DEFAULT_MODEL
-            : SegmentSource::DATABASE;
-    results.back()->segment_info.Swap(&it.second);
-  }
-  std::move(callback).Run(std::move(results));
-}
-
-void DefaultModelManager::SetDefaultProvidersForTesting(
-    std::map<SegmentId, std::unique_ptr<DefaultModelProvider>>&& providers) {
-  default_model_providers_ = std::move(providers);
-}
-
-}  // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/execution/default_model_manager.h b/components/segmentation_platform/internal/execution/default_model_manager.h
deleted file mode 100644
index 380b5c7..0000000
--- a/components/segmentation_platform/internal/execution/default_model_manager.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_DEFAULT_MODEL_MANAGER_H_
-#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_DEFAULT_MODEL_MANAGER_H_
-
-#include <deque>
-#include <map>
-#include <memory>
-#include <set>
-#include <vector>
-
-#include "base/functional/callback.h"
-#include "base/logging.h"
-#include "components/segmentation_platform/internal/database/segment_info_database.h"
-#include "components/segmentation_platform/internal/proto/model_prediction.pb.h"
-#include "components/segmentation_platform/public/model_provider.h"
-#include "components/segmentation_platform/public/proto/model_metadata.pb.h"
-
-namespace segmentation_platform {
-using proto::SegmentId;
-
-class SegmentInfoDatabase;
-
-// DefaultModelManager provides support to query all default models available.
-// It also provides useful methods to combine results from both the database and
-// the default model.
-class DefaultModelManager {
- public:
-  DefaultModelManager(ModelProviderFactory* model_provider_factory,
-                      const base::flat_set<SegmentId>& segment_ids);
-  virtual ~DefaultModelManager();
-
-  // Disallow copy/assign.
-  DefaultModelManager(const DefaultModelManager&) = delete;
-  DefaultModelManager& operator=(const DefaultModelManager&) = delete;
-
-  // Callback for returning a list of segment infos associated with IDs.
-  // The same segment ID can be repeated multiple times.
-  enum class SegmentSource {
-    DATABASE,
-    DEFAULT_MODEL,
-  };
-  struct SegmentInfoWrapper {
-    SegmentInfoWrapper();
-    ~SegmentInfoWrapper();
-    SegmentInfoWrapper(const SegmentInfoWrapper&) = delete;
-    SegmentInfoWrapper& operator=(const SegmentInfoWrapper&) = delete;
-
-    SegmentSource segment_source;
-    proto::SegmentInfo segment_info;
-  };
-  using SegmentInfoList = std::vector<std::unique_ptr<SegmentInfoWrapper>>;
-  using MultipleSegmentInfoCallback = base::OnceCallback<void(SegmentInfoList)>;
-
-  // Utility function to get the segment info from both the database and the
-  // default model for a given set of segment IDs. The result can contain
-  // the same segment ID multiple times.
-  virtual void GetAllSegmentInfoFromBothModels(
-      const base::flat_set<SegmentId>& segment_ids,
-      SegmentInfoDatabase* segment_database,
-      MultipleSegmentInfoCallback callback);
-
-  // Returns the default provider or `nulllptr` when unavailable.
-  DefaultModelProvider* GetDefaultProvider(SegmentId segment_id);
-
-  void SetDefaultProvidersForTesting(
-      std::map<SegmentId, std::unique_ptr<DefaultModelProvider>>&& providers);
-
- private:
-  // Default model providers.
-  std::map<SegmentId, std::unique_ptr<DefaultModelProvider>>
-      default_model_providers_;
-  const raw_ptr<ModelProviderFactory, DanglingUntriaged>
-      model_provider_factory_;
-
-  base::WeakPtrFactory<DefaultModelManager> weak_ptr_factory_{this};
-};
-
-}  // namespace segmentation_platform
-
-#endif  // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_DEFAULT_MODEL_MANAGER_H_
diff --git a/components/segmentation_platform/internal/execution/default_model_manager_unittest.cc b/components/segmentation_platform/internal/execution/default_model_manager_unittest.cc
deleted file mode 100644
index e6c21358..0000000
--- a/components/segmentation_platform/internal/execution/default_model_manager_unittest.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/memory/weak_ptr.h"
-#include "base/test/gmock_callback_support.h"
-#include "base/test/task_environment.h"
-#include "components/segmentation_platform/internal/database/test_segment_info_database.h"
-#include "components/segmentation_platform/internal/execution/mock_model_provider.h"
-#include "components/segmentation_platform/public/model_provider.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-using base::test::RunOnceCallback;
-using testing::_;
-
-namespace segmentation_platform {
-
-using proto::SegmentId;
-
-class DefaultModelManagerTest : public testing::Test {
- public:
-  DefaultModelManagerTest() : model_provider_factory_(&model_provider_data_) {}
-  ~DefaultModelManagerTest() override = default;
-
-  MockDefaultModelProvider& FindHandler(proto::SegmentId segment_id) {
-    return *(*model_provider_data_.default_model_providers.find(segment_id))
-                .second;
-  }
-
-  void OnGetAllSegments(DefaultModelManager::SegmentInfoList entries) {
-    get_all_segment_result_.swap(entries);
-  }
-
-  const DefaultModelManager::SegmentInfoList& get_all_segment_result() const {
-    return get_all_segment_result_;
-  }
-
-  base::test::TaskEnvironment task_environment_;
-  test::TestSegmentInfoDatabase segment_database_;
-  TestModelProviderFactory::Data model_provider_data_;
-  TestModelProviderFactory model_provider_factory_;
-  std::unique_ptr<DefaultModelManager> default_model_manager_;
-  DefaultModelManager::SegmentInfoList get_all_segment_result_;
-  base::WeakPtrFactory<DefaultModelManagerTest> weak_ptr_factory_{this};
-};
-
-TEST_F(DefaultModelManagerTest, BasicTest) {
-  const auto segment_1 = SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
-  const auto segment_2 = SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHARE;
-  const auto segment_3 = SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_VOICE;
-  const auto segment_4 =
-      SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_QUERY_TILES;
-
-  // Set some model versions.
-  const int model_version_db = 4;
-  // This version is set by
-  // MockDefaultModelProvider::MockDefaultModelProvider().
-  const int model_version_default = 1;
-
-  // Initialize DB and default models with 1 and 2 segments respectively.
-  model_provider_data_.segments_supporting_default_model = {segment_1,
-                                                            segment_2};
-  default_model_manager_ = std::make_unique<DefaultModelManager>(
-      &model_provider_factory_,
-      model_provider_data_.segments_supporting_default_model);
-
-  // Set up models 1 and 3 in DB (Server models).
-  proto::SegmentInfo* segment_1_from_db =
-      segment_database_.FindOrCreateSegment(segment_1);
-  segment_1_from_db->set_model_version(model_version_db);
-  proto::SegmentInfo* segment_3_from_db =
-      segment_database_.FindOrCreateSegment(segment_3);
-  segment_3_from_db->set_model_version(model_version_db);
-
-  // Set up default models 1 and 2.
-  proto::SegmentationModelMetadata metadata_1;
-  proto::SegmentationModelMetadata metadata_2;
-  model_provider_data_.default_provider_metadata[segment_1] = metadata_1;
-  model_provider_data_.default_provider_metadata[segment_2] = metadata_2;
-  proto::SegmentInfo* segment_1_default_from_db =
-      segment_database_.FindOrCreateSegment(
-          segment_1, proto::ModelSource::DEFAULT_MODEL_SOURCE);
-  segment_1_default_from_db->set_model_version(model_version_default);
-  proto::SegmentInfo* segment_2_from_db = segment_database_.FindOrCreateSegment(
-      segment_2, proto::ModelSource::DEFAULT_MODEL_SOURCE);
-  segment_2_from_db->set_model_version(model_version_default);
-
-  // Query models.
-  default_model_manager_->GetAllSegmentInfoFromBothModels(
-      {segment_1, segment_2}, &segment_database_,
-      base::BindOnce(&DefaultModelManagerTest::OnGetAllSegments,
-                     weak_ptr_factory_.GetWeakPtr()));
-  task_environment_.RunUntilIdle();
-
-  // Verify that model exists from both sources in order: segment_1 from db both
-  // for server and default, segment_2 from db for default.
-  EXPECT_EQ(3u, get_all_segment_result().size());
-  EXPECT_EQ(segment_1, get_all_segment_result()[0]->segment_info.segment_id());
-  EXPECT_EQ(model_version_db,
-            get_all_segment_result()[0]->segment_info.model_version());
-  EXPECT_EQ(proto::ModelSource::SERVER_MODEL_SOURCE,
-            get_all_segment_result()[0]->segment_info.model_source());
-  EXPECT_EQ(segment_1, get_all_segment_result()[1]->segment_info.segment_id());
-  EXPECT_EQ(model_version_default,
-            get_all_segment_result()[1]->segment_info.model_version());
-  EXPECT_EQ(proto::ModelSource::DEFAULT_MODEL_SOURCE,
-            get_all_segment_result()[1]->segment_info.model_source());
-  EXPECT_EQ(segment_2, get_all_segment_result()[2]->segment_info.segment_id());
-  EXPECT_EQ(model_version_default,
-            get_all_segment_result()[2]->segment_info.model_version());
-  EXPECT_EQ(proto::ModelSource::DEFAULT_MODEL_SOURCE,
-            get_all_segment_result()[2]->segment_info.model_source());
-
-  // Query again, this time with a segment ID that doesn't exist in either
-  // sources.
-  default_model_manager_->GetAllSegmentInfoFromBothModels(
-      {segment_4}, &segment_database_,
-      base::BindOnce(&DefaultModelManagerTest::OnGetAllSegments,
-                     weak_ptr_factory_.GetWeakPtr()));
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(0u, get_all_segment_result().size());
-
-  // Query for a model only available in the default model.
-  model_provider_data_.default_provider_metadata[segment_2] = metadata_2;
-  default_model_manager_->GetAllSegmentInfoFromBothModels(
-      {segment_2}, &segment_database_,
-      base::BindOnce(&DefaultModelManagerTest::OnGetAllSegments,
-                     weak_ptr_factory_.GetWeakPtr()));
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(1u, get_all_segment_result().size());
-  EXPECT_EQ(segment_2, get_all_segment_result()[0]->segment_info.segment_id());
-  EXPECT_EQ(proto::ModelSource::DEFAULT_MODEL_SOURCE,
-            get_all_segment_result()[0]->segment_info.model_source());
-
-  // Query for a model only available in the database.
-  default_model_manager_->GetAllSegmentInfoFromBothModels(
-      {segment_3}, &segment_database_,
-      base::BindOnce(&DefaultModelManagerTest::OnGetAllSegments,
-                     weak_ptr_factory_.GetWeakPtr()));
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(1u, get_all_segment_result().size());
-  EXPECT_EQ(segment_3, get_all_segment_result()[0]->segment_info.segment_id());
-  EXPECT_EQ(proto::ModelSource::SERVER_MODEL_SOURCE,
-            get_all_segment_result()[0]->segment_info.model_source());
-}
-
-}  // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/execution/model_manager_impl.cc b/components/segmentation_platform/internal/execution/model_manager_impl.cc
index e144eef8..991c520 100644
--- a/components/segmentation_platform/internal/execution/model_manager_impl.cc
+++ b/components/segmentation_platform/internal/execution/model_manager_impl.cc
@@ -36,13 +36,11 @@
     ModelProviderFactory* model_provider_factory,
     base::Clock* clock,
     SegmentInfoDatabase* segment_database,
-    DefaultModelManager* default_model_manager,
     const SegmentationModelUpdatedCallback& model_updated_callback)
     : segment_ids_(segment_ids),
       model_provider_factory_(model_provider_factory),
       clock_(clock),
       segment_database_(segment_database),
-      default_model_manager_(default_model_manager),
       model_updated_callback_(model_updated_callback) {}
 
 void ModelManagerImpl::Initialize() {
@@ -58,13 +56,19 @@
         std::move(provider));
 
     // Default models
-    auto* default_provider =
-        default_model_manager_->GetDefaultProvider(segment_id);
+    std::unique_ptr<DefaultModelProvider> default_provider =
+        model_provider_factory_->CreateDefaultProvider(segment_id);
     if (!default_provider) {
+      segment_database_->UpdateSegment(segment_id,
+                                       ModelSource::DEFAULT_MODEL_SOURCE,
+                                       absl::nullopt, base::DoNothing());
       continue;
     }
     std::unique_ptr<DefaultModelProvider::ModelConfig> model_config =
         default_provider->GetModelConfig();
+    model_providers_.emplace(
+        std::make_pair(segment_id, ModelSource::DEFAULT_MODEL_SOURCE),
+        std::move(default_provider));
     OnSegmentationModelUpdated(ModelSource::DEFAULT_MODEL_SOURCE, segment_id,
                                model_config->metadata,
                                model_config->model_version);
@@ -76,13 +80,10 @@
 ModelProvider* ModelManagerImpl::GetModelProvider(
     proto::SegmentId segment_id,
     proto::ModelSource model_source) {
-  // TODO(ritikagup) : Remove the explicit check once default models are stored
-  // in `model_providers_`.
-  if (model_source == ModelSource::DEFAULT_MODEL_SOURCE) {
-    return default_model_manager_->GetDefaultProvider(segment_id);
-  }
   auto it = model_providers_.find(std::make_pair(segment_id, model_source));
-  DCHECK(it != model_providers_.end());
+  if (it == model_providers_.end()) {
+    return nullptr;
+  }
   return it->second.get();
 }
 
diff --git a/components/segmentation_platform/internal/execution/model_manager_impl.h b/components/segmentation_platform/internal/execution/model_manager_impl.h
index 44d567d..2ed5e0ef 100644
--- a/components/segmentation_platform/internal/execution/model_manager_impl.h
+++ b/components/segmentation_platform/internal/execution/model_manager_impl.h
@@ -14,7 +14,6 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "components/segmentation_platform/internal/database/segment_info_database.h"
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/execution/model_manager.h"
 #include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -43,7 +42,6 @@
       ModelProviderFactory* model_provider_factory,
       base::Clock* clock,
       SegmentInfoDatabase* segment_database,
-      DefaultModelManager* default_model_manager,
       const SegmentationModelUpdatedCallback& model_updated_callback);
 
   ~ModelManagerImpl() override;
@@ -107,9 +105,6 @@
   // Database for segment information and metadata.
   raw_ptr<SegmentInfoDatabase> segment_database_;
 
-  // Class to get segment info from default models.
-  const raw_ptr<DefaultModelManager> default_model_manager_;
-
   // Invoked whenever there is an update to any of the relevant ML models.
   SegmentationModelUpdatedCallback model_updated_callback_;
 
diff --git a/components/segmentation_platform/internal/execution/model_manager_impl_unittest.cc b/components/segmentation_platform/internal/execution/model_manager_impl_unittest.cc
index c1a01349..5630aa5 100644
--- a/components/segmentation_platform/internal/execution/model_manager_impl_unittest.cc
+++ b/components/segmentation_platform/internal/execution/model_manager_impl_unittest.cc
@@ -21,7 +21,6 @@
 #include "components/segmentation_platform/internal/database/mock_signal_database.h"
 #include "components/segmentation_platform/internal/database/signal_database.h"
 #include "components/segmentation_platform/internal/database/test_segment_info_database.h"
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/execution/mock_model_provider.h"
 #include "components/segmentation_platform/internal/execution/model_execution_status.h"
 #include "components/segmentation_platform/internal/execution/model_manager.h"
@@ -50,6 +49,9 @@
 constexpr SegmentId kSearchUserSegmentId =
     SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER;
 
+constexpr SegmentId kPasswordManagerUserSegmentId =
+    SegmentId::PASSWORD_MANAGER_USER;
+
 using Sample = SignalDatabase::Sample;
 
 class MockSegmentInfoDatabase : public test::TestSegmentInfoDatabase {
@@ -95,10 +97,7 @@
     clock_.SetNow(base::Time::Now());
     // Initialize DB and default models.
     model_provider_data_.segments_supporting_default_model = {
-        kSearchUserSegmentId};
-    default_model_manager_ = std::make_unique<DefaultModelManager>(
-        &model_provider_factory_,
-        model_provider_data_.segments_supporting_default_model);
+        kSearchUserSegmentId, kPasswordManagerUserSegmentId};
   }
 
   void TearDown() override {
@@ -113,7 +112,7 @@
       const ModelManager::SegmentationModelUpdatedCallback& callback) {
     model_manager_ = std::make_unique<ModelManagerImpl>(
         segment_ids, &model_provider_factory_, &clock_, segment_database_.get(),
-        default_model_manager_.get(), callback);
+        callback);
     model_manager_->Initialize();
   }
 
@@ -132,8 +131,6 @@
   base::SimpleTestClock clock_;
   std::unique_ptr<test::TestSegmentInfoDatabase> segment_database_;
   std::unique_ptr<MockSignalDatabase> signal_database_;
-  std::unique_ptr<DefaultModelManager> default_model_manager_;
-
   std::unique_ptr<ModelManagerImpl> model_manager_;
 };
 
@@ -308,7 +305,7 @@
 }
 
 TEST_F(ModelManagerTest, DatabaseUpdateForDefaultModel) {
-  auto segment_id = SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SEARCH_USER;
+  auto segment_id = kSearchUserSegmentId;
   // Fill in old data for default model in the SegmentInfo database.
   segment_database_->SetBucketDuration(
       segment_id, 456, proto::TimeUnit::MONTH,
@@ -373,4 +370,17 @@
             segment_info_from_db_2->model_metadata().time_unit());
 }
 
+TEST_F(ModelManagerTest, GetModelProvider) {
+  CreateModelManager({kSearchUserSegmentId, kPasswordManagerUserSegmentId},
+                     base::DoNothing());
+  ASSERT_TRUE(model_manager_->GetModelProvider(
+      kSearchUserSegmentId, proto::ModelSource::DEFAULT_MODEL_SOURCE));
+  ASSERT_TRUE(model_manager_->GetModelProvider(
+      kPasswordManagerUserSegmentId, proto::ModelSource::DEFAULT_MODEL_SOURCE));
+  ASSERT_TRUE(model_manager_->GetModelProvider(
+      kSearchUserSegmentId, proto::ModelSource::SERVER_MODEL_SOURCE));
+  ASSERT_TRUE(model_manager_->GetModelProvider(
+      kPasswordManagerUserSegmentId, proto::ModelSource::SERVER_MODEL_SOURCE));
+}
+
 }  // namespace segmentation_platform
diff --git a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc
index b5367915..5ac9748 100644
--- a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc
+++ b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc
@@ -16,7 +16,6 @@
 #include "components/segmentation_platform/internal/database/segment_info_database.h"
 #include "components/segmentation_platform/internal/database/signal_storage_config.h"
 #include "components/segmentation_platform/internal/database/storage_service.h"
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/execution/processing/mock_feature_aggregator.h"
 #include "components/segmentation_platform/internal/mock_ukm_data_manager.h"
 #include "components/segmentation_platform/public/input_delegate.h"
@@ -43,7 +42,7 @@
     auto moved_signal_db = std::make_unique<MockSignalDatabase>();
     signal_database_ = moved_signal_db.get();
     storage_service_ = std::make_unique<StorageService>(
-        nullptr, std::move(moved_signal_db), nullptr, nullptr, nullptr, nullptr,
+        nullptr, std::move(moved_signal_db), nullptr, nullptr, nullptr,
         &ukm_data_manager_);
     clock_.SetNow(base::Time::Now());
     segment_id_ = SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
diff --git a/components/segmentation_platform/internal/scheduler/execution_service.cc b/components/segmentation_platform/internal/scheduler/execution_service.cc
index 9e5ec4b7..9ae589c 100644
--- a/components/segmentation_platform/internal/scheduler/execution_service.cc
+++ b/components/segmentation_platform/internal/scheduler/execution_service.cc
@@ -8,7 +8,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/segmentation_platform/internal/database/cached_result_provider.h"
 #include "components/segmentation_platform/internal/database/storage_service.h"
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/execution/execution_request.h"
 #include "components/segmentation_platform/internal/execution/model_executor_impl.h"
 #include "components/segmentation_platform/internal/execution/processing/feature_aggregator_impl.h"
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
index 38f0fbd..4b95b8b 100644
--- a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
+++ b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
@@ -114,8 +114,7 @@
             storage_service_->segment_info_database(),
             storage_service_->signal_storage_config(),
             init_params->profile_prefs, config.get(),
-            field_trial_register_.get(), init_params->clock, platform_options_,
-            storage_service_->default_model_manager());
+            field_trial_register_.get(), init_params->clock, platform_options_);
   }
 
   proxy_ = std::make_unique<ServiceProxyImpl>(
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc b/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc
index 70d2d775..0108ff9f 100644
--- a/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc
+++ b/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc
@@ -93,8 +93,6 @@
     SegmentationPlatformServiceTestBase::InitPlatform(
         ukm_data_manager_.get(), /*history_service=*/nullptr);
 
-    SetUpDefaultModelProviders();
-
     segmentation_platform_service_impl_->GetServiceProxy()->AddObserver(
         &observer_);
   }
@@ -326,6 +324,7 @@
   // segment on demand is executed.
   EXPECT_TRUE(segmentation_platform_service_impl_->IsPlatformInitialized());
   EXPECT_EQ(pending_queue_size, GetPendingActionsQueueSize());
+  SetUpDefaultModelProviders();
   AssertSelectedSegmentOnDemand(
       kTestSegmentationKey4, /*is_ready=*/true,
       SegmentId::OPTIMIZATION_TARGET_SEGMENTATION_SHOPPING_USER);
diff --git a/components/segmentation_platform/internal/selection/request_dispatcher.cc b/components/segmentation_platform/internal/selection/request_dispatcher.cc
index 3204e3b..34ab4ac 100644
--- a/components/segmentation_platform/internal/selection/request_dispatcher.cc
+++ b/components/segmentation_platform/internal/selection/request_dispatcher.cc
@@ -10,6 +10,7 @@
 #include "base/containers/circular_deque.h"
 #include "base/functional/callback_forward.h"
 #include "base/location.h"
+#include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/components/segmentation_platform/internal/selection/request_dispatcher_unittest.cc b/components/segmentation_platform/internal/selection/request_dispatcher_unittest.cc
index 4ecc345..83ffc9f 100644
--- a/components/segmentation_platform/internal/selection/request_dispatcher_unittest.cc
+++ b/components/segmentation_platform/internal/selection/request_dispatcher_unittest.cc
@@ -110,7 +110,7 @@
         std::make_unique<ClientResultPrefs>(&prefs_), &clock_);
     cached_result_writer_ = cached_result_writer.get();
     storage_service_ = std::make_unique<StorageService>(
-        nullptr, nullptr, nullptr, nullptr, nullptr, std::move(config_holder),
+        nullptr, nullptr, nullptr, nullptr, std::move(config_holder),
         &ukm_data_manager_);
     storage_service_->set_cached_result_writer_for_testing(
         std::move(cached_result_writer));
diff --git a/components/segmentation_platform/internal/selection/segment_selector_impl.cc b/components/segmentation_platform/internal/selection/segment_selector_impl.cc
index 5bdca298..6ace8c5 100644
--- a/components/segmentation_platform/internal/selection/segment_selector_impl.cc
+++ b/components/segmentation_platform/internal/selection/segment_selector_impl.cc
@@ -81,8 +81,7 @@
     const Config* config,
     FieldTrialRegister* field_trial_register,
     base::Clock* clock,
-    const PlatformOptions& platform_options,
-    DefaultModelManager* default_model_manager)
+    const PlatformOptions& platform_options)
     : SegmentSelectorImpl(
           segment_database,
           signal_storage_config,
@@ -90,8 +89,7 @@
           config,
           field_trial_register,
           clock,
-          platform_options,
-          default_model_manager) {}
+          platform_options) {}
 
 SegmentSelectorImpl::SegmentSelectorImpl(
     SegmentInfoDatabase* segment_database,
@@ -100,12 +98,10 @@
     const Config* config,
     FieldTrialRegister* field_trial_register,
     base::Clock* clock,
-    const PlatformOptions& platform_options,
-    DefaultModelManager* default_model_manager)
+    const PlatformOptions& platform_options)
     : result_prefs_(std::move(prefs)),
       segment_database_(segment_database),
       signal_storage_config_(signal_storage_config),
-      default_model_manager_(default_model_manager),
       config_(config),
       field_trial_register_(field_trial_register),
       clock_(clock),
diff --git a/components/segmentation_platform/internal/selection/segment_selector_impl.h b/components/segmentation_platform/internal/selection/segment_selector_impl.h
index 9ea0c155..478cc6d7 100644
--- a/components/segmentation_platform/internal/selection/segment_selector_impl.h
+++ b/components/segmentation_platform/internal/selection/segment_selector_impl.h
@@ -26,7 +26,6 @@
 namespace segmentation_platform {
 
 struct Config;
-class DefaultModelManager;
 class ExperimentalGroupRecorder;
 class FieldTrialRegister;
 class SegmentationResultPrefs;
@@ -40,8 +39,7 @@
                       const Config* config,
                       FieldTrialRegister* field_trial_register,
                       base::Clock* clock,
-                      const PlatformOptions& platform_options,
-                      DefaultModelManager* default_model_manager);
+                      const PlatformOptions& platform_options);
 
   SegmentSelectorImpl(SegmentInfoDatabase* segment_database,
                       SignalStorageConfig* signal_storage_config,
@@ -49,8 +47,7 @@
                       const Config* config,
                       FieldTrialRegister* field_trial_register,
                       base::Clock* clock,
-                      const PlatformOptions& platform_options,
-                      DefaultModelManager* default_model_manager);
+                      const PlatformOptions& platform_options);
 
   ~SegmentSelectorImpl() override;
 
@@ -131,9 +128,6 @@
   // The database to determine whether the signal storage requirements are met.
   const raw_ptr<SignalStorageConfig> signal_storage_config_;
 
-  // The default model manager is used for the default model fallbacks.
-  const raw_ptr<DefaultModelManager> default_model_manager_;
-
   // The config for providing configuration params.
   const raw_ptr<const Config, DanglingUntriaged> config_;
 
diff --git a/components/segmentation_platform/internal/selection/segment_selector_unittest.cc b/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
index 63cb919..e69e61a 100644
--- a/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
+++ b/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
@@ -12,7 +12,6 @@
 #include "components/segmentation_platform/internal/database/mock_signal_storage_config.h"
 #include "components/segmentation_platform/internal/database/segment_info_database.h"
 #include "components/segmentation_platform/internal/database/test_segment_info_database.h"
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/execution/mock_model_provider.h"
 #include "components/segmentation_platform/internal/execution/model_executor_impl.h"
 #include "components/segmentation_platform/internal/execution/processing/mock_feature_list_query_processor.h"
@@ -128,15 +127,13 @@
     std::vector<proto::SegmentId> all_segments;
     for (const auto& it : config_->segments)
       all_segments.push_back(it.first);
-    default_manager_ =
-        std::make_unique<DefaultModelManager>(&provider_factory_, all_segments);
     segment_database_ = std::make_unique<test::TestSegmentInfoDatabase>();
     auto prefs_moved = std::make_unique<TestSegmentationResultPrefs>();
     prefs_ = prefs_moved.get();
     segment_selector_ = std::make_unique<SegmentSelectorImpl>(
         segment_database_.get(), &signal_storage_config_,
         std::move(prefs_moved), config_.get(), &field_trial_register_, &clock_,
-        PlatformOptions::CreateDefault(), default_manager_.get());
+        PlatformOptions::CreateDefault());
     segment_selector_->set_training_data_collector_for_testing(
         &training_data_collector_);
     segment_selector_->OnPlatformInitialized(nullptr);
@@ -204,7 +201,6 @@
   base::SimpleTestClock clock_;
   std::unique_ptr<test::TestSegmentInfoDatabase> segment_database_;
   MockSignalStorageConfig signal_storage_config_;
-  std::unique_ptr<DefaultModelManager> default_manager_;
   raw_ptr<TestSegmentationResultPrefs, DanglingUntriaged> prefs_;
   std::unique_ptr<SegmentSelectorImpl> segment_selector_;
   MockTrainingDataCollector training_data_collector_;
@@ -475,7 +471,7 @@
   segment_selector_ = std::make_unique<SegmentSelectorImpl>(
       segment_database_.get(), &signal_storage_config_, std::move(prefs_moved),
       config_.get(), &field_trial_register_, &clock_,
-      PlatformOptions::CreateDefault(), default_manager_.get());
+      PlatformOptions::CreateDefault());
   segment_selector_->set_training_data_collector_for_testing(
       &training_data_collector_);
   segment_selector_->OnPlatformInitialized(execution_service_.get());
@@ -520,7 +516,7 @@
   segment_selector_ = std::make_unique<SegmentSelectorImpl>(
       segment_database_.get(), &signal_storage_config_, std::move(prefs_moved),
       config_.get(), &field_trial_register_, &clock_,
-      PlatformOptions::CreateDefault(), default_manager_.get());
+      PlatformOptions::CreateDefault());
   segment_selector_->set_training_data_collector_for_testing(
       &training_data_collector_);
   segment_selector_->OnPlatformInitialized(execution_service_.get());
@@ -660,7 +656,7 @@
   segment_selector_ = std::make_unique<SegmentSelectorImpl>(
       segment_database_.get(), &signal_storage_config_, std::move(prefs_moved),
       config_.get(), &field_trial_register_, &clock_,
-      PlatformOptions::CreateDefault(), default_manager_.get());
+      PlatformOptions::CreateDefault());
 
   // When segment result is missing, unknown subsegment is recorded, otherwise
   // record metrics based on the subsegment mapping.
diff --git a/components/segmentation_platform/internal/service_proxy_impl_unittest.cc b/components/segmentation_platform/internal/service_proxy_impl_unittest.cc
index 8c7e5194..eb13eb4 100644
--- a/components/segmentation_platform/internal/service_proxy_impl_unittest.cc
+++ b/components/segmentation_platform/internal/service_proxy_impl_unittest.cc
@@ -11,7 +11,6 @@
 #include "components/prefs/testing_pref_service.h"
 #include "components/segmentation_platform/internal/constants.h"
 #include "components/segmentation_platform/internal/database/test_segment_info_database.h"
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/execution/mock_model_provider.h"
 #include "components/segmentation_platform/internal/execution/model_executor.h"
 #include "components/segmentation_platform/internal/execution/processing/feature_list_query_processor.h"
@@ -98,8 +97,7 @@
                             config,
                             nullptr,
                             nullptr,
-                            PlatformOptions::CreateDefault(),
-                            nullptr) {}
+                            PlatformOptions::CreateDefault()) {}
   ~FakeSegmentSelectorImpl() override = default;
 
   void UpdateSelectedSegment(SegmentId new_selection, float) override {
diff --git a/components/segmentation_platform/internal/signals/signal_filter_processor.h b/components/segmentation_platform/internal/signals/signal_filter_processor.h
index b548bb2..ed1b8206 100644
--- a/components/segmentation_platform/internal/signals/signal_filter_processor.h
+++ b/components/segmentation_platform/internal/signals/signal_filter_processor.h
@@ -5,9 +5,11 @@
 #ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SIGNALS_SIGNAL_FILTER_PROCESSOR_H_
 #define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SIGNALS_SIGNAL_FILTER_PROCESSOR_H_
 
+#include <set>
+
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
+#include "components/segmentation_platform/internal/database/segment_info_database.h"
 #include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
 
 namespace segmentation_platform {
diff --git a/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc b/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
index 13392bf..09fb328 100644
--- a/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
+++ b/components/segmentation_platform/internal/signals/signal_filter_processor_unittest.cc
@@ -15,7 +15,6 @@
 #include "components/segmentation_platform/internal/database/signal_storage_config.h"
 #include "components/segmentation_platform/internal/database/storage_service.h"
 #include "components/segmentation_platform/internal/database/test_segment_info_database.h"
-#include "components/segmentation_platform/internal/execution/default_model_manager.h"
 #include "components/segmentation_platform/internal/execution/mock_model_provider.h"
 #include "components/segmentation_platform/internal/mock_ukm_data_manager.h"
 #include "components/segmentation_platform/internal/signals/histogram_signal_handler.h"
@@ -53,36 +52,6 @@
                void(base::flat_set<proto::SegmentId> history_based_segments));
 };
 
-// Noop version. For database calls, just passes the calls to the DB.
-class TestDefaultModelManager : public DefaultModelManager {
- public:
-  TestDefaultModelManager()
-      : DefaultModelManager(nullptr, base::flat_set<SegmentId>()) {}
-  ~TestDefaultModelManager() override = default;
-
-  void GetAllSegmentInfoFromBothModels(
-      const base::flat_set<SegmentId>& segment_ids,
-      SegmentInfoDatabase* segment_database,
-      MultipleSegmentInfoCallback callback) override {
-    segment_database->GetSegmentInfoForSegments(
-        segment_ids,
-        base::BindOnce(
-            [](DefaultModelManager::MultipleSegmentInfoCallback callback,
-               std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> db_list) {
-              DefaultModelManager::SegmentInfoList list;
-              for (auto& pair : *db_list) {
-                list.push_back(std::make_unique<
-                               DefaultModelManager::SegmentInfoWrapper>());
-                list.back()->segment_source =
-                    DefaultModelManager::SegmentSource::DATABASE;
-                list.back()->segment_info.Swap(&pair.second);
-              }
-              std::move(callback).Run(std::move(list));
-            },
-            std::move(callback)));
-  }
-};
-
 class SignalFilterProcessorTest : public testing::Test {
  public:
   SignalFilterProcessorTest() = default;
@@ -106,14 +75,12 @@
     auto moved_signal_config = std::make_unique<MockSignalStorageConfig>();
     signal_storage_config_ = moved_signal_config.get();
     ukm_data_manager_ = std::make_unique<MockUkmDataManager>();
-    auto default_model_manager = std::make_unique<TestDefaultModelManager>();
-    default_model_manager_ = default_model_manager.get();
     storage_service_ = std::make_unique<StorageService>(
         std::move(moved_segment_database), nullptr,
-        std::move(moved_signal_config), std::move(default_model_manager),
-        std::make_unique<ModelManagerImpl>(
-            segment_ids, nullptr, nullptr, segment_database_,
-            default_model_manager_, base::DoNothing()),
+        std::move(moved_signal_config),
+        std::make_unique<ModelManagerImpl>(segment_ids, nullptr, nullptr,
+                                           segment_database_,
+                                           base::DoNothing()),
         nullptr, ukm_data_manager_.get());
 
     signal_filter_processor_ = std::make_unique<SignalFilterProcessor>(
@@ -129,7 +96,6 @@
   std::unique_ptr<MockUkmDataManager> ukm_data_manager_;
   std::unique_ptr<StorageService> storage_service_;
   raw_ptr<test::TestSegmentInfoDatabase> segment_database_;
-  raw_ptr<TestDefaultModelManager> default_model_manager_;
   raw_ptr<MockSignalStorageConfig> signal_storage_config_;
 };
 
diff --git a/components/services/print_compositor/public/mojom/print_compositor.mojom b/components/services/print_compositor/public/mojom/print_compositor.mojom
index 6457cf8..249466316 100644
--- a/components/services/print_compositor/public/mojom/print_compositor.mojom
+++ b/components/services/print_compositor/public/mojom/print_compositor.mojom
@@ -83,8 +83,8 @@
       => (Status status,
           mojo_base.mojom.ReadOnlySharedMemoryRegion? pdf_region);
 
-  // Sets the URL which is committed in the main frame of the WebContents,
-  // for use in crash diagnosis.
+  // Tells the service what URL is committed in the main frame of the
+  // WebContents that is printing, for use in crash diagnosis.
   SetWebContentsURL(url.mojom.Url url);
 
   // Sets the user-agent string for the document.
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 9d7e978..6b2f1af 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -296,6 +296,7 @@
     switches::kGpuWatchdogTimeoutSeconds,
     switches::kUseCmdDecoder,
     switches::kForceVideoOverlays,
+    switches::kSkiaGraphiteBackend,
 #if BUILDFLAG(IS_ANDROID)
     switches::kEnableReachedCodeProfiler,
     switches::kReachedCodeSamplingIntervalUs,
diff --git a/content/browser/hid/hid_test_utils.cc b/content/browser/hid/hid_test_utils.cc
index 5a43f5d..052ad1f 100644
--- a/content/browser/hid/hid_test_utils.cc
+++ b/content/browser/hid/hid_test_utils.cc
@@ -26,11 +26,17 @@
 
 void MockHidDelegate::AddObserver(BrowserContext* browser_context,
                                   Observer* observer) {
+  if (assert_browser_context_) {
+    ASSERT_TRUE(browser_context);
+  }
   observer_list_.AddObserver(observer);
 }
 
 void MockHidDelegate::RemoveObserver(BrowserContext* browser_context,
                                      Observer* observer) {
+  if (assert_browser_context_) {
+    ASSERT_TRUE(browser_context);
+  }
   observer_list_.RemoveObserver(observer);
 }
 
@@ -63,6 +69,10 @@
   }
 }
 
+void MockHidDelegate::SetAssertBrowserContext(bool assert_browser_context) {
+  assert_browser_context_ = assert_browser_context;
+}
+
 HidTestContentBrowserClient::HidTestContentBrowserClient() = default;
 
 HidTestContentBrowserClient::~HidTestContentBrowserClient() = default;
diff --git a/content/browser/hid/hid_test_utils.h b/content/browser/hid/hid_test_utils.h
index 9aeff38..b361ab0 100644
--- a/content/browser/hid/hid_test_utils.h
+++ b/content/browser/hid/hid_test_utils.h
@@ -81,8 +81,11 @@
 
   const base::ObserverList<Observer>& observer_list() { return observer_list_; }
 
+  void SetAssertBrowserContext(bool assert_browser_context);
+
  private:
   base::ObserverList<Observer> observer_list_;
+  bool assert_browser_context_ = false;
 };
 
 // Test implementation of ContentBrowserClient for HID tests. The test client
diff --git a/content/browser/interest_group/auction_worklet_manager_unittest.cc b/content/browser/interest_group/auction_worklet_manager_unittest.cc
index fbcc283c..12f23830 100644
--- a/content/browser/interest_group/auction_worklet_manager_unittest.cc
+++ b/content/browser/interest_group/auction_worklet_manager_unittest.cc
@@ -206,7 +206,11 @@
       const absl::optional<std::string>& auction_signals_json,
       const absl::optional<std::string>& per_buyer_signals_json,
       const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_per_buyer_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       const std::string& seller_signals_json,
       auction_worklet::mojom::KAnonymityBidMode kanon_mode,
       bool bid_is_kanon,
@@ -337,7 +341,11 @@
       const blink::AuctionConfig::NonSharedParams&
           auction_ad_config_non_shared_params,
       const absl::optional<GURL>& direct_from_seller_seller_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_seller_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       auction_worklet::mojom::ComponentAuctionOtherSellerPtr
           browser_signals_other_seller,
       const absl::optional<blink::AdCurrency>& component_expect_bid_currency,
@@ -364,7 +372,11 @@
       const blink::AuctionConfig::NonSharedParams&
           auction_ad_config_non_shared_params,
       const absl::optional<GURL>& direct_from_seller_seller_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_seller_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       auction_worklet::mojom::ComponentAuctionOtherSellerPtr
           browser_signals_other_seller,
       const url::Origin& browser_signal_interest_group_owner,
diff --git a/content/browser/interest_group/header_direct_from_seller_signals.h b/content/browser/interest_group/header_direct_from_seller_signals.h
index 3a4a764..1e8cd85 100644
--- a/content/browser/interest_group/header_direct_from_seller_signals.h
+++ b/content/browser/interest_group/header_direct_from_seller_signals.h
@@ -71,17 +71,17 @@
                            CompletionCallback callback);
 
   // Results of the `sellerSignals` JSON dictionary field.
-  const absl::optional<std::string>& seller_signals() {
+  const absl::optional<std::string>& seller_signals() const {
     return seller_signals_;
   }
 
   // Results of the `auctionSignals` JSON dictionary field.
-  const absl::optional<std::string>& auction_signals() {
+  const absl::optional<std::string>& auction_signals() const {
     return auction_signals_;
   }
 
   // Results of the `perBuyerSignals` JSON dictionary field.
-  const base::flat_map<url::Origin, std::string>& per_buyer_signals() {
+  const base::flat_map<url::Origin, std::string>& per_buyer_signals() const {
     return per_buyer_signals_;
   }
 
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc
index d8561da..bb384cf 100644
--- a/content/browser/interest_group/interest_group_auction.cc
+++ b/content/browser/interest_group/interest_group_auction.cc
@@ -1333,7 +1333,12 @@
         PerBuyerCurrency(owner_, *auction_->config_),
         GetDirectFromSellerPerBuyerSignals(
             url_builder, bid_state->bidder->interest_group.owner),
-        GetDirectFromSellerAuctionSignals(url_builder));
+        GetDirectFromSellerPerBuyerSignalsHeaderAdSlot(
+            *auction_->direct_from_seller_signals_header_ad_slot(),
+            bid_state->bidder->interest_group.owner),
+        GetDirectFromSellerAuctionSignals(url_builder),
+        GetDirectFromSellerAuctionSignalsHeaderAdSlot(
+            *auction_->direct_from_seller_signals_header_ad_slot()));
     bid_state->bid_finalizer.reset();
   }
 
@@ -2105,6 +2110,7 @@
 
   bidding_and_scoring_phase_start_time_ = base::TimeTicks::Now();
 
+  CHECK_EQ(num_scoring_dependencies_, 0);
   num_scoring_dependencies_ =
       buyer_helpers_.size() + component_auctions_.size();
 
@@ -2113,6 +2119,11 @@
     ++num_scoring_dependencies_;
   }
 
+  // Also wait for directFromSellerSignalsHeaderAdSlot to finish JSON parsing.
+  if (direct_from_seller_signals_header_ad_slot_pending_) {
+    ++num_scoring_dependencies_;
+  }
+
   // TODO(morlovich): If the config already resolved additional_bids here,
   // may start work on it.
 
@@ -2301,8 +2312,11 @@
       top_level_seller_winning_bid_info;
   top_level_seller_winning_bid_info.auction_config = config_;
   DCHECK(subresource_url_builder_);  // Must have been created by scoring.
+  CHECK(direct_from_seller_signals_header_ad_slot_);  // Should never be null.
   top_level_seller_winning_bid_info.subresource_url_builder =
       std::move(subresource_url_builder_);
+  top_level_seller_winning_bid_info.direct_from_seller_signals_header_ad_slot =
+      std::move(direct_from_seller_signals_header_ad_slot_);
   top_level_seller_winning_bid_info.bid = winner->bid->bid;
 
   if (winner->bid->auction == this) {
@@ -2353,8 +2367,13 @@
     component_seller_winning_bid_info->auction_config =
         component_auction->config_;
     DCHECK(component_auction->subresource_url_builder_);
+    // Should never be null.
+    CHECK(component_auction->direct_from_seller_signals_header_ad_slot_);
     component_seller_winning_bid_info->subresource_url_builder =
         std::move(component_auction->subresource_url_builder_);
+    component_seller_winning_bid_info
+        ->direct_from_seller_signals_header_ad_slot = std::move(
+        component_auction->direct_from_seller_signals_header_ad_slot_);
     const LeaderInfo& component_leader = component_auction->leader_info();
     component_seller_winning_bid_info->bid = component_leader.top_bid->bid->bid;
     // The bidder in this auction was the actual bidder, so the currency comes
@@ -2500,10 +2519,13 @@
     AdAuctionPageData* auction_page_data,
     const absl::optional<std::string>&
         direct_from_seller_signals_header_ad_slot) {
+  CHECK(!direct_from_seller_signals_header_ad_slot_pending_);
   if (!direct_from_seller_signals_header_ad_slot) {
     return;
   }
-
+  if (started_bidding_and_scoring_phase_) {
+    ++num_scoring_dependencies_;
+  }
   direct_from_seller_signals_header_ad_slot_pending_ = true;
   HeaderDirectFromSellerSignals::ParseAndFind(
       auction_page_data->GetAuctionSignalsForOrigin(config_->seller),
@@ -3098,6 +3120,12 @@
   return absl::nullopt;
 }
 
+absl::optional<std::string>
+InterestGroupAuction::GetDirectFromSellerAuctionSignalsHeaderAdSlot(
+    const HeaderDirectFromSellerSignals& signals) {
+  return signals.auction_signals();
+}
+
 absl::optional<GURL> InterestGroupAuction::GetDirectFromSellerPerBuyerSignals(
     const SubresourceUrlBuilder* subresource_url_builder,
     const url::Origin& owner) {
@@ -3112,6 +3140,17 @@
   return it->second.subresource_url;
 }
 
+absl::optional<std::string>
+InterestGroupAuction::GetDirectFromSellerPerBuyerSignalsHeaderAdSlot(
+    const HeaderDirectFromSellerSignals& signals,
+    const url::Origin& owner) {
+  auto it = signals.per_buyer_signals().find(owner);
+  if (it == signals.per_buyer_signals().end()) {
+    return absl::nullopt;
+  }
+  return it->second;
+}
+
 absl::optional<GURL> InterestGroupAuction::GetDirectFromSellerSellerSignals(
     const SubresourceUrlBuilder* subresource_url_builder) {
   if (subresource_url_builder && subresource_url_builder->seller_signals()) {
@@ -3120,6 +3159,12 @@
   return absl::nullopt;
 }
 
+absl::optional<std::string>
+InterestGroupAuction::GetDirectFromSellerSellerSignalsHeaderAdSlot(
+    const HeaderDirectFromSellerSignals& signals) {
+  return signals.seller_signals();
+}
+
 InterestGroupAuction::LeaderInfo::LeaderInfo() = default;
 InterestGroupAuction::LeaderInfo::~LeaderInfo() = default;
 
@@ -3527,7 +3572,11 @@
   seller_worklet_handle_->GetSellerWorklet()->ScoreAd(
       bid_raw->ad_metadata, bid_raw->bid, bid_raw->bid_currency,
       config_->non_shared_params, GetDirectFromSellerSellerSignals(url_builder),
+      GetDirectFromSellerSellerSignalsHeaderAdSlot(
+          *direct_from_seller_signals_header_ad_slot_),
       GetDirectFromSellerAuctionSignals(url_builder),
+      GetDirectFromSellerAuctionSignalsHeaderAdSlot(
+          *direct_from_seller_signals_header_ad_slot_),
       GetOtherSellerParam(*bid_raw),
       parent_ ? PerBuyerCurrency(config_->seller, *parent_->config_)
               : absl::nullopt,
@@ -4133,12 +4182,19 @@
 void InterestGroupAuction::OnDirectFromSellerSignalHeaderAdSlotResolved(
     std::unique_ptr<HeaderDirectFromSellerSignals> signals,
     std::vector<std::string> errors) {
+  CHECK(direct_from_seller_signals_header_ad_slot_pending_);
+  CHECK(direct_from_seller_signals_header_ad_slot_);
   direct_from_seller_signals_header_ad_slot_ = std::move(signals);
   errors_.insert(errors_.end(), errors.begin(), errors.end());
 
   direct_from_seller_signals_header_ad_slot_pending_ = false;
-  for (const auto& buyer_helper : buyer_helpers_) {
-    buyer_helper->NotifyConfigDependencyResolved();
+
+  if (started_bidding_and_scoring_phase_) {
+    for (const auto& buyer_helper : buyer_helpers_) {
+      buyer_helper->NotifyConfigDependencyResolved();
+    }
+    OnScoringDependencyDone();
+    ScoreQueuedBidsIfReady();
   }
 }
 
diff --git a/content/browser/interest_group/interest_group_auction.h b/content/browser/interest_group/interest_group_auction.h
index dda380b..ae4a142 100644
--- a/content/browser/interest_group/interest_group_auction.h
+++ b/content/browser/interest_group/interest_group_auction.h
@@ -710,22 +710,41 @@
       const blink::AuctionConfig& config,
       const url::Origin& buyer);
 
-  // Gets the buyer DirectFromSellerSignals auction-signals in `config` for
-  // buyer.  Public so that InterestGroupAuctionReporter can use it.
+  // Gets the DirectFromSellerSignals auction-signals. Public so that
+  // InterestGroupAuctionReporter can use it.
   static absl::optional<GURL> GetDirectFromSellerAuctionSignals(
       const SubresourceUrlBuilder* subresource_url_builder);
 
+  // Gets the DirectFromSellerSignalsHeaderAdSlot auction-signals. Public so
+  // that InterestGroupAuctionReporter can use it.
+  static absl::optional<std::string>
+  GetDirectFromSellerAuctionSignalsHeaderAdSlot(
+      const HeaderDirectFromSellerSignals& signals);
+
   // Gets the buyer DirectFromSellerSignals per-buyer-signals in `config` for
   // buyer. Public so that InterestGroupAuctionReporter can use it.
   static absl::optional<GURL> GetDirectFromSellerPerBuyerSignals(
       const SubresourceUrlBuilder* subresource_url_builder,
       const url::Origin& owner);
 
-  // Gets the buyer DirectFromSellerSignals seller-signals in `config` for
-  // buyer. Public so that InterestGroupAuctionReporter can use it.
+  // Gets the buyer DirectFromSellerSignalsHeaderAdSlot per-buyer-signals
+  // for `owner`. Public so that InterestGroupAuctionReporter can use it.
+  static absl::optional<std::string>
+  GetDirectFromSellerPerBuyerSignalsHeaderAdSlot(
+      const HeaderDirectFromSellerSignals& signals,
+      const url::Origin& owner);
+
+  // Gets DirectFromSellerSignals seller-signals. Public so that
+  // InterestGroupAuctionReporter can use it.
   static absl::optional<GURL> GetDirectFromSellerSellerSignals(
       const SubresourceUrlBuilder* subresource_url_builder);
 
+  // Gets DirectFromSellerSignalsHeaderAdSlot seller-signals. Public so that
+  // InterestGroupAuctionReporter can use it.
+  static absl::optional<std::string>
+  GetDirectFromSellerSellerSignalsHeaderAdSlot(
+      const HeaderDirectFromSellerSignals& signals);
+
   // Replaces `${}` placeholders in a debug report URL's query string for post
   // auction signals if exist. Only replaces unescaped placeholder ${}, but
   // not escaped placeholder (i.e., %24%7B%7D).
@@ -821,7 +840,8 @@
   // True if all async prerequisites for calling ScoreBid on the SellerWorklet
   // are done.
   bool ReadyToScoreBids() const {
-    return seller_worklet_received_ && config_promises_resolved_;
+    return seller_worklet_received_ && config_promises_resolved_ &&
+           !direct_from_seller_signals_header_ad_slot_pending_;
   }
 
   // Called when RequestSellerWorklet() returns. Starts scoring bids, if there
@@ -842,6 +862,7 @@
   // True if all bids have been generated (or decoded from additional_bids) and
   // scored and all config promises resolved.
   bool IsBiddingAndScoringPhaseComplete() const {
+    CHECK(started_bidding_and_scoring_phase_);
     return num_scoring_dependencies_ == 0 && bids_being_scored_ == 0 &&
            unscored_bids_.empty();
   }
@@ -1007,6 +1028,11 @@
   // creating it if needed.
   SubresourceUrlBuilder* SubresourceUrlBuilderIfReady();
 
+  const HeaderDirectFromSellerSignals*
+  direct_from_seller_signals_header_ad_slot() const {
+    return direct_from_seller_signals_header_ad_slot_.get();
+  }
+
   void OnDecompressedServerResponse(
       std::unique_ptr<data_decoder::DataDecoder> decoder,
       AdAuctionRequestContext* request_context,
@@ -1110,7 +1136,8 @@
   // This includes bidders that are still attempting to generate bids ---
   // both BuyerHelpers and component auctions. BuyerHelpers may generate
   // multiple bids (or no bids). It also includes waiting for promises in
-  // configuration to resolve.
+  // configuration to resolve, and waiting for
+  // directFromSellerSignalsHeaderAdSlot to parse.
   // TODO(morlovich): And will wait for additional_bids.
   //
   // When this reaches 0, the SellerWorklet's SendPendingSignalsRequests()
@@ -1161,7 +1188,7 @@
   std::unique_ptr<SubresourceUrlBuilder> subresource_url_builder_;
 
   // Stores the loaded HeaderDirectFromSellerSignals, if there were any. Should
-  // never be null.
+  // never be null until moved to the reporter.
   //
   // After `direct_from_seller_signals_header_ad_slot_` has been
   // set to true, the default constructed value gets replaced with the found
diff --git a/content/browser/interest_group/interest_group_auction_reporter.cc b/content/browser/interest_group/interest_group_auction_reporter.cc
index 4ba47e1..b8398d63 100644
--- a/content/browser/interest_group/interest_group_auction_reporter.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter.cc
@@ -456,8 +456,12 @@
       seller_info->auction_config->non_shared_params,
       InterestGroupAuction::GetDirectFromSellerSellerSignals(
           seller_info->subresource_url_builder.get()),
+      InterestGroupAuction::GetDirectFromSellerSellerSignalsHeaderAdSlot(
+          *seller_info->direct_from_seller_signals_header_ad_slot),
       InterestGroupAuction::GetDirectFromSellerAuctionSignals(
           seller_info->subresource_url_builder.get()),
+      InterestGroupAuction::GetDirectFromSellerAuctionSignalsHeaderAdSlot(
+          *seller_info->direct_from_seller_signals_header_ad_slot),
       std::move(other_seller),
       winning_bid_info_.storage_interest_group->interest_group.owner,
       /*browser_signal_buyer_and_seller_reporting_id=*/
@@ -718,8 +722,13 @@
       InterestGroupAuction::GetDirectFromSellerPerBuyerSignals(
           seller_info.subresource_url_builder.get(),
           winning_bid_info_.storage_interest_group->interest_group.owner),
+      InterestGroupAuction::GetDirectFromSellerPerBuyerSignalsHeaderAdSlot(
+          *seller_info.direct_from_seller_signals_header_ad_slot,
+          winning_bid_info_.storage_interest_group->interest_group.owner),
       InterestGroupAuction::GetDirectFromSellerAuctionSignals(
           seller_info.subresource_url_builder.get()),
+      InterestGroupAuction::GetDirectFromSellerAuctionSignalsHeaderAdSlot(
+          *seller_info.direct_from_seller_signals_header_ad_slot),
       signals_for_winner, kanon_mode_, bid_is_kanon_,
       winning_bid_info_.render_url,
       RoundStochasticallyToKBits(winning_bid_info_.bid,
diff --git a/content/browser/interest_group/interest_group_auction_reporter.h b/content/browser/interest_group/interest_group_auction_reporter.h
index d5a88e2..fbe1f1b 100644
--- a/content/browser/interest_group/interest_group_auction_reporter.h
+++ b/content/browser/interest_group/interest_group_auction_reporter.h
@@ -46,6 +46,7 @@
 class AuctionWorkletManager;
 struct BiddingAndAuctionResponse;
 class BrowserContext;
+class HeaderDirectFromSellerSignals;
 class InterestGroupManagerImpl;
 class PrivateAggregationManager;
 
@@ -118,6 +119,8 @@
         auction_config;
 
     std::unique_ptr<SubresourceUrlBuilder> subresource_url_builder;
+    std::unique_ptr<HeaderDirectFromSellerSignals>
+        direct_from_seller_signals_header_ad_slot;
 
     // Bid fed as input to the seller. If this is the top level seller and the
     // bid came from a component auction, it's the (optionally) modified bid
diff --git a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
index 8cc4909..dc0013d 100644
--- a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
@@ -25,6 +25,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "content/browser/fenced_frame/fenced_frame_reporter.h"
 #include "content/browser/interest_group/auction_worklet_manager.h"
+#include "content/browser/interest_group/header_direct_from_seller_signals.h"
 #include "content/browser/interest_group/interest_group_k_anonymity_manager.h"
 #include "content/browser/interest_group/interest_group_manager_impl.h"
 #include "content/browser/interest_group/mock_auction_process_manager.h"
@@ -65,6 +66,9 @@
   // return nothing, though.
   out.subresource_url_builder = std::make_unique<SubresourceUrlBuilder>(
       /*direct_from_seller_signals=*/absl::nullopt);
+  // Also must not be null.
+  out.direct_from_seller_signals_header_ad_slot =
+      std::make_unique<HeaderDirectFromSellerSignals>();
 
   // The specific values these are assigned to don't matter for these tests, but
   // they don't have default initializers, so have to set them to placate memory
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc
index 45c4932..cc92844 100644
--- a/content/browser/interest_group/interest_group_browsertest.cc
+++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -5270,6 +5270,60 @@
                 JsReplace(kAuctionConfigTemplate, test_origin, decision_url)));
 }
 
+IN_PROC_BROWSER_TEST_F(
+    InterestGroupBrowserTest,
+    RunAdAuctionRejectPromiseDirectFromSellerSignalsHeaderAdSlot) {
+  GURL test_url = https_server_->GetURL("a.test", "/echo");
+  url::Origin test_origin = url::Origin::Create(test_url);
+  ASSERT_TRUE(NavigateToURL(shell(), test_url));
+  GURL decision_url =
+      https_server_->GetURL("a.test", "/interest_group/decision_logic.js");
+
+  const char kAuctionConfigTemplate[] = R"({
+      seller: $1,
+      decisionLogicUrl: $2,
+      directFromSellerSignalsHeaderAdSlot: new Promise((resolve, reject) => {
+        setTimeout(() => { reject('boo'); }, 10) }),
+      interestGroupBuyers: []
+  })";
+
+  EXPECT_EQ("Promise argument rejected or resolved to invalid value.",
+            RunAuctionAndWait(
+                JsReplace(kAuctionConfigTemplate, test_origin, decision_url)));
+}
+
+IN_PROC_BROWSER_TEST_F(
+    InterestGroupBrowserTest,
+    RunAdAuctionMissingDirectFromSellerSignalsHeaderAdSlotLogged) {
+  GURL test_url = https_server_->GetURL("a.test", "/echo");
+  url::Origin test_origin = url::Origin::Create(test_url);
+  ASSERT_TRUE(NavigateToURL(shell(), test_url));
+  GURL decision_url =
+      https_server_->GetURL("a.test", "/interest_group/decision_logic.js");
+
+  // Fetch a URL with adAuctionHeaders: true. The response has no
+  // Ad-Auction-Signals header, so signals aren't found. An error should be
+  // logged to devtools.
+  EXPECT_TRUE(ExecJs(
+      web_contents()->GetPrimaryMainFrame(),
+      content::JsReplace("fetch($1, {adAuctionHeaders: true})", test_url)));
+
+  const char kAuctionConfigTemplate[] = R"({
+      seller: $1,
+      decisionLogicUrl: $2,
+      directFromSellerSignalsHeaderAdSlot: "notFound",
+      interestGroupBuyers: []
+  })";
+
+  WebContentsConsoleObserver console_observer(shell()->web_contents());
+  console_observer.SetPattern(
+      "Worklet error: When looking for directFromSellerSignalsHeaderAdSlot "
+      "notFound, failed to find a matching response.");
+  EXPECT_EQ(nullptr, RunAuctionAndWait(JsReplace(kAuctionConfigTemplate,
+                                                 test_origin, decision_url)));
+  EXPECT_TRUE(console_observer.Wait());
+}
+
 IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest,
                        RunAdAuctionPromiseInvalidDirectFromSellerSignals) {
   GURL test_url = https_server_->GetURL("a.test", "/echo");
@@ -5768,6 +5822,164 @@
   }
 }
 
+// Create a cross origin iframe, and load header-based directFromSellerSignals
+// in that frame. Then, in the main frame, run an auction using the loaded
+// signals.
+IN_PROC_BROWSER_TEST_F(
+    InterestGroupBrowserTest,
+    DirectFromSellerSignalsHeaderAdSlotFromCrossOriginIframe) {
+  constexpr char kBidderHost[] = "a.test";
+  constexpr char kTopFrameHost[] = "c.test";
+  constexpr char kSellerHost[] = "b.test";
+  constexpr char kIframeHost[] = "d.test";
+  url::Origin seller_origin =
+      url::Origin::Create(https_server_->GetURL(kSellerHost, "/echo"));
+  url::Origin iframe_origin =
+      url::Origin::Create(https_server_->GetURL(kIframeHost, "/echo"));
+
+  GURL bidder_url = https_server_->GetURL(kBidderHost, "/echo");
+  ASSERT_TRUE(NavigateToURL(shell(), bidder_url));
+  url::Origin bidder_origin = url::Origin::Create(bidder_url);
+
+  ASSERT_EQ(kSuccess,
+            JoinInterestGroupAndVerify(
+                /*owner=*/bidder_origin, /*name=*/"cars", /*priority=*/0.0,
+                blink::InterestGroup::ExecutionMode::kCompatibilityMode,
+                /*bidding_url=*/
+                https_server_->GetURL(kBidderHost,
+                                      "/interest_group/bidding_logic.js"),
+                /*ads=*/
+                {{{GURL("https://example.com/render"),
+                   /*metadata=*/absl::nullopt}}}));
+
+  GURL top_frame_url = https_server_->GetURL(
+      kTopFrameHost,
+      base::StringPrintf(
+          "/cross_site_iframe_factory.html?%s(%s)", kTopFrameHost,
+          https_server_->GetURL(kIframeHost, "/echo").spec().c_str()));
+
+  ASSERT_TRUE(NavigateToURL(shell(), top_frame_url));
+  RenderFrameHost* const iframe_host =
+      ChildFrameAt(web_contents()->GetPrimaryMainFrame(), /*index=*/0);
+
+  const char kHeaderSignalsPath[] = "/header_direct_from_seller_signals.json";
+  // The actual body of the request is just an empty JSON dict for the test,
+  // but it could be any arbitrary payload that the server wants to deliver
+  // with the header signals.
+  const char kHeaderSignalsBodyResponse[] = "{}";
+  const char kHeaderSignalsResponse[] = R"([{
+      "adSlot": "adSlot1",
+      "sellerSignals": {"json": "for", "the": ["seller"]}
+    }])";
+  network_responder_->RegisterNetworkResponse(
+      kHeaderSignalsPath, kHeaderSignalsBodyResponse, "application/json",
+      /*extra_response_headers=*/
+      {{"Access-Control-Allow-Origin", iframe_origin.Serialize()},
+       {"Ad-Auction-Signals", kHeaderSignalsResponse}});
+  EXPECT_TRUE(ExecJs(iframe_host,
+                     content::JsReplace("fetch($1, {adAuctionHeaders: true})",
+                                        https_server_->GetURL(
+                                            kSellerHost, kHeaderSignalsPath))));
+
+  TestFencedFrameURLMappingResultObserver observer;
+  ConvertFencedFrameURNToURL(
+      GURL(EvalJs(web_contents()->GetPrimaryMainFrame(),
+                  JsReplace(
+                      R"(
+(async function() {
+  return await navigator.runAdAuction({
+      seller: $1,
+      decisionLogicUrl: $2,
+      interestGroupBuyers: [$3],
+      directFromSellerSignalsHeaderAdSlot: "adSlot1"
+  });
+})())",
+                      seller_origin.Serialize().c_str(),
+                      https_server_->GetURL(kSellerHost,
+                                            "/interest_group/"
+                                            "decision_simple_direct_from_"
+                                            "seller_signals_validator.js"),
+                      bidder_origin.Serialize().c_str()))
+               .ExtractString()),
+      &observer);
+  EXPECT_EQ(GURL("https://example.com/render"), observer.mapped_url());
+}
+
+// Start an auction using directFromSellerSignalsHeaderAdSlot, but navigate away
+// immediately after starting the auction.
+IN_PROC_BROWSER_TEST_F(
+    InterestGroupBrowserTest,
+    DirectFromSellerSignalsHeaderAdSlotNavigateAwayDuringAuction) {
+  constexpr char kBidderHost[] = "a.test";
+  constexpr char kTopFrameHost[] = "c.test";
+  constexpr char kSellerHost[] = "b.test";
+  constexpr char kNewTopFrameHost[] = "d.test";
+  url::Origin seller_origin =
+      url::Origin::Create(https_server_->GetURL(kSellerHost, "/echo"));
+  const url::Origin top_frame_origin =
+      url::Origin::Create(https_server_->GetURL(kTopFrameHost, "/echo"));
+
+  GURL bidder_url = https_server_->GetURL(kBidderHost, "/echo");
+  ASSERT_TRUE(NavigateToURL(shell(), bidder_url));
+  url::Origin bidder_origin = url::Origin::Create(bidder_url);
+
+  ASSERT_EQ(kSuccess,
+            JoinInterestGroupAndVerify(
+                /*owner=*/bidder_origin, /*name=*/"cars", /*priority=*/0.0,
+                blink::InterestGroup::ExecutionMode::kCompatibilityMode,
+                /*bidding_url=*/
+                https_server_->GetURL(kBidderHost,
+                                      "/interest_group/bidding_logic.js"),
+                /*ads=*/
+                {{{GURL("https://example.com/render"),
+                   /*metadata=*/absl::nullopt}}}));
+
+  GURL top_frame_url = https_server_->GetURL(kTopFrameHost, "/echo");
+  ASSERT_TRUE(NavigateToURL(shell(), top_frame_url));
+
+  const char kHeaderSignalsPath[] = "/header_direct_from_seller_signals.json";
+  // The actual body of the request is just an empty JSON dict for the test,
+  // but it could be any arbitrary payload that the server wants to deliver
+  // with the header signals.
+  const char kHeaderSignalsBodyResponse[] = "{}";
+  const char kHeaderSignalsResponse[] = R"([{
+      "adSlot": "adSlot1",
+      "sellerSignals": {"json": "for", "the": ["seller"]}
+    }])";
+  network_responder_->RegisterNetworkResponse(
+      kHeaderSignalsPath, kHeaderSignalsBodyResponse, "application/json",
+      /*extra_response_headers=*/
+      {{"Access-Control-Allow-Origin", top_frame_origin.Serialize()},
+       {"Ad-Auction-Signals", kHeaderSignalsResponse}});
+  EXPECT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(),
+                     content::JsReplace("fetch($1, {adAuctionHeaders: true})",
+                                        https_server_->GetURL(
+                                            kSellerHost, kHeaderSignalsPath))));
+
+  ExecuteScriptAsync(web_contents()->GetPrimaryMainFrame(),
+                     JsReplace(
+                         R"(
+(async function() {
+  return await navigator.runAdAuction({
+      seller: $1,
+      decisionLogicUrl: $2,
+      interestGroupBuyers: [$3],
+      directFromSellerSignalsHeaderAdSlot: "adSlot1"
+  });
+})())",
+                         seller_origin.Serialize().c_str(),
+                         https_server_->GetURL(kSellerHost,
+                                               "/interest_group/"
+                                               "decision_simple_direct_from_"
+                                               "seller_signals_validator.js"),
+                         bidder_origin.Serialize().c_str()));
+
+  // Navigate away without waiting for the auction to complete. Nothing should
+  // crash.
+  ASSERT_TRUE(
+      NavigateToURL(shell(), https_server_->GetURL(kNewTopFrameHost, "/echo")));
+}
+
 IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest,
                        InvalidDirectFromSellerSignalsHeaderAdSlot) {
   GURL test_url = https_server_->GetURL("a.test", "/echo");
@@ -9951,9 +10163,17 @@
   EXPECT_EQ(nullptr, RunAuctionAndWait(auction_config));
 }
 
+class InterestGroupWorkletValidationBrowserTest
+    : public InterestGroupBrowserTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  bool UseHeaderDirectFromSellerSignals() const { return GetParam(); }
+};
+
 // Use bidder and seller worklet files that validate their arguments all have
 // the expected values.
-IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest, ValidateWorkletParameters) {
+IN_PROC_BROWSER_TEST_P(InterestGroupWorkletValidationBrowserTest,
+                       ValidateWorkletParameters) {
   // Use different hostnames for each participant, since
   // `trusted_bidding_signals` only checks the hostname of certain parameters.
   constexpr char kBidderHost[] = "a.test";
@@ -10022,44 +10242,82 @@
           /*ad_sizes=*/{},
           /*size_groups=*/{}, /*auction_server_request_flags=*/{})));
 
-  // For `directFromSellerSignals` to work, we need to navigate to a page that
-  // declares the subresource bundle resources we pass to those fields.
   GURL seller_script_url = https_server_->GetURL(
       kSellerHost, "/interest_group/decision_argument_validator.js");
   url::Origin seller_origin = url::Origin::Create(seller_script_url);
-  std::vector<NetworkResponder::SubresourceResponse> subresource_responses = {
-      NetworkResponder::SubresourceResponse(
-          /*subresource_url=*/
-          "/direct_from_seller_signals?sellerSignals",
-          /*payload=*/
-          R"({"json": "for", "the": ["seller"]})"),
-      NetworkResponder::SubresourceResponse(
-          /*subresource_url=*/"/direct_from_seller_signals?auctionSignals",
-          /*payload=*/
-          R"({"json": "for", "all": ["parties"]})"),
-      NetworkResponder::DirectFromSellerPerBuyerSignals(
-          bidder_origin, /*payload=*/
-          R"({"json": "for", "buyer": [1]})"),
-      NetworkResponder::DirectFromSellerPerBuyerSignals(
-          second_bidder_origin, /*payload=*/
-          R"({"json": "for", "buyer": [2]})"),
-  };
-  std::vector<NetworkResponder::SubresourceBundle> bundles = {
-      NetworkResponder::SubresourceBundle(
-          /*bundle_url=*/https_server_->GetURL(kSellerHost,
-                                               "/generated_bundle.wbn"),
-          /*subresources=*/subresource_responses)};
 
-  network_responder_->RegisterDirectFromSellerSignalsResponse(
-      /*bundles=*/bundles,
-      /*allow_origin=*/top_frame_origin.Serialize());
-  constexpr char kPagePath[] = "/page-with-bundles.html";
-  network_responder_->RegisterHtmlWithSubresourceBundles(
-      /*bundles=*/bundles,
-      /*page_url=*/kPagePath);
+  if (UseHeaderDirectFromSellerSignals()) {
+    // For `directFromSellerSignalsHeaderAdSlot`, we need to make a network
+    // request to a resource that has signals in the Ad-Auction-Signals header
+    // value.
+    ASSERT_TRUE(
+        NavigateToURL(shell(), https_server_->GetURL(kTopFrameHost, "/echo")));
+    const char kHeaderSignalsPath[] = "/header_direct_from_seller_signals.json";
+    // The actual body of the request is just an empty JSON dict for the test,
+    // but it could be any arbitrary payload that the server wants to deliver
+    // with the header signals.
+    const char kHeaderSignalsBodyResponse[] = "{}";
+    const std::string kHeaderSignalsResponse =
+        base::StringPrintf(R"([{
+      "adSlot": "adSlot1",
+      "sellerSignals": {"json": "for", "the": ["seller"]},
+      "auctionSignals": {"json": "for", "all": ["parties"]},
+      "perBuyerSignals": {
+        "%s": {"json": "for", "buyer": [1]},
+        "%s": {"json": "for", "buyer": [2]}
+      }
+    }])",
+                           bidder_origin.Serialize().c_str(),
+                           second_bidder_origin.Serialize().c_str());
+    network_responder_->RegisterNetworkResponse(
+        kHeaderSignalsPath, kHeaderSignalsBodyResponse, "application/json",
+        /*extra_response_headers=*/
+        {{"Access-Control-Allow-Origin", top_frame_origin.Serialize()},
+         {"Ad-Auction-Signals", kHeaderSignalsResponse}});
+    EXPECT_TRUE(
+        ExecJs(web_contents()->GetPrimaryMainFrame(),
+               content::JsReplace(
+                   "fetch($1, {adAuctionHeaders: true})",
+                   https_server_->GetURL(kSellerHost, kHeaderSignalsPath))));
+  } else {
+    // For subresource bundle `directFromSellerSignals` to work, we need to
+    // navigate to a page that declares the subresource bundle resources we pass
+    // to those fields.
+    std::vector<NetworkResponder::SubresourceResponse> subresource_responses = {
+        NetworkResponder::SubresourceResponse(
+            /*subresource_url=*/
+            "/direct_from_seller_signals?sellerSignals",
+            /*payload=*/
+            R"({"json": "for", "the": ["seller"]})"),
+        NetworkResponder::SubresourceResponse(
+            /*subresource_url=*/"/direct_from_seller_signals?auctionSignals",
+            /*payload=*/
+            R"({"json": "for", "all": ["parties"]})"),
+        NetworkResponder::DirectFromSellerPerBuyerSignals(
+            bidder_origin, /*payload=*/
+            R"({"json": "for", "buyer": [1]})"),
+        NetworkResponder::DirectFromSellerPerBuyerSignals(
+            second_bidder_origin, /*payload=*/
+            R"({"json": "for", "buyer": [2]})"),
+    };
+    std::vector<NetworkResponder::SubresourceBundle> bundles = {
+        NetworkResponder::SubresourceBundle(
+            /*bundle_url=*/https_server_->GetURL(kSellerHost,
+                                                 "/generated_bundle.wbn"),
+            /*subresources=*/subresource_responses)};
 
-  ASSERT_TRUE(
-      NavigateToURL(shell(), https_server_->GetURL(kTopFrameHost, kPagePath)));
+    network_responder_->RegisterDirectFromSellerSignalsResponse(
+        /*bundles=*/bundles,
+        /*allow_origin=*/top_frame_origin.Serialize());
+    constexpr char kPagePath[] = "/page-with-bundles.html";
+    network_responder_->RegisterHtmlWithSubresourceBundles(
+        /*bundles=*/bundles,
+        /*page_url=*/kPagePath);
+
+    ASSERT_TRUE(NavigateToURL(shell(),
+                              https_server_->GetURL(kTopFrameHost, kPagePath)));
+  }
+
   TestFencedFrameURLMappingResultObserver observer;
   ConvertFencedFrameURNToURL(
       GURL(EvalJs(shell(),
@@ -10073,7 +10331,7 @@
     interestGroupBuyers: [$4, $5],
     auctionSignals: {so: 'I', hear: ['you', 'like', 'json']},
     sellerSignals: {signals: 'from', the: ['seller']},
-    directFromSellerSignals: $6,
+    $6: $7,
     sellerTimeout: 200,
     perBuyerSignals: {$4: {signalsForBuyer: 1}, $5: {signalsForBuyer: 2}},
     perBuyerTimeouts: {$4: 110, $5: 120, '*': 150},
@@ -10089,8 +10347,15 @@
                           kSellerHost,
                           "/interest_group/trusted_scoring_signals.json"),
                       bidder_origin, second_bidder_origin,
-                      https_server_->GetURL(kSellerHost,
-                                            "/direct_from_seller_signals")))
+                      UseHeaderDirectFromSellerSignals()
+                          ? "directFromSellerSignalsHeaderAdSlot"
+                          : "directFromSellerSignals",
+                      UseHeaderDirectFromSellerSignals()
+                          ? "adSlot1"
+                          : https_server_
+                                ->GetURL(kSellerHost,
+                                         "/direct_from_seller_signals")
+                                .spec()))
                .ExtractString()),
       &observer);
   EXPECT_EQ(GURL("https://example.com/render"), observer.mapped_url());
@@ -10105,6 +10370,16 @@
   WaitForUrl(https_server_->GetURL(kSellerHost, "/echo?report_bidder"));
 }
 
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    InterestGroupWorkletValidationBrowserTest,
+    testing::Bool(),
+    [](const testing::TestParamInfo<bool>& info) {
+      return base::StringPrintf(
+          "%s", info.param ? "header_direct_from_seller_signals"
+                           : "subresource_bundle_direct_from_seller_signals");
+    });
+
 // Same as above test, but leaves out the extra bidder and uses the older
 // version 1 bidding signals format.
 IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest,
@@ -10240,9 +10515,22 @@
   WaitForUrl(https_server_->GetURL(kSellerHost, "/echo?report_bidder"));
 }
 
+class InterestGroupComponentWorkletValidationBrowserTest
+    : public InterestGroupBrowserTest,
+      public testing::WithParamInterface<std::tuple<bool, bool>> {
+ public:
+  bool TopLevelUseHeaderDirectFromSellerSignals() const {
+    return std::get<0>(GetParam());
+  }
+
+  bool ComponentUseHeaderDirectFromSellerSignals() const {
+    return std::get<1>(GetParam());
+  }
+};
+
 // Use bidder and seller worklet files that validate their arguments all have
 // the expected values, in the case of an auction with one component auction.
-IN_PROC_BROWSER_TEST_F(InterestGroupBrowserTest,
+IN_PROC_BROWSER_TEST_P(InterestGroupComponentWorkletValidationBrowserTest,
                        ComponentAuctionValidateWorkletParameters) {
   // Use different hostnames for each participant.
   //
@@ -10308,8 +10596,6 @@
             /*ad_sizes=*/{},
             /*size_groups=*/{}, /*auction_server_request_flags=*/{})));
 
-    // For `directFromSellerSignals` to work, we need to navigate to a page that
-    // declares the subresource bundle resources we pass to those fields.
     GURL top_level_seller_script_url = https_server_->GetURL(
         kTopLevelSellerHost,
         "/interest_group/"
@@ -10322,6 +10608,10 @@
         url::Origin::Create(top_level_seller_script_url);
     const url::Origin component_seller_origin =
         url::Origin::Create(component_seller_script_url);
+
+    // For subresource bundle `directFromSellerSignals` to work, we need to
+    // navigate to a page that declares the subresource bundle resources we pass
+    // to those fields.
     std::vector<NetworkResponder::SubresourceResponse>
         top_level_subresource_responses = {
             NetworkResponder::SubresourceResponse(
@@ -10372,6 +10662,58 @@
     ASSERT_TRUE(NavigateToURL(shell(),
                               https_server_->GetURL(kTopFrameHost, kPagePath)));
 
+    // For `directFromSellerSignalsHeaderAdSlot`, we need to make a network
+    // request to a resource that has signals in the Ad-Auction-Signals header
+    // value. We do this for both the top-level seller and the component seller.
+    const char kTopLevelHeaderSignalsPath[] =
+        "/top_level_header_direct_from_seller_signals.json";
+    const char kComponentHeaderSignalsPath[] =
+        "/component_header_direct_from_seller_signals.json";
+    // The actual body of both requests is just an empty JSON dict for the test,
+    // but it could be any arbitrary payload that the server wants to deliver
+    // with the header signals.
+    const char kHeaderSignalsBodyResponse[] = "{}";
+    // Intentionally use the same adSlot name for both responses -- responses
+    // from different sellers shouldn't conflict.
+    const char kTopLevelHeaderSignalsResponse[] = R"([{
+      "adSlot": "adSlot1",
+      "sellerSignals": {"json": "for", "the": ["seller"]},
+      "auctionSignals": {"json": "for", "all": ["parties"]}
+    }])";
+    const std::string kComponentHeaderSignalsResponse =
+        base::StringPrintf(R"([{
+      "adSlot": "adSlot1",
+      "sellerSignals": {"from": "component", "json": "for", "the": ["seller"]},
+      "auctionSignals": {
+        "from": "component", "json": "for", "all": ["parties"]},
+      "perBuyerSignals": {
+        "%s": {"from": "component", "json": "for", "buyer": [1]}
+      }
+    }])",
+                           bidder_origin.Serialize().c_str());
+    network_responder_->RegisterNetworkResponse(
+        kTopLevelHeaderSignalsPath, kHeaderSignalsBodyResponse,
+        "application/json",
+        /*extra_response_headers=*/
+        {{"Access-Control-Allow-Origin", top_frame_origin.Serialize()},
+         {"Ad-Auction-Signals", kTopLevelHeaderSignalsResponse}});
+    network_responder_->RegisterNetworkResponse(
+        kComponentHeaderSignalsPath, kHeaderSignalsBodyResponse,
+        "application/json",
+        /*extra_response_headers=*/
+        {{"Access-Control-Allow-Origin", top_frame_origin.Serialize()},
+         {"Ad-Auction-Signals", kComponentHeaderSignalsResponse}});
+    EXPECT_TRUE(ExecJs(
+        web_contents()->GetPrimaryMainFrame(),
+        content::JsReplace("fetch($1, {adAuctionHeaders: true})",
+                           https_server_->GetURL(kTopLevelSellerHost,
+                                                 kTopLevelHeaderSignalsPath))));
+    EXPECT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(),
+                       content::JsReplace("fetch($1, {adAuctionHeaders: true})",
+                                          https_server_->GetURL(
+                                              kComponentSellerHost,
+                                              kComponentHeaderSignalsPath))));
+
     // TODO(caraitto): Instead of StringPrintf(), we can pass a single large
     // base::Value to JsReplace().
     TestFencedFrameURLMappingResultObserver observer;
@@ -10391,7 +10733,7 @@
     trustedScoringSignalsURL: "%s",
     auctionSignals: maybePromise(["top-level auction signals"]),
     sellerSignals: maybePromise(["top-level seller signals"]),
-    directFromSellerSignals: maybePromise("%s"),
+    %s: maybePromise("%s"),
     sellerTimeout: 300,
     perBuyerSignals: maybePromise(
         {[componentBuyer]: ["top-level buyer signals"]}),
@@ -10407,7 +10749,7 @@
       interestGroupBuyers: [componentBuyer],
       auctionSignals: maybePromise(["component auction signals"]),
       sellerSignals: maybePromise(["component seller signals"]),
-      directFromSellerSignals: maybePromise("%s"),
+      %s: maybePromise("%s"),
       sellerTimeout: 200,
       perBuyerSignals: maybePromise(
           {[componentBuyer]: ["component buyer signals"]}),
@@ -10432,11 +10774,16 @@
                                 "/interest_group/trusted_scoring_signals.json")
                             .spec()
                             .c_str(),
-                        https_server_
-                            ->GetURL(kTopLevelSellerHost,
-                                     "/direct_from_seller_signals")
-                            .spec()
-                            .c_str(),
+                        TopLevelUseHeaderDirectFromSellerSignals()
+                            ? "directFromSellerSignalsHeaderAdSlot"
+                            : "directFromSellerSignals",
+                        TopLevelUseHeaderDirectFromSellerSignals()
+                            ? "adSlot1"
+                            : https_server_
+                                  ->GetURL(kTopLevelSellerHost,
+                                           "/direct_from_seller_signals")
+                                  .spec()
+                                  .c_str(),
                         component_seller_script_url.spec().c_str(),
                         https_server_
                             ->GetURL(
@@ -10444,11 +10791,16 @@
                                 "/interest_group/trusted_scoring_signals2.json")
                             .spec()
                             .c_str(),
-                        https_server_
-                            ->GetURL(kComponentSellerHost,
-                                     "/direct_from_seller_signals")
-                            .spec()
-                            .c_str()))
+                        ComponentUseHeaderDirectFromSellerSignals()
+                            ? "directFromSellerSignalsHeaderAdSlot"
+                            : "directFromSellerSignals",
+                        ComponentUseHeaderDirectFromSellerSignals()
+                            ? "adSlot1"
+                            : https_server_
+                                  ->GetURL(kComponentSellerHost,
+                                           "/direct_from_seller_signals")
+                                  .spec()
+                                  .c_str()))
                 .ExtractString()),
         &observer);
     EXPECT_EQ(GURL("https://example.com/render"), observer.mapped_url());
@@ -10467,6 +10819,21 @@
   }
 }
 
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    InterestGroupComponentWorkletValidationBrowserTest,
+    testing::Combine(testing::Bool(), testing::Bool()),
+    [](const testing::TestParamInfo<std::tuple<bool, bool>>& info) {
+      return base::StringPrintf(
+          "%s_%s",
+          std::get<0>(info.param)
+              ? "top_level_header_direct_from_seller_signals"
+              : "top_level_subresource_bundle_direct_from_seller_signals",
+          std::get<1>(info.param)
+              ? "component_header_direct_from_seller_signals"
+              : "component_subresource_bundle_direct_from_seller_signals");
+    });
+
 // TODO(crbug.com/1441988): Remove this test once old names are no longer
 // supported.
 // Same as ComponentAuctionValidateWorkletParameters, but using deprecated names
@@ -11311,6 +11678,13 @@
   ASSERT_TRUE(NavigateToURL(shell(), test_url));
   url::Origin test_origin = url::Origin::Create(test_url);
 
+  // Need to fetch a URL with adAuctionHeaders: true for the auction to succeed
+  // when using directFromSellerSignalsHeaderAdSlot -- it doesn't matter which
+  // resource is fetched.
+  EXPECT_TRUE(ExecJs(
+      web_contents()->GetPrimaryMainFrame(),
+      content::JsReplace("fetch($1, {adAuctionHeaders: true})", test_url)));
+
   constexpr char kBiddingLogicScript[] = R"(
 function generateBid(
     interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals,
@@ -11408,11 +11782,13 @@
                           test_origin,
                           https_server_->GetURL("a.test", kBiddingLogicPath))));
 
-  TestFencedFrameURLMappingResultObserver observer;
-  ConvertFencedFrameURNToURL(
-      GURL(EvalJs(shell(),
-                  JsReplace(
-                      R"(
+  for (bool header_direct_from_seller_signals : {false, true}) {
+    SCOPED_TRACE(header_direct_from_seller_signals);
+    TestFencedFrameURLMappingResultObserver observer;
+    ConvertFencedFrameURNToURL(
+        GURL(EvalJs(shell(),
+                    JsReplace(
+                        R"(
 (async function() {
   return await navigator.runAdAuction({
     seller: $1,
@@ -11430,18 +11806,22 @@
       setTimeout(
           () => { resolve(undefined); }, 1)
     }),
-    directFromSellerSignals: new Promise((resolve, reject) => {
+    $3: new Promise((resolve, reject) => {
       setTimeout(
-          () => { resolve("null"); }, 1)
+          () => { resolve(null); }, 1)
     }),
   });
 })())",
-                      test_origin,
-                      https_server_->GetURL("a.test", kDecisionLogicPath)))
-               .ExtractString()),
-      &observer);
+                        test_origin,
+                        https_server_->GetURL("a.test", kDecisionLogicPath),
+                        header_direct_from_seller_signals
+                            ? "directFromSellerSignalsHeaderAdSlot"
+                            : "directFromSellerSignals"))
+                 .ExtractString()),
+        &observer);
 
-  EXPECT_EQ(GURL("https://example.com/render"), observer.mapped_url());
+    EXPECT_EQ(GURL("https://example.com/render"), observer.mapped_url());
+  }
 }
 
 // Test for perBuyerTimeouts and perBuyerCumulativeTimeouts being passed to
diff --git a/content/browser/interest_group/mock_auction_process_manager.cc b/content/browser/interest_group/mock_auction_process_manager.cc
index b147513..b27e37a 100644
--- a/content/browser/interest_group/mock_auction_process_manager.cc
+++ b/content/browser/interest_group/mock_auction_process_manager.cc
@@ -122,7 +122,11 @@
     const absl::optional<std::string>& auction_signals_json,
     const absl::optional<std::string>& per_buyer_signals_json,
     const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_per_buyer_signals_header_ad_slot,
     const absl::optional<GURL>& direct_from_seller_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     const std::string& seller_signals_json,
     auction_worklet::mojom::KAnonymityBidMode kanon_mode,
     bool bid_is_kanon,
@@ -164,7 +168,11 @@
     const absl::optional<base::TimeDelta> per_buyer_timeout,
     const absl::optional<blink::AdCurrency>& per_buyer_currency,
     const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
-    const absl::optional<GURL>& direct_from_seller_auction_signals) {
+    const absl::optional<std::string>&
+        direct_from_seller_per_buyer_signals_header_ad_slot,
+    const absl::optional<GURL>& direct_from_seller_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot) {
   // per_buyer_timeout passed to GenerateBid() should not be empty, because
   // auction_config's all_buyers_timeout (which is the key of '*' in
   // perBuyerTimeouts) is set in the AuctionRunnerTest.
@@ -342,7 +350,11 @@
     const blink::AuctionConfig::NonSharedParams&
         auction_ad_config_non_shared_params,
     const absl::optional<GURL>& direct_from_seller_seller_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_seller_signals_header_ad_slot,
     const absl::optional<GURL>& direct_from_seller_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     auction_worklet::mojom::ComponentAuctionOtherSellerPtr
         browser_signals_other_seller,
     const absl::optional<blink::AdCurrency>& component_expect_bid_currency,
@@ -386,7 +398,11 @@
     const blink::AuctionConfig::NonSharedParams&
         auction_ad_config_non_shared_params,
     const absl::optional<GURL>& direct_from_seller_seller_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_seller_signals_header_ad_slot,
     const absl::optional<GURL>& direct_from_seller_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     auction_worklet::mojom::ComponentAuctionOtherSellerPtr
         browser_signals_other_seller,
     const url::Origin& browser_signal_interest_group_owner,
diff --git a/content/browser/interest_group/mock_auction_process_manager.h b/content/browser/interest_group/mock_auction_process_manager.h
index a613a7f..610aa585 100644
--- a/content/browser/interest_group/mock_auction_process_manager.h
+++ b/content/browser/interest_group/mock_auction_process_manager.h
@@ -84,7 +84,11 @@
       const absl::optional<std::string>& auction_signals_json,
       const absl::optional<std::string>& per_buyer_signals_json,
       const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_per_buyer_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       const std::string& seller_signals_json,
       auction_worklet::mojom::KAnonymityBidMode kanon_mode,
       bool bid_is_kanon,
@@ -116,7 +120,11 @@
       const absl::optional<base::TimeDelta> per_buyer_timeout,
       const absl::optional<blink::AdCurrency>& per_buyer_currency,
       const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
-      const absl::optional<GURL>& direct_from_seller_auction_signals) override;
+      const absl::optional<std::string>&
+          direct_from_seller_per_buyer_signals_header_ad_slot,
+      const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot) override;
 
   // Waits for GenerateBid() to be invoked.
   void WaitForGenerateBid();
@@ -243,7 +251,11 @@
       const blink::AuctionConfig::NonSharedParams&
           auction_ad_config_non_shared_params,
       const absl::optional<GURL>& direct_from_seller_seller_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_seller_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       auction_worklet::mojom::ComponentAuctionOtherSellerPtr
           browser_signals_other_seller,
       const absl::optional<blink::AdCurrency>& component_expect_bid_currency,
@@ -260,7 +272,11 @@
       const blink::AuctionConfig::NonSharedParams&
           auction_ad_config_non_shared_params,
       const absl::optional<GURL>& direct_from_seller_seller_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_seller_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       auction_worklet::mojom::ComponentAuctionOtherSellerPtr
           browser_signals_other_seller,
       const url::Origin& browser_signal_interest_group_owner,
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
index 18c228a..d2aa512 100644
--- a/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
@@ -101,7 +101,7 @@
       }
     }
 
-    selection_controller_->HideAndDisallowShowingAutomatically();
+    selection_controller_->OnSessionEndEvent(event);
   }
 
   raw_ptr<ui::TouchSelectionController> selection_controller_;
@@ -562,10 +562,11 @@
 
 void TouchSelectionControllerClientAura::ExecuteCommand(int command_id,
                                                         int event_flags) {
-  if (command_id != ui::TouchEditable::kSelectAll &&
-      command_id != ui::TouchEditable::kSelectWord) {
-    rwhva_->selection_controller()->HideAndDisallowShowingAutomatically();
-  }
+  const bool should_dismiss_handles =
+      command_id != ui::TouchEditable::kSelectAll &&
+      command_id != ui::TouchEditable::kSelectWord;
+  rwhva_->selection_controller()->OnMenuCommand(should_dismiss_handles);
+
   RenderWidgetHostDelegate* host_delegate = rwhva_->host()->delegate();
   if (!host_delegate)
     return;
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc b/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
index e184d4d..724dd2de 100644
--- a/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
@@ -1378,6 +1378,11 @@
       ui::TouchSelectionDragType::kDoublePressDrag, 1);
   histogram_tester.ExpectTotalCount(ui::kTouchSelectionDragTypeHistogramName,
                                     2);
+
+  // Start typing to end the touch selection session.
+  generator.PressAndReleaseKey(ui::VKEY_A);
+  histogram_tester.ExpectUniqueSample(
+      ui::kTouchSelectionSessionTouchDownCountHistogramName, 3, 1);
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc b/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc
index 573c31d..573c0fd2 100644
--- a/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc
@@ -206,11 +206,12 @@
 
 void TouchSelectionControllerClientChildFrame::ExecuteCommand(int command_id,
                                                               int event_flags) {
-  if (command_id != ui::TouchEditable::kSelectAll &&
-      command_id != ui::TouchEditable::kSelectWord) {
-    manager_->GetTouchSelectionController()
-        ->HideAndDisallowShowingAutomatically();
-  }
+  const bool should_dismiss_handles =
+      command_id != ui::TouchEditable::kSelectAll &&
+      command_id != ui::TouchEditable::kSelectWord;
+  manager_->GetTouchSelectionController()->OnMenuCommand(
+      should_dismiss_handles);
+
   RenderWidgetHostDelegate* host_delegate = rwhv_->host()->delegate();
   if (!host_delegate)
     return;
diff --git a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
index 7869e23..df149dd 100644
--- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
@@ -4942,11 +4942,12 @@
   EXPECT_EQ(main_frame_url, main_document->GetLastCommittedURL());
   // Execute script in an isolated world to avoid causing a Trusted Types
   // violation due to eval.
-  EXPECT_EQ("Graphics Feature Status",
-            EvalJs(main_document,
-                   "document.querySelector('info-view').shadowRoot"
-                   ".querySelector('h3').textContent",
-                   EXECUTE_SCRIPT_DEFAULT_OPTIONS, /*world_id=*/1));
+  EXPECT_THAT(EvalJs(main_document,
+                     "document.querySelector('info-view').shadowRoot"
+                     ".querySelector('h3').textContent",
+                     EXECUTE_SCRIPT_DEFAULT_OPTIONS, /*world_id=*/1)
+                  .ExtractString(),
+              testing::StartsWith("Graphics Feature Status"));
 }
 
 // Start with A(B), navigate A to C. By emulating a slow unload handler B, check
diff --git a/content/browser/resources/gpu/BUILD.gn b/content/browser/resources/gpu/BUILD.gn
index 1078ac5..0e8785f 100644
--- a/content/browser/resources/gpu/BUILD.gn
+++ b/content/browser/resources/gpu/BUILD.gn
@@ -9,11 +9,7 @@
 
   static_files = [ "gpu_internals.html" ]
 
-  web_component_files = [
-    "info_view.ts",
-    "info_view_table.ts",
-    "info_view_table_row.ts",
-  ]
+  web_component_files = [ "info_view.ts" ]
 
   non_web_component_files = [
     "browser_bridge.ts",
diff --git a/content/browser/resources/gpu/gpu_internals.ts b/content/browser/resources/gpu/gpu_internals.ts
index 36efe9c..2349cb7 100644
--- a/content/browser/resources/gpu/gpu_internals.ts
+++ b/content/browser/resources/gpu/gpu_internals.ts
@@ -20,11 +20,17 @@
   document.querySelector('info-view')!.addBrowserBridgeListeners(browserBridge);
 
   // Because of inherent raciness (between the deprecated DevTools API which
-  // telemtry uses to drive the relevant tests, and the asynchronous loading of
-  // JS modules like this one) it's possible for telemetry tests to inject code
-  // *before* `browserBridge` is set and the DOM is populated. This flag is used
-  // to synchronize script injection by tests to prevent such races.
-  Object.assign(window, {gpuPagePopulated: true});
+  // telemetry uses to drive the relevant tests, and the asynchronous
+  // loading of JS modules like this one) it's possible for telemetry tests
+  // to inject code *before* `browserBridge` is set and the DOM is
+  // populated. This flag is used to synchronize script injection by tests
+  // to prevent such races.
+  Object.assign(window, {
+    gpuPagePopulated: true,
+    getGPUInfo(category: string, feature = '') {
+      return document.querySelector('info-view')!.getInfo(category, feature);
+    },
+  });
 }
 
 document.addEventListener('DOMContentLoaded', onLoad);
diff --git a/content/browser/resources/gpu/info_view.html b/content/browser/resources/gpu/info_view.html
index ce3643da..7d25830 100644
--- a/content/browser/resources/gpu/info_view.html
+++ b/content/browser/resources/gpu/info_view.html
@@ -42,7 +42,8 @@
     margin-top: 0;
   }
 
-  #content > div {
+  #content > div,
+  #download-to-file {
     margin-bottom: 1em;
   }
 
@@ -72,9 +73,7 @@
 
   #download-to-file {
     font: inherit;
-    margin: 0 1px 0 0;
     min-height: 2em;
-    padding: 1px 10px;
     user-select: none;
   }
 
@@ -83,12 +82,41 @@
     margin-bottom: 2px;
     margin-top: 10px;
   }
-</style>
+  
+  table.info-table {
+    border-collapse: collapse;
+    table-layout: fixed;
+    width: 100%;
+  }
+  .info-table td {
+    border: 1px solid #777;
+    vertical-align: top;
+    overflow-x: auto;
+  }
+  .info-table td:nth-child(1) {
+    font-weight: bold;
+    width: 25%;
+  }
+  .info-table td:nth-child(2) {
+    font-weight: bold;
+    width: 75%;
+  }
 
-<div id="content">
+  /*
+  This class is used to show text that is only available
+  when the user copies text or downloads the report to a file.
+  We insert extra but hidden text to make plain text formatting
+  look better, at copy/download time we make the text visible
+  */
+  .copy {
+    display: none;
+  }
+</style>
+<style id="dynamic-style"></style>
 <div>
   <button id="download-to-file">Download Report to File</button>
 </div>
+<div id="content">
 <div>
   <h3>Graphics Feature Status</h3>
   <ul class="feature-status-list"></ul>
diff --git a/content/browser/resources/gpu/info_view.ts b/content/browser/resources/gpu/info_view.ts
index 96c08f7..0492ab76 100644
--- a/content/browser/resources/gpu/info_view.ts
+++ b/content/browser/resources/gpu/info_view.ts
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import './info_view_table.js';
-
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {CustomElement} from 'chrome://resources/js/custom_element.js';
 
 import {AngleFeature, BrowserBridge, ClientInfo, FeatureStatus, Problem} from './browser_bridge.js';
 import {getTemplate} from './info_view.html.js';
-import {ArrayData, Data} from './info_view_table_row.js';
 import {VulkanInfo} from './vulkan_info.js';
 
 /**
@@ -28,12 +25,307 @@
   };
 }());
 
+function getProblemTextAndUrl(problem: Problem) {
+  let text = problem.description;
+  let url = '';
+  const pattern = ' Please update your graphics driver via this link: ';
+  const pos = text.search(pattern);
+  if (pos > 0) {
+    url = text.substring(pos + pattern.length);
+    text = text.substring(0, pos);
+  }
+  return {text, url};
+}
+
+function formatANGLEBug(bug: string) {
+  if (bug.includes('crbug.com/')) {
+    return bug.match(/\d+/)!.toString();
+  } else if (bug.includes('anglebug.com/')) {
+    return `anglebug:${bug.match(/\d+/)}`;
+  } else {
+    return bug;
+  }
+}
+
+/**
+ * Calls a function to insert an element between every element
+ * of an existing array
+ */
+function insertBetweenElements<Type>(
+    array: Type[], fn: (i: number) => Type): Type[] {
+  const newArray = array.slice(0, 1);
+  for (let i = 1; i < array.length; ++i) {
+    newArray.push(fn(i), array[i] as Type);
+  }
+  return newArray;
+}
+
+/** Inserts <span>, </span> between every element in array */
+function separateByCommas(array: HTMLElement[], comma = ', ') {
+  return insertBetweenElements(array, () => createElem('span', comma));
+}
+
+/**
+ * Conditionally add elements to an array
+ *
+ * ```js
+ * const array = [
+ *   "carrots",
+ *   "potatoes",
+ *   ...addIf(haveFruit, () => ["apple", "cherry"]),
+ * ]
+ * ```
+ *
+ * The function is not called if `cond` is false.
+ */
+function addIf<T>(cond: boolean, fn: () => T[]) {
+  return cond ? fn() : [];
+}
+
+/**
+ * Word wraps a string, prefixing each line.
+ */
+function wordWrap(s: string, prefix = '    ', maxLength?: number) {
+  maxLength = maxLength || (80 - prefix.length);
+  const lines: string[] = [];
+  const words = s.split(' ');
+  const line: string[] = [];
+  let length = 0;
+  for (const word of words) {
+    if (length + word.length + 1 >= maxLength) {
+      lines.push(line.join(' '));
+      line.length = 0;
+      length = 0;
+    }
+    line.push(word);
+    length += word.length + 1;
+  }
+  if (line.length) {
+    lines.push(line.join(' '));
+  }
+  return lines.map(s => `${prefix}${s}`).join('\n');
+}
+
+interface Attributes {
+  [key: string]: string|Attributes;
+}
+
+/**
+ * Creates an HTMLElement with optional attributes and children
+ *
+ * Examples:
+ *
+ * ```js
+ *   br = createElem('br');
+ *   p = createElem('p', 'hello world');
+ *   a = createElem('a', {href: 'https://google.com', textContent: 'Google'});
+ *   ul = createElement('ul', {}, [
+ *     createElem('li', 'apple'),
+ *     createElem('li', 'banana'),
+ *   ]);
+ *   h1 = createElem('h1', { style: { color: 'red' }, textContent: 'Title'})
+ * ```
+ */
+function createElem(
+    tag: string, attrs: Attributes|string = {}, children: HTMLElement[] = []) {
+  const elem = document.createElement(tag) as HTMLElement;
+  if (typeof attrs === 'string') {
+    elem.textContent = attrs;
+  } else {
+    const elemAsAttribs = elem as unknown as Attributes;
+    for (const [key, value] of Object.entries(attrs)) {
+      if (typeof value === 'function' && key.startsWith('on')) {
+        const eventName = key.substring(2).toLowerCase();
+        elem.addEventListener(eventName, value, {passive: false});
+      } else if (typeof value === 'object') {
+        for (const [k, v] of Object.entries(value)) {
+          (elemAsAttribs[key] as Attributes)[k] = v;
+        }
+      } else if (elemAsAttribs[key] === undefined) {
+        elem.setAttribute(key, value);
+      } else {
+        elemAsAttribs[key] = value;
+      }
+    }
+  }
+  for (const child of children) {
+    elem.appendChild(child);
+  }
+  return elem;
+}
+
+export interface Data {
+  description: string;
+  id?: string;
+  value: string;
+}
+
+export interface ArrayData {
+  description: string;
+  value: Data[];
+}
+
+/** Creates the td elements for a table row */
+function createInfoElements(
+    data: Data|ArrayData, padSize: number): HTMLElement[] {
+  const desc = createElem('td', {}, [
+    createElem('span', data.description.padEnd(padSize)),
+    createHidden(':'),
+  ]);
+
+  if (Array.isArray(data.value)) {
+    return [
+      desc,
+      createElem('td', {}, [createInfoTable((data as ArrayData).value)]),
+    ];
+  } else {
+    return [
+      desc,
+      createElem('td', {
+        textContent: data.value.toString().trim(),
+        id: (data as Data).id!,
+      }),
+    ];
+  }
+}
+
+/** Creates a table from the given data */
+function createInfoTable(data: Data[]|ArrayData[]) {
+  const longestDesc = Math.min(
+      32,
+      (data as Data[])
+          .reduce(
+              (longest, {description}) => Math.max(longest, description.length),
+              0));
+  return createElem('table', {className: 'info-table'}, [
+    createElem(
+        'tbody', {},
+        data.map(
+            data => createElem('tr', {}, createInfoElements(data, longestDesc)),
+            )),
+  ]);
+}
+
+/**
+ * Creates a hidden span that will only be used when the when
+ * the user copies or downloads text.
+ */
+function createHidden(textContent: string) {
+  return createElem('span', {className: 'copy', textContent});
+}
+
+/**
+ * Given a string or Attributes returns the `textContent`
+ * and the attributes with `textContent` removed
+ */
+function separateTextContentFromAttributes(attrs: Attributes|string = {}) {
+  return typeof attrs === 'string' ? {textContent: attrs, attribs: {}} : {
+    textContent: attrs['textContent'] as string || '',
+    attribs: {...attrs, textContent: ''},
+  };
+}
+
+/**
+ * Creates a list item with a hidden `*   ` span prepended for copy
+ */
+function createLi(attrs: Attributes|string = {}, children: HTMLElement[] = []) {
+  const {textContent, attribs} = separateTextContentFromAttributes(attrs);
+  return createElem('li', attribs, [
+    createHidden('*   '),
+    createElem('span', textContent),
+    ...children,
+  ]);
+}
+
+/**
+ * Creates a heading tag with hidden text for copying
+ * so the copy will be like markdown.
+ */
+function createHeading(
+    tag: string, padChar: string, attrs: Attributes|string = {},
+    children: HTMLElement[] = []) {
+  const {textContent, attribs} = separateTextContentFromAttributes(attrs);
+  return createElem(tag, attribs, [
+    createHidden('\n\n'),
+    createElem('span', textContent),
+    createHidden(`\n${''.padEnd(textContent.length, padChar)}`),
+    ...children,
+  ]);
+}
+
+/**
+ * Creates a link pair with an anchor tag that is visible
+ * in the page and hidden text for copying so the copy
+ * will appear as (href)
+ */
+function createLinkPair(textContent: string, href: string) {
+  return [
+    createElem('a', {
+      className: 'hide-on-copy',
+      textContent,
+      href,
+    }),
+    createHidden(`(${href})`),
+  ];
+}
+
+/**
+ * Adds hidden spans to an existing heading. Used when the text is
+ * copied to make the heading appear like markdown
+ */
+function addMarkdownHeading(padChar: string) {
+  return function(el: Element) {
+    el.appendChild(
+        createHidden(`\n${''.padEnd(el.textContent!.length, padChar)}`));
+  };
+}
+
+/**
+ * Get a string data value
+ */
+function getDataValue(data: Data|ArrayData): string {
+  return Array.isArray(data.value) ?
+      data.value.map(data => getDataValue(data)).join(',') :
+      data.value;
+}
+
+/**
+ * Go through Datas and find ones that start with 'GPUx'
+ * return the first with who's value ends itn '*ACTIVE*'
+ * or else the first one.
+ * @param data
+ * @returns
+ */
+function getActiveGPU(data: Data[]|ArrayData[]) {
+  // get list of GPUs
+  const gpus =
+      [...data].filter(({description}) => /^GPU\d+$/.test(description));
+  // get list of active GPUs
+  const active = gpus.filter(data => getDataValue(data).endsWith('*ACTIVE*'));
+  const all = [...active, ...gpus];
+  // get the first one
+  if (all.length > 0) {
+    const gpu = getDataValue(all[0]!);
+    const parts = gpu.split(', ')[0]!.split('=');
+    return parts.length === 2 && parts[0]! === 'VENDOR' ? parseInt(parts[1]!) :
+                                                          0;
+  }
+  return 0;
+}
+
+/** convert a value to a string or empty string if null or undefined */
+function safeString(value: any) {
+  return typeof value === 'undefined' || value === null ? '' : value.toString();
+}
+
 /**
  * @fileoverview This view displays information on the current GPU
  * hardware.  Its primary usefulness is to allow users to copy-paste
  * their data in an easy to read format for bug reports.
  */
 export class InfoViewElement extends CustomElement {
+  browserBridge?: BrowserBridge;
+
   static override get template() {
     return getTemplate();
   }
@@ -48,34 +340,132 @@
     this.refresh(browserBridge);
   }
 
+  /**
+   * public interface for testing
+   */
+  getInfo(category: string, feature: string = ''): string|string[] {
+    const gpuInfo = this.browserBridge?.gpuInfo;
+    if (!gpuInfo) {
+      throw new Error('no gpuInfo');
+    }
+
+    switch (category) {
+      case 'feature-status-for-hardware-gpu-list':
+        return safeString(
+            gpuInfo.featureStatusForHardwareGpu?.featureStatus[feature]);
+      case 'feature-status-list':
+        return safeString(gpuInfo.featureStatus?.featureStatus[feature]);
+      case 'active-gpu-for-hardware':
+        return safeString(getActiveGPU(gpuInfo.basicInfoForHardwareGpu));
+      case 'active-gpu':
+        return safeString(getActiveGPU(gpuInfo.basicInfo));
+      case 'workarounds':
+        return (gpuInfo.featureStatus || gpuInfo.featureStatusForHardwareGpu)
+                   ?.workarounds ||
+            [];
+      default:
+        throw new Error(`unknown category: ${category}`);
+    }
+  }
+
+  getSelectionText(all: boolean) {
+    const dynamicStyle = this.getRequiredElement('#dynamic-style')!;
+    dynamicStyle.textContent = `
+      #content { white-space: pre !important; }
+      .copy { display: initial; }
+      .hide-on-copy { display: none; }
+    `;
+    const contentDiv = this.getRequiredElement('#content')!;
+
+    // document.getSelection doesn't work through shadowDom
+    // and shadowRoot getSelection is non-standard chromium
+    const shadowDoc = this.shadowRoot! as unknown as Document;
+    const selection = shadowDoc.getSelection()!;
+
+    if (all) {
+      selection.removeAllRanges();
+      selection.selectAllChildren(contentDiv);
+    } else {
+      const position =
+          selection.anchorNode?.compareDocumentPosition(selection.focusNode!);
+      const [startNode, startOffset, endNode, endOffset] =
+          ((position || 0) & Node.DOCUMENT_POSITION_FOLLOWING) ?
+          [
+            selection.anchorNode!,
+            selection.anchorOffset,
+            selection.focusNode!,
+            selection.focusOffset,
+          ] :
+          [
+            selection.focusNode!,
+            selection.focusOffset,
+            selection.anchorNode!,
+            selection.anchorOffset,
+          ];
+      if (startOffset === 0) {
+        // Given the selection between > and <
+        //
+        //   * >abc
+        //   * def<
+        //
+        // We need to move the start of the selection back to the parent
+        // otherwise the selection above will copied as
+        //
+        //   abc
+        //   * def
+        //
+        // since the * (the list item's bullet) is not selectable directly.
+        const li = startNode.parentElement?.closest('li');
+        selection.setBaseAndExtent(
+            li || startNode.parentNode!, 0, endNode, endOffset);
+      }
+    }
+
+    // Get text and remove superfluous lines and whitespace.
+    const text = selection.toString()
+                     .replace(/\s*\n\s*\n\s*\n+/g, '\n\n')
+                     .replace(/\t/g, ' ')
+                     .trim();
+
+    if (all) {
+      shadowDoc.getSelection()?.removeAllRanges();
+    }
+
+    dynamicStyle.textContent = '';
+    return text;
+  }
+
+
   connectedCallback() {
     // Add handler to 'download report to clipboard' button
-    const downloadButton =
-        this.shadowRoot!.querySelector<HTMLElement>('#download-to-file')!;
+    const downloadButton = this.getRequiredElement('#download-to-file');
     assert(downloadButton);
     downloadButton.onclick = (() => {
-      // Make sure nothing is selected
-      const s = window.getSelection()!;
-      s.removeAllRanges();
-
-      // Select everything
-      s.selectAllChildren(this.shadowRoot!);
-      const text = s.toString();
-
-      // And deselect everything at the end.
-      window.getSelection()!.removeAllRanges();
-
+      const text = this.getSelectionText(true);
       const blob = new Blob([text], {type: 'text/text'});
       const filename = `about-gpu-${
           new Date().toISOString().replace(/[^a-z0-9-]/ig, '-')}.txt`;
       saveData(blob, filename);
     });
+
+    // Add a copy handler to massage the text for plain text.
+    document.addEventListener('copy', (event) => {
+      const text = this.getSelectionText(false);
+      event!.clipboardData!.setData('text/plain', text);
+      event.preventDefault();
+    });
+
+    this.shadowRoot!.querySelectorAll('h1, h2, h3')
+        .forEach(addMarkdownHeading('='));
+    this.shadowRoot!.querySelectorAll('h4, h5, h6')
+        .forEach(addMarkdownHeading('-'));
   }
 
   /**
    * Updates the view based on its currently known data
    */
   refresh(browserBridge: BrowserBridge) {
+    this.browserBridge = browserBridge;
     let clientInfo: ClientInfo;
     function createSourcePermalink(
         revisionIdentifier: string, filepath: string): string {
@@ -134,6 +524,8 @@
     const dawnInfoDiv = this.getRequiredElement('.dawn-info-div');
     const dawnInfoList = this.getRequiredElement('.dawn-info-list');
 
+
+
     const basicInfoForHardwareGpuDiv =
         this.getRequiredElement('.basic-info-for-hardware-gpu-div');
     const featureStatusForHardwareGpuDiv =
@@ -173,12 +565,8 @@
             featureStatusForHardwareGpuList, problemsForHardwareGpuDiv,
             problemsForHardwareGpuList, workaroundsForHardwareGpuDiv,
             workaroundsForHardwareGpuList);
-        if (gpuInfo.basicInfoForHardwareGpu) {
-          this.setTable_(
-              'basic-info-for-hardware-gpu', gpuInfo.basicInfoForHardwareGpu);
-        } else {
-          this.setTable_('basic-info-for-hardware-gpu', []);
-        }
+        this.setTable_(
+            'basic-info-for-hardware-gpu', gpuInfo.basicInfoForHardwareGpu);
       } else {
         basicInfoForHardwareGpuDiv.hidden = true;
         featureStatusForHardwareGpuDiv.hidden = true;
@@ -186,44 +574,19 @@
         workaroundsForHardwareGpuDiv.hidden = true;
       }
 
-      if (gpuInfo.basicInfo) {
-        this.setTable_('basic-info', gpuInfo.basicInfo);
-      } else {
-        this.setTable_('basic-info', []);
-      }
-
-      if (gpuInfo.compositorInfo) {
-        this.setTable_('compositor-info', gpuInfo.compositorInfo);
-      } else {
-        this.setTable_('compositor-info', []);
-      }
-
-      if (gpuInfo.gpuMemoryBufferInfo) {
-        this.setTable_('gpu-memory-buffer-info', gpuInfo.gpuMemoryBufferInfo);
-      } else {
-        this.setTable_('gpu-memory-buffer-info', []);
-      }
-
-      if (gpuInfo.displayInfo) {
-        this.setTable_('display-info', gpuInfo.displayInfo);
-      } else {
-        this.setTable_('display-info', []);
-      }
-
-      if (gpuInfo.videoAcceleratorsInfo) {
-        this.setTable_(
-            'video-acceleration-info', gpuInfo.videoAcceleratorsInfo);
-      } else {
-        this.setTable_('video-acceleration-info', []);
-      }
+      this.setTable_('basic-info', gpuInfo.basicInfo);
+      this.setTable_('compositor-info', gpuInfo.compositorInfo);
+      this.setTable_('gpu-memory-buffer-info', gpuInfo.gpuMemoryBufferInfo);
+      this.setTable_('display-info', gpuInfo.displayInfo);
+      this.setTable_('video-acceleration-info', gpuInfo.videoAcceleratorsInfo);
 
       if (gpuInfo.ANGLEFeatures) {
         if (gpuInfo.ANGLEFeatures.length) {
           angleFeaturesDiv.hidden = false;
           angleFeaturesList.textContent = '';
           for (const angleFeature of gpuInfo.ANGLEFeatures) {
-            const angleFeatureEl = this.createAngleFeatureEl_(angleFeature);
-            angleFeaturesList.appendChild(angleFeatureEl);
+            angleFeaturesList.appendChild(
+                this.createAngleFeatureEl_(angleFeature));
           }
         } else {
           angleFeaturesDiv.hidden = true;
@@ -253,23 +616,16 @@
         diagnosticsDiv.hidden = true;
       }
 
-      if (gpuInfo.vulkanInfo) {
-        const vulkanInfo = new VulkanInfo(gpuInfo.vulkanInfo);
-        const data = [{
-          'description': 'info',
-          'value': vulkanInfo.toString(),
-          'id': 'vulkan-info-value',
-        }];
-        this.setTable_('vulkan-info', data);
-      } else {
-        this.setTable_('vulkan-info', []);
-      }
+      this.setTable_(
+          'vulkan-info',
+          gpuInfo.vulkanInfo ? [{
+            'description': 'info',
+            'value': new VulkanInfo(gpuInfo.vulkanInfo).toString(),
+            'id': 'vulkan-info-value',
+          }] :
+                               []);
 
-      if (gpuInfo.devicePerfInfo) {
-        this.setTable_('device-perf-info', gpuInfo.devicePerfInfo);
-      } else {
-        this.setTable_('device-perf-info', []);
-      }
+      this.setTable_('device-perf-info', gpuInfo.devicePerfInfo);
     } else {
       this.setText_('basic-info', '... loading ...');
       diagnosticsDiv.hidden = true;
@@ -282,11 +638,8 @@
     const messageList = this.getRequiredElement('#log-messages > ul');
     messageList.innerHTML = window.trustedTypes!.emptyHTML;
     browserBridge.logMessages.forEach(messageObj => {
-      const messageEl = document.createElement('span');
-      messageEl.textContent = `${messageObj.header}: ${messageObj.message}`;
-      const li = document.createElement('li');
-      li.appendChild(messageEl);
-      messageList.appendChild(li);
+      messageList.appendChild(
+          createElem('li', `${messageObj.header}: ${messageObj.message}`));
     });
   }
 
@@ -333,7 +686,10 @@
         'class': 'feature-yellow',
       },
       'unavailable_off': {'label': 'Unavailable', 'class': 'feature-red'},
-      'unavailable_off_ok': {'label': 'Unavailable', 'class': 'feature-yellow'},
+      'unavailable_off_ok': {
+        'label': 'Unavailable',
+        'class': 'feature-yellow',
+      },
       'enabled_readback': {
         'label': 'Hardware accelerated but at reduced performance',
         'class': 'feature-yellow',
@@ -351,28 +707,32 @@
     featureStatusList.textContent = '';
     for (const featureName in featureInfo.featureStatus) {
       const featureStatus = featureInfo.featureStatus[featureName]!;
-      const featureEl = document.createElement('li');
 
-      const nameEl = document.createElement('span');
-      if (!featureLabelMap[featureName]) {
+      const label = featureLabelMap[featureName];
+      if (!label) {
         console.info('Missing featureLabel for', featureName);
       }
-      nameEl.textContent = featureLabelMap[featureName] + ': ';
-      featureEl.appendChild(nameEl);
 
-      const statusEl = document.createElement('span');
       const statusInfo = statusMap[featureStatus];
       if (!statusInfo) {
         console.info('Missing status for ', featureStatus);
-        statusEl.textContent = 'Unknown';
-        statusEl.className = 'feature-red';
-      } else {
-        statusEl.textContent = statusInfo['label'];
-        statusEl.className = statusInfo['class'];
       }
-      featureEl.appendChild(statusEl);
 
-      featureStatusList.appendChild(featureEl);
+      featureStatusList.appendChild(createLi({}, [
+        createElem('span', `${label}: `),
+
+        createElem(
+            'span',
+            statusInfo ? {
+              textContent: statusInfo['label'],
+              className: statusInfo['class'],
+            } :
+                         {
+                           textContent: 'Unknown',
+                           className: 'feature-red',
+                         },
+            ),
+      ]));
     }
 
     // problems list
@@ -380,8 +740,7 @@
       problemsDiv.hidden = false;
       problemsList.textContent = '';
       for (const problem of featureInfo.problems) {
-        const problemEl = this.createProblemEl_(problem);
-        problemsList.appendChild(problemEl);
+        problemsList.appendChild(this.createProblemEl_(problem));
       }
     } else {
       problemsDiv.hidden = true;
@@ -392,9 +751,7 @@
       workaroundsDiv.hidden = false;
       workaroundsList.textContent = '';
       for (const workaround of featureInfo.workarounds) {
-        const workaroundEl = document.createElement('li');
-        workaroundEl.textContent = workaround;
-        workaroundsList.appendChild(workaroundEl);
+        workaroundsList.appendChild(createLi(workaround));
       }
     } else {
       workaroundsDiv.hidden = true;
@@ -402,189 +759,134 @@
   }
 
   private createProblemEl_(problem: Problem): HTMLElement {
-    const problemEl = document.createElement('li');
+    const {text, url} = getProblemTextAndUrl(problem);
+    return createLi({}, [
+      createElem('span', text),
 
-    // Description of issue
-    const desc = document.createElement('a');
-    let text = problem.description;
-    const pattern = ' Please update your graphics driver via this link: ';
-    const pos = text.search(pattern);
-    let url = '';
-    if (pos > 0) {
-      url = text.substring(pos + pattern.length);
-      text = text.substring(0, pos);
-    }
-    desc.textContent = text;
-    problemEl.appendChild(desc);
+      // add bug separator
+      ...addIf(
+          problem.crBugs.length > 0, () => [createElem('span', ':\n    ')]),
 
-    // Spacing ':' element
-    if (problem.crBugs.length > 0) {
-      const tmp = document.createElement('span');
-      tmp.textContent = ': ';
-      problemEl.appendChild(tmp);
-    }
+      // add bugs
+      ...separateByCommas(problem.crBugs.map((id) => {
+        const bugId = parseInt(id);
+        const href = `http://crbug.com/${bugId}`;
+        return createElem('span', {}, createLinkPair(bugId.toString(), href));
+      })),
 
-    let nbugs = 0;
-    let j;
+      // add affectedGpuSettings
+      ...addIf(
+          problem.affectedGpuSettings.length > 0,
+          () =>
+              [createElem('br'),
+               createHidden('    '),
+               createElem(
+                   'i', {},
+                   [
+                     createElem(
+                         'span',
+                         problem.tag === 'disabledFeatures' ?
+                             'Disabled Features: ' :
+                             'Applied Workarounds: '),
+                     ...separateByCommas(
+                         problem.affectedGpuSettings.map(
+                             (textContent) => createElem('span', {
+                               textContent,
+                               className: problem.tag === 'disabledFeatures' ?
+                                   'feature-red' :
+                                   'feature-yellow',
+                             }),
+                             ),
+                         ',\n        '),
+                   ]),
+    ]),
 
-    // crBugs
-    for (j = 0; j < problem.crBugs.length; ++j) {
-      if (nbugs > 0) {
-        const tmp = document.createElement('span');
-        tmp.textContent = ', ';
-        problemEl.appendChild(tmp);
-      }
+      // add driver update link
+      ...addIf(
+          !!url,
+          () =>
+              [createElem('br'),
+               createHidden('    '),
+               createElem(
+                   'b', {className: 'bg-yellow'},
+                   [
+                     createElem(
+                         'span', 'Please update your graphics drive via '),
+                     createElem('a', {textContent: 'this link', href: url}),
+                   ]),
+    ]),
 
-      const link = document.createElement('a');
-      const bugid = parseInt(problem.crBugs[j]!);
-      link.textContent = bugid.toString();
-      link.href = 'http://crbug.com/' + bugid;
-      problemEl.appendChild(link);
-      nbugs++;
-    }
+      // for copy spacing
+      createElem('span', '\n\n'),
 
-    if (problem.affectedGpuSettings.length > 0) {
-      const brNode = document.createElement('br');
-      problemEl.appendChild(brNode);
-
-      const iNode = document.createElement('i');
-      problemEl.appendChild(iNode);
-
-      const headNode = document.createElement('span');
-      if (problem.tag === 'disabledFeatures') {
-        headNode.textContent = 'Disabled Features: ';
-      } else {  // problem.tag === 'workarounds'
-        headNode.textContent = 'Applied Workarounds: ';
-      }
-      iNode.appendChild(headNode);
-      for (j = 0; j < problem.affectedGpuSettings.length; ++j) {
-        if (j > 0) {
-          const separateNode = document.createElement('span');
-          separateNode.textContent = ', ';
-          iNode.appendChild(separateNode);
-        }
-        const nameNode = document.createElement('span');
-        if (problem.tag === 'disabledFeatures') {
-          nameNode.classList.add('feature-red');
-        } else {  // problem.tag === 'workarounds'
-          nameNode.classList.add('feature-yellow');
-        }
-        nameNode.textContent = problem.affectedGpuSettings[j]!;
-        iNode.appendChild(nameNode);
-      }
-    }
-
-    // Append driver update link.
-    if (pos > 0) {
-      const brNode = document.createElement('br');
-      problemEl.appendChild(brNode);
-
-      const bNode = document.createElement('b');
-      bNode.classList.add('bg-yellow');
-      problemEl.appendChild(bNode);
-
-      const tmp = document.createElement('span');
-      tmp.textContent = 'Please update your graphics driver via ';
-      bNode.appendChild(tmp);
-
-      const link = document.createElement('a');
-      link.textContent = 'this link';
-      link.href = url;
-      bNode.appendChild(link);
-    }
-
-    return problemEl;
+    ]);
   }
 
   private createAngleFeatureEl_(angleFeature: AngleFeature) {
-    const angleFeatureEl = document.createElement('li');
+    return createLi({}, [
+      // Name comes first, bolded
+      createElem('b', angleFeature.name),
 
-    // Name comes first, bolded
-    const name = document.createElement('b');
-    name.textContent = angleFeature.name;
-    angleFeatureEl.appendChild(name);
+      // If there's a category, it follows the name in parentheses
+      ...addIf(
+          !!angleFeature.category,
+          () =>
+              [createElem('span', ` (${angleFeature.category})`),
+    ]),
 
-    // If there's a category, it follows the name in parentheses
-    if (angleFeature.category) {
-      const separator = document.createElement('span');
-      separator.textContent = ' ';
-      angleFeatureEl.appendChild(separator);
+      // If there's a bug link, try to parse the crbug/anglebug number
+      ...addIf(
+          !!angleFeature.bug,
+          () =>
+              [createElem('span', ' '),
+               ...createLinkPair(
+                   formatANGLEBug(angleFeature.bug), angleFeature.bug),
+    ]),
 
-      const category = document.createElement('span');
-      category.textContent = '(' + angleFeature.category + ')';
-      angleFeatureEl.appendChild(category);
-    }
+      // Follow with a colon, and the status (colored)
+      createElem('span', ': '),
+      createElem(
+          'span',
+          angleFeature.status === 'enabled' ?
+              {className: 'feature-green', textContent: 'Enabled'} :
+              {className: 'feature-red', textContent: 'Disabled'}),
 
-    // If there's a bug link, try to parse the crbug/anglebug number
-    if (angleFeature.bug) {
-      const separator = document.createElement('span');
-      separator.textContent = ' ';
-      angleFeatureEl.appendChild(separator);
+      ...addIf(
+          !!angleFeature.condition,
+          () =>
+              [createHidden('\n    condition'),
+               createElem('span', {
+                 className: 'feature-gray',
+                 textContent: `: ${angleFeature.condition}`,
+               }),
+    ]),
 
-      const bug = document.createElement('a');
-      if (angleFeature.bug.includes('crbug.com/')) {
-        bug.textContent = angleFeature.bug.match(/\d+/)!.toString();
-      } else if (angleFeature.bug.includes('anglebug.com/')) {
-        bug.textContent = 'anglebug:' + angleFeature.bug.match(/\d+/);
-      } else {
-        bug.textContent = angleFeature.bug;
-      }
-      bug.href = angleFeature.bug;
-      angleFeatureEl.appendChild(bug);
-    }
+      ...addIf(
+          !!angleFeature.description,
+          () =>
+              [createElem('br'),
+               createElem('i', wordWrap(angleFeature.description!)),
+    ]),
 
-    // Follow with a colon, and the status (colored)
-    const separator = document.createElement('span');
-    separator.textContent = ': ';
-    angleFeatureEl.appendChild(separator);
-
-    const status = document.createElement('span');
-    if (angleFeature.status === 'enabled') {
-      status.textContent = 'Enabled';
-      status.classList.add('feature-green');
-    } else {
-      status.textContent = 'Disabled';
-      status.classList.add('feature-red');
-    }
-    angleFeatureEl.appendChild(status);
-
-    if (angleFeature.condition) {
-      const condition = document.createElement('span');
-      condition.textContent = ': ' + angleFeature.condition;
-      condition.classList.add('feature-gray');
-      angleFeatureEl.appendChild(condition);
-    }
-
-    // if there's a description, put on new line, italicized
-    if (angleFeature.description) {
-      const brNode = document.createElement('br');
-      angleFeatureEl.appendChild(brNode);
-
-      const iNode = document.createElement('i');
-      angleFeatureEl.appendChild(iNode);
-
-      const description = document.createElement('span');
-      description.textContent = angleFeature.description;
-      iNode.appendChild(description);
-    }
-
-    return angleFeatureEl;
+      // for copy spacing
+      createElem('span', '\n\n'),
+    ]);
   }
 
   private setText_(outputElementId: string, text: string) {
     this.getRequiredElement(`#${outputElementId}`).textContent = text;
   }
 
-  private setTable_(outputElementId: string, inputData: Data[]|ArrayData[]) {
-    const table = document.createElement('info-view-table');
-    table.setData(inputData);
+  private setTable_(
+      outputElementId: string, inputData: Data[]|ArrayData[]|undefined) {
+    const table = createInfoTable(inputData || []);
 
     const peg = this.$(`#${outputElementId}`);
     if (!peg) {
       throw new Error('Node ' + outputElementId + ' not found');
     }
 
-    peg.innerHTML = window.trustedTypes!.emptyHTML;
+    peg.textContent = '';
     peg.appendChild(table);
   }
 
@@ -593,26 +895,23 @@
     let inProcessingToggles = false;
 
     for (let i = 0; i < gpuDawnInfo.length; ++i) {
-      let infoString = gpuDawnInfo[i]!;
+      const infoString = gpuDawnInfo[i]!;
       let infoEl: HTMLElement;
 
       if (infoString.startsWith('<')) {
         // GPU type and backend type.
         // Add an empty line for the next adaptor.
-        const separator = document.createElement('br');
-        separator.textContent = '';
-        dawnInfoList.appendChild(separator);
+        dawnInfoList.appendChild(createElem('br'));
 
         // e.g. <Discrete GPU> D3D12 backend
-        infoEl = document.createElement('h3');
-        infoEl.textContent = infoString;
-        dawnInfoList.appendChild(infoEl);
+        infoEl = createHeading('h3', '-', infoString);
         inProcessingToggles = false;
       } else if (infoString.startsWith('[')) {
         // e.g. [Default Toggle Names]
-        infoEl = document.createElement('h4');
-        infoEl.classList.add('dawn-info-header');
-        infoEl.textContent = infoString;
+        infoEl = createHeading('h4', '-', {
+          className: 'dawn-info-header',
+          textContent: infoString,
+        });
 
         if (infoString === '[WebGPU Status]' ||
             infoString === '[Default Supported Features]') {
@@ -622,29 +921,22 @@
         }
       } else if (inProcessingToggles) {
         // Each toggle takes 3 strings
-        infoEl = document.createElement('li');
+        infoEl = createLi({}, [
+          // The toggle name comes first, bolded.
+          createElem('b', `${infoString}: \n    `),
 
-        // The toggle name comes first, bolded.
-        const name = document.createElement('b');
-        name.textContent = infoString + ':  ';
-        infoEl.appendChild(name);
+          // URL
+          ...createLinkPair(gpuDawnInfo[++i]!, gpuDawnInfo[i]!),
 
-        // URL
-        infoString = gpuDawnInfo[++i]!;
-        const url = document.createElement('a');
-        url.textContent = infoString;
-        url.href = infoString;
-        infoEl.appendChild(url);
+          // Description, italicized
+          createElem('i', `:\n${wordWrap(gpuDawnInfo[++i]!)}`),
 
-        // Description, italicized
-        infoString = gpuDawnInfo[++i]!;
-        const description = document.createElement('i');
-        description.textContent = ':  ' + infoString;
-        infoEl.appendChild(description);
+          // for copy spacing
+          createElem('span', '\n\n'),
+        ]);
       } else {
         // Display supported extensions
-        infoEl = document.createElement('li');
-        infoEl.textContent = infoString;
+        infoEl = createLi(infoString);
       }
 
       dawnInfoList.appendChild(infoEl);
diff --git a/content/browser/resources/gpu/info_view_table.html b/content/browser/resources/gpu/info_view_table.html
deleted file mode 100644
index a29cbd35..0000000
--- a/content/browser/resources/gpu/info_view_table.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<style>
-  :host {
-    display: flex;
-    cursor: auto;
-    width: 100%;
-  }
-
-  div {
-    width: 100%;
-  }
-</style>
-<div id="info-view-table"></div>
diff --git a/content/browser/resources/gpu/info_view_table.ts b/content/browser/resources/gpu/info_view_table.ts
deleted file mode 100644
index fa098cc..0000000
--- a/content/browser/resources/gpu/info_view_table.ts
+++ /dev/null
@@ -1,32 +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.
-
-import './info_view_table_row.js';
-
-import {CustomElement} from 'chrome://resources/js/custom_element.js';
-
-import {getTemplate} from './info_view_table.html.js';
-import {ArrayData, Data} from './info_view_table_row.js';
-
-export class InfoViewTableElement extends CustomElement {
-  static override get template() {
-    return getTemplate();
-  }
-
-  setData(dataArray: Data[]|ArrayData[]) {
-    dataArray.forEach(data => {
-      const row = document.createElement('info-view-table-row');
-      row.setData(data);
-      this.shadowRoot!.querySelector('#info-view-table')!.appendChild(row);
-    });
-  }
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'info-view-table': InfoViewTableElement;
-  }
-}
-
-customElements.define('info-view-table', InfoViewTableElement);
diff --git a/content/browser/resources/gpu/info_view_table_row.html b/content/browser/resources/gpu/info_view_table_row.html
deleted file mode 100644
index 4fd6046..0000000
--- a/content/browser/resources/gpu/info_view_table_row.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<style>
-  :host {
-    border: none;
-    display: flex;
-  }
-
-  #array {
-    width: 100%;
-  }
-
-  #title {
-    overflow-x: auto;
-    width: 25%;
-  }
-
-  #value {
-    overflow-x: auto;
-    width: 75%;
-  }
-
-  :host(:not([is-array])) #array {
-    display: none;
-  }
-
-  :host([is-array]) #title,
-  :host([is-array]) #value {
-    display: none;
-  }
-
-  div {
-    border: 1px solid #777;
-    margin-inline-end: -1px;
-    margin-top: -1px;
-  }
-
-  .row-title {
-    font-weight: bold;
-  }
-</style>
-<div id="title">
-  <span class="row-title">title</span>
-</div>
-<div id="value">
-  <span>value</span>
-</div>
-<div id="array">
-  <span class="row-title"></span>
-</div>
diff --git a/content/browser/resources/gpu/info_view_table_row.ts b/content/browser/resources/gpu/info_view_table_row.ts
deleted file mode 100644
index f36b487..0000000
--- a/content/browser/resources/gpu/info_view_table_row.ts
+++ /dev/null
@@ -1,53 +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.
-
-import {CustomElement} from 'chrome://resources/js/custom_element.js';
-
-import {getTemplate} from './info_view_table_row.html.js';
-
-export interface Data {
-  description: string;
-  id?: string;
-  value: string;
-}
-
-export interface ArrayData {
-  description: string;
-  value: Data[];
-}
-
-export class InfoViewTableRowElement extends CustomElement {
-  static override get template() {
-    return getTemplate();
-  }
-
-  setData(data: Data|ArrayData) {
-    const isArray = data.value instanceof Array;
-    this.toggleAttribute('is-array', isArray);
-    if (!isArray) {
-      this.shadowRoot!.querySelector('.row-title')!.textContent =
-          data.description;
-      this.shadowRoot!.querySelector('#value > span')!.textContent =
-          (data as Data).value;
-      this.shadowRoot!.querySelector('#value > span')!.id =
-          String((data as Data).id);
-    } else {
-      const array = this.shadowRoot!.querySelector('#array')!;
-      array.querySelector('span')!.textContent = data.description;
-      (data as ArrayData).value.forEach(value => {
-        const row = document.createElement('info-view-table-row');
-        row.setData(value);
-        array.appendChild(row);
-      });
-    }
-  }
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'info-view-table-row': InfoViewTableRowElement;
-  }
-}
-
-customElements.define('info-view-table-row', InfoViewTableRowElement);
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 8caacbd..b03b3b2 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -6123,6 +6123,113 @@
   EXPECT_EQ(1, GetRequestCount(relative_url));
 }
 
+class ServiceWorkerAutoPreloadBrowserTest
+    : public ServiceWorkerRaceNetworkRequestBrowserTest {
+ public:
+  ServiceWorkerAutoPreloadBrowserTest() {
+    feature_list_.InitWithFeatures(
+        {kServiceWorkerAutoPreload},
+        {features::kServiceWorkerBypassFetchHandler});
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerAutoPreloadBrowserTest,
+                       NetworkRequestRepliedFirstButFetchHandlerResultIsUsed) {
+  // Register the ServiceWorker and navigate to the in scope URL.
+  SetupAndRegisterServiceWorker();
+  const std::string relative_url =
+      "/service_worker/mock_response?sw_slow&sw_respond";
+  const GURL test_url = embedded_test_server()->GetURL(relative_url);
+  NavigationHandleObserver observer(web_contents(), test_url);
+  WorkerRunningStatusObserver service_worker_running_status_observer(
+      public_context());
+  NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+  EXPECT_TRUE(observer.has_committed());
+  service_worker_running_status_observer.WaitUntilRunning();
+
+  // ServiceWorker will respond after the delay, so we expect the network
+  // request initiated by the RaceNetworkRequest is requested to the server
+  // although it's not actually used.
+  while (GetRequestCount(relative_url) != 1) {
+    base::RunLoop().RunUntilIdle();
+  }
+  EXPECT_EQ(1, GetRequestCount(relative_url));
+
+  // Unlike RaceNetworkRequest, AutoPreload always waits for the response is
+  // from the fetch handler.
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the fetch handler",
+            GetInnerText());
+
+  // Check the response header. "X-Response-From: fetch-handler" is returned
+  // when the result from the fetch handler is used.
+  EXPECT_EQ("fetch-handler",
+            observer.GetNormalizedResponseHeader("X-Response-From"));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerAutoPreloadBrowserTest, PassThrough) {
+  // Register the ServiceWorker and navigate to the in scope URL.
+  SetupAndRegisterServiceWorker();
+  // Capture the response head.
+  const std::string relative_url =
+      "/service_worker/mock_response?sw_pass_through";
+  const GURL test_url = embedded_test_server()->GetURL(relative_url);
+
+  WorkerRunningStatusObserver service_worker_running_status_observer(
+      public_context());
+  NavigationHandleObserver observer(web_contents(), test_url);
+  NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+  EXPECT_TRUE(observer.has_committed());
+  service_worker_running_status_observer.WaitUntilRunning();
+
+  // Request count should be 1. RaceNetworkRequest + pass through request from
+  // fetch handler but the fetch handler request will reuse the response from
+  // RaceNetworkRequest.
+  while (GetRequestCount(relative_url) != 1) {
+    base::RunLoop().RunUntilIdle();
+  }
+  EXPECT_EQ(1, GetRequestCount(relative_url));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerAutoPreloadBrowserTest,
+                       NetworkRequest_Wins_FetchHandler_Fallback) {
+  // Register the ServiceWorker and navigate to the in scope URL.
+  SetupAndRegisterServiceWorker();
+  const std::string relative_url =
+      "/service_worker/mock_response?sw_slow&sw_fallback";
+  NavigateToURLBlockUntilNavigationsComplete(
+      shell(), embedded_test_server()->GetURL(relative_url), 1);
+
+  // ServiceWorker will respond after the delay, so we expect the network
+  // request initiated by the RaceNetworkRequest responds first, then get a
+  // fallback result from the fetch handler. In that case AutoPreload doesn't
+  // send another network request for the fallback, but reuses the
+  // RaceNetworkRequest.
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the network",
+            GetInnerText());
+  EXPECT_EQ(1, GetRequestCount(relative_url));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerAutoPreloadBrowserTest,
+                       FetchHandler_Wins_Fallback) {
+  // Register the ServiceWorker and navigate to the in scope URL.
+  SetupAndRegisterServiceWorker();
+  const std::string relative_url =
+      "/service_worker/mock_response?server_slow&sw_fallback";
+  NavigateToURLBlockUntilNavigationsComplete(
+      shell(), embedded_test_server()->GetURL(relative_url), 1);
+
+  // Server will respond after the delay, so we expect the fetch handler
+  // responds first and the result is fallback. In that case AutoPreload doesn't
+  // send another network request for the fallback, but reuses the
+  // RaceNetworkRequest.
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Slow response from the network",
+            GetInnerText());
+  EXPECT_EQ(1, GetRequestCount(relative_url));
+}
+
 class ServiceWorkerRaceNetworkRequestOriginTrialBrowserTest
     : public ServiceWorkerRaceNetworkRequestBrowserTest {
  public:
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 0d1a5e08..f910fae 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -300,9 +300,11 @@
 
   ClearRunningServiceWorkers();
   storage_partition_ = nullptr;
-  process_manager_->Shutdown();
   storage_control_.reset();
   context_core_.reset();
+  // Shutdown the `process_manager_` at the end so that the steps above can have
+  // a valid browser context pointer through `process_manager_`.
+  process_manager_->Shutdown();
 }
 
 void ServiceWorkerContextWrapper::DeleteAndStartOver() {
diff --git a/content/browser/service_worker/service_worker_hid_delegate_observer_unittest.cc b/content/browser/service_worker/service_worker_hid_delegate_observer_unittest.cc
index a0c5d969..80b0c490 100644
--- a/content/browser/service_worker/service_worker_hid_delegate_observer_unittest.cc
+++ b/content/browser/service_worker/service_worker_hid_delegate_observer_unittest.cc
@@ -164,6 +164,7 @@
 
   void SetUp() override {
     ServiceWorkerDeviceDelegateObserverTest::SetUp();
+    hid_delegate().SetAssertBrowserContext(true);
     ON_CALL(hid_delegate(), GetHidManager).WillByDefault(Return(&hid_manager_));
     ON_CALL(hid_delegate(), IsFidoAllowedForOrigin)
         .WillByDefault(Return(false));
@@ -916,4 +917,22 @@
       context()->hid_delegate_observer()->registration_id_map().empty());
 }
 
+// Shutdown the service worker context and make sure that
+// ServiceWorkerHidDelegateObserver removes itself from the hid delegate
+// properly.
+TEST_F(ServiceWorkerHidDelegateObserverTest, ShutdownServiceWorkerContext) {
+  const GURL origin(kTestUrl);
+  auto registration = InstallServiceWorker(origin);
+  auto* version = registration->newest_installed_version();
+  ASSERT_NE(version, nullptr);
+  StartServiceWorker(version);
+  CreateHidService(version);
+  EXPECT_TRUE(context()->hid_delegate_observer()->GetHidServiceForTesting(
+      registration->id()));
+
+  EXPECT_FALSE(hid_delegate().observer_list().empty());
+  helper()->ShutdownContext();
+  EXPECT_TRUE(hid_delegate().observer_list().empty());
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.cc b/content/browser/service_worker/service_worker_main_resource_loader.cc
index 569e2c5d..40179971 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader.cc
@@ -343,6 +343,16 @@
     } else if (race_network_request_mode != kSkipped &&
                MaybeStartRaceNetworkRequest(context, active_worker)) {
       dispatched_preload_type_ = DispatchedPreloadType::kRaceNetworkRequest;
+    } else if (MaybeStartAutoPreload(context, active_worker)) {
+      // When the AutoPreload is triggered, set the commit responsibility
+      // because the response is always committed by the fetch handler
+      // regardless of the race result, except for the case when the fetch
+      // handler result is fallback. The fallback case is handled after
+      // receiving the fetch handler result.
+      SetCommitResponsibility(FetchResponseFrom::kServiceWorker);
+      dispatched_preload_type_ = DispatchedPreloadType::kAutoPreload;
+      active_worker->set_fetch_handler_bypass_option(
+          blink::mojom::ServiceWorkerFetchHandlerBypassOption::kAutoPreload);
     } else if (fetch_dispatcher_->MaybeStartNavigationPreload(
                    resource_request_, context, frame_tree_node_id_)) {
       dispatched_preload_type_ = DispatchedPreloadType::kNavigationPreload;
@@ -356,6 +366,16 @@
   fetch_dispatcher_->Run();
 }
 
+bool ServiceWorkerMainResourceLoader::MaybeStartAutoPreload(
+    scoped_refptr<ServiceWorkerContextWrapper> context,
+    scoped_refptr<ServiceWorkerVersion> version) {
+  if (!base::FeatureList::IsEnabled(kServiceWorkerAutoPreload)) {
+    return false;
+  }
+
+  return StartRaceNetworkRequest(context, version);
+}
+
 bool ServiceWorkerMainResourceLoader::MaybeStartRaceNetworkRequest(
     scoped_refptr<ServiceWorkerContextWrapper> context,
     scoped_refptr<ServiceWorkerVersion> version) {
@@ -504,6 +524,7 @@
     switch (commit_responsibility()) {
       case FetchResponseFrom::kNoResponseYet:
       case FetchResponseFrom::kSubresourceLoaderIsHandlingRedirect:
+      case FetchResponseFrom::kAutoPreloadHandlingFallback:
         NOTREACHED();
         break;
       case FetchResponseFrom::kServiceWorker:
@@ -549,20 +570,49 @@
       blink::ServiceWorkerStatusToString(status), "result",
       ComposeFetchEventResultString(fetch_result, *response));
 
+  // Transition the state if the fetch result is fallback. This is a special
+  // treatment for RaceNetworkRequest and AutoPreload.
+  if (fetch_result ==
+      ServiceWorkerFetchDispatcher::FetchEventResult::kShouldFallback) {
+    switch (commit_responsibility()) {
+      case FetchResponseFrom::kNoResponseYet:
+        // If the RaceNetworkRequest or AutoPreload is triggered but the
+        // response is not handled yet, ask RaceNetworkRequestURLLoaderClient to
+        // handle the response regardless of the response status not to dispatch
+        // additional network request for fallback.
+        switch (dispatched_preload_type_) {
+          case DispatchedPreloadType::kRaceNetworkRequest:
+          case DispatchedPreloadType::kAutoPreload:
+            SetCommitResponsibility(FetchResponseFrom::kWithoutServiceWorker);
+            break;
+          default:
+            break;
+        }
+        break;
+      case FetchResponseFrom::kServiceWorker:
+        switch (dispatched_preload_type_) {
+          case DispatchedPreloadType::kAutoPreload:
+            // If the AutoPreload is triggered and the response is already
+            // received, but the fetch result is fallback, set the intermediate
+            // state to let RaceNetworkRequestURLLoaderClient to commit the
+            // response.
+            SetCommitResponsibility(
+                FetchResponseFrom::kAutoPreloadHandlingFallback);
+            break;
+          default:
+            break;
+        }
+        break;
+      case FetchResponseFrom::kWithoutServiceWorker:
+        break;
+      case FetchResponseFrom::kSubresourceLoaderIsHandlingRedirect:
+      case FetchResponseFrom::kAutoPreloadHandlingFallback:
+        NOTREACHED_NORETURN();
+    }
+  }
+
   switch (commit_responsibility()) {
     case FetchResponseFrom::kNoResponseYet:
-      // If the RaceNetworkRequest is triggered but the response is not handled
-      // yet, and the fetch handler result is FetchEventResult::kShouldFallback,
-      // ask RaceNetworkRequestURLLoaderClient to handle the response regardless
-      // of the response status not to dispatch additional network request for
-      // fallback.
-      if (dispatched_preload_type_ ==
-              DispatchedPreloadType::kRaceNetworkRequest &&
-          fetch_result ==
-              ServiceWorkerFetchDispatcher::FetchEventResult::kShouldFallback) {
-        SetCommitResponsibility(FetchResponseFrom::kWithoutServiceWorker);
-        return;
-      }
       SetCommitResponsibility(FetchResponseFrom::kServiceWorker);
       break;
     case FetchResponseFrom::kServiceWorker:
@@ -577,6 +627,20 @@
             std::move(body_as_stream->stream));
       }
       return;
+    case FetchResponseFrom::kAutoPreloadHandlingFallback:
+      // |kAutoPreloadHandlingFallback| is the intermediate state to transfer
+      // the commit responsibility from the fetch handler to the network
+      // request (kServiceWorker). If the fetch handler result is fallback,
+      // manually set the network request (kWithoutServiceWorker).
+      SetCommitResponsibility(FetchResponseFrom::kWithoutServiceWorker);
+      // If the network request is faster than the fetch handler, the response
+      // from the network is processed but not committed. We have to explicitly
+      // commit and complete the response. Otherwise
+      // |ServiceWorkerRaceNetworkRequestURLLoaderClient::CommitResponse()| will
+      // be called.
+      race_network_request_url_loader_client_
+          ->CommitAndCompleteResponseIfDataTransferFinished();
+      return;
     case FetchResponseFrom::kSubresourceLoaderIsHandlingRedirect:
       NOTREACHED_NORETURN();
   }
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.h b/content/browser/service_worker/service_worker_main_resource_loader.h
index 55a06b7..a0dde1cd 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.h
+++ b/content/browser/service_worker/service_worker_main_resource_loader.h
@@ -126,10 +126,14 @@
   //    the corresponding request from the ServiceWorker.
   // kNavigationPreload:
   //    Enabled when Navigation Preload is triggered.
+  // kAutoPreload:
+  //    AutoPreload is triggered. This is consumed in the fetch handler or
+  //    the fallback request.
   enum class DispatchedPreloadType {
     kNone,
     kRaceNetworkRequest,
-    kNavigationPreload
+    kNavigationPreload,
+    kAutoPreload,
   };
 
   void DidPrepareFetchEvent(scoped_refptr<ServiceWorkerVersion> version,
@@ -239,6 +243,14 @@
       scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
       scoped_refptr<ServiceWorkerVersion> version);
 
+  // If the feature is enabled, invoke the preload network request.
+  // See this doc for the high-level code flow in
+  // ServiceWorkerMainResourceLoader.
+  // https://docs.google.com/presentation/d/13A54OUqaBPrgkIQZE3a3CnhT3pe3C70j07HCisjNZlI/edit#slide=id.g2753dd0eed3_0_0
+  bool MaybeStartAutoPreload(
+      scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
+      scoped_refptr<ServiceWorkerVersion> version);
+
   NavigationLoaderInterceptor::FallbackCallback fallback_callback_;
 
   network::ResourceRequest resource_request_;
diff --git a/content/common/service_worker/race_network_request_url_loader_client.cc b/content/common/service_worker/race_network_request_url_loader_client.cc
index a241cdf..35c3907 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.cc
+++ b/content/common/service_worker/race_network_request_url_loader_client.cc
@@ -3,11 +3,14 @@
 // found in the LICENSE file.
 
 #include "content/common/service_worker/race_network_request_url_loader_client.h"
+
+#include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/trace_event/trace_event.h"
+#include "content/common/features.h"
 #include "content/common/service_worker/service_worker_resource_loader.h"
 #include "content/public/common/content_features.h"
 #include "mojo/public/c/system/data_pipe.h"
@@ -156,6 +159,8 @@
       // fallback request.
       owner_->HandleRedirect(redirect_info, head);
       break;
+    case FetchResponseFrom::kAutoPreloadHandlingFallback:
+      NOTREACHED_NORETURN();
   }
   redirected_ = true;
 }
@@ -216,6 +221,9 @@
       // instead because it may have a response from the cache.
       // TODO(crbug.com/1420517): More comprehensive error handling may be
       // needed, especially the case when HTTP cache hit or redirect happened.
+      //
+      // When the AutoPreload is enabled, RaceNetworkRequest works just for the
+      // dedupe purpose. The fetch handler should always commit the response.
       if (head_->headers->response_code() != net::HttpStatusCode::HTTP_OK) {
         owner_->SetCommitResponsibility(FetchResponseFrom::kServiceWorker);
       } else {
@@ -226,8 +234,9 @@
       break;
     case FetchResponseFrom::kServiceWorker:
       // If commit responsibility is FetchResponseFrom::kServiceWorker, that
-      // means the response was already received from the fetch handler. The
-      // response from RaceNetworkRequest is simply discarded in that case.
+      // means the response was already received from the fetch handler, or the
+      // AutoPreload is enabled. The response from RaceNetworkRequest is
+      // consumed only for the dedupe purpose.
       break;
     case FetchResponseFrom::kWithoutServiceWorker:
       // kWithoutServiceWorker is set When the fetch handler response comes
@@ -235,6 +244,8 @@
       // response.
       CommitResponse();
       break;
+    case FetchResponseFrom::kAutoPreloadHandlingFallback:
+      NOTREACHED_NORETURN();
   }
 
   forwarding_client_->OnReceiveResponse(
@@ -260,7 +271,6 @@
   if (!owner_) {
     return;
   }
-  TransitionState(State::kCompleted);
   switch (owner_->commit_responsibility()) {
     case FetchResponseFrom::kNoResponseYet:
     case FetchResponseFrom::kSubresourceLoaderIsHandlingRedirect:
@@ -274,9 +284,12 @@
       // RaceNetworkRequest, do nothing. Defer the handling to the owner.
       break;
     case FetchResponseFrom::kWithoutServiceWorker:
+      TransitionState(State::kCompleted);
       owner_->CommitCompleted(completion_status_->error_code,
                               "RaceNetworkRequest has completed.");
       break;
+    case FetchResponseFrom::kAutoPreloadHandlingFallback:
+      NOTREACHED_NORETURN();
   }
   data_pipe_for_race_network_request_.producer.reset();
   forwarding_client_->OnComplete(completion_status_.value());
@@ -288,6 +301,14 @@
   body_consumer_watcher_.Cancel();
 }
 
+void ServiceWorkerRaceNetworkRequestURLLoaderClient::
+    CommitAndCompleteResponseIfDataTransferFinished() {
+  if (state_ == State::kDataTransferFinished) {
+    CommitResponse();
+    CompleteResponse();
+  }
+}
+
 void ServiceWorkerRaceNetworkRequestURLLoaderClient::OnDataTransferComplete() {
   MaybeCommitResponse();
   TRACE_EVENT0(
diff --git a/content/common/service_worker/race_network_request_url_loader_client.h b/content/common/service_worker/race_network_request_url_loader_client.h
index 3b19f2e..6ef1ce0 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.h
+++ b/content/common/service_worker/race_network_request_url_loader_client.h
@@ -134,6 +134,9 @@
   // pipe may be stacked. So this method provides a way to just consume data.
   void DrainData(mojo::ScopedDataPipeConsumerHandle source);
 
+  // Commit and complete the response. Those can be called from |owner_|.
+  void CommitAndCompleteResponseIfDataTransferFinished();
+
  private:
   struct DataPipeInfo {
     mojo::ScopedDataPipeProducerHandle producer;
diff --git a/content/common/service_worker/service_worker_resource_loader.cc b/content/common/service_worker/service_worker_resource_loader.cc
index 0f581af..7dc3222 100644
--- a/content/common/service_worker/service_worker_resource_loader.cc
+++ b/content/common/service_worker/service_worker_resource_loader.cc
@@ -3,7 +3,11 @@
 // found in the LICENSE file.
 
 #include "content/common/service_worker/service_worker_resource_loader.h"
+
 #include "base/check_op.h"
+#include "base/feature_list.h"
+#include "base/trace_event/trace_event.h"
+#include "content/common/features.h"
 
 namespace content {
 ServiceWorkerResourceLoader::ServiceWorkerResourceLoader() = default;
@@ -11,6 +15,11 @@
 
 void ServiceWorkerResourceLoader::SetCommitResponsibility(
     FetchResponseFrom fetch_response_from) {
+  TRACE_EVENT_WITH_FLOW2(
+      "ServiceWorker", "ServiceWorkerResourceLoader::SetCommitResponsibility",
+      this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+      "commit_responsibility_", commit_responsibility_, "fetch_response_from",
+      fetch_response_from);
   switch (fetch_response_from) {
     case FetchResponseFrom::kNoResponseYet:
       NOTREACHED_NORETURN();
@@ -19,10 +28,12 @@
       CHECK(!IsMainResourceLoader());
       CHECK(commit_responsibility_ == FetchResponseFrom::kServiceWorker ||
             commit_responsibility_ == FetchResponseFrom::kWithoutServiceWorker);
-      commit_responsibility_ = fetch_response_from;
+      break;
+    case FetchResponseFrom::kAutoPreloadHandlingFallback:
+      CHECK(base::FeatureList::IsEnabled(kServiceWorkerAutoPreload));
+      CHECK_EQ(commit_responsibility_, FetchResponseFrom::kServiceWorker);
       break;
     case FetchResponseFrom::kServiceWorker:
-    case FetchResponseFrom::kWithoutServiceWorker:
       if (IsMainResourceLoader()) {
         CHECK_EQ(commit_responsibility_, FetchResponseFrom::kNoResponseYet);
       } else {
@@ -30,9 +41,20 @@
               commit_responsibility_ ==
                   FetchResponseFrom::kSubresourceLoaderIsHandlingRedirect);
       }
-      commit_responsibility_ = fetch_response_from;
+      break;
+    case FetchResponseFrom::kWithoutServiceWorker:
+      if (IsMainResourceLoader()) {
+        CHECK(commit_responsibility_ == FetchResponseFrom::kNoResponseYet ||
+              commit_responsibility_ ==
+                  FetchResponseFrom::kAutoPreloadHandlingFallback);
+      } else {
+        CHECK(commit_responsibility_ == FetchResponseFrom::kNoResponseYet ||
+              commit_responsibility_ ==
+                  FetchResponseFrom::kSubresourceLoaderIsHandlingRedirect);
+      }
       break;
   }
+  commit_responsibility_ = fetch_response_from;
 }
 
 void ServiceWorkerResourceLoader::RecordFetchResponseFrom() {
diff --git a/content/common/service_worker/service_worker_resource_loader.h b/content/common/service_worker/service_worker_resource_loader.h
index 7b0e9b0..0ca7d3e 100644
--- a/content/common/service_worker/service_worker_resource_loader.h
+++ b/content/common/service_worker/service_worker_resource_loader.h
@@ -35,7 +35,16 @@
     // to be updated to either |kServiceWorker| or |kWithoutServiceWorker| after
     // receiving the final response.
     kSubresourceLoaderIsHandlingRedirect = 3,
-    kMaxValue = kSubresourceLoaderIsHandlingRedirect,
+    // When ServiceWorkerAutoPreload is enabled, in most cases the response from
+    // |kServiceWorker| is expected. However, when the fetch handler result is
+    // fallback, the browser tries to use the response from the network request.
+    // In this case |commit_responsibility_| is transitioned from
+    // |kServiceWorker| to |kWithoutServiceWorker|, but we don't want to permit
+    // that transition in normal cases. This state is a special intermediate
+    // state to bridge those states, which is used only to handle fallback with
+    // ServiceWorkerAutoPreload.
+    kAutoPreloadHandlingFallback = 4,
+    kMaxValue = kAutoPreloadHandlingFallback,
   };
 
   ServiceWorkerResourceLoader();
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index 5eab9616..08e729ad 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -531,6 +531,8 @@
         // If the fetch request is already handled by RaceNetworkRequest, no
         // need to call CommitCompleted here.
         return;
+      case FetchResponseFrom::kAutoPreloadHandlingFallback:
+        NOTREACHED_NORETURN();
     }
   }
   fetch_request_restarted_ = true;
@@ -630,6 +632,8 @@
       // fallback. The response from RaceNetworkRequest is currently handled by
       // the code path for the non-fallback case.
       return;
+    case FetchResponseFrom::kAutoPreloadHandlingFallback:
+      NOTREACHED_NORETURN();
   }
 
   // Hand over to the network loader.
@@ -697,6 +701,8 @@
             std::move(body_as_stream->stream));
       }
       return;
+    case FetchResponseFrom::kAutoPreloadHandlingFallback:
+      NOTREACHED_NORETURN();
   }
   RecordFetchResponseFrom();
 
@@ -842,6 +848,7 @@
     switch (commit_responsibility()) {
       case FetchResponseFrom::kNoResponseYet:
       case FetchResponseFrom::kSubresourceLoaderIsHandlingRedirect:
+      case FetchResponseFrom::kAutoPreloadHandlingFallback:
         NOTREACHED();
         break;
       case FetchResponseFrom::kServiceWorker:
diff --git a/content/services/auction_worklet/auction_v8_helper_unittest.cc b/content/services/auction_worklet/auction_v8_helper_unittest.cc
index f00fbb10..1ac107e9 100644
--- a/content/services/auction_worklet/auction_v8_helper_unittest.cc
+++ b/content/services/auction_worklet/auction_v8_helper_unittest.cc
@@ -94,7 +94,11 @@
       const absl::optional<std::string>& auction_signals_json,
       const absl::optional<std::string>& per_buyer_signals_json,
       const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_per_buyer_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       const std::string& seller_signals_json,
       mojom::KAnonymityBidMode kanon_mode,
       bool bid_is_kanon,
diff --git a/content/services/auction_worklet/bidder_worklet.cc b/content/services/auction_worklet/bidder_worklet.cc
index 0f8808e..5a2b687 100644
--- a/content/services/auction_worklet/bidder_worklet.cc
+++ b/content/services/auction_worklet/bidder_worklet.cc
@@ -99,6 +99,29 @@
   return true;
 }
 
+// Checks both types of DirectFromSellerSignals results (subresource bundle
+// based and header based) -- at most one of these should be non-null.
+//
+// Returns the V8 conversion of the in-use version of DirectFromSellerSignals,
+// or v8::Null() if both types of DirectFromSellerSignals are null.
+v8::Local<v8::Value> GetDirectFromSellerSignals(
+    const DirectFromSellerSignalsRequester::Result& subresource_bundle_result,
+    const absl::optional<std::string>& header_result,
+    AuctionV8Helper& v8_helper,
+    v8::Local<v8::Context> context,
+    std::vector<std::string>& errors) {
+  CHECK(subresource_bundle_result.IsNull() || !header_result);
+
+  if (header_result) {
+    // `header_result` JSON was validated, parsed and reconstructed into a
+    // string by the browser process, so CHECK it is valid JSON.
+    return v8_helper.CreateValueFromJson(context, *header_result)
+        .ToLocalChecked();
+  }
+
+  return subresource_bundle_result.GetSignals(v8_helper, context, errors);
+}
+
 // TODO(crbug.com/1441988): Remove this code after rename. These functions allow
 // having multiple dictionary keys (e.g. renderUrl and renderURL) share the same
 // V8 value.
@@ -445,7 +468,11 @@
     const absl::optional<std::string>& auction_signals_json,
     const absl::optional<std::string>& per_buyer_signals_json,
     const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_per_buyer_signals_header_ad_slot,
     const absl::optional<GURL>& direct_from_seller_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     const std::string& seller_signals_json,
     mojom::KAnonymityBidMode kanon_mode,
     bool bid_is_kanon,
@@ -467,6 +494,10 @@
     uint64_t trace_id,
     ReportWinCallback report_win_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
+  CHECK((!direct_from_seller_per_buyer_signals &&
+         !direct_from_seller_auction_signals) ||
+        (!direct_from_seller_per_buyer_signals_header_ad_slot &&
+         !direct_from_seller_auction_signals_header_ad_slot));
 
   report_win_tasks_.emplace_front();
   auto report_win_task = report_win_tasks_.begin();
@@ -535,6 +566,10 @@
         DirectFromSellerSignalsRequester::Result();
   }
   report_win_task->trace_wait_deps_start = base::TimeTicks::Now();
+  report_win_task->direct_from_seller_per_buyer_signals_header_ad_slot =
+      direct_from_seller_per_buyer_signals_header_ad_slot;
+  report_win_task->direct_from_seller_auction_signals_header_ad_slot =
+      direct_from_seller_auction_signals_header_ad_slot;
 
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("fledge", "wait_report_win_deps", trace_id);
   RunReportWinIfReady(report_win_task);
@@ -555,13 +590,26 @@
     const absl::optional<base::TimeDelta> per_buyer_timeout,
     const absl::optional<blink::AdCurrency>& expected_buyer_currency,
     const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
-    const absl::optional<GURL>& direct_from_seller_auction_signals) {
+    const absl::optional<std::string>&
+        direct_from_seller_per_buyer_signals_header_ad_slot,
+    const absl::optional<GURL>& direct_from_seller_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot) {
+  CHECK((!direct_from_seller_per_buyer_signals &&
+         !direct_from_seller_auction_signals) ||
+        (!direct_from_seller_per_buyer_signals_header_ad_slot &&
+         !direct_from_seller_auction_signals_header_ad_slot));
+
   GenerateBidTaskList::iterator task = finalize_receiver_set_.current_context();
   task->auction_signals_json = auction_signals_json;
   task->per_buyer_signals_json = per_buyer_signals_json;
   task->per_buyer_timeout = per_buyer_timeout;
   task->expected_buyer_currency = expected_buyer_currency;
   task->finalize_generate_bid_called = true;
+  task->direct_from_seller_per_buyer_signals_header_ad_slot =
+      direct_from_seller_per_buyer_signals_header_ad_slot;
+  task->direct_from_seller_auction_signals_header_ad_slot =
+      direct_from_seller_auction_signals_header_ad_slot;
   HandleDirectFromSellerForGenerateBid(direct_from_seller_per_buyer_signals,
                                        direct_from_seller_auction_signals,
                                        task);
@@ -658,8 +706,12 @@
     const absl::optional<std::string>& per_buyer_signals_json,
     DirectFromSellerSignalsRequester::Result
         direct_from_seller_result_per_buyer_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_per_buyer_signals_header_ad_slot,
     DirectFromSellerSignalsRequester::Result
         direct_from_seller_result_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     const std::string& seller_signals_json,
     mojom::KAnonymityBidMode kanon_mode,
     bool bid_is_kanon,
@@ -807,12 +859,14 @@
   v8::Local<v8::Object> direct_from_seller_signals = v8::Object::New(isolate);
   gin::Dictionary direct_from_seller_signals_dict(isolate,
                                                   direct_from_seller_signals);
-  v8::Local<v8::Value> per_buyer_signals =
-      direct_from_seller_result_per_buyer_signals.GetSignals(
-          *v8_helper_, context, errors_out);
-  v8::Local<v8::Value> auction_signals =
-      direct_from_seller_result_auction_signals.GetSignals(*v8_helper_, context,
-                                                           errors_out);
+  v8::Local<v8::Value> per_buyer_signals = GetDirectFromSellerSignals(
+      direct_from_seller_result_per_buyer_signals,
+      direct_from_seller_per_buyer_signals_header_ad_slot, *v8_helper_, context,
+      errors_out);
+  v8::Local<v8::Value> auction_signals = GetDirectFromSellerSignals(
+      direct_from_seller_result_auction_signals,
+      direct_from_seller_auction_signals_header_ad_slot, *v8_helper_, context,
+      errors_out);
   if (!direct_from_seller_signals_dict.Set("perBuyerSignals",
                                            per_buyer_signals) ||
       !direct_from_seller_signals_dict.Set("auctionSignals", auction_signals)) {
@@ -901,8 +955,12 @@
     const absl::optional<std::string>& per_buyer_signals_json,
     DirectFromSellerSignalsRequester::Result
         direct_from_seller_result_per_buyer_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_per_buyer_signals_header_ad_slot,
     DirectFromSellerSignalsRequester::Result
         direct_from_seller_result_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     const absl::optional<base::TimeDelta> per_buyer_timeout,
     const absl::optional<blink::AdCurrency>& expected_buyer_currency,
     const url::Origin& browser_signal_seller_origin,
@@ -928,7 +986,9 @@
       base::OptionalToPtr(auction_signals_json),
       base::OptionalToPtr(per_buyer_signals_json),
       direct_from_seller_result_per_buyer_signals,
-      direct_from_seller_result_auction_signals, per_buyer_timeout,
+      direct_from_seller_per_buyer_signals_header_ad_slot,
+      direct_from_seller_result_auction_signals,
+      direct_from_seller_auction_signals_header_ad_slot, per_buyer_timeout,
       expected_buyer_currency, browser_signal_seller_origin,
       base::OptionalToPtr(browser_signal_top_level_seller_origin),
       browser_signal_recency, bidding_browser_signals, auction_start_time,
@@ -965,8 +1025,11 @@
               base::OptionalToPtr(auction_signals_json),
               base::OptionalToPtr(per_buyer_signals_json),
               direct_from_seller_result_per_buyer_signals,
-              direct_from_seller_result_auction_signals, per_buyer_timeout,
-              expected_buyer_currency, browser_signal_seller_origin,
+              direct_from_seller_per_buyer_signals_header_ad_slot,
+              direct_from_seller_result_auction_signals,
+              direct_from_seller_auction_signals_header_ad_slot,
+              per_buyer_timeout, expected_buyer_currency,
+              browser_signal_seller_origin,
               base::OptionalToPtr(browser_signal_top_level_seller_origin),
               browser_signal_recency, bidding_browser_signals,
               auction_start_time, requested_ad_size,
@@ -1027,8 +1090,12 @@
     const std::string* per_buyer_signals_json,
     const DirectFromSellerSignalsRequester::Result&
         direct_from_seller_result_per_buyer_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_per_buyer_signals_header_ad_slot,
     const DirectFromSellerSignalsRequester::Result&
         direct_from_seller_result_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     const absl::optional<base::TimeDelta> per_buyer_timeout,
     const absl::optional<blink::AdCurrency>& expected_buyer_currency,
     const url::Origin& browser_signal_seller_origin,
@@ -1293,12 +1360,14 @@
   v8::Local<v8::Object> direct_from_seller_signals = v8::Object::New(isolate);
   gin::Dictionary direct_from_seller_signals_dict(isolate,
                                                   direct_from_seller_signals);
-  v8::Local<v8::Value> per_buyer_signals =
-      direct_from_seller_result_per_buyer_signals.GetSignals(
-          *v8_helper_, context, errors_out);
-  v8::Local<v8::Value> auction_signals =
-      direct_from_seller_result_auction_signals.GetSignals(*v8_helper_, context,
-                                                           errors_out);
+  v8::Local<v8::Value> per_buyer_signals = GetDirectFromSellerSignals(
+      direct_from_seller_result_per_buyer_signals,
+      direct_from_seller_per_buyer_signals_header_ad_slot, *v8_helper_, context,
+      errors_out);
+  v8::Local<v8::Value> auction_signals = GetDirectFromSellerSignals(
+      direct_from_seller_result_auction_signals,
+      direct_from_seller_auction_signals_header_ad_slot, *v8_helper_, context,
+      errors_out);
   if (!direct_from_seller_signals_dict.Set("perBuyerSignals",
                                            per_buyer_signals) ||
       !direct_from_seller_signals_dict.Set("auctionSignals", auction_signals)) {
@@ -1838,7 +1907,9 @@
           std::move(task->auction_signals_json),
           std::move(task->per_buyer_signals_json),
           std::move(task->direct_from_seller_result_per_buyer_signals),
+          std::move(task->direct_from_seller_per_buyer_signals_header_ad_slot),
           std::move(task->direct_from_seller_result_auction_signals),
+          std::move(task->direct_from_seller_auction_signals_header_ad_slot),
           std::move(task->per_buyer_timeout),
           std::move(task->expected_buyer_currency),
           std::move(task->browser_signal_seller_origin),
@@ -1921,7 +1992,9 @@
           std::move(task->auction_signals_json),
           std::move(task->per_buyer_signals_json),
           std::move(task->direct_from_seller_result_per_buyer_signals),
+          std::move(task->direct_from_seller_per_buyer_signals_header_ad_slot),
           std::move(task->direct_from_seller_result_auction_signals),
+          std::move(task->direct_from_seller_auction_signals_header_ad_slot),
           std::move(task->seller_signals_json), std::move(task->kanon_mode),
           std::move(task->bid_is_kanon),
           std::move(task->browser_signal_render_url),
diff --git a/content/services/auction_worklet/bidder_worklet.h b/content/services/auction_worklet/bidder_worklet.h
index ac70d60..4aa2aef 100644
--- a/content/services/auction_worklet/bidder_worklet.h
+++ b/content/services/auction_worklet/bidder_worklet.h
@@ -149,7 +149,11 @@
       const absl::optional<std::string>& auction_signals_json,
       const absl::optional<std::string>& per_buyer_signals_json,
       const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_per_buyer_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       const std::string& seller_signals_json,
       mojom::KAnonymityBidMode kanon_mode,
       bool bid_is_kanon,
@@ -181,7 +185,11 @@
       const absl::optional<base::TimeDelta> per_buyer_timeout,
       const absl::optional<blink::AdCurrency>& expected_buyer_currency,
       const absl::optional<GURL>& direct_from_seller_per_buyer_signals,
-      const absl::optional<GURL>& direct_from_seller_auction_signals) override;
+      const absl::optional<std::string>&
+          direct_from_seller_per_buyer_signals_header_ad_slot,
+      const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot) override;
 
  private:
   struct GenerateBidTask {
@@ -249,6 +257,12 @@
     // DirectFromSellerSignals errors are fatal, so no error information is
     // stored here.
 
+    // Header-based DirectFromSellerSignals.
+    absl::optional<std::string>
+        direct_from_seller_per_buyer_signals_header_ad_slot;
+    absl::optional<std::string>
+        direct_from_seller_auction_signals_header_ad_slot;
+
     mojo::AssociatedRemote<mojom::GenerateBidClient> generate_bid_client;
   };
 
@@ -300,6 +314,12 @@
     // DirectFromSellerSignals errors are fatal, so no error information is
     // stored here.
 
+    // Header-based DirectFromSellerSignals.
+    absl::optional<std::string>
+        direct_from_seller_per_buyer_signals_header_ad_slot;
+    absl::optional<std::string>
+        direct_from_seller_auction_signals_header_ad_slot;
+
     ReportWinCallback callback;
   };
 
@@ -398,8 +418,12 @@
         const absl::optional<std::string>& per_buyer_signals_json,
         DirectFromSellerSignalsRequester::Result
             direct_from_seller_result_per_buyer_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_per_buyer_signals_header_ad_slot,
         DirectFromSellerSignalsRequester::Result
             direct_from_seller_result_auction_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_auction_signals_header_ad_slot,
         const std::string& seller_signals_json,
         mojom::KAnonymityBidMode kanon_mode,
         bool bid_is_kanon,
@@ -429,8 +453,12 @@
         const absl::optional<std::string>& per_buyer_signals_json,
         DirectFromSellerSignalsRequester::Result
             direct_from_seller_result_per_buyer_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_per_buyer_signals_header_ad_slot,
         DirectFromSellerSignalsRequester::Result
             direct_from_seller_result_auction_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_auction_signals_header_ad_slot,
         const absl::optional<base::TimeDelta> per_buyer_timeout,
         const absl::optional<blink::AdCurrency>& expected_buyer_currency,
         const url::Origin& browser_signal_seller_origin,
@@ -463,8 +491,12 @@
         const std::string* per_buyer_signals_json,
         const DirectFromSellerSignalsRequester::Result&
             direct_from_seller_result_per_buyer_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_per_buyer_signals_header_ad_slot,
         const DirectFromSellerSignalsRequester::Result&
             direct_from_seller_result_auction_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_auction_signals_header_ad_slot,
         const absl::optional<base::TimeDelta> per_buyer_timeout,
         const absl::optional<blink::AdCurrency>& expected_buyer_currency,
         const url::Origin& browser_signal_seller_origin,
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc
index 2de1580..54fb06f6 100644
--- a/content/services/auction_worklet/bidder_worklet_unittest.cc
+++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -538,9 +538,12 @@
     bidder_worklet->ReportWin(
         reporting_id_field_, reporting_id_, auction_signals_,
         per_buyer_signals_, direct_from_seller_per_buyer_signals_,
-        direct_from_seller_auction_signals_, seller_signals_, kanon_mode_,
-        bid_is_kanon_, browser_signal_render_url_, browser_signal_bid_,
-        browser_signal_bid_currency_, browser_signal_highest_scoring_other_bid_,
+        direct_from_seller_per_buyer_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_, seller_signals_,
+        kanon_mode_, bid_is_kanon_, browser_signal_render_url_,
+        browser_signal_bid_, browser_signal_bid_currency_,
+        browser_signal_highest_scoring_other_bid_,
         browser_signal_highest_scoring_other_bid_currency_,
         browser_signal_made_highest_scoring_other_bid_, browser_signal_ad_cost_,
         browser_signal_modeling_signals_, browser_signal_join_count_,
@@ -709,14 +712,17 @@
     BeginGenerateBid(bidder_worklet,
                      bid_finalizer.BindNewEndpointAndPassReceiver(),
                      std::move(generate_bid_client));
-    bid_finalizer->FinishGenerateBid(auction_signals_, per_buyer_signals_,
-                                     per_buyer_timeout_, per_buyer_currency_,
-                                     provide_direct_from_seller_signals_late_
-                                         ? direct_from_seller_per_buyer_signals_
-                                         : absl::nullopt,
-                                     provide_direct_from_seller_signals_late_
-                                         ? direct_from_seller_auction_signals_
-                                         : absl::nullopt);
+    bid_finalizer->FinishGenerateBid(
+        auction_signals_, per_buyer_signals_, per_buyer_timeout_,
+        per_buyer_currency_,
+        provide_direct_from_seller_signals_late_
+            ? direct_from_seller_per_buyer_signals_
+            : absl::nullopt,
+        direct_from_seller_per_buyer_signals_header_ad_slot_,
+        provide_direct_from_seller_signals_late_
+            ? direct_from_seller_auction_signals_
+            : absl::nullopt,
+        direct_from_seller_auction_signals_header_ad_slot_);
   }
 
   // Calls BeginGenerateBid()/FinishGenerateBid(), expecting the
@@ -739,7 +745,9 @@
         auction_signals_, per_buyer_signals_, per_buyer_timeout_,
         per_buyer_currency_,
         /*direct_from_seller_per_buyer_signals=*/absl::nullopt,
-        /*direct_from_seller_auction_signals=*/absl::nullopt);
+        /*direct_from_seller_per_buyer_signals_header_ad_slot=*/absl::nullopt,
+        /*direct_from_seller_auction_signals=*/absl::nullopt,
+        /*direct_from_seller_auction_signals_header_ad_slot=*/absl::nullopt);
   }
 
   // Create a BidderWorklet and invokes BeginGenerateBid()/FinishGenerateBid(),
@@ -892,7 +900,11 @@
   absl::optional<std::string> auction_signals_;
   absl::optional<std::string> per_buyer_signals_;
   absl::optional<GURL> direct_from_seller_per_buyer_signals_;
+  absl::optional<std::string>
+      direct_from_seller_per_buyer_signals_header_ad_slot_;
   absl::optional<GURL> direct_from_seller_auction_signals_;
+  absl::optional<std::string>
+      direct_from_seller_auction_signals_header_ad_slot_;
   absl::optional<base::TimeDelta> per_buyer_timeout_;
   absl::optional<blink::AdCurrency> per_buyer_currency_;
   url::Origin top_window_origin_;
@@ -2610,7 +2622,9 @@
           /*auction_signals_json=*/base::NumberToString(bid_value),
           per_buyer_signals_, per_buyer_timeout_, per_buyer_currency_,
           /*direct_from_seller_per_buyer_signals=*/absl::nullopt,
-          /*direct_from_seller_auction_signals=*/absl::nullopt);
+          /*direct_from_seller_per_buyer_signals_header_ad_slot=*/absl::nullopt,
+          /*direct_from_seller_auction_signals=*/absl::nullopt,
+          /*direct_from_seller_auction_signals_header_ad_slot=*/absl::nullopt);
     }
 
     // If this is the first loop iteration, wait for all the Mojo calls to
@@ -2726,7 +2740,9 @@
         auction_signals_, per_buyer_signals_, per_buyer_timeout_,
         per_buyer_currency_,
         /*direct_from_seller_per_buyer_signals=*/absl::nullopt,
-        /*direct_from_seller_auction_signals=*/absl::nullopt);
+        /*direct_from_seller_per_buyer_signals_header_ad_slot=*/absl::nullopt,
+        /*direct_from_seller_auction_signals=*/absl::nullopt,
+        /*direct_from_seller_auction_signals_header_ad_slot=*/absl::nullopt);
   }
   // This should trigger a single network request for all needed signals.
   bidder_worklet->SendPendingSignalsRequests();
@@ -2851,7 +2867,9 @@
         auction_signals_, per_buyer_signals_, per_buyer_timeout_,
         per_buyer_currency_,
         /*direct_from_seller_per_buyer_signals=*/absl::nullopt,
-        /*direct_from_seller_auction_signals=*/absl::nullopt);
+        /*direct_from_seller_per_buyer_signals_header_ad_slot=*/absl::nullopt,
+        /*direct_from_seller_auction_signals=*/absl::nullopt,
+        /*direct_from_seller_auction_signals_header_ad_slot=*/absl::nullopt);
   }
   // This should trigger a single network request for all needed signals.
   bidder_worklet->SendPendingSignalsRequests();
@@ -2982,7 +3000,9 @@
         auction_signals_, per_buyer_signals_, per_buyer_timeout_,
         per_buyer_currency_,
         /*direct_from_seller_per_buyer_signals=*/absl::nullopt,
-        /*direct_from_seller_auction_signals=*/absl::nullopt);
+        /*direct_from_seller_per_buyer_signals_header_ad_slot=*/absl::nullopt,
+        /*direct_from_seller_auction_signals=*/absl::nullopt,
+        /*direct_from_seller_auction_signals_header_ad_slot=*/absl::nullopt);
   }
   // This should trigger a single network request for all needed signals.
   bidder_worklet->SendPendingSignalsRequests();
@@ -3096,7 +3116,9 @@
         auction_signals_, per_buyer_signals_, per_buyer_timeout_,
         per_buyer_currency_,
         /*direct_from_seller_per_buyer_signals=*/absl::nullopt,
-        /*direct_from_seller_auction_signals=*/absl::nullopt);
+        /*direct_from_seller_per_buyer_signals_header_ad_slot=*/absl::nullopt,
+        /*direct_from_seller_auction_signals=*/absl::nullopt,
+        /*direct_from_seller_auction_signals_header_ad_slot=*/absl::nullopt);
   }
 
   // Calling FinishGenerateBid() shouldn't cause any callbacks to be invoked -
@@ -3359,6 +3381,58 @@
           /*modeling_signals=*/absl::nullopt, base::TimeDelta()));
 }
 
+TEST_F(BidderWorkletTest,
+       GenerateBidDirectFromSellerSignalsHeaderAdSlotAuctionSignals) {
+  const std::string kGenerateBidBody =
+      R"({ad: directFromSellerSignals.auctionSignals,
+           bid:1, render:"https://response.test/"})";
+
+  direct_from_seller_auction_signals_header_ad_slot_ = R"("foo")";
+  RunGenerateBidWithReturnValueExpectingResult(
+      kGenerateBidBody,
+      mojom::BidderWorkletBid::New(
+          R"("foo")", 1, /*bid_currency=*/absl::nullopt,
+          /*ad_cost=*/absl::nullopt,
+          blink::AdDescriptor(GURL("https://response.test/")),
+          /*ad_component_descriptors=*/absl::nullopt,
+          /*modeling_signals=*/absl::nullopt, base::TimeDelta()));
+
+  direct_from_seller_auction_signals_header_ad_slot_ = "[1]";
+  RunGenerateBidWithReturnValueExpectingResult(
+      kGenerateBidBody,
+      mojom::BidderWorkletBid::New(
+          "[1]", 1, /*bid_currency=*/absl::nullopt, /*ad_cost=*/absl::nullopt,
+          blink::AdDescriptor(GURL("https://response.test/")),
+          /*ad_component_descriptors=*/absl::nullopt,
+          /*modeling_signals=*/absl::nullopt, base::TimeDelta()));
+}
+
+TEST_F(BidderWorkletTest,
+       GenerateBidDirectFromSellerSignalsHeaderAdSlotPerBuyerSignals) {
+  const std::string kGenerateBidBody =
+      R"({ad: directFromSellerSignals.perBuyerSignals,
+           bid:1, render:"https://response.test/"})";
+
+  direct_from_seller_per_buyer_signals_header_ad_slot_ = R"("foo")";
+  RunGenerateBidWithReturnValueExpectingResult(
+      kGenerateBidBody,
+      mojom::BidderWorkletBid::New(
+          R"("foo")", 1, /*bid_currency=*/absl::nullopt,
+          /*ad_cost=*/absl::nullopt,
+          blink::AdDescriptor(GURL("https://response.test/")),
+          /*ad_component_descriptors=*/absl::nullopt,
+          /*modeling_signals=*/absl::nullopt, base::TimeDelta()));
+
+  direct_from_seller_per_buyer_signals_header_ad_slot_ = "[1]";
+  RunGenerateBidWithReturnValueExpectingResult(
+      kGenerateBidBody,
+      mojom::BidderWorkletBid::New(
+          "[1]", 1, /*bid_currency=*/absl::nullopt, /*ad_cost=*/absl::nullopt,
+          blink::AdDescriptor(GURL("https://response.test/")),
+          /*ad_component_descriptors=*/absl::nullopt,
+          /*modeling_signals=*/absl::nullopt, base::TimeDelta()));
+}
+
 TEST_F(BidderWorkletTest, GenerateBidBrowserSignalSellerOrigin) {
   browser_signal_seller_origin_ =
       url::Origin::Create(GURL("https://foo.test/"));
@@ -3696,9 +3770,12 @@
   bidder_worklet->ReportWin(
       reporting_id_field_, reporting_id_, /*auction_signals_json=*/"0",
       per_buyer_signals_, direct_from_seller_per_buyer_signals_,
-      direct_from_seller_auction_signals_, seller_signals_, kanon_mode_,
-      bid_is_kanon_, browser_signal_render_url_, browser_signal_bid_,
-      browser_signal_bid_currency_, browser_signal_highest_scoring_other_bid_,
+      direct_from_seller_per_buyer_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_, seller_signals_,
+      kanon_mode_, bid_is_kanon_, browser_signal_render_url_,
+      browser_signal_bid_, browser_signal_bid_currency_,
+      browser_signal_highest_scoring_other_bid_,
       browser_signal_highest_scoring_other_bid_currency_,
       browser_signal_made_highest_scoring_other_bid_, browser_signal_ad_cost_,
       browser_signal_modeling_signals_, browser_signal_join_count_,
@@ -5091,9 +5168,12 @@
   bidder_worklet->ReportWin(
       reporting_id_field_, reporting_id_, auction_signals_, per_buyer_signals_,
       direct_from_seller_per_buyer_signals_,
-      direct_from_seller_auction_signals_, seller_signals_, kanon_mode_,
-      bid_is_kanon_, browser_signal_render_url_, browser_signal_bid_,
-      browser_signal_bid_currency_, browser_signal_highest_scoring_other_bid_,
+      direct_from_seller_per_buyer_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_, seller_signals_,
+      kanon_mode_, bid_is_kanon_, browser_signal_render_url_,
+      browser_signal_bid_, browser_signal_bid_currency_,
+      browser_signal_highest_scoring_other_bid_,
       browser_signal_highest_scoring_other_bid_currency_,
       browser_signal_made_highest_scoring_other_bid_, browser_signal_ad_cost_,
       browser_signal_modeling_signals_, browser_signal_join_count_,
@@ -5143,9 +5223,11 @@
           reporting_id_field_, reporting_id_,
           /*auction_signals_json=*/base::NumberToString(i), per_buyer_signals_,
           direct_from_seller_per_buyer_signals_,
-          direct_from_seller_auction_signals_, seller_signals_, kanon_mode_,
-          bid_is_kanon_, browser_signal_render_url_, browser_signal_bid_,
-          browser_signal_bid_currency_,
+          direct_from_seller_per_buyer_signals_header_ad_slot_,
+          direct_from_seller_auction_signals_,
+          direct_from_seller_auction_signals_header_ad_slot_, seller_signals_,
+          kanon_mode_, bid_is_kanon_, browser_signal_render_url_,
+          browser_signal_bid_, browser_signal_bid_currency_,
           browser_signal_highest_scoring_other_bid_,
           browser_signal_highest_scoring_other_bid_currency_,
           browser_signal_made_highest_scoring_other_bid_,
@@ -5197,9 +5279,12 @@
         reporting_id_field_, reporting_id_,
         /*auction_signals_json=*/base::NumberToString(i), per_buyer_signals_,
         direct_from_seller_per_buyer_signals_,
-        direct_from_seller_auction_signals_, seller_signals_, kanon_mode_,
-        bid_is_kanon_, browser_signal_render_url_, browser_signal_bid_,
-        browser_signal_bid_currency_, browser_signal_highest_scoring_other_bid_,
+        direct_from_seller_per_buyer_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_, seller_signals_,
+        kanon_mode_, bid_is_kanon_, browser_signal_render_url_,
+        browser_signal_bid_, browser_signal_bid_currency_,
+        browser_signal_highest_scoring_other_bid_,
         browser_signal_highest_scoring_other_bid_currency_,
         browser_signal_made_highest_scoring_other_bid_, browser_signal_ad_cost_,
         browser_signal_modeling_signals_, browser_signal_join_count_,
@@ -5379,6 +5464,36 @@
       "sendReportTo(sellerSignals)", GURL("https://interest.group.name.test/"));
 }
 
+TEST_F(BidderWorkletTest,
+       ReportWinDirectFromSellerSignalsHeaderAdSlotAuctionSignals) {
+  direct_from_seller_auction_signals_header_ad_slot_ =
+      R"("https://interest.group.name.test/")";
+  RunReportWinWithFunctionBodyExpectingResult(
+      "sendReportTo(directFromSellerSignals.auctionSignals)",
+      GURL("https://interest.group.name.test/"));
+
+  direct_from_seller_auction_signals_header_ad_slot_ = absl::nullopt;
+  RunReportWinWithFunctionBodyExpectingResult(
+      R"(sendReportTo("https://" +
+          (directFromSellerSignals.auctionSignals === null)))",
+      GURL("https://true/"));
+}
+
+TEST_F(BidderWorkletTest,
+       ReportWinDirectFromSellerSignalsHeaderAdSlotPerBuyerSignals) {
+  direct_from_seller_per_buyer_signals_header_ad_slot_ =
+      R"("https://interest.group.name.test/")";
+  RunReportWinWithFunctionBodyExpectingResult(
+      "sendReportTo(directFromSellerSignals.perBuyerSignals)",
+      GURL("https://interest.group.name.test/"));
+
+  direct_from_seller_per_buyer_signals_header_ad_slot_ = absl::nullopt;
+  RunReportWinWithFunctionBodyExpectingResult(
+      R"(sendReportTo("https://" +
+          (directFromSellerSignals.perBuyerSignals === null)))",
+      GURL("https://true/"));
+}
+
 TEST_F(BidderWorkletTest, ReportWinInterestGroupOwner) {
   interest_group_bidding_url_ = GURL("https://foo.test/bar");
   // Add an extra ".test" because origin's shouldn't have a terminal slash,
@@ -5622,9 +5737,12 @@
     bidder_worklet->ReportWin(
         reporting_id_field_, reporting_id_, auction_signals_,
         per_buyer_signals_, direct_from_seller_per_buyer_signals_,
-        direct_from_seller_auction_signals_, seller_signals_, kanon_mode_,
-        bid_is_kanon_, browser_signal_render_url_, browser_signal_bid_,
-        browser_signal_bid_currency_, browser_signal_highest_scoring_other_bid_,
+        direct_from_seller_per_buyer_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_, seller_signals_,
+        kanon_mode_, bid_is_kanon_, browser_signal_render_url_,
+        browser_signal_bid_, browser_signal_bid_currency_,
+        browser_signal_highest_scoring_other_bid_,
         browser_signal_highest_scoring_other_bid_currency_,
         browser_signal_made_highest_scoring_other_bid_, browser_signal_ad_cost_,
         browser_signal_modeling_signals_, browser_signal_join_count_,
@@ -6386,9 +6504,12 @@
   bidder_worklet->ReportWin(
       reporting_id_field_, reporting_id_, auction_signals_, per_buyer_signals_,
       direct_from_seller_per_buyer_signals_,
-      direct_from_seller_auction_signals_, seller_signals_, kanon_mode_,
-      bid_is_kanon_, browser_signal_render_url_, browser_signal_bid_,
-      browser_signal_bid_currency_, browser_signal_highest_scoring_other_bid_,
+      direct_from_seller_per_buyer_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_, seller_signals_,
+      kanon_mode_, bid_is_kanon_, browser_signal_render_url_,
+      browser_signal_bid_, browser_signal_bid_currency_,
+      browser_signal_highest_scoring_other_bid_,
       browser_signal_highest_scoring_other_bid_currency_,
       browser_signal_made_highest_scoring_other_bid_, browser_signal_ad_cost_,
       browser_signal_modeling_signals_, browser_signal_join_count_,
@@ -8127,7 +8248,9 @@
       auction_signals_, per_buyer_signals_, per_buyer_timeout_,
       per_buyer_currency_,
       /*direct_from_seller_per_buyer_signals=*/absl::nullopt,
-      /*direct_from_seller_auction_signals=*/absl::nullopt);
+      /*direct_from_seller_per_buyer_signals_header_ad_slot=*/absl::nullopt,
+      /*direct_from_seller_auction_signals=*/absl::nullopt,
+      /*direct_from_seller_auction_signals_header_ad_slot=*/absl::nullopt);
   load_script_run_loop_ = std::make_unique<base::RunLoop>();
   load_script_run_loop_->Run();
   ASSERT_TRUE(bid_);
@@ -8166,7 +8289,9 @@
       auction_signals_, per_buyer_signals_, per_buyer_timeout_,
       per_buyer_currency_,
       /*direct_from_seller_per_buyer_signals=*/absl::nullopt,
-      /*direct_from_seller_auction_signals=*/absl::nullopt);
+      /*direct_from_seller_per_buyer_signals_header_ad_slot=*/absl::nullopt,
+      /*direct_from_seller_auction_signals=*/absl::nullopt,
+      /*direct_from_seller_auction_signals_header_ad_slot=*/absl::nullopt);
   task_environment_.RunUntilIdle();
   EXPECT_FALSE(bid_);
 
@@ -8233,7 +8358,9 @@
       auction_signals_, per_buyer_signals_, per_buyer_timeout_,
       per_buyer_currency_,
       /*direct_from_seller_per_buyer_signals=*/absl::nullopt,
-      /*direct_from_seller_auction_signals=*/absl::nullopt);
+      /*direct_from_seller_per_buyer_signals_header_ad_slot=*/absl::nullopt,
+      /*direct_from_seller_auction_signals=*/absl::nullopt,
+      /*direct_from_seller_auction_signals_header_ad_slot=*/absl::nullopt);
   load_script_run_loop_ = std::make_unique<base::RunLoop>();
   load_script_run_loop_->Run();
   ASSERT_TRUE(bid_);
diff --git a/content/services/auction_worklet/direct_from_seller_signals_requester.cc b/content/services/auction_worklet/direct_from_seller_signals_requester.cc
index 68c619f..879b2a82 100644
--- a/content/services/auction_worklet/direct_from_seller_signals_requester.cc
+++ b/content/services/auction_worklet/direct_from_seller_signals_requester.cc
@@ -132,6 +132,18 @@
   return v8_result.ToLocalChecked();
 }
 
+bool DirectFromSellerSignalsRequester::Result::IsNull() const {
+  if (absl::holds_alternative<ErrorString>(response_or_error_)) {
+    return false;
+  }
+
+  DCHECK(absl::holds_alternative<scoped_refptr<ResponseString>>(
+      response_or_error_));
+  scoped_refptr<ResponseString> response =
+      absl::get<scoped_refptr<ResponseString>>(response_or_error_);
+  return response == nullptr;
+}
+
 DirectFromSellerSignalsRequester::Result::ResponseString::ResponseString(
     std::string&& other)
     : value_(std::move(other)) {}
diff --git a/content/services/auction_worklet/direct_from_seller_signals_requester.h b/content/services/auction_worklet/direct_from_seller_signals_requester.h
index 91959cb..c46223e 100644
--- a/content/services/auction_worklet/direct_from_seller_signals_requester.h
+++ b/content/services/auction_worklet/direct_from_seller_signals_requester.h
@@ -68,6 +68,10 @@
                                     v8::Local<v8::Context> context,
                                     std::vector<std::string>& errors) const;
 
+    // Returns true if this Result is a null value, and false otherwise. Returns
+    // false if Result is an error.
+    bool IsNull() const;
+
    private:
     // Private methods are called by DirectFromSellerSignalsRequester.
     friend DirectFromSellerSignalsRequester;
diff --git a/content/services/auction_worklet/public/mojom/bidder_worklet.mojom b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom
index 51957f058..1fd6214 100644
--- a/content/services/auction_worklet/public/mojom/bidder_worklet.mojom
+++ b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom
@@ -322,15 +322,27 @@
   //  page. Null will be passed to the worklet in that case.
   //
   // See BeginGenerateBid for description of
-  //  `direct_from_seller_per_buyer_signals`, `
+  //  `direct_from_seller_per_buyer_signals`,
   //  `direct_from_seller_auction_signals`
+  //
+  //  `direct_from_seller_per_buyer_signals_header_ad_slot` A JSON string of the
+  //   DirectFromSellerSignals for this specific buyer. Must not be passed if
+  //   `direct_from_seller_per_buyer_signals` or
+  //   `direct_from_seller_auction_signals` is passed.
+  //
+  //  `direct_from_seller_auction_signals_header_ad_slot` A JSON string of the
+  //   DirectFromSellerSignals for the seller and all buyers. Must not be passed
+  //   if `direct_from_seller_auction_signals` or
+  //   `direct_from_seller_per_buyer_signals` is passed.
   FinishGenerateBid(
       string? auction_signals_json,
       string? per_buyer_signals_json,
       mojo_base.mojom.TimeDelta? per_buyer_timeout,
       blink.mojom.AdCurrency? expected_buyer_currency,
       url.mojom.Url? direct_from_seller_per_buyer_signals,
-      url.mojom.Url? direct_from_seller_auction_signals);
+      string? direct_from_seller_per_buyer_signals_header_ad_slot,
+      url.mojom.Url? direct_from_seller_auction_signals,
+      string? direct_from_seller_auction_signals_header_ad_slot);
 };
 
 // Manages the auction workflow for one loaded FLEDGE bidder worklet.
@@ -369,19 +381,19 @@
   //  was joined; can affect context reuse in certain execution modes.
   //
   // `direct_from_seller_per_buyer_signals` The subresource URL of the
-  // DirectFromSellerSignals for the specific owner of this interest group, as
-  // produced by concatenating the `directFromSellerSignals` URL prefix field
-  // passed from runAdAuction() with "?perBuyerSignals=[buyer]" for the
-  // URL-encoded buyer origin for this buyer. Since this is fetched from a
-  // subresource bundle, it may only be fetched using the URLLoaderFactory
-  // passed in when creating the worklet.
+  //  DirectFromSellerSignals for the specific owner of this interest group, as
+  //  produced by concatenating the `directFromSellerSignals` URL prefix field
+  //  passed from runAdAuction() with "?perBuyerSignals=[buyer]" for the
+  //  URL-encoded buyer origin for this buyer. Since this is fetched from a
+  //  subresource bundle, it may only be fetched using the URLLoaderFactory
+  //  passed in when creating the worklet.
   //
   // `direct_from_seller_auction_signals` The subresource URL of the
-  // DirectFromSellerSignals for the seller and all buyers, as produced by
-  // concatenating the `directFromSellerSignals` URL prefix field passed from
-  // runAdAuction() with "?auctionSignals". Since this is fetched from a
-  // subresource bundle, it may only be fetched using the URLLoaderFactory
-  // passed in when creating the worklet.
+  //  DirectFromSellerSignals for the seller and all buyers, as produced by
+  //  concatenating the `directFromSellerSignals` URL prefix field passed from
+  //  runAdAuction() with "?auctionSignals". Since this is fetched from a
+  //  subresource bundle, it may only be fetched using the URLLoaderFactory
+  //  passed in when creating the worklet.
   //
   // Both `direct_from_seller_auction_signals` and
   // `direct_from_seller_per_buyer_signals` can alternatively be passed as
@@ -472,6 +484,11 @@
   //  subresource bundle, it may only be fetched using the URLLoaderFactory
   //  passed in when creating the worklet.
   //
+  // `direct_from_seller_per_buyer_signals_header_ad_slot` A JSON string of the
+  //  DirectFromSellerSignals for this specific buyer. Must not be passed if
+  //  `direct_from_seller_per_buyer_signals` or
+  //  `direct_from_seller_auction_signals` is passed.
+  //
   // `direct_from_seller_auction_signals` The subresource URL of the
   //  DirectFromSellerSignals for the seller and all buyers, as produced by
   //  concatenating the `directFromSellerSignals` URL prefix field passed from
@@ -479,6 +496,11 @@
   //  subresource bundle, it may only be fetched using the URLLoaderFactory
   //  passed in when creating the worklet.
   //
+  // `direct_from_seller_auction_signals_header_ad_slot` A JSON string of the
+  //   DirectFromSellerSignals for the seller and all buyers. Must not be passed
+  //   if `direct_from_seller_auction_signals` or
+  //   `direct_from_seller_per_buyer_signals` is passed.
+  //
   // `seller_signals_json` is a JSON representation of the object returned by
   //  the seller worklet's ReportResult method.
   //
@@ -571,7 +593,9 @@
       string? auction_signals_json,
       string? per_buyer_signals_json,
       url.mojom.Url? direct_from_seller_per_buyer_signals,
+      string? direct_from_seller_per_buyer_signals_header_ad_slot,
       url.mojom.Url? direct_from_seller_auction_signals,
+      string? direct_from_seller_auction_signals_header_ad_slot,
       string seller_signals_json,
       KAnonymityBidMode kanon_mode,
       bool bid_is_kanon,
diff --git a/content/services/auction_worklet/public/mojom/seller_worklet.mojom b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
index f61806a9..0688a40 100644
--- a/content/services/auction_worklet/public/mojom/seller_worklet.mojom
+++ b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
@@ -167,18 +167,28 @@
   //  vary between auctions that can share a SellerWorklet.
   //
   // `direct_from_seller_seller_signals` The subresource URL of the
-  // DirectFromSellerSignals for the seller, as produced by concatenating the
-  // `directFromSellerSignals` URL prefix field passed from runAdAuction() with
-  // "?sellerSignals". Since this is fetched from a subresource bundle, it may
-  // only be fetched using the URLLoaderFactory passed in when creating the
-  // worklet.
+  //  DirectFromSellerSignals for the seller, as produced by concatenating the
+  //  `directFromSellerSignals` URL prefix field passed from runAdAuction() with
+  //  "?sellerSignals". Since this is fetched from a subresource bundle, it may
+  //  only be fetched using the URLLoaderFactory passed in when creating the
+  //  worklet.
+  //
+  // `direct_from_seller_seller_signals_header_ad_slot` A JSON string of the
+  //  DirectFromSellerSignals for the seller. Must not be passed if
+  //  `direct_from_seller_seller_signals` or
+  //  `direct_from_seller_auction_signals` is passed.
   //
   // `direct_from_seller_auction_signals` The subresource URL of the
-  // directFromSellerSignals for the seller and all buyers, as produced by
-  // concatenating the `directFromSellerSignals` URL prefix field passed from
-  // runAdAuction() with "?auctionSignals". Since this is fetched from a
-  // subresource bundle, it may only be fetched using the URLLoaderFactory
-  // passed in when creating the worklet.
+  //  directFromSellerSignals for the seller and all buyers, as produced by
+  //  concatenating the `directFromSellerSignals` URL prefix field passed from
+  //  runAdAuction() with "?auctionSignals". Since this is fetched from a
+  //  subresource bundle, it may only be fetched using the URLLoaderFactory
+  //  passed in when creating the worklet.
+  //
+  // `direct_from_seller_auction_signals_header_ad_slot` A JSON string of the
+  //  DirectFromSellerSignals for the seller and all buyers. Must not be passed
+  //  if `direct_from_seller_auction_signals` or
+  //  `direct_from_seller_seller_signals` is passed.
   //
   // `browser_signals_other_seller` The origin of the other seller associated
   //  with the bid. If this is a component seller worklet, it's the
@@ -219,7 +229,9 @@
           blink.mojom.AuctionAdConfigNonSharedParams
               auction_ad_config_non_shared_params,
           url.mojom.Url? direct_from_seller_seller_signals,
+          string? direct_from_seller_seller_signals_header_ad_slot,
           url.mojom.Url? direct_from_seller_auction_signals,
+          string? direct_from_seller_auction_signals_header_ad_slot,
           ComponentAuctionOtherSeller? browser_signals_other_seller,
           blink.mojom.AdCurrency? component_expect_bid_currency,
           url.mojom.Origin browser_signal_interest_group_owner,
@@ -252,18 +264,28 @@
   //  vary between auctions that can share a SellerWorklet.
   //
   // `direct_from_seller_seller_signals` The subresource URL of the
-  // DirectFromSellerSignals for the seller, as produced by concatenating the
-  // `directFromSellerSignals` URL prefix field passed from runAdAuction() with
-  // "?sellerSignals". Since this is fetched from a subresource bundle, it may
-  // only be fetched using the URLLoaderFactory passed in when creating the
-  // worklet.
+  //  DirectFromSellerSignals for the seller, as produced by concatenating the
+  //  `directFromSellerSignals` URL prefix field passed from runAdAuction() with
+  //  "?sellerSignals". Since this is fetched from a subresource bundle, it may
+  //  only be fetched using the URLLoaderFactory passed in when creating the
+  //  worklet.
+  //
+  // `direct_from_seller_seller_signals_header_ad_slot` A JSON string of the
+  //  DirectFromSellerSignals for the seller. Must not be passed if
+  //  `direct_from_seller_seller_signals` or
+  //  `direct_from_seller_auction_signals` is passed.
   //
   // `direct_from_seller_auction_signals` The subresource URL of the
-  // directFromSellerSignals for the seller and all buyers, as produced by
-  // concatenating the `directFromSellerSignals` URL prefix field passed from
-  // runAdAuction() with "?auctionSignals". Since this is fetched from a
-  // subresource bundle, it may only be fetched using the URLLoaderFactory
-  // passed in when creating the worklet.
+  //  directFromSellerSignals for the seller and all buyers, as produced by
+  //  concatenating the `directFromSellerSignals` URL prefix field passed from
+  //  runAdAuction() with "?auctionSignals". Since this is fetched from a
+  //  subresource bundle, it may only be fetched using the URLLoaderFactory
+  //  passed in when creating the worklet.
+  //
+  // `direct_from_seller_auction_signals_header_ad_slot` A JSON string of the
+  //  DirectFromSellerSignals for the seller and all buyers. Must not be passed
+  //  if `direct_from_seller_auction_signals` or
+  //  `direct_from_seller_seller_signals` is passed.
   //
   // `browser_signals_other_seller` The origin of the other seller associated
   //  with the bid. If this is a component seller worklet, it's the
@@ -339,7 +361,9 @@
       blink.mojom.AuctionAdConfigNonSharedParams
           auction_ad_config_non_shared_params,
       url.mojom.Url? direct_from_seller_seller_signals,
+      string? direct_from_seller_seller_signals_header_ad_slot,
       url.mojom.Url? direct_from_seller_auction_signals,
+      string? direct_from_seller_auction_signals_header_ad_slot,
       ComponentAuctionOtherSeller? browser_signals_other_seller,
       url.mojom.Origin browser_signal_interest_group_owner,
       string? browser_signal_buyer_and_seller_reporting_id,
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc
index 4533e682..4c3a667a 100644
--- a/content/services/auction_worklet/seller_worklet.cc
+++ b/content/services/auction_worklet/seller_worklet.cc
@@ -60,6 +60,29 @@
 
 namespace {
 
+// Checks both types of DirectFromSellerSignals results (subresource bundle
+// based and header based) -- at most one of these should be non-null.
+//
+// Returns the V8 conversion of the in-use version of DirectFromSellerSignals,
+// or v8::Null() if both types of DirectFromSellerSignals are null.
+v8::Local<v8::Value> GetDirectFromSellerSignals(
+    const DirectFromSellerSignalsRequester::Result& subresource_bundle_result,
+    const absl::optional<std::string>& header_result,
+    AuctionV8Helper& v8_helper,
+    v8::Local<v8::Context> context,
+    std::vector<std::string>& errors) {
+  CHECK(subresource_bundle_result.IsNull() || !header_result);
+
+  if (header_result) {
+    // `header_result` JSON was validated, parsed and reconstructed into a
+    // string by the browser process, so CHECK it is valid JSON.
+    return v8_helper.CreateValueFromJson(context, *header_result)
+        .ToLocalChecked();
+  }
+
+  return subresource_bundle_result.GetSignals(v8_helper, context, errors);
+}
+
 // TODO(crbug.com/1441988): Remove this code after rename. These functions allow
 // having multiple dictionary keys (e.g. renderUrl and renderURL) share the same
 // V8 value.
@@ -596,7 +619,11 @@
     const blink::AuctionConfig::NonSharedParams&
         auction_ad_config_non_shared_params,
     const absl::optional<GURL>& direct_from_seller_seller_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_seller_signals_header_ad_slot,
     const absl::optional<GURL>& direct_from_seller_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
     const absl::optional<blink::AdCurrency>& component_expect_bid_currency,
     const url::Origin& browser_signal_interest_group_owner,
@@ -607,6 +634,10 @@
     uint64_t trace_id,
     mojo::PendingRemote<auction_worklet::mojom::ScoreAdClient>
         score_ad_client) {
+  CHECK((!direct_from_seller_seller_signals &&
+         !direct_from_seller_auction_signals) ||
+        (!direct_from_seller_seller_signals_header_ad_slot &&
+         !direct_from_seller_auction_signals_header_ad_slot));
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
   score_ad_tasks_.emplace_front();
 
@@ -668,6 +699,10 @@
     score_ad_task->direct_from_seller_result_auction_signals =
         DirectFromSellerSignalsRequester::Result();
   }
+  score_ad_task->direct_from_seller_seller_signals_header_ad_slot =
+      direct_from_seller_seller_signals_header_ad_slot;
+  score_ad_task->direct_from_seller_auction_signals_header_ad_slot =
+      direct_from_seller_auction_signals_header_ad_slot;
 
   score_ad_task->trace_wait_deps_start = base::TimeTicks::Now();
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("fledge", "wait_score_ad_deps", trace_id);
@@ -697,7 +732,11 @@
     const blink::AuctionConfig::NonSharedParams&
         auction_ad_config_non_shared_params,
     const absl::optional<GURL>& direct_from_seller_seller_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_seller_signals_header_ad_slot,
     const absl::optional<GURL>& direct_from_seller_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
     const url::Origin& browser_signal_interest_group_owner,
     const absl::optional<std::string>&
@@ -715,6 +754,10 @@
     bool has_scoring_signals_data_version,
     uint64_t trace_id,
     ReportResultCallback callback) {
+  CHECK((!direct_from_seller_seller_signals &&
+         !direct_from_seller_auction_signals) ||
+        (!direct_from_seller_seller_signals_header_ad_slot &&
+         !direct_from_seller_auction_signals_header_ad_slot));
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
   // `browser_signals_component_auction_report_result_params` should only be
   // populated for sellers in component auctions, which are the only case where
@@ -786,6 +829,10 @@
     report_result_task->direct_from_seller_result_auction_signals =
         DirectFromSellerSignalsRequester::Result();
   }
+  report_result_task->direct_from_seller_seller_signals_header_ad_slot =
+      direct_from_seller_seller_signals_header_ad_slot;
+  report_result_task->direct_from_seller_auction_signals_header_ad_slot =
+      direct_from_seller_auction_signals_header_ad_slot;
 
   report_result_task->trace_wait_deps_start = base::TimeTicks::Now();
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("fledge", "wait_report_result_deps",
@@ -848,8 +895,12 @@
         auction_ad_config_non_shared_params,
     DirectFromSellerSignalsRequester::Result
         direct_from_seller_result_seller_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_seller_signals_header_ad_slot,
     DirectFromSellerSignalsRequester::Result
         direct_from_seller_result_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     scoped_refptr<TrustedSignals::Result> trusted_scoring_signals,
     mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
     const absl::optional<blink::AdCurrency>& component_expect_bid_currency,
@@ -953,12 +1004,14 @@
   gin::Dictionary direct_from_seller_signals_dict(isolate,
                                                   direct_from_seller_signals);
   std::vector<std::string> errors_out;
-  v8::Local<v8::Value> seller_signals =
-      direct_from_seller_result_seller_signals.GetSignals(*v8_helper_, context,
-                                                          errors_out);
-  v8::Local<v8::Value> auction_signals =
-      direct_from_seller_result_auction_signals.GetSignals(*v8_helper_, context,
-                                                           errors_out);
+  v8::Local<v8::Value> seller_signals = GetDirectFromSellerSignals(
+      direct_from_seller_result_seller_signals,
+      direct_from_seller_seller_signals_header_ad_slot, *v8_helper_, context,
+      errors_out);
+  v8::Local<v8::Value> auction_signals = GetDirectFromSellerSignals(
+      direct_from_seller_result_auction_signals,
+      direct_from_seller_auction_signals_header_ad_slot, *v8_helper_, context,
+      errors_out);
   if (!direct_from_seller_signals_dict.Set("sellerSignals", seller_signals) ||
       !direct_from_seller_signals_dict.Set("auctionSignals", auction_signals)) {
     PostScoreAdCallbackToUserThreadOnError(
@@ -1297,8 +1350,12 @@
         auction_ad_config_non_shared_params,
     DirectFromSellerSignalsRequester::Result
         direct_from_seller_result_seller_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_seller_signals_header_ad_slot,
     DirectFromSellerSignalsRequester::Result
         direct_from_seller_result_auction_signals,
+    const absl::optional<std::string>&
+        direct_from_seller_auction_signals_header_ad_slot,
     mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
     const url::Origin& browser_signal_interest_group_owner,
     const absl::optional<std::string>&
@@ -1408,12 +1465,14 @@
   v8::Local<v8::Object> direct_from_seller_signals = v8::Object::New(isolate);
   gin::Dictionary direct_from_seller_signals_dict(isolate,
                                                   direct_from_seller_signals);
-  v8::Local<v8::Value> seller_signals =
-      direct_from_seller_result_seller_signals.GetSignals(*v8_helper_, context,
-                                                          errors_out);
-  v8::Local<v8::Value> auction_signals =
-      direct_from_seller_result_auction_signals.GetSignals(*v8_helper_, context,
-                                                           errors_out);
+  v8::Local<v8::Value> seller_signals = GetDirectFromSellerSignals(
+      direct_from_seller_result_seller_signals,
+      direct_from_seller_seller_signals_header_ad_slot, *v8_helper_, context,
+      errors_out);
+  v8::Local<v8::Value> auction_signals = GetDirectFromSellerSignals(
+      direct_from_seller_result_auction_signals,
+      direct_from_seller_auction_signals_header_ad_slot, *v8_helper_, context,
+      errors_out);
   if (!direct_from_seller_signals_dict.Set("sellerSignals", seller_signals) ||
       !direct_from_seller_signals_dict.Set("auctionSignals", auction_signals)) {
     PostReportResultCallbackToUserThread(std::move(callback),
@@ -1778,7 +1837,9 @@
           task->ad_metadata_json, task->bid, std::move(task->bid_currency),
           std::move(task->auction_ad_config_non_shared_params),
           std::move(task->direct_from_seller_result_seller_signals),
+          std::move(task->direct_from_seller_seller_signals_header_ad_slot),
           std::move(task->direct_from_seller_result_auction_signals),
+          std::move(task->direct_from_seller_auction_signals_header_ad_slot),
           std::move(task->trusted_scoring_signals_result),
           std::move(task->browser_signals_other_seller),
           std::move(task->component_expect_bid_currency),
@@ -1904,7 +1965,9 @@
           base::Unretained(v8_state_.get()),
           std::move(task->auction_ad_config_non_shared_params),
           std::move(task->direct_from_seller_result_seller_signals),
+          std::move(task->direct_from_seller_seller_signals_header_ad_slot),
           std::move(task->direct_from_seller_result_auction_signals),
+          std::move(task->direct_from_seller_auction_signals_header_ad_slot),
           std::move(task->browser_signals_other_seller),
           std::move(task->browser_signal_interest_group_owner),
           std::move(task->browser_signal_buyer_and_seller_reporting_id),
diff --git a/content/services/auction_worklet/seller_worklet.h b/content/services/auction_worklet/seller_worklet.h
index 58664341..fb52af8 100644
--- a/content/services/auction_worklet/seller_worklet.h
+++ b/content/services/auction_worklet/seller_worklet.h
@@ -100,7 +100,11 @@
       const blink::AuctionConfig::NonSharedParams&
           auction_ad_config_non_shared_params,
       const absl::optional<GURL>& direct_from_seller_seller_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_seller_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
       const absl::optional<blink::AdCurrency>& component_expect_bid_currency,
       const url::Origin& browser_signal_interest_group_owner,
@@ -116,7 +120,11 @@
       const blink::AuctionConfig::NonSharedParams&
           auction_ad_config_non_shared_params,
       const absl::optional<GURL>& direct_from_seller_seller_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_seller_signals_header_ad_slot,
       const absl::optional<GURL>& direct_from_seller_auction_signals,
+      const absl::optional<std::string>&
+          direct_from_seller_auction_signals_header_ad_slot,
       mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
       const url::Origin& browser_signal_interest_group_owner,
       const absl::optional<std::string>&
@@ -196,6 +204,12 @@
         direct_from_seller_result_auction_signals;
     // DirectFromSellerSignals errors are fatal, so no error information is
     // stored here.
+
+    // Header-based DirectFromSellerSignals.
+    absl::optional<std::string>
+        direct_from_seller_seller_signals_header_ad_slot;
+    absl::optional<std::string>
+        direct_from_seller_auction_signals_header_ad_slot;
   };
 
   using ScoreAdTaskList = std::list<ScoreAdTask>;
@@ -244,6 +258,12 @@
     // DirectFromSellerSignals errors are fatal, so no error information is
     // stored here.
 
+    // Header-based DirectFromSellerSignals.
+    absl::optional<std::string>
+        direct_from_seller_seller_signals_header_ad_slot;
+    absl::optional<std::string>
+        direct_from_seller_auction_signals_header_ad_slot;
+
     ReportResultCallback callback;
   };
 
@@ -299,8 +319,12 @@
             auction_ad_config_non_shared_params,
         DirectFromSellerSignalsRequester::Result
             direct_from_seller_result_seller_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_seller_signals_header_ad_slot,
         DirectFromSellerSignalsRequester::Result
             direct_from_seller_result_auction_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_auction_signals_header_ad_slot,
         scoped_refptr<TrustedSignals::Result> trusted_scoring_signals,
         mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
         const absl::optional<blink::AdCurrency>& component_expect_bid_currency,
@@ -318,8 +342,12 @@
             auction_ad_config_non_shared_params,
         DirectFromSellerSignalsRequester::Result
             direct_from_seller_result_seller_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_seller_signals_header_ad_slot,
         DirectFromSellerSignalsRequester::Result
             direct_from_seller_result_auction_signals,
+        const absl::optional<std::string>&
+            direct_from_seller_auction_signals_header_ad_slot,
         mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
         const url::Origin& browser_signal_interest_group_owner,
         const absl::optional<std::string>&
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc
index abc7fc3..f8d6377 100644
--- a/content/services/auction_worklet/seller_worklet_unittest.cc
+++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -366,7 +366,10 @@
       base::OnceClosure done_closure) {
     seller_worklet->ScoreAd(
         ad_metadata_, bid_, bid_currency_, auction_ad_config_non_shared_params_,
-        direct_from_seller_seller_signals_, direct_from_seller_auction_signals_,
+        direct_from_seller_seller_signals_,
+        direct_from_seller_seller_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_,
         browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
         browser_signal_interest_group_owner_, browser_signal_render_url_,
         browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
@@ -458,7 +461,10 @@
       mojom::SellerWorklet* seller_worklet) {
     seller_worklet->ScoreAd(
         ad_metadata_, bid_, bid_currency_, auction_ad_config_non_shared_params_,
-        direct_from_seller_seller_signals_, direct_from_seller_auction_signals_,
+        direct_from_seller_seller_signals_,
+        direct_from_seller_seller_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_,
         browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
         browser_signal_interest_group_owner_, browser_signal_render_url_,
         browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
@@ -579,7 +585,10 @@
       base::OnceClosure done_closure) {
     seller_worklet->ReportResult(
         auction_ad_config_non_shared_params_,
-        direct_from_seller_seller_signals_, direct_from_seller_auction_signals_,
+        direct_from_seller_seller_signals_,
+        direct_from_seller_seller_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_,
         browser_signals_other_seller_.Clone(),
         browser_signal_interest_group_owner_,
         browser_signal_buyer_and_seller_reporting_id_,
@@ -637,7 +646,10 @@
       mojom::SellerWorklet* seller_worklet) {
     seller_worklet->ReportResult(
         auction_ad_config_non_shared_params_,
-        direct_from_seller_seller_signals_, direct_from_seller_auction_signals_,
+        direct_from_seller_seller_signals_,
+        direct_from_seller_seller_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_,
         browser_signals_other_seller_.Clone(),
         browser_signal_interest_group_owner_,
         browser_signal_buyer_and_seller_reporting_id_,
@@ -768,7 +780,10 @@
   absl::optional<GURL> trusted_scoring_signals_url_;
   blink::AuctionConfig::NonSharedParams auction_ad_config_non_shared_params_;
   absl::optional<GURL> direct_from_seller_seller_signals_;
+  absl::optional<std::string> direct_from_seller_seller_signals_header_ad_slot_;
   absl::optional<GURL> direct_from_seller_auction_signals_;
+  absl::optional<std::string>
+      direct_from_seller_auction_signals_header_ad_slot_;
   url::Origin top_window_origin_;
   mojom::AuctionWorkletPermissionsPolicyStatePtr permissions_policy_state_;
   absl::optional<uint16_t> experiment_group_id_;
@@ -1579,6 +1594,18 @@
   RunScoreAdWithReturnValueExpectingResult(
       "auctionConfig.decisionLogicUrl.length",
       decision_logic_url_.spec().length());
+
+  direct_from_seller_auction_signals_header_ad_slot_ = R"("abcde")";
+  RunScoreAdWithReturnValueExpectingResult(
+      "directFromSellerSignals.auctionSignals.length",
+      direct_from_seller_auction_signals_header_ad_slot_->length() -
+          std::string(R"("")").length());
+
+  direct_from_seller_seller_signals_header_ad_slot_ = R"("abcdefg")";
+  RunScoreAdWithReturnValueExpectingResult(
+      "directFromSellerSignals.sellerSignals.length",
+      direct_from_seller_seller_signals_header_ad_slot_->length() -
+          std::string(R"("")").length());
 }
 
 TEST_F(SellerWorkletTest, ScoreAdExperimentGroupIdParam) {
@@ -3084,6 +3111,19 @@
       /*expected_report_url=*/absl::nullopt);
 }
 
+TEST_F(SellerWorkletTest,
+       ReportResultDirectFromSellerSignalsHeaderAdSlotParam) {
+  direct_from_seller_auction_signals_header_ad_slot_ = R"("abcde")";
+  direct_from_seller_seller_signals_header_ad_slot_ = R"("abcdefg")";
+
+  const char kExpectedJson[] =
+      R"({"auctionSignals":"abcde", "sellerSignals":"abcdefg"})";
+
+  RunReportResultCreatedScriptExpectingResult(
+      "directFromSellerSignals", /*extra_code=*/std::string(), kExpectedJson,
+      /*expected_report_url=*/absl::nullopt);
+}
+
 TEST_F(SellerWorkletTest, ReportResultAuctionConfigParamPerBuyerTimeouts) {
   // Empty AuctionAdConfig, with nothing filled in, except the seller and
   // decision logic URL.
@@ -3250,7 +3290,9 @@
           ad_metadata_, bid_, bid_currency_,
           auction_ad_config_non_shared_params_,
           direct_from_seller_seller_signals_,
+          direct_from_seller_seller_signals_header_ad_slot_,
           direct_from_seller_auction_signals_,
+          direct_from_seller_auction_signals_header_ad_slot_,
           browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
           browser_signal_interest_group_owner_, browser_signal_render_url_,
           browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
@@ -3282,7 +3324,9 @@
       seller_worklet->ReportResult(
           auction_ad_config_non_shared_params_,
           direct_from_seller_seller_signals_,
+          direct_from_seller_seller_signals_header_ad_slot_,
           direct_from_seller_auction_signals_,
+          direct_from_seller_auction_signals_header_ad_slot_,
           browser_signals_other_seller_.Clone(),
           browser_signal_interest_group_owner_,
           browser_signal_buyer_and_seller_reporting_id_,
@@ -3320,7 +3364,10 @@
   base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper_.get());
   seller_worklet->ScoreAd(
       ad_metadata_, bid_, bid_currency_, auction_ad_config_non_shared_params_,
-      direct_from_seller_seller_signals_, direct_from_seller_auction_signals_,
+      direct_from_seller_seller_signals_,
+      direct_from_seller_seller_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_,
       browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
       browser_signal_interest_group_owner_, browser_signal_render_url_,
       browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
@@ -3346,7 +3393,9 @@
   base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper_.get());
   seller_worklet->ReportResult(
       auction_ad_config_non_shared_params_, direct_from_seller_seller_signals_,
+      direct_from_seller_seller_signals_header_ad_slot_,
       direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_,
       browser_signals_other_seller_.Clone(),
       browser_signal_interest_group_owner_,
       browser_signal_buyer_and_seller_reporting_id_, browser_signal_render_url_,
@@ -3991,7 +4040,10 @@
 
   seller_worklet->ScoreAd(
       ad_metadata_, bid_, bid_currency_, auction_ad_config_non_shared_params_,
-      direct_from_seller_seller_signals_, direct_from_seller_auction_signals_,
+      direct_from_seller_seller_signals_,
+      direct_from_seller_seller_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_,
       browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
       browser_signal_interest_group_owner_, browser_signal_render_url_,
       browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
@@ -4049,7 +4101,10 @@
 
   seller_worklet->ScoreAd(
       ad_metadata_, bid_, bid_currency_, auction_ad_config_non_shared_params_,
-      direct_from_seller_seller_signals_, direct_from_seller_auction_signals_,
+      direct_from_seller_seller_signals_,
+      direct_from_seller_seller_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_,
       browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
       browser_signal_interest_group_owner_, browser_signal_render_url_,
       browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
@@ -4712,7 +4767,10 @@
     seller_worklet->ScoreAd(
         ad_metadata_, i + 1, bid_currency_,
         auction_ad_config_non_shared_params_,
-        direct_from_seller_seller_signals_, direct_from_seller_auction_signals_,
+        direct_from_seller_seller_signals_,
+        direct_from_seller_seller_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_,
         browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
         browser_signal_interest_group_owner_, browser_signal_render_url_,
         browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
diff --git a/content/test/data/interest_group/bidding_argument_validator.js b/content/test/data/interest_group/bidding_argument_validator.js
index 7cdf4129..0ac3bae9 100644
--- a/content/test/data/interest_group/bidding_argument_validator.js
+++ b/content/test/data/interest_group/bidding_argument_validator.js
@@ -170,13 +170,15 @@
 function validateDirectFromSellerSignals(directFromSellerSignals) {
   const perBuyerSignalsJSON =
       JSON.stringify(directFromSellerSignals.perBuyerSignals);
-  if (perBuyerSignalsJSON !== '{"json":"for","buyer":[1]}') {
+  if (perBuyerSignalsJSON !== '{"json":"for","buyer":[1]}' &&
+      perBuyerSignalsJSON !== '{"buyer":[1],"json":"for"}') {
     throw 'Wrong directFromSellerSignals.perBuyerSignals ' +
         perBuyerSignalsJSON;
   }
   const auctionSignalsJSON =
       JSON.stringify(directFromSellerSignals.auctionSignals);
-  if (auctionSignalsJSON !== '{"json":"for","all":["parties"]}') {
+  if (auctionSignalsJSON !== '{"json":"for","all":["parties"]}' &&
+      auctionSignalsJSON !== '{"all":["parties"],"json":"for"}') {
     throw 'Wrong directFromSellerSignals.auctionSignals ' +
         auctionSignalsJSON;
   }
diff --git a/content/test/data/interest_group/component_auction_bidding_argument_validator.js b/content/test/data/interest_group/component_auction_bidding_argument_validator.js
index a7ac46f..2ea02c0 100644
--- a/content/test/data/interest_group/component_auction_bidding_argument_validator.js
+++ b/content/test/data/interest_group/component_auction_bidding_argument_validator.js
@@ -231,14 +231,17 @@
 function validateDirectFromSellerSignals(directFromSellerSignals) {
   const perBuyerSignalsJSON =
       JSON.stringify(directFromSellerSignals.perBuyerSignals);
-  if (perBuyerSignalsJSON !== '{"from":"component","json":"for","buyer":[1]}') {
+  if (perBuyerSignalsJSON !== '{"from":"component","json":"for","buyer":[1]}' &&
+      perBuyerSignalsJSON !== '{"buyer":[1],"from":"component","json":"for"}') {
     throw 'Wrong directFromSellerSignals.perBuyerSignals ' +
         perBuyerSignalsJSON;
   }
   const auctionSignalsJSON =
       JSON.stringify(directFromSellerSignals.auctionSignals);
   if (auctionSignalsJSON !==
-      '{"from":"component","json":"for","all":["parties"]}') {
+          '{"from":"component","json":"for","all":["parties"]}' &&
+      auctionSignalsJSON !==
+          '{"all":["parties"],"from":"component","json":"for"}') {
     throw 'Wrong directFromSellerSignals.auctionSignals ' +
         auctionSignalsJSON;
   }
diff --git a/content/test/data/interest_group/component_auction_component_decision_argument_validator.js b/content/test/data/interest_group/component_auction_component_decision_argument_validator.js
index aa86253a..c07843a 100644
--- a/content/test/data/interest_group/component_auction_component_decision_argument_validator.js
+++ b/content/test/data/interest_group/component_auction_component_decision_argument_validator.js
@@ -221,7 +221,9 @@
   const auctionSignalsJSON =
       JSON.stringify(directFromSellerSignals.auctionSignals);
   if (auctionSignalsJSON !==
-      '{"from":"component","json":"for","all":["parties"]}') {
+          '{"from":"component","json":"for","all":["parties"]}' &&
+      auctionSignalsJSON !==
+          '{"all":["parties"],"from":"component","json":"for"}') {
     throw 'Wrong directFromSellerSignals.auctionSignals ' +
         auctionSignalsJSON;
   }
diff --git a/content/test/data/interest_group/component_auction_top_level_decision_argument_validator.js b/content/test/data/interest_group/component_auction_top_level_decision_argument_validator.js
index 93b918c..fe20c805 100644
--- a/content/test/data/interest_group/component_auction_top_level_decision_argument_validator.js
+++ b/content/test/data/interest_group/component_auction_top_level_decision_argument_validator.js
@@ -228,7 +228,8 @@
   }
   const auctionSignalsJSON =
       JSON.stringify(directFromSellerSignals.auctionSignals);
-  if (auctionSignalsJSON !== '{"json":"for","all":["parties"]}') {
+  if (auctionSignalsJSON !== '{"json":"for","all":["parties"]}' &&
+      auctionSignalsJSON !== '{"all":["parties"],"json":"for"}') {
     throw 'Wrong directFromSellerSignals.auctionSignals ' +
         auctionSignalsJSON;
   }
diff --git a/content/test/data/interest_group/decision_argument_validator.js b/content/test/data/interest_group/decision_argument_validator.js
index 41ed09d..4f87ffe6 100644
--- a/content/test/data/interest_group/decision_argument_validator.js
+++ b/content/test/data/interest_group/decision_argument_validator.js
@@ -226,7 +226,8 @@
   }
   const auctionSignalsJSON =
       JSON.stringify(directFromSellerSignals.auctionSignals);
-  if (auctionSignalsJSON !== '{"json":"for","all":["parties"]}') {
+  if (auctionSignalsJSON !== '{"json":"for","all":["parties"]}' &&
+      auctionSignalsJSON !== '{"all":["parties"],"json":"for"}') {
     throw 'Wrong directFromSellerSignals.auctionSignals ' +
         auctionSignalsJSON;
   }
diff --git a/content/test/gpu/gpu_tests/context_lost_integration_test.py b/content/test/gpu/gpu_tests/context_lost_integration_test.py
index 6fde3bdb..ab0f12d 100644
--- a/content/test/gpu/gpu_tests/context_lost_integration_test.py
+++ b/content/test/gpu/gpu_tests/context_lost_integration_test.py
@@ -57,58 +57,17 @@
 
 feature_query_script = """
   function GetFeatureStatus(feature_name, for_hardware_gpu) {
-    let query_result;
-    const infoView = document.querySelector('info-view');
-    if (for_hardware_gpu) {
-      query_result = infoView.shadowRoot.querySelector(
-          '.feature-status-for-hardware-gpu-list');
-    } else {
-      query_result = infoView.shadowRoot.querySelector('.feature-status-list');
-    }
-    for (let i = 0; i < query_result.childElementCount; i++) {
-      let feature_status = query_result.children[i].textContent.split(': ');
-      if (feature_status.length == 2 && feature_status[0] == feature_name)
-        return feature_status[1];
-    }
-    return "";
+    return getGPUInfo(for_hardware_gpu
+        ? 'feature-status-for-hardware-gpu-list'
+        : 'feature-status-list', feature_name);
   }
 """
 
 vendor_id_query_script = """
   function GetActiveVendorId(for_hardware_gpu) {
-    let div;
-    const infoView = document.querySelector('info-view');
-    if (for_hardware_gpu) {
-      div = infoView.shadowRoot.querySelector(
-          '.basic-info-for-hardware-gpu-div');
-    } else {
-      div = infoView.shadowRoot.querySelector('#basic-info');
-    }
-    const table = div.querySelector('info-view-table');
-    let trs = table.shadowRoot.querySelectorAll('info-view-table-row');
-    let vendor_id = 0;
-    // The first four rows are "Initialization time", "In-process GPU",
-    // "Passthrough Command Decoder", and "Sandboxed".
-    for (let i = 4; i < trs.length; i++) {
-      let tds = trs[i].shadowRoot.querySelectorAll('div');
-      let token = tds[0].textContent.trim();
-      if (!token.startsWith('GPU'))
-        break;
-      if (i == 4 && token != 'GPU0')
-        break;
-      let gpu_string = tds[1].textContent.trim();
-      let vendor_info = gpu_string.split(', ')[0].split('= ');
-      if (vendor_info.length != 2 || vendor_info[0] != 'VENDOR')
-        break;
-      let id = parseInt(vendor_info[1]);
-      if (vendor_id == 0)
-        vendor_id = id;
-      if (gpu_string.endsWith('*ACTIVE*')) {
-        vendor_id = id;
-        break;
-      }
-    }
-    return vendor_id;
+    return getGPUInfo(for_hardware_gpu
+        ? 'active-gpu-for-hardware'
+        : 'active-gpu');
   }
 """
 
@@ -322,7 +281,7 @@
     tab.Navigate('chrome:gpu',
                  script_to_evaluate_on_commit=feature_query_script)
     tab.WaitForJavaScriptCondition('window.gpuPagePopulated', timeout=10)
-    status = (tab.EvaluateJavaScript('GetFeatureStatus("WebGL", %s)' %
+    status = (tab.EvaluateJavaScript('GetFeatureStatus("webgl", %s)' %
                                      ('true' if for_hardware_gpu else 'false')))
     tab.Close()
     return status
@@ -671,7 +630,7 @@
     self._NavigateAndWaitForLoad(test_path)
     # Check WebGL status at browser startup.
     webgl_status = self._GetWebGLFeatureStatus(False)
-    if webgl_status != 'Hardware accelerated':
+    if webgl_status != 'enabled':
       self.fail('WebGL should be hardware accelerated initially, but got %s' %
                 webgl_status)
     webgl_status_for_hardware_gpu = self._GetWebGLFeatureStatus(True)
@@ -681,12 +640,12 @@
     # Check WebGL status after three GPU crashes - fallback to SwiftShader.
     self._KillGPUProcess(3, True)
     webgl_status = self._GetWebGLFeatureStatus(False)
-    if webgl_status != 'Software only, hardware acceleration unavailable':
+    if webgl_status != 'unavailable_software':
       self.fail('WebGL should be software only with SwiftShader, but got %s' %
                 webgl_status)
     webgl_status_for_hardware_gpu = self._GetWebGLFeatureStatus(True)
-    if webgl_status_for_hardware_gpu != 'Hardware accelerated':
-      self.fail('WebGL status for hardware gpu should be "accelerated", '
+    if webgl_status_for_hardware_gpu != 'enabled':
+      self.fail('WebGL status for hardware gpu should be "enabled", '
                 'but got %s' % webgl_status_for_hardware_gpu)
     self._RestartBrowser('must restart after tests that kill the GPU process')
 
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
index cabc13a7..c2f5ca6 100644
--- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -38,12 +38,7 @@
   window.domAutomationController = domAutomationController;
 
   function GetDriverBugWorkarounds() {
-    var query_result = document.querySelector('info-view').shadowRoot
-        .querySelector('.workarounds-list');
-    var browser_list = []
-    for (var i=0; i < query_result.childElementCount; i++)
-      browser_list.push(query_result.children[i].textContent);
-    return browser_list;
+    return getGPUInfo('workarounds');
   };
 """
 
diff --git a/content/test/gpu/gpu_tests/hardware_accelerated_feature_integration_test.py b/content/test/gpu/gpu_tests/hardware_accelerated_feature_integration_test.py
index 8971385..54e6778 100644
--- a/content/test/gpu/gpu_tests/hardware_accelerated_feature_integration_test.py
+++ b/content/test/gpu/gpu_tests/hardware_accelerated_feature_integration_test.py
@@ -14,19 +14,7 @@
 
 test_harness_script = r"""
   function VerifyHardwareAccelerated(feature) {
-    feature += ': '
-    var list = document.querySelector('info-view').shadowRoot.querySelector(
-        '.feature-status-list');
-    for (var i=0; i < list.childElementCount; i++) {
-      var span_list = list.children[i].getElementsByTagName('span');
-      var feature_str = span_list[0].textContent;
-      var value_str = span_list[1].textContent;
-      if ((feature_str == feature) &&
-          (value_str == 'Hardware accelerated')) {
-        return true;
-      }
-    }
-    return false;
+    return getGPUInfo('feature-status-list', feature) === 'enabled';
   };
 """
 
@@ -61,7 +49,7 @@
 
   @classmethod
   def GenerateGpuTests(cls, options: ct.ParsedCmdArgs) -> ct.TestGenerator:
-    tests = ('WebGL', 'Canvas')
+    tests = ('webgl', '2d_canvas')
     for feature in tests:
       yield ('HardwareAcceleratedFeature_%s_accelerated' %
              safe_feature_name(feature), 'chrome://gpu', [feature])
diff --git a/extensions/browser/api/device_permissions_manager.cc b/extensions/browser/api/device_permissions_manager.cc
index 794b733..01b50d10 100644
--- a/extensions/browser/api/device_permissions_manager.cc
+++ b/extensions/browser/api/device_permissions_manager.cc
@@ -679,9 +679,10 @@
 DevicePermissionsManagerFactory::~DevicePermissionsManagerFactory() {
 }
 
-KeyedService* DevicePermissionsManagerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+DevicePermissionsManagerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new DevicePermissionsManager(context);
+  return std::make_unique<DevicePermissionsManager>(context);
 }
 
 BrowserContext* DevicePermissionsManagerFactory::GetBrowserContextToUse(
diff --git a/extensions/browser/api/device_permissions_manager.h b/extensions/browser/api/device_permissions_manager.h
index 0135321c..611a977 100644
--- a/extensions/browser/api/device_permissions_manager.h
+++ b/extensions/browser/api/device_permissions_manager.h
@@ -141,6 +141,9 @@
 // Manages saved device permissions for all extensions.
 class DevicePermissionsManager : public KeyedService {
  public:
+  explicit DevicePermissionsManager(content::BrowserContext* context);
+  ~DevicePermissionsManager() override;
+
   DevicePermissionsManager(const DevicePermissionsManager&) = delete;
   DevicePermissionsManager& operator=(const DevicePermissionsManager&) = delete;
 
@@ -187,9 +190,6 @@
   friend class DevicePermissionsManagerFactory;
   FRIEND_TEST_ALL_PREFIXES(DevicePermissionsManagerTest, SuspendExtension);
 
-  explicit DevicePermissionsManager(content::BrowserContext* context);
-  ~DevicePermissionsManager() override;
-
   DevicePermissions* GetInternal(const std::string& extension_id) const;
 
   base::ThreadChecker thread_checker_;
@@ -216,7 +216,7 @@
   ~DevicePermissionsManagerFactory() override;
 
   // BrowserContextKeyedServiceFactory implementation
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
diff --git a/extensions/browser/event_router_factory.cc b/extensions/browser/event_router_factory.cc
index 86ec42d..20f68c6 100644
--- a/extensions/browser/event_router_factory.cc
+++ b/extensions/browser/event_router_factory.cc
@@ -38,9 +38,10 @@
 EventRouterFactory::~EventRouterFactory() {
 }
 
-KeyedService* EventRouterFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+EventRouterFactory::BuildServiceInstanceForBrowserContext(
     BrowserContext* context) const {
-  return new EventRouter(context, ExtensionPrefs::Get(context));
+  return std::make_unique<EventRouter>(context, ExtensionPrefs::Get(context));
 }
 
 BrowserContext* EventRouterFactory::GetBrowserContextToUse(
diff --git a/extensions/browser/event_router_factory.h b/extensions/browser/event_router_factory.h
index d2f0c47..9e37a9d7 100644
--- a/extensions/browser/event_router_factory.h
+++ b/extensions/browser/event_router_factory.h
@@ -27,7 +27,7 @@
   ~EventRouterFactory() override;
 
   // BrowserContextKeyedServiceFactory implementation
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
diff --git a/extensions/browser/mock_extension_system.h b/extensions/browser/mock_extension_system.h
index a90472d0..ba0f529d 100644
--- a/extensions/browser/mock_extension_system.h
+++ b/extensions/browser/mock_extension_system.h
@@ -88,9 +88,9 @@
   ~MockExtensionSystemFactory() override = default;
 
   // BrowserContextKeyedServiceFactory overrides:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override {
-    return new T(context);
+    return std::make_unique<T>(context);
   }
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override {
diff --git a/extensions/browser/updater/update_service.h b/extensions/browser/updater/update_service.h
index 4fc2522..d779515 100644
--- a/extensions/browser/updater/update_service.h
+++ b/extensions/browser/updater/update_service.h
@@ -65,7 +65,6 @@
                                 UpdateFoundCallback update_found_callback,
                                 base::OnceClosure callback);
 
- protected:
   UpdateService(content::BrowserContext* context,
                 scoped_refptr<update_client::UpdateClient> update_client);
   ~UpdateService() override;
diff --git a/extensions/browser/updater/update_service_factory.cc b/extensions/browser/updater/update_service_factory.cc
index 84fceb3..849168c 100644
--- a/extensions/browser/updater/update_service_factory.cc
+++ b/extensions/browser/updater/update_service_factory.cc
@@ -4,6 +4,8 @@
 
 #include "extensions/browser/updater/update_service_factory.h"
 
+#include <memory>
+
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/update_client/update_client.h"
 #include "extensions/browser/extension_registry_factory.h"
@@ -32,9 +34,10 @@
 
 UpdateServiceFactory::~UpdateServiceFactory() = default;
 
-KeyedService* UpdateServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+UpdateServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new UpdateService(
+  return std::make_unique<UpdateService>(
       context, ExtensionsBrowserClient::Get()->CreateUpdateClient(context));
 }
 
diff --git a/extensions/browser/updater/update_service_factory.h b/extensions/browser/updater/update_service_factory.h
index e314db89..152e515 100644
--- a/extensions/browser/updater/update_service_factory.h
+++ b/extensions/browser/updater/update_service_factory.h
@@ -5,6 +5,8 @@
 #ifndef EXTENSIONS_BROWSER_UPDATER_UPDATE_SERVICE_FACTORY_H_
 #define EXTENSIONS_BROWSER_UPDATER_UPDATE_SERVICE_FACTORY_H_
 
+#include <memory>
+
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
@@ -29,7 +31,7 @@
   ~UpdateServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
diff --git a/gpu/command_buffer/service/service_utils.cc b/gpu/command_buffer/service/service_utils.cc
index f8deb87d..7e7ab4f 100644
--- a/gpu/command_buffer/service/service_utils.cc
+++ b/gpu/command_buffer/service/service_utils.cc
@@ -203,7 +203,8 @@
 }
 
 GrContextType ParseGrContextType(const base::CommandLine* command_line) {
-  if (base::FeatureList::IsEnabled(features::kSkiaGraphite)) {
+  if (base::FeatureList::IsEnabled(features::kSkiaGraphite) ||
+      command_line->HasSwitch(switches::kSkiaGraphiteBackend)) {
     [[maybe_unused]] auto value =
         command_line->GetSwitchValueASCII(switches::kSkiaGraphiteBackend);
 #if BUILDFLAG(SKIA_USE_DAWN)
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index d1aebd6..fb2bfc5d 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -35,6 +35,7 @@
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/config/gpu_crash_keys.h"
 #include "gpu/config/gpu_finch_features.h"
+#include "gpu/config/gpu_switches.h"
 #include "gpu/ipc/common/gpu_client_ids.h"
 #include "gpu/ipc/common/memory_stats.h"
 #include "gpu/ipc/service/gpu_channel.h"
@@ -85,7 +86,7 @@
 const int kMaxKeepAliveTimeMs = 200;
 #endif
 #if BUILDFLAG(IS_WIN)
-void TrimD3DResources() {
+void TrimD3DResources(const scoped_refptr<SharedContextState>& context_state) {
   // Graphics drivers periodically allocate internal memory buffers in
   // order to speed up subsequent rendering requests. These memory allocations
   // in general lead to increased memory usage by the overall system.
@@ -98,13 +99,22 @@
   // apps should only call Trim when going idle for a period of time or during
   // low memory conditions.
   Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
-      gl::QueryD3D11DeviceObjectFromANGLE();
+      context_state->GetD3D11Device();
   if (d3d11_device) {
     Microsoft::WRL::ComPtr<IDXGIDevice3> dxgi_device;
     if (SUCCEEDED(d3d11_device.As(&dxgi_device))) {
       dxgi_device->Trim();
     }
   }
+
+  Microsoft::WRL::ComPtr<ID3D11Device> angle_d3d11_device =
+      gl::QueryD3D11DeviceObjectFromANGLE();
+  if (angle_d3d11_device && angle_d3d11_device != d3d11_device) {
+    Microsoft::WRL::ComPtr<IDXGIDevice3> dxgi_device;
+    if (SUCCEEDED(angle_d3d11_device.As(&dxgi_device))) {
+      dxgi_device->Trim();
+    }
+  }
 }
 #endif
 
@@ -858,7 +868,7 @@
   if (gr_shader_cache_)
     gr_shader_cache_->PurgeMemory(memory_pressure_level);
 #if BUILDFLAG(IS_WIN)
-  TrimD3DResources();
+  TrimD3DResources(shared_context_state_);
 #endif
 }
 
@@ -976,10 +986,12 @@
 #if BUILDFLAG(IS_APPLE)
   const bool want_graphite = gr_context_type == GrContextType::kGraphiteDawn ||
                              gr_context_type == GrContextType::kGraphiteMetal;
+  const bool force_graphite = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSkiaGraphiteBackend);
   const bool is_angle_metal =
       gl::GetANGLEImplementation() == gl::ANGLEImplementation::kMetal;
   // Fallback from Graphite to Ganesh/GL if ANGLE is not using Metal too.
-  if (want_graphite && !is_angle_metal) {
+  if (want_graphite && !force_graphite && !is_angle_metal) {
     gr_context_type = GrContextType::kGL;
   }
 #endif
diff --git a/headless/lib/browser/headless_browser_main_parts_posix.cc b/headless/lib/browser/headless_browser_main_parts_posix.cc
index 7677c5c..4823468 100644
--- a/headless/lib/browser/headless_browser_main_parts_posix.cc
+++ b/headless/lib/browser/headless_browser_main_parts_posix.cc
@@ -4,15 +4,17 @@
 
 #include "headless/lib/browser/headless_browser_main_parts.h"
 
+#include <errno.h>
 #include <signal.h>
 #include <unistd.h>
 
+#include "base/files/file_descriptor_watcher_posix.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/no_destructor.h"
-#include "base/task/single_thread_task_runner.h"
+#include "base/posix/eintr_wrapper.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -35,6 +37,26 @@
 
 namespace {
 
+int g_read_fd = 0;
+int g_write_fd = 0;
+
+bool CreatePipe() {
+  CHECK(!g_read_fd);
+  CHECK(!g_write_fd);
+
+  int pipe_fd[2];
+  int result = pipe(pipe_fd);
+  if (result < 0) {
+    PLOG(ERROR) << "Could not create signal pipe";
+    return false;
+  }
+
+  g_read_fd = pipe_fd[0];
+  g_write_fd = pipe_fd[1];
+
+  return true;
+}
+
 class BrowserShutdownHandler {
  public:
   typedef base::OnceCallback<void(int)> ShutdownCallback;
@@ -75,19 +97,32 @@
   }
 
   void Init(ShutdownCallback shutdown_callback) {
-    task_runner_ = content::GetUIThreadTaskRunner({});
     shutdown_callback_ = std::move(shutdown_callback);
+
+    // We cannot just PostTask from a signal handler, so route the signal
+    // through a pipe.
+    CHECK(CreatePipe());
+
+    file_descriptor_watcher_controller_ =
+        base::FileDescriptorWatcher::WatchReadable(
+            g_read_fd,
+            base::BindRepeating(
+                &BrowserShutdownHandler::OnFileCanReadWithoutBlocking,
+                base::Unretained(this)));
+  }
+
+  // This is called whenever data is available in |g_read_fd|.
+  void OnFileCanReadWithoutBlocking() {
+    int pipe_data;
+    if (HANDLE_EINTR(read(g_read_fd, &pipe_data, sizeof(pipe_data))) > 0) {
+      Shutdown(pipe_data);
+    }
   }
 
   void Shutdown(int signal) {
     if (shutdown_callback_) {
       int exit_code = 0x80u + signal;
-      if (!task_runner_->PostTask(
-              FROM_HERE,
-              base::BindOnce(std::move(shutdown_callback_), exit_code))) {
-        RAW_LOG(WARNING, "No valid task runner, exiting ungracefully.");
-        kill(getpid(), signal);
-      }
+      std::move(shutdown_callback_).Run(exit_code);
     }
   }
 
@@ -114,11 +149,14 @@
     action.sa_handler = SIG_DFL;
     RAW_CHECK(sigaction(signal, &action, nullptr) == 0);
 
-    GetInstance().Shutdown(signal);
+    // Send signal number through the pipe.
+    int pipe_data = signal;
+    std::ignore = write(g_write_fd, &pipe_data, sizeof(pipe_data));
   }
 
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   ShutdownCallback shutdown_callback_;
+  std::unique_ptr<base::FileDescriptorWatcher::Controller>
+      file_descriptor_watcher_controller_;
 };
 
 }  // namespace
diff --git a/infra/config/lib/bootstrap.star b/infra/config/lib/bootstrap.star
index e6dd602..4b117ac 100644
--- a/infra/config/lib/bootstrap.star
+++ b/infra/config/lib/bootstrap.star
@@ -22,6 +22,7 @@
 //recipes.star for more information on bootstrappable recipes.
 """
 
+load("./chrome_settings.star", "per_builder_outputs_config")
 load("./nodes.star", "nodes")
 load("//project.star", "settings")
 
@@ -163,7 +164,9 @@
                 if builder_shadow_properties != None:
                     non_bootstrapped_shadow_properties = get_non_bootstrapped_properties(builder_shadow_properties)
 
-                properties_file = "builders/{}/{}/properties.json".format(bucket_name, builder_name)
+                root_out_dir = per_builder_outputs_config().root_dir
+                out_dir = "{}/{}/{}".format(root_out_dir, bucket_name, builder_name)
+                properties_file = "{}/properties.json".format(out_dir)
                 bootstrap_property = {
                     "top_level_project": {
                         "repo": {
@@ -175,7 +178,7 @@
                     "properties_file": "infra/config/generated/{}".format(properties_file),
                 }
                 if builder_shadow_properties:
-                    shadow_properties_file = "builders/{}/{}/shadow-properties.json".format(bucket_name, builder_name)
+                    shadow_properties_file = "{}/shadow-properties.json".format(out_dir)
                     bootstrap_property["shadow_properties_file"] = "infra/config/generated/{}".format(shadow_properties_file)
                     ctx.output[shadow_properties_file] = json.indent(json.encode(builder_shadow_properties), indent = "  ")
 
diff --git a/infra/config/lib/chrome_settings.star b/infra/config/lib/chrome_settings.star
new file mode 100644
index 0000000..1473991
--- /dev/null
+++ b/infra/config/lib/chrome_settings.star
@@ -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.
+"""Library for configuring global defaults for CBI libs.
+
+Generators can't access lucicfg vars, so in order to provide
+configuration for generators, the information must be present in the
+lucicfg graph. This file provides the chrome_settings struct that
+can be used to configure project-wide defaults. For generators to access
+this information, separate functions are provided for reading the
+information from the graph.
+"""
+
+load("./nodes.star", "nodes")
+
+_PER_BUILDER_OUTPUTS = nodes.create_singleton_node_type("per_builder_outputs")
+
+def _per_builder_outputs(*, root_dir):
+    """Configure per-builder outputs for the project.
+
+    Generators can get the config values using per_builder_outputs_config.
+
+    Args:
+        root_dir: The root directory in the generated output directory under
+            which per-builder outputs will be generated. Must be a non-empty
+            string.
+    """
+    if not root_dir or type(root_dir) != type(""):
+        fail("root_dir")
+    _PER_BUILDER_OUTPUTS.add(props = dict(
+        root_dir = root_dir,
+    ))
+
+def per_builder_outputs_config():
+    """Get the per-builder outputs config.
+
+    Returns:
+        A struct with the following attributes:
+        * root_dir: The name of the root directory to generate
+            per-builder outputs to.
+    """
+    node = _PER_BUILDER_OUTPUTS.get()
+    if node == None:
+        fail("In order to generate per-builder outputs, project.per_builder_outputs must be called")
+    return node.props
+
+chrome_settings = struct(
+    per_builder_outputs = _per_builder_outputs,
+)
diff --git a/infra/config/lib/nodes.star b/infra/config/lib/nodes.star
index b80a08e..d873bcdc 100644
--- a/infra/config/lib/nodes.star
+++ b/infra/config/lib/nodes.star
@@ -10,6 +10,51 @@
 
 _CHROMIUM_NS_KIND = "@chromium"
 
+def _create_singleton_node_type(kind):
+    """Create a singleton node type.
+
+    Singleton nodes types only allow for a single node of the type to exist.
+    This can be used for creating configuration nodes for generators since
+    generators are unable to access lucicfg vars.
+
+    Args:
+        kind: (str) An identifier for the kind of the node. Must be unique
+            within the chromium namespace.
+
+    Returns:
+        A node type that can be used for creating and getting a node of
+        the given kind.
+
+        The type has the following properties:
+        * kind: The kind of node of the type.
+
+        The node type has the following methods:
+        * key(): Creates a key for the node.
+        * add(**kwargs): Adds a node with a key created via `key()`.
+            `graph.add_node` will be called with the key and `**kwargs`.
+            Returns the key.
+        * get(): Gets the node with the key given by
+            `key(bucket_name, key_value)`.
+    """
+
+    def key():
+        return graph.key(_CHROMIUM_NS_KIND, "", kind, "")
+
+    def add(**kwargs):
+        k = key()
+        graph.add_node(k, **kwargs)
+        return k
+
+    def get():
+        return graph.node(key())
+
+    return struct(
+        kind = kind,
+        key = key,
+        add = add,
+        get = get,
+    )
+
 def _create_unscoped_node_type(kind, allow_unnamed = False):
     """Create an unscoped node type.
 
@@ -340,6 +385,7 @@
 
 nodes = struct(
     BUILDER = _BUILDER,
+    create_singleton_node_type = _create_singleton_node_type,
     create_unscoped_node_type = _create_unscoped_node_type,
     create_bucket_scoped_node_type = _create_bucket_scoped_node_type,
     create_node_type_with_builder_ref = _create_node_type_with_builder_ref,
diff --git a/infra/config/main.star b/infra/config/main.star
index d3579f12..56cf2f6 100755
--- a/infra/config/main.star
+++ b/infra/config/main.star
@@ -7,6 +7,7 @@
 # for information on starlark/lucicfg
 
 load("//lib/branches.star", "branches")
+load("//lib/chrome_settings.star", "chrome_settings")
 load("//project.star", "settings")
 
 lucicfg.check_version(
@@ -140,6 +141,10 @@
     tree_closing_enabled = True,
 )
 
+chrome_settings.per_builder_outputs(
+    root_dir = "builders",
+)
+
 # An all-purpose public realm.
 luci.realm(
     name = "public",
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 6059595..3495d4e 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2193,8 +2193,12 @@
       <message name="IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_TITLE" desc="Title for Lockdown Mode.">
         This setting is enabled on your device
       </message>
-      <message name="IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY" desc="Title for Lockdown Mode.">
-        To disable Lockdown Mode in Chrome turn it off on your device.
+
+      <message name="IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPAD" desc="iPad summary for lockdown mode info button">
+        To disable Lockdown Mode in Chrome turn it off on your iPad.
+      </message>
+      <message name="IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPHONE" desc="iPhone summary for lockdown mode info button">
+        To disable Lockdown Mode in Chrome turn it off on your iPhone.
       </message>
       <message name="IDS_IOS_LOCKDOWN_MODE_FOOTER" desc="Title for Lockdown Mode.">
         When turned on, certain web technologies are blocked, which might cause some websites to load more slowly or not operate correctly.
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY.png.sha1
deleted file mode 100644
index 65e7d063..0000000
--- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b12b0cc061d65f65e17170b8c8e8af7c5a4f3a5c
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPAD.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPAD.png.sha1
new file mode 100644
index 0000000..ce0f02e
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPAD.png.sha1
@@ -0,0 +1 @@
+16c4baf639ae094467377e2ee3af89fbd7b582bb
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPHONE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPHONE.png.sha1
new file mode 100644
index 0000000..1c8704d
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPHONE.png.sha1
@@ -0,0 +1 @@
+820831f8c416a5d89f132fa9c4b0fe8aaffb6d27
\ No newline at end of file
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container.mm b/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container.mm
index 9d20316a..0666f8a1 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container.mm
@@ -225,6 +225,7 @@
       return l10n_util::GetNSString(IDS_IOS_SET_UP_LIST_TITLE);
     case ContentSuggestionsModuleType::kSafetyCheck:
     case ContentSuggestionsModuleType::kSafetyCheckMultiRow:
+    case ContentSuggestionsModuleType::kSafetyCheckMultiRowOverflow:
       return l10n_util::GetNSString(IDS_IOS_SAFETY_CHECK_TITLE);
     default:
       NOTREACHED();
@@ -247,6 +248,7 @@
     case ContentSuggestionsModuleType::kMostVisited:
     case ContentSuggestionsModuleType::kShortcuts:
     case ContentSuggestionsModuleType::kSafetyCheckMultiRow:
+    case ContentSuggestionsModuleType::kSafetyCheckMultiRowOverflow:
       contentMargins.bottom = kReducedContentBottomInset;
       break;
     default:
@@ -342,6 +344,7 @@
 - (BOOL)shouldShowSeeMore {
   switch (_type) {
     case ContentSuggestionsModuleType::kCompactedSetUpList:
+    case ContentSuggestionsModuleType::kSafetyCheckMultiRowOverflow:
       return YES;
     default:
       return NO;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h
index 193c97d..5565159 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h
@@ -23,7 +23,8 @@
   kSetUpListAllSet = 6,
   kSafetyCheck = 7,
   kSafetyCheckMultiRow = 8,
-  kMaxValue = kSafetyCheckMultiRow,
+  kSafetyCheckMultiRowOverflow = 9,
+  kMaxValue = kSafetyCheckMultiRowOverflow,
 };
 
 // Represents the content suggestions collection view.
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
index f60d74f..c697202 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -975,16 +975,21 @@
   // different places in the Magic Stack depending on the Safety Check state(s).
   // However, for now, the module will simply be inserted at the front of the
   // Magic Stack.
+  int moduleIndex = 0;
 
-  int check_issues_count = CheckIssuesCount(_safetyCheckState);
+  int checkIssuesCount = CheckIssuesCount(_safetyCheckState);
 
-  if (check_issues_count > 1) {
+  if (checkIssuesCount > 2) {
+    [order insertObject:@(int(ContentSuggestionsModuleType::
+                                  kSafetyCheckMultiRowOverflow))
+                atIndex:moduleIndex];
+  } else if (checkIssuesCount > 1) {
     [order
         insertObject:@(int(ContentSuggestionsModuleType::kSafetyCheckMultiRow))
-             atIndex:0];
+             atIndex:moduleIndex];
   } else {
     [order insertObject:@(int(ContentSuggestionsModuleType::kSafetyCheck))
-                atIndex:0];
+                atIndex:moduleIndex];
   }
 }
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.mm
index d7c022a9..6c164bf 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.mm
@@ -76,6 +76,7 @@
     case ContentSuggestionsModuleType::kSetUpListAllSet:
     case ContentSuggestionsModuleType::kSafetyCheck:
     case ContentSuggestionsModuleType::kSafetyCheckMultiRow:
+    case ContentSuggestionsModuleType::kSafetyCheckMultiRowOverflow:
       break;
   }
   UMA_HISTOGRAM_ENUMERATION(kMagicStackTopModuleImpressionHistogram, type);
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index ea9637a5..ef8b104d 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -38,6 +38,7 @@
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h"
 #import "ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_state.h"
 #import "ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_view.h"
+#import "ios/chrome/browser/ui/content_suggestions/safety_check/types.h"
 #import "ios/chrome/browser/ui/content_suggestions/safety_check/utils.h"
 #import "ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_item_view.h"
 #import "ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_item_view_data.h"
@@ -672,8 +673,13 @@
   int checkIssuesCount = CheckIssuesCount(state);
 
   ContentSuggestionsModuleType type =
-      checkIssuesCount > 1 ? ContentSuggestionsModuleType::kSafetyCheckMultiRow
-                           : ContentSuggestionsModuleType::kSafetyCheck;
+      ContentSuggestionsModuleType::kSafetyCheck;
+
+  if (checkIssuesCount > 2) {
+    type = ContentSuggestionsModuleType::kSafetyCheckMultiRowOverflow;
+  } else if (checkIssuesCount > 1) {
+    type = ContentSuggestionsModuleType::kSafetyCheckMultiRow;
+  }
 
   [_magicStack insertArrangedSubview:self.safetyCheckModuleContainer
                              atIndex:[self indexForMagicStackModule:type]];
@@ -830,7 +836,15 @@
 }
 
 - (void)seeMoreWasTappedForModuleType:(ContentSuggestionsModuleType)type {
-  [self.audience showSetUpListShowMoreMenu];
+  if (type == ContentSuggestionsModuleType::kSafetyCheckMultiRowOverflow) {
+    [self.audience didSelectSafetyCheckItem:SafetyCheckItemType::kDefault];
+    return;
+  }
+
+  if (type == ContentSuggestionsModuleType::kCompactedSetUpList) {
+    [self.audience showSetUpListShowMoreMenu];
+    return;
+  }
 }
 
 - (void)neverShowModuleType:(ContentSuggestionsModuleType)type {
@@ -927,8 +941,13 @@
   int checkIssuesCount = CheckIssuesCount(state);
 
   ContentSuggestionsModuleType type =
-      checkIssuesCount > 1 ? ContentSuggestionsModuleType::kSafetyCheckMultiRow
-                           : ContentSuggestionsModuleType::kSafetyCheck;
+      ContentSuggestionsModuleType::kSafetyCheck;
+
+  if (checkIssuesCount > 2) {
+    type = ContentSuggestionsModuleType::kSafetyCheckMultiRowOverflow;
+  } else if (checkIssuesCount > 1) {
+    type = ContentSuggestionsModuleType::kSafetyCheckMultiRow;
+  }
 
   self.safetyCheckModuleContainer = [[MagicStackModuleContainer alloc]
       initWithContentView:self.safetyCheckView
@@ -1076,7 +1095,8 @@
         break;
       }
       case ContentSuggestionsModuleType::kSafetyCheck:
-      case ContentSuggestionsModuleType::kSafetyCheckMultiRow: {
+      case ContentSuggestionsModuleType::kSafetyCheckMultiRow:
+      case ContentSuggestionsModuleType::kSafetyCheckMultiRowOverflow: {
         if (IsSafetyCheckMagicStackEnabled()) {
           [_magicStack addArrangedSubview:self.safetyCheckModuleContainer];
         }
diff --git a/ios/chrome/browser/ui/settings/privacy/lockdown_mode/lockdown_mode_egtest.mm b/ios/chrome/browser/ui/settings/privacy/lockdown_mode/lockdown_mode_egtest.mm
index 84e4ca0..d84afd51 100644
--- a/ios/chrome/browser/ui/settings/privacy/lockdown_mode/lockdown_mode_egtest.mm
+++ b/ios/chrome/browser/ui/settings/privacy/lockdown_mode/lockdown_mode_egtest.mm
@@ -14,6 +14,7 @@
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/testing/earl_grey/earl_grey_test.h"
+#import "ui/base/device_form_factor.h"
 #import "ui/base/l10n/l10n_util.h"
 
 using chrome_test_util::ButtonWithAccessibilityLabelId;
@@ -117,10 +118,18 @@
   GREYAssert(WaitForPopupDisplay(l10n_util::GetNSString(
                  IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_TITLE)),
              @"Lockdown mode 'i' button wasn't tapped");
-  [[EarlGrey
-      selectElementWithMatcher:grey_text(l10n_util::GetNSString(
-                                   IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY))]
-      assertWithMatcher:grey_notNil()];
+
+  if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
+    [[EarlGrey selectElementWithMatcher:
+                   grey_text(l10n_util::GetNSString(
+                       IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPAD))]
+        assertWithMatcher:grey_notNil()];
+  } else {
+    [[EarlGrey selectElementWithMatcher:
+                   grey_text(l10n_util::GetNSString(
+                       IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPHONE))]
+        assertWithMatcher:grey_notNil()];
+  }
 }
 
 #pragma mark - Helpers
diff --git a/ios/chrome/browser/ui/settings/privacy/lockdown_mode/lockdown_mode_view_controller.mm b/ios/chrome/browser/ui/settings/privacy/lockdown_mode/lockdown_mode_view_controller.mm
index dbe106d..148f222 100644
--- a/ios/chrome/browser/ui/settings/privacy/lockdown_mode/lockdown_mode_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/privacy/lockdown_mode/lockdown_mode_view_controller.mm
@@ -12,11 +12,11 @@
 #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_info_button_item.h"
 #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_switch_cell.h"
 #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_switch_item.h"
-
 #import "ios/chrome/browser/ui/settings/elements/info_popover_view_controller.h"
 #import "ios/chrome/common/string_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/grit/ios_strings.h"
+#import "ui/base/device_form_factor.h"
 #import "ui/base/l10n/l10n_util_mac.h"
 
 namespace {
@@ -134,7 +134,13 @@
   };
 
   NSString* message;
-  message = l10n_util::GetNSString(IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY);
+  if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
+    message = l10n_util::GetNSString(
+        IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPAD);
+  } else {
+    message = l10n_util::GetNSString(
+        IDS_IOS_LOCKDOWN_MODE_INFO_BUTTON_SUMMARY_FOR_IPHONE);
+  }
   NSAttributedString* attributedString =
       [[NSAttributedString alloc] initWithString:message
                                       attributes:textAttributes];
diff --git a/media/capture/README.md b/media/capture/README.md
new file mode 100644
index 0000000..ea2439e2
--- /dev/null
+++ b/media/capture/README.md
@@ -0,0 +1 @@
+See [docs/media/capture/README.md](../../docs/media/capture/README.md)
diff --git a/media/gpu/vaapi/test/h265_decoder.cc b/media/gpu/vaapi/test/h265_decoder.cc
index 7e519e90..3d8b9c95 100644
--- a/media/gpu/vaapi/test/h265_decoder.cc
+++ b/media/gpu/vaapi/test/h265_decoder.cc
@@ -121,10 +121,10 @@
   state_ = kAfterReset;
 }
 
-H265Decoder::DecodeResult H265Decoder::Decode() {
+H265Decoder::DecodeResult H265Decoder::DecodeNALUs() {
   DCHECK(state_ != kError) << "Decoder in error state";
 
-  while (true) {
+  while (output_queue.empty()) {
     H265Parser::Result par_res;
 
     if (!curr_nalu_) {
@@ -293,6 +293,8 @@
              << static_cast<int>(curr_nalu_->nal_unit_type);
     curr_nalu_.reset();
   }
+
+  return kOk;
 }
 
 bool H265Decoder::ProcessPPS(int pps_id, bool* need_new_buffers) {
@@ -876,7 +878,7 @@
 
 VideoDecoder::Result H265Decoder::DecodeNextFrame() {
   while (!is_stream_over_ && output_queue.empty())
-    Decode();
+    DecodeNALUs();
 
   if (is_stream_over_)
     OutputAllRemainingPics();
diff --git a/media/gpu/vaapi/test/h265_decoder.h b/media/gpu/vaapi/test/h265_decoder.h
index 0b55398..03c9e49 100644
--- a/media/gpu/vaapi/test/h265_decoder.h
+++ b/media/gpu/vaapi/test/h265_decoder.h
@@ -79,6 +79,7 @@
                           // properly (e.g. allocate buffers with the new
                           // resolution).
     kRanOutOfStreamData,  // Need more stream data to proceed.
+    kOk,                  // Decoded a frame successfully.
   };
 
   // Process H265 stream structures.
@@ -142,9 +143,9 @@
   bool PerformDpbOperations(const H265SPS* sps);
 
   // This is the main method used for running the decode loop. It will try to
-  // decode all frames in the stream until there is a configuration change,
-  // error or the end of the stream is reached.
-  DecodeResult Decode();
+  // decode a single frame in the stream, or up until it reaches either a
+  // configuration change, or the end of the stream.
+  DecodeResult DecodeNALUs();
 
   // Decoder state.
   State state_;
diff --git a/media/remoting/README b/media/remoting/README.md
similarity index 100%
rename from media/remoting/README
rename to media/remoting/README.md
diff --git a/net/base/features.cc b/net/base/features.cc
index d600558..5569670 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -369,6 +369,19 @@
     &kEnableIpProtectionProxy, /*name=*/"IpPrivacyProxyAllowlist",
     /*default_value=*/""};
 
+const base::FeatureParam<std::string> kIpPrivacyTokenServer{
+    &kEnableIpProtectionProxy, /*name=*/"IpPrivacyTokenServer",
+    /*default_value=*/"https://autopush-phosphor-pa.sandbox.googleapis.com"};
+
+const base::FeatureParam<std::string> kIpPrivacyTokenServerGetInitialDataPath{
+    &kEnableIpProtectionProxy,
+    /*name=*/"IpPrivacyTokenServerGetInitialDataPath",
+    /*default_value=*/"/v1/getInitialData"};
+
+const base::FeatureParam<std::string> kIpPrivacyTokenServerGetTokensPath{
+    &kEnableIpProtectionProxy, /*name=*/"IpPrivacyTokenServerGetTokensPath",
+    /*default_value=*/"/v1/authWithHeaderCreds"};
+
 const base::FeatureParam<int> kIpPrivacyAuthTokenCacheBatchSize{
     &kEnableIpProtectionProxy, /*name=*/"IpPrivacyAuthTokenCacheBatchSize",
     /*default_value=*/64};
diff --git a/net/base/features.h b/net/base/features.h
index de2a3f7..c22eb086 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -385,6 +385,19 @@
 NET_EXPORT extern const base::FeatureParam<std::string>
     kIpPrivacyProxyAllowlist;
 
+// Sets the name of the IP protection auth token server.
+NET_EXPORT extern const base::FeatureParam<std::string> kIpPrivacyTokenServer;
+
+// Sets the path component of the IP protection auth token server URL used for
+// getting initial token signing data.
+NET_EXPORT extern const base::FeatureParam<std::string>
+    kIpPrivacyTokenServerGetInitialDataPath;
+
+// Sets the path component of the IP protection auth token server URL used for
+// getting blind-signed tokens.
+NET_EXPORT extern const base::FeatureParam<std::string>
+    kIpPrivacyTokenServerGetTokensPath;
+
 // Sets the batch size to fetch new auth tokens for IP protection.
 NET_EXPORT extern const base::FeatureParam<int>
     kIpPrivacyAuthTokenCacheBatchSize;
diff --git a/printing/backend/cups_helper.cc b/printing/backend/cups_helper.cc
index ac026d7e..7d908c8 100644
--- a/printing/backend/cups_helper.cc
+++ b/printing/backend/cups_helper.cc
@@ -403,6 +403,36 @@
   return true;
 }
 
+bool GetHpPjlColorAsGrayModeSettings(ppd_file_t* ppd,
+                                     mojom::ColorModel* color_model_for_black,
+                                     mojom::ColorModel* color_model_for_color,
+                                     bool* color_is_default) {
+  // Some HP printers use "HPPJLColorAsGray" attribute in their PPDs.
+  ppd_option_t* color_mode_option = ppdFindOption(ppd, kCUPSHpPjlColorAsGray);
+  if (!color_mode_option) {
+    return false;
+  }
+
+  if (ppdFindChoice(color_mode_option, kHpPjlColorAsGrayYes)) {
+    *color_model_for_black = mojom::ColorModel::kHpPjlColorAsGrayYes;
+  }
+
+  if (ppdFindChoice(color_mode_option, kHpPjlColorAsGrayNo)) {
+    *color_model_for_color = mojom::ColorModel::kHpPjlColorAsGrayNo;
+  }
+
+  ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kCUPSHpPjlColorAsGray);
+  if (!marked_choice) {
+    marked_choice =
+        ppdFindChoice(color_mode_option, color_mode_option->defchoice);
+  }
+  if (marked_choice) {
+    *color_is_default =
+        EqualsCaseInsensitiveASCII(marked_choice->choice, kHpPjlColorAsGrayNo);
+  }
+  return true;
+}
+
 bool GetCanonCNColorModeSettings(ppd_file_t* ppd,
                                  mojom::ColorModel* color_model_for_black,
                                  mojom::ColorModel* color_model_for_color,
@@ -707,6 +737,7 @@
          GetColorModeSettings(ppd, cm_black, cm_color, is_color) ||
          GetHPColorSettings(ppd, cm_black, cm_color, is_color) ||
          GetHPColorModeSettings(ppd, cm_black, cm_color, is_color) ||
+         GetHpPjlColorAsGrayModeSettings(ppd, cm_black, cm_color, is_color) ||
          GetBrotherColorSettings(ppd, cm_black, cm_color, is_color) ||
          GetCanonCNColorModeSettings(ppd, cm_black, cm_color, is_color) ||
          GetCanonCNIJGrayscaleSettings(ppd, cm_black, cm_color, is_color) ||
diff --git a/printing/backend/cups_helper_unittest.cc b/printing/backend/cups_helper_unittest.cc
index c44fa3c..8b2774d5 100644
--- a/printing/backend/cups_helper_unittest.cc
+++ b/printing/backend/cups_helper_unittest.cc
@@ -419,8 +419,9 @@
 }
 
 TEST(PrintBackendCupsHelperTest, PpdParsingHpPrinters) {
-  constexpr char kTestPpdData[] =
-      R"(*PPD-Adobe: "4.3"
+  {
+    constexpr char kTestPpdData[] =
+        R"(*PPD-Adobe: "4.3"
 *ColorDevice: True
 *OpenUI *HPColorMode/Mode: PickOne
 *DefaultHPColorMode: ColorPrint
@@ -430,14 +431,35 @@
   << /ProcessColorModel /DeviceGray >> setpagedevice"
 *CloseUI: *HPColorMode)";
 
-  PrinterSemanticCapsAndDefaults caps;
-  EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
-                                   kTestPpdData, &caps));
-  EXPECT_TRUE(caps.color_changeable);
-  EXPECT_TRUE(caps.color_default);
-  EXPECT_EQ(mojom::ColorModel::kHPColorColor, caps.color_model);
-  EXPECT_EQ(mojom::ColorModel::kHPColorBlack, caps.bw_model);
-  VerifyCapabilityColorModels(caps);
+    PrinterSemanticCapsAndDefaults caps;
+    EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
+                                     kTestPpdData, &caps));
+    EXPECT_TRUE(caps.color_changeable);
+    EXPECT_TRUE(caps.color_default);
+    EXPECT_EQ(mojom::ColorModel::kHPColorColor, caps.color_model);
+    EXPECT_EQ(mojom::ColorModel::kHPColorBlack, caps.bw_model);
+    VerifyCapabilityColorModels(caps);
+  }
+
+  {
+    constexpr char kTestPpdData[] =
+        R"(*PPD-Adobe: "4.3"
+*ColorDevice: True
+*OpenUI *HPPJLColorAsGray/Print Color as Gray: PickOne
+*DefaultHPPJLColorAsGray: no
+*HPPJLColorAsGray yes/On: " "
+*HPPJLColorAsGray no/Off: " "
+*CloseUI: *HPPJLColorAsGray)";
+
+    PrinterSemanticCapsAndDefaults caps;
+    EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
+                                     kTestPpdData, &caps));
+    EXPECT_TRUE(caps.color_changeable);
+    EXPECT_TRUE(caps.color_default);
+    EXPECT_EQ(mojom::ColorModel::kHpPjlColorAsGrayNo, caps.color_model);
+    EXPECT_EQ(mojom::ColorModel::kHpPjlColorAsGrayYes, caps.bw_model);
+    VerifyCapabilityColorModels(caps);
+  }
 }
 
 TEST(PrintBackendCupsHelperTest, PpdParsingCanonPrinters) {
diff --git a/printing/mojom/print.mojom b/printing/mojom/print.mojom
index 6c007213..b39b1f9a 100644
--- a/printing/mojom/print.mojom
+++ b/printing/mojom/print.mojom
@@ -51,6 +51,8 @@
   // Used in Xerox printer PPDs.
   [MinVersion=1] kXeroxXROutputColorPrintAsColor,
   [MinVersion=1] kXeroxXROutputColorPrintAsGrayscale,
+  [MinVersion=2] kHpPjlColorAsGrayNo,   // Used in HP printer PPDs.
+  [MinVersion=2] kHpPjlColorAsGrayYes,  // Used in HP printer PPDs.
 };
 
 // Print job duplex mode values.
diff --git a/printing/print_job_constants_cups.cc b/printing/print_job_constants_cups.cc
index fc8084c7..a5a2e6e 100644
--- a/printing/print_job_constants_cups.cc
+++ b/printing/print_job_constants_cups.cc
@@ -19,6 +19,7 @@
 const char kCUPSCanonCNIJGrayScale[] = "CNIJGrayScale";
 const char kCUPSEpsonInk[] = "Ink";
 const char kCUPSHpColorMode[] = "HPColorMode";
+const char kCUPSHpPjlColorAsGray[] = "HPPJLColorAsGray";
 const char kCUPSKonicaMinoltaSelectColor[] = "SelectColor";
 const char kCUPSLexmarkBLW[] = "BLW";
 const char kCUPSOkiControl[] = "OKControl";
@@ -44,6 +45,8 @@
 const char kHighGray[] = "High.Gray";
 const char kHpColorPrint[] = "ColorPrint";
 const char kHpGrayscalePrint[] = "GrayscalePrint";
+const char kHpPjlColorAsGrayNo[] = "no";
+const char kHpPjlColorAsGrayYes[] = "yes";
 const char kLexmarkBLWFalse[] = "FalseM";
 const char kLexmarkBLWTrue[] = "TrueM";
 const char kMono[] = "Mono";
@@ -75,6 +78,7 @@
       {kCUPSColorModel, kGray, kColor},                      // Generic
       {kCUPSEpsonInk, kEpsonMono, kEpsonColor},              // Epson
       {kCUPSHpColorMode, kHpGrayscalePrint, kHpColorPrint},  // HP
+      {kCUPSHpPjlColorAsGray, kHpPjlColorAsGrayYes, kHpPjlColorAsGrayNo},  // HP
       {kCUPSKonicaMinoltaSelectColor, kGrayscale, kColor},   // Konica Minolta
       {kCUPSLexmarkBLW, kLexmarkBLWTrue, kLexmarkBLWFalse},  // Lexmark
       {kCUPSOkiControl, kGray, kAuto},                       // Oki
diff --git a/printing/print_job_constants_cups.h b/printing/print_job_constants_cups.h
index 716db7b..cdd2619 100644
--- a/printing/print_job_constants_cups.h
+++ b/printing/print_job_constants_cups.h
@@ -31,6 +31,7 @@
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSCanonCNIJGrayScale[];
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSEpsonInk[];
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSHpColorMode[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSHpPjlColorAsGray[];
 COMPONENT_EXPORT(PRINTING_BASE)
 extern const char kCUPSKonicaMinoltaSelectColor[];
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kCUPSLexmarkBLW[];
@@ -57,6 +58,8 @@
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kHighGray[];
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kHpColorPrint[];
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kHpGrayscalePrint[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kHpPjlColorAsGrayNo[];
+COMPONENT_EXPORT(PRINTING_BASE) extern const char kHpPjlColorAsGrayYes[];
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kKonicaMinoltaColor[];
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kKonicaMinoltaGrayscale[];
 COMPONENT_EXPORT(PRINTING_BASE) extern const char kLexmarkBLWFalse[];
diff --git a/printing/print_settings.cc b/printing/print_settings.cc
index e6f6692..8f75e613 100644
--- a/printing/print_settings.cc
+++ b/printing/print_settings.cc
@@ -93,6 +93,14 @@
       *color_setting_name = kColor;
       *color_value = kBlack;
       break;
+    case mojom::ColorModel::kHpPjlColorAsGrayNo:
+      *color_setting_name = kCUPSHpPjlColorAsGray;
+      *color_value = kHpPjlColorAsGrayNo;
+      break;
+    case mojom::ColorModel::kHpPjlColorAsGrayYes:
+      *color_setting_name = kCUPSHpPjlColorAsGray;
+      *color_value = kHpPjlColorAsGrayYes;
+      break;
     case mojom::ColorModel::kPrintoutModeNormal:
       *color_setting_name = kCUPSPrintoutMode;
       *color_value = kNormal;
@@ -223,6 +231,7 @@
     case mojom::ColorModel::kRGBA:
     case mojom::ColorModel::kColorModeColor:
     case mojom::ColorModel::kHPColorColor:
+    case mojom::ColorModel::kHpPjlColorAsGrayNo:
     case mojom::ColorModel::kPrintoutModeNormal:
     case mojom::ColorModel::kProcessColorModelCMYK:
     case mojom::ColorModel::kProcessColorModelRGB:
@@ -242,6 +251,7 @@
     case mojom::ColorModel::kGrayscale:
     case mojom::ColorModel::kColorModeMonochrome:
     case mojom::ColorModel::kHPColorBlack:
+    case mojom::ColorModel::kHpPjlColorAsGrayYes:
     case mojom::ColorModel::kPrintoutModeNormalGray:
     case mojom::ColorModel::kProcessColorModelGreyscale:
     case mojom::ColorModel::kBrotherCUPSMono:
diff --git a/services/device/generic_sensor/fake_platform_sensor_and_provider.cc b/services/device/generic_sensor/fake_platform_sensor_and_provider.cc
index c382f97..7d1df16 100644
--- a/services/device/generic_sensor/fake_platform_sensor_and_provider.cc
+++ b/services/device/generic_sensor/fake_platform_sensor_and_provider.cc
@@ -70,6 +70,10 @@
   UpdateSharedBufferAndNotifyClients(reading);
 }
 
+void FakePlatformSensor::TriggerError() {
+  NotifySensorError();
+}
+
 FakePlatformSensorProvider::FakePlatformSensorProvider() {
   ON_CALL(*this, DoCreateSensorInternal(_, _, _))
       .WillByDefault(
diff --git a/services/device/generic_sensor/fake_platform_sensor_and_provider.h b/services/device/generic_sensor/fake_platform_sensor_and_provider.h
index ca906bb..3e0e2f3 100644
--- a/services/device/generic_sensor/fake_platform_sensor_and_provider.h
+++ b/services/device/generic_sensor/fake_platform_sensor_and_provider.h
@@ -33,6 +33,9 @@
   // Public interface to UpdateSharedBufferAndNotifyClients().
   void AddNewReading(const SensorReading& reading);
 
+  // Public interface to NotifySensorError().
+  void TriggerError();
+
  protected:
   void StopSensor() override {}
 
diff --git a/services/device/generic_sensor/generic_sensor_service_unittest.cc b/services/device/generic_sensor/generic_sensor_service_unittest.cc
index fb39afa..2b866b5 100644
--- a/services/device/generic_sensor/generic_sensor_service_unittest.cc
+++ b/services/device/generic_sensor/generic_sensor_service_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/barrier_closure.h"
 #include "base/functional/bind.h"
+#include "base/functional/callback_forward.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
@@ -51,7 +52,11 @@
       std::move(on_reading_changed_callback_).Run(reading_data_.als.value);
     }
   }
-  void RaiseError() override {}
+  void RaiseError() override {
+    if (on_error_callback_) {
+      std::move(on_error_callback_).Run();
+    }
+  }
 
   double WaitForReading() {
     base::test::TestFuture<double> future;
@@ -95,6 +100,11 @@
     on_reading_changed_callback_ = std::move(callback);
   }
 
+  // For RaiseError().
+  void SetOnErrorCallback(base::OnceClosure callback) {
+    on_error_callback_ = std::move(callback);
+  }
+
   mojom::Sensor* sensor() { return sensor_.get(); }
   void ResetSensor() { sensor_.reset(); }
 
@@ -108,6 +118,9 @@
   // |on_reading_changed_callback_| is called to verify the data is same as we
   // expected in SensorReadingChanged().
   base::OnceCallback<void(double)> on_reading_changed_callback_;
+
+  base::OnceClosure on_error_callback_;
+
   SensorType type_;
 };
 
@@ -317,6 +330,39 @@
   EXPECT_TRUE(client->AddConfigurationSync(PlatformSensorConfiguration(31.0)));
 }
 
+// Tests that error notifications are delivered even if a sensor is suspended.
+TEST_F(GenericSensorServiceTest, ErrorWhileSuspendedTest) {
+  auto client = std::make_unique<TestSensorClient>(SensorType::AMBIENT_LIGHT);
+  {
+    base::RunLoop run_loop;
+    sensor_provider_->GetSensor(
+        SensorType::AMBIENT_LIGHT,
+        base::BindOnce(&TestSensorClient::OnSensorCreated,
+                       base::Unretained(client.get()), run_loop.QuitClosure()));
+    run_loop.Run();
+  }
+
+  client->sensor()->Suspend();
+
+  // Expect that SensorReadingChanged() will not be called.
+  client->SetOnReadingChangedCallback(
+      base::BindOnce([](double) { ADD_FAILURE() << "Unexpected reading."; }));
+
+  EXPECT_TRUE(client->AddConfigurationSync(PlatformSensorConfiguration(30.0)));
+
+  // Expect that RaiseError() will be called.
+  base::test::TestFuture<void> error_future;
+  client->SetOnErrorCallback(error_future.GetCallback());
+
+  auto scoped_sensor =
+      fake_platform_sensor_provider_->GetSensor(SensorType::AMBIENT_LIGHT);
+  auto* fake_platform_sensor =
+      static_cast<FakePlatformSensor*>(scoped_sensor.get());
+  fake_platform_sensor->TriggerError();
+
+  EXPECT_TRUE(error_future.Wait());
+}
+
 // Test suspend and resume. After resuming, client can add configuration and
 // be notified by SensorReadingChanged() as usual.
 TEST_F(GenericSensorServiceTest, SuspendThenResumeTest) {
diff --git a/services/device/generic_sensor/sensor_impl.cc b/services/device/generic_sensor/sensor_impl.cc
index ad65fe3a..1887960 100644
--- a/services/device/generic_sensor/sensor_impl.cc
+++ b/services/device/generic_sensor/sensor_impl.cc
@@ -64,7 +64,6 @@
 }
 
 void SensorImpl::OnSensorError() {
-  DCHECK(!suspended_);
   if (client_)
     client_->RaiseError();
 }
diff --git a/services/network/network_service_proxy_allow_list.cc b/services/network/network_service_proxy_allow_list.cc
index db249bc..c6860b9 100644
--- a/services/network/network_service_proxy_allow_list.cc
+++ b/services/network/network_service_proxy_allow_list.cc
@@ -4,8 +4,6 @@
 //
 #include "services/network/network_service_proxy_allow_list.h"
 
-#include <memory>
-
 #include "base/command_line.h"
 #include "base/strings/strcat.h"
 #include "components/privacy_sandbox/masked_domain_list/masked_domain_list.pb.h"
@@ -15,6 +13,30 @@
 #include "services/network/public/cpp/network_switches.h"
 
 namespace network {
+namespace {
+
+void AddBypassRulesForDomain(net::ProxyBypassRules& bypass_rules,
+                             const std::string& domain) {
+  CHECK(bypass_rules.AddRuleFromString(domain));
+  if (!(domain.starts_with(".") || domain.starts_with("*"))) {
+    // Also bypass proxy for any subdomains.
+    CHECK(bypass_rules.AddRuleFromString("." + domain));
+  }
+}
+
+net::ProxyBypassRules BuildBypassRules(
+    const masked_domain_list::ResourceOwner& resource_owner) {
+  net::ProxyBypassRules bypass_rules;
+  for (auto resource : resource_owner.owned_resources()) {
+    AddBypassRulesForDomain(bypass_rules, resource.domain());
+  }
+  for (auto property : resource_owner.owned_properties()) {
+    AddBypassRulesForDomain(bypass_rules, property);
+  }
+  return bypass_rules;
+}
+
+}  // namespace
 
 NetworkServiceProxyAllowList::NetworkServiceProxyAllowList() {
   custom_proxy_config_ = network::mojom::CustomProxyConfig::New();
@@ -161,14 +183,8 @@
   // domains that will allow proxy bypass.
   allow_list_with_bypass_map_.clear();
   for (auto owner : mdl.resource_owners()) {
-    net::ProxyBypassRules bypass_rules;
+    net::ProxyBypassRules bypass_rules = BuildBypassRules(owner);
     for (auto resource : owner.owned_resources()) {
-      for (auto property : owner.owned_properties()) {
-        CHECK(bypass_rules.AddRuleFromString(property));
-        // Also bypass proxy for any subdomains.
-        CHECK(bypass_rules.AddRuleFromString("." + property));
-      }
-
       AddDomainRules(resource.domain(), bypass_rules);
     }
   }
diff --git a/services/network/network_service_proxy_allow_list_unittest.cc b/services/network/network_service_proxy_allow_list_unittest.cc
index e4c9bcf2..17554b89 100644
--- a/services/network/network_service_proxy_allow_list_unittest.cc
+++ b/services/network/network_service_proxy_allow_list_unittest.cc
@@ -185,7 +185,11 @@
     // subdomains) in the MDL should be not be proxied when the top-level site
     // is a property with the same owner as the resource.
     MatchTest{"3PRsrcInPropSameOwner", "acme-ra.com", "acme-pa.com", false},
-    MatchTest{"3PRsrcInRsrcSameOwner", "acme-ra.com", "acme-rb.co.uk", true},
+    MatchTest{"3PRsrcInRsrcSameOwner", "acme-ra.com", "acme-rb.co.uk", false},
+    MatchTest{"3PRsrcInSubRsrcSameOwner", "acme-ra.com", "sub.acme-rb.co.uk",
+              false},
+    MatchTest{"3PSubRsrcInSubRsrcSameOwner", "sub.acme-ra.com",
+              "sub.acme-rb.co.uk", false},
     MatchTest{"3PSubSameOwner", "sub.acme-ra.com", "acme-pa.com", false},
     MatchTest{"3PSubSubSameOwner", "sub.sub.acme-ra.com", "acme-pa.com", false},
 };
diff --git a/testing/buildbot/filters/android.emulator_o.chrome_public_test_apk.filter b/testing/buildbot/filters/android.emulator_o.chrome_public_test_apk.filter
index 88fcba9..2eb5e465 100644
--- a/testing/buildbot/filters/android.emulator_o.chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/android.emulator_o.chrome_public_test_apk.filter
@@ -4,8 +4,5 @@
 # TODO(crbug/1345504)
 -org.chromium.chrome.browser.shape_detection.ShapeDetectionTest.testTextDetection
 
-# TODO(crbug/1465894)
--org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.PasswordAccessoryIntegrationTest.testPasswordSheetDisplaysProvidedItems
-
 # TODO(crbug/1469692)
 -org.chromium.chrome.browser.browsing_data.ClearBrowsingDataFragmentBasicTest.testRenderSearchHistoryLinkSignedOutKnownNonGoogleDSE
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 79ff961..ddfc5ca 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -13181,6 +13181,21 @@
             ]
         }
     ],
+    "RestoreTabsOnFRE": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "RestoreTabsOnFRE"
+                    ]
+                }
+            ]
+        }
+    ],
     "RestoreUmaClientIdIndependentLogs": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_bypass_option.mojom b/third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_bypass_option.mojom
index 66a7a69..434cbf4 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_bypass_option.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_bypass_option.mojom
@@ -15,4 +15,5 @@
   kBypassOnlyIfServiceWorkerNotStarted,
   kRaceNetworkRequest,
   kRaceNetworkRequestHoldback,
+  kAutoPreload,
 };
diff --git a/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py b/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
index ec263718..053b5f02 100755
--- a/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
+++ b/third_party/blink/renderer/build/scripts/core/style/make_computed_style_base.py
@@ -30,6 +30,8 @@
     'RotateTransformOperation',
     'TranslateTransformOperation',
     'NGGridTrackList',
+    'StyleHighlightData',
+    'FilterOperations',
     'ComputedGridTrackList',
     'absl::optional<gfx::Size>',
     'double',
@@ -46,7 +48,6 @@
     'ScrollStartData',
     'AtomicString',
     'scoped_refptr',
-    'Persistent',
     'std::unique_ptr',
     'Vector<String>',
     'Font',
@@ -59,6 +60,8 @@
     'StyleIntrinsicLength',
     'absl::optional<StyleScrollbarColor>',
     'absl::optional<StyleOverflowClipMargin>',
+    # Compressed builds a Member can be 32 bits, vs. a pointer will be 64.
+    'Member',
     # Aligns like float
     'absl::optional<Length>',
     'StyleInitialLetter',
diff --git a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
index 097b0f2..ce5a872 100644
--- a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl
@@ -15,21 +15,6 @@
 
 namespace blink {
 
-struct SameSizeVerifierForComputedStyleBase {
-  {% if computed_style.subgroups is defined %}
-  void* data_refs[{{computed_style.subgroups|length}}];
-  {% endif %}
-  {% for field in computed_style.fields|rejectattr("is_bit_field") %}
-  {{field.type_name}} {{field.name}};
-  {% endfor %}
-  unsigned bit_fields[{{computed_style.num_32_bit_words_for_bit_fields}}];
-};
-
-// If this fails, the packing algorithm in make_computed_style_base.py has
-// failed to produce the optimal packed size. To fix, update the algorithm to
-// ensure that the buckets are placed so that each takes up at most 1 word.
-ASSERT_SIZE(ComputedStyleBase, SameSizeVerifierForComputedStyleBase);
-
 // Constructor and destructor are protected so that only the parent class ComputedStyle
 // can instantiate this class.
 ComputedStyleBase::ComputedStyleBase() :
@@ -69,6 +54,10 @@
 {% endfor %}
 }
 
+void ComputedStyleBase::Trace(Visitor* visitor) const {
+  static_cast<const ComputedStyle*>(this)->TraceAfterDispatch(visitor);
+}
+
 {% for name, groups_to_diff in diff_functions_map.items() %}
 bool ComputedStyleBase::{{name}}(const ComputedStyle& a, const ComputedStyle& b) {
   {{fieldwise_diff(groups_to_diff)|indent(4)}}
diff --git a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.h.tmpl b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.h.tmpl
index 1882284..7f9bc91 100644
--- a/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.h.tmpl
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/style/data_ref.h"
 #include "third_party/blink/renderer/core/style/member_copy.h"
 #include "third_party/blink/renderer/core/style/computed_style_initial_values.h"
+#include "third_party/blink/renderer/core/style/style_cached_data.h"
 {% for path in include_paths %}
 #include "{{path}}"
 {% endfor %}
@@ -90,7 +91,7 @@
 // example, a field with the 'keyword' template has only one setter, whereas an
 // 'external' field has an extra setter that takes an rvalue reference. A list
 // of the available templates can be found in css_properties.json5.
-class ComputedStyleBase {
+class ComputedStyleBase : public GarbageCollected<ComputedStyleBase> {
   // Properties with protected accessors must be friends because
   // Longhand::Apply* functions typically need the "raw" computed value:
   {% for property in longhands %}
@@ -192,6 +193,18 @@
   CORE_EXPORT Vector<DebugDiff> DebugDiffFields(const ComputedStyleBase& o) const;
 #endif // DCHECK_IS_ON()
 
+  CORE_EXPORT void Trace(Visitor* visitor) const;
+  void TraceAfterDispatch(Visitor* visitor) const {
+    {% for subgroup in computed_style.subgroups %}
+    visitor->Trace({{subgroup.member_name}});
+    {% endfor %}
+    {% for field in computed_style.fields %}
+    {% if field.wrapper_pointer_name == 'Member' %}
+    visitor->Trace({{field.name}});
+    {% endif %}
+    {% endfor %}
+  }
+
  private:
   {% for subgroup in computed_style.subgroups %}
   {{declare_field_group_class(subgroup)|indent(2)}}
@@ -215,8 +228,6 @@
   {% endif %}
   {% endfor %}
 
-  ~ComputedStyleBase() = default;
-
  private:
   friend class ComputedStyleBuilder;
   friend class ComputedStyleBuilderBase;
@@ -296,4 +307,21 @@
 
 }  // namespace blink
 
+namespace blink {
+{% for group in computed_style.all_subgroups|sort(attribute='name') %}
+template <typename T>
+struct ThreadingTrait<
+    T,
+    std::enable_if_t<std::is_base_of<blink::ComputedStyleBase::{{group.type_name}}, T>::value>> {
+  static constexpr ThreadAffinity kAffinity = kMainThreadOnly;
+};
+{% endfor %}
+template <typename T>
+struct ThreadingTrait<
+    T,
+    std::enable_if_t<std::is_base_of<blink::ComputedStyleBase, T>::value>> {
+  static constexpr ThreadAffinity kAffinity = kMainThreadOnly;
+};
+}  // namespace blink
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COMPUTED_STYLE_BASE_H_
diff --git a/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl b/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl
index af753cd..f70dbfd 100644
--- a/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl
@@ -210,7 +210,7 @@
   {% else -%}
     {{comma()}}{{member}}({{parent}} == {{noninherited}}
         ? {{parent}}
-        : DataRef(base::AdoptRef(new {{subgroup.type_name}}(*{{noninherited}}, *{{parent}}))))
+        : DataRef(MakeGarbageCollected<{{subgroup.type_name}}>(*{{noninherited}}, *{{parent}})))
   {% endif %}
 {% endfor %}
 {% for field in group.fields %}
diff --git a/third_party/blink/renderer/build/scripts/templates/fields/group.tmpl b/third_party/blink/renderer/build/scripts/templates/fields/group.tmpl
index 780a2d1..167771d 100644
--- a/third_party/blink/renderer/build/scripts/templates/fields/group.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/fields/group.tmpl
@@ -5,13 +5,16 @@
 {{declare_field_group_class(subgroup)}}
 
 {% endfor %}
-class {{group.type_name}} : public RefCounted<{{group.type_name}}> {
+class {{group.type_name}} : public GarbageCollected<{{group.type_name}}> {
  public:
-  static scoped_refptr<{{group.type_name}}> Create() {
-    return base::AdoptRef(new {{group.type_name}});
+  explicit {{group.type_name}}();
+  CORE_EXPORT {{group.type_name}}(const {{group.type_name}}&);
+
+  static {{group.type_name}}* Create() {
+    return MakeGarbageCollected<{{group.type_name}}>();
   }
-  scoped_refptr<{{group.type_name}}> Copy() const {
-    return base::AdoptRef(new {{group.type_name}}(*this));
+  {{group.type_name}}* Copy() const {
+    return MakeGarbageCollected<{{group.type_name}}>(*this);
   }
 
   {% if group.all_fields|selectattr("is_inherited")|list|length > 0 and
@@ -25,23 +28,17 @@
     }
   {% endif %}
 
-  // See comments in ComputedStyle.
-  void* operator new(size_t size) {
-    DCHECK(IsMainThread());
-    if (freelist_ != nullptr) {
-      {{group.type_name}}* ret = freelist_;
-      freelist_ = nullptr;
-      return ret;
-    }
-    return ::WTF::Partitions::FastMalloc(size, "{{group.type_name}}");
-  }
-  void operator delete(void* p) {
-    DCHECK(IsMainThread());
-    if (freelist_ == nullptr) {
-      freelist_ = static_cast<{{group.type_name}}*>(p);
-    } else {
-      ::WTF::Partitions::FastFree(p);
-    }
+  CORE_EXPORT void Trace(Visitor* visitor) const {
+  {% for subgroup in group.subgroups %}
+    visitor->Trace({{subgroup.member_name}});
+  {% endfor %}
+  {% for field in group.fields %}
+    {% if field.wrapper_pointer_name == 'Member' %}
+    visitor->Trace({{field.name}});
+    {% elif not field.size and not field.wrapper_pointer_name %}
+    TraceIfNeeded<{{field.type_name}}>::Trace(visitor, {{field.name}});
+    {% endif %}
+  {% endfor %}
   }
 
   bool operator==(const {{group.type_name}}& other) const {
@@ -63,12 +60,6 @@
   {% for field in group.fields %}
   {{declare_storage(field)}}
   {% endfor %}
-
- private:
-  {{group.type_name}}();
-  CORE_EXPORT {{group.type_name}}(const {{group.type_name}}&);
-
-  CORE_EXPORT static {{group.type_name}}* freelist_;
 };
 {%- endmacro %}
 
@@ -100,7 +91,4 @@
      {% endif %}
   {% endfor %}
   {}
-
-CORE_EXPORT ComputedStyleBase::{{group.type_name}}*
-ComputedStyleBase::{{group.type_name}}::freelist_ = nullptr;
 {%- endmacro %}
diff --git a/third_party/blink/renderer/core/animation/animation_utils.cc b/third_party/blink/renderer/core/animation/animation_utils.cc
index 0b7ced5..f689901d 100644
--- a/third_party/blink/renderer/core/animation/animation_utils.cc
+++ b/third_party/blink/renderer/core/animation/animation_utils.cc
@@ -37,7 +37,7 @@
     return;
 
   StyleResolver& resolver = target->GetDocument().GetStyleResolver();
-  scoped_refptr<const ComputedStyle> style =
+  const ComputedStyle* style =
       resolver.StyleForInterpolations(*target, interpolations);
 
   for (const auto& property : properties) {
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index 08ede45..2a53bd2 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -200,7 +200,7 @@
       const Timing& timing,
       const KeyframeEffectModelBase& effect) {
     // TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
-    auto style = GetDocument().GetStyleResolver().ResolveStyle(
+    const auto* style = GetDocument().GetStyleResolver().ResolveStyle(
         element_, StyleRecalcContext());
     effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
                                                      nullptr);
@@ -500,7 +500,7 @@
     // As the compositor code only understands CompositorKeyframeValues, we must
     // snapshot the effect to make those available.
     // TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
-    auto style = GetDocument().GetStyleResolver().ResolveStyle(
+    const auto* style = GetDocument().GetStyleResolver().ResolveStyle(
         element_, StyleRecalcContext());
     effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
                                                      nullptr);
@@ -672,7 +672,7 @@
   SetCustomProperty("--x", "5");
 
   UpdateAllLifecyclePhasesForTest();
-  auto style = GetDocument().GetStyleResolver().ResolveStyle(
+  const auto* style = GetDocument().GetStyleResolver().ResolveStyle(
       element_, StyleRecalcContext());
   EXPECT_TRUE(style->NonInheritedVariables());
   EXPECT_TRUE(style->NonInheritedVariables()
diff --git a/third_party/blink/renderer/core/animation/css/css_animation_update.cc b/third_party/blink/renderer/core/animation/css/css_animation_update.cc
index 4b14fb2..50aca22 100644
--- a/third_party/blink/renderer/core/animation/css/css_animation_update.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animation_update.cc
@@ -52,19 +52,14 @@
 
 void CSSAnimationUpdate::StartTransition(
     const PropertyHandle& property,
-    scoped_refptr<const ComputedStyle> from,
-    scoped_refptr<const ComputedStyle> to,
-    scoped_refptr<const ComputedStyle> reversing_adjusted_start_value,
+    const ComputedStyle* from,
+    const ComputedStyle* to,
+    const ComputedStyle* reversing_adjusted_start_value,
     double reversing_shortening_factor,
     const InertEffect& effect) {
-  NewTransition* new_transition = MakeGarbageCollected<NewTransition>();
-  new_transition->property = property;
-  new_transition->from = std::move(from);
-  new_transition->to = std::move(to);
-  new_transition->reversing_adjusted_start_value =
-      std::move(reversing_adjusted_start_value);
-  new_transition->reversing_shortening_factor = reversing_shortening_factor;
-  new_transition->effect = &effect;
+  NewTransition* new_transition = MakeGarbageCollected<NewTransition>(
+      property, from, to, reversing_adjusted_start_value,
+      reversing_shortening_factor, &effect);
   new_transitions_.Set(property, new_transition);
 }
 
@@ -72,7 +67,4 @@
   new_transitions_.erase(property);
 }
 
-CSSAnimationUpdate::NewTransition::NewTransition() = default;
-CSSAnimationUpdate::NewTransition::~NewTransition() = default;
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/css/css_animation_update.h b/third_party/blink/renderer/core/animation/css/css_animation_update.h
index b472dedd..131b682 100644
--- a/third_party/blink/renderer/core/animation/css/css_animation_update.h
+++ b/third_party/blink/renderer/core/animation/css/css_animation_update.h
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
 #include "third_party/blink/renderer/core/css/css_property_equality.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/core/style/scoped_css_name.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
@@ -180,13 +181,12 @@
     updated_compositor_keyframes_.push_back(animation);
   }
 
-  void StartTransition(
-      const PropertyHandle&,
-      scoped_refptr<const ComputedStyle> from,
-      scoped_refptr<const ComputedStyle> to,
-      scoped_refptr<const ComputedStyle> reversing_adjusted_start_value,
-      double reversing_shortening_factor,
-      const InertEffect&);
+  void StartTransition(const PropertyHandle&,
+                       const ComputedStyle* from,
+                       const ComputedStyle* to,
+                       const ComputedStyle* reversing_adjusted_start_value,
+                       double reversing_shortening_factor,
+                       const InertEffect&);
   void UnstartTransition(const PropertyHandle&);
   void CancelTransition(const PropertyHandle& property) {
     cancelled_transitions_.insert(property);
@@ -232,14 +232,29 @@
 
   struct NewTransition : public GarbageCollected<NewTransition> {
    public:
-    NewTransition();
-    virtual ~NewTransition();
-    void Trace(Visitor* visitor) const { visitor->Trace(effect); }
+    NewTransition(const PropertyHandle& property,
+                  const ComputedStyle* from,
+                  const ComputedStyle* to,
+                  const ComputedStyle* reversing_adjusted_start_value,
+                  double reversing_shortening_factor,
+                  const InertEffect* effect)
+        : property(property),
+          from(from),
+          to(to),
+          reversing_adjusted_start_value(reversing_adjusted_start_value),
+          reversing_shortening_factor(reversing_shortening_factor),
+          effect(effect) {}
+    void Trace(Visitor* visitor) const {
+      visitor->Trace(from);
+      visitor->Trace(to);
+      visitor->Trace(reversing_adjusted_start_value);
+      visitor->Trace(effect);
+    }
 
     PropertyHandle property = HashTraits<blink::PropertyHandle>::EmptyValue();
-    scoped_refptr<const ComputedStyle> from;
-    scoped_refptr<const ComputedStyle> to;
-    scoped_refptr<const ComputedStyle> reversing_adjusted_start_value;
+    Member<const ComputedStyle> from;
+    Member<const ComputedStyle> to;
+    Member<const ComputedStyle> reversing_adjusted_start_value;
     double reversing_shortening_factor;
     Member<const InertEffect> effect;
   };
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index 88c9f7b..3e6e056 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -2132,15 +2132,6 @@
     if (suppressed_transitions.Contains(property))
       continue;
 
-    RunningTransition* running_transition =
-        MakeGarbageCollected<RunningTransition>();
-    running_transition->from = new_transition->from;
-    running_transition->to = new_transition->to;
-    running_transition->reversing_adjusted_start_value =
-        new_transition->reversing_adjusted_start_value;
-    running_transition->reversing_shortening_factor =
-        new_transition->reversing_shortening_factor;
-
     const InertEffect* inert_animation = new_transition->effect.Get();
     TransitionEventDelegate* event_delegate =
         MakeGarbageCollected<TransitionEventDelegate>(element, property);
@@ -2164,7 +2155,12 @@
                               ASSERT_NO_EXCEPTION);
     }
     animation->Update(kTimingUpdateOnDemand);
-    running_transition->animation = animation;
+
+    RunningTransition* running_transition =
+        MakeGarbageCollected<RunningTransition>(
+            animation, new_transition->from, new_transition->to,
+            new_transition->reversing_adjusted_start_value,
+            new_transition->reversing_shortening_factor);
     transitions_.Set(property, running_transition);
   }
   ClearPendingUpdate();
@@ -2371,14 +2367,14 @@
   }
 
   const ComputedStyle* reversing_adjusted_start_value =
-      state.before_change_style.get();
+      state.before_change_style;
   double reversing_shortening_factor = 1;
   if (interrupted_transition) {
     AnimationEffect* effect = interrupted_transition->animation->effect();
     const absl::optional<double> interrupted_progress =
         effect ? effect->Progress() : absl::nullopt;
     if (interrupted_progress) {
-      reversing_adjusted_start_value = interrupted_transition->to.get();
+      reversing_adjusted_start_value = interrupted_transition->to;
       reversing_shortening_factor =
           ClampTo((interrupted_progress.value() *
                    interrupted_transition->reversing_shortening_factor) +
@@ -2596,7 +2592,7 @@
   CalculateTransitionActiveInterpolations(update, animating_element);
 }
 
-scoped_refptr<const ComputedStyle> CSSAnimations::CalculateBeforeChangeStyle(
+const ComputedStyle* CSSAnimations::CalculateBeforeChangeStyle(
     Element& animating_element,
     const ComputedStyle& base_style) {
   ActiveInterpolationsMap interpolations_map;
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.h b/third_party/blink/renderer/core/animation/css/css_animations.h
index 74bd117..887ea64 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.h
+++ b/third_party/blink/renderer/core/animation/css/css_animations.h
@@ -188,14 +188,28 @@
 
   struct RunningTransition : public GarbageCollected<RunningTransition> {
    public:
-    virtual ~RunningTransition() = default;
+    RunningTransition(Animation* animation,
+                      const ComputedStyle* from,
+                      const ComputedStyle* to,
+                      const ComputedStyle* reversing_adjusted_start_value,
+                      double reversing_shortening_factor)
+        : animation(animation),
+          from(from),
+          to(to),
+          reversing_adjusted_start_value(reversing_adjusted_start_value),
+          reversing_shortening_factor(reversing_shortening_factor) {}
 
-    void Trace(Visitor* visitor) const { visitor->Trace(animation); }
+    void Trace(Visitor* visitor) const {
+      visitor->Trace(animation);
+      visitor->Trace(from);
+      visitor->Trace(to);
+      visitor->Trace(reversing_adjusted_start_value);
+    }
 
     Member<Animation> animation;
-    scoped_refptr<const ComputedStyle> from;
-    scoped_refptr<const ComputedStyle> to;
-    scoped_refptr<const ComputedStyle> reversing_adjusted_start_value;
+    Member<const ComputedStyle> from;
+    Member<const ComputedStyle> to;
+    Member<const ComputedStyle> reversing_adjusted_start_value;
     double reversing_shortening_factor;
   };
 
@@ -261,7 +275,7 @@
     Element& animating_element;
     const ComputedStyle& old_style;
     const ComputedStyle& base_style;
-    scoped_refptr<const ComputedStyle> before_change_style;
+    const ComputedStyle* before_change_style;
     const TransitionMap* active_transitions;
     HashSet<PropertyHandle>* listed_properties;
     const CSSTransitionData* transition_data;
@@ -380,7 +394,7 @@
   // on the element as of the previous style change event, except with any
   // styles derived from declarative animations updated to the current time.
   // https://drafts.csswg.org/css-transitions-1/#before-change-style
-  static scoped_refptr<const ComputedStyle> CalculateBeforeChangeStyle(
+  static const ComputedStyle* CalculateBeforeChangeStyle(
       Element& animating_element,
       const ComputedStyle& base_style);
 
diff --git a/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
index 3b306be..156630c1 100644
--- a/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_length_interpolation_type.cc
@@ -137,7 +137,7 @@
                       .CreateLength(conversion_data, value_range_);
   if (LengthPropertyFunctions::SetLength(CssProperty(), builder, length)) {
 #if DCHECK_IS_ON()
-    scoped_refptr<const ComputedStyle> before_style = builder.CloneStyle();
+    const ComputedStyle* before_style = builder.CloneStyle();
     // Assert that setting the length on ComputedStyle directly is identical to
     // the StyleBuilder code path. This check is useful for catching differences
     // in clamping behavior.
@@ -147,7 +147,7 @@
                                               before));
     StyleBuilder::ApplyProperty(GetProperty().GetCSSProperty(), state,
                                 *CSSValue::Create(length, zoom));
-    scoped_refptr<const ComputedStyle> after_style = builder.CloneStyle();
+    const ComputedStyle* after_style = builder.CloneStyle();
     DCHECK(
         LengthPropertyFunctions::GetLength(CssProperty(), *after_style, after));
     DCHECK(before.IsSpecified());
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc b/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
index 763ffc06..9060b83 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
@@ -165,7 +165,7 @@
 
   auto* effect = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
 
-  auto style =
+  const auto* style =
       document->GetStyleResolver().ResolveStyle(element, StyleRecalcContext());
 
   // Snapshot should update first time after construction
@@ -642,7 +642,7 @@
       KeyframesAtZeroAndOne(CSSPropertyID::kOpacity, "0", "1");
   auto* effect = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
 
-  auto style = GetDocument().GetStyleResolver().ResolveStyle(
+  const auto* style = GetDocument().GetStyleResolver().ResolveStyle(
       element, StyleRecalcContext());
 
   const CompositorKeyframeValue* value;
@@ -679,7 +679,7 @@
   auto* effect =
       MakeGarbageCollected<StringKeyframeEffectModel>(opacity_keyframes);
 
-  auto style = GetDocument().GetStyleResolver().ResolveStyle(
+  const auto* style = GetDocument().GetStyleResolver().ResolveStyle(
       element, StyleRecalcContext());
 
   EXPECT_TRUE(effect->SnapshotAllCompositorKeyframesIfNecessary(
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc b/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
index 5ec41d6..6f6c5303 100644
--- a/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
+++ b/third_party/blink/renderer/core/animation/scroll_timeline_util_test.cc
@@ -114,10 +114,10 @@
           GetDocument().GetStyleResolver().CreateComputedStyleBuilder();
       style_builder.SetWritingMode(writing_mode);
       style_builder.SetDirection(direction);
-      scoped_refptr<const ComputedStyle> style = style_builder.TakeStyle();
-      EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kY, style.get()),
+      const ComputedStyle* style = style_builder.TakeStyle();
+      EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kY, style),
                 CompositorScrollTimeline::ScrollDown);
-      EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kX, style.get()),
+      EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kX, style),
                 CompositorScrollTimeline::ScrollRight);
     }
   }
@@ -129,67 +129,61 @@
       GetDocument().GetStyleResolver().CreateComputedStyleBuilder();
   builder.SetWritingMode(WritingMode::kHorizontalTb);
   builder.SetDirection(TextDirection::kLtr);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
-  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style.get()),
+  const ComputedStyle* style = builder.TakeStyle();
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style),
             CompositorScrollTimeline::ScrollDown);
-  EXPECT_EQ(
-      ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style.get()),
-      CompositorScrollTimeline::ScrollRight);
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style),
+            CompositorScrollTimeline::ScrollRight);
 
   // vertical-lr, ltr
   builder = GetDocument().GetStyleResolver().CreateComputedStyleBuilder();
   builder.SetWritingMode(WritingMode::kVerticalLr);
   builder.SetDirection(TextDirection::kLtr);
   style = builder.TakeStyle();
-  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style.get()),
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style),
             CompositorScrollTimeline::ScrollRight);
-  EXPECT_EQ(
-      ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style.get()),
-      CompositorScrollTimeline::ScrollDown);
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style),
+            CompositorScrollTimeline::ScrollDown);
 
   // vertical-rl, ltr
   builder = GetDocument().GetStyleResolver().CreateComputedStyleBuilder();
   builder.SetWritingMode(WritingMode::kVerticalRl);
   builder.SetDirection(TextDirection::kLtr);
   style = builder.TakeStyle();
-  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style.get()),
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style),
             CompositorScrollTimeline::ScrollLeft);
-  EXPECT_EQ(
-      ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style.get()),
-      CompositorScrollTimeline::ScrollDown);
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style),
+            CompositorScrollTimeline::ScrollDown);
 
   // horizontal-tb, rtl
   builder = GetDocument().GetStyleResolver().CreateComputedStyleBuilder();
   builder.SetWritingMode(WritingMode::kHorizontalTb);
   builder.SetDirection(TextDirection::kRtl);
   style = builder.TakeStyle();
-  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style.get()),
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style),
             CompositorScrollTimeline::ScrollDown);
-  EXPECT_EQ(
-      ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style.get()),
-      CompositorScrollTimeline::ScrollLeft);
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style),
+            CompositorScrollTimeline::ScrollLeft);
 
   // vertical-lr, rtl
   builder = GetDocument().GetStyleResolver().CreateComputedStyleBuilder();
   builder.SetWritingMode(WritingMode::kVerticalLr);
   builder.SetDirection(TextDirection::kRtl);
   style = builder.TakeStyle();
-  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style.get()),
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style),
             CompositorScrollTimeline::ScrollRight);
-  EXPECT_EQ(
-      ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style.get()),
-      CompositorScrollTimeline::ScrollUp);
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style),
+            CompositorScrollTimeline::ScrollUp);
 
   // vertical-rl, rtl
   builder = GetDocument().GetStyleResolver().CreateComputedStyleBuilder();
   builder.SetWritingMode(WritingMode::kVerticalRl);
   builder.SetDirection(TextDirection::kRtl);
   style = builder.TakeStyle();
-  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style.get()),
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kBlock, style),
             CompositorScrollTimeline::ScrollLeft);
-  EXPECT_EQ(
-      ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style.get()),
-      CompositorScrollTimeline::ScrollUp);
+  EXPECT_EQ(ConvertOrientation(ScrollTimeline::ScrollAxis::kInline, style),
+            CompositorScrollTimeline::ScrollUp);
 }
 
 TEST_F(ScrollTimelineUtilTest, ConvertOrientationNullStyle) {
diff --git a/third_party/blink/renderer/core/animation/transition_keyframe.cc b/third_party/blink/renderer/core/animation/transition_keyframe.cc
index 2a623d91..64784cf 100644
--- a/third_party/blink/renderer/core/animation/transition_keyframe.cc
+++ b/third_party/blink/renderer/core/animation/transition_keyframe.cc
@@ -51,7 +51,7 @@
   value_->GetType().Apply(value_->GetInterpolableValue(),
                           value_->GetNonInterpolableValue(), environment);
 
-  scoped_refptr<const ComputedStyle> style = state.TakeStyle();
+  const ComputedStyle* style = state.TakeStyle();
   String property_value =
       AnimationUtils::KeyframeValueFromComputedStyle(
           property_, *style, document, element->GetLayoutObject())
diff --git a/third_party/blink/renderer/core/css/container_query_evaluator_test.cc b/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
index b4b1f35..966407f 100644
--- a/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
+++ b/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
@@ -298,7 +298,7 @@
   ComputedStyleBuilder builder(
       *GetDocument().GetStyleResolver().InitialStyleForElement());
   builder.SetContainerType(type_inline_size);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   container_element.SetComputedStyle(style);
 
   ContainerQueryEvaluator* evaluator = CreateEvaluatorForType(type_inline_size);
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node_test.cc b/third_party/blink/renderer/core/css/css_math_expression_node_test.cc
index d2f12e2b..16aea16 100644
--- a/third_party/blink/renderer/core/css/css_math_expression_node_test.cc
+++ b/third_party/blink/renderer/core/css/css_math_expression_node_test.cc
@@ -96,11 +96,10 @@
 TEST(CSSCalculationValue, AccumulatePixelsAndPercent) {
   ComputedStyleBuilder builder(*ComputedStyle::CreateInitialStyleSingleton());
   builder.SetEffectiveZoom(5);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   CSSToLengthConversionData::Flags ignored_flags = 0;
   CSSToLengthConversionData conversion_data(
-      *style, style.get(), style.get(),
-      CSSToLengthConversionData::ViewportSize(nullptr),
+      *style, style, style, CSSToLengthConversionData::ViewportSize(nullptr),
       CSSToLengthConversionData::ContainerSizes(), style->EffectiveZoom(),
       ignored_flags);
 
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 2ca88ab..7195166d 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -292,7 +292,7 @@
     // Name of the pointer type that wraps this field (e.g. scoped_refptr).
     wrapper_pointer_name: {
       valid_type: "str",
-      valid_values: ["scoped_refptr", "Persistent", "std::unique_ptr"],
+      valid_values: ["scoped_refptr", "Member", "std::unique_ptr"],
     },
 
     // - keywords: ["keyword1", "keyword2"]
@@ -1613,7 +1613,7 @@
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal" ],
       include_paths: ["third_party/blink/renderer/core/style/scoped_css_name.h"],
       type_name: "ScopedCSSName",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       default_value: "nullptr",
       field_group: "*",
       field_template: "external",
@@ -1627,7 +1627,7 @@
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal" ],
       include_paths: ["third_party/blink/renderer/core/style/scoped_css_name.h"],
       type_name: "ScopedCSSName",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       default_value: "nullptr",
       field_group: "*",
       field_template: "external",
@@ -1656,11 +1656,10 @@
       compositable: true,
       field_group: "*",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/core/style/style_filter_data.h"],
-      wrapper_pointer_name: "Persistent",
-      default_value: "MakeGarbageCollected<StyleFilterData>()",
-      type_name: "StyleFilterData",
-      computed_style_custom_functions: ["initial", "getter","setter"],
+      include_paths: ["third_party/blink/renderer/core/style/filter_operations.h"],
+      default_value: "FilterOperations()",
+      type_name: "FilterOperations",
+      computed_style_custom_functions: ["initial"],
       style_builder_custom_functions: ["value"],
       keywords: ["none"],
       typedom_types: ["Keyword"],
@@ -2558,7 +2557,7 @@
       name: "container-name",
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       type_name: "ScopedCSSNameList",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       default_value: "nullptr",
       field_group: "*",
       field_template: "external",
@@ -2584,7 +2583,7 @@
       field_group: "*",
       field_template: "external",
       include_paths: ["third_party/blink/renderer/core/style/content_data.h"],
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       default_value: "nullptr",
       separator: ",",
       type_name: "ContentData",
@@ -2774,11 +2773,10 @@
       compositable: true,
       field_group: "*",
       field_template: "external",
-      include_paths: ["third_party/blink/renderer/core/style/style_filter_data.h"],
-      wrapper_pointer_name: "Persistent",
-      default_value: "MakeGarbageCollected<StyleFilterData>()",
-      type_name: "StyleFilterData",
-      computed_style_custom_functions: ["initial", "getter", "setter"],
+      include_paths: ["third_party/blink/renderer/core/style/filter_operations.h"],
+      default_value: "FilterOperations()",
+      type_name: "FilterOperations",
+      computed_style_custom_functions: ["initial"],
       style_builder_custom_functions: ["value"],
       keywords: ["none"],
       typedom_types: ["Keyword"],
@@ -3240,7 +3238,7 @@
       field_group: "*",
       field_template: "external",
       include_paths: ["third_party/blink/renderer/core/style/style_image.h"],
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       default_value: "nullptr",
       typedom_types: ["Keyword", "Image"],
       type_name: "StyleImage",
@@ -3265,7 +3263,7 @@
       field_template: "external",
       include_paths: ["third_party/blink/renderer/core/keywords.h",
                       "third_party/blink/renderer/core/style/list_style_type_data.h"],
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       default_value: "ListStyleTypeData::CreateCounterStyle(keywords::kDisc, nullptr)",
       type_name: "ListStyleTypeData",
       keywords: [
@@ -4056,7 +4054,7 @@
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal" ],
       include_paths: ["third_party/blink/renderer/core/style/scoped_css_name.h"],
       type_name: "ScopedCSSName",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       default_value: "nullptr",
       field_group: "*",
       field_template: "external",
@@ -4070,7 +4068,7 @@
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal" ],
       include_paths: ["third_party/blink/renderer/core/style/scoped_css_name.h"],
       type_name: "ScopedCSSName",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       default_value: "nullptr",
       field_group: "*",
       field_template: "external",
@@ -4620,7 +4618,7 @@
       field_template: "external",
       default_value: "nullptr",
       type_name: "ScopedCSSNameList",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       converter: "ConvertViewTimelineName",
       separator: ",",
       runtime_flag: "ScrollTimeline",
@@ -4655,7 +4653,7 @@
       field_group: "*",
       field_template: "external",
       include_paths: ["third_party/blink/renderer/core/style/shape_value.h"],
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       default_value: "nullptr",
       typedom_types: ["Keyword", "Image"],
       type_name: "ShapeValue",
@@ -5145,7 +5143,7 @@
       field_template: "external",
       default_value: "nullptr",
       type_name: "ScopedCSSNameList",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       converter: "ConvertTimelineScope",
       separator: ",",
       runtime_flag: "TimelineScope",
@@ -5416,7 +5414,7 @@
       field_template: "external",
       default_value: "nullptr",
       type_name: "ScopedCSSNameList",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       converter: "ConvertViewTimelineName",
       separator: ",",
       runtime_flag: "ScrollTimeline",
diff --git a/third_party/blink/renderer/core/css/font_face_set_document.cc b/third_party/blink/renderer/core/css/font_face_set_document.cc
index 09c5ebd..8702bc4c5 100644
--- a/third_party/blink/renderer/core/css/font_face_set_document.cc
+++ b/third_party/blink/renderer/core/css/font_face_set_document.cc
@@ -200,7 +200,7 @@
   default_font_description.SetComputedSize(FontFaceSet::kDefaultFontSize);
 
   builder.SetFontDescription(default_font_description);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   font = GetDocument()->GetStyleEngine().ComputeFont(
       *GetDocument()->documentElement(), *style, *parsed_style);
diff --git a/third_party/blink/renderer/core/css/post_style_update_scope.cc b/third_party/blink/renderer/core/css/post_style_update_scope.cc
index 2ba34f22..6baae4d 100644
--- a/third_party/blink/renderer/core/css/post_style_update_scope.cc
+++ b/third_party/blink/renderer/core/css/post_style_update_scope.cc
@@ -97,9 +97,8 @@
 
 void PostStyleUpdateScope::AnimationData::StoreOldStyleIfNeeded(
     Element& element) {
-  old_styles_.insert(
-      &element, scoped_refptr<const ComputedStyle>(
-                    ComputedStyle::NullifyEnsured(element.GetComputedStyle())));
+  old_styles_.insert(&element,
+                     ComputedStyle::NullifyEnsured(element.GetComputedStyle()));
 }
 
 const ComputedStyle* PostStyleUpdateScope::AnimationData::GetOldStyle(
@@ -108,7 +107,7 @@
   if (iter == old_styles_.end()) {
     return ComputedStyle::NullifyEnsured(element.GetComputedStyle());
   }
-  return iter->value.get();
+  return iter->value.Get();
 }
 
 void PostStyleUpdateScope::PseudoData::AddPendingBackdrop(
diff --git a/third_party/blink/renderer/core/css/post_style_update_scope.h b/third_party/blink/renderer/core/css/post_style_update_scope.h
index 424679c..984975b 100644
--- a/third_party/blink/renderer/core/css/post_style_update_scope.h
+++ b/third_party/blink/renderer/core/css/post_style_update_scope.h
@@ -65,8 +65,7 @@
     friend class ContainerQueryTest;
 
     HeapHashSet<Member<Element>> elements_with_pending_updates_;
-    HeapHashMap<Member<const Element>, scoped_refptr<const ComputedStyle>>
-        old_styles_;
+    HeapHashMap<Member<const Element>, Member<const ComputedStyle>> old_styles_;
   };
 
   class PseudoData {
diff --git a/third_party/blink/renderer/core/css/properties/css_property_test.cc b/third_party/blink/renderer/core/css/properties/css_property_test.cc
index eb0d691..ced127d0 100644
--- a/third_party/blink/renderer/core/css/properties/css_property_test.cc
+++ b/third_party/blink/renderer/core/css/properties/css_property_test.cc
@@ -36,9 +36,8 @@
     return &set->PropertyAt(0).Value();
   }
 
-  scoped_refptr<const ComputedStyle> ComputedStyleWithValue(
-      const CSSProperty& property,
-      const CSSValue& value) {
+  const ComputedStyle* ComputedStyleWithValue(const CSSProperty& property,
+                                              const CSSValue& value) {
     StyleResolverState state(GetDocument(), *GetDocument().body());
     state.SetStyle(GetDocument().GetStyleResolver().InitialStyle());
 
diff --git a/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc b/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
index 73dbfbd..e6d10a2dd 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/custom_property_test.cc
@@ -303,7 +303,7 @@
                              /* StyleRecalcContext */ nullptr, StyleRequest());
     state.SetStyle(*GetDocument().GetStyleResolver().InitialStyleForElement());
     property.ApplyValue(state, *declaration, CSSProperty::ValueMode::kNormal);
-    scoped_refptr<const ComputedStyle> style = state.TakeStyle();
+    const ComputedStyle* style = state.TakeStyle();
     ASSERT_TRUE(style->GetVariableData(AtomicString("--x")));
     EXPECT_FALSE(
         style->GetVariableData(AtomicString("--x"))->IsAnimationTainted());
@@ -315,7 +315,7 @@
                              /* StyleRecalcContext */ nullptr, StyleRequest());
     state.SetStyle(*GetDocument().GetStyleResolver().InitialStyleForElement());
     property.ApplyValue(state, *declaration, CSSProperty::ValueMode::kAnimated);
-    scoped_refptr<const ComputedStyle> style = state.TakeStyle();
+    const ComputedStyle* style = state.TakeStyle();
     ASSERT_TRUE(style->GetVariableData(AtomicString("--x")));
     EXPECT_TRUE(
         style->GetVariableData(AtomicString("--x"))->IsAnimationTainted());
diff --git a/third_party/blink/renderer/core/css/resolver/element_resolve_context.cc b/third_party/blink/renderer/core/css/resolver/element_resolve_context.cc
index b23d6e4..ca187f4 100644
--- a/third_party/blink/renderer/core/css/resolver/element_resolve_context.cc
+++ b/third_party/blink/renderer/core/css/resolver/element_resolve_context.cc
@@ -31,8 +31,6 @@
 
 ElementResolveContext::ElementResolveContext(Element& element)
     : element_(&element),
-      parent_node_(nullptr),
-      layout_parent_(nullptr),
       element_link_state_(
           element.GetDocument().GetVisitedLinkState().DetermineLinkState(
               element)) {
diff --git a/third_party/blink/renderer/core/css/resolver/element_resolve_context.h b/third_party/blink/renderer/core/css/resolver/element_resolve_context.h
index ea35607..4dcc62a 100644
--- a/third_party/blink/renderer/core/css/resolver/element_resolve_context.h
+++ b/third_party/blink/renderer/core/css/resolver/element_resolve_context.h
@@ -45,9 +45,7 @@
   Element& GetElement() const { return *element_; }
   const ContainerNode* ParentNode() const { return parent_node_; }
   const ContainerNode* LayoutParent() const { return layout_parent_; }
-  const ComputedStyle* RootElementStyle() const {
-    return root_element_style_.get();
-  }
+  const ComputedStyle* RootElementStyle() const { return root_element_style_; }
   const ComputedStyle* ParentStyle() const {
     return ParentNode() && ParentNode()->IsElementNode()
                ? ParentNode()->GetComputedStyle()
@@ -60,9 +58,9 @@
 
  private:
   Element* element_;
-  ContainerNode* parent_node_;
-  ContainerNode* layout_parent_;
-  scoped_refptr<const ComputedStyle> root_element_style_;
+  ContainerNode* parent_node_{nullptr};
+  ContainerNode* layout_parent_{nullptr};
+  const ComputedStyle* root_element_style_{nullptr};
   EInsideLink element_link_state_;
 };
 
diff --git a/third_party/blink/renderer/core/css/resolver/element_style_resources.cc b/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
index d0183390..2878021 100644
--- a/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
+++ b/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
@@ -286,11 +286,11 @@
   for (CSSPropertyID property : pending_svg_resource_properties_) {
     switch (property) {
       case CSSPropertyID::kBackdropFilter:
-        LoadResourcesForFilter(builder.MutableBackdropFilter().Operations(),
+        LoadResourcesForFilter(builder.MutableBackdropFilterOperations(),
                                document);
         break;
       case CSSPropertyID::kFilter:
-        LoadResourcesForFilter(builder.MutableFilter().Operations(), document);
+        LoadResourcesForFilter(builder.MutableFilterOperations(), document);
         break;
       default:
         NOTREACHED();
diff --git a/third_party/blink/renderer/core/css/resolver/font_builder_test.cc b/third_party/blink/renderer/core/css/resolver/font_builder_test.cc
index 8803cdc..97df08f9 100644
--- a/third_party/blink/renderer/core/css/resolver/font_builder_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/font_builder_test.cc
@@ -75,7 +75,7 @@
   ComputedStyleBuilder builder =
       GetDocument().GetStyleResolver().CreateComputedStyleBuilder();
   builder.SetFontDescription(parent_description);
-  scoped_refptr<const ComputedStyle> parent_style = builder.TakeStyle();
+  const ComputedStyle* parent_style = builder.TakeStyle();
 
   builder =
       GetDocument().GetStyleResolver().CreateComputedStyleBuilderInheritingFrom(
@@ -83,9 +83,9 @@
 
   FontBuilder font_builder(&GetDocument());
   funcs.set_value(font_builder);
-  font_builder.CreateFont(builder, parent_style.get());
+  font_builder.CreateFont(builder, parent_style);
 
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   FontDescription output_description = style->GetFontDescription();
 
   // FontBuilder should have overwritten our base value set in the parent,
diff --git a/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc b/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
index 038d137f..8fff50db 100644
--- a/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
+++ b/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
@@ -51,20 +51,31 @@
   return hash;
 }
 
-void CachedMatchedProperties::Set(
-    scoped_refptr<const ComputedStyle>&& style,
-    scoped_refptr<const ComputedStyle>&& parent_style,
-    const MatchedPropertiesVector& properties) {
+CachedMatchedProperties::CachedMatchedProperties(
+    const ComputedStyle* style,
+    const ComputedStyle* parent_style,
+    const MatchedPropertiesVector& properties)
+    : computed_style(style), parent_computed_style(parent_style) {
+  matched_properties.ReserveInitialCapacity(properties.size());
+  matched_properties_types.ReserveInitialCapacity(properties.size());
   for (const auto& new_matched_properties : properties) {
     matched_properties.push_back(new_matched_properties.properties);
     matched_properties_types.push_back(new_matched_properties.types_);
   }
+}
 
-  // Note that we don't cache the original ComputedStyle instance. It may be
-  // further modified.  The ComputedStyle in the cache is really just a holder
-  // for the substructures and never used as-is.
-  this->computed_style = style;
-  this->parent_computed_style = parent_style;
+void CachedMatchedProperties::Set(const ComputedStyle* style,
+                                  const ComputedStyle* parent_style,
+                                  const MatchedPropertiesVector& properties) {
+  computed_style = style;
+  parent_computed_style = parent_style;
+
+  matched_properties.clear();
+  matched_properties_types.clear();
+  for (const auto& new_matched_properties : properties) {
+    matched_properties.push_back(new_matched_properties.properties);
+    matched_properties_types.push_back(new_matched_properties.types_);
+  }
 }
 
 void CachedMatchedProperties::Clear() {
@@ -191,23 +202,20 @@
   return !(*this == properties);
 }
 
-void MatchedPropertiesCache::Add(
-    const Key& key,
-    scoped_refptr<const ComputedStyle>&& style,
-    scoped_refptr<const ComputedStyle>&& parent_style) {
+void MatchedPropertiesCache::Add(const Key& key,
+                                 const ComputedStyle* style,
+                                 const ComputedStyle* parent_style) {
   DCHECK(key.IsValid());
 
   Member<CachedMatchedProperties>& cache_item =
       cache_.insert(key.hash_, nullptr).stored_value->value;
 
   if (!cache_item) {
-    cache_item = MakeGarbageCollected<CachedMatchedProperties>();
+    cache_item = MakeGarbageCollected<CachedMatchedProperties>(
+        style, parent_style, key.result_.GetMatchedProperties());
   } else {
-    cache_item->Clear();
+    cache_item->Set(style, parent_style, key.result_.GetMatchedProperties());
   }
-
-  cache_item->Set(std::move(style), std::move(parent_style),
-                  key.result_.GetMatchedProperties());
 }
 
 void MatchedPropertiesCache::Clear() {
diff --git a/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h b/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h
index a3843ad..a549917 100644
--- a/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h
+++ b/third_party/blink/renderer/core/css/resolver/matched_properties_cache.h
@@ -49,17 +49,27 @@
   Vector<UntracedMember<CSSPropertyValueSet>> matched_properties;
   Vector<MatchedProperties::Data> matched_properties_types;
 
-  scoped_refptr<const ComputedStyle> computed_style;
-  scoped_refptr<const ComputedStyle> parent_computed_style;
+  // Note that we don't cache the original ComputedStyle instance. It may be
+  // further modified. The ComputedStyle in the cache is really just a holder
+  // for the substructures and never used as-is.
+  Member<const ComputedStyle> computed_style;
+  Member<const ComputedStyle> parent_computed_style;
 
-  void Set(scoped_refptr<const ComputedStyle>&& style,
-           scoped_refptr<const ComputedStyle>&& parent_style,
+  CachedMatchedProperties(const ComputedStyle* style,
+                          const ComputedStyle* parent_style,
+                          const MatchedPropertiesVector&);
+
+  void Set(const ComputedStyle* style,
+           const ComputedStyle* parent_style,
            const MatchedPropertiesVector&);
   void Clear();
 
   bool DependenciesEqual(const StyleResolverState&);
 
-  void Trace(Visitor*) const {}
+  void Trace(Visitor* visitor) const {
+    visitor->Trace(computed_style);
+    visitor->Trace(parent_computed_style);
+  }
 
   bool operator==(const MatchedPropertiesVector& properties);
   bool operator!=(const MatchedPropertiesVector& properties);
@@ -99,9 +109,7 @@
   };
 
   const CachedMatchedProperties* Find(const Key&, const StyleResolverState&);
-  void Add(const Key&,
-           scoped_refptr<const ComputedStyle>&&,
-           scoped_refptr<const ComputedStyle>&& parent_style);
+  void Add(const Key&, const ComputedStyle*, const ComputedStyle* parent_style);
 
   void Clear();
   void ClearViewportDependent();
diff --git a/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc b/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc
index 39f6b46..7b93679 100644
--- a/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc
@@ -150,8 +150,7 @@
   const auto& parent = InitialStyle();
   ComputedStyleBuilder ensured_parent_builder = CreateStyleBuilder();
   ensured_parent_builder.SetIsEnsuredInDisplayNone();
-  scoped_refptr<const ComputedStyle> ensured_parent =
-      ensured_parent_builder.TakeStyle();
+  const auto* ensured_parent = ensured_parent_builder.TakeStyle();
 
   TestKey key1("display:block", 1, GetDocument());
 
@@ -171,7 +170,7 @@
   const auto& parent = InitialStyle();
   auto builder = CreateStyleBuilder();
   builder.SetIsEnsuredOutsideFlatTree();
-  auto ensured_style = builder.TakeStyle();
+  const auto* ensured_style = builder.TakeStyle();
 
   TestKey key1("display:block", 1, GetDocument());
   StyleRecalcContext context;
@@ -194,11 +193,11 @@
 
   auto builder = CreateStyleBuilder();
   builder.SetIsEnsuredInDisplayNone();
-  auto parent_none = builder.TakeStyle();
+  const auto* parent_none = builder.TakeStyle();
 
   builder = CreateStyleBuilder();
   builder.SetIsEnsuredOutsideFlatTree();
-  auto style_flat = builder.TakeStyle();
+  const auto* style_flat = builder.TakeStyle();
 
   StyleRecalcContext context;
   context.is_outside_flat_tree = true;
@@ -220,8 +219,8 @@
   auto parent_builder_b = CreateStyleBuilder();
   parent_builder_b.SetWritingMode(WritingMode::kVerticalRl);
 
-  auto parent_a = parent_builder_a.TakeStyle();
-  auto parent_b = parent_builder_b.TakeStyle();
+  const auto* parent_a = parent_builder_a.TakeStyle();
+  const auto* parent_b = parent_builder_b.TakeStyle();
 
   const auto& style_a = InitialStyle();
   const auto& style_b = InitialStyle();
@@ -242,8 +241,8 @@
   auto parent_builder_b = CreateStyleBuilder();
   parent_builder_b.SetDirection(TextDirection::kRtl);
 
-  auto parent_a = parent_builder_a.TakeStyle();
-  auto parent_b = parent_builder_b.TakeStyle();
+  const auto* parent_a = parent_builder_a.TakeStyle();
+  const auto* parent_b = parent_builder_b.TakeStyle();
 
   const auto& style_a = InitialStyle();
   const auto& style_b = InitialStyle();
@@ -261,11 +260,11 @@
 
   auto builder = CreateStyleBuilder();
   builder.SetDarkColorScheme(false);
-  auto parent_a = builder.TakeStyle();
+  const auto* parent_a = builder.TakeStyle();
 
   builder = CreateStyleBuilder();
   builder.SetDarkColorScheme(true);
-  auto parent_b = builder.TakeStyle();
+  const auto* parent_b = builder.TakeStyle();
 
   const auto& style_a = InitialStyle();
   const auto& style_b = InitialStyle();
@@ -287,15 +286,15 @@
                                    CreateVariableData("1px"), true);
   parent_builder_b.SetVariableData(AtomicString("--x"),
                                    CreateVariableData("2px"), true);
-  auto parent_a = parent_builder_a.TakeStyle();
-  auto parent_b = parent_builder_b.TakeStyle();
+  const auto* parent_a = parent_builder_a.TakeStyle();
+  const auto* parent_b = parent_builder_b.TakeStyle();
 
   auto style_builder_a = CreateStyleBuilder();
   auto style_builder_b = CreateStyleBuilder();
   style_builder_a.SetHasVariableReferenceFromNonInheritedProperty();
   style_builder_b.SetHasVariableReferenceFromNonInheritedProperty();
-  auto style_a = style_builder_a.TakeStyle();
-  auto style_b = style_builder_b.TakeStyle();
+  const auto* style_a = style_builder_a.TakeStyle();
+  const auto* style_b = style_builder_b.TakeStyle();
 
   TestKey key("top:var(--x)", 1, GetDocument());
   cache.Add(key, *style_a, *parent_a);
@@ -314,8 +313,8 @@
   auto style_builder_b = CreateStyleBuilder();
   style_builder_a.SetHasVariableReferenceFromNonInheritedProperty();
   style_builder_b.SetHasVariableReferenceFromNonInheritedProperty();
-  auto style_a = style_builder_a.TakeStyle();
-  auto style_b = style_builder_b.TakeStyle();
+  const auto* style_a = style_builder_a.TakeStyle();
+  const auto* style_b = style_builder_b.TakeStyle();
 
   TestKey key("top:var(--x)", 1, GetDocument());
 
@@ -335,8 +334,8 @@
                                    CreateVariableData("1px"), true);
   parent_builder_b.SetVariableData(AtomicString("--x"),
                                    CreateVariableData("2px"), true);
-  auto parent_a = parent_builder_a.TakeStyle();
-  auto parent_b = parent_builder_b.TakeStyle();
+  const auto* parent_a = parent_builder_a.TakeStyle();
+  const auto* parent_b = parent_builder_b.TakeStyle();
   const auto& style_a = InitialStyle();
   const auto& style_b = InitialStyle();
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
index 753b4c25..4dadf96 100644
--- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -304,7 +304,7 @@
 #if DCHECK_IS_ON()
   DCHECK_EQ(builder.GetFont().GetFontDescription().Orientation(),
             FontOrientation::kHorizontal);
-  scoped_refptr<const ComputedStyle> cloned_style = builder.CloneStyle();
+  const ComputedStyle* cloned_style = builder.CloneStyle();
   LayoutNGTextCombine::AssertStyleIsValid(*cloned_style);
 #endif
 }
@@ -895,7 +895,7 @@
     // it to have a backdrop filter either.
     if (is_document_element && is_in_main_frame &&
         builder.HasBackdropFilter()) {
-      builder.MutableBackdropFilter().clear();
+      builder.SetBackdropFilter(FilterOperations());
     }
   } else {
     AdjustStyleForFirstLetter(builder);
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_test.cc b/third_party/blink/renderer/core/css/resolver/style_builder_test.cc
index 875fa500..7f9ee5f 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_test.cc
@@ -127,9 +127,6 @@
                            nullptr /* StyleRecalcContext */,
                            StyleRequest(&parent_style));
 
-  scoped_refptr<const ComputedStyle> style1;
-  scoped_refptr<const ComputedStyle> style2;
-
   // grid-template-areas applied first.
   state.SetStyle(parent_style);
   StyleBuilder::ApplyProperty(grid_template_areas, state,
@@ -138,7 +135,7 @@
                               *grid_template_columns_value);
   StyleBuilder::ApplyProperty(grid_template_rows, state,
                               *grid_template_rows_value);
-  style1 = state.TakeStyle();
+  const ComputedStyle* style1 = state.TakeStyle();
 
   // grid-template-areas applied last.
   state.SetStyle(parent_style);
@@ -148,7 +145,7 @@
                               *grid_template_rows_value);
   StyleBuilder::ApplyProperty(grid_template_areas, state,
                               *grid_template_areas_value);
-  style2 = state.TakeStyle();
+  const ComputedStyle* style2 = state.TakeStyle();
 
   ASSERT_TRUE(style1);
   ASSERT_TRUE(style2);
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
index 0cf89eb..f2c377e 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
@@ -92,12 +92,12 @@
         cascade_(InitState(state_, nullptr)) {}
 
   TestCascade(Document& document,
-              scoped_refptr<const ComputedStyle> parent_style,
+              const ComputedStyle* parent_style,
               Element* target = nullptr)
       : state_(document, target ? *target : *document.body()),
         cascade_(InitState(state_, parent_style)) {}
 
-  scoped_refptr<const ComputedStyle> TakeStyle() { return state_.TakeStyle(); }
+  const ComputedStyle* TakeStyle() { return state_.TakeStyle(); }
 
   StyleResolverState& State() { return state_; }
   StyleCascade& InnerCascade() { return cascade_; }
@@ -163,8 +163,7 @@
     DCHECK(ref.IsValid());
     const LayoutObject* layout_object = nullptr;
     bool allow_visited_style = false;
-    scoped_refptr<const ComputedStyle> style =
-        state_.StyleBuilder().CloneStyle();
+    const ComputedStyle* style = state_.StyleBuilder().CloneStyle();
     const CSSValue* value = ref.GetProperty().CSSValueFromComputedStyle(
         *style, layout_object, allow_visited_style);
     return value ? value->CssText() : g_null_atom;
@@ -225,9 +224,8 @@
   Document& GetDocument() const { return state_.GetDocument(); }
   Element* Body() const { return GetDocument().body(); }
 
-  static StyleResolverState& InitState(
-      StyleResolverState& state,
-      scoped_refptr<const ComputedStyle> parent_style) {
+  static StyleResolverState& InitState(StyleResolverState& state,
+                                       const ComputedStyle* parent_style) {
     state.GetDocument().GetStyleEngine().UpdateViewportSize();
     if (parent_style) {
       state.CreateNewStyle(*InitialStyle(state.GetDocument()), *parent_style);
@@ -240,7 +238,7 @@
     return state;
   }
 
-  static scoped_refptr<const ComputedStyle> InitialStyle(Document& document) {
+  static const ComputedStyle* InitialStyle(Document& document) {
     return document.GetStyleResolver().InitialStyleForElement();
   }
 
@@ -2550,7 +2548,7 @@
   cascade.Apply();
   EXPECT_EQ("rgb(150, 150, 150)", cascade.ComputedValue("background-color"));
 
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
 
   ComputedStyleBuilder builder(*style);
   builder.SetInsideLink(EInsideLink::kInsideVisitedLink);
@@ -2582,7 +2580,7 @@
   cascade.Apply();
   EXPECT_EQ("rgb(150, 150, 150)", cascade.ComputedValue("color"));
 
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
 
   ComputedStyleBuilder builder(*style);
   builder.SetInsideLink(EInsideLink::kInsideVisitedLink);
@@ -3060,7 +3058,7 @@
   cascade.Add("--x", "1px");
   cascade.Add("width", "var(--x)");
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
 }
 
@@ -3069,7 +3067,7 @@
   cascade.Add("--x", "1px");
   cascade.Add("margin", "var(--x)");
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
 }
 
@@ -3077,7 +3075,7 @@
   TestCascade cascade(GetDocument());
   cascade.Add("width", "var(--x)");
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
 }
 
@@ -3085,7 +3083,7 @@
   TestCascade cascade(GetDocument());
   cascade.Add("margin", "var(--x)");
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
 }
 
@@ -3093,7 +3091,7 @@
   TestCascade cascade(GetDocument());
   cascade.Add("color", "var(--x)");
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_FALSE(style->HasVariableReferenceFromNonInheritedProperty());
 }
 
@@ -3101,7 +3099,7 @@
   TestCascade cascade(GetDocument());
   cascade.Add("width", "1px");
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_FALSE(style->HasVariableReferenceFromNonInheritedProperty());
 }
 
@@ -3231,7 +3229,7 @@
   cascade.Add("border-block-start-color", "red", Origin::kUserAgent);
   cascade.Add("border-block-start-color", "green", Origin::kAuthor);
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_TRUE(style->HasAuthorBorder());
 }
 
@@ -3243,7 +3241,7 @@
   cascade.Add("background-clip", "padding-box", Origin::kUser);
   cascade.Add("border-right-color", "green", Origin::kUser);
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_FALSE(style->HasAuthorBackground());
   EXPECT_FALSE(style->HasAuthorBorder());
 }
@@ -3254,7 +3252,7 @@
   cascade.Add("background-color", "red", Origin::kUserAgent);
   cascade.Add("background-color", "revert", Origin::kAuthor);
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_FALSE(style->HasAuthorBackground());
 }
 
@@ -3264,7 +3262,7 @@
   cascade.Add("border-top-color", "red", Origin::kUserAgent);
   cascade.Add("border-top-color", "revert", Origin::kAuthor);
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_FALSE(style->HasAuthorBorder());
 }
 
@@ -3274,7 +3272,7 @@
   cascade.Add("border-block-start-color", "red", Origin::kUserAgent);
   cascade.Add("border-block-start-color", "revert", Origin::kAuthor);
   cascade.Apply();
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
   EXPECT_FALSE(style->HasAuthorBorder());
 }
 
@@ -3459,7 +3457,7 @@
   cascade.Add("display:block");
   cascade.Apply();  // Should not affect 'color'.
 
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
 
   ComputedStyleBuilder builder(*style);
   builder.SetInsideLink(EInsideLink::kInsideVisitedLink);
@@ -3491,7 +3489,7 @@
 
   cascade.Apply();
 
-  auto style = cascade.TakeStyle();
+  const auto* style = cascade.TakeStyle();
 
   ComputedStyleBuilder builder(*style);
   builder.SetInsideLink(EInsideLink::kInsideVisitedLink);
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 07a03a6..dfbe152 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -122,12 +122,12 @@
 
 namespace {
 
-scoped_refptr<const ComputedStyle> BuildInitialStyleForImg(
-    const scoped_refptr<const ComputedStyle>& initial_style) {
+const ComputedStyle* BuildInitialStyleForImg(
+    const ComputedStyle& initial_style) {
   // This matches the img {} declarations in html.css to avoid copy-on-write
   // when only UA styles apply for these properties. See crbug.com/1369454
   // for details.
-  ComputedStyleBuilder builder(*initial_style);
+  ComputedStyleBuilder builder(initial_style);
   builder.SetOverflowX(EOverflow::kClip);
   builder.SetOverflowY(EOverflow::kClip);
   builder.SetOverflowClipMargin(StyleOverflowClipMargin::CreateContent());
@@ -464,7 +464,7 @@
 
 StyleResolver::StyleResolver(Document& document)
     : initial_style_(ComputedStyle::CreateInitialStyleSingleton()),
-      initial_style_for_img_(BuildInitialStyleForImg(initial_style_)),
+      initial_style_for_img_(BuildInitialStyleForImg(*initial_style_)),
       document_(document) {
   UpdateMediaType();
 }
@@ -472,7 +472,6 @@
 StyleResolver::~StyleResolver() = default;
 
 void StyleResolver::Dispose() {
-  initial_style_.reset();
   matched_properties_cache_.Clear();
 }
 
@@ -923,7 +922,7 @@
   }
 }
 
-scoped_refptr<const ComputedStyle> StyleResolver::StyleForViewport() {
+const ComputedStyle* StyleResolver::StyleForViewport() {
   ComputedStyleBuilder builder = InitialStyleBuilderForElement();
 
   builder.SetZIndex(0);
@@ -948,7 +947,7 @@
     return nullptr;
   }
   auto* old_style = animating_element->GetComputedStyle();
-  return old_style ? old_style->BaseData().get() : nullptr;
+  return old_style ? old_style->BaseData().Get() : nullptr;
 }
 
 static const ComputedStyle* CachedAnimationBaseComputedStyle(
@@ -986,7 +985,7 @@
 // any other properties or elements. (The exceptions can be found in
 // CanReuseBaseComputedStyle().) This is known as the “base computed style
 // optimization”.
-scoped_refptr<const ComputedStyle> StyleResolver::ResolveStyle(
+const ComputedStyle* StyleResolver::ResolveStyle(
     Element* element,
     const StyleRecalcContext& style_recalc_context,
     const StyleRequest& style_request) {
@@ -1527,15 +1526,13 @@
     // optimization was sound.
     ApplyBaseStyleNoCache(element, style_recalc_context, style_request, state,
                           cascade);
-    scoped_refptr<const ComputedStyle> style_snapshot =
-        state.StyleBuilder().CloneStyle();
+    const ComputedStyle* style_snapshot = state.StyleBuilder().CloneStyle();
     DCHECK_EQ(g_null_atom, ComputeBaseComputedStyleDiff(
                                animation_base_computed_style, *style_snapshot));
 #endif
 
     state.SetStyle(*animation_base_computed_style);
-    state.StyleBuilder().SetBaseData(
-        scoped_refptr<StyleBaseData>(GetBaseData(state)));
+    state.StyleBuilder().SetBaseData(GetBaseData(state));
     state.StyleBuilder().SetStyleType(style_request.pseudo_id);
     if (!state.ParentStyle()) {
       state.SetParentStyle(InitialStyleForElement());
@@ -1582,7 +1579,7 @@
 
 #if DCHECK_IS_ON()
     // Verify that we got the right answer.
-    scoped_refptr<const ComputedStyle> incremental_style = state.TakeStyle();
+    const ComputedStyle* incremental_style = state.TakeStyle();
     ApplyBaseStyleNoCache(element, style_recalc_context, style_request, state,
                           cascade);
 
@@ -1602,10 +1599,9 @@
         state.StyleBuilder().ViewportUnitFlags() |
         incremental_style->ViewportUnitFlags());
 
-    scoped_refptr<const ComputedStyle> style_snapshot =
-        state.StyleBuilder().CloneStyle();
-    DCHECK_EQ(g_null_atom, ComputeBaseComputedStyleDiff(incremental_style.get(),
-                                                        *style_snapshot));
+    const ComputedStyle* style_snapshot = state.StyleBuilder().CloneStyle();
+    DCHECK_EQ(g_null_atom,
+              ComputeBaseComputedStyleDiff(incremental_style, *style_snapshot));
     // The incremental style must not contain BaseData, otherwise we'd risk
     // creating an infinite chain of BaseData/ComputedStyle in
     // ApplyAnimatedStyle.
@@ -1643,14 +1639,14 @@
                                                       CascadeOrigin::kAuthor);
     cascade.Apply();
   }
-  scoped_refptr<const ComputedStyle> style = state.TakeStyle();
+  const ComputedStyle* style = state.TakeStyle();
   return CompositorKeyframeValueFactory::Create(property, *style, offset);
 }
 
-scoped_refptr<const ComputedStyle> StyleResolver::StyleForPage(
+const ComputedStyle* StyleResolver::StyleForPage(
     uint32_t page_index,
     const AtomicString& page_name) {
-  scoped_refptr<const ComputedStyle> initial_style = InitialStyleForElement();
+  const ComputedStyle* initial_style = InitialStyleForElement();
   if (!GetDocument().documentElement()) {
     return initial_style;
   }
@@ -1658,7 +1654,7 @@
   const ComputedStyle* document_style = GetDocument().GetComputedStyle();
   StyleResolverState state(GetDocument(), *GetDocument().documentElement(),
                            nullptr /* StyleRecalcContext */,
-                           StyleRequest(initial_style.get()));
+                           StyleRequest(initial_style));
   state.CreateNewStyle(*initial_style, *document_style);
 
   STACK_UNINITIALIZED StyleCascade cascade(state);
@@ -1739,8 +1735,7 @@
   return builder;
 }
 
-scoped_refptr<const ComputedStyle> StyleResolver::StyleForText(
-    Text* text_node) {
+const ComputedStyle* StyleResolver::StyleForText(Text* text_node) {
   DCHECK(text_node);
   if (Node* parent_node = LayoutTreeBuilderTraversal::Parent(*text_node)) {
     const ComputedStyle* style = parent_node->GetComputedStyle();
@@ -2088,11 +2083,11 @@
         !IsForcedColorsModeEnabled() || is_inherited_cache_hit;
 
     const ComputedStyle* parent_style =
-        is_inherited_cache_hit ? cached_matched_properties->computed_style.get()
+        is_inherited_cache_hit ? cached_matched_properties->computed_style.Get()
                                : state.ParentStyle();
     const ComputedStyle& source_for_noninherited =
         is_non_inherited_cache_hit
-            ? *cached_matched_properties->computed_style.get()
+            ? *cached_matched_properties->computed_style.Get()
             : initial_style;
 
     InitStyle(element, style_request, source_for_noninherited, parent_style,
@@ -2245,7 +2240,7 @@
   cascade.Apply();
 
   CSSPropertyRef property_ref(property_name, element->GetDocument());
-  scoped_refptr<const ComputedStyle> style = state.TakeStyle();
+  const ComputedStyle* style = state.TakeStyle();
   return ComputedStyleUtils::ComputedPropertyValue(property_ref.GetProperty(),
                                                    *style);
 }
@@ -2256,11 +2251,11 @@
     const CSSValue& filter_value) {
   ComputedStyleBuilder parent_builder = CreateComputedStyleBuilder();
   parent_builder.SetFont(font);
-  scoped_refptr<const ComputedStyle> parent = parent_builder.TakeStyle();
+  const ComputedStyle* parent = parent_builder.TakeStyle();
 
   StyleResolverState state(GetDocument(), *element,
                            nullptr /* StyleRecalcContext */,
-                           StyleRequest(parent.get()));
+                           StyleRequest(parent));
 
   GetDocument().GetStyleEngine().UpdateViewportSize();
   state.SetStyle(*parent);
@@ -2270,11 +2265,11 @@
 
   state.LoadPendingResources();
 
-  scoped_refptr<const ComputedStyle> style = state.TakeStyle();
+  const ComputedStyle* style = state.TakeStyle();
   return style->Filter();
 }
 
-scoped_refptr<const ComputedStyle> StyleResolver::StyleForInterpolations(
+const ComputedStyle* StyleResolver::StyleForInterpolations(
     Element& element,
     ActiveInterpolationsMap& interpolations) {
   StyleRecalcContext style_recalc_context =
@@ -2300,8 +2295,7 @@
   cascade.Apply();
 }
 
-scoped_refptr<const ComputedStyle>
-StyleResolver::BeforeChangeStyleForTransitionUpdate(
+const ComputedStyle* StyleResolver::BeforeChangeStyleForTransitionUpdate(
     Element& element,
     const ComputedStyle& base_style,
     ActiveInterpolationsMap& transition_interpolations) {
@@ -2342,13 +2336,11 @@
       }
 #if DCHECK_IS_ON()
       // Verify that our application went as planned.
-      scoped_refptr<const ComputedStyle> applied_style =
-          state.StyleBuilder().CloneStyle();
+      const ComputedStyle* applied_style = state.StyleBuilder().CloneStyle();
       cascade.Apply(filter);
-      scoped_refptr<const ComputedStyle> correct_style =
-          state.StyleBuilder().CloneStyle();
-      DCHECK_EQ(g_null_atom, ComputeBaseComputedStyleDiff(applied_style.get(),
-                                                          *correct_style));
+      const ComputedStyle* correct_style = state.StyleBuilder().CloneStyle();
+      DCHECK_EQ(g_null_atom,
+                ComputeBaseComputedStyleDiff(applied_style, *correct_style));
 #endif
     } else {
       cascade.Apply(filter);
@@ -2363,8 +2355,7 @@
   apply(CascadeFilter(CSSProperty::kLegacyOverlapping, true));
 
   if (state.RejectedLegacyOverlapping()) {
-    scoped_refptr<const ComputedStyle> non_legacy_style =
-        state.StyleBuilder().CloneStyle();
+    const ComputedStyle* non_legacy_style = state.StyleBuilder().CloneStyle();
     // Re-apply all overlapping properties (both legacy and non-legacy).
     apply(CascadeFilter(CSSProperty::kOverlapping, false));
     UseCountLegacyOverlapping(GetDocument(), *non_legacy_style,
@@ -2460,7 +2451,7 @@
             ->EnsureScopedValue(&GetDocument()));
   }
   state.UpdateFont();
-  scoped_refptr<const ComputedStyle> font_style = state.TakeStyle();
+  const ComputedStyle* font_style = state.TakeStyle();
   return font_style->GetFont();
 }
 
@@ -2477,6 +2468,8 @@
 
 void StyleResolver::Trace(Visitor* visitor) const {
   visitor->Trace(matched_properties_cache_);
+  visitor->Trace(initial_style_);
+  visitor->Trace(initial_style_for_img_);
   visitor->Trace(selector_filter_);
   visitor->Trace(document_);
   visitor->Trace(tracker_);
@@ -2496,8 +2489,7 @@
   return builder;
 }
 
-scoped_refptr<const ComputedStyle>
-StyleResolver::CreateInheritedDisplayContentsStyleIfNeeded(
+const ComputedStyle* StyleResolver::CreateInheritedDisplayContentsStyleIfNeeded(
     const ComputedStyle& parent_style,
     const ComputedStyle& layout_parent_style) {
   if (parent_style.InheritedEqual(layout_parent_style)) {
@@ -2787,7 +2779,7 @@
 #undef PROPAGATE_VALUE
 #undef PROPAGATE_FROM
 
-scoped_refptr<const ComputedStyle> StyleResolver::StyleForFormattedText(
+const ComputedStyle* StyleResolver::StyleForFormattedText(
     bool is_text_run,
     const FontDescription& default_font,
     const CSSPropertyValueSet* css_property_value_set) {
@@ -2796,7 +2788,7 @@
                                css_property_value_set);
 }
 
-scoped_refptr<const ComputedStyle> StyleResolver::StyleForFormattedText(
+const ComputedStyle* StyleResolver::StyleForFormattedText(
     bool is_text_run,
     const ComputedStyle& parent_style,
     const CSSPropertyValueSet* css_property_value_set) {
@@ -2804,7 +2796,7 @@
                                &parent_style, css_property_value_set);
 }
 
-scoped_refptr<const ComputedStyle> StyleResolver::StyleForFormattedText(
+const ComputedStyle* StyleResolver::StyleForFormattedText(
     bool is_text_run,
     const FontDescription* default_font,
     const ComputedStyle* parent_style,
@@ -2893,7 +2885,7 @@
 //  * inline-sizing.
 // Additionally, all of the sizing properties and box-sizing also apply to
 // initial letters (see [css-sizing-3]).
-scoped_refptr<const ComputedStyle> StyleResolver::StyleForInitialLetterText(
+const ComputedStyle* StyleResolver::StyleForInitialLetterText(
     const ComputedStyle& initial_letter_box_style,
     const ComputedStyle& paragraph_style) {
   DCHECK(paragraph_style.InitialLetter().IsNormal());
@@ -2948,7 +2940,7 @@
   return position_fallback_rule;
 }
 
-scoped_refptr<const ComputedStyle> StyleResolver::ResolvePositionFallbackStyle(
+const ComputedStyle* StyleResolver::ResolvePositionFallbackStyle(
     Element& element,
     unsigned index) {
   const ComputedStyle& base_style = element.ComputedStyleRef();
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.h b/third_party/blink/renderer/core/css/resolver/style_resolver.h
index 5567e70..b3058f2 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -24,7 +24,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_STYLE_RESOLVER_H_
 
 #include "base/gtest_prod_util.h"
-#include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/core/animation/interpolation.h"
 #include "third_party/blink/renderer/core/animation/property_handle.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -66,10 +65,9 @@
   ~StyleResolver();
   void Dispose();
 
-  scoped_refptr<const ComputedStyle> ResolveStyle(
-      Element*,
-      const StyleRecalcContext&,
-      const StyleRequest& = StyleRequest());
+  const ComputedStyle* ResolveStyle(Element*,
+                                    const StyleRecalcContext&,
+                                    const StyleRequest& = StyleRequest());
 
   // Return a reference to the initial style singleton.
   const ComputedStyle& InitialStyle() const;
@@ -85,7 +83,7 @@
   // root element style. In addition to initial values things like zoom, font,
   // forced color mode etc. is set.
   ComputedStyleBuilder InitialStyleBuilderForElement() const;
-  scoped_refptr<const ComputedStyle> InitialStyleForElement() const {
+  const ComputedStyle* InitialStyleForElement() const {
     return InitialStyleBuilderForElement().TakeStyle();
   }
 
@@ -99,23 +97,22 @@
       const CSSValue*,
       double offset);
 
-  scoped_refptr<const ComputedStyle> StyleForPage(
-      uint32_t page_index,
-      const AtomicString& page_name);
-  scoped_refptr<const ComputedStyle> StyleForText(Text*);
-  scoped_refptr<const ComputedStyle> StyleForViewport();
-  scoped_refptr<const ComputedStyle> StyleForFormattedText(
+  const ComputedStyle* StyleForPage(uint32_t page_index,
+                                    const AtomicString& page_name);
+  const ComputedStyle* StyleForText(Text*);
+  const ComputedStyle* StyleForViewport();
+  const ComputedStyle* StyleForFormattedText(
       bool is_text_run,
       const ComputedStyle& parent_style,
       const CSSPropertyValueSet* css_property_value_set);
-  scoped_refptr<const ComputedStyle> StyleForFormattedText(
+  const ComputedStyle* StyleForFormattedText(
       bool is_text_run,
       const FontDescription& default_font,
       const CSSPropertyValueSet* css_property_value_set);
   // Returns `ComputedStyle` for rendering initial letter text.
   // `initial_letter_box_style` should have non-normal `initial-letter`
   // property.
-  scoped_refptr<const ComputedStyle> StyleForInitialLetterText(
+  const ComputedStyle* StyleForInitialLetterText(
       const ComputedStyle& initial_letter_box_style,
       const ComputedStyle& paragraph_style);
 
@@ -127,7 +124,7 @@
   ComputedStyleBuilder CreateAnonymousStyleBuilderWithDisplay(
       const ComputedStyle& parent_style,
       EDisplay);
-  scoped_refptr<const ComputedStyle> CreateAnonymousStyleWithDisplay(
+  const ComputedStyle* CreateAnonymousStyleWithDisplay(
       const ComputedStyle& parent_style,
       EDisplay display) {
     return CreateAnonymousStyleBuilderWithDisplay(parent_style, display)
@@ -136,8 +133,7 @@
 
   // Create ComputedStyle for anonymous wrappers between text boxes and
   // display:contents elements.
-  scoped_refptr<const ComputedStyle>
-  CreateInheritedDisplayContentsStyleIfNeeded(
+  const ComputedStyle* CreateInheritedDisplayContentsStyleIfNeeded(
       const ComputedStyle& parent_style,
       const ComputedStyle& layout_parent_style);
 
@@ -208,7 +204,7 @@
                                            const Font&,
                                            const CSSValue&);
 
-  scoped_refptr<const ComputedStyle> StyleForInterpolations(
+  const ComputedStyle* StyleForInterpolations(
       Element& element,
       ActiveInterpolationsMap& animations);
 
@@ -217,16 +213,14 @@
   // ticked to the current time. Ticking the animations is required to ensure
   // smooth retargeting of transitions.
   // https://drafts.csswg.org/css-transitions-1/#before-change-style
-  scoped_refptr<const ComputedStyle> BeforeChangeStyleForTransitionUpdate(
+  const ComputedStyle* BeforeChangeStyleForTransitionUpdate(
       Element& element,
       const ComputedStyle& base_style,
       ActiveInterpolationsMap& transition_interpolations);
   StyleRulePositionFallback* ResolvePositionFallbackRule(
       const TreeScope* tree_scope,
       AtomicString position_fallback_name);
-  scoped_refptr<const ComputedStyle> ResolvePositionFallbackStyle(
-      Element&,
-      unsigned index);
+  const ComputedStyle* ResolvePositionFallbackStyle(Element&, unsigned index);
 
   // Check if the BODY or HTML element's display or containment stops
   // propagation of BODY style to HTML and viewport.
@@ -345,8 +339,10 @@
                                 Functor& func) const;
 
   MatchedPropertiesCache matched_properties_cache_;
-  scoped_refptr<const ComputedStyle> initial_style_;
-  scoped_refptr<const ComputedStyle> initial_style_for_img_;
+
+  // Both these members are on a hot-path for creating ComputedStyle objects.
+  subtle::UncompressedMember<const ComputedStyle> initial_style_;
+  subtle::UncompressedMember<const ComputedStyle> initial_style_for_img_;
   SelectorFilter selector_filter_;
 
   Member<Document> document_;
@@ -364,7 +360,7 @@
   FRIEND_TEST_ALL_PREFIXES(StyleResolverTest, TreeScopedReferences);
 
   Element& EnsureElementForFormattedText();
-  scoped_refptr<const ComputedStyle> StyleForFormattedText(
+  const ComputedStyle* StyleForFormattedText(
       bool is_text_run,
       const FontDescription* default_font,
       const ComputedStyle* parent_style,
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
index a3d212d2..a4b5514 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
@@ -145,7 +145,7 @@
   return *inside_link_;
 }
 
-scoped_refptr<const ComputedStyle> StyleResolverState::TakeStyle() {
+const ComputedStyle* StyleResolverState::TakeStyle() {
   if (had_no_matched_properties_ &&
       pseudo_request_type_ == StyleRequest::kForRenderer) {
     return nullptr;
@@ -190,8 +190,7 @@
   return UnzoomedLengthConversionData(style_builder_->GetFontSizeStyle());
 }
 
-void StyleResolverState::SetParentStyle(
-    scoped_refptr<const ComputedStyle> parent_style) {
+void StyleResolverState::SetParentStyle(const ComputedStyle* parent_style) {
   parent_style_ = std::move(parent_style);
   if (style_builder_) {
     // Need to update conversion data for 'lh' units.
@@ -200,8 +199,8 @@
 }
 
 void StyleResolverState::SetLayoutParentStyle(
-    scoped_refptr<const ComputedStyle> parent_style) {
-  layout_parent_style_ = std::move(parent_style);
+    const ComputedStyle* parent_style) {
+  layout_parent_style_ = parent_style;
 }
 
 void StyleResolverState::LoadPendingResources() {
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
index ddb0484..978cfb2 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
@@ -112,7 +112,7 @@
   }
   ComputedStyleBuilder& StyleBuilder() { return *style_builder_; }
   const ComputedStyleBuilder& StyleBuilder() const { return *style_builder_; }
-  scoped_refptr<const ComputedStyle> TakeStyle();
+  const ComputedStyle* TakeStyle();
 
   const CSSToLengthConversionData& CssToLengthConversionData() const {
     return css_to_length_conversion_data_;
@@ -145,18 +145,16 @@
   // element, null otherwise.
   PseudoElement* GetPseudoElement() const;
 
-  void SetParentStyle(scoped_refptr<const ComputedStyle>);
-  const ComputedStyle* ParentStyle() const { return parent_style_.get(); }
+  void SetParentStyle(const ComputedStyle*);
+  const ComputedStyle* ParentStyle() const { return parent_style_; }
 
-  void SetLayoutParentStyle(scoped_refptr<const ComputedStyle>);
+  void SetLayoutParentStyle(const ComputedStyle*);
   const ComputedStyle* LayoutParentStyle() const {
-    return layout_parent_style_.get();
+    return layout_parent_style_;
   }
 
-  void SetOldStyle(scoped_refptr<const ComputedStyle> old_style) {
-    old_style_ = std::move(old_style);
-  }
-  const ComputedStyle* OldStyle() const { return old_style_.get(); }
+  void SetOldStyle(const ComputedStyle* old_style) { old_style_ = old_style; }
+  const ComputedStyle* OldStyle() const { return old_style_; }
 
   ElementStyleResources& GetElementStyleResources() {
     return element_style_resources_;
@@ -193,7 +191,7 @@
   const CSSValue& ResolveLightDarkPair(const CSSValue&);
 
   const ComputedStyle* OriginatingElementStyle() const {
-    return originating_element_style_.get();
+    return originating_element_style_;
   }
   bool IsForHighlight() const { return is_for_highlight_; }
   bool UsesHighlightPseudoInheritance() const {
@@ -269,14 +267,14 @@
 
   // parent_style_ is not always just ElementResolveContext::ParentStyle(),
   // so we keep it separate.
-  scoped_refptr<const ComputedStyle> parent_style_;
+  const ComputedStyle* parent_style_;
   // This will almost-always be the same that parent_style_, except in the
   // presence of display: contents. This is the style against which we have to
   // do adjustment.
-  scoped_refptr<const ComputedStyle> layout_parent_style_;
+  const ComputedStyle* layout_parent_style_;
   // The ComputedStyle stored on the element before the current lifecycle update
   // started.
-  scoped_refptr<const ComputedStyle> old_style_;
+  const ComputedStyle* old_style_;
 
   CSSAnimationUpdate animation_update_;
   StyleRequest::RequestType pseudo_request_type_;
@@ -303,7 +301,7 @@
   // This is computed only once, lazily (thus the absl::optional).
   mutable absl::optional<EInsideLink> inside_link_;
 
-  scoped_refptr<const ComputedStyle> originating_element_style_;
+  const ComputedStyle* originating_element_style_;
   // True if we are resolving styles for a highlight pseudo-element.
   const bool is_for_highlight_;
   // True if this is a highlight style request, and highlight inheritance
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
index 5a46eb0..61918a1c 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
@@ -50,11 +50,11 @@
 
 class StyleResolverTest : public PageTestBase {
  protected:
-  scoped_refptr<const ComputedStyle> StyleForId(const char* id) {
+  const ComputedStyle* StyleForId(const char* id) {
     Element* element = GetElementById(id);
     StyleRecalcContext recalc_context;
     recalc_context.old_style = element->GetComputedStyle();
-    auto style = GetStyleEngine().GetStyleResolver().ResolveStyle(
+    const auto* style = GetStyleEngine().GetStyleResolver().ResolveStyle(
         element, recalc_context);
     DCHECK(style);
     return style;
@@ -149,7 +149,7 @@
   StyleResolver& resolver = GetStyleEngine().GetStyleResolver();
   StyleRecalcContext recalc_context;
   recalc_context.old_style = div->GetComputedStyle();
-  auto style1 = resolver.ResolveStyle(div, recalc_context);
+  const auto* style1 = resolver.ResolveStyle(div, recalc_context);
   ASSERT_TRUE(style1);
   EXPECT_EQ(20, style1->FontSize());
   ASSERT_TRUE(style1->GetBaseComputedStyle());
@@ -225,7 +225,7 @@
 
   div->SetNeedsAnimationStyleRecalc();
   GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
-  auto style = StyleForId("div");
+  const auto* style = StyleForId("div");
 
   const CSSBitset* bitset = style->GetBaseImportantSet();
   EXPECT_FALSE(CSSAnimations::IsAnimatingStandardProperties(
@@ -295,7 +295,7 @@
 
   div->SetNeedsAnimationStyleRecalc();
   GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
-  auto style = StyleForId("div");
+  const auto* style = StyleForId("div");
 
   EXPECT_TRUE(style->GetBaseComputedStyle());
   EXPECT_TRUE(style->GetBaseImportantSet());
@@ -372,7 +372,7 @@
 
   div->SetNeedsAnimationStyleRecalc();
   GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
-  auto computed_style = StyleForId("div");
+  const auto* computed_style = StyleForId("div");
 
   EXPECT_TRUE(computed_style->HasFontRelativeUnits());
   EXPECT_TRUE(computed_style->GetBaseComputedStyle());
@@ -396,7 +396,7 @@
 
   div->SetNeedsAnimationStyleRecalc();
   GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
-  auto computed_style = StyleForId("div");
+  const auto* computed_style = StyleForId("div");
 
   EXPECT_TRUE(computed_style->HasFontRelativeUnits());
   EXPECT_TRUE(computed_style->GetBaseComputedStyle());
@@ -610,7 +610,7 @@
   )HTML");
 
   GetDocument().GetStyleEngine().UpdateActiveStyle();
-  scoped_refptr<const ComputedStyle> page_style =
+  const ComputedStyle* page_style =
       GetDocument().GetStyleResolver().StyleForPage(0, g_empty_atom);
   ASSERT_TRUE(page_style);
   const CSSValue* computed_value = ComputedStyleUtils::ComputedPropertyValue(
@@ -646,7 +646,7 @@
   StyleRequest target_text_style_request = pseudo_style_request;
   target_text_style_request.pseudo_id = kPseudoIdTargetText;
 
-  scoped_refptr<const ComputedStyle> target_text_style =
+  const ComputedStyle* target_text_style =
       GetDocument().GetStyleResolver().ResolveStyle(GetDocument().body(),
                                                     StyleRecalcContext(),
                                                     target_text_style_request);
@@ -655,7 +655,7 @@
   StyleRequest selection_style_style_request = pseudo_style_request;
   selection_style_style_request.pseudo_id = kPseudoIdSelection;
 
-  scoped_refptr<const ComputedStyle> selection_style =
+  const ComputedStyle* selection_style =
       GetDocument().GetStyleResolver().ResolveStyle(
           GetDocument().body(), StyleRecalcContext(),
           selection_style_style_request);
@@ -671,8 +671,7 @@
   CursorList* cursor_list = target_text_style->Cursors();
   ASSERT_FALSE(cursor_list);
 
-  for (const auto* pseudo_style :
-       {target_text_style.get(), selection_style.get()}) {
+  for (const auto* pseudo_style : {target_text_style, selection_style}) {
     // Check that the color applies.
     EXPECT_EQ(Color(0, 128, 0),
               pseudo_style->VisitedDependentColor(GetCSSPropertyColor()));
@@ -1025,9 +1024,9 @@
 
   c->EnsureComputedStyle();
 
-  scoped_refptr<const ComputedStyle> a_style = a->GetComputedStyle();
-  scoped_refptr<const ComputedStyle> b_style = b->GetComputedStyle();
-  scoped_refptr<const ComputedStyle> c_style = c->GetComputedStyle();
+  const ComputedStyle* a_style = a->GetComputedStyle();
+  const ComputedStyle* b_style = b->GetComputedStyle();
+  const ComputedStyle* c_style = c->GetComputedStyle();
 
   ASSERT_TRUE(a_style);
   ASSERT_TRUE(b_style);
@@ -1050,9 +1049,9 @@
   EXPECT_TRUE(c->GetComputedStyle());
   EXPECT_TRUE(d->GetComputedStyle());
   EXPECT_TRUE(e->GetComputedStyle());
-  EXPECT_NE(a_style.get(), a->GetComputedStyle());
-  EXPECT_NE(b_style.get(), b->GetComputedStyle());
-  EXPECT_NE(c_style.get(), c->GetComputedStyle());
+  EXPECT_NE(a_style, a->GetComputedStyle());
+  EXPECT_NE(b_style, b->GetComputedStyle());
+  EXPECT_NE(c_style, c->GetComputedStyle());
 }
 
 TEST_F(StyleResolverTest, ComputeValueStandardProperty) {
@@ -1309,7 +1308,7 @@
   pseudo_style_request.layout_parent_override = element_style;
   pseudo_style_request.originating_element_style = element_style;
   pseudo_style_request.pseudo_id = kPseudoIdSelection;
-  scoped_refptr<const ComputedStyle> selection_style =
+  const ComputedStyle* selection_style =
       GetDocument().GetStyleResolver().ResolveStyle(
           target, StyleRecalcContext(), pseudo_style_request);
   ASSERT_FALSE(selection_style);
@@ -1350,7 +1349,7 @@
   pseudo_style_request.layout_parent_override = element_style;
   pseudo_style_request.originating_element_style = element_style;
   pseudo_style_request.pseudo_id = kPseudoIdSelection;
-  scoped_refptr<const ComputedStyle> selection_style =
+  const ComputedStyle* selection_style =
       GetDocument().GetStyleResolver().ResolveStyle(
           target, StyleRecalcContext(), pseudo_style_request);
   ASSERT_TRUE(selection_style);
@@ -1390,7 +1389,7 @@
   pseudo_style_request.layout_parent_override = element_style;
   pseudo_style_request.originating_element_style = element_style;
   pseudo_style_request.pseudo_id = kPseudoIdSelection;
-  scoped_refptr<const ComputedStyle> selection_style =
+  const ComputedStyle* selection_style =
       GetDocument().GetStyleResolver().ResolveStyle(
           target, StyleRecalcContext(), pseudo_style_request);
   ASSERT_TRUE(selection_style);
@@ -1427,7 +1426,7 @@
   pseudo_style_request.layout_parent_override = element_style;
   pseudo_style_request.originating_element_style = element_style;
   pseudo_style_request.pseudo_id = kPseudoIdSelection;
-  scoped_refptr<const ComputedStyle> selection_style =
+  const ComputedStyle* selection_style =
       GetDocument().GetStyleResolver().ResolveStyle(
           target, StyleRecalcContext(), pseudo_style_request);
   ASSERT_TRUE(selection_style);
@@ -1467,7 +1466,7 @@
   pseudo_style_request.layout_parent_override = element_style;
   pseudo_style_request.originating_element_style = element_style;
   pseudo_style_request.pseudo_id = kPseudoIdSelection;
-  scoped_refptr<const ComputedStyle> selection_style =
+  const ComputedStyle* selection_style =
       GetDocument().GetStyleResolver().ResolveStyle(
           target, StyleRecalcContext(), pseudo_style_request);
   ASSERT_TRUE(selection_style);
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index a3fb49e..615f1ed 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -3744,12 +3744,11 @@
     return;
   }
 
-  scoped_refptr<const ComputedStyle> viewport_style =
-      resolver_->StyleForViewport();
+  const ComputedStyle* viewport_style = resolver_->StyleForViewport();
   if (ComputedStyle::ComputeDifference(
-          viewport_style.get(), GetDocument().GetLayoutView()->Style()) !=
+          viewport_style, GetDocument().GetLayoutView()->Style()) !=
       ComputedStyle::Difference::kEqual) {
-    GetDocument().GetLayoutView()->SetStyle(std::move(viewport_style));
+    GetDocument().GetLayoutView()->SetStyle(viewport_style);
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index c0186d9..81b6fca 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -2749,8 +2749,8 @@
   EXPECT_FALSE(innermost->GetComputedStyle());
 
   inner->EnsureComputedStyle();
-  scoped_refptr<const ComputedStyle> outer_style = outer->GetComputedStyle();
-  scoped_refptr<const ComputedStyle> inner_style = inner->GetComputedStyle();
+  const ComputedStyle* outer_style = outer->GetComputedStyle();
+  const ComputedStyle* inner_style = inner->GetComputedStyle();
 
   ASSERT_TRUE(outer_style);
   ASSERT_TRUE(inner_style);
@@ -3920,8 +3920,7 @@
   auto* inner_editor = DynamicTo<HTMLInputElement>(input)->InnerEditorElement();
   ASSERT_TRUE(inner_editor);
 
-  scoped_refptr<const ComputedStyle> old_inner_style =
-      inner_editor->GetComputedStyle();
+  const ComputedStyle* old_inner_style = inner_editor->GetComputedStyle();
   EXPECT_TRUE(old_inner_style);
 
   unsigned start_count = GetStyleEngine().StyleForElementCount();
@@ -4787,14 +4786,14 @@
   // with ChildNeedsStyleRecalc(), but the child needs to be marked dirty to
   // make sure the next EnsureComputedStyle updates the style to reflect the
   // changes.
-  scoped_refptr<const ComputedStyle> old_style = span->EnsureComputedStyle();
+  const ComputedStyle* old_style = span->EnsureComputedStyle();
   span->SetInlineStyleProperty(CSSPropertyID::kColor, "green");
   EXPECT_FALSE(host->ChildNeedsStyleRecalc());
   EXPECT_TRUE(span->NeedsStyleRecalc());
   UpdateAllLifecyclePhases();
 
   EXPECT_EQ(span->GetComputedStyle(), old_style);
-  scoped_refptr<const ComputedStyle> new_style = span->EnsureComputedStyle();
+  const ComputedStyle* new_style = span->EnsureComputedStyle();
   EXPECT_NE(new_style, old_style);
 
   EXPECT_EQ(Color::FromRGB(255, 0, 0),
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index b0b50d6..0bc6e7e 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -145,7 +145,7 @@
       element_.Get());
 }
 
-scoped_refptr<const ComputedStyle> DisplayLockContext::AdjustElementStyle(
+const ComputedStyle* DisplayLockContext::AdjustElementStyle(
     const ComputedStyle* style) const {
   if (IsAlwaysVisible())
     return style;
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index b5e9e66a..05b9ec0 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -107,8 +107,7 @@
   void SetRequestedState(EContentVisibility state,
                          const AtomicString& toggle_visibility);
   // Called by style to adjust the element's style based on the current state.
-  scoped_refptr<const ComputedStyle> AdjustElementStyle(
-      const ComputedStyle*) const;
+  const ComputedStyle* AdjustElementStyle(const ComputedStyle*) const;
 
   // Is called by the intersection observer callback to inform us of the
   // intersection state.
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index c6bb820..3973509 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2724,16 +2724,15 @@
     focused_element_->blur();
 }
 
-scoped_refptr<const ComputedStyle> Document::StyleForPage(uint32_t page_index) {
+const ComputedStyle* Document::StyleForPage(uint32_t page_index) {
   AtomicString page_name;
   if (const LayoutView* layout_view = GetLayoutView())
     page_name = layout_view->NamedPageAtIndex(page_index);
   return StyleForPage(page_index, page_name);
 }
 
-scoped_refptr<const ComputedStyle> Document::StyleForPage(
-    uint32_t page_index,
-    const AtomicString& page_name) {
+const ComputedStyle* Document::StyleForPage(uint32_t page_index,
+                                            const AtomicString& page_name) {
   GetStyleEngine().UpdateViewportSize();
   GetStyleEngine().UpdateActiveStyle();
   return GetStyleEngine().GetStyleResolver().StyleForPage(page_index,
@@ -2874,8 +2873,7 @@
   DCHECK(!ax_object_cache_ || this != &AXObjectCacheOwner());
 
   UpdateForcedColors();
-  scoped_refptr<const ComputedStyle> style =
-      GetStyleResolver().StyleForViewport();
+  const ComputedStyle* style = GetStyleResolver().StyleForViewport();
   layout_view_ = MakeGarbageCollected<LayoutNGView>(this);
   SetLayoutObject(layout_view_);
 
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 848a685..56ecb26 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -740,10 +740,9 @@
   // Get the computed style for a given page and name. Note that when using the
   // function that doesn't provide a page name, layout needs to be complete,
   // since page names are determined during layout.
-  scoped_refptr<const ComputedStyle> StyleForPage(uint32_t page_index);
-  scoped_refptr<const ComputedStyle> StyleForPage(
-      uint32_t page_index,
-      const AtomicString& page_name);
+  const ComputedStyle* StyleForPage(uint32_t page_index);
+  const ComputedStyle* StyleForPage(uint32_t page_index,
+                                    const AtomicString& page_name);
 
   // Ensures that location-based data will be valid for a given node.
   //
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 62c2ef2b..e135f19a 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3085,7 +3085,7 @@
   ClearNeedsReattachLayoutTree();
 }
 
-scoped_refptr<const ComputedStyle> Element::StyleForLayoutObject(
+const ComputedStyle* Element::StyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
   DCHECK(GetDocument().InStyleRecalc());
 
@@ -3105,7 +3105,7 @@
   }
 
   new_style_recalc_context.old_style = PostStyleUpdateScope::GetOldStyle(*this);
-  scoped_refptr<const ComputedStyle> style =
+  const ComputedStyle* style =
       HasCustomStyleCallbacks()
           ? CustomStyleForLayoutObject(new_style_recalc_context)
           : OriginalStyleForLayoutObject(new_style_recalc_context);
@@ -3118,7 +3118,7 @@
     // time to compute the actual style and trigger transitions starting from
     // style with @starting-style applied.
     new_style_recalc_context.old_style =
-        style->Display() == EDisplay::kNone ? nullptr : style.get();
+        style->Display() == EDisplay::kNone ? nullptr : style;
     style = HasCustomStyleCallbacks()
                 ? CustomStyleForLayoutObject(new_style_recalc_context)
                 : OriginalStyleForLayoutObject(new_style_recalc_context);
@@ -3142,7 +3142,7 @@
       }
     }
     context->SetRequestedState(style->ContentVisibility(), toggle_visibility);
-    style = context->AdjustElementStyle(style.get());
+    style = context->AdjustElementStyle(style);
   }
 
   if (style->DependsOnSizeContainerQueries()) {
@@ -3157,7 +3157,7 @@
   AdjustStyle(builder);
 }
 
-scoped_refptr<const ComputedStyle> Element::OriginalStyleForLayoutObject(
+const ComputedStyle* Element::OriginalStyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
   return GetDocument().GetStyleResolver().ResolveStyle(this,
                                                        style_recalc_context);
@@ -3427,7 +3427,7 @@
   }
 }
 
-scoped_refptr<const ComputedStyle> Element::PropagateInheritedProperties() {
+const ComputedStyle* Element::PropagateInheritedProperties() {
   if (IsPseudoElement()) {
     return nullptr;
   }
@@ -3550,8 +3550,8 @@
     new_style_recalc_context.parent_forces_recalc = true;
   }
 
-  scoped_refptr<const ComputedStyle> new_style;
-  scoped_refptr<const ComputedStyle> old_style = GetComputedStyle();
+  const ComputedStyle* new_style = nullptr;
+  const ComputedStyle* old_style = GetComputedStyle();
 
   StyleRecalcChange child_change = change.ForChildren(*this);
 
@@ -3592,7 +3592,7 @@
   }
 
   if (HighlightRecalc highlight_recalc =
-          CalculateHighlightRecalc(old_style.get(), new_style.get());
+          CalculateHighlightRecalc(old_style, new_style);
       highlight_recalc != HighlightRecalc::kNone) {
     DCHECK(new_style);
 
@@ -3605,48 +3605,48 @@
       DCHECK_EQ(highlight_recalc, HighlightRecalc::kFull);
 
       const StyleHighlightData* parent_highlights =
-          parent_style ? parent_style->HighlightData().get() : nullptr;
+          parent_style ? &parent_style->HighlightData() : nullptr;
 
       if (UsesHighlightPseudoInheritance(kPseudoIdSelection) &&
           new_style->HasPseudoElementStyle(kPseudoIdSelection)) {
-        StyleHighlightData& highlights = builder.MutableHighlightData();
+        StyleHighlightData& highlights = builder.AccessHighlightData();
         const ComputedStyle* highlight_parent =
             parent_highlights ? parent_highlights->Selection() : nullptr;
         StyleRequest style_request{kPseudoIdSelection, highlight_parent};
-        style_request.originating_element_style = new_style.get();
+        style_request.originating_element_style = new_style;
         highlights.SetSelection(
             StyleForPseudoElement(new_style_recalc_context, style_request));
       }
 
       if (UsesHighlightPseudoInheritance(kPseudoIdTargetText) &&
           new_style->HasPseudoElementStyle(kPseudoIdTargetText)) {
-        StyleHighlightData& highlights = builder.MutableHighlightData();
+        StyleHighlightData& highlights = builder.AccessHighlightData();
         const ComputedStyle* highlight_parent =
             parent_highlights ? parent_highlights->TargetText() : nullptr;
         StyleRequest style_request{kPseudoIdTargetText, highlight_parent};
-        style_request.originating_element_style = new_style.get();
+        style_request.originating_element_style = new_style;
         highlights.SetTargetText(
             StyleForPseudoElement(new_style_recalc_context, style_request));
       }
 
       if (UsesHighlightPseudoInheritance(kPseudoIdSpellingError) &&
           new_style->HasPseudoElementStyle(kPseudoIdSpellingError)) {
-        StyleHighlightData& highlights = builder.MutableHighlightData();
+        StyleHighlightData& highlights = builder.AccessHighlightData();
         const ComputedStyle* highlight_parent =
             parent_highlights ? parent_highlights->SpellingError() : nullptr;
         StyleRequest style_request{kPseudoIdSpellingError, highlight_parent};
-        style_request.originating_element_style = new_style.get();
+        style_request.originating_element_style = new_style;
         highlights.SetSpellingError(
             StyleForPseudoElement(new_style_recalc_context, style_request));
       }
 
       if (UsesHighlightPseudoInheritance(kPseudoIdGrammarError) &&
           new_style->HasPseudoElementStyle(kPseudoIdGrammarError)) {
-        StyleHighlightData& highlights = builder.MutableHighlightData();
+        StyleHighlightData& highlights = builder.AccessHighlightData();
         const ComputedStyle* highlight_parent =
             parent_highlights ? parent_highlights->GrammarError() : nullptr;
         StyleRequest style_request{kPseudoIdGrammarError, highlight_parent};
-        style_request.originating_element_style = new_style.get();
+        style_request.originating_element_style = new_style;
         highlights.SetGrammarError(
             StyleForPseudoElement(new_style_recalc_context, style_request));
       }
@@ -3658,14 +3658,14 @@
         if (custom_highlight_names) {
           for (const AtomicString& custom_highlight_name :
                *custom_highlight_names) {
-            StyleHighlightData& highlights = builder.MutableHighlightData();
+            StyleHighlightData& highlights = builder.AccessHighlightData();
             const ComputedStyle* highlight_parent =
                 parent_highlights
                     ? parent_highlights->CustomHighlight(custom_highlight_name)
                     : nullptr;
             StyleRequest style_request{kPseudoIdHighlight, highlight_parent,
                                        custom_highlight_name};
-            style_request.originating_element_style = new_style.get();
+            style_request.originating_element_style = new_style;
             highlights.SetCustomHighlight(
                 custom_highlight_name,
                 StyleForPseudoElement(new_style_recalc_context, style_request));
@@ -3678,7 +3678,7 @@
   }
 
   ComputedStyle::Difference diff =
-      ComputedStyle::ComputeDifference(old_style.get(), new_style.get());
+      ComputedStyle::ComputeDifference(old_style, new_style);
 
   if (old_style && old_style->IsEnsuredInDisplayNone()) {
     // Make sure we traverse children for clearing ensured computed styles
@@ -3727,8 +3727,7 @@
 
   if (!child_change.ReattachLayoutTree() &&
       (GetForceReattachLayoutTree() || NeedsReattachLayoutTree() ||
-       ComputedStyle::NeedsReattachLayoutTree(*this, old_style.get(),
-                                              new_style.get()))) {
+       ComputedStyle::NeedsReattachLayoutTree(*this, old_style, new_style))) {
     child_change = child_change.ForceReattachLayoutTree();
   }
 
@@ -3742,10 +3741,10 @@
   } else {
     INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
                                   styles_changed, 1);
-    probe::DidUpdateComputedStyle(this, old_style.get(), new_style.get());
+    probe::DidUpdateComputedStyle(this, old_style, new_style);
     if (this == GetDocument().documentElement()) {
       if (GetDocument().GetStyleEngine().UpdateRootFontRelativeUnits(
-              old_style.get(), new_style.get())) {
+              old_style, new_style)) {
         // Trigger a full document recalc on root font units changes. We could
         // keep track of which elements depend on root font units like we do for
         // viewport styles, but we assume root font size changes are rare and
@@ -3755,9 +3754,8 @@
       }
     }
     child_change = ApplyComputedStyleDiff(child_change, diff);
-    UpdateCallbackSelectors(old_style.get(), new_style.get());
-    NotifyIfMatchedDocumentRulesSelectorsChanged(old_style.get(),
-                                                 new_style.get());
+    UpdateCallbackSelectors(old_style, new_style);
+    NotifyIfMatchedDocumentRulesSelectorsChanged(old_style, new_style);
   }
 
   if (auto* context = GetDisplayLockContext()) {
@@ -3848,7 +3846,7 @@
             ? LayoutObject::ApplyStyleChanges::kNo
             : LayoutObject::ApplyStyleChanges::kYes;
 
-    scoped_refptr<const ComputedStyle> layout_style(std::move(new_style));
+    const ComputedStyle* layout_style = new_style;
     if (auto* pseudo_element = DynamicTo<PseudoElement>(this)) {
       if (layout_style->Display() == EDisplay::kContents) {
         layout_style =
@@ -3870,7 +3868,7 @@
         apply_changes = LayoutObject::ApplyStyleChanges::kYes;
       }
     }
-    layout_object->SetStyle(layout_style.get(), apply_changes);
+    layout_object->SetStyle(layout_style, apply_changes);
   }
   return child_change;
 }
@@ -6357,7 +6355,7 @@
     if (!element_style) {
       StyleRecalcContext local_style_recalc_context = style_recalc_context;
       local_style_recalc_context.is_ensuring_style = true;
-      scoped_refptr<const ComputedStyle> new_style = nullptr;
+      const ComputedStyle* new_style = nullptr;
       // TODO(crbug.com/953707): Avoid setting inline style during
       // HTMLImageElement::CustomStyleForLayoutObject.
       if (HasCustomStyleCallbacks() && !IsA<HTMLImageElement>(*this)) {
@@ -6365,8 +6363,8 @@
       } else {
         new_style = OriginalStyleForLayoutObject(local_style_recalc_context);
       }
-      element_style = new_style.get();
-      SetComputedStyle(std::move(new_style));
+      element_style = new_style;
+      SetComputedStyle(new_style);
     }
   }
 
@@ -6395,9 +6393,9 @@
   if (UsesHighlightPseudoInheritance(pseudo_element_specifier)) {
     const ComputedStyle* highlight_element_style = nullptr;
     ContainerNode* parent = LayoutTreeBuilderTraversal::Parent(*this);
-    if (parent && parent->GetComputedStyle()->HighlightData()) {
+    if (parent) {
       highlight_element_style =
-          parent->GetComputedStyle()->HighlightData()->Style(
+          parent->GetComputedStyle()->HighlightData().Style(
               pseudo_element_specifier, pseudo_argument);
     }
     style_request.parent_override = highlight_element_style;
@@ -6418,12 +6416,11 @@
     child_recalc_context.container = this;
   }
 
-  scoped_refptr<const ComputedStyle> result =
-      GetDocument().GetStyleResolver().ResolveStyle(this, child_recalc_context,
-                                                    style_request);
+  const ComputedStyle* result = GetDocument().GetStyleResolver().ResolveStyle(
+      this, child_recalc_context, style_request);
   DCHECK(result);
   return element_style->AddCachedPseudoElementStyle(
-      std::move(result), pseudo_element_specifier, pseudo_argument);
+      result, pseudo_element_specifier, pseudo_argument);
 }
 
 bool Element::HasDisplayContentsStyle() const {
@@ -6642,10 +6639,10 @@
     // RemainingTextLayoutObject should have been cleared from DetachLayoutTree.
     DCHECK(!To<FirstLetterPseudoElement>(element)->RemainingTextLayoutObject());
     DCHECK(text_node_changed);
-    scoped_refptr<const ComputedStyle> pseudo_style =
+    const ComputedStyle* pseudo_style =
         element->StyleForLayoutObject(style_recalc_context);
-    if (PseudoElementLayoutObjectIsNeeded(pseudo_style.get(), this)) {
-      element->SetComputedStyle(std::move(pseudo_style));
+    if (PseudoElementLayoutObjectIsNeeded(pseudo_style, this)) {
+      element->SetComputedStyle(pseudo_style);
     } else {
       GetElementRareData()->SetPseudoElement(kPseudoIdFirstLetter, nullptr);
     }
@@ -6727,9 +6724,9 @@
                                            view_transition_name);
   pseudo_element->InsertedInto(*this);
 
-  scoped_refptr<const ComputedStyle> pseudo_style =
+  const ComputedStyle* pseudo_style =
       pseudo_element->StyleForLayoutObject(style_recalc_context);
-  if (!PseudoElementLayoutObjectIsNeeded(pseudo_style.get(), this)) {
+  if (!PseudoElementLayoutObjectIsNeeded(pseudo_style, this)) {
     GetElementRareData()->SetPseudoElement(pseudo_id, nullptr,
                                            view_transition_name);
     return nullptr;
@@ -6866,16 +6863,16 @@
     return cached;
   }
 
-  scoped_refptr<const ComputedStyle> result = UncachedStyleForPseudoElement(
+  const ComputedStyle* result = UncachedStyleForPseudoElement(
       StyleRequest(pseudo_id, style, pseudo_argument));
   if (result) {
-    return style->AddCachedPseudoElementStyle(std::move(result), pseudo_id,
+    return style->AddCachedPseudoElementStyle(result, pseudo_id,
                                               pseudo_argument);
   }
   return nullptr;
 }
 
-scoped_refptr<const ComputedStyle> Element::UncachedStyleForPseudoElement(
+const ComputedStyle* Element::UncachedStyleForPseudoElement(
     const StyleRequest& request) {
   // Highlight pseudos are resolved into StyleHighlightData during originating
   // style recalc, where we have the actual StyleRecalcContext.
@@ -6885,7 +6882,7 @@
       StyleRecalcContext::FromInclusiveAncestors(*this), request);
 }
 
-scoped_refptr<const ComputedStyle> Element::StyleForPseudoElement(
+const ComputedStyle* Element::StyleForPseudoElement(
     const StyleRecalcContext& style_recalc_context,
     const StyleRequest& request) {
   GetDocument().GetStyleEngine().UpdateViewportSize();
@@ -6910,9 +6907,8 @@
     }
     StyleRequest before_after_request = request;
     before_after_request.layout_parent_override = layout_parent_style;
-    scoped_refptr<const ComputedStyle> result =
-        GetDocument().GetStyleResolver().ResolveStyle(
-            this, style_recalc_context, before_after_request);
+    const ComputedStyle* result = GetDocument().GetStyleResolver().ResolveStyle(
+        this, style_recalc_context, before_after_request);
     if (result) {
       if (auto* quote = DynamicTo<HTMLQuoteElement>(this)) {
         ComputedStyleBuilder builder(*result);
@@ -6932,9 +6928,8 @@
     StyleRecalcContext local_recalc_context(style_recalc_context);
     local_recalc_context.old_style = PostStyleUpdateScope::GetOldStyle(*this);
     Element* target = IsPseudoElement() ? parentElement() : this;
-    scoped_refptr<const ComputedStyle> result =
-        GetDocument().GetStyleResolver().ResolveStyle(
-            target, local_recalc_context, first_line_inherited_request);
+    const ComputedStyle* result = GetDocument().GetStyleResolver().ResolveStyle(
+        target, local_recalc_context, first_line_inherited_request);
     if (result) {
       ComputedStyleBuilder builder(*result);
       builder.SetStyleType(kPseudoIdFirstLineInherited);
@@ -7663,7 +7658,7 @@
   DCHECK(HasCustomStyleCallbacks());
 }
 
-scoped_refptr<const ComputedStyle> Element::CustomStyleForLayoutObject(
+const ComputedStyle* Element::CustomStyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
   DCHECK(HasCustomStyleCallbacks());
   return OriginalStyleForLayoutObject(style_recalc_context);
@@ -8838,13 +8833,13 @@
     return cached_style;
   }
 
-  scoped_refptr<const ComputedStyle> style =
+  const ComputedStyle* style =
       GetDocument().GetStyleResolver().ResolvePositionFallbackStyle(*this,
                                                                     index);
   if (!style) {
     return nullptr;
   }
-  return base_style->AddCachedPositionFallbackStyle(std::move(style), index);
+  return base_style->AddCachedPositionFallbackStyle(style, index);
 }
 
 CSSToggleMap* Element::GetToggleMap() {
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 03f0bbfa..86512ba 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -903,17 +903,15 @@
   //
   // This is appropriate to use if the cached version is invalid in a given
   // situation.
-  scoped_refptr<const ComputedStyle> UncachedStyleForPseudoElement(
-      const StyleRequest&);
+  const ComputedStyle* UncachedStyleForPseudoElement(const StyleRequest&);
 
   // This is the same as UncachedStyleForPseudoElement, except that the caller
   // must provide an appropriate StyleRecalcContext such that e.g. @container
   // queries are evaluated correctly.
   //
   // See StyleRecalcContext for more information.
-  scoped_refptr<const ComputedStyle> StyleForPseudoElement(
-      const StyleRecalcContext&,
-      const StyleRequest&);
+  const ComputedStyle* StyleForPseudoElement(const StyleRecalcContext&,
+                                             const StyleRequest&);
 
   // Returns the ComputedStyle after applying the declarations in the @try block
   // at the given index. Returns nullptr if the current element doesn't use
@@ -1011,8 +1009,7 @@
   bool IsSpellCheckingEnabled() const;
 
   // FIXME: public for LayoutTreeBuilder, we shouldn't expose this though.
-  scoped_refptr<const ComputedStyle> StyleForLayoutObject(
-      const StyleRecalcContext&);
+  const ComputedStyle* StyleForLayoutObject(const StyleRecalcContext&);
 
   // Called by StyleAdjuster during style resolution. Provides an opportunity to
   // make final Element-specific adjustments to the ComputedStyle.
@@ -1242,7 +1239,7 @@
 
   virtual void WillRecalcStyle(const StyleRecalcChange);
   virtual void DidRecalcStyle(const StyleRecalcChange);
-  virtual scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  virtual const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&);
   virtual void AdjustStyle(ComputedStyleBuilder&);
 
@@ -1283,8 +1280,7 @@
 
   static bool AttributeValueIsJavaScriptURL(const Attribute&);
 
-  scoped_refptr<const ComputedStyle> OriginalStyleForLayoutObject(
-      const StyleRecalcContext&);
+  const ComputedStyle* OriginalStyleForLayoutObject(const StyleRecalcContext&);
 
   // Step 4 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
   Node* InsertAdjacent(const String& where, Node* new_child, ExceptionState&);
@@ -1344,7 +1340,7 @@
   // these changes can be directly propagated to this element (the child).
   // If these conditions are met, propagates the changes to the current style
   // and returns the new style. Otherwise, returns null.
-  scoped_refptr<const ComputedStyle> PropagateInheritedProperties();
+  const ComputedStyle* PropagateInheritedProperties();
 
   const ComputedStyle* EnsureOwnComputedStyle(
       const StyleRecalcContext&,
diff --git a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
index cddfabf..918fad6b 100644
--- a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
+++ b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
@@ -342,8 +342,7 @@
   return PseudoElement::CreateLayoutObject(style);
 }
 
-scoped_refptr<const ComputedStyle>
-FirstLetterPseudoElement::CustomStyleForLayoutObject(
+const ComputedStyle* FirstLetterPseudoElement::CustomStyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
   LayoutObject* first_letter_text =
       FirstLetterPseudoElement::FirstLetterTextLayoutObject(*this);
@@ -418,7 +417,7 @@
     // compute initial-letter font during layout to take proper effective style.
     const ComputedStyle& paragraph_style =
         paragraph.EffectiveStyle(NGStyleVariant::kFirstLine);
-    scoped_refptr<const ComputedStyle> initial_letter_text_style =
+    const ComputedStyle* initial_letter_text_style =
         GetDocument().GetStyleResolver().StyleForInitialLetterText(
             *letter_style, paragraph_style);
     letter->SetStyle(std::move(initial_letter_text_style));
diff --git a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h
index 8bd93e34..9134025 100644
--- a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h
+++ b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h
@@ -62,7 +62,7 @@
  private:
   LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
 
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&) override;
 
   void AttachFirstLetterTextLayoutObjects(LayoutText* first_letter_text);
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.cc b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
index 5a0d727..80aeee9 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder.cc
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
@@ -128,7 +128,7 @@
   parent_layout_object->AddChild(new_layout_object, next_layout_object);
 }
 
-scoped_refptr<const ComputedStyle>
+const ComputedStyle*
 LayoutTreeBuilderForText::CreateInlineWrapperStyleForDisplayContentsIfNeeded()
     const {
   // If the parent element is not a display:contents element, the style and the
@@ -164,20 +164,20 @@
 }
 
 void LayoutTreeBuilderForText::CreateLayoutObject() {
-  const ComputedStyle* style = style_.get();
+  const ComputedStyle* style = style_;
   LayoutObject* layout_object_parent = context_.parent;
   LayoutObject* next_layout_object = NextLayoutObject();
-  scoped_refptr<const ComputedStyle> nullable_wrapper_style =
+  const ComputedStyle* nullable_wrapper_style =
       CreateInlineWrapperStyleForDisplayContentsIfNeeded();
   if (LayoutObject* wrapper = CreateInlineWrapperForDisplayContentsIfNeeded(
-          nullable_wrapper_style.get())) {
+          nullable_wrapper_style)) {
     layout_object_parent = wrapper;
     next_layout_object = nullptr;
   }
   // SVG <text> doesn't accept anonymous LayoutInlines. But the Text should have
   // the adjusted ComputedStyle.
   if (nullable_wrapper_style)
-    style = nullable_wrapper_style.get();
+    style = nullable_wrapper_style;
 
   LayoutText* new_layout_object = node_->CreateTextLayoutObject();
   if (!layout_object_parent->IsChildAllowed(new_layout_object, *style)) {
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.h b/third_party/blink/renderer/core/dom/layout_tree_builder.h
index bf88e493..47a42f1 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder.h
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder.h
@@ -102,7 +102,7 @@
 
   NodeType* node_;
   Node::AttachContext& context_;
-  scoped_refptr<const ComputedStyle> style_;
+  const ComputedStyle* style_;
 };
 
 class LayoutTreeBuilderForElement : public LayoutTreeBuilder<Element> {
@@ -128,8 +128,8 @@
   void CreateLayoutObject();
 
  private:
-  scoped_refptr<const ComputedStyle>
-  CreateInlineWrapperStyleForDisplayContentsIfNeeded() const;
+  const ComputedStyle* CreateInlineWrapperStyleForDisplayContentsIfNeeded()
+      const;
   LayoutObject* CreateInlineWrapperForDisplayContentsIfNeeded(
       const ComputedStyle* wrapper_style) const;
 };
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index 8ce18ca..1b732fe 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -1052,7 +1052,7 @@
   data_ = MakeGarbageCollected<NodeData>(layout_object, nullptr);
 }
 
-void Node::SetComputedStyle(scoped_refptr<const ComputedStyle> computed_style) {
+void Node::SetComputedStyle(const ComputedStyle* computed_style) {
   // We don't set computed style for text nodes.
   DCHECK(IsElementNode());
 
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h
index 19eaab2e..e8511e5 100644
--- a/third_party/blink/renderer/core/dom/node.h
+++ b/third_party/blink/renderer/core/dom/node.h
@@ -325,7 +325,7 @@
 
   bool SupportsAltText();
 
-  void SetComputedStyle(scoped_refptr<const ComputedStyle> computed_style);
+  void SetComputedStyle(const ComputedStyle* computed_style);
 
   // Other methods (not part of DOM)
   ALWAYS_INLINE NodeType getNodeType() const {
diff --git a/third_party/blink/renderer/core/dom/node_rare_data.cc b/third_party/blink/renderer/core/dom/node_rare_data.cc
index 7d8145d2..0634a5c 100644
--- a/third_party/blink/renderer/core/dom/node_rare_data.cc
+++ b/third_party/blink/renderer/core/dom/node_rare_data.cc
@@ -80,7 +80,7 @@
 }
 
 NodeData::NodeData(LayoutObject* layout_object,
-                   scoped_refptr<const ComputedStyle> computed_style)
+                   const ComputedStyle* computed_style)
     : computed_style_(computed_style),
       layout_object_(layout_object),
       bit_field_(RestyleFlags::encode(0) |
@@ -91,8 +91,7 @@
 NodeData::NodeData(blink::NodeData&&) = default;
 NodeData::~NodeData() = default;
 
-void NodeData::SetComputedStyle(
-    scoped_refptr<const ComputedStyle> computed_style) {
+void NodeData::SetComputedStyle(const ComputedStyle* computed_style) {
   DCHECK_NE(&SharedEmptyData(), this);
   computed_style_ = computed_style;
 }
@@ -103,6 +102,7 @@
   return *shared_empty_data;
 }
 void NodeData::Trace(Visitor* visitor) const {
+  visitor->Trace(computed_style_);
   visitor->Trace(layout_object_);
 }
 
diff --git a/third_party/blink/renderer/core/dom/node_rare_data.h b/third_party/blink/renderer/core/dom/node_rare_data.h
index 0fe9a9f..87752b62d 100644
--- a/third_party/blink/renderer/core/dom/node_rare_data.h
+++ b/third_party/blink/renderer/core/dom/node_rare_data.h
@@ -94,8 +94,7 @@
   virtual ~NodeData();
   virtual void Trace(Visitor*) const;
 
-  CORE_EXPORT NodeData(LayoutObject*,
-                       scoped_refptr<const ComputedStyle> computed_style);
+  CORE_EXPORT NodeData(LayoutObject*, const ComputedStyle* computed_style);
   NodeData(const NodeData&) = delete;
   NodeData(NodeData&&);
 
@@ -106,9 +105,9 @@
   }
 
   const ComputedStyle* GetComputedStyle() const {
-    return computed_style_.get();
+    return computed_style_.Get();
   }
-  void SetComputedStyle(scoped_refptr<const ComputedStyle> computed_style);
+  void SetComputedStyle(const ComputedStyle* computed_style);
 
   void SetIsPseudoElement(bool value) { is_pseudo_element_ = value; }
   bool IsPseudoElement() const { return is_pseudo_element_; }
@@ -134,7 +133,7 @@
   }
 
  protected:
-  scoped_refptr<const ComputedStyle> computed_style_;
+  subtle::UncompressedMember<const ComputedStyle> computed_style_;
   Member<LayoutObject> layout_object_;
   BitField bit_field_;
   bool is_pseudo_element_ = false;
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.cc b/third_party/blink/renderer/core/dom/pseudo_element.cc
index bbaf844..4b29808c 100644
--- a/third_party/blink/renderer/core/dom/pseudo_element.cc
+++ b/third_party/blink/renderer/core/dom/pseudo_element.cc
@@ -196,7 +196,7 @@
   }
 }
 
-scoped_refptr<const ComputedStyle> PseudoElement::CustomStyleForLayoutObject(
+const ComputedStyle* PseudoElement::CustomStyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
   Element* parent = ParentOrShadowHostElement();
   return parent->StyleForPseudoElement(
@@ -204,7 +204,7 @@
                                          view_transition_name_));
 }
 
-scoped_refptr<const ComputedStyle> PseudoElement::LayoutStyleForDisplayContents(
+const ComputedStyle* PseudoElement::LayoutStyleForDisplayContents(
     const ComputedStyle& style) {
   // For display:contents we should not generate a box, but we generate a non-
   // observable inline box for pseudo elements to be able to locate the
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.h b/third_party/blink/renderer/core/dom/pseudo_element.h
index 3c49ef1..ff7149f8 100644
--- a/third_party/blink/renderer/core/dom/pseudo_element.h
+++ b/third_party/blink/renderer/core/dom/pseudo_element.h
@@ -54,7 +54,7 @@
   const AtomicString& view_transition_name() const {
     return view_transition_name_;
   }
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&) override;
   void AttachLayoutTree(AttachContext&) override;
   bool LayoutObjectIsNeeded(const DisplayStyle&) const override;
@@ -63,8 +63,7 @@
   bool CanStartSelection() const override { return false; }
   bool CanContainRangeEndPoint() const override { return false; }
   PseudoId GetPseudoId() const override { return pseudo_id_; }
-  scoped_refptr<const ComputedStyle> LayoutStyleForDisplayContents(
-      const ComputedStyle&);
+  const ComputedStyle* LayoutStyleForDisplayContents(const ComputedStyle&);
 
   static AtomicString PseudoElementNameForEvents(Element*);
   static bool IsWebExposed(PseudoId, const Node*);
@@ -94,7 +93,7 @@
 
    private:
     PseudoElement* element_;
-    scoped_refptr<const ComputedStyle> original_style_;
+    const ComputedStyle* original_style_{nullptr};
   };
 
   PseudoId pseudo_id_;
diff --git a/third_party/blink/renderer/core/dom/text.cc b/third_party/blink/renderer/core/dom/text.cc
index 8b75f4c..96c0449 100644
--- a/third_party/blink/renderer/core/dom/text.cc
+++ b/third_party/blink/renderer/core/dom/text.cc
@@ -389,7 +389,7 @@
 }  // namespace
 
 void Text::RecalcTextStyle(const StyleRecalcChange change) {
-  scoped_refptr<const ComputedStyle> new_style =
+  const ComputedStyle* new_style =
       GetDocument().GetStyleResolver().StyleForText(this);
   if (LayoutText* layout_text = GetLayoutObject()) {
     const ComputedStyle* layout_parent_style =
@@ -401,7 +401,7 @@
       // display:contents text child changed.
       SetNeedsReattachLayoutTree();
     } else {
-      layout_text->SetStyle(std::move(new_style));
+      layout_text->SetStyle(new_style);
       if (NeedsStyleRecalc())
         layout_text->SetTextIfNeeded(data());
     }
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 584fa082..3c8c305ba 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -117,7 +117,6 @@
 #include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/style_retain_scope.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
 #include "third_party/blink/renderer/core/layout/traced_layout_object.h"
@@ -698,7 +697,6 @@
   LayoutObject* root_for_this_layout = GetLayoutView();
 
   FontCachePurgePreventer font_cache_purge_preventer;
-  StyleRetainScope style_retain_scope;
   bool in_subtree_layout = false;
   base::AutoReset<bool> change_scheduling_enabled(&layout_scheduling_enabled_,
                                                   false);
diff --git a/third_party/blink/renderer/core/highlight/highlight_style_utils.cc b/third_party/blink/renderer/core/highlight/highlight_style_utils.cc
index b0b83fa..b1db0c92 100644
--- a/third_party/blink/renderer/core/highlight/highlight_style_utils.cc
+++ b/third_party/blink/renderer/core/highlight/highlight_style_utils.cc
@@ -204,8 +204,7 @@
 
 // Returns highlight styles for the given node, inheriting from the originating
 // element only, like most impls did before highlights were added to css-pseudo.
-scoped_refptr<const ComputedStyle>
-HighlightPseudoStyleWithOriginatingInheritance(
+const ComputedStyle* HighlightPseudoStyleWithOriginatingInheritance(
     Node* node,
     PseudoId pseudo,
     const AtomicString& pseudo_argument = g_null_atom) {
@@ -317,7 +316,7 @@
 // Returns highlight styles for the given node, inheriting through the “tree” of
 // highlight pseudo styles mirroring the originating element tree. None of the
 // returned styles are influenced by originating elements or pseudo-elements.
-scoped_refptr<const ComputedStyle> HighlightStyleUtils::HighlightPseudoStyle(
+const ComputedStyle* HighlightStyleUtils::HighlightPseudoStyle(
     Node* node,
     const ComputedStyle& style,
     PseudoId pseudo,
@@ -327,21 +326,17 @@
                                                           pseudo_argument);
   }
 
-  if (!style.HighlightData()) {
-    return nullptr;
-  }
-
   switch (pseudo) {
     case kPseudoIdSelection:
-      return style.HighlightData()->Selection();
+      return style.HighlightData().Selection();
     case kPseudoIdTargetText:
-      return style.HighlightData()->TargetText();
+      return style.HighlightData().TargetText();
     case kPseudoIdSpellingError:
-      return style.HighlightData()->SpellingError();
+      return style.HighlightData().SpellingError();
     case kPseudoIdGrammarError:
-      return style.HighlightData()->GrammarError();
+      return style.HighlightData().GrammarError();
     case kPseudoIdHighlight:
-      return style.HighlightData()->CustomHighlight(pseudo_argument);
+      return style.HighlightData().CustomHighlight(pseudo_argument);
     default:
       NOTREACHED();
       return nullptr;
@@ -361,10 +356,10 @@
     }
   }
 
-  scoped_refptr<const ComputedStyle> pseudo_style =
+  const ComputedStyle* pseudo_style =
       HighlightPseudoStyle(node, style, pseudo, pseudo_argument);
   Color result =
-      ResolveColor(document, style, pseudo_style.get(), pseudo,
+      ResolveColor(document, style, pseudo_style, pseudo,
                    GetCSSPropertyBackgroundColor(), previous_layer_color);
   if (pseudo == kPseudoIdSelection && NodeIsReplaced(node)) {
     // Avoid that ::selection full obscures selected replaced elements like
@@ -417,24 +412,24 @@
   // specified on the originating element (or the other highlight overlays).
   highlight_style.shadow = nullptr;
 
-  scoped_refptr<const ComputedStyle> pseudo_style =
+  const ComputedStyle* pseudo_style =
       HighlightPseudoStyle(node, style, pseudo, pseudo_argument);
   Color previous_layer_current_color = previous_layer_text_style.current_color;
 
   if (!uses_text_as_clip && !ignored_selection) {
     highlight_style.current_color =
-        ResolveColor(document, style, pseudo_style.get(), pseudo,
+        ResolveColor(document, style, pseudo_style, pseudo,
                      GetCSSPropertyColor(), previous_layer_current_color);
     highlight_style.fill_color = ResolveColor(
-        document, style, pseudo_style.get(), pseudo,
+        document, style, pseudo_style, pseudo,
         GetCSSPropertyWebkitTextFillColor(), previous_layer_current_color);
     // TODO(crbug.com/1147859) ignore highlight ‘text-emphasis-color’
     // https://github.com/w3c/csswg-drafts/issues/7101
     highlight_style.emphasis_mark_color = ResolveColor(
-        document, style, pseudo_style.get(), pseudo,
+        document, style, pseudo_style, pseudo,
         GetCSSPropertyTextEmphasisColor(), previous_layer_current_color);
     highlight_style.stroke_color = ResolveColor(
-        document, style, pseudo_style.get(), pseudo,
+        document, style, pseudo_style, pseudo,
         GetCSSPropertyWebkitTextStrokeColor(), previous_layer_current_color);
   }
 
@@ -472,9 +467,9 @@
     return absl::nullopt;
   }
 
-  if (scoped_refptr<const ComputedStyle> pseudo_style =
+  if (const ComputedStyle* pseudo_style =
           HighlightPseudoStyle(node, style, pseudo)) {
-    return ResolveColor(document, style, pseudo_style.get(), pseudo,
+    return ResolveColor(document, style, pseudo_style, pseudo,
                         GetCSSPropertyTextDecorationColor(),
                         previous_layer_color);
   }
@@ -490,14 +485,14 @@
   // RuntimeEnabledFeatures::HighlightInheritanceEnabled() is true to avoid
   // needing a non-const node.
   const ComputedStyle* style = node.GetComputedStyle();
-  if (!style || !style->HighlightData()) {
+  if (!style) {
     return false;
   }
   const ComputedStyle* pseudo_style = nullptr;
   switch (type) {
     case DocumentMarker::kTextFragment:
       if (RuntimeEnabledFeatures::HighlightOverlayPaintingEnabled()) {
-        pseudo_style = style->HighlightData()->TargetText();
+        pseudo_style = style->HighlightData().TargetText();
       }
       break;
 
@@ -505,7 +500,7 @@
       if (RuntimeEnabledFeatures::CSSSpellingGrammarErrorsEnabled() ||
           RuntimeEnabledFeatures::
               CSSPaintingForSpellingGrammarErrorsEnabled()) {
-        pseudo_style = style->HighlightData()->SpellingError();
+        pseudo_style = style->HighlightData().SpellingError();
       }
       break;
 
@@ -513,7 +508,7 @@
       if (RuntimeEnabledFeatures::CSSSpellingGrammarErrorsEnabled() ||
           RuntimeEnabledFeatures::
               CSSPaintingForSpellingGrammarErrorsEnabled()) {
-        pseudo_style = style->HighlightData()->GrammarError();
+        pseudo_style = style->HighlightData().GrammarError();
       }
       break;
 
@@ -531,11 +526,11 @@
     const Node* node,
     const AtomicString& pseudo_argument) {
   const ComputedStyle* style = node->GetComputedStyle();
-  if (!style || !style->HighlightData()) {
+  if (!style) {
     return false;
   }
   const ComputedStyle* pseudo_style =
-      style->HighlightData()->CustomHighlight(pseudo_argument);
+      style->HighlightData().CustomHighlight(pseudo_argument);
   if (!pseudo_style) {
     return false;
   }
diff --git a/third_party/blink/renderer/core/highlight/highlight_style_utils.h b/third_party/blink/renderer/core/highlight/highlight_style_utils.h
index a8ad2fd..3da2399 100644
--- a/third_party/blink/renderer/core/highlight/highlight_style_utils.h
+++ b/third_party/blink/renderer/core/highlight/highlight_style_utils.h
@@ -61,7 +61,7 @@
       absl::optional<Color> previous_layer_color,
       PseudoId);
 
-  static scoped_refptr<const ComputedStyle> HighlightPseudoStyle(
+  static const ComputedStyle* HighlightPseudoStyle(
       Node* node,
       const ComputedStyle& style,
       PseudoId pseudo,
diff --git a/third_party/blink/renderer/core/highlight/highlight_style_utils_test.cc b/third_party/blink/renderer/core/highlight/highlight_style_utils_test.cc
index 833b447..4285756 100644
--- a/third_party/blink/renderer/core/highlight/highlight_style_utils_test.cc
+++ b/third_party/blink/renderer/core/highlight/highlight_style_utils_test.cc
@@ -26,11 +26,10 @@
 Color SelectionWebkitTextFillColor(const Document& document,
                                    Node* node,
                                    const ComputedStyle& originating_style) {
-  scoped_refptr<const ComputedStyle> pseudo_style =
-      HighlightStyleUtils::HighlightPseudoStyle(node, originating_style,
-                                                kPseudoIdSelection);
+  const ComputedStyle* pseudo_style = HighlightStyleUtils::HighlightPseudoStyle(
+      node, originating_style, kPseudoIdSelection);
   return HighlightStyleUtils::ResolveColor(
-      document, originating_style, pseudo_style.get(), kPseudoIdSelection,
+      document, originating_style, pseudo_style, kPseudoIdSelection,
       GetCSSPropertyWebkitTextFillColor(), Color::kBlack);
 }
 
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
index bbccd42..7726ed0b 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
@@ -16,6 +16,8 @@
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h"
 
+namespace blink {
+
 namespace {
 
 const unsigned CanvasFontCacheMaxFonts = 50;
@@ -24,12 +26,8 @@
 const unsigned CanvasFontCacheHardMaxFontsLowEnd = 20;
 const unsigned CanvasFontCacheHiddenMaxFonts = 1;
 const int defaultFontSize = 10;
-}
 
-namespace blink {
-
-CanvasFontCache::CanvasFontCache(Document& document)
-    : document_(&document), pruning_scheduled_(false) {
+const ComputedStyle* CreateDefaultFontStyle(const Document& document) {
   const AtomicString& default_font_family = font_family_names::kSansSerif;
   FontFamily font_family;
   font_family.SetFamily(default_font_family,
@@ -43,9 +41,16 @@
           ? document.GetStyleResolver().CreateComputedStyleBuilder()
           : ComputedStyleBuilder(*ComputedStyle::CreateInitialStyleSingleton());
   builder.SetFontDescription(default_font_description);
-  default_font_style_ = builder.TakeStyle();
+  return builder.TakeStyle();
 }
 
+}  // namespace
+
+CanvasFontCache::CanvasFontCache(Document& document)
+    : document_(&document),
+      default_font_style_(CreateDefaultFontStyle(document)),
+      pruning_scheduled_(false) {}
+
 CanvasFontCache::~CanvasFontCache() {
 }
 
@@ -164,6 +169,7 @@
 void CanvasFontCache::Trace(Visitor* visitor) const {
   visitor->Trace(fetched_fonts_);
   visitor->Trace(document_);
+  visitor->Trace(default_font_style_);
 }
 
 void CanvasFontCache::Dispose() {
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h
index 8f32137..b033fd7 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.h
@@ -68,7 +68,7 @@
   LinkedHashSet<String> font_lru_list_;
   std::unique_ptr<FontCachePurgePreventer> main_cache_purge_preventer_;
   Member<Document> document_;
-  scoped_refptr<const ComputedStyle> default_font_style_;
+  Member<const ComputedStyle> default_font_style_;
   bool pruning_scheduled_;
 };
 
diff --git a/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc b/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
index 3526a38..b3607a4 100644
--- a/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
+++ b/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
@@ -580,12 +580,11 @@
     field->blur();
 }
 
-scoped_refptr<const ComputedStyle>
-DateTimeEditElement::CustomStyleForLayoutObject(
+const ComputedStyle* DateTimeEditElement::CustomStyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
   // TODO(crbug.com/1181868): This is a kind of layout. We might want to
   // introduce new LayoutObject.
-  scoped_refptr<const ComputedStyle> original_style =
+  const ComputedStyle* original_style =
       OriginalStyleForLayoutObject(style_recalc_context);
   float width = 0;
   for (Node* child = FieldsWrapperElement()->firstChild(); child;
diff --git a/third_party/blink/renderer/core/html/forms/date_time_edit_element.h b/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
index 028dacd8..a1765e96 100644
--- a/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
+++ b/third_party/blink/renderer/core/html/forms/date_time_edit_element.h
@@ -140,7 +140,7 @@
   void UpdateUIState();
 
   // Element function.
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&) override;
   bool IsDateTimeEditElement() const override;
 
diff --git a/third_party/blink/renderer/core/html/forms/html_select_list_element.cc b/third_party/blink/renderer/core/html/forms/html_select_list_element.cc
index f6bae89..9f2b75db 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_list_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_list_element.cc
@@ -47,7 +47,7 @@
   }
 
  private:
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext& style_recalc_context) override {
     HTMLSelectListElement* selectlist =
         DynamicTo<HTMLSelectListElement>(OwnerShadowHost());
@@ -57,7 +57,7 @@
 
     const ComputedStyle& button_style =
         selectlist->ButtonPart()->ComputedStyleRef();
-    scoped_refptr<const ComputedStyle> original_style =
+    const ComputedStyle* original_style =
         OriginalStyleForLayoutObject(style_recalc_context);
     ComputedStyleBuilder style_builder(*original_style);
     if (button_style.HasAuthorBorderRadius()) {
diff --git a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
index 3f1cc7b..2bd93d3 100644
--- a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
+++ b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
@@ -108,18 +108,16 @@
   return kNoPart;
 }
 
-scoped_refptr<const ComputedStyle> StyleForHoveredScrollbarPart(
-    HTMLSelectElement& element,
-    const ComputedStyle* style,
-    Scrollbar* scrollbar,
-    PseudoId target_id) {
+const ComputedStyle* StyleForHoveredScrollbarPart(HTMLSelectElement& element,
+                                                  const ComputedStyle* style,
+                                                  Scrollbar* scrollbar,
+                                                  PseudoId target_id) {
   ScrollbarPart part = ScrollbarPartFromPseudoId(target_id);
   if (part == kNoPart)
     return nullptr;
   scrollbar->SetHoveredPart(part);
-  scoped_refptr<const ComputedStyle> part_style =
-      element.UncachedStyleForPseudoElement(
-          StyleRequest(target_id, To<CustomScrollbar>(scrollbar), part, style));
+  const ComputedStyle* part_style = element.UncachedStyleForPseudoElement(
+      StyleRequest(target_id, To<CustomScrollbar>(scrollbar), part, style));
   return part_style;
 }
 
@@ -325,10 +323,9 @@
     }
     // For Pseudo-class styles, Style should be calculated via that status.
     if (temp_scrollbar) {
-      scoped_refptr<const ComputedStyle> part_style =
-          StyleForHoveredScrollbarPart(owner_element,
-                                       owner_element.GetComputedStyle(),
-                                       temp_scrollbar, target.first);
+      const ComputedStyle* part_style = StyleForHoveredScrollbarPart(
+          owner_element, owner_element.GetComputedStyle(), temp_scrollbar,
+          target.first);
       if (part_style) {
         AppendOwnerElementPseudoStyles(target.second + ":hover", data,
                                        *part_style);
diff --git a/third_party/blink/renderer/core/html/forms/menu_list_inner_element.cc b/third_party/blink/renderer/core/html/forms/menu_list_inner_element.cc
index 43dd290..5701027 100644
--- a/third_party/blink/renderer/core/html/forms/menu_list_inner_element.cc
+++ b/third_party/blink/renderer/core/html/forms/menu_list_inner_element.cc
@@ -17,8 +17,7 @@
   SetHasCustomStyleCallbacks();
 }
 
-scoped_refptr<const ComputedStyle>
-MenuListInnerElement::CustomStyleForLayoutObject(
+const ComputedStyle* MenuListInnerElement::CustomStyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
   const ComputedStyle& parent_style = OwnerShadowHost()->ComputedStyleRef();
   ComputedStyleBuilder style_builder =
diff --git a/third_party/blink/renderer/core/html/forms/menu_list_inner_element.h b/third_party/blink/renderer/core/html/forms/menu_list_inner_element.h
index 2308152b60..ec80202 100644
--- a/third_party/blink/renderer/core/html/forms/menu_list_inner_element.h
+++ b/third_party/blink/renderer/core/html/forms/menu_list_inner_element.h
@@ -14,7 +14,7 @@
   explicit MenuListInnerElement(Document& document);
 
  private:
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&) override;
 };
 
diff --git a/third_party/blink/renderer/core/html/forms/select_type.cc b/third_party/blink/renderer/core/html/forms/select_type.cc
index 6b32e4b..19fb45ff 100644
--- a/third_party/blink/renderer/core/html/forms/select_type.cc
+++ b/third_party/blink/renderer/core/html/forms/select_type.cc
@@ -94,7 +94,7 @@
   void UpdateTextStyleAndContent() override;
   HTMLOptionElement* OptionToBeShown() const override;
   const ComputedStyle* OptionStyle() const override {
-    return option_style_.get();
+    return option_style_.Get();
   }
   void MaximumOptionWidthMightBeChanged() const override;
 
@@ -123,7 +123,7 @@
 
   Member<PopupMenu> popup_;
   Member<PopupUpdater> popup_updater_;
-  scoped_refptr<const ComputedStyle> option_style_;
+  Member<const ComputedStyle> option_style_;
   int ax_menulist_last_active_index_ = -1;
   bool has_updated_menulist_active_option_ = false;
   bool popup_is_visible_ = false;
@@ -133,6 +133,7 @@
 void MenuListSelectType::Trace(Visitor* visitor) const {
   visitor->Trace(popup_);
   visitor->Trace(popup_updater_);
+  visitor->Trace(option_style_);
   SelectType::Trace(visitor);
 }
 
@@ -516,10 +517,10 @@
     builder.SetDirection(option_style->Direction());
     builder.SetUnicodeBidi(option_style->GetUnicodeBidi());
     builder.SetTextAlign(option_style->GetTextAlign(true));
-    scoped_refptr<const ComputedStyle> new_style = builder.TakeStyle();
+    const ComputedStyle* new_style = builder.TakeStyle();
     if (auto* inner_layout = inner_element.GetLayoutObject()) {
       inner_layout->SetModifiedStyleOutsideStyleRecalc(
-          std::move(new_style), LayoutObject::ApplyStyleChanges::kYes);
+          new_style, LayoutObject::ApplyStyleChanges::kYes);
     } else {
       inner_element.SetComputedStyle(std::move(new_style));
     }
diff --git a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
index 9d398e4..83eab9d 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
+++ b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
@@ -47,8 +47,8 @@
   setAttribute(html_names::kIdAttr, shadow_element_names::kIdEditingViewPort);
 }
 
-scoped_refptr<const ComputedStyle>
-EditingViewPortElement::CustomStyleForLayoutObject(const StyleRecalcContext&) {
+const ComputedStyle* EditingViewPortElement::CustomStyleForLayoutObject(
+    const StyleRecalcContext&) {
   // FXIME: Move these styles to html.css.
 
   ComputedStyleBuilder style_builder =
@@ -127,8 +127,7 @@
   return MakeGarbageCollected<LayoutNGTextControlInnerEditor>(this);
 }
 
-scoped_refptr<const ComputedStyle>
-TextControlInnerEditorElement::CustomStyleForLayoutObject(
+const ComputedStyle* TextControlInnerEditorElement::CustomStyleForLayoutObject(
     const StyleRecalcContext&) {
   Element* host = OwnerShadowHost();
   DCHECK(host);
@@ -199,7 +198,7 @@
   if (!is_visible_)
     style_builder.SetOpacity(0);
 
-  scoped_refptr<const ComputedStyle> style = style_builder.TakeStyle();
+  const ComputedStyle* style = style_builder.TakeStyle();
 
   if (style->HasPseudoElementStyle(kPseudoIdScrollbar)) {
     ComputedStyleBuilder no_scrollbar_style_builder =
diff --git a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.h b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.h
index 988a027e..eccfa1f 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.h
+++ b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.h
@@ -37,7 +37,7 @@
   explicit EditingViewPortElement(Document&);
 
  protected:
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&) override;
 
  private:
@@ -55,7 +55,7 @@
 
  private:
   LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&) override;
   bool SupportsFocus() const override { return false; }
   bool is_visible_ = true;
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index 9ea9f6d..88f2125 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -3134,6 +3134,13 @@
 
   bool is_old_auto = SelfOrAncestorHasDirAutoAttribute();
   bool is_new_auto = HasDirectionAuto();
+
+  if (is_new_auto) {
+    if (auto* input_element = DynamicTo<HTMLInputElement>(*this)) {
+      input_element->EnsureShadowSubtree();
+    }
+  }
+
   bool needs_slot_assignment_recalc = false;
   auto* parent =
       GetParentForDirectionality(*this, needs_slot_assignment_recalc);
diff --git a/third_party/blink/renderer/core/html/html_embed_element_test.cc b/third_party/blink/renderer/core/html/html_embed_element_test.cc
index dfba53e8..8117b38 100644
--- a/third_party/blink/renderer/core/html/html_embed_element_test.cc
+++ b/third_party/blink/renderer/core/html/html_embed_element_test.cc
@@ -49,7 +49,7 @@
 
   UpdateAllLifecyclePhasesForTest();
 
-  scoped_refptr<const ComputedStyle> initial_style =
+  const ComputedStyle* initial_style =
       GetDocument().GetStyleResolver().InitialStyleForElement();
 
   // We should get |true| as a result and don't trigger a DCHECK.
diff --git a/third_party/blink/renderer/core/html/html_html_element.cc b/third_party/blink/renderer/core/html/html_html_element.cc
index e0ed9164..dd52fe89 100644
--- a/third_party/blink/renderer/core/html/html_html_element.cc
+++ b/third_party/blink/renderer/core/html/html_html_element.cc
@@ -95,9 +95,8 @@
          layout_style.Direction() != propagated_style.Direction();
 }
 
-scoped_refptr<const ComputedStyle> CreateLayoutStyle(
-    const ComputedStyle& style,
-    const ComputedStyle& propagated_style) {
+const ComputedStyle* CreateLayoutStyle(const ComputedStyle& style,
+                                       const ComputedStyle& propagated_style) {
   ComputedStyleBuilder builder(style);
   builder.SetDirection(propagated_style.Direction());
   builder.SetWritingMode(propagated_style.GetWritingMode());
@@ -107,8 +106,8 @@
 
 }  // namespace
 
-scoped_refptr<const ComputedStyle> HTMLHtmlElement::LayoutStyleForElement(
-    scoped_refptr<const ComputedStyle> style) {
+const ComputedStyle* HTMLHtmlElement::LayoutStyleForElement(
+    const ComputedStyle* style) {
   DCHECK(style);
   DCHECK(GetDocument().InStyleRecalc());
   DCHECK(GetLayoutObject());
@@ -144,7 +143,7 @@
     return;
 
   const ComputedStyle* const old_style = layout_object->Style();
-  scoped_refptr<const ComputedStyle> new_style =
+  const ComputedStyle* new_style =
       LayoutStyleForElement(layout_object->Style());
 
   if (old_style == new_style)
diff --git a/third_party/blink/renderer/core/html/html_html_element.h b/third_party/blink/renderer/core/html/html_html_element.h
index 410a459..53fa5b1 100644
--- a/third_party/blink/renderer/core/html/html_html_element.h
+++ b/third_party/blink/renderer/core/html/html_html_element.h
@@ -41,8 +41,7 @@
   void ParseAttribute(const AttributeModificationParams&) override;
   bool HasNonInBodyInsertionMode() const override { return true; }
   void PropagateWritingModeAndDirectionFromBody();
-  scoped_refptr<const ComputedStyle> LayoutStyleForElement(
-      scoped_refptr<const ComputedStyle> style);
+  const ComputedStyle* LayoutStyleForElement(const ComputedStyle* style);
 
   BlockingAttribute& blocking() const { return *blocking_attribute_; }
   bool IsPotentiallyRenderBlocking() const override {
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.cc b/third_party/blink/renderer/core/html/html_plugin_element.cc
index 72579eef..8d902623 100644
--- a/third_party/blink/renderer/core/html/html_plugin_element.cc
+++ b/third_party/blink/renderer/core/html/html_plugin_element.cc
@@ -920,10 +920,9 @@
   }
 }
 
-scoped_refptr<const ComputedStyle>
-HTMLPlugInElement::CustomStyleForLayoutObject(
+const ComputedStyle* HTMLPlugInElement::CustomStyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
-  scoped_refptr<const ComputedStyle> style =
+  const ComputedStyle* style =
       OriginalStyleForLayoutObject(style_recalc_context);
   if (IsImageType() && !GetLayoutObject() && style &&
       LayoutObjectIsNeeded(*style)) {
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.h b/third_party/blink/renderer/core/html/html_plugin_element.h
index 5451bed..7be0d5c 100644
--- a/third_party/blink/renderer/core/html/html_plugin_element.h
+++ b/third_party/blink/renderer/core/html/html_plugin_element.h
@@ -161,7 +161,7 @@
   bool IsFocusableStyle() const final;
   bool IsKeyboardFocusable() const final;
   void DidAddUserAgentShadowRoot(ShadowRoot&) final;
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&) final;
 
   // HTMLElement overrides:
diff --git a/third_party/blink/renderer/core/html/shadow/meter_shadow_element_test.cc b/third_party/blink/renderer/core/html/shadow/meter_shadow_element_test.cc
index d039a171e..67eac58 100644
--- a/third_party/blink/renderer/core/html/shadow/meter_shadow_element_test.cc
+++ b/third_party/blink/renderer/core/html/shadow/meter_shadow_element_test.cc
@@ -45,7 +45,7 @@
   GetDocument().GetStyleEngine().RecalcStyle();
   EXPECT_FALSE(shadow_element->GetComputedStyle());
 
-  scoped_refptr<const ComputedStyle> style =
+  const ComputedStyle* style =
       shadow_element->StyleForLayoutObject(StyleRecalcContext());
   EXPECT_FALSE(shadow_element->LayoutObjectIsNeeded(*style));
 }
diff --git a/third_party/blink/renderer/core/html/shadow/progress_shadow_element_test.cc b/third_party/blink/renderer/core/html/shadow/progress_shadow_element_test.cc
index 43c08b51..eb41e0a 100644
--- a/third_party/blink/renderer/core/html/shadow/progress_shadow_element_test.cc
+++ b/third_party/blink/renderer/core/html/shadow/progress_shadow_element_test.cc
@@ -45,7 +45,7 @@
   GetDocument().GetStyleEngine().RecalcStyle();
   EXPECT_TRUE(shadow_element->GetComputedStyle());
 
-  scoped_refptr<const ComputedStyle> style =
+  const ComputedStyle* style =
       shadow_element->StyleForLayoutObject(StyleRecalcContext());
   EXPECT_TRUE(shadow_element->LayoutObjectIsNeeded(*style));
 }
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
index 8d38d043..c5894bbc 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
@@ -822,6 +822,7 @@
   visitor->Trace(paint_order_map_);
   visitor->Trace(document_order_map_);
   visitor->Trace(css_value_cache_);
+  visitor->Trace(style_cache_);
   InspectorBaseAgent::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h
index 6b85a72..2181637 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h
@@ -118,8 +118,7 @@
   WTF::HashMap<String, int> string_table_;
 
   HeapHashMap<Member<const CSSValue>, int> css_value_cache_;
-  HashMap<scoped_refptr<const ComputedStyle>, protocol::Array<int>*>
-      style_cache_;
+  HeapHashMap<Member<const ComputedStyle>, protocol::Array<int>*> style_cache_;
 
   std::unique_ptr<protocol::Array<protocol::DOMSnapshot::DocumentSnapshot>>
       documents_;
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index bbd8f715..03918712 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -575,8 +575,6 @@
   "shapes/shape_interval.h",
   "shapes/shape_outside_info.cc",
   "shapes/shape_outside_info.h",
-  "style_retain_scope.cc",
-  "style_retain_scope.h",
   "svg/layout_svg_block.cc",
   "svg/layout_svg_block.h",
   "svg/layout_svg_container.cc",
@@ -803,7 +801,6 @@
   "selection_state_test.cc",
   "shapes/box_shape_test.cc",
   "shapes/ellipse_shape_test.cc",
-  "style_retain_scope_test.cc",
   "svg/layout_svg_container_test.cc",
   "svg/layout_svg_inline_test.cc",
   "svg/layout_svg_root_test.cc",
diff --git a/third_party/blink/renderer/core/layout/custom_scrollbar.cc b/third_party/blink/renderer/core/layout/custom_scrollbar.cc
index 5f989975..c23a254 100644
--- a/third_party/blink/renderer/core/layout/custom_scrollbar.cc
+++ b/third_party/blink/renderer/core/layout/custom_scrollbar.cc
@@ -131,9 +131,9 @@
   PositionScrollbarParts();
 }
 
-scoped_refptr<const ComputedStyle>
-CustomScrollbar::GetScrollbarPseudoElementStyle(ScrollbarPart part_type,
-                                                PseudoId pseudo_id) {
+const ComputedStyle* CustomScrollbar::GetScrollbarPseudoElementStyle(
+    ScrollbarPart part_type,
+    PseudoId pseudo_id) {
   Element* element = StyleSource();
   DCHECK(element);
   Document& document = element->GetDocument();
@@ -150,9 +150,8 @@
   if (!element->GetLayoutObject())
     return nullptr;
   const ComputedStyle* source_style = StyleSource()->GetLayoutObject()->Style();
-  scoped_refptr<const ComputedStyle> part_style =
-      element->UncachedStyleForPseudoElement(
-          StyleRequest(pseudo_id, this, part_type, source_style));
+  const ComputedStyle* part_style = element->UncachedStyleForPseudoElement(
+      StyleRequest(pseudo_id, this, part_type, source_style));
   if (!part_style)
     return nullptr;
   if (part_style->DependsOnFontMetrics()) {
@@ -240,9 +239,8 @@
   if (part_type == kNoPart)
     return;
 
-  scoped_refptr<const ComputedStyle> part_style =
-      GetScrollbarPseudoElementStyle(part_type,
-                                     PseudoForScrollbarPart(part_type));
+  const ComputedStyle* part_style = GetScrollbarPseudoElementStyle(
+      part_type, PseudoForScrollbarPart(part_type));
   bool need_layout_object =
       part_style && part_style->Display() != EDisplay::kNone;
 
@@ -283,7 +281,7 @@
   }
 
   if (part_layout_object)
-    part_layout_object->SetStyle(std::move(part_style));
+    part_layout_object->SetStyle(part_style);
 }
 
 gfx::Rect CustomScrollbar::ButtonRect(ScrollbarPart part_type) const {
diff --git a/third_party/blink/renderer/core/layout/custom_scrollbar.h b/third_party/blink/renderer/core/layout/custom_scrollbar.h
index 7ef76bed..16a42c9 100644
--- a/third_party/blink/renderer/core/layout/custom_scrollbar.h
+++ b/third_party/blink/renderer/core/layout/custom_scrollbar.h
@@ -97,9 +97,7 @@
 
   void DestroyScrollbarParts();
   void UpdateScrollbarParts();
-  scoped_refptr<const ComputedStyle> GetScrollbarPseudoElementStyle(
-      ScrollbarPart,
-      PseudoId);
+  const ComputedStyle* GetScrollbarPseudoElementStyle(ScrollbarPart, PseudoId);
   void UpdateScrollbarPart(ScrollbarPart);
 
   HeapHashMap<ScrollbarPart, Member<LayoutCustomScrollbarPart>> parts_;
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index 68d13dc..9ae023a2 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -109,7 +109,7 @@
 }
 
 bool FlexItem::MainAxisIsInlineAxis() const {
-  return algorithm_->IsHorizontalFlow() == style_.IsHorizontalWritingMode();
+  return algorithm_->IsHorizontalFlow() == style_->IsHorizontalWritingMode();
 }
 
 LayoutUnit FlexItem::FlowAwareMarginStart() const {
@@ -202,22 +202,26 @@
 }
 
 ItemPosition FlexItem::Alignment() const {
-  return FlexLayoutAlgorithm::AlignmentForChild(*algorithm_->Style(), style_);
+  return FlexLayoutAlgorithm::AlignmentForChild(*algorithm_->Style(), *style_);
 }
 
 void FlexItem::UpdateAutoMarginsInMainAxis(LayoutUnit auto_margin_offset) {
   DCHECK_GE(auto_margin_offset, LayoutUnit());
 
   if (algorithm_->IsHorizontalFlow()) {
-    if (style_.MarginLeft().IsAuto())
+    if (style_->MarginLeft().IsAuto()) {
       physical_margins_.left = auto_margin_offset;
-    if (style_.MarginRight().IsAuto())
+    }
+    if (style_->MarginRight().IsAuto()) {
       physical_margins_.right = auto_margin_offset;
+    }
   } else {
-    if (style_.MarginTop().IsAuto())
+    if (style_->MarginTop().IsAuto()) {
       physical_margins_.top = auto_margin_offset;
-    if (style_.MarginBottom().IsAuto())
+    }
+    if (style_->MarginBottom().IsAuto()) {
       physical_margins_.bottom = auto_margin_offset;
+    }
   }
 }
 
@@ -227,9 +231,9 @@
 
   bool is_horizontal = algorithm_->IsHorizontalFlow();
   const Length& top_or_left =
-      is_horizontal ? style_.MarginTop() : style_.MarginLeft();
+      is_horizontal ? style_->MarginTop() : style_->MarginLeft();
   const Length& bottom_or_right =
-      is_horizontal ? style_.MarginBottom() : style_.MarginRight();
+      is_horizontal ? style_->MarginBottom() : style_->MarginRight();
   if (top_or_left.IsAuto() && bottom_or_right.IsAuto()) {
     offset_->cross_axis_offset += available_alignment_space / 2;
     if (is_horizontal) {
@@ -242,13 +246,13 @@
     return true;
   }
   bool should_adjust_top_or_left = true;
-  if (algorithm_->IsColumnFlow() && !style_.IsLeftToRightDirection()) {
+  if (algorithm_->IsColumnFlow() && !style_->IsLeftToRightDirection()) {
     // For column flows, only make this adjustment if topOrLeft corresponds to
     // the "before" margin, so that flipForRightToLeftColumn will do the right
     // thing.
     should_adjust_top_or_left = false;
   }
-  if (!algorithm_->IsColumnFlow() && style_.IsFlippedBlocksWritingMode()) {
+  if (!algorithm_->IsColumnFlow() && style_->IsFlippedBlocksWritingMode()) {
     // If we are a flipped writing mode, we need to adjust the opposite side.
     // This is only needed for row flows because this only affects the
     // block-direction axis.
@@ -284,14 +288,15 @@
       std::max(cross_axis_border_padding_,
                Line()->cross_axis_extent_ - CrossAxisMarginExtent());
 
-  if ((MainAxisIsInlineAxis() && style_.LogicalHeight().IsAuto()) ||
-      (!MainAxisIsInlineAxis() && style_.LogicalWidth().IsAuto())) {
+  if ((MainAxisIsInlineAxis() && style_->LogicalHeight().IsAuto()) ||
+      (!MainAxisIsInlineAxis() && style_->LogicalWidth().IsAuto())) {
     cross_axis_size_ =
         min_max_cross_sizes_->ClampSizeToMinAndMax(stretched_size);
   }
 }
 
 void FlexItem::Trace(Visitor* visitor) const {
+  visitor->Trace(style_);
   visitor->Trace(ng_input_node_);
   visitor->Trace(layout_result_);
 }
@@ -345,7 +350,7 @@
   const ComputedStyle& flex_box_style = algorithm_->StyleRef();
   for (wtf_size_t i = 0; i < violations.size(); ++i) {
     DCHECK(!violations[i]->frozen_) << i;
-    const ComputedStyle& child_style = violations[i]->style_;
+    const ComputedStyle& child_style = *violations[i]->style_;
     LayoutUnit child_size = violations[i]->flexed_content_size_;
     remaining_free_space_ -=
         child_size - violations[i]->flex_base_content_size_;
@@ -378,8 +383,8 @@
     DCHECK(!flex_item.frozen_) << i;
     float flex_factor =
         (flex_sign == kPositiveFlexibility)
-            ? flex_item.style_.ResolvedFlexGrow(flex_box_style)
-            : flex_item.style_.ResolvedFlexShrink(flex_box_style);
+            ? flex_item.style_->ResolvedFlexGrow(flex_box_style)
+            : flex_item.style_->ResolvedFlexShrink(flex_box_style);
     if (flex_factor == 0 ||
         (flex_sign == kPositiveFlexibility &&
          flex_item.flex_base_content_size_ >
@@ -425,14 +430,14 @@
     if (remaining_free_space_ > 0 && total_flex_grow_ > 0 &&
         flex_sign == kPositiveFlexibility && std::isfinite(total_flex_grow_)) {
       extra_space = remaining_free_space_ *
-                    flex_item.style_.ResolvedFlexGrow(flex_box_style) /
+                    flex_item.style_->ResolvedFlexGrow(flex_box_style) /
                     total_flex_grow_;
     } else if (remaining_free_space_ < 0 && total_weighted_flex_shrink_ > 0 &&
                flex_sign == kNegativeFlexibility &&
                std::isfinite(total_weighted_flex_shrink_) &&
-               flex_item.style_.ResolvedFlexShrink(flex_box_style)) {
+               flex_item.style_->ResolvedFlexShrink(flex_box_style)) {
       extra_space = remaining_free_space_ *
-                    flex_item.style_.ResolvedFlexShrink(flex_box_style) *
+                    flex_item.style_->ResolvedFlexShrink(flex_box_style) *
                     flex_item.flex_base_content_size_ /
                     total_weighted_flex_shrink_;
     }
@@ -467,8 +472,8 @@
 
   int number_of_auto_margins = 0;
   bool is_horizontal = algorithm_->IsHorizontalFlow();
-  for (wtf_size_t i = 0; i < line_items_.size(); ++i) {
-    const ComputedStyle& style = line_items_[i].style_;
+  for (const auto& line_item : line_items_) {
+    const ComputedStyle& style = *line_item.style_;
     if (is_horizontal) {
       if (style.MarginLeft().IsAuto())
         ++number_of_auto_margins;
@@ -686,8 +691,8 @@
     line_has_in_flow_item = true;
     sum_flex_base_size +=
         flex_item.FlexBaseMarginBoxSize() + gap_between_items_;
-    total_flex_grow += flex_item.style_.ResolvedFlexGrow(StyleRef());
-    const float flex_shrink = flex_item.style_.ResolvedFlexShrink(StyleRef());
+    total_flex_grow += flex_item.style_->ResolvedFlexGrow(StyleRef());
+    const float flex_shrink = flex_item.style_->ResolvedFlexShrink(StyleRef());
     total_flex_shrink += flex_shrink;
     total_weighted_flex_shrink +=
         flex_shrink * flex_item.flex_base_content_size_;
@@ -865,7 +870,7 @@
       LayoutUnit available_space = flex_item.AvailableAlignmentSpace();
       if (!is_webkit_box &&
           flex_item.style_
-                  .ResolvedAlignSelf(ItemPosition::kStretch, &StyleRef())
+                  ->ResolvedAlignSelf(ItemPosition::kStretch, &StyleRef())
                   .Overflow() == OverflowAlignment::kSafe) {
         available_space = available_space.ClampNegativeToZero();
       }
@@ -1221,6 +1226,7 @@
 }
 
 void FlexLayoutAlgorithm::Trace(Visitor* visitor) const {
+  visitor->Trace(style_);
   visitor->Trace(all_items_);
 }
 
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index 36b9773..b5fd5b6 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -151,7 +151,7 @@
 
   const FlexLayoutAlgorithm* algorithm_;
   wtf_size_t line_number_;
-  const ComputedStyle& style_;
+  Member<const ComputedStyle> style_;
   const LayoutUnit flex_base_content_size_;
   const MinMaxSizes min_max_main_sizes_;
   const absl::optional<MinMaxSizes> min_max_cross_sizes_;
@@ -430,7 +430,7 @@
   friend class NGFlexLayoutAlgorithm;
   EOverflow MainAxisOverflowForChild(const LayoutBox& child) const;
 
-  const ComputedStyle* style_;
+  Member<const ComputedStyle> style_;
   const LayoutUnit line_break_length_;
   FlexItemVector all_items_;
   Vector<FlexLine> flex_lines_;
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index 0861a869..24b539b4 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -765,7 +765,7 @@
                                                   new_display);
 
   parent->UpdateAnonymousChildStyle(nullptr, new_style_builder);
-  scoped_refptr<const ComputedStyle> new_style = new_style_builder.TakeStyle();
+  const ComputedStyle* new_style = new_style_builder.TakeStyle();
 
   LayoutBlock* layout_block;
   if (new_display == EDisplay::kFlex) {
@@ -782,7 +782,7 @@
     layout_block = MakeGarbageCollected<LayoutNGBlockFlow>(nullptr);
   }
   layout_block->SetDocumentForAnonymous(&parent->GetDocument());
-  layout_block->SetStyle(std::move(new_style));
+  layout_block->SetStyle(new_style);
   return layout_block;
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index 722b3de..f1e1095 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -85,9 +85,8 @@
 
 LayoutBlockFlow::~LayoutBlockFlow() = default;
 
-LayoutBlockFlow* LayoutBlockFlow::CreateAnonymous(
-    Document* document,
-    scoped_refptr<const ComputedStyle> style) {
+LayoutBlockFlow* LayoutBlockFlow::CreateAnonymous(Document* document,
+                                                  const ComputedStyle* style) {
   auto* layout_block_flow = MakeGarbageCollected<LayoutNGBlockFlow>(nullptr);
   layout_block_flow->SetDocumentForAnonymous(document);
   layout_block_flow->SetStyle(style);
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h
index 770ff9ae..b69ebca4 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -67,8 +67,7 @@
   ~LayoutBlockFlow() override;
   void Trace(Visitor*) const override;
 
-  static LayoutBlockFlow* CreateAnonymous(Document*,
-                                          scoped_refptr<const ComputedStyle>);
+  static LayoutBlockFlow* CreateAnonymous(Document*, const ComputedStyle*);
 
   bool IsLayoutBlockFlow() const final {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index fccb566..dc047820 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -136,9 +136,8 @@
   LayoutUnit intrinsic_logical_widths_initial_block_size;
   Member<void*> result;
   HeapVector<Member<const NGLayoutResult>, 1> layout_results;
-  void* pointers[1];
   wtf_size_t first_fragment_item_index_;
-  Member<void*> rare_data;
+  Member<void*> members[2];
 };
 
 ASSERT_SIZE(LayoutBox, SameSizeAsLayoutBox);
@@ -473,6 +472,7 @@
 void LayoutBox::Trace(Visitor* visitor) const {
   visitor->Trace(measure_result_);
   visitor->Trace(layout_results_);
+  visitor->Trace(overflow_);
   visitor->Trace(rare_data_);
   LayoutBoxModelObject::Trace(visitor);
 }
@@ -3532,7 +3532,7 @@
 
   DCHECK(!LayoutOverflowIsSet());
   if (!overflow_)
-    overflow_ = std::make_unique<BoxOverflowModel>();
+    overflow_ = MakeGarbageCollected<BoxOverflowModel>();
   overflow_->layout_overflow.emplace(layout_overflow->ToLayoutRect());
 }
 
@@ -3657,7 +3657,7 @@
 
   if (!VisualOverflowIsSet()) {
     if (!overflow_)
-      overflow_ = std::make_unique<BoxOverflowModel>();
+      overflow_ = MakeGarbageCollected<BoxOverflowModel>();
 
     overflow_->visual_overflow.emplace(border_box);
   }
@@ -3681,7 +3681,7 @@
 
   if (!VisualOverflowIsSet()) {
     if (!overflow_)
-      overflow_ = std::make_unique<BoxOverflowModel>();
+      overflow_ = MakeGarbageCollected<BoxOverflowModel>();
 
     overflow_->visual_overflow.emplace(border_box);
   }
@@ -4208,7 +4208,7 @@
 
 void LayoutBox::MutableForPainting::SavePreviousOverflowData() {
   if (!GetLayoutBox().overflow_)
-    GetLayoutBox().overflow_ = std::make_unique<BoxOverflowModel>();
+    GetLayoutBox().overflow_ = MakeGarbageCollected<BoxOverflowModel>();
   auto& previous_overflow = GetLayoutBox().overflow_->previous_overflow_data;
   if (!previous_overflow)
     previous_overflow.emplace();
@@ -4230,7 +4230,7 @@
     return;
 
   if (!GetLayoutBox().overflow_)
-    GetLayoutBox().overflow_ = std::make_unique<BoxOverflowModel>();
+    GetLayoutBox().overflow_ = MakeGarbageCollected<BoxOverflowModel>();
   auto& previous_overflow = GetLayoutBox().overflow_->previous_overflow_data;
   if (!previous_overflow)
     previous_overflow.emplace();
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 1815bf14..8a3813d 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1283,7 +1283,7 @@
     void ClearPreviousOverflowData() {
       DCHECK(!GetLayoutBox().HasVisualOverflow());
       DCHECK(!GetLayoutBox().HasLayoutOverflow());
-      GetLayoutBox().overflow_.reset();
+      GetLayoutBox().overflow_ = nullptr;
     }
     void SavePreviousContentBoxRect() {
       auto& rare_data = GetLayoutBox().EnsureRareData();
@@ -1660,13 +1660,12 @@
   friend class LayoutBoxTest;
 
  private:
-  std::unique_ptr<BoxOverflowModel> overflow_;
-
   // The index of the first fragment item associated with this object in
   // |NGFragmentItems::Items()|. Zero means there are no such item.
   // Valid only when IsInLayoutNGInlineFormattingContext().
   wtf_size_t first_fragment_item_index_ = 0u;
 
+  Member<BoxOverflowModel> overflow_;
   Member<LayoutBoxRareData> rare_data_;
 
   FRIEND_TEST_ALL_PREFIXES(LayoutMultiColumnSetTest, ScrollAnchroingCrash);
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 53fb6bd..53174aa2 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -223,8 +223,8 @@
 }
 
 StyleDifference AdjustForCompositableAnimationPaint(
-    scoped_refptr<const ComputedStyle> old_style,
-    scoped_refptr<const ComputedStyle> new_style,
+    const ComputedStyle* old_style,
+    const ComputedStyle* new_style,
     Node* node,
     StyleDifference diff) {
   DCHECK(new_style);
@@ -320,7 +320,7 @@
   unsigned bitfields_;
   unsigned bitfields2_;
   unsigned bitfields3_;
-  void* pointers[1];
+  subtle::UncompressedMember<void*> uncompressed_member;
   Member<void*> members[5];
 #if DCHECK_IS_ON()
   bool is_destroyed_;
@@ -2479,9 +2479,8 @@
   return diff;
 }
 
-void LayoutObject::SetPseudoElementStyle(
-    scoped_refptr<const ComputedStyle> pseudo_style,
-    bool match_parent_size) {
+void LayoutObject::SetPseudoElementStyle(const ComputedStyle* pseudo_style,
+                                         bool match_parent_size) {
   NOT_DESTROYED();
   DCHECK(pseudo_style->StyleType() == kPseudoIdBefore ||
          pseudo_style->StyleType() == kPseudoIdAfter ||
@@ -2515,7 +2514,7 @@
   if (IsText() && Parent() && UNLIKELY(Parent()->IsInitialLetterBox())) {
     // Note: `Parent()` can be null for text for generated contents.
     // See "accessibility/css-generated-content.html"
-    scoped_refptr<const ComputedStyle> initial_letter_text_style =
+    const ComputedStyle* initial_letter_text_style =
         GetDocument().GetStyleResolver().StyleForInitialLetterText(
             *pseudo_style, Parent()->ContainingBlock()->StyleRef());
     SetStyle(std::move(initial_letter_text_style));
@@ -2537,7 +2536,7 @@
 }
 
 DISABLE_CFI_PERF
-void LayoutObject::SetStyle(scoped_refptr<const ComputedStyle> style,
+void LayoutObject::SetStyle(const ComputedStyle* style,
                             ApplyStyleChanges apply_changes) {
   NOT_DESTROYED();
   if (style_ == style)
@@ -2572,11 +2571,9 @@
       if (style_->HasPseudoElementStyle(pseudo) ||
           style->HasPseudoElementStyle(pseudo)) {
         const ComputedStyle* pseudo_old_style =
-            style_->HighlightData() ? style_->HighlightData()->Style(pseudo)
-                                    : nullptr;
+            style_->HighlightData().Style(pseudo);
         const ComputedStyle* pseudo_new_style =
-            style->HighlightData() ? style->HighlightData()->Style(pseudo)
-                                   : nullptr;
+            style->HighlightData().Style(pseudo);
 
         if (pseudo_old_style && pseudo_new_style) {
           diff.Merge(pseudo_old_style->VisualInvalidationDiff(
@@ -2611,17 +2608,17 @@
 
   StyleWillChange(diff, *style);
 
-  scoped_refptr<const ComputedStyle> old_style = std::move(style_);
+  const ComputedStyle* old_style = std::move(style_);
   SetStyleInternal(std::move(style));
 
   if (!IsText())
-    UpdateImageObservers(old_style.get(), style_.get());
+    UpdateImageObservers(old_style, style_.Get());
 
-  CheckCounterChanges(old_style.get(), style_.get());
+  CheckCounterChanges(old_style, style_.Get());
 
   bool does_not_need_layout_or_paint_invalidation = !parent_;
 
-  StyleDidChange(diff, old_style.get());
+  StyleDidChange(diff, old_style);
 
   // FIXME: |this| might be destroyed here. This can currently happen for a
   // LayoutTextFragment when its first-letter block gets an update in
@@ -2733,8 +2730,8 @@
       !has_new_first_line_style)
     return;
 
-  using FirstLineStyleMap = HeapHashMap<WeakMember<const LayoutObject>,
-                                        scoped_refptr<const ComputedStyle>>;
+  using FirstLineStyleMap =
+      HeapHashMap<WeakMember<const LayoutObject>, Member<const ComputedStyle>>;
   DEFINE_STATIC_LOCAL(Persistent<FirstLineStyleMap>, first_line_style_map,
                       (MakeGarbageCollected<FirstLineStyleMap>()));
   DCHECK_EQ(bitfields_.RegisteredAsFirstLineImageObserver(),
@@ -2747,7 +2744,7 @@
   // UpdateFillImages() may indirectly call LayoutBlock::ImageChanged() which
   // will invalidate the first line style cache and remove a reference to
   // new_first_line_style, so hold a reference here.
-  scoped_refptr<const ComputedStyle> new_first_line_style =
+  const ComputedStyle* new_first_line_style =
       has_new_first_line_style ? FirstLineStyleWithoutFallback() : nullptr;
 
   if (new_first_line_style && !new_first_line_style->HasBackgroundImage())
@@ -3690,7 +3687,7 @@
 
   // Remove this object as ImageResourceObserver.
   if (style_ && !IsText())
-    UpdateImageObservers(style_.get(), nullptr);
+    UpdateImageObservers(style_.Get(), nullptr);
 
   // We must have removed all image observers.
   SECURITY_CHECK(!bitfields_.RegisteredAsFirstLineImageObserver());
@@ -4135,7 +4132,7 @@
       // it's based on first_line_block's style. We need to get the uncached
       // first line style based on this object's style and cache the result in
       // it.
-      if (scoped_refptr<const ComputedStyle> first_line_style =
+      if (const ComputedStyle* first_line_style =
               first_line_block->GetUncachedPseudoElementStyle(
                   StyleRequest(kPseudoIdFirstLine, Style()))) {
         return StyleRef().ReplaceCachedPseudoElementStyle(
@@ -4152,7 +4149,7 @@
             Parent()->FirstLineStyleWithoutFallback()) {
       // A first-line style is in effect. Get uncached first line style based on
       // parent_first_line_style and cache the result in this object's style.
-      if (scoped_refptr<const ComputedStyle> first_line_style =
+      if (const ComputedStyle* first_line_style =
               GetUncachedPseudoElementStyle(StyleRequest(
                   kPseudoIdFirstLineInherited, parent_first_line_style))) {
         return StyleRef().AddCachedPseudoElementStyle(
@@ -4179,7 +4176,7 @@
   return element->CachedStyleForPseudoElement(pseudo);
 }
 
-scoped_refptr<const ComputedStyle> LayoutObject::GetUncachedPseudoElementStyle(
+const ComputedStyle* LayoutObject::GetUncachedPseudoElementStyle(
     const StyleRequest& request) const {
   NOT_DESTROYED();
   DCHECK_NE(request.pseudo_id, kPseudoIdBefore);
@@ -4199,10 +4196,7 @@
 
 const ComputedStyle* LayoutObject::GetSelectionStyle() const {
   if (UsesHighlightPseudoInheritance(kPseudoIdSelection)) {
-    if (!StyleRef().HighlightData()) {
-      return nullptr;
-    }
-    return StyleRef().HighlightData()->Selection();
+    return StyleRef().HighlightData().Selection();
   }
   return GetCachedPseudoElementStyle(kPseudoIdSelection);
 }
@@ -4960,7 +4954,7 @@
 }
 
 void LayoutObject::SetModifiedStyleOutsideStyleRecalc(
-    scoped_refptr<const ComputedStyle> style,
+    const ComputedStyle* style,
     ApplyStyleChanges apply_changes) {
   NOT_DESTROYED();
   SetStyle(style, apply_changes);
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index dfbc6e0..953647d 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1760,8 +1760,7 @@
   // from the originating element's style (because we can cache only one
   // version), while the uncached pseudo style can inherit from any style.
   const ComputedStyle* GetCachedPseudoElementStyle(PseudoId) const;
-  scoped_refptr<const ComputedStyle> GetUncachedPseudoElementStyle(
-      const StyleRequest&) const;
+  const ComputedStyle* GetUncachedPseudoElementStyle(const StyleRequest&) const;
 
   // Returns the ::selection style, which may be stored in StyleCachedData (old
   // impl) or StyleHighlightData (new impl).
@@ -2303,11 +2302,11 @@
   // and new ComputedStyle like paint and size invalidations. If kNo, just set
   // the ComputedStyle member.
   enum class ApplyStyleChanges { kNo, kYes };
-  void SetStyle(scoped_refptr<const ComputedStyle>,
+  void SetStyle(const ComputedStyle*,
                 ApplyStyleChanges = ApplyStyleChanges::kYes);
 
   // Set the style of the object if it's generated content.
-  void SetPseudoElementStyle(scoped_refptr<const ComputedStyle>,
+  void SetPseudoElementStyle(const ComputedStyle*,
                              bool match_parent_size = false);
 
   // In some cases we modify the ComputedStyle after the style recalc, either
@@ -2317,7 +2316,7 @@
   // that node with the new ComputedStyle. Modifying the ComputedStyle of a node
   // outside of style recalc can break invariants in the style engine, so this
   // function must not gain any new call sites.
-  void SetModifiedStyleOutsideStyleRecalc(scoped_refptr<const ComputedStyle>,
+  void SetModifiedStyleOutsideStyleRecalc(const ComputedStyle*,
                                           ApplyStyleChanges);
 
   // This function returns an enclosing non-anonymous LayoutBlock for this
@@ -2547,7 +2546,7 @@
 
   const ComputedStyle* Style() const {
     NOT_DESTROYED();
-    return style_.get();
+    return style_.Get();
   }
 
   // style_ can only be nullptr before the first style is set, thus most
@@ -3595,7 +3594,7 @@
   // Updates only the local style ptr of the object.  Does not update the state
   // of the object, and so only should be called when the style is known not to
   // have changed (or from SetStyle).
-  void SetStyleInternal(scoped_refptr<const ComputedStyle> style) {
+  void SetStyleInternal(const ComputedStyle* style) {
     NOT_DESTROYED();
     style_ = std::move(style);
   }
@@ -4307,7 +4306,7 @@
   friend class LineLayoutItem;
   friend class LocalFrameView;
 
-  scoped_refptr<const ComputedStyle> style_;
+  subtle::UncompressedMember<const ComputedStyle> style_;
 
   Member<Node> node_;
 
diff --git a/third_party/blink/renderer/core/layout/layout_object_hot.cc b/third_party/blink/renderer/core/layout/layout_object_hot.cc
index 87df0c9..56319de 100644
--- a/third_party/blink/renderer/core/layout/layout_object_hot.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_hot.cc
@@ -18,6 +18,7 @@
 namespace blink {
 
 void LayoutObject::Trace(Visitor* visitor) const {
+  visitor->Trace(style_);
   visitor->Trace(node_);
   visitor->Trace(parent_);
   visitor->Trace(previous_);
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index c716a74d..26435996 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -190,18 +190,17 @@
   LayoutObject::Trace(visitor);
 }
 
-LayoutText* LayoutText::CreateEmptyAnonymous(
-    Document& doc,
-    scoped_refptr<const ComputedStyle> style) {
+LayoutText* LayoutText::CreateEmptyAnonymous(Document& doc,
+                                             const ComputedStyle* style) {
   auto* text = MakeGarbageCollected<LayoutText>(nullptr, StringImpl::empty_);
   text->SetDocumentForAnonymous(&doc);
-  text->SetStyle(std::move(style));
+  text->SetStyle(style);
   return text;
 }
 
 LayoutText* LayoutText::CreateAnonymousForFormattedText(
     Document& doc,
-    scoped_refptr<const ComputedStyle> style,
+    const ComputedStyle* style,
     String text) {
   auto* layout_text =
       MakeGarbageCollected<LayoutText>(nullptr, std::move(text));
diff --git a/third_party/blink/renderer/core/layout/layout_text.h b/third_party/blink/renderer/core/layout/layout_text.h
index ccc4a30..c95806c 100644
--- a/third_party/blink/renderer/core/layout/layout_text.h
+++ b/third_party/blink/renderer/core/layout/layout_text.h
@@ -80,13 +80,11 @@
 
   void Trace(Visitor*) const override;
 
-  static LayoutText* CreateEmptyAnonymous(Document&,
-                                          scoped_refptr<const ComputedStyle>);
+  static LayoutText* CreateEmptyAnonymous(Document&, const ComputedStyle*);
 
-  static LayoutText* CreateAnonymousForFormattedText(
-      Document&,
-      scoped_refptr<const ComputedStyle>,
-      String);
+  static LayoutText* CreateAnonymousForFormattedText(Document&,
+                                                     const ComputedStyle*,
+                                                     String);
 
   const char* GetName() const override {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index 9d25cd80..3fa6668 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -679,7 +679,7 @@
 PhysicalSize LayoutView::PageAreaSize(wtf_size_t page_index,
                                       const AtomicString& page_name) const {
   NOT_DESTROYED();
-  scoped_refptr<const ComputedStyle> page_style =
+  const ComputedStyle* page_style =
       GetDocument().StyleForPage(page_index, page_name);
   WebPrintPageDescription description = default_page_description_;
   GetDocument().GetPageDescription(*page_style, &description);
diff --git a/third_party/blink/renderer/core/layout/list_marker.cc b/third_party/blink/renderer/core/layout/list_marker.cc
index 0bbe769..451ac6c6 100644
--- a/third_party/blink/renderer/core/layout/list_marker.cc
+++ b/third_party/blink/renderer/core/layout/list_marker.cc
@@ -259,7 +259,7 @@
     if (!child) {
       LayoutListMarkerImage* image =
           LayoutListMarkerImage::CreateAnonymous(&marker.GetDocument());
-      scoped_refptr<const ComputedStyle> image_style =
+      const ComputedStyle* image_style =
           marker.GetDocument()
               .GetStyleResolver()
               .CreateAnonymousStyleWithDisplay(marker.StyleRef(),
@@ -284,7 +284,7 @@
   // |LayoutObject::PropagateStyleToAnonymousChildren()| to avoid unexpected
   // full layout due by style difference. See http://crbug.com/980399
   const auto& style_parent = child ? *child->Parent() : marker;
-  scoped_refptr<const ComputedStyle> text_style =
+  const ComputedStyle* text_style =
       marker.GetDocument().GetStyleResolver().CreateAnonymousStyleWithDisplay(
           style_parent.StyleRef(), marker.StyleRef().Display());
   if (IsA<LayoutTextFragment>(child))
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
index 5a6930a0..2d2b356 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
@@ -2216,7 +2216,7 @@
         min_max_content_contributions.depends_on_block_constraints;
 
     MinMaxSizes item_final_contribution;
-    const ComputedStyle& child_style = item.style_;
+    const ComputedStyle& child_style = *item.style_;
     const LayoutUnit flex_base_size_border_box =
         item.flex_base_content_size_ + item.main_axis_border_padding_;
     const LayoutUnit hypothetical_main_size_border_box =
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_line_resolver.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_line_resolver.h
index 1970a8d..61d89c31 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_line_resolver.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_line_resolver.h
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/style/grid_area.h"
 #include "third_party/blink/renderer/core/style/grid_enums.h"
 #include "third_party/blink/renderer/core/style/named_grid_lines_map.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
 
@@ -130,7 +131,9 @@
 
   bool IsSubgridded(GridTrackSizingDirection track_direction) const;
 
-  scoped_refptr<const ComputedStyle> style_;
+  // This doesn't create a cycle as ComputeStyle doesn't have any references to
+  // layout-time objects.
+  Persistent<const ComputedStyle> style_;
 
   wtf_size_t column_auto_repetitions_{1};
   wtf_size_t row_auto_repetitions_{1};
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
index 35339904..e7a99e0 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
@@ -14,6 +14,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_height.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "third_party/blink/renderer/platform/wtf/vector_traits.h"
 
 namespace blink {
 
@@ -41,7 +42,7 @@
  public:
   unsigned fragment_start = 0;
   const NGInlineItem* item = nullptr;
-  const ComputedStyle* style = nullptr;
+  Member<const ComputedStyle> style;
 
   // Points to style->GetFont(), or |scaled_font| in an SVG <text>.
   const Font* font;
@@ -95,6 +96,8 @@
   NGInlineBoxState(const NGInlineBoxState&) = delete;
   NGInlineBoxState& operator=(const NGInlineBoxState&) = delete;
 
+  void Trace(Visitor* visitor) const { visitor->Trace(style); }
+
   // Reset |style|, |is_svg_text|, |font|, |scaled_font|, |scaling_factor|, and
   // |alignment_type|.
   void ResetStyle(const ComputedStyle& style_ref,
@@ -311,7 +314,7 @@
   // Update edges of inline fragmented boxes.
   void UpdateFragmentedBoxDataEdges(Vector<BoxData>* fragmented_boxes);
 
-  Vector<NGInlineBoxState, 4> stack_;
+  HeapVector<NGInlineBoxState, 4> stack_;
   Vector<BoxData, 4> box_data_list_;
 
   bool is_empty_line_ = false;
@@ -321,4 +324,6 @@
 
 }  // namespace blink
 
+WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::NGInlineBoxState)
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_BOX_STATE_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
index 2560892..b281107 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
@@ -13,7 +13,7 @@
 namespace {
 
 struct SameSizeAsNGInlineBreakToken : NGBreakToken {
-  scoped_refptr<const ComputedStyle> style_;
+  Member<const ComputedStyle> style;
   unsigned numbers[2];
 };
 
@@ -122,6 +122,7 @@
   // in ctor.
   if (flags_ & kHasSubBreakToken)
     visitor->Trace(*sub_break_token_);
+  visitor->Trace(style_);
   NGBreakToken::TraceAfterDispatch(visitor);
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
index 01b6603a..76c484e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
@@ -40,7 +40,7 @@
 
   // The style at the end of this break token. The next line should start with
   // this style.
-  const ComputedStyle* Style() const { return style_.get(); }
+  const ComputedStyle* Style() const { return style_.Get(); }
 
   // The point where the next layout should start, or where the previous layout
   // ended.
@@ -95,7 +95,7 @@
  private:
   const Member<const NGBreakToken>* SubBreakTokenAddress() const;
 
-  scoped_refptr<const ComputedStyle> style_;
+  Member<const ComputedStyle> style_;
   NGInlineItemTextIndex start_;
 
   // This is an array of one item if |kHasSubBreakToken|, or zero.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
index a81fab1..8a0a319b 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -195,8 +195,8 @@
     : style(*item.Style()),
       item_index(item_index),
       should_create_box_fragment(item.ShouldCreateBoxFragment()),
-      text_metrics(style.GetFontHeight()) {
-  DCHECK(&style);
+      text_metrics(style->GetFontHeight()) {
+  DCHECK(style);
 }
 
 // True if this inline box should create a box fragment when it has |child|.
@@ -205,7 +205,7 @@
     ShouldCreateBoxFragmentForChild(const BoxInfo& child) const {
   // When a child inline box has margins, the parent has different width/height
   // from the union of children.
-  const ComputedStyle& child_style = child.style;
+  const ComputedStyle& child_style = *child.style;
   if (child_style.MayHaveMargin())
     return true;
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
index ed32d5d..b889dee 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
@@ -150,7 +150,7 @@
   void ClearNeedsLayout(LayoutObject*);
   void UpdateShouldCreateBoxFragment(LayoutInline*);
 
-  // In public to modify VectorTraits<BidiContext> in WTF namespace.
+  // The following structs are public to modify VectorTraits in WTF namespace.
   struct BidiContext {
     DISALLOW_NEW();
 
@@ -162,6 +162,22 @@
     UChar exit;
   };
 
+  // Keep track of inline boxes to compute ShouldCreateBoxFragment.
+  struct BoxInfo {
+    DISALLOW_NEW();
+
+    Member<const ComputedStyle> style;
+    unsigned item_index;
+    bool should_create_box_fragment;
+    FontHeight text_metrics;
+
+    void Trace(Visitor* visitor) const { visitor->Trace(style); }
+
+    BoxInfo(unsigned item_index, const NGInlineItem& item);
+    bool ShouldCreateBoxFragmentForChild(const BoxInfo& child) const;
+    void SetShouldCreateBoxFragment(HeapVector<NGInlineItem>* items);
+  };
+
  private:
   static bool NeedsBoxInfo();
 
@@ -174,21 +190,7 @@
   // white space is collapsed.
   OffsetMappingBuilder mapping_builder_;
 
-  // Keep track of inline boxes to compute ShouldCreateBoxFragment.
-  struct BoxInfo {
-    DISALLOW_NEW();
-
-    const ComputedStyle& style;
-    unsigned item_index;
-    bool should_create_box_fragment;
-    FontHeight text_metrics;
-
-    BoxInfo(unsigned item_index, const NGInlineItem& item);
-    bool ShouldCreateBoxFragmentForChild(const BoxInfo& child) const;
-    void SetShouldCreateBoxFragment(HeapVector<NGInlineItem>* items);
-  };
-  Vector<BoxInfo> boxes_;
-
+  HeapVector<BoxInfo> boxes_;
   HeapVector<BidiContext> bidi_context_;
 
   const SvgTextChunkOffsets* text_chunk_offsets_;
@@ -298,5 +300,9 @@
     blink::NGInlineItemsBuilder::BidiContext)
 WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(
     blink::NGInlineItemsBuilderForOffsetMapping::BidiContext)
+WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(
+    blink::NGInlineItemsBuilder::BoxInfo)
+WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(
+    blink::NGInlineItemsBuilderForOffsetMapping::BoxInfo)
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEMS_BUILDER_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
index 881c643..8a3ef11a 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
@@ -52,7 +52,7 @@
     block_flow_->SetStyle(style_, LayoutObject::ApplyStyleChanges::kNo);
   }
 
-  scoped_refptr<const ComputedStyle> GetStyle(EWhiteSpace whitespace) {
+  const ComputedStyle* GetStyle(EWhiteSpace whitespace) {
     if (whitespace == EWhiteSpace::kNormal)
       return style_;
     ComputedStyleBuilder builder =
@@ -67,7 +67,7 @@
 
   void AppendText(const String& text, NGInlineItemsBuilder* builder) {
     LayoutText* layout_text =
-        LayoutText::CreateEmptyAnonymous(GetDocument(), style_.get());
+        LayoutText::CreateEmptyAnonymous(GetDocument(), style_);
     anonymous_objects_->push_back(layout_text);
     builder->AppendText(text, layout_text);
   }
@@ -190,7 +190,7 @@
   Persistent<LayoutBlockFlow> block_flow_;
   Persistent<HeapVector<NGInlineItem>> items_;
   String text_;
-  scoped_refptr<const ComputedStyle> style_;
+  Persistent<const ComputedStyle> style_;
   Persistent<HeapVector<Member<LayoutObject>>> anonymous_objects_;
 };
 
@@ -423,9 +423,9 @@
 TEST_F(NGInlineItemsBuilderTest, Empty) {
   HeapVector<NGInlineItem> items;
   NGInlineItemsBuilder builder(GetLayoutBlockFlow(), &items);
-  scoped_refptr<const ComputedStyle> block_style =
+  const ComputedStyle* block_style =
       &GetDocument().GetStyleResolver().InitialStyle();
-  builder.EnterBlock(block_style.get());
+  builder.EnterBlock(block_style);
   builder.ExitBlock();
 
   EXPECT_EQ("", builder.ToString());
@@ -470,9 +470,8 @@
       GetDocument().GetStyleResolver().InitialStyle());
   block_style_builder.SetUnicodeBidi(UnicodeBidi::kBidiOverride);
   block_style_builder.SetDirection(TextDirection::kRtl);
-  scoped_refptr<const ComputedStyle> block_style =
-      block_style_builder.TakeStyle();
-  builder.EnterBlock(block_style.get());
+  const ComputedStyle* block_style = block_style_builder.TakeStyle();
+  builder.EnterBlock(block_style);
   AppendText("Hello", &builder);
   builder.ExitBlock();
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index 2e3f2857..cc09be5 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -1689,7 +1689,7 @@
       EFloat previous_float_type = EFloat::kNone;
       for (const auto& floating_object : floating_objects_) {
         const EClear float_clear =
-            floating_object.float_style.Clear(floating_object.style);
+            floating_object.float_style->Clear(*floating_object.style);
 
         // If this float clears the previous float we start a new "line".
         // This is subtly different to block layout which will only reset either
@@ -1708,7 +1708,7 @@
         floats_inline_size_ += floating_object.float_inline_max_size_with_margin
                                    .ClampNegativeToZero();
         previous_float_type =
-            floating_object.float_style.Floating(floating_object.style);
+            floating_object.float_style->Floating(*floating_object.style);
       }
       max_inline_size =
           std::max(max_inline_size, line_inline_size + floats_inline_size_);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
index 9290d1a..6258644d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
@@ -136,10 +136,13 @@
   struct FloatingObject {
     DISALLOW_NEW();
 
-    void Trace(Visitor* visitor) const {}
+    void Trace(Visitor* visitor) const {
+      visitor->Trace(float_style);
+      visitor->Trace(style);
+    }
 
-    const ComputedStyle& float_style;
-    const ComputedStyle& style;
+    Member<const ComputedStyle> float_style;
+    Member<const ComputedStyle> style;
     LayoutUnit float_inline_max_size_with_margin;
   };
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
index dc47069..4f431ab3 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -28,7 +28,7 @@
 
  public:
   NGLineBoxFragmentBuilder(NGInlineNode node,
-                           scoped_refptr<const ComputedStyle> style,
+                           const ComputedStyle* style,
                            const NGConstraintSpace& space,
                            WritingDirectionMode writing_direction)
       : NGFragmentBuilder(
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index e1f110a..bd28956 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -3078,7 +3078,7 @@
           }
           continue;
         }
-        scoped_refptr<const ComputedStyle> was_current_style = current_style_;
+        const ComputedStyle* was_current_style = current_style_;
         SetCurrentStyle(*item.Style());
         const NGInlineItemResult item_result_before = *item_result;
         BreakText(item_result, item, *item.TextShapeResult(),
@@ -3424,7 +3424,7 @@
 }
 
 void NGLineBreaker::SetCurrentStyle(const ComputedStyle& style) {
-  if (&style == current_style_.get()) {
+  if (&style == current_style_) {
 #if EXPENSIVE_DCHECKS_ARE_ON()
     // Check that cache fields are already setup correctly.
     DCHECK_EQ(auto_wrap_, ShouldAutoWrap(style));
@@ -3592,7 +3592,7 @@
     // in inline in the current fragmentainer (and the block-in-inline part
     // won't be seen there).
     sub_break_token = NGInlineBreakToken::Create(
-        node_, current_style_.get(), current_, flags, sub_break_token);
+        node_, current_style_, current_, flags, sub_break_token);
 
     // Move past the block in inline, since we stopped at it. This is where
     // regular inline content will resume.
@@ -3600,8 +3600,8 @@
     MoveToNextOf(items[current_.item_index]);
   }
 
-  return NGInlineBreakToken::Create(node_, current_style_.get(), current_,
-                                    flags, sub_break_token);
+  return NGInlineBreakToken::Create(node_, current_style_, current_, flags,
+                                    sub_break_token);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
index 5a3f60b1..6426df4a 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -355,7 +355,7 @@
   NGExclusionSpace* exclusion_space_;
   const NGInlineBreakToken* break_token_;
   const NGColumnSpannerPath* column_spanner_path_;
-  scoped_refptr<const ComputedStyle> current_style_;
+  const ComputedStyle* current_style_ = nullptr;
 
   LazyLineBreakIterator break_iterator_;
   HarfBuzzShaper shaper_;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h
index 1809b549..6afe231 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_info.h
@@ -247,7 +247,7 @@
       unsigned* end_offset_out = nullptr) const;
 
   const NGInlineItemsData* items_data_ = nullptr;
-  scoped_refptr<const ComputedStyle> line_style_;
+  const ComputedStyle* line_style_{nullptr};
   NGInlineItemResults results_;
 
   NGBfcOffset bfc_offset_;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h
index 6a32d94..0cf101ae9 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h
@@ -85,7 +85,7 @@
                                  TextDirection direction);
   void HideChild(NGLogicalLineItem* child);
 
-  scoped_refptr<const ComputedStyle> line_style_;
+  const ComputedStyle* line_style_;
   LayoutUnit available_width_;
   TextDirection line_direction_;
 
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_ruby_run.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_ruby_run.cc
index 6ddf69c..4523a81e 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_ruby_run.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_ruby_run.cc
@@ -196,12 +196,12 @@
   DCHECK(parent_ruby->IsRuby());
   LayoutNGRubyRun* rr = MakeGarbageCollected<LayoutNGRubyRun>();
   rr->SetDocumentForAnonymous(&parent_ruby->GetDocument());
-  scoped_refptr<const ComputedStyle> new_style =
+  const ComputedStyle* new_style =
       parent_ruby->GetDocument()
           .GetStyleResolver()
           .CreateAnonymousStyleWithDisplay(parent_ruby->StyleRef(),
                                            EDisplay::kInlineBlock);
-  rr->SetStyle(std::move(new_style));
+  rr->SetStyle(new_style);
   return *rr;
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index ab581eab..7b1d7dc 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -39,16 +39,16 @@
 
  public:
   NGBoxFragmentBuilder(NGLayoutInputNode node,
-                       scoped_refptr<const ComputedStyle> style,
+                       const ComputedStyle* style,
                        const NGConstraintSpace& space,
                        WritingDirectionMode writing_direction)
-      : NGFragmentBuilder(node, std::move(style), space, writing_direction),
+      : NGFragmentBuilder(node, style, space, writing_direction),
         is_inline_formatting_context_(node.IsInline()) {}
 
   // Build a fragment for LayoutObject without NGLayoutInputNode. LayoutInline
   // has NGInlineItem but does not have corresponding NGLayoutInputNode.
   NGBoxFragmentBuilder(LayoutObject* layout_object,
-                       scoped_refptr<const ComputedStyle> style,
+                       const ComputedStyle* style,
                        const NGConstraintSpace& space,
                        WritingDirectionMode writing_direction)
       : NGFragmentBuilder(/* node */ nullptr,
@@ -723,7 +723,7 @@
   // Table specific types.
   absl::optional<LogicalRect> table_grid_rect_;
   NGTableFragmentData::ColumnGeometries table_column_geometries_;
-  scoped_refptr<const NGTableBorders> table_collapsed_borders_;
+  const NGTableBorders* table_collapsed_borders_ = nullptr;
   std::unique_ptr<NGTableFragmentData::CollapsedBordersGeometry>
       table_collapsed_borders_geometry_;
   absl::optional<wtf_size_t> table_column_count_;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
index 423ea65..ee6305f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
@@ -458,12 +458,12 @@
 
  protected:
   NGFragmentBuilder(const NGLayoutInputNode& node,
-                    scoped_refptr<const ComputedStyle> style,
+                    const ComputedStyle* style,
                     const NGConstraintSpace& space,
                     WritingDirectionMode writing_direction)
       : node_(node),
         space_(space),
-        style_(std::move(style)),
+        style_(style),
         writing_direction_(writing_direction),
         style_variant_(NGStyleVariant::kStandard) {
     DCHECK(style_);
@@ -504,7 +504,7 @@
 
   NGLayoutInputNode node_;
   const NGConstraintSpace& space_;
-  scoped_refptr<const ComputedStyle> style_;
+  const ComputedStyle* style_;
   WritingDirectionMode writing_direction_;
   NGStyleVariant style_variant_;
   NGPhysicalFragment::NGBoxType box_type_ =
diff --git a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
index d820814..00f3a63 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
@@ -666,7 +666,7 @@
     const LogicalRect& ink_overflow,
     const NGInlinePaintContext* inline_context) {
   LogicalRect accumulated_bound;
-  auto pseudo_style =
+  auto* pseudo_style =
       fragment_item->Type() == NGFragmentItem::kSvgText
           ? nullptr
           : HighlightStyleUtils::HighlightPseudoStyle(
@@ -726,11 +726,11 @@
 
     const CustomHighlightMarker& highlight_marker =
         To<CustomHighlightMarker>(*marker);
-    auto pseudo_style = fragment_item->Type() == NGFragmentItem::kSvgText
-                            ? nullptr
-                            : HighlightStyleUtils::HighlightPseudoStyle(
-                                  text_node, style, kPseudoIdHighlight,
-                                  highlight_marker.GetHighlightName());
+    const auto* pseudo_style = fragment_item->Type() == NGFragmentItem::kSvgText
+                                   ? nullptr
+                                   : HighlightStyleUtils::HighlightPseudoStyle(
+                                         text_node, style, kPseudoIdHighlight,
+                                         highlight_marker.GetHighlightName());
 
     LogicalRect decoration_bound;
     if (pseudo_style && pseudo_style->HasAppliedTextDecorations()) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h
index eac9de7..658af80 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h
@@ -73,7 +73,7 @@
   STACK_ALLOCATED();
  public:
   NGLayoutAlgorithm(NGInputNodeType node,
-                    scoped_refptr<const ComputedStyle> style,
+                    const ComputedStyle* style,
                     const NGConstraintSpace& space,
                     TextDirection direction,
                     const NGBreakTokenType* break_token)
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
index a3fba88..bb69f1b1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
 
-#include "base/memory/scoped_refptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
@@ -88,7 +87,7 @@
                                            length, content_size);
   }
 
-  scoped_refptr<const ComputedStyle> initial_style_;
+  Persistent<const ComputedStyle> initial_style_;
 };
 
 class NGLengthUtilsTestWithNode : public RenderingTest {
@@ -477,7 +476,7 @@
   builder.SetMarginRight(Length::Fixed(52));
   builder.SetMarginBottom(Length::Auto());
   builder.SetMarginLeft(Length::Percent(11));
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
 
@@ -500,7 +499,7 @@
   builder.SetBorderBottomStyle(EBorderStyle::kSolid);
   builder.SetBorderLeftStyle(EBorderStyle::kSolid);
   builder.SetWritingMode(WritingMode::kVerticalLr);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   NGBoxStrut borders = ComputeBordersForTest(*style);
 
@@ -517,7 +516,7 @@
   builder.SetPaddingBottom(Length::Auto());
   builder.SetPaddingLeft(Length::Percent(11));
   builder.SetWritingMode(WritingMode::kVerticalRl);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   NGConstraintSpace constraint_space = ConstructConstraintSpace(
       200, 300, false, false, WritingMode::kVerticalRl);
@@ -534,7 +533,7 @@
   ComputedStyleBuilder builder(*initial_style_);
   builder.SetMarginRight(Length::Auto());
   builder.SetMarginLeft(Length::Auto());
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   LayoutUnit kInlineSize(150);
   LayoutUnit kAvailableInlineSize(200);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 9306d839..daf4dfc0 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -123,7 +123,7 @@
   return true;
 }
 
-scoped_refptr<const ComputedStyle> CreateFlippedAutoAnchorStyle(
+const ComputedStyle* CreateFlippedAutoAnchorStyle(
     const ComputedStyle& base_style,
     bool flip_block,
     bool flip_inline) {
@@ -264,7 +264,7 @@
   }
 
   void ClearAutoAnchorFallbackData() {
-    auto_anchor_style_.reset();
+    auto_anchor_style_ = nullptr;
     auto_anchor_flippable_in_block_ = false;
     auto_anchor_flippable_in_inline_ = false;
     auto_anchor_flip_block_ = false;
@@ -284,7 +284,7 @@
   // Created when the current style is generated by auto anchor positioning
   // and has any axis flipped compared to the base style.
   // https://drafts.csswg.org/css-anchor-position-1/#automatic-anchor-fallbacks
-  scoped_refptr<const ComputedStyle> auto_anchor_style_;
+  const ComputedStyle* auto_anchor_style_ = nullptr;
 
   bool auto_anchor_flippable_in_block_ = false;
   bool auto_anchor_flippable_in_inline_ = false;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index 75027e4..499360c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -172,10 +172,7 @@
   }
 
   const NGTableBorders* TableCollapsedBorders() const {
-    if (const auto* field = GetRareField(FieldId::kTableCollapsedBorders)) {
-      return field->table_collapsed_borders.get();
-    }
-    return nullptr;
+    return rare_data_ ? rare_data_->table_collapsed_borders_ : nullptr;
   }
 
   const NGTableFragmentData::CollapsedBordersGeometry*
diff --git a/third_party/blink/renderer/core/layout/ng/ng_relative_utils_test.cc b/third_party/blink/renderer/core/layout/ng/ng_relative_utils_test.cc
index 47bcf89..7297e58 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_relative_utils_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_relative_utils_test.cc
@@ -25,10 +25,10 @@
     initial_style_ = ComputedStyle::CreateInitialStyleSingleton();
   }
 
-  scoped_refptr<const ComputedStyle> CreateStyle(LayoutUnit top,
-                                                 LayoutUnit right,
-                                                 LayoutUnit bottom,
-                                                 LayoutUnit left) {
+  const ComputedStyle* CreateStyle(LayoutUnit top,
+                                   LayoutUnit right,
+                                   LayoutUnit bottom,
+                                   LayoutUnit left) {
     ComputedStyleBuilder builder(*initial_style_);
     builder.SetPosition(EPosition::kRelative);
     builder.SetTop(top == kAuto ? Length::Auto() : Length::Fixed(top.ToInt()));
@@ -41,7 +41,7 @@
     return builder.TakeStyle();
   }
 
-  scoped_refptr<const ComputedStyle> initial_style_;
+  Persistent<const ComputedStyle> initial_style_;
   LogicalSize container_size_;
 };
 
@@ -49,8 +49,7 @@
   LogicalOffset offset;
 
   // Everything auto defaults to kZero,kZero
-  scoped_refptr<const ComputedStyle> style =
-      CreateStyle(kAuto, kAuto, kAuto, kAuto);
+  const ComputedStyle* style = CreateStyle(kAuto, kAuto, kAuto, kAuto);
   offset = ComputeRelativeOffset(
       *style, {WritingMode::kHorizontalTb, TextDirection::kLtr},
       container_size_);
@@ -87,8 +86,7 @@
   LogicalOffset offset;
 
   // Set all sides
-  scoped_refptr<const ComputedStyle> style =
-      CreateStyle(kTop, kRight, kBottom, kLeft);
+  const ComputedStyle* style = CreateStyle(kTop, kRight, kBottom, kLeft);
 
   // kLtr
   offset = ComputeRelativeOffset(
@@ -114,8 +112,7 @@
   LogicalOffset offset;
 
   // Set all sides
-  scoped_refptr<const ComputedStyle> style =
-      CreateStyle(kTop, kRight, kBottom, kLeft);
+  const ComputedStyle* style = CreateStyle(kTop, kRight, kBottom, kLeft);
 
   // kLtr
   offset = ComputeRelativeOffset(
diff --git a/third_party/blink/renderer/core/layout/ng/physical_fragment_rare_data.cc b/third_party/blink/renderer/core/layout/ng/physical_fragment_rare_data.cc
index 1dd7e3ee..af7ab92 100644
--- a/third_party/blink/renderer/core/layout/ng/physical_fragment_rare_data.cc
+++ b/third_party/blink/renderer/core/layout/ng/physical_fragment_rare_data.cc
@@ -50,10 +50,6 @@
     SetField(FieldId::kTableGridRect).table_grid_rect =
         *builder.table_grid_rect_;
   }
-  if (builder.table_collapsed_borders_) {
-    SetField(FieldId::kTableCollapsedBorders).table_collapsed_borders =
-        std::move(builder.table_collapsed_borders_);
-  }
   if (builder.table_collapsed_borders_geometry_) {
     SetField(FieldId::kTableCollapsedBordersGeometry)
         .table_collapsed_borders_geometry =
@@ -73,6 +69,7 @@
     SetField(FieldId::kPageName).page_name = builder.page_name_;
   }
 
+  table_collapsed_borders_ = builder.table_collapsed_borders_;
   if (!builder.table_column_geometries_.empty()) {
     table_column_geometries_ =
         MakeGarbageCollected<NGTableFragmentData::ColumnGeometries>(
@@ -96,7 +93,8 @@
 
 PhysicalFragmentRareData::PhysicalFragmentRareData(
     const PhysicalFragmentRareData& other)
-    : table_column_geometries_(other.table_column_geometries_) {
+    : table_collapsed_borders_(other.table_collapsed_borders_),
+      table_column_geometries_(other.table_column_geometries_) {
   field_list_.ReserveInitialCapacity(other.field_list_.capacity());
 
   // Each field should be processed in order of FieldId to avoid vector
@@ -109,7 +107,6 @@
   CLONE_IF_EXISTS(kFrameSetLayoutData, frame_set_layout_data, other);
   CLONE_IF_EXISTS(kMathMLPaintInfo, mathml_paint_info, other);
   SET_IF_EXISTS(kTableGridRect, table_grid_rect, other);
-  SET_IF_EXISTS(kTableCollapsedBorders, table_collapsed_borders, other);
   CLONE_IF_EXISTS(kTableCollapsedBordersGeometry,
                   table_collapsed_borders_geometry, other);
   SET_IF_EXISTS(kTableCellColumnIndex, table_cell_column_index, other);
@@ -138,7 +135,6 @@
     FUNC(kFrameSetLayoutData, frame_set_layout_data);                       \
     FUNC(kMathMLPaintInfo, mathml_paint_info);                              \
     FUNC(kTableGridRect, table_grid_rect);                                  \
-    FUNC(kTableCollapsedBorders, table_collapsed_borders);                  \
     FUNC(kTableCollapsedBordersGeometry, table_collapsed_borders_geometry); \
     FUNC(kTableCellColumnIndex, table_cell_column_index);                   \
     FUNC(kTableSectionStartRowIndex, table_section_start_row_index);        \
diff --git a/third_party/blink/renderer/core/layout/ng/physical_fragment_rare_data.h b/third_party/blink/renderer/core/layout/ng/physical_fragment_rare_data.h
index ac97d24..30aba53d 100644
--- a/third_party/blink/renderer/core/layout/ng/physical_fragment_rare_data.h
+++ b/third_party/blink/renderer/core/layout/ng/physical_fragment_rare_data.h
@@ -45,6 +45,7 @@
   ~PhysicalFragmentRareData();
 
   void Trace(Visitor* visitor) const {
+    visitor->Trace(table_collapsed_borders_);
     visitor->Trace(table_column_geometries_);
   }
 
@@ -63,7 +64,6 @@
     kFrameSetLayoutData,
     kMathMLPaintInfo,
     kTableGridRect,
-    kTableCollapsedBorders,
     kTableCollapsedBordersGeometry,
     kTableCellColumnIndex,
     kTableSectionStartRowIndex,
@@ -157,7 +157,8 @@
   RareBitFieldType bit_field_;
   // A garbage-collected field is not stored in the Vector in order to avoid
   // troublesome conditional tracing.
-  Member<NGTableFragmentData::ColumnGeometries> table_column_geometries_;
+  Member<const NGTableBorders> table_collapsed_borders_;
+  Member<const NGTableFragmentData::ColumnGeometries> table_column_geometries_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
index b1a0a05..3235559 100644
--- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
@@ -42,15 +42,20 @@
 
 LayoutNGTable::~LayoutNGTable() = default;
 
+void LayoutNGTable::Trace(Visitor* visitor) const {
+  visitor->Trace(cached_table_borders_);
+  LayoutNGBlock::Trace(visitor);
+}
+
 LayoutNGTable* LayoutNGTable::CreateAnonymousWithParent(
     const LayoutObject& parent) {
-  scoped_refptr<const ComputedStyle> new_style =
+  const ComputedStyle* new_style =
       parent.GetDocument().GetStyleResolver().CreateAnonymousStyleWithDisplay(
           parent.StyleRef(),
           parent.IsLayoutInline() ? EDisplay::kInlineTable : EDisplay::kTable);
   auto* new_table = MakeGarbageCollected<LayoutNGTable>(nullptr);
   new_table->SetDocumentForAnonymous(&parent.GetDocument());
-  new_table->SetStyle(std::move(new_style));
+  new_table->SetStyle(new_style);
   return new_table;
 }
 
@@ -189,10 +194,9 @@
   return cached_table_borders_ && cached_table_borders_->IsCollapsed();
 }
 
-void LayoutNGTable::SetCachedTableBorders(
-    scoped_refptr<const NGTableBorders> table_borders) {
+void LayoutNGTable::SetCachedTableBorders(const NGTableBorders* table_borders) {
   NOT_DESTROYED();
-  cached_table_borders_ = std::move(table_borders);
+  cached_table_borders_ = table_borders;
 }
 
 void LayoutNGTable::InvalidateCachedTableBorders() {
@@ -200,7 +204,7 @@
   // TODO(layout-dev) When cached borders are invalidated, we could do a
   // special kind of relayout where fragments can replace only TableBorders,
   // keep the geometry, and repaint.
-  cached_table_borders_.reset();
+  cached_table_borders_ = nullptr;
 }
 
 const NGTableTypes::Columns* LayoutNGTable::GetCachedTableColumnConstraints() {
@@ -393,7 +397,7 @@
   NOT_DESTROYED();
   // DCHECK(cached_table_borders_.get())
   // ScrollAnchoring fails this DCHECK.
-  if (ShouldCollapseBorders() && cached_table_borders_.get()) {
+  if (ShouldCollapseBorders() && cached_table_borders_) {
     return cached_table_borders_->TableBorder()
         .ConvertToPhysical(Style()->GetWritingDirection())
         .left;
@@ -405,7 +409,7 @@
   NOT_DESTROYED();
   // DCHECK(cached_table_borders_.get())
   // ScrollAnchoring fails this DCHECK.
-  if (ShouldCollapseBorders() && cached_table_borders_.get()) {
+  if (ShouldCollapseBorders() && cached_table_borders_) {
     return cached_table_borders_->TableBorder()
         .ConvertToPhysical(Style()->GetWritingDirection())
         .right;
@@ -417,7 +421,7 @@
   NOT_DESTROYED();
   // DCHECK(cached_table_borders_.get())
   // ScrollAnchoring fails this DCHECK.
-  if (ShouldCollapseBorders() && cached_table_borders_.get()) {
+  if (ShouldCollapseBorders() && cached_table_borders_) {
     return cached_table_borders_->TableBorder()
         .ConvertToPhysical(Style()->GetWritingDirection())
         .top;
@@ -429,7 +433,7 @@
   NOT_DESTROYED();
   // DCHECK(cached_table_borders_.get())
   // ScrollAnchoring fails this DCHECK.
-  if (ShouldCollapseBorders() && cached_table_borders_.get()) {
+  if (ShouldCollapseBorders() && cached_table_borders_) {
     return cached_table_borders_->TableBorder()
         .ConvertToPhysical(Style()->GetWritingDirection())
         .bottom;
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h
index a4222cbd..9a9f9c3d 100644
--- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h
+++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h
@@ -101,6 +101,8 @@
   explicit LayoutNGTable(Element*);
   ~LayoutNGTable() override;
 
+  void Trace(Visitor*) const override;
+
   static LayoutNGTable* CreateAnonymousWithParent(const LayoutObject&);
 
   bool IsFirstCell(const LayoutNGTableCell&) const;
@@ -118,10 +120,10 @@
 
   const NGTableBorders* GetCachedTableBorders() const {
     NOT_DESTROYED();
-    return cached_table_borders_.get();
+    return cached_table_borders_.Get();
   }
 
-  void SetCachedTableBorders(scoped_refptr<const NGTableBorders>);
+  void SetCachedTableBorders(const NGTableBorders*);
 
   const NGTableTypes::Columns* GetCachedTableColumnConstraints();
 
@@ -225,7 +227,7 @@
   void InvalidateCachedTableBorders();
 
   // Table borders are cached because computing collapsed borders is expensive.
-  scoped_refptr<const NGTableBorders> cached_table_borders_;
+  Member<const NGTableBorders> cached_table_borders_;
 
   // Table columns do not depend on any outside data (e.g. NGConstraintSpace).
   // They are cached because computing them is expensive.
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.cc b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.cc
index 264778c9..2707f5c 100644
--- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.cc
@@ -27,12 +27,12 @@
 
 LayoutNGTableCell* LayoutNGTableCell::CreateAnonymousWithParent(
     const LayoutObject& parent) {
-  scoped_refptr<const ComputedStyle> new_style =
+  const ComputedStyle* new_style =
       parent.GetDocument().GetStyleResolver().CreateAnonymousStyleWithDisplay(
           parent.StyleRef(), EDisplay::kTableCell);
   auto* new_cell = MakeGarbageCollected<LayoutNGTableCell>(nullptr);
   new_cell->SetDocumentForAnonymous(&parent.GetDocument());
-  new_cell->SetStyle(std::move(new_style));
+  new_cell->SetStyle(new_style);
   return new_cell;
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.cc b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.cc
index bbc86dae..92e380e 100644
--- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.cc
@@ -18,12 +18,12 @@
 
 LayoutNGTableRow* LayoutNGTableRow::CreateAnonymousWithParent(
     const LayoutObject& parent) {
-  scoped_refptr<const ComputedStyle> new_style =
+  const ComputedStyle* new_style =
       parent.GetDocument().GetStyleResolver().CreateAnonymousStyleWithDisplay(
           parent.StyleRef(), EDisplay::kTableRow);
   auto* new_row = MakeGarbageCollected<LayoutNGTableRow>(nullptr);
   new_row->SetDocumentForAnonymous(&parent.GetDocument());
-  new_row->SetStyle(std::move(new_style));
+  new_row->SetStyle(new_style);
   return new_row;
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc
index 82c01af0..124d3be 100644
--- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.cc
@@ -16,12 +16,12 @@
 
 LayoutNGTableSection* LayoutNGTableSection::CreateAnonymousWithParent(
     const LayoutObject& parent) {
-  scoped_refptr<const ComputedStyle> new_style =
+  const ComputedStyle* new_style =
       parent.GetDocument().GetStyleResolver().CreateAnonymousStyleWithDisplay(
           parent.StyleRef(), EDisplay::kTableRowGroup);
   auto* new_section = MakeGarbageCollected<LayoutNGTableSection>(nullptr);
   new_section->SetDocumentForAnonymous(&parent.GetDocument());
-  new_section->SetStyle(std::move(new_style));
+  new_section->SetStyle(new_style);
   return new_section;
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.cc
index b5edd253..7814b589 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.cc
@@ -32,12 +32,12 @@
     return true;
 
   EBorderStyle edge_border_style =
-      NGTableBorders::BorderStyle(edge.style.get(), edge.edge_side);
+      NGTableBorders::BorderStyle(edge.style.Get(), edge.edge_side);
   if (edge_border_style == EBorderStyle::kHidden)
     return false;
 
   LayoutUnit edge_width =
-      NGTableBorders::BorderWidth(edge.style.get(), edge.edge_side);
+      NGTableBorders::BorderWidth(edge.style.Get(), edge.edge_side);
   if (source_width < edge_width)
     return false;
   if (source_width > edge_width)
@@ -112,14 +112,13 @@
 
 }  // namespace
 
-scoped_refptr<NGTableBorders> NGTableBorders::ComputeTableBorders(
+const NGTableBorders* NGTableBorders::ComputeTableBorders(
     const NGBlockNode& table) {
   const ComputedStyle& table_style = table.Style();
   const bool is_collapsed =
       table_style.BorderCollapse() == EBorderCollapse::kCollapse;
-  scoped_refptr<NGTableBorders> table_borders =
-      base::MakeRefCounted<NGTableBorders>(
-          ComputeNonCollapsedTableBorders(table_style), is_collapsed);
+  NGTableBorders* table_borders = MakeGarbageCollected<NGTableBorders>(
+      ComputeNonCollapsedTableBorders(table_style), is_collapsed);
 
   if (!is_collapsed)
     return table_borders;
@@ -230,14 +229,12 @@
   // COL borders have precedence over COLGROUP borders.
   // We have to traverse COL first, then COLGROUP.
   ColBordersMarker col_borders_marker(table_row_count, ++box_order,
-                                      table_writing_direction,
-                                      *table_borders.get());
+                                      table_writing_direction, *table_borders);
   VisitLayoutNGTableColumn(
       const_cast<HeapVector<NGBlockNode>&>(grouped_children.columns),
       table_column_count, &col_borders_marker);
-  ColgroupBordersMarker colgroup_borders_marker(table_row_count, ++box_order,
-                                                table_writing_direction,
-                                                *table_borders.get());
+  ColgroupBordersMarker colgroup_borders_marker(
+      table_row_count, ++box_order, table_writing_direction, *table_borders);
   VisitLayoutNGTableColumn(
       const_cast<HeapVector<NGBlockNode>&>(grouped_children.columns),
       table_column_count, &colgroup_borders_marker);
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.h b/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.h
index 290e60d5..ba9259ba 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.h
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_borders.h
@@ -59,12 +59,14 @@
 //   |   |   |    |
 //   |9  |11 |13  |15
 
-class NGTableBorders : public RefCounted<NGTableBorders> {
+class NGTableBorders : public GarbageCollected<NGTableBorders> {
  public:
-  static scoped_refptr<NGTableBorders> ComputeTableBorders(const NGBlockNode&);
+  static const NGTableBorders* ComputeTableBorders(const NGBlockNode&);
 
   NGTableBorders(const NGBoxStrut& table_border, const bool is_collapsed);
 
+  void Trace(Visitor* visitor) const { visitor->Trace(edges_); }
+
 #if DCHECK_IS_ON()
   String DumpEdges();
   void ShowEdges();
@@ -81,13 +83,15 @@
   // style border defines the edge.
   struct Edge {
     DISALLOW_NEW();
-    scoped_refptr<const ComputedStyle> style;
+    Member<const ComputedStyle> style;
     EdgeSide edge_side;
     // Box order is used to compute edge painting precedence.
     // Lower box order has precedence.
-    // The order value is defined as "box visited index" while
-    // computing collapsed edges.
+    // The order value is defined as "box visited index" while computing
+    // collapsed edges.
     wtf_size_t box_order;
+
+    void Trace(Visitor* visitor) const { visitor->Trace(style); }
   };
 
   static LayoutUnit BorderWidth(const ComputedStyle* style,
@@ -152,17 +156,17 @@
   }
 
   LayoutUnit BorderWidth(wtf_size_t edge_index) const {
-    return BorderWidth(edges_[edge_index].style.get(),
+    return BorderWidth(edges_[edge_index].style.Get(),
                        edges_[edge_index].edge_side);
   }
 
   EBorderStyle BorderStyle(wtf_size_t edge_index) const {
-    return BorderStyle(edges_[edge_index].style.get(),
+    return BorderStyle(edges_[edge_index].style.Get(),
                        edges_[edge_index].edge_side);
   }
 
   Color BorderColor(wtf_size_t edge_index) const {
-    return BorderColor(edges_[edge_index].style.get(),
+    return BorderColor(edges_[edge_index].style.Get(),
                        edges_[edge_index].edge_side);
   }
 
@@ -170,7 +174,7 @@
     return edges_[edge_index].box_order;
   }
 
-  using Edges = Vector<Edge>;
+  using Edges = HeapVector<Edge>;
 
   struct Section {
     wtf_size_t start_row;
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
index be81175..4f1f1d7 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
@@ -533,7 +533,7 @@
 
   const LogicalSize border_spacing = table.Style().TableBorderSpacing();
   NGTableGroupedChildren grouped_children(table);
-  scoped_refptr<const NGTableBorders> table_borders = table.GetTableBorders();
+  const NGTableBorders* table_borders = table.GetTableBorders();
 
   // Compute min/max inline constraints.
   const scoped_refptr<const NGTableTypes::Columns> column_constraints =
@@ -585,9 +585,8 @@
   const bool is_fixed_layout = Style().IsFixedTableLayout();
   const LogicalSize border_spacing = Style().TableBorderSpacing();
   NGTableGroupedChildren grouped_children(Node());
-  const scoped_refptr<const NGTableBorders> table_borders =
-      Node().GetTableBorders();
-  DCHECK(table_borders.get());
+  const NGTableBorders* table_borders = Node().GetTableBorders();
+  DCHECK(table_borders);
   const NGBoxStrut border_padding = container_builder_.BorderPadding();
 
   // Algorithm:
@@ -715,10 +714,8 @@
     text_autosizer.emplace(To<LayoutNGTable>(Node().GetLayoutBox()));
 
   const LogicalSize border_spacing = Style().TableBorderSpacing();
-  NGTableGroupedChildren grouped_children(Node());
-  const scoped_refptr<const NGTableBorders> table_borders =
-      Node().GetTableBorders();
   const NGBoxStrut border_padding = container_builder_.BorderPadding();
+  NGTableGroupedChildren grouped_children(Node());
 
   const scoped_refptr<const NGTableTypes::Columns> column_constraints =
       Node().GetColumnConstraints(grouped_children, border_padding);
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc
index 80af97d..3b957bc2 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc
@@ -10,17 +10,16 @@
 
 namespace blink {
 
-scoped_refptr<const NGTableBorders> NGTableNode::GetTableBorders() const {
+const NGTableBorders* NGTableNode::GetTableBorders() const {
   LayoutNGTable* layout_table = To<LayoutNGTable>(box_.Get());
-  scoped_refptr<const NGTableBorders> table_borders =
-      layout_table->GetCachedTableBorders();
+  const NGTableBorders* table_borders = layout_table->GetCachedTableBorders();
   if (!table_borders) {
     table_borders = NGTableBorders::ComputeTableBorders(*this);
-    layout_table->SetCachedTableBorders(table_borders.get());
+    layout_table->SetCachedTableBorders(table_borders);
   } else {
 #if DCHECK_IS_ON()
     // TODO(crbug.com/1191742) remove these DCHECKs as soon as bug is found.
-    auto duplicate_table_borders = NGTableBorders::ComputeTableBorders(*this);
+    auto* duplicate_table_borders = NGTableBorders::ComputeTableBorders(*this);
     DCHECK(*duplicate_table_borders == *table_borders);
 #endif
   }
@@ -39,7 +38,7 @@
       layout_table->GetCachedTableColumnConstraints();
   if (!column_constraints) {
     column_constraints = NGTableAlgorithmUtils::ComputeColumnConstraints(
-        *this, grouped_children, *GetTableBorders().get(), border_padding);
+        *this, grouped_children, *GetTableBorders(), border_padding);
     layout_table->SetCachedTableColumnConstraints(column_constraints.get());
   }
   return column_constraints;
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_node.h b/third_party/blink/renderer/core/layout/ng/table/ng_table_node.h
index 70edb7ca..8b3d08c 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_node.h
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_node.h
@@ -20,7 +20,7 @@
 
   const NGBoxStrut& GetTableBordersStrut() const;
 
-  scoped_refptr<const NGTableBorders> GetTableBorders() const;
+  const NGTableBorders* GetTableBorders() const;
 
   LayoutUnit ComputeCaptionBlockSize(const NGConstraintSpace& space) const;
 
diff --git a/third_party/blink/renderer/core/layout/overflow_model.h b/third_party/blink/renderer/core/layout/overflow_model.h
index 7962eb07..c2f3f7f 100644
--- a/third_party/blink/renderer/core/layout/overflow_model.h
+++ b/third_party/blink/renderer/core/layout/overflow_model.h
@@ -25,6 +25,7 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 
 namespace blink {
 
@@ -168,7 +169,7 @@
   bool has_subpixel_visual_effect_outsets_ = false;
 };
 
-struct BoxOverflowModel {
+struct BoxOverflowModel : public GarbageCollected<BoxOverflowModel> {
   absl::optional<BoxLayoutOverflowModel> layout_overflow;
   absl::optional<BoxVisualOverflowModel> visual_overflow;
 
@@ -181,7 +182,7 @@
   };
   absl::optional<PreviousOverflowData> previous_overflow_data;
 
-  USING_FAST_MALLOC(BoxOverflowModel);
+  void Trace(Visitor*) const {}
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/style_retain_scope.cc b/third_party/blink/renderer/core/layout/style_retain_scope.cc
deleted file mode 100644
index 6ec3cf6e..0000000
--- a/third_party/blink/renderer/core/layout/style_retain_scope.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/layout/style_retain_scope.h"
-
-#include "third_party/abseil-cpp/absl/base/attributes.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-
-namespace blink {
-
-namespace {
-
-ABSL_CONST_INIT thread_local StyleRetainScope* current = nullptr;
-
-}  // namespace
-
-StyleRetainScope::StyleRetainScope() : resetter_(&current, this) {}
-
-StyleRetainScope::~StyleRetainScope() {
-  DCHECK_EQ(current, this);
-}
-
-StyleRetainScope* StyleRetainScope::Current() {
-  return current;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/style_retain_scope.h b/third_party/blink/renderer/core/layout/style_retain_scope.h
deleted file mode 100644
index e09cf3f..0000000
--- a/third_party/blink/renderer/core/layout/style_retain_scope.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_STYLE_RETAIN_SCOPE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_STYLE_RETAIN_SCOPE_H_
-
-#include "base/auto_reset.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class ComputedStyle;
-
-// This class retains references to temporary styles during layout.
-class CORE_EXPORT StyleRetainScope {
-  STACK_ALLOCATED();
-
- public:
-  StyleRetainScope();
-  ~StyleRetainScope();
-
-  static StyleRetainScope* Current();
-
-  // Retain a reference to |style| for the lifetime of |this|.
-  void Retain(const ComputedStyle& style) {
-    styles_retained_during_layout_.push_back(&style);
-  }
-
- private:
-  Vector<scoped_refptr<const ComputedStyle>> styles_retained_during_layout_;
-  const base::AutoReset<StyleRetainScope*> resetter_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_STYLE_RETAIN_SCOPE_H_
diff --git a/third_party/blink/renderer/core/layout/style_retain_scope_test.cc b/third_party/blink/renderer/core/layout/style_retain_scope_test.cc
deleted file mode 100644
index 84d7b96..0000000
--- a/third_party/blink/renderer/core/layout/style_retain_scope_test.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/layout/style_retain_scope.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
-
-namespace blink {
-
-TEST(StyleRetainScopeTest, Current) {
-  EXPECT_EQ(StyleRetainScope::Current(), nullptr);
-  {
-    StyleRetainScope scope;
-    EXPECT_EQ(StyleRetainScope::Current(), &scope);
-    {
-      StyleRetainScope scope2;
-      EXPECT_EQ(StyleRetainScope::Current(), &scope2);
-    }
-    EXPECT_EQ(StyleRetainScope::Current(), &scope);
-  }
-  EXPECT_EQ(StyleRetainScope::Current(), nullptr);
-}
-
-TEST(StyleRetainScopeTest, Retain) {
-  scoped_refptr<const ComputedStyle> style =
-      ComputedStyle::CreateInitialStyleSingleton();
-  EXPECT_TRUE(style->HasOneRef());
-  {
-    StyleRetainScope scope;
-    scope.Retain(*style);
-
-    EXPECT_FALSE(style->HasOneRef());
-    EXPECT_TRUE(style->HasAtLeastOneRef());
-  }
-  EXPECT_TRUE(style->HasOneRef());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.cc b/third_party/blink/renderer/core/layout/text_autosizer.cc
index 9567e3e..d2240e58 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer.cc
+++ b/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -54,7 +54,6 @@
 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h"
 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.h"
 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.h"
-#include "third_party/blink/renderer/core/layout/style_retain_scope.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/platform/network/network_utils.h"
@@ -1224,7 +1223,7 @@
 
   ComputedStyleBuilder builder(current_style);
   builder.SetTextAutosizingMultiplier(multiplier);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   if (multiplier > 1 && !did_check_cross_site_use_count_) {
     ReportIfCrossSiteFrame();
@@ -1233,16 +1232,8 @@
 
   switch (relayout_behavior) {
     case kAlreadyInLayout:
-      // Don't free current_style until the end of the layout pass. This allows
-      // other parts of the system to safely hold raw ComputedStyle* pointers
-      // during layout, e.g. BreakingContext::current_style_.
-      if (auto* scope = StyleRetainScope::Current())
-        scope->Retain(current_style);
-      else
-        DCHECK(false);
-
       layout_object->SetModifiedStyleOutsideStyleRecalc(
-          std::move(style), LayoutObject::ApplyStyleChanges::kNo);
+          style, LayoutObject::ApplyStyleChanges::kNo);
       if (layout_object->IsText())
         To<LayoutText>(layout_object)->AutosizingMultiplerChanged();
       layout_object->SetNeedsLayoutAndFullPaintInvalidation(
@@ -1251,7 +1242,7 @@
 
     case kLayoutNeeded:
       layout_object->SetModifiedStyleOutsideStyleRecalc(
-          std::move(style), LayoutObject::ApplyStyleChanges::kYes);
+          style, LayoutObject::ApplyStyleChanges::kYes);
       break;
   }
 
diff --git a/third_party/blink/renderer/core/page/print_context.cc b/third_party/blink/renderer/core/page/print_context.cc
index 4f4b221..193638d 100644
--- a/third_party/blink/renderer/core/page/print_context.cc
+++ b/third_party/blink/renderer/core/page/print_context.cc
@@ -252,8 +252,7 @@
   // want to collect @page rules and figure out what declarations apply on a
   // given page (that may or may not exist).
   print_context->BeginPrintMode(WebPrintParams(gfx::SizeF(800, 1000)));
-  scoped_refptr<const ComputedStyle> style =
-      document->StyleForPage(page_number);
+  const ComputedStyle* style = document->StyleForPage(page_number);
 
   // Implement formatters for properties we care about.
   if (!strcmp(property_name, "margin-left")) {
@@ -294,7 +293,7 @@
 
   // Named pages aren't supported here, because this function may be called
   // without laying out first.
-  scoped_refptr<const ComputedStyle> style = frame->GetDocument()->StyleForPage(
+  const ComputedStyle* style = frame->GetDocument()->StyleForPage(
       page_number, /* page_name */ AtomicString());
   frame->GetDocument()->GetPageDescription(*style, &description);
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_decorating_box.h b/third_party/blink/renderer/core/paint/ng/ng_decorating_box.h
index e4a79fa6..fbd1ed4 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_decorating_box.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_decorating_box.h
@@ -37,6 +37,8 @@
   explicit NGDecoratingBox(const NGFragmentItem& item)
       : NGDecoratingBox(item, item.Style(), /* decorations */ nullptr) {}
 
+  void Trace(Visitor* visitor) const { visitor->Trace(style_); }
+
   const PhysicalOffset& ContentOffsetInContainer() const {
     return content_offset_in_container_;
   }
@@ -47,10 +49,12 @@
 
  private:
   PhysicalOffset content_offset_in_container_;
-  const ComputedStyle* style_;
+  Member<const ComputedStyle> style_;
   const Vector<AppliedTextDecoration, 1>* decorations_;
 };
 
 }  // namespace blink
 
+WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::NGDecoratingBox)
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_DECORATING_BOX_H_
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
index cc671bb..de62c21 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
@@ -162,28 +162,28 @@
                                         const ComputedStyle& originating_style,
                                         PseudoId pseudo) {
   DCHECK(pseudo == kPseudoIdSpellingError || pseudo == kPseudoIdGrammarError);
-  if (scoped_refptr<const ComputedStyle> pseudo_style =
+  if (const ComputedStyle* pseudo_style =
           HighlightStyleUtils::HighlightPseudoStyle(node, originating_style,
                                                     pseudo)) {
     const Document& document = node->GetDocument();
     // If the ‘color’, ‘-webkit-text-fill-color’, ‘-webkit-text-stroke-color’,
     // or ‘-webkit-text-stroke-width’ differs from the originating style.
     Color pseudo_color = HighlightStyleUtils::ResolveColor(
-        document, originating_style, pseudo_style.get(), pseudo,
+        document, originating_style, pseudo_style, pseudo,
         GetCSSPropertyColor(), {});
     if (pseudo_color !=
         originating_style.VisitedDependentColor(GetCSSPropertyColor())) {
       return true;
     }
     if (HighlightStyleUtils::ResolveColor(
-            document, originating_style, pseudo_style.get(), pseudo,
+            document, originating_style, pseudo_style, pseudo,
             GetCSSPropertyWebkitTextFillColor(), {}) !=
         originating_style.VisitedDependentColor(
             GetCSSPropertyWebkitTextFillColor())) {
       return true;
     }
     if (HighlightStyleUtils::ResolveColor(
-            document, originating_style, pseudo_style.get(), pseudo,
+            document, originating_style, pseudo_style, pseudo,
             GetCSSPropertyWebkitTextStrokeColor(), {}) !=
         originating_style.VisitedDependentColor(
             GetCSSPropertyWebkitTextStrokeColor())) {
@@ -193,7 +193,7 @@
       return true;
     // If there is a background color.
     if (!HighlightStyleUtils::ResolveColor(document, originating_style,
-                                           pseudo_style.get(), pseudo,
+                                           pseudo_style, pseudo,
                                            GetCSSPropertyBackgroundColor(), {})
              .IsFullyTransparent()) {
       return true;
@@ -227,7 +227,7 @@
     // https://github.com/w3c/csswg-drafts/issues/7101
     if (originating_style.GetTextEmphasisMark() != TextEmphasisMark::kNone &&
         HighlightStyleUtils::ResolveColor(
-            document, originating_style, pseudo_style.get(), pseudo,
+            document, originating_style, pseudo_style, pseudo,
             GetCSSPropertyTextEmphasisColor(), {}) !=
             originating_style.VisitedDependentColor(
                 GetCSSPropertyTextEmphasisColor())) {
@@ -650,7 +650,7 @@
                 highlight_pseudo_marker.GetPseudoId(), text_style, paint_info_,
                 highlight_pseudo_marker.GetPseudoArgument());
 
-        scoped_refptr<const ComputedStyle> pseudo_style =
+        const ComputedStyle* pseudo_style =
             HighlightStyleUtils::HighlightPseudoStyle(
                 node_, originating_style_,
                 highlight_pseudo_marker.GetPseudoId(),
@@ -699,7 +699,7 @@
     return kOverlay;
 
   if (selection_ && spelling_.empty() && grammar_.empty()) {
-    scoped_refptr<const ComputedStyle> pseudo_style =
+    const ComputedStyle* pseudo_style =
         HighlightStyleUtils::HighlightPseudoStyle(node_, originating_style_,
                                                   kPseudoIdSelection);
 
@@ -789,7 +789,7 @@
   }
 
   if (!text_painter_.GetSvgState()) {
-    if (auto pseudo_style = HighlightStyleUtils::HighlightPseudoStyle(
+    if (const auto* pseudo_style = HighlightStyleUtils::HighlightPseudoStyle(
             node_, originating_style_, PseudoFor(type))) {
       const TextPaintStyle text_style =
           HighlightStyleUtils::HighlightPaintingStyle(
@@ -1140,7 +1140,7 @@
         decoration_info->SetHighlightOverrideColor(
             HighlightStyleUtils::ResolveColor(
                 layout_object_->GetDocument(), originating_style_,
-                decoration_layer.style.get(), decoration_layer.id.PseudoId(),
+                decoration_layer.style.Get(), decoration_layer.id.PseudoId(),
                 GetCSSPropertyTextDecorationColor(),
                 layers_[decoration_layer_index - 1].text_style.current_color));
       }
@@ -1205,7 +1205,7 @@
         decoration_info->SetHighlightOverrideColor(
             HighlightStyleUtils::ResolveColor(
                 layout_object_->GetDocument(), originating_style_,
-                decoration_layer.style.get(), decoration_layer.id.PseudoId(),
+                decoration_layer.style.Get(), decoration_layer.id.PseudoId(),
                 GetCSSPropertyTextDecorationColor(),
                 layers_[decoration_layer_index - 1].text_style.current_color));
       }
@@ -1267,14 +1267,14 @@
 
 NGHighlightPainter::LayerPaintState::LayerPaintState(
     NGHighlightOverlay::HighlightLayer id,
-    const scoped_refptr<const ComputedStyle> style,
+    const ComputedStyle* style,
     TextPaintStyle text_style)
     : id(id),
       style(style),
       text_style(text_style),
       decorations_in_effect(style && style->HasAppliedTextDecorations()
-                                  ? style->TextDecorationsInEffect()
-                                  : TextDecorationLine::kNone) {}
+                                ? style->TextDecorationsInEffect()
+                                : TextDecorationLine::kNone) {}
 
 bool NGHighlightPainter::LayerPaintState::operator==(
     const HighlightLayer& other) const {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
index 24124c6..3fc4ef8 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
@@ -206,15 +206,16 @@
 
   SelectionPaintState* Selection() { return selection_; }
 
- private:
   struct LayerPaintState {
     DISALLOW_NEW();
 
    public:
     LayerPaintState(NGHighlightOverlay::HighlightLayer id,
-                    const scoped_refptr<const ComputedStyle> style,
+                    const ComputedStyle* style,
                     TextPaintStyle text_style);
 
+    void Trace(Visitor* visitor) const { visitor->Trace(style); }
+
     // Equality on HighlightLayer id only, for Vector::Find.
     bool operator==(const LayerPaintState&) const = delete;
     bool operator!=(const LayerPaintState&) const = delete;
@@ -222,11 +223,12 @@
     bool operator!=(const NGHighlightOverlay::HighlightLayer&) const;
 
     const NGHighlightOverlay::HighlightLayer id;
-    const scoped_refptr<const ComputedStyle> style;
+    const Member<const ComputedStyle> style;
     const TextPaintStyle text_style;
     const TextDecorationLine decorations_in_effect;
   };
 
+ private:
   Case ComputePaintCase() const;
   void FastPaintSpellingGrammarDecorations(const Text& text_node,
                                            const StringView& text,
@@ -275,7 +277,7 @@
   DocumentMarkerVector spelling_;
   DocumentMarkerVector grammar_;
   DocumentMarkerVector custom_;
-  Vector<LayerPaintState> layers_;
+  HeapVector<LayerPaintState> layers_;
   Vector<NGHighlightOverlay::HighlightPart> parts_;
   const bool skip_backgrounds_;
   Case paint_case_;
@@ -283,4 +285,7 @@
 
 }  // namespace blink
 
+WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(
+    blink::NGHighlightPainter::LayerPaintState)
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_HIGHLIGHT_PAINTER_H_
diff --git a/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context.h b/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context.h
index 0976ae0b..dad361eb 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context.h
@@ -19,7 +19,7 @@
   STACK_ALLOCATED();
 
  public:
-  using DecoratingBoxList = Vector<NGDecoratingBox, 4>;
+  using DecoratingBoxList = HeapVector<NGDecoratingBox, 4>;
   const DecoratingBoxList& DecoratingBoxes() const { return decorating_boxes_; }
 
   NGInlineCursor CursorForDescendantsOfLine() const {
diff --git a/third_party/blink/renderer/core/paint/outline_painter_test.cc b/third_party/blink/renderer/core/paint/outline_painter_test.cc
index 380af31..94cacbdb 100644
--- a/third_party/blink/renderer/core/paint/outline_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/outline_painter_test.cc
@@ -15,11 +15,11 @@
 using OutlinePainterTest = RenderingTest;
 
 TEST_F(OutlinePainterTest, FocusRingOutset) {
-  auto initial_style = ComputedStyle::CreateInitialStyleSingleton();
+  const auto* initial_style = ComputedStyle::CreateInitialStyleSingleton();
   ComputedStyleBuilder builder(*initial_style);
   builder.SetOutlineStyle(EBorderStyle::kSolid);
   builder.SetOutlineStyleIsAuto(true);
-  auto style = builder.TakeStyle();
+  const auto* style = builder.TakeStyle();
   LayoutObject::OutlineInfo info =
       LayoutObject::OutlineInfo::GetFromStyle(*style);
   EXPECT_EQ(2, OutlinePainter::OutlineOutsetExtent(*style, info));
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index a9d2bd5..8787a76 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2037,7 +2037,7 @@
                                const ComputedStyle& new_style) {
   if (!filter_on_effect_node_dirty_) {
     filter_on_effect_node_dirty_ =
-        old_style ? !old_style->FilterDataEquivalent(new_style) ||
+        old_style ? old_style->Filter() != new_style.Filter() ||
                         !old_style->ReflectionDataEquivalent(new_style)
                   : new_style.HasFilterInducingProperty();
   }
@@ -2057,7 +2057,7 @@
                                        const ComputedStyle& new_style) {
   if (!backdrop_filter_on_effect_node_dirty_) {
     backdrop_filter_on_effect_node_dirty_ =
-        old_style ? !old_style->BackdropFilterDataEquivalent(new_style)
+        old_style ? old_style->BackdropFilter() != new_style.BackdropFilter()
                   : new_style.HasBackdropFilter();
   }
 }
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 8954b0b..eafd87d 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -2060,11 +2060,11 @@
   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
   bool uses_standard_scrollbar_style =
       style_source.StyleRef().UsesStandardScrollbarStyle();
-  scoped_refptr<const ComputedStyle> corner =
+  const ComputedStyle* corner =
       (GetLayoutBox()->IsScrollContainer() && !uses_standard_scrollbar_style)
           ? style_source.GetUncachedPseudoElementStyle(
                 StyleRequest(kPseudoIdScrollbarCorner, style_source.Style()))
-          : scoped_refptr<ComputedStyle>(nullptr);
+          : nullptr;
   if (corner) {
     if (!scroll_corner_) {
       scroll_corner_ = LayoutCustomScrollbarPart::CreateAnonymous(
@@ -2199,11 +2199,11 @@
 
   // Update custom resizer style.
   const LayoutObject& style_source = ScrollbarStyleSource(*GetLayoutBox());
-  scoped_refptr<const ComputedStyle> resizer =
+  const ComputedStyle* resizer =
       GetLayoutBox()->IsScrollContainer()
           ? style_source.GetUncachedPseudoElementStyle(
                 StyleRequest(kPseudoIdResizer, style_source.Style()))
-          : scoped_refptr<ComputedStyle>(nullptr);
+          : nullptr;
   if (resizer) {
     if (!resizer_) {
       resizer_ = LayoutCustomScrollbarPart::CreateAnonymous(
diff --git a/third_party/blink/renderer/core/style/build.gni b/third_party/blink/renderer/core/style/build.gni
index bcd1f4b..d94aff4 100644
--- a/third_party/blink/renderer/core/style/build.gni
+++ b/third_party/blink/renderer/core/style/build.gni
@@ -79,8 +79,6 @@
   "style_difference.h",
   "style_fetched_image.cc",
   "style_fetched_image.h",
-  "style_filter_data.cc",
-  "style_filter_data.h",
   "style_generated_image.cc",
   "style_generated_image.h",
   "style_highlight_data.cc",
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 2459cfb..83eb3fa 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -113,7 +113,8 @@
 // inheritance structure. Make sure the fields have the same access specifiers
 // as in the "real" class since it can affect the layout. Reference the fields
 // so that they are not seen as unused (-Wunused-private-field).
-struct SameSizeAsComputedStyleBase {
+struct SameSizeAsComputedStyleBase
+    : public GarbageCollected<SameSizeAsComputedStyleBase> {
   SameSizeAsComputedStyleBase() {
     base::debug::Alias(&data_refs);
     base::debug::Alias(&pointers);
@@ -122,16 +123,15 @@
 
  private:
   void* data_refs[8];
-  void* pointers[1];
+  Member<void*> pointers[1];
   unsigned bitfields[5];
 };
 
-struct SameSizeAsComputedStyle : public SameSizeAsComputedStyleBase,
-                                 public RefCounted<SameSizeAsComputedStyle> {
+struct SameSizeAsComputedStyle : public SameSizeAsComputedStyleBase {
   SameSizeAsComputedStyle() { base::debug::Alias(&own_ptrs); }
 
  private:
-  void* own_ptrs[1];
+  Member<void*> own_ptrs[1];
 };
 
 // If this assert fails, it means that size of ComputedStyle has changed. Please
@@ -142,7 +142,7 @@
 
 StyleCachedData& ComputedStyle::EnsureCachedData() const {
   if (!cached_data_) {
-    cached_data_ = std::make_unique<StyleCachedData>();
+    cached_data_ = MakeGarbageCollected<StyleCachedData>();
   }
   return *cached_data_;
 }
@@ -154,7 +154,7 @@
 
 PseudoElementStyleCache* ComputedStyle::GetPseudoElementStyleCache() const {
   if (cached_data_) {
-    return cached_data_->pseudo_element_styles_.get();
+    return cached_data_->pseudo_element_styles_.Get();
   }
   return nullptr;
 }
@@ -162,13 +162,13 @@
 PseudoElementStyleCache& ComputedStyle::EnsurePseudoElementStyleCache() const {
   if (!cached_data_ || !cached_data_->pseudo_element_styles_) {
     EnsureCachedData().pseudo_element_styles_ =
-        std::make_unique<PseudoElementStyleCache>();
+        MakeGarbageCollected<PseudoElementStyleCache>();
   }
   return *cached_data_->pseudo_element_styles_;
 }
 
-scoped_refptr<ComputedStyle> ComputedStyle::CreateInitialStyleSingleton() {
-  return base::MakeRefCounted<ComputedStyle>(PassKey());
+const ComputedStyle* ComputedStyle::CreateInitialStyleSingleton() {
+  return MakeGarbageCollected<ComputedStyle>(PassKey());
 }
 
 Vector<AtomicString>* ComputedStyle::GetVariableNamesCache() const {
@@ -187,10 +187,10 @@
 }
 
 const ComputedStyle* ComputedStyle::AddCachedPositionFallbackStyle(
-    scoped_refptr<const ComputedStyle> style,
+    const ComputedStyle* style,
     unsigned index) const {
-  EnsurePositionFallbackStyleCache(index + 1)[index] = std::move(style);
-  return (*cached_data_->position_fallback_styles_)[index].get();
+  EnsurePositionFallbackStyleCache(index + 1)[index] = style;
+  return (*cached_data_->position_fallback_styles_)[index].Get();
 }
 
 const ComputedStyle* ComputedStyle::GetCachedPositionFallbackStyle(
@@ -199,14 +199,14 @@
       index >= cached_data_->position_fallback_styles_->size()) {
     return nullptr;
   }
-  return (*cached_data_->position_fallback_styles_)[index].get();
+  return (*cached_data_->position_fallback_styles_)[index].Get();
 }
 
 PositionFallbackStyleCache& ComputedStyle::EnsurePositionFallbackStyleCache(
     unsigned ensure_size) const {
   if (!cached_data_ || !cached_data_->position_fallback_styles_) {
     EnsureCachedData().position_fallback_styles_ =
-        std::make_unique<PositionFallbackStyleCache>();
+        MakeGarbageCollected<PositionFallbackStyleCache>();
   }
   if (cached_data_->position_fallback_styles_->size() < ensure_size) {
     cached_data_->position_fallback_styles_->resize(ensure_size);
@@ -214,24 +214,23 @@
   return *cached_data_->position_fallback_styles_;
 }
 
-ALWAYS_INLINE ComputedStyle::ComputedStyle() : RefCounted<ComputedStyle>() {}
+ALWAYS_INLINE ComputedStyle::ComputedStyle() = default;
 
 ALWAYS_INLINE ComputedStyle::ComputedStyle(const ComputedStyle& initial_style)
-    : ComputedStyleBase(initial_style), RefCounted<ComputedStyle>() {}
+    : ComputedStyleBase(initial_style) {}
 
 ALWAYS_INLINE ComputedStyle::ComputedStyle(const ComputedStyle& initial_style,
                                            const ComputedStyle& parent_style,
                                            ComputedStyleAccessFlags& access)
-    : ComputedStyleBase(initial_style, parent_style, access),
-      RefCounted<ComputedStyle>() {}
+    : ComputedStyleBase(initial_style, parent_style, access) {}
 
 ALWAYS_INLINE ComputedStyle::ComputedStyle(PassKey key) : ComputedStyle() {}
 
-ALWAYS_INLINE ComputedStyle::ComputedStyle(PassKey key,
+ALWAYS_INLINE ComputedStyle::ComputedStyle(BuilderPassKey key,
                                            const ComputedStyle& initial_style)
     : ComputedStyle(initial_style) {}
 
-ALWAYS_INLINE ComputedStyle::ComputedStyle(PassKey key,
+ALWAYS_INLINE ComputedStyle::ComputedStyle(BuilderPassKey key,
                                            const ComputedStyle& initial_style,
                                            const ComputedStyle& parent_style,
                                            ComputedStyleAccessFlags& access)
@@ -605,7 +604,7 @@
     if (pseudo_style->StyleType() == pseudo_id &&
         (!PseudoElementHasArguments(pseudo_id) ||
          pseudo_style->PseudoArgument() == pseudo_argument)) {
-      return pseudo_style.get();
+      return pseudo_style.Get();
     }
   }
 
@@ -629,7 +628,7 @@
 }
 
 const ComputedStyle* ComputedStyle::AddCachedPseudoElementStyle(
-    scoped_refptr<const ComputedStyle> pseudo,
+    const ComputedStyle* pseudo,
     PseudoId pseudo_id,
     const AtomicString& pseudo_argument) const {
   DCHECK(pseudo);
@@ -646,7 +645,7 @@
   DCHECK(!GetCachedPseudoElementStyle(pseudo->StyleType(),
                                       pseudo->PseudoArgument()));
 
-  const ComputedStyle* result = pseudo.get();
+  const ComputedStyle* result = pseudo;
 
   EnsurePseudoElementStyleCache().push_back(std::move(pseudo));
 
@@ -654,7 +653,7 @@
 }
 
 const ComputedStyle* ComputedStyle::ReplaceCachedPseudoElementStyle(
-    scoped_refptr<const ComputedStyle> pseudo_style,
+    const ComputedStyle* pseudo_style,
     PseudoId pseudo_id,
     const AtomicString& pseudo_argument) const {
   DCHECK(pseudo_style->StyleType() != kPseudoIdNone &&
@@ -666,7 +665,7 @@
            cached_style->PseudoArgument() == pseudo_argument)) {
         SECURITY_CHECK(cached_style->IsEnsuredInDisplayNone());
         cached_style = pseudo_style;
-        return pseudo_style.get();
+        return pseudo_style;
       }
     }
   }
@@ -680,14 +679,14 @@
 }
 
 const ComputedStyle* ComputedStyle::GetBaseComputedStyle() const {
-  if (auto* base_data = BaseData().get()) {
+  if (auto* base_data = BaseData().Get()) {
     return base_data->GetBaseComputedStyle();
   }
   return nullptr;
 }
 
 const CSSBitset* ComputedStyle::GetBaseImportantSet() const {
-  if (auto* base_data = BaseData().get()) {
+  if (auto* base_data = BaseData().Get()) {
     return base_data->GetBaseImportantSet();
   }
   return nullptr;
@@ -1152,7 +1151,7 @@
       ContainsPaint() != other.ContainsPaint() ||
       IsOverflowVisibleAlongBothAxes() !=
           other.IsOverflowVisibleAlongBothAxes() ||
-      !BackdropFilterDataEquivalent(other) ||
+      BackdropFilter() != other.BackdropFilter() ||
       PotentialCompositingReasonsFor3DTransformChanged(other)) {
     diff.SetCompositingReasonsChanged();
   }
@@ -1414,10 +1413,6 @@
   }
 }
 
-bool ComputedStyle::HasFilters() const {
-  return FilterInternal().Get() && !FilterInternal()->operations_.IsEmpty();
-}
-
 namespace {
 
 gfx::RectF GetReferenceBox(const LayoutBox* box, CoordBox coord_box) {
@@ -2612,7 +2607,8 @@
 }
 
 ComputedStyleBuilder::ComputedStyleBuilder(const ComputedStyle& style) {
-  style_ = base::AdoptRef(new ComputedStyle(style));
+  style_ = MakeGarbageCollected<ComputedStyle>(ComputedStyle::BuilderPassKey(),
+                                               style);
   SetStyleBase(*style_);
 }
 
@@ -2620,8 +2616,9 @@
     const ComputedStyle& initial_style,
     const ComputedStyle& parent_style,
     IsAtShadowBoundary is_at_shadow_boundary) {
-  style_ = base::AdoptRef(new ComputedStyle(initial_style, parent_style,
-                                            GetAccessFlagsForConstructor()));
+  style_ = MakeGarbageCollected<ComputedStyle>(ComputedStyle::BuilderPassKey(),
+                                               initial_style, parent_style,
+                                               GetAccessFlagsForConstructor());
   SetStyleBase(*style_);
 
   // Even if surrounding content is user-editable, shadow DOM should act as a
@@ -2640,10 +2637,11 @@
   SetBaseTextDecorationData(parent_style.AppliedTextDecorationData());
 }
 
-scoped_refptr<const ComputedStyle> ComputedStyleBuilder::CloneStyle() const {
+const ComputedStyle* ComputedStyleBuilder::CloneStyle() const {
   DCHECK(style_);
   ResetAccess();
-  return base::AdoptRef(new ComputedStyle(*style_));
+  return MakeGarbageCollected<ComputedStyle>(ComputedStyle::BuilderPassKey(),
+                                             *style_);
 }
 
 void ComputedStyleBuilder::PropagateIndependentInheritedProperties(
@@ -2686,16 +2684,6 @@
   return true;
 }
 
-StyleHighlightData& ComputedStyleBuilder::MutableHighlightData() {
-  scoped_refptr<StyleHighlightData>& data = MutableHighlightDataInternal();
-  if (!data) {
-    data = StyleHighlightData::Create();
-  } else if (!data->HasOneRef()) {
-    data = data->Copy();
-  }
-  return *data;
-}
-
 // Compute the FontOrientation from this style. It's derived from WritingMode
 // and TextOrientation.
 FontOrientation ComputedStyleBuilder::ComputeFontOrientation() const {
@@ -2832,6 +2820,4 @@
 STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kNone,
                    EOverscrollBehavior::kNone);
 
-CORE_EXPORT ComputedStyle* ComputedStyle::freelist_ = nullptr;
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 79b63df6..58be381 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -55,6 +55,7 @@
 #include "third_party/blink/renderer/core/style/cursor_list.h"
 #include "third_party/blink/renderer/core/style/data_ref.h"
 #include "third_party/blink/renderer/core/style/display_style.h"
+#include "third_party/blink/renderer/core/style/filter_operations.h"
 #include "third_party/blink/renderer/core/style/font_size_style.h"
 #include "third_party/blink/renderer/core/style/style_cached_data.h"
 #include "third_party/blink/renderer/core/style/style_highlight_data.h"
@@ -72,6 +73,7 @@
 #include "third_party/blink/renderer/platform/text/writing_direction_mode.h"
 #include "third_party/blink/renderer/platform/text/writing_mode_utils.h"
 #include "third_party/blink/renderer/platform/transforms/transform_operations.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/leak_annotations.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
@@ -94,7 +96,6 @@
 class FloodColor;
 class CSSTransitionData;
 class CSSVariableData;
-class FilterOperations;
 class Font;
 class Hyphenation;
 class LayoutBox;
@@ -213,8 +214,7 @@
 //
 // Since this class is huge, do not mark all of it CORE_EXPORT.  Instead,
 // export only the methods you need below.
-class ComputedStyle : public ComputedStyleBase,
-                      public RefCounted<ComputedStyle> {
+class ComputedStyle final : public ComputedStyleBase {
   // Needed to allow access to private/protected getters of fields to allow diff
   // generation
   friend class ComputedStyleBase;
@@ -299,7 +299,7 @@
   using ComputedStyleBase::Resize;
 
  protected:
-  mutable std::unique_ptr<StyleCachedData> cached_data_;
+  mutable Member<StyleCachedData> cached_data_;
 
   StyleCachedData& EnsureCachedData() const;
 
@@ -326,36 +326,24 @@
 
  public:
   using PassKey = base::PassKey<ComputedStyle>;
+  using BuilderPassKey = base::PassKey<ComputedStyleBuilder>;
 
-  // See comment on freelist_.
-  void* operator new(size_t size) {
-    DCHECK(IsMainThread());
-    if (freelist_ != nullptr) {
-      ComputedStyle* ret = freelist_;
-      freelist_ = nullptr;
-      return ret;
-    }
-    return ::WTF::Partitions::FastMalloc(size, "ComputedStyle");
-  }
-  void operator delete(void* p) {
-    DCHECK(IsMainThread());
-    if (freelist_ == nullptr) {
-      freelist_ = static_cast<ComputedStyle*>(p);
-    } else {
-      ::WTF::Partitions::FastFree(p);
-    }
-  }
-
-  ALWAYS_INLINE ComputedStyle(PassKey, const ComputedStyle& initial_style);
-  ALWAYS_INLINE ComputedStyle(PassKey,
+  ALWAYS_INLINE ComputedStyle(BuilderPassKey,
+                              const ComputedStyle& initial_style);
+  ALWAYS_INLINE ComputedStyle(BuilderPassKey,
                               const ComputedStyle& initial_style,
                               const ComputedStyle& parent_style,
                               ComputedStyleAccessFlags& access);
   ALWAYS_INLINE explicit ComputedStyle(PassKey);
 
+  void TraceAfterDispatch(Visitor* visitor) const {
+    visitor->Trace(cached_data_);
+    ComputedStyleBase::TraceAfterDispatch(visitor);
+  }
+
   // Create the per-document/context singleton that is used for shallow-copying
   // into new instances.
-  CORE_EXPORT static scoped_refptr<ComputedStyle> CreateInitialStyleSingleton();
+  CORE_EXPORT static const ComputedStyle* CreateInitialStyleSingleton();
 
   static const ComputedStyle* NullifyEnsured(const ComputedStyle* style) {
     if (!style) {
@@ -447,20 +435,18 @@
   CORE_EXPORT const ComputedStyle* GetCachedPseudoElementStyle(
       PseudoId,
       const AtomicString& pseudo_argument = g_null_atom) const;
-  const ComputedStyle* AddCachedPseudoElementStyle(
-      scoped_refptr<const ComputedStyle>,
-      PseudoId,
-      const AtomicString&) const;
+  const ComputedStyle* AddCachedPseudoElementStyle(const ComputedStyle*,
+                                                   PseudoId,
+                                                   const AtomicString&) const;
   const ComputedStyle* ReplaceCachedPseudoElementStyle(
-      scoped_refptr<const ComputedStyle> pseudo_style,
+      const ComputedStyle* pseudo_style,
       PseudoId pseudo_id,
       const AtomicString& pseudo_argument) const;
   void ClearCachedPseudoElementStyles() const;
 
   const ComputedStyle* GetCachedPositionFallbackStyle(unsigned index) const;
-  const ComputedStyle* AddCachedPositionFallbackStyle(
-      scoped_refptr<const ComputedStyle>,
-      unsigned index) const;
+  const ComputedStyle* AddCachedPositionFallbackStyle(const ComputedStyle*,
+                                                      unsigned index) const;
 
   // If this ComputedStyle is affected by animation/transitions, then the
   // unanimated "base" style can be retrieved with this function.
@@ -520,38 +506,17 @@
     return base::ValuesEquivalent(AnchorName(), o.AnchorName());
   }
 
-  const FilterOperations& BackdropFilter() const {
-    DCHECK(BackdropFilterInternal().Get());
-    return BackdropFilterInternal()->operations_;
-  }
   // For containing blocks, use |HasNonInitialBackdropFilter()| which includes
   // will-change: backdrop-filter.
-  static bool HasBackdropFilter(const StyleFilterData* backdrop_filter) {
-    DCHECK(backdrop_filter);
-    return !backdrop_filter->operations_.Operations().empty();
+  static bool HasBackdropFilter(const FilterOperations& backdrop_filter) {
+    return !backdrop_filter.Operations().empty();
   }
-  bool HasBackdropFilter() const {
-    return HasBackdropFilter(BackdropFilterInternal());
-  }
-  bool BackdropFilterDataEquivalent(const ComputedStyle& o) const {
-    return base::ValuesEquivalent(BackdropFilterInternal(),
-                                  o.BackdropFilterInternal());
-  }
+  bool HasBackdropFilter() const { return HasBackdropFilter(BackdropFilter()); }
 
   // filter (aka -webkit-filter)
-  const FilterOperations& Filter() const {
-    DCHECK(FilterInternal().Get());
-    return FilterInternal()->operations_;
-  }
   // For containing blocks, use |HasNonInitialFilter()| which includes
   // will-change: filter.
-  bool HasFilter() const {
-    DCHECK(FilterInternal().Get());
-    return !FilterInternal()->operations_.Operations().empty();
-  }
-  bool FilterDataEquivalent(const ComputedStyle& o) const {
-    return base::ValuesEquivalent(FilterInternal(), o.FilterInternal());
-  }
+  bool HasFilter() const { return !Filter().Operations().empty(); }
 
   // background-image
   bool HasBackgroundImage() const {
@@ -2158,8 +2123,6 @@
                       ApplyMotionPath,
                       ApplyIndependentTransformProperties) const;
 
-  bool HasFilters() const;
-
   // Returns |true| if any property that renders using filter operations is
   // used (including, but not limited to, 'filter' and 'box-reflect').
   bool HasFilterInducingProperty() const {
@@ -2767,16 +2730,6 @@
   // Derived flags:
   bool CalculateIsStackingContextWithoutContainment() const;
 
-  // A one-element freelist that we can use to get fewer calls to new/delete
-  // when recalculating style; the new and delete calls usually come in
-  // exact pairs, so barring DCHECK verification, a single-element list
-  // is usually sufficient to get rid of nearly all such calls, and we don't
-  // need anything longer or more complex. (We still run the constructors and
-  // destructors, though; it's only the memory that is reused, not the object.)
-  //
-  // Subobjects in generated code use exactly the same pattern (see group.tmpl).
-  CORE_EXPORT static ComputedStyle* freelist_;
-
   FRIEND_TEST_ALL_PREFIXES(
       ComputedStyleTest,
       UpdatePropertySpecificDifferencesRespectsTransformAnimation);
@@ -2896,10 +2849,10 @@
   ComputedStyleBuilder& operator=(const ComputedStyleBuilder&) = delete;
   ComputedStyleBuilder& operator=(ComputedStyleBuilder&&) = default;
 
-  scoped_refptr<const ComputedStyle> TakeStyle() { return std::move(style_); }
+  const ComputedStyle* TakeStyle() { return std::move(style_); }
 
   // NOTE: Prefer `TakeStyle()` if possible.
-  CORE_EXPORT scoped_refptr<const ComputedStyle> CloneStyle() const;
+  CORE_EXPORT const ComputedStyle* CloneStyle() const;
 
   // Copies the values of any independent inherited properties from the parent
   // that are not explicitly set in this style.
@@ -2930,18 +2883,11 @@
   }
 
   // backdrop-filter
-  FilterOperations& MutableBackdropFilter() {
-    DCHECK(BackdropFilterInternal().Get());
-    return MutableBackdropFilterInternal()->operations_;
-  }
-  void SetBackdropFilter(const FilterOperations& ops) {
-    DCHECK(BackdropFilterInternal().Get());
-    if (BackdropFilterInternal()->operations_ != ops) {
-      MutableBackdropFilterInternal()->operations_ = ops;
-    }
+  FilterOperations::FilterOperationVector& MutableBackdropFilterOperations() {
+    return MutableBackdropFilterInternal().Operations();
   }
   bool HasBackdropFilter() const {
-    return ComputedStyle::HasBackdropFilter(BackdropFilterInternal());
+    return ComputedStyle::HasBackdropFilter(BackdropFilter());
   }
 
   // background
@@ -3138,15 +3084,8 @@
   }
 
   // filter
-  FilterOperations& MutableFilter() {
-    DCHECK(FilterInternal().Get());
-    return MutableFilterInternal()->operations_;
-  }
-  void SetFilter(const FilterOperations& v) {
-    DCHECK(FilterInternal().Get());
-    if (FilterInternal()->operations_ != v) {
-      MutableFilterInternal()->operations_ = v;
-    }
+  FilterOperations::FilterOperationVector& MutableFilterOperations() {
+    return MutableFilterInternal().Operations();
   }
 
   // float
@@ -3422,7 +3361,7 @@
 
   // BaseData
   const ComputedStyle* GetBaseComputedStyle() const {
-    if (auto* base_data = BaseData().get()) {
+    if (auto* base_data = BaseData().Get()) {
       return base_data->GetBaseComputedStyle();
     }
     return nullptr;
@@ -3445,7 +3384,9 @@
   }
 
   // ::selection, etc
-  StyleHighlightData& MutableHighlightData();
+  StyleHighlightData& AccessHighlightData() {
+    return MutableHighlightDataInternal();
+  }
 
   // CustomHighlightNames
   void SetCustomHighlightNames(
@@ -3561,7 +3502,7 @@
   }
 
  private:
-  scoped_refptr<ComputedStyle> style_;
+  ComputedStyle* style_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5 b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
index 5870aec..17061e0b 100644
--- a/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
+++ b/third_party/blink/renderer/core/style/computed_style_diff_functions.json5
@@ -402,15 +402,12 @@
     },
     {
         name: "UpdatePropertySpecificDifferencesFilter",
+        fields_to_diff: ["filter"],
         predicates_to_test: [
           {
             predicate: "a.ReflectionDataEquivalent(b)",
             field_dependencies: ["-webkit-box-reflect"]
           },
-          {
-            predicate: "a.FilterDataEquivalent(b)",
-            field_dependencies: ["filter"]
-          },
         ]
     },
     {
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index 8b246c3..4b69237 100644
--- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -327,7 +327,7 @@
       type_name: "FillLayer",
       default_value: "FillLayer(EFillLayerType::kBackground, true)",
       field_group: "background",
-      computed_style_custom_functions: ["getter", "setter"],
+      computed_style_custom_functions: ["initial", "getter", "setter"],
     },
     {
       name: "HasClipPath",
@@ -377,7 +377,7 @@
       type_name: "CursorList",
       include_paths: ["third_party/blink/renderer/core/style/cursor_list.h"],
       default_value: "nullptr",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       field_group: "*",
       computed_style_custom_functions: ["getter", "setter"],
     },
@@ -481,9 +481,8 @@
       field_template: "external",
       type_name: "StyleHighlightData",
       include_paths: ["third_party/blink/renderer/core/style/style_highlight_data.h"],
-      default_value: "nullptr",
-      wrapper_pointer_name: "scoped_refptr",
-      field_group: "*",
+      default_value: "StyleHighlightData()",
+      field_group: "*->highlight-data",
       computed_style_custom_functions: [],
     },
     {
@@ -503,7 +502,7 @@
       type_name: "FillLayer",
       field_group: "*",
       default_value: "FillLayer(EFillLayerType::kMask, true)",
-      computed_style_custom_functions: ["getter", "setter"],
+      computed_style_custom_functions: ["initial", "getter", "setter"],
     },
     {
       name: "CounterDirectives",
@@ -573,7 +572,7 @@
       name: "DocumentRulesSelectors",
       field_template: "external",
       type_name: "HeapHashSet<WeakMember<StyleRule>>",
-      wrapper_pointer_name: "Persistent",
+      wrapper_pointer_name: "Member",
       field_group: "*",
       default_value: "nullptr",
       include_paths: ["third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h",
@@ -1129,7 +1128,7 @@
       type_name: "StyleBaseData",
       include_paths: ["third_party/blink/renderer/core/style/style_base_data.h"],
       default_value: "nullptr",
-      wrapper_pointer_name: "scoped_refptr",
+      wrapper_pointer_name: "Member",
       custom_compare: true,
       reset_on_new_style: true,
     },
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc
index 5757f3b..7d4c552 100644
--- a/third_party/blink/renderer/core/style/computed_style_test.cc
+++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -52,9 +52,7 @@
     initial_style_ = ComputedStyle::CreateInitialStyleSingleton();
   }
 
-  scoped_refptr<const ComputedStyle> InitialComputedStyle() {
-    return initial_style_;
-  }
+  const ComputedStyle* InitialComputedStyle() { return initial_style_; }
 
   ComputedStyleBuilder CreateComputedStyleBuilder() {
     return ComputedStyleBuilder(*initial_style_);
@@ -66,7 +64,7 @@
   }
 
  private:
-  scoped_refptr<const ComputedStyle> initial_style_;
+  Persistent<const ComputedStyle> initial_style_;
 };
 
 TEST_F(ComputedStyleTest, ShapeOutsideBoxEqual) {
@@ -109,7 +107,7 @@
 TEST_F(ComputedStyleTest, ForcesStackingContext) {
   ComputedStyleBuilder builder = CreateComputedStyleBuilder();
   builder.SetForcesStackingContext(true);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   EXPECT_TRUE(style->IsStackingContextWithoutContainment());
 }
 
@@ -118,13 +116,13 @@
   builder.SetTransformStyle3D(ETransformStyle3D::kPreserve3d);
   builder.SetOverflowX(EOverflow::kHidden);
   builder.SetOverflowY(EOverflow::kHidden);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   EXPECT_EQ(ETransformStyle3D::kFlat, style->UsedTransformStyle3D());
   EXPECT_TRUE(style->IsStackingContextWithoutContainment());
 }
 
 TEST_F(ComputedStyleTest, LayoutContainmentStackingContext) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   EXPECT_FALSE(style->IsStackingContextWithoutContainment());
 
   ComputedStyleBuilder builder(*style);
@@ -137,18 +135,18 @@
 TEST_F(ComputedStyleTest, IsStackingContextWithoutContainmentAfterClone) {
   ComputedStyleBuilder builder1 = CreateComputedStyleBuilder();
   builder1.SetForcesStackingContext(true);
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
   EXPECT_TRUE(style1->IsStackingContextWithoutContainment());
 
   ComputedStyleBuilder builder2(*style1);
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
   EXPECT_TRUE(style2->IsStackingContextWithoutContainment());
 
   // Verify that the cached value for IsStackingContextWithoutContainment
   // isn't copied from `style1`.
   ComputedStyleBuilder builder3(*style1);
   builder3.SetForcesStackingContext(false);
-  scoped_refptr<const ComputedStyle> style3 = builder3.TakeStyle();
+  const ComputedStyle* style3 = builder3.TakeStyle();
   EXPECT_FALSE(style3->IsStackingContextWithoutContainment());
 }
 
@@ -156,13 +154,13 @@
   {
     ComputedStyleBuilder builder1 = CreateComputedStyleBuilder();
     builder1.SetForcesStackingContext(true);
-    scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
+    const ComputedStyle* style1 = builder1.TakeStyle();
     EXPECT_TRUE(style1->IsStackingContextWithoutContainment());
 
     // Whether the style is a stacking context or not should not be copied
     // from the style we're cloning.
     ComputedStyleBuilder builder2 = CreateComputedStyleBuilderFrom(*style1);
-    scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+    const ComputedStyle* style2 = builder2.TakeStyle();
     EXPECT_TRUE(style2->IsStackingContextWithoutContainment());
   }
 
@@ -170,11 +168,11 @@
   // expected to be false.
   {
     ComputedStyleBuilder builder1 = CreateComputedStyleBuilder();
-    scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
+    const ComputedStyle* style1 = builder1.TakeStyle();
     EXPECT_FALSE(style1->IsStackingContextWithoutContainment());
 
     ComputedStyleBuilder builder2 = CreateComputedStyleBuilderFrom(*style1);
-    scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+    const ComputedStyle* style2 = builder2.TakeStyle();
     EXPECT_FALSE(style2->IsStackingContextWithoutContainment());
   }
 
@@ -183,12 +181,12 @@
   {
     ComputedStyleBuilder builder1 = CreateComputedStyleBuilder();
     builder1.SetForcesStackingContext(true);
-    scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
+    const ComputedStyle* style1 = builder1.TakeStyle();
     EXPECT_TRUE(style1->IsStackingContextWithoutContainment());
 
     ComputedStyleBuilder builder2 = CreateComputedStyleBuilderFrom(*style1);
     builder2.SetForcesStackingContext(false);
-    scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+    const ComputedStyle* style2 = builder2.TakeStyle();
     // Value copied from 'style1' must not persist.
     EXPECT_FALSE(style2->IsStackingContextWithoutContainment());
   }
@@ -203,7 +201,7 @@
 
     ComputedStyleBuilder builder = CreateComputedStyleBuilder();
     builder.SetPseudoElementStyles(match_result.PseudoElementStyles());
-    scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+    const ComputedStyle* style = builder.TakeStyle();
 
     EXPECT_TRUE(style->HasPseudoElementStyle(pseudo_id));
     EXPECT_TRUE(style->HasAnyPseudoElementStyles());
@@ -212,10 +210,10 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesRespectsTransformAnimation) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetHasCurrentTransformAnimation(true);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -232,11 +230,11 @@
 
   ComputedStyleBuilder builder = CreateComputedStyleBuilder();
   builder.SetTransform(operations);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   builder = ComputedStyleBuilder(*style);
   builder.SetHasCurrentTransformAnimation(true);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -246,10 +244,10 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesRespectsScaleAnimation) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetHasCurrentScaleAnimation(true);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -258,10 +256,10 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesRespectsRotateAnimation) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetHasCurrentRotateAnimation(true);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -270,10 +268,10 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesRespectsTranslateAnimation) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetHasCurrentTranslateAnimation(true);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -282,10 +280,10 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesCompositingReasonsOpacity) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetHasCurrentOpacityAnimation(true);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -294,10 +292,10 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesCompositingReasonsFilter) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetHasCurrentFilterAnimation(true);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -306,10 +304,10 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesCompositingReasonsBackdropFilter) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetHasCurrentBackdropFilterAnimation(true);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -318,10 +316,10 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesCompositingReasonsBackfaceVisibility) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetBackfaceVisibility(EBackfaceVisibility::kHidden);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -330,11 +328,11 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesCompositingReasonsWillChange) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetBackfaceVisibility(EBackfaceVisibility::kHidden);
   builder.SetWillChangeProperties({CSSPropertyID::kOpacity});
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -345,12 +343,12 @@
        UpdatePropertySpecificDifferencesCompositingReasonsUsedStylePreserve3D) {
   ComputedStyleBuilder builder = CreateComputedStyleBuilder();
   builder.SetTransformStyle3D(ETransformStyle3D::kPreserve3d);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   builder = ComputedStyleBuilder(*style);
   // This induces a flat used transform style.
   builder.SetOpacity(0.5);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -359,10 +357,10 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesCompositingReasonsOverflow) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   builder.SetOverflowX(EOverflow::kHidden);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -371,11 +369,11 @@
 
 TEST_F(ComputedStyleTest,
        UpdatePropertySpecificDifferencesCompositingReasonsContainsPaint) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   ComputedStyleBuilder builder(*style);
   // This induces a flat used transform style.
   builder.SetContain(kContainsPaint);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
 
   StyleDifference diff;
   style->UpdatePropertySpecificDifferences(*other, diff);
@@ -384,7 +382,7 @@
 
 TEST_F(ComputedStyleTest, HasOutlineWithCurrentColor) {
   ComputedStyleBuilder builder = CreateComputedStyleBuilder();
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   EXPECT_FALSE(style->HasOutline());
   EXPECT_FALSE(style->HasOutlineWithCurrentColor());
 
@@ -405,7 +403,7 @@
 TEST_F(ComputedStyleTest, BorderWidth) {
   ComputedStyleBuilder builder = CreateComputedStyleBuilder();
   builder.SetBorderBottomWidth(LayoutUnit(5));
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   EXPECT_EQ(style->BorderBottomWidth(), 0);
   EXPECT_EQ(style->BorderBottom().Width(), 5);
 
@@ -429,11 +427,11 @@
 
   ComputedStyleBuilder builder = CreateComputedStyleBuilder();
   builder.AddCursor(image_value, false);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   builder = CreateComputedStyleBuilder();
   builder.AddCursor(other_image_value, false);
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* other = builder.TakeStyle();
   EXPECT_EQ(*style, *other);
 }
 
@@ -450,8 +448,8 @@
   builder.SetBorderTopStyle(EBorderStyle::kSolid);
   builder.SetBorderRightStyle(EBorderStyle::kSolid);
   builder.SetBorderBottomStyle(EBorderStyle::kSolid);
-  scoped_refptr<const ComputedStyle> style = builder.CloneStyle();
-  scoped_refptr<const ComputedStyle> other = builder.TakeStyle();
+  const ComputedStyle* style = builder.CloneStyle();
+  const ComputedStyle* other = builder.TakeStyle();
   EXPECT_TRUE(style->BorderSizeEquals(*other));
 
   UPDATE_STYLE(style, SetBorderLeftWidth, LayoutUnit(1));
@@ -541,34 +539,34 @@
   EXPECT_FALSE(style->HasBorder());
 }
 
-#define TEST_ANIMATION_FLAG(flag, inherited)                               \
-  do {                                                                     \
-    auto builder = CreateComputedStyleBuilder();                           \
-    builder.Set##flag(true);                                               \
-    auto style = builder.TakeStyle();                                      \
-    EXPECT_TRUE(style->flag());                                            \
-    auto other = InitialComputedStyle();                                   \
-    EXPECT_FALSE(other->flag());                                           \
-    EXPECT_EQ(ComputedStyle::Difference::inherited,                        \
-              ComputedStyle::ComputeDifference(style.get(), other.get())); \
-    auto diff = style->VisualInvalidationDiff(*document, *other);          \
-    EXPECT_TRUE(diff.HasDifference());                                     \
-    EXPECT_TRUE(diff.CompositingReasonsChanged());                         \
+#define TEST_ANIMATION_FLAG(flag, inherited)                      \
+  do {                                                            \
+    auto builder = CreateComputedStyleBuilder();                  \
+    builder.Set##flag(true);                                      \
+    const auto* style = builder.TakeStyle();                      \
+    EXPECT_TRUE(style->flag());                                   \
+    const auto* other = InitialComputedStyle();                   \
+    EXPECT_FALSE(other->flag());                                  \
+    EXPECT_EQ(ComputedStyle::Difference::inherited,               \
+              ComputedStyle::ComputeDifference(style, other));    \
+    auto diff = style->VisualInvalidationDiff(*document, *other); \
+    EXPECT_TRUE(diff.HasDifference());                            \
+    EXPECT_TRUE(diff.CompositingReasonsChanged());                \
   } while (false)
 
-#define TEST_ANIMATION_FLAG_NO_DIFF(flag)                                  \
-  do {                                                                     \
-    auto builder = CreateComputedStyleBuilder();                           \
-    builder.Set##flag(true);                                               \
-    auto style = builder.TakeStyle();                                      \
-    EXPECT_TRUE(style->flag());                                            \
-    auto other = InitialComputedStyle();                                   \
-    EXPECT_FALSE(other->flag());                                           \
-    EXPECT_EQ(ComputedStyle::Difference::kEqual,                           \
-              ComputedStyle::ComputeDifference(style.get(), other.get())); \
-    auto diff = style->VisualInvalidationDiff(*document, *other);          \
-    EXPECT_FALSE(diff.HasDifference());                                    \
-    EXPECT_FALSE(diff.CompositingReasonsChanged());                        \
+#define TEST_ANIMATION_FLAG_NO_DIFF(flag)                         \
+  do {                                                            \
+    auto builder = CreateComputedStyleBuilder();                  \
+    builder.Set##flag(true);                                      \
+    const auto* style = builder.TakeStyle();                      \
+    EXPECT_TRUE(style->flag());                                   \
+    const auto* other = InitialComputedStyle();                   \
+    EXPECT_FALSE(other->flag());                                  \
+    EXPECT_EQ(ComputedStyle::Difference::kEqual,                  \
+              ComputedStyle::ComputeDifference(style, other));    \
+    auto diff = style->VisualInvalidationDiff(*document, *other); \
+    EXPECT_FALSE(diff.HasDifference());                           \
+    EXPECT_FALSE(diff.CompositingReasonsChanged());               \
   } while (false)
 
 TEST_F(ComputedStyleTest, AnimationFlags) {
@@ -597,9 +595,6 @@
   css_test_helpers::RegisterProperty(dummy->GetDocument(), "--x", "<length>",
                                      "0px", false);
 
-  scoped_refptr<const ComputedStyle> style1;
-  scoped_refptr<const ComputedStyle> style2;
-
   using UnitType = CSSPrimitiveValue::UnitType;
 
   const auto* value1 = CSSNumericLiteralValue::Create(1.0, UnitType::kPixels);
@@ -611,11 +606,11 @@
 
   ComputedStyleBuilder builder = CreateComputedStyleBuilder();
   builder.SetVariableValue(AtomicString("--x"), value1, false);
-  style1 = builder.TakeStyle();
+  const ComputedStyle* style1 = builder.TakeStyle();
 
   builder = CreateComputedStyleBuilder();
   builder.SetVariableValue(AtomicString("--x"), value1, false);
-  style2 = builder.TakeStyle();
+  const ComputedStyle* style2 = builder.TakeStyle();
   EXPECT_TRUE(style1->CustomPropertiesEqual(properties, *style2));
 
   builder = CreateComputedStyleBuilder();
@@ -634,8 +629,8 @@
   css_test_helpers::RegisterProperty(dummy->GetDocument(), "--x", "<length>",
                                      "0px", false);
 
-  scoped_refptr<const ComputedStyle> style1;
-  scoped_refptr<const ComputedStyle> style2;
+  const ComputedStyle* style1;
+  const ComputedStyle* style2;
 
   auto value1 = css_test_helpers::CreateVariableData("foo");
   auto value2 = css_test_helpers::CreateVariableData("bar");
@@ -677,8 +672,8 @@
   const auto* value1 = CSSNumericLiteralValue::Create(1.0, UnitType::kPixels);
   const auto* value2 = CSSNumericLiteralValue::Create(2.0, UnitType::kPixels);
 
-  scoped_refptr<const ComputedStyle> old_style = old_builder.TakeStyle();
-  scoped_refptr<const ComputedStyle> new_style = new_builder.TakeStyle();
+  const ComputedStyle* old_style = old_builder.TakeStyle();
+  const ComputedStyle* new_style = new_builder.TakeStyle();
   EXPECT_FALSE(old_style->HasVariableDeclaration());
   EXPECT_FALSE(old_style->HasVariableReference());
   EXPECT_FALSE(new_style->HasVariableReference());
@@ -689,7 +684,7 @@
   old_builder.SetVariableValue(AtomicString("--x"), value1, true);
   old_style = old_builder.TakeStyle();
   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
-            ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
+            ComputedStyle::ComputeDifference(old_style, new_style));
 
   old_builder = CreateComputedStyleBuilder();
   new_builder = CreateComputedStyleBuilder();
@@ -699,7 +694,7 @@
   old_style = old_builder.TakeStyle();
   new_style = new_builder.TakeStyle();
   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
-            ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
+            ComputedStyle::ComputeDifference(old_style, new_style));
 
   // Change value of variable
   old_builder = CreateComputedStyleBuilder();
@@ -712,7 +707,7 @@
   EXPECT_FALSE(new_style->HasVariableDeclaration());
   EXPECT_TRUE(new_style->HasVariableReference());
   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
-            ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
+            ComputedStyle::ComputeDifference(old_style, new_style));
 
   old_builder = CreateComputedStyleBuilder();
   new_builder = CreateComputedStyleBuilder();
@@ -726,7 +721,7 @@
   EXPECT_TRUE(new_style->HasVariableDeclaration());
   EXPECT_FALSE(new_style->HasVariableReference());
   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
-            ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
+            ComputedStyle::ComputeDifference(old_style, new_style));
 
   old_builder = CreateComputedStyleBuilder();
   new_builder = CreateComputedStyleBuilder();
@@ -741,7 +736,7 @@
   EXPECT_TRUE(new_style->HasVariableDeclaration());
   EXPECT_TRUE(new_style->HasVariableReference());
   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
-            ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
+            ComputedStyle::ComputeDifference(old_style, new_style));
 }
 
 TEST_F(ComputedStyleTest, CustomPropertiesInheritance_StyleRecalc) {
@@ -757,8 +752,8 @@
   const auto* value1 = CSSNumericLiteralValue::Create(1.0, UnitType::kPixels);
   const auto* value2 = CSSNumericLiteralValue::Create(2.0, UnitType::kPixels);
 
-  scoped_refptr<const ComputedStyle> old_style = old_builder.TakeStyle();
-  scoped_refptr<const ComputedStyle> new_style = new_builder.TakeStyle();
+  const ComputedStyle* old_style = old_builder.TakeStyle();
+  const ComputedStyle* new_style = new_builder.TakeStyle();
   EXPECT_FALSE(old_style->HasVariableDeclaration());
   EXPECT_FALSE(old_style->HasVariableReference());
   EXPECT_FALSE(new_style->HasVariableReference());
@@ -772,7 +767,7 @@
   old_style = old_builder.TakeStyle();
   EXPECT_TRUE(old_style->HasVariableReference());
   EXPECT_EQ(ComputedStyle::Difference::kInherited,
-            ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
+            ComputedStyle::ComputeDifference(old_style, new_style));
 
   old_builder = CreateComputedStyleBuilder();
   new_builder = CreateComputedStyleBuilder();
@@ -785,7 +780,7 @@
   new_style = new_builder.TakeStyle();
   EXPECT_TRUE(old_style->HasVariableDeclaration());
   EXPECT_EQ(ComputedStyle::Difference::kInherited,
-            ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
+            ComputedStyle::ComputeDifference(old_style, new_style));
 
   old_builder = CreateComputedStyleBuilder();
   new_builder = CreateComputedStyleBuilder();
@@ -799,7 +794,7 @@
   new_style = new_builder.TakeStyle();
   EXPECT_TRUE(old_style->HasVariableDeclaration());
   EXPECT_EQ(ComputedStyle::Difference::kInherited,
-            ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
+            ComputedStyle::ComputeDifference(old_style, new_style));
 
   old_builder = CreateComputedStyleBuilder();
   new_builder = CreateComputedStyleBuilder();
@@ -813,14 +808,14 @@
   new_style = new_builder.TakeStyle();
   EXPECT_TRUE(old_style->HasVariableReference());
   EXPECT_EQ(ComputedStyle::Difference::kInherited,
-            ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
+            ComputedStyle::ComputeDifference(old_style, new_style));
 }
 
 TEST_F(ComputedStyleTest, ApplyColorSchemeLightOnDark) {
   std::unique_ptr<DummyPageHolder> dummy_page_holder =
       std::make_unique<DummyPageHolder>(gfx::Size(0, 0), nullptr);
   Document& document = dummy_page_holder->GetDocument();
-  scoped_refptr<const ComputedStyle> initial =
+  const ComputedStyle* initial =
       document.GetStyleResolver().InitialStyleForElement();
 
   ColorSchemeHelper color_scheme_helper(document);
@@ -828,7 +823,7 @@
       mojom::blink::PreferredColorScheme::kDark);
   StyleResolverState state(document, *document.documentElement(),
                            nullptr /* StyleRecalcContext */,
-                           StyleRequest(initial.get()));
+                           StyleRequest(initial));
 
   state.SetStyle(*initial);
 
@@ -857,7 +852,7 @@
   std::unique_ptr<DummyPageHolder> dummy_page_holder =
       std::make_unique<DummyPageHolder>(gfx::Size(0, 0), nullptr);
   Document& document = dummy_page_holder->GetDocument();
-  scoped_refptr<const ComputedStyle> initial =
+  const ComputedStyle* initial =
       document.GetStyleResolver().InitialStyleForElement();
 
   ColorSchemeHelper color_scheme_helper(document);
@@ -865,7 +860,7 @@
       mojom::blink::PreferredColorScheme::kDark);
   StyleResolverState state(document, *document.documentElement(),
                            nullptr /* StyleRecalcContext */,
-                           StyleRequest(initial.get()));
+                           StyleRequest(initial));
 
   state.SetStyle(*initial);
 
@@ -886,7 +881,7 @@
   cascade1.MutableMatchResult().AddMatchedProperties(dark_declaration,
                                                      CascadeOrigin::kNone);
   cascade1.Apply();
-  scoped_refptr<const ComputedStyle> style = state.StyleBuilder().CloneStyle();
+  const ComputedStyle* style = state.StyleBuilder().CloneStyle();
   EXPECT_EQ(Color::kWhite, style->VisitedDependentColor(GetCSSPropertyColor()));
 
   StyleCascade cascade2(state);
@@ -905,7 +900,7 @@
   std::unique_ptr<DummyPageHolder> dummy_page_holder =
       std::make_unique<DummyPageHolder>(gfx::Size(0, 0), nullptr);
   Document& document = dummy_page_holder->GetDocument();
-  scoped_refptr<const ComputedStyle> initial =
+  const ComputedStyle* initial =
       document.GetStyleResolver().InitialStyleForElement();
 
   ColorSchemeHelper color_scheme_helper(document);
@@ -913,7 +908,7 @@
       mojom::blink::PreferredColorScheme::kDark);
   StyleResolverState state(document, *document.documentElement(),
                            nullptr /* StyleRecalcContext */,
-                           StyleRequest(initial.get()));
+                           StyleRequest(initial));
 
   state.SetStyle(*initial);
 
@@ -946,12 +941,12 @@
   std::unique_ptr<DummyPageHolder> dummy_page_holder =
       std::make_unique<DummyPageHolder>(gfx::Size(0, 0), nullptr);
   Document& document = dummy_page_holder->GetDocument();
-  scoped_refptr<const ComputedStyle> initial =
+  const ComputedStyle* initial =
       document.GetStyleResolver().InitialStyleForElement();
 
   StyleResolverState state(document, *document.documentElement(),
                            nullptr /* StyleRecalcContext */,
-                           StyleRequest(initial.get()));
+                           StyleRequest(initial));
 
   state.SetStyle(*initial);
   state.StyleBuilder().SetEffectiveZoom(1.5);
@@ -962,7 +957,7 @@
 
   To<Longhand>(GetCSSPropertyStrokeWidth())
       .ApplyValue(state, *calc_value, CSSProperty::ValueMode::kNormal);
-  scoped_refptr<const ComputedStyle> style = state.TakeStyle();
+  const ComputedStyle* style = state.TakeStyle();
   auto* computed_value = To<Longhand>(GetCSSPropertyStrokeWidth())
                              .CSSValueFromComputedStyleInternal(
                                  *style, nullptr /* layout_object */,
@@ -972,7 +967,7 @@
 }
 
 TEST_F(ComputedStyleTest, InitialVariableNamesEmpty) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   EXPECT_TRUE(style->GetVariableNames().empty());
 }
 
@@ -990,7 +985,7 @@
   builder.SetInitialData(StyleInitialData::Create(
       *Document::CreateForTest(execution_context.GetExecutionContext()),
       *registry));
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   EXPECT_EQ(2u, style->GetVariableNames().size());
   EXPECT_TRUE(style->GetVariableNames().Contains("--x"));
@@ -1006,7 +1001,7 @@
                           inherited);
   builder.SetVariableData(AtomicString("--b"), CreateVariableData("bar"),
                           inherited);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   EXPECT_EQ(2u, style->GetVariableNames().size());
   EXPECT_TRUE(style->GetVariableNames().Contains("--a"));
@@ -1022,7 +1017,7 @@
                           !inherited);
   builder.SetVariableData(AtomicString("--b"), CreateVariableData("bar"),
                           !inherited);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   EXPECT_EQ(2u, style->GetVariableNames().size());
   EXPECT_TRUE(style->GetVariableNames().Contains("--a"));
@@ -1042,7 +1037,7 @@
                           !inherited);
   builder.SetVariableData(AtomicString("--c"), CreateVariableData("baz"),
                           !inherited);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   EXPECT_EQ(4u, style->GetVariableNames().size());
   EXPECT_TRUE(style->GetVariableNames().Contains("--a"));
@@ -1076,7 +1071,7 @@
                           !inherited);
   builder.SetVariableData(AtomicString("--c"), CreateVariableData("baz"),
                           !inherited);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   EXPECT_EQ(5u, style->GetVariableNames().size());
   EXPECT_TRUE(style->GetVariableNames().Contains("--a"));
@@ -1087,7 +1082,7 @@
 }
 
 TEST_F(ComputedStyleTest, GetVariableNamesCount_Invalidation) {
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
+  const ComputedStyle* style = InitialComputedStyle();
   EXPECT_EQ(style->GetVariableNamesCount(), 0u);
 
   auto data = css_test_helpers::CreateVariableData("foo");
@@ -1108,7 +1103,7 @@
 }
 
 TEST_F(ComputedStyleTest, GetVariableNames_Invalidation) {
-  scoped_refptr<const ComputedStyle> style;
+  const ComputedStyle* style;
 
   auto data = css_test_helpers::CreateVariableData("foo");
   ComputedStyleBuilder builder = CreateComputedStyleBuilder();
@@ -1136,7 +1131,7 @@
 TEST_F(ComputedStyleTest, GetVariableNamesWithInitialData_Invalidation) {
   using css_test_helpers::CreateLengthRegistration;
 
-  scoped_refptr<const ComputedStyle> style;
+  const ComputedStyle* style;
 
   ScopedNullExecutionContext execution_context;
   {
@@ -1487,7 +1482,7 @@
   auto& animations = builder.AccessAnimations();
   animations.DelayStartList().clear();
   animations.DelayStartList().push_back(CSSAnimationData::InitialDelayStart());
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   EXPECT_EQ(1u, style->Animations()->DelayStartList().size());
 
   builder = ComputedStyleBuilder(*style);
@@ -1495,7 +1490,7 @@
   EXPECT_EQ(1u, cloned_style_animations.DelayStartList().size());
   cloned_style_animations.DelayStartList().push_back(
       CSSAnimationData::InitialDelayStart());
-  scoped_refptr<const ComputedStyle> cloned_style = builder.TakeStyle();
+  const ComputedStyle* cloned_style = builder.TakeStyle();
 
   EXPECT_EQ(2u, cloned_style->Animations()->DelayStartList().size());
   EXPECT_EQ(1u, style->Animations()->DelayStartList().size());
@@ -1507,7 +1502,7 @@
   auto& transitions = builder.AccessTransitions();
   transitions.PropertyList().clear();
   transitions.PropertyList().push_back(CSSTransitionData::InitialProperty());
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   EXPECT_EQ(1u, style->Transitions()->PropertyList().size());
 
   builder = ComputedStyleBuilder(*style);
@@ -1515,7 +1510,7 @@
   EXPECT_EQ(1u, cloned_style_transitions.PropertyList().size());
   cloned_style_transitions.PropertyList().push_back(
       CSSTransitionData::InitialProperty());
-  scoped_refptr<const ComputedStyle> cloned_style = builder.TakeStyle();
+  const ComputedStyle* cloned_style = builder.TakeStyle();
 
   EXPECT_EQ(2u, cloned_style->Transitions()->PropertyList().size());
   EXPECT_EQ(1u, style->Transitions()->PropertyList().size());
@@ -1525,14 +1520,13 @@
   std::unique_ptr<DummyPageHolder> dummy_page_holder =
       std::make_unique<DummyPageHolder>(gfx::Size(0, 0), nullptr);
   Document& document = dummy_page_holder->GetDocument();
-  scoped_refptr<const ComputedStyle> initial =
+  const ComputedStyle* initial =
       document.GetStyleResolver().InitialStyleForElement();
 
   StyleResolverState state(document, *document.documentElement(),
                            nullptr /* StyleRecalcContext */,
-                           StyleRequest(initial.get()));
+                           StyleRequest(initial));
 
-  scoped_refptr<const ComputedStyle> style = InitialComputedStyle();
   state.SetStyle(*initial);
   EXPECT_FALSE(state.StyleBuilder().Animations());
   EXPECT_FALSE(state.StyleBuilder().Transitions());
@@ -1543,18 +1537,18 @@
   EXPECT_FALSE(state.StyleBuilder().Transitions());
 }
 
-#define TEST_STYLE_VALUE_NO_DIFF(field_name)                          \
-  {                                                                   \
-    ComputedStyleBuilder builder1 = CreateComputedStyleBuilder();     \
-    ComputedStyleBuilder builder2 = CreateComputedStyleBuilder();     \
-    builder1.Set##field_name(                                         \
-        ComputedStyleInitialValues::Initial##field_name());           \
-    builder2.Set##field_name(                                         \
-        ComputedStyleInitialValues::Initial##field_name());           \
-    scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle(); \
-    scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle(); \
-    auto diff = style1->VisualInvalidationDiff(*document, *style2);   \
-    EXPECT_FALSE(diff.HasDifference());                               \
+#define TEST_STYLE_VALUE_NO_DIFF(field_name)                        \
+  {                                                                 \
+    ComputedStyleBuilder builder1 = CreateComputedStyleBuilder();   \
+    ComputedStyleBuilder builder2 = CreateComputedStyleBuilder();   \
+    builder1.Set##field_name(                                       \
+        ComputedStyleInitialValues::Initial##field_name());         \
+    builder2.Set##field_name(                                       \
+        ComputedStyleInitialValues::Initial##field_name());         \
+    const ComputedStyle* style1 = builder1.TakeStyle();             \
+    const ComputedStyle* style2 = builder2.TakeStyle();             \
+    auto diff = style1->VisualInvalidationDiff(*document, *style2); \
+    EXPECT_FALSE(diff.HasDifference());                             \
   }
 
 // Ensures ref-counted values are compared by their values, not by pointers.
@@ -1566,8 +1560,8 @@
     scoped_refptr<type> value2 = base::MakeRefCounted<type>(value1->data); \
     builder1.Set##field_name(value1);                                      \
     builder2.Set##field_name(value2);                                      \
-    scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();      \
-    scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();      \
+    const ComputedStyle* style1 = builder1.TakeStyle();                    \
+    const ComputedStyle* style2 = builder2.TakeStyle();                    \
     auto diff = style1->VisualInvalidationDiff(*document, *style2);        \
     EXPECT_FALSE(diff.HasDifference());                                    \
   }
@@ -1681,8 +1675,8 @@
   builder1.SetWidth(Length(100.0, Length::kFixed));
   builder2.SetWidth(Length(200.0, Length::kFixed));
 
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
 
   EXPECT_EQ(0u, style1->DebugDiffFields(*style1).size());
   EXPECT_EQ(0u, style2->DebugDiffFields(*style2).size());
@@ -1708,8 +1702,8 @@
 
   builder1.SetForcesStackingContext(true);
 
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
 
   ASSERT_EQ(2u, style1->DebugDiffFields(*style2).size());
 
@@ -1728,8 +1722,8 @@
   ComputedStyleBuilder builder1 = CreateComputedStyleBuilder();
   ComputedStyleBuilder builder2 = CreateComputedStyleBuilder();
 
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
 
   // Trigger lazy-evaluation of the field on *one* of the styles.
   EXPECT_FALSE(style1->IsStackingContextWithoutContainment());
@@ -1758,7 +1752,7 @@
 
   builder.SetDirection(TextDirection::kLtr);
   builder.SetWritingMode(WritingMode::kHorizontalTb);
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
   EXPECT_EQ(left, style->ScrollPaddingInlineStart());
   EXPECT_EQ(right, style->ScrollPaddingInlineEnd());
   EXPECT_EQ(top, style->ScrollPaddingBlockStart());
@@ -1813,7 +1807,7 @@
 }
 
 TEST_F(ComputedStyleTest, BasicBuilder) {
-  scoped_refptr<const ComputedStyle> original = InitialComputedStyle();
+  const ComputedStyle* original = InitialComputedStyle();
 
   Length left = Length::Fixed(1.0f);
   Length right = Length::Fixed(2.0f);
@@ -1822,7 +1816,7 @@
   builder.SetScrollPaddingLeft(left);
   builder.SetScrollPaddingRight(right);
 
-  scoped_refptr<const ComputedStyle> style = builder.TakeStyle();
+  const ComputedStyle* style = builder.TakeStyle();
 
   EXPECT_NE(left, original->ScrollPaddingLeft());
   EXPECT_NE(right, original->ScrollPaddingRight());
@@ -1839,9 +1833,7 @@
 
   ComputedStyleBuilder builder2(std::move(builder1));
 
-  EXPECT_FALSE(builder1.TakeStyle());
-
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
   ASSERT_TRUE(style2);
   EXPECT_EQ(one, style2->ScrollPaddingLeft());
 }
@@ -1855,9 +1847,7 @@
   ComputedStyleBuilder builder2(*InitialComputedStyle());
   builder2 = std::move(builder1);
 
-  EXPECT_FALSE(builder1.TakeStyle());
-
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
   ASSERT_TRUE(style2);
   EXPECT_EQ(one, style2->ScrollPaddingLeft());
 }
@@ -1875,11 +1865,11 @@
           1u, MakeGarbageCollected<ScopedCSSName>(AtomicString("test"),
                                                   /* tree_scope */ nullptr))));
 
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
 
   EXPECT_EQ(ComputedStyle::Difference::kEqual,
-            ComputedStyle::ComputeDifference(style1.get(), style2.get()));
+            ComputedStyle::ComputeDifference(style1, style2));
 }
 
 TEST_F(ComputedStyleTest, ScrollTimelineAxisNoDiff) {
@@ -1889,11 +1879,11 @@
   builder1.SetScrollTimelineAxis(Vector<TimelineAxis>(1u, TimelineAxis::kY));
   builder2.SetScrollTimelineAxis(Vector<TimelineAxis>(1u, TimelineAxis::kY));
 
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
 
   EXPECT_EQ(ComputedStyle::Difference::kEqual,
-            ComputedStyle::ComputeDifference(style1.get(), style2.get()));
+            ComputedStyle::ComputeDifference(style1, style2));
 }
 
 TEST_F(ComputedStyleTest, ViewTimelineNameNoDiff) {
@@ -1909,11 +1899,11 @@
           1u, MakeGarbageCollected<ScopedCSSName>(AtomicString("test"),
                                                   /* tree_scope */ nullptr))));
 
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
 
   EXPECT_EQ(ComputedStyle::Difference::kEqual,
-            ComputedStyle::ComputeDifference(style1.get(), style2.get()));
+            ComputedStyle::ComputeDifference(style1, style2));
 }
 
 TEST_F(ComputedStyleTest, ViewTimelineAxisNoDiff) {
@@ -1923,11 +1913,11 @@
   builder1.SetViewTimelineAxis(Vector<TimelineAxis>(1u, TimelineAxis::kY));
   builder2.SetViewTimelineAxis(Vector<TimelineAxis>(1u, TimelineAxis::kY));
 
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
 
   EXPECT_EQ(ComputedStyle::Difference::kEqual,
-            ComputedStyle::ComputeDifference(style1.get(), style2.get()));
+            ComputedStyle::ComputeDifference(style1, style2));
 }
 
 TEST_F(ComputedStyleTest, ViewTimelineInsetNoDiff) {
@@ -1939,11 +1929,11 @@
   builder2.SetViewTimelineInset(Vector<TimelineInset>(
       1u, TimelineInset(Length::Fixed(1.0f), Length::Fixed(1.0f))));
 
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
 
   EXPECT_EQ(ComputedStyle::Difference::kEqual,
-            ComputedStyle::ComputeDifference(style1.get(), style2.get()));
+            ComputedStyle::ComputeDifference(style1, style2));
 }
 
 TEST_F(ComputedStyleTest, ContainerNameNoDiff) {
@@ -1961,11 +1951,11 @@
                                                   /* tree_scope */ nullptr))));
   builder2.SetContainerType(kContainerTypeSize);
 
-  scoped_refptr<const ComputedStyle> style1 = builder1.TakeStyle();
-  scoped_refptr<const ComputedStyle> style2 = builder2.TakeStyle();
+  const ComputedStyle* style1 = builder1.TakeStyle();
+  const ComputedStyle* style2 = builder2.TakeStyle();
 
   EXPECT_EQ(ComputedStyle::Difference::kEqual,
-            ComputedStyle::ComputeDifference(style1.get(), style2.get()));
+            ComputedStyle::ComputeDifference(style1, style2));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/data_ref.h b/third_party/blink/renderer/core/style/data_ref.h
index 2a1782b0..72e29c6 100644
--- a/third_party/blink/renderer/core/style/data_ref.h
+++ b/third_party/blink/renderer/core/style/data_ref.h
@@ -24,19 +24,18 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_DATA_REF_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_DATA_REF_H_
 
-#include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 namespace blink {
 
 template <typename T>
 class DataRef {
-  USING_FAST_MALLOC(DataRef);
+  DISALLOW_NEW();
 
  public:
-  explicit DataRef(scoped_refptr<T>&& data) : data_(data) {}
+  explicit DataRef(T* data) : data_(data) {}
 
-  const T* Get() const { return data_.get(); }
+  const T* Get() const { return data_.Get(); }
 
   const T& operator*() const { return *Get(); }
   const T* operator->() const { return Get(); }
@@ -46,7 +45,7 @@
       access_flag = true;
       data_ = data_->Copy();
     }
-    return data_.get();
+    return data_.Get();
   }
 
   bool operator==(const DataRef<T>& o) const {
@@ -63,8 +62,12 @@
 
   void operator=(std::nullptr_t) { data_ = nullptr; }
 
+  void Trace(Visitor* visitor) const { visitor->Trace(data_); }
+
  private:
-  scoped_refptr<T> data_;
+  // These ComputedStyle sub-objects are heavily inlined, and on relatively hot
+  // codepaths. Disable pointer-compression.
+  subtle::UncompressedMember<T> data_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/fill_layer.cc b/third_party/blink/renderer/core/style/fill_layer.cc
index 2591edc8..2698335 100644
--- a/third_party/blink/renderer/core/style/fill_layer.cc
+++ b/third_party/blink/renderer/core/style/fill_layer.cc
@@ -30,9 +30,8 @@
 namespace blink {
 
 struct SameSizeAsFillLayer {
-  FillLayer* next_;
-
-  Persistent<StyleImage> image_;
+  Member<FillLayerWrapper> next_;
+  Member<StyleImage> image_;
 
   Length position_x_;
   Length position_y_;
@@ -88,7 +87,8 @@
       cached_properties_computed_(false) {}
 
 FillLayer::FillLayer(const FillLayer& o)
-    : next_(o.next_ ? new FillLayer(*o.next_) : nullptr),
+    : next_(o.next_ ? MakeGarbageCollected<FillLayerWrapper>(*o.next_)
+                    : nullptr),
       image_(o.image_),
       position_x_(o.position_x_),
       position_y_(o.position_y_),
@@ -125,14 +125,15 @@
       any_layer_has_default_attachment_image_(false),
       cached_properties_computed_(false) {}
 
-FillLayer::~FillLayer() {
-  delete next_;
+void FillLayer::Trace(Visitor* visitor) const {
+  visitor->Trace(next_);
+  visitor->Trace(image_);
 }
 
 FillLayer& FillLayer::operator=(const FillLayer& o) {
   if (next_ != o.next_) {
-    delete next_;
-    next_ = o.next_ ? new FillLayer(*o.next_) : nullptr;
+    next_ =
+        o.next_ ? MakeGarbageCollected<FillLayerWrapper>(*o.next_) : nullptr;
   }
 
   image_ = o.image_;
@@ -184,7 +185,7 @@
 
 bool FillLayer::operator==(const FillLayer& o) const {
   return LayerPropertiesEqual(o) &&
-         ((next_ && o.next_) ? *next_ == *o.next_ : next_ == o.next_);
+         ((Next() && o.Next()) ? *Next() == *o.Next() : Next() == o.Next());
 }
 
 bool FillLayer::VisuallyEqual(const FillLayer& o) const {
@@ -196,7 +197,7 @@
     return false;
   }
   if (next_ && o.next_) {
-    return next_->VisuallyEqual(*o.next_);
+    return next_->layer.VisuallyEqual(o.next_->layer);
   }
   return next_ == o.next_;
 }
@@ -350,9 +351,8 @@
 void FillLayer::CullEmptyLayers() {
   FillLayer* next;
   for (FillLayer* p = this; p; p = next) {
-    next = p->next_;
+    next = p->Next();
     if (next && !next->IsImageSet()) {
-      delete next;
       p->next_ = nullptr;
       break;
     }
@@ -378,19 +378,19 @@
        To<StyleGeneratedImage>(image_.Get())->IsUsingCurrentColor());
   cached_properties_computed_ = true;
 
-  if (next_) {
-    next_->ComputeCachedPropertiesIfNeeded();
+  if (auto* next = Next()) {
+    next->ComputeCachedPropertiesIfNeeded();
     layers_clip_max_ = static_cast<unsigned>(
-        EnclosingFillBox(LayersClipMax(), next_->LayersClipMax()));
-    any_layer_uses_content_box_ |= next_->any_layer_uses_content_box_;
-    any_layer_has_image_ |= next_->any_layer_has_image_;
-    any_layer_has_url_image_ |= next_->any_layer_has_url_image_;
-    any_layer_has_local_attachment_ |= next_->any_layer_has_local_attachment_;
+        EnclosingFillBox(LayersClipMax(), next->LayersClipMax()));
+    any_layer_uses_content_box_ |= next->any_layer_uses_content_box_;
+    any_layer_has_image_ |= next->any_layer_has_image_;
+    any_layer_has_url_image_ |= next->any_layer_has_url_image_;
+    any_layer_has_local_attachment_ |= next->any_layer_has_local_attachment_;
     any_layer_has_fixed_attachment_image_ |=
-        next_->any_layer_has_fixed_attachment_image_;
+        next->any_layer_has_fixed_attachment_image_;
     any_layer_has_default_attachment_image_ |=
-        next_->any_layer_has_default_attachment_image_;
-    any_layer_uses_current_color_ |= next_->any_layer_uses_current_color_;
+        next->any_layer_has_default_attachment_image_;
+    any_layer_uses_current_color_ |= next->any_layer_uses_current_color_;
   }
 }
 
diff --git a/third_party/blink/renderer/core/style/fill_layer.h b/third_party/blink/renderer/core/style/fill_layer.h
index 883abec2..4f2c024e 100644
--- a/third_party/blink/renderer/core/style/fill_layer.h
+++ b/third_party/blink/renderer/core/style/fill_layer.h
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/platform/geometry/length.h"
 #include "third_party/blink/renderer/platform/geometry/length_size.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
@@ -52,13 +53,15 @@
   LengthSize size;
 };
 
-// FIXME(Oilpan): Move FillLayer to Oilpan's heap.
+class FillLayerWrapper;
+
 class CORE_EXPORT FillLayer {
-  USING_FAST_MALLOC(FillLayer);
+  DISALLOW_NEW();
 
  public:
-  FillLayer(EFillLayerType, bool use_initial_values = false);
-  ~FillLayer();
+  explicit FillLayer(EFillLayerType, bool use_initial_values = false);
+
+  void Trace(Visitor* visitor) const;
 
   StyleImage* GetImage() const { return image_.Get(); }
   const Length& PositionX() const { return position_x_; }
@@ -88,14 +91,9 @@
     return FillSize(static_cast<EFillSizeType>(size_type_), size_length_);
   }
 
-  const FillLayer* Next() const { return next_; }
-  FillLayer* Next() { return next_; }
-  FillLayer* EnsureNext() {
-    if (!next_) {
-      next_ = new FillLayer(GetType());
-    }
-    return next_;
-  }
+  const FillLayer* Next() const;
+  FillLayer* Next();
+  FillLayer* EnsureNext();
 
   bool IsImageSet() const { return image_set_; }
   bool IsPositionXSet() const { return pos_x_set_; }
@@ -307,9 +305,8 @@
   }
   void ComputeCachedProperties() const;
 
-  FillLayer* next_;
-
-  Persistent<StyleImage> image_;
+  Member<FillLayerWrapper> next_;
+  Member<StyleImage> image_;
 
   Length position_x_;
   Length position_y_;
@@ -364,6 +361,27 @@
   mutable unsigned cached_properties_computed_ : 1;
 };
 
+class FillLayerWrapper : public GarbageCollected<FillLayerWrapper> {
+ public:
+  explicit FillLayerWrapper(EFillLayerType type) : layer(type) {}
+
+  void Trace(Visitor* visitor) const { visitor->Trace(layer); }
+  FillLayer layer;
+};
+
+inline const FillLayer* FillLayer::Next() const {
+  return next_ ? &next_->layer : nullptr;
+}
+inline FillLayer* FillLayer::Next() {
+  return next_ ? &next_->layer : nullptr;
+}
+inline FillLayer* FillLayer::EnsureNext() {
+  if (!next_) {
+    next_ = MakeGarbageCollected<FillLayerWrapper>(GetType());
+  }
+  return &next_->layer;
+}
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_FILL_LAYER_H_
diff --git a/third_party/blink/renderer/core/style/list_style_type_data.h b/third_party/blink/renderer/core/style/list_style_type_data.h
index 4bef084f..5e0cac5 100644
--- a/third_party/blink/renderer/core/style/list_style_type_data.h
+++ b/third_party/blink/renderer/core/style/list_style_type_data.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_LIST_STYLE_TYPE_DATA_H_
 
 #include "base/check_op.h"
+#include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
@@ -20,7 +21,7 @@
 class ListStyleTypeData final : public GarbageCollected<ListStyleTypeData> {
  public:
   ~ListStyleTypeData() = default;
-  void Trace(Visitor*) const;
+  CORE_EXPORT void Trace(Visitor*) const;
 
   enum class Type { kCounterStyle, kString };
 
diff --git a/third_party/blink/renderer/core/style/member_copy.h b/third_party/blink/renderer/core/style/member_copy.h
index 6ec461e..86ad5ad3 100644
--- a/third_party/blink/renderer/core/style/member_copy.h
+++ b/third_party/blink/renderer/core/style/member_copy.h
@@ -9,7 +9,6 @@
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/core/style/content_data.h"
 #include "third_party/blink/renderer/core/style/data_ref.h"
-#include "third_party/blink/renderer/core/style/style_filter_data.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 
 namespace blink {
@@ -20,7 +19,7 @@
 }
 
 template <typename T>
-Persistent<T> MemberCopy(const Persistent<T>& v) {
+Member<T> MemberCopy(const Member<T>& v) {
   return v;
 }
 
@@ -29,15 +28,10 @@
   return v ? v->Clone() : nullptr;
 }
 
-inline Persistent<ContentData> MemberCopy(const Persistent<ContentData>& v) {
+inline Member<ContentData> MemberCopy(const Member<ContentData>& v) {
   return v ? v->Clone() : nullptr;
 }
 
-inline Persistent<StyleFilterData> MemberCopy(
-    const Persistent<StyleFilterData>& v) {
-  return v->Copy();
-}
-
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_MEMBER_COPY_H_
diff --git a/third_party/blink/renderer/core/style/style_base_data.cc b/third_party/blink/renderer/core/style/style_base_data.cc
index 9db06b9..afda4a7 100644
--- a/third_party/blink/renderer/core/style/style_base_data.cc
+++ b/third_party/blink/renderer/core/style/style_base_data.cc
@@ -7,7 +7,7 @@
 
 namespace blink {
 
-StyleBaseData::StyleBaseData(scoped_refptr<const ComputedStyle> style,
+StyleBaseData::StyleBaseData(const ComputedStyle* style,
                              std::unique_ptr<CSSBitset> set)
     : computed_style_(style), important_set_(std::move(set)) {}
 
diff --git a/third_party/blink/renderer/core/style/style_base_data.h b/third_party/blink/renderer/core/style/style_base_data.h
index 8b38973..02c8945 100644
--- a/third_party/blink/renderer/core/style/style_base_data.h
+++ b/third_party/blink/renderer/core/style/style_base_data.h
@@ -7,6 +7,9 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/properties/css_bitset.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+#include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 
@@ -14,25 +17,23 @@
 
 class ComputedStyle;
 
-class CORE_EXPORT StyleBaseData : public RefCounted<StyleBaseData> {
-  USING_FAST_MALLOC(StyleBaseData);
-
+class CORE_EXPORT StyleBaseData : public GarbageCollected<StyleBaseData> {
  public:
-  static scoped_refptr<StyleBaseData> Create(
-      scoped_refptr<const ComputedStyle> style,
-      std::unique_ptr<CSSBitset> important_set) {
-    return base::AdoptRef(new StyleBaseData(style, std::move(important_set)));
+  static StyleBaseData* Create(const ComputedStyle* style,
+                               std::unique_ptr<CSSBitset> important_set) {
+    return MakeGarbageCollected<StyleBaseData>(style, std::move(important_set));
   }
+  StyleBaseData(const ComputedStyle*, std::unique_ptr<CSSBitset>);
 
   const ComputedStyle* GetBaseComputedStyle() const {
-    return computed_style_.get();
+    return computed_style_.Get();
   }
   const CSSBitset* GetBaseImportantSet() const { return important_set_.get(); }
 
- private:
-  StyleBaseData(scoped_refptr<const ComputedStyle>, std::unique_ptr<CSSBitset>);
+  void Trace(Visitor* visitor) const { visitor->Trace(computed_style_); }
 
-  scoped_refptr<const ComputedStyle> computed_style_;
+ private:
+  Member<const ComputedStyle> computed_style_;
 
   // Keeps track of the !important declarations used to build the base
   // computed style. These declarations must not be overwritten by animation
diff --git a/third_party/blink/renderer/core/style/style_cached_data.h b/third_party/blink/renderer/core/style/style_cached_data.h
index 43de9f1e..d29988d 100644
--- a/third_party/blink/renderer/core/style/style_cached_data.h
+++ b/third_party/blink/renderer/core/style/style_cached_data.h
@@ -13,10 +13,17 @@
 
 class ComputedStyle;
 
-using PositionFallbackStyleCache = Vector<scoped_refptr<const ComputedStyle>>;
-using PseudoElementStyleCache = Vector<scoped_refptr<const ComputedStyle>, 4>;
+using PositionFallbackStyleCache = HeapVector<Member<const ComputedStyle>>;
+using PseudoElementStyleCache = HeapVector<Member<const ComputedStyle>, 4>;
 
-class CORE_EXPORT StyleCachedData final {
+class CORE_EXPORT StyleCachedData final
+    : public GarbageCollected<StyleCachedData> {
+ public:
+  void Trace(Visitor* visitor) const {
+    visitor->Trace(pseudo_element_styles_);
+    visitor->Trace(position_fallback_styles_);
+  }
+
  private:
   friend class ComputedStyle;
   friend class ComputedStyleBuilder;
@@ -39,13 +46,13 @@
   //    <script>
   //      getComputedStyle(div, "::before").color // still green.
   //    </script>
-  std::unique_ptr<PseudoElementStyleCache> pseudo_element_styles_;
+  Member<PseudoElementStyleCache> pseudo_element_styles_;
 
   // This cache stores the ComputedStyles for an anchor-positioned element after
   // applying each @try block in the @position-fallback rule. Note that this is
   // not the computed style of any element, but used when laying out an
   // anchor-positioned element with fallback positions only.
-  std::unique_ptr<PositionFallbackStyleCache> position_fallback_styles_;
+  Member<PositionFallbackStyleCache> position_fallback_styles_;
 
   // Stores the names of of all custom properties on a given ComputedStyle.
   std::unique_ptr<Vector<AtomicString>> variable_names_;
diff --git a/third_party/blink/renderer/core/style/style_filter_data.cc b/third_party/blink/renderer/core/style/style_filter_data.cc
deleted file mode 100644
index 9468cfe..0000000
--- a/third_party/blink/renderer/core/style/style_filter_data.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/style/style_filter_data.h"
-
-namespace blink {
-
-StyleFilterData::StyleFilterData() : operations_() {}
-
-StyleFilterData::StyleFilterData(const StyleFilterData& o)
-    : operations_(o.operations_) {}
-
-bool StyleFilterData::operator==(const StyleFilterData& o) const {
-  return operations_ == o.operations_;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/style/style_filter_data.h b/third_party/blink/renderer/core/style/style_filter_data.h
deleted file mode 100644
index 5ba02b6..0000000
--- a/third_party/blink/renderer/core/style/style_filter_data.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_FILTER_DATA_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_FILTER_DATA_H_
-
-#include "third_party/blink/renderer/core/style/filter_operations.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-
-#include <iosfwd>
-
-namespace blink {
-
-class StyleFilterData final : public GarbageCollected<StyleFilterData> {
- public:
-  StyleFilterData();
-  explicit StyleFilterData(const StyleFilterData&);
-
-  StyleFilterData* Copy() const {
-    return MakeGarbageCollected<StyleFilterData>(*this);
-  }
-
-  bool operator==(const StyleFilterData&) const;
-  bool operator!=(const StyleFilterData& o) const { return !(*this == o); }
-
-  void Trace(Visitor* visitor) const { visitor->Trace(operations_); }
-
-  FilterOperations operations_;
-};
-
-inline std::ostream& operator<<(std::ostream& stream,
-                                const StyleFilterData& style_filter_data) {
-  return stream << style_filter_data.operations_;
-}
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_FILTER_DATA_H_
diff --git a/third_party/blink/renderer/core/style/style_highlight_data.cc b/third_party/blink/renderer/core/style/style_highlight_data.cc
index afa8ad1..3c7ff0a 100644
--- a/third_party/blink/renderer/core/style/style_highlight_data.cc
+++ b/third_party/blink/renderer/core/style/style_highlight_data.cc
@@ -9,22 +9,6 @@
 
 namespace blink {
 
-scoped_refptr<StyleHighlightData> StyleHighlightData::Create() {
-  return base::AdoptRef(new StyleHighlightData);
-}
-scoped_refptr<StyleHighlightData> StyleHighlightData::Copy() const {
-  return base::AdoptRef(new StyleHighlightData(*this));
-}
-
-StyleHighlightData::StyleHighlightData() = default;
-
-StyleHighlightData::StyleHighlightData(const StyleHighlightData& other)
-    : selection_(other.selection_),
-      target_text_(other.target_text_),
-      spelling_error_(other.spelling_error_),
-      grammar_error_(other.grammar_error_),
-      custom_highlights_(other.custom_highlights_) {}
-
 // Compares two CustomHighlightsStyleMaps with base::ValuesEquivalent as
 // comparison function on the values.
 bool HighlightStyleMapEquals(const CustomHighlightsStyleMap& a,
@@ -76,19 +60,19 @@
 }
 
 const ComputedStyle* StyleHighlightData::Selection() const {
-  return selection_.get();
+  return selection_.Get();
 }
 
 const ComputedStyle* StyleHighlightData::TargetText() const {
-  return target_text_.get();
+  return target_text_.Get();
 }
 
 const ComputedStyle* StyleHighlightData::SpellingError() const {
-  return spelling_error_.get();
+  return spelling_error_.Get();
 }
 
 const ComputedStyle* StyleHighlightData::GrammarError() const {
-  return grammar_error_.get();
+  return grammar_error_.Get();
 }
 
 const ComputedStyle* StyleHighlightData::CustomHighlight(
@@ -96,37 +80,40 @@
   if (highlight_name) {
     auto iter = custom_highlights_.find(highlight_name);
     if (iter != custom_highlights_.end()) {
-      return iter->value.get();
+      return iter->value.Get();
     }
   }
   return nullptr;
 }
 
-void StyleHighlightData::SetSelection(
-    scoped_refptr<const ComputedStyle>&& style) {
-  selection_ = std::move(style);
+void StyleHighlightData::SetSelection(const ComputedStyle* style) {
+  selection_ = style;
 }
 
-void StyleHighlightData::SetTargetText(
-    scoped_refptr<const ComputedStyle>&& style) {
-  target_text_ = std::move(style);
+void StyleHighlightData::SetTargetText(const ComputedStyle* style) {
+  target_text_ = style;
 }
 
-void StyleHighlightData::SetSpellingError(
-    scoped_refptr<const ComputedStyle>&& style) {
-  spelling_error_ = std::move(style);
+void StyleHighlightData::SetSpellingError(const ComputedStyle* style) {
+  spelling_error_ = style;
 }
 
-void StyleHighlightData::SetGrammarError(
-    scoped_refptr<const ComputedStyle>&& style) {
-  grammar_error_ = std::move(style);
+void StyleHighlightData::SetGrammarError(const ComputedStyle* style) {
+  grammar_error_ = style;
 }
 
-void StyleHighlightData::SetCustomHighlight(
-    const AtomicString& highlight_name,
-    scoped_refptr<const ComputedStyle>&& style) {
+void StyleHighlightData::SetCustomHighlight(const AtomicString& highlight_name,
+                                            const ComputedStyle* style) {
   DCHECK(highlight_name);
-  custom_highlights_.Set(highlight_name, std::move(style));
+  custom_highlights_.Set(highlight_name, style);
+}
+
+void StyleHighlightData::Trace(Visitor* visitor) const {
+  visitor->Trace(selection_);
+  visitor->Trace(target_text_);
+  visitor->Trace(spelling_error_);
+  visitor->Trace(grammar_error_);
+  visitor->Trace(custom_highlights_);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/style_highlight_data.h b/third_party/blink/renderer/core/style/style_highlight_data.h
index 433fcd17b..b6a80cf 100644
--- a/third_party/blink/renderer/core/style/style_highlight_data.h
+++ b/third_party/blink/renderer/core/style/style_highlight_data.h
@@ -9,6 +9,8 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
@@ -18,18 +20,12 @@
 
 class ComputedStyle;
 using CustomHighlightsStyleMap =
-    HashMap<AtomicString, scoped_refptr<const ComputedStyle>>;
+    HeapHashMap<AtomicString, Member<const ComputedStyle>>;
 
-class CORE_EXPORT StyleHighlightData final
-    : public RefCounted<StyleHighlightData> {
+class CORE_EXPORT StyleHighlightData final {
+  DISALLOW_NEW();
+
  public:
-  StyleHighlightData(StyleHighlightData&& other) = delete;
-  StyleHighlightData& operator=(const StyleHighlightData& other) = delete;
-  StyleHighlightData& operator=(StyleHighlightData&& other) = delete;
-
-  static scoped_refptr<StyleHighlightData> Create();
-  scoped_refptr<StyleHighlightData> Copy() const;
-
   bool operator==(const StyleHighlightData&) const;
 
   const ComputedStyle* Style(
@@ -43,21 +39,19 @@
   const CustomHighlightsStyleMap& CustomHighlights() const {
     return custom_highlights_;
   }
-  void SetSelection(scoped_refptr<const ComputedStyle>&&);
-  void SetTargetText(scoped_refptr<const ComputedStyle>&&);
-  void SetSpellingError(scoped_refptr<const ComputedStyle>&&);
-  void SetGrammarError(scoped_refptr<const ComputedStyle>&&);
-  void SetCustomHighlight(const AtomicString&,
-                          scoped_refptr<const ComputedStyle>&&);
+  void SetSelection(const ComputedStyle*);
+  void SetTargetText(const ComputedStyle*);
+  void SetSpellingError(const ComputedStyle*);
+  void SetGrammarError(const ComputedStyle*);
+  void SetCustomHighlight(const AtomicString&, const ComputedStyle*);
+
+  void Trace(Visitor*) const;
 
  private:
-  StyleHighlightData();
-  StyleHighlightData(const StyleHighlightData& other);
-
-  scoped_refptr<const ComputedStyle> selection_;
-  scoped_refptr<const ComputedStyle> target_text_;
-  scoped_refptr<const ComputedStyle> spelling_error_;
-  scoped_refptr<const ComputedStyle> grammar_error_;
+  Member<const ComputedStyle> selection_;
+  Member<const ComputedStyle> target_text_;
+  Member<const ComputedStyle> spelling_error_;
+  Member<const ComputedStyle> grammar_error_;
   CustomHighlightsStyleMap custom_highlights_;
 };
 
diff --git a/third_party/blink/renderer/core/svg/svg_element.cc b/third_party/blink/renderer/core/svg/svg_element.cc
index dcec4d8..7aa8b69 100644
--- a/third_party/blink/renderer/core/svg/svg_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_element.cc
@@ -1059,7 +1059,7 @@
   // attributes that didn't change.
 }
 
-scoped_refptr<const ComputedStyle> SVGElement::CustomStyleForLayoutObject(
+const ComputedStyle* SVGElement::CustomStyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
   SVGElement* corresponding_element = CorrespondingElement();
   if (!corresponding_element) {
diff --git a/third_party/blink/renderer/core/svg/svg_element.h b/third_party/blink/renderer/core/svg/svg_element.h
index 3b0240b..36802ac 100644
--- a/third_party/blink/renderer/core/svg/svg_element.h
+++ b/third_party/blink/renderer/core/svg/svg_element.h
@@ -170,7 +170,7 @@
   void CollectExtraStyleForPresentationAttribute(
       MutableCSSPropertyValueSet*) override;
 
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&) final;
   bool LayoutObjectIsNeeded(const DisplayStyle&) const override;
 
diff --git a/third_party/blink/renderer/core/svg/svg_element_rare_data.cc b/third_party/blink/renderer/core/svg/svg_element_rare_data.cc
index ca9bbbe..d879e559 100644
--- a/third_party/blink/renderer/core/svg/svg_element_rare_data.cc
+++ b/third_party/blink/renderer/core/svg/svg_element_rare_data.cc
@@ -53,7 +53,7 @@
     needs_override_computed_style_update_ = false;
   }
   DCHECK(override_computed_style_);
-  return override_computed_style_.get();
+  return override_computed_style_.Get();
 }
 
 void SVGElementRareData::ClearOverriddenComputedStyle() {
@@ -71,6 +71,7 @@
   visitor->Trace(outgoing_references_);
   visitor->Trace(incoming_references_);
   visitor->Trace(animated_smil_style_properties_);
+  visitor->Trace(override_computed_style_);
   visitor->Trace(element_instances_);
   visitor->Trace(corresponding_element_);
   visitor->Trace(resource_client_);
diff --git a/third_party/blink/renderer/core/svg/svg_element_rare_data.h b/third_party/blink/renderer/core/svg/svg_element_rare_data.h
index eb13b0c..ae3838b 100644
--- a/third_party/blink/renderer/core/svg/svg_element_rare_data.h
+++ b/third_party/blink/renderer/core/svg/svg_element_rare_data.h
@@ -115,7 +115,7 @@
   bool web_animated_attributes_dirty_ : 1;
   HashSet<QualifiedName> web_animated_attributes_;
   Member<MutableCSSPropertyValueSet> animated_smil_style_properties_;
-  scoped_refptr<const ComputedStyle> override_computed_style_;
+  Member<const ComputedStyle> override_computed_style_;
   // Used by <animateMotion>
   AffineTransform animate_motion_transform_;
 };
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index de67f86..cc490b81 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -2547,7 +2547,7 @@
   DCHECK(document);
   // Named pages aren't supported here, because this function may be called
   // without laying out first.
-  scoped_refptr<const ComputedStyle> style =
+  const ComputedStyle* style =
       document->StyleForPage(page_number, /* page_name */ AtomicString());
   return style->Visibility() !=
          EVisibility::kHidden;  // display property doesn't apply to @page.
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_pseudo_element_base.cc b/third_party/blink/renderer/core/view_transition/view_transition_pseudo_element_base.cc
index 151ab7a9..84c0599 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_pseudo_element_base.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_pseudo_element_base.cc
@@ -41,7 +41,7 @@
   }
 }
 
-scoped_refptr<const ComputedStyle>
+const ComputedStyle*
 ViewTransitionPseudoElementBase::CustomStyleForLayoutObject(
     const StyleRecalcContext& style_recalc_context) {
   // Set the parent style to the style of our parent.
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_pseudo_element_base.h b/third_party/blink/renderer/core/view_transition/view_transition_pseudo_element_base.h
index 868d10f..8ee0060c 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_pseudo_element_base.h
+++ b/third_party/blink/renderer/core/view_transition/view_transition_pseudo_element_base.h
@@ -21,7 +21,7 @@
   ~ViewTransitionPseudoElementBase() override = default;
 
   bool CanGeneratePseudoElement(PseudoId) const override;
-  scoped_refptr<const ComputedStyle> CustomStyleForLayoutObject(
+  const ComputedStyle* CustomStyleForLayoutObject(
       const StyleRecalcContext&) override;
   void Trace(Visitor* visitor) const override;
 
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
index 06ea9ea..c228b7d3 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
@@ -155,18 +155,12 @@
 }
 
 TEST_F(WorkletAnimationTest, StyleHasCurrentAnimation) {
-  scoped_refptr<const ComputedStyle> style1 =
-      GetDocument()
-          .GetStyleResolver()
-          .ResolveStyle(element_, StyleRecalcContext())
-          .get();
+  const ComputedStyle* style1 = GetDocument().GetStyleResolver().ResolveStyle(
+      element_, StyleRecalcContext());
   EXPECT_FALSE(style1->HasCurrentOpacityAnimation());
   worklet_animation_->play(ASSERT_NO_EXCEPTION);
-  scoped_refptr<const ComputedStyle> style2 =
-      GetDocument()
-          .GetStyleResolver()
-          .ResolveStyle(element_, StyleRecalcContext())
-          .get();
+  const ComputedStyle* style2 = GetDocument().GetStyleResolver().ResolveStyle(
+      element_, StyleRecalcContext());
   EXPECT_TRUE(style2->HasCurrentOpacityAnimation());
 }
 
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
index a05357a4..27babcb 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -524,8 +524,7 @@
           element_font_description.SpecifiedSize());
 
       font_style_builder.SetFontDescription(element_font_description);
-      scoped_refptr<const ComputedStyle> font_style =
-          font_style_builder.TakeStyle();
+      const ComputedStyle* font_style = font_style_builder.TakeStyle();
       Font font = canvas()->GetDocument().GetStyleEngine().ComputeFont(
           *canvas(), *font_style, *parsed_style);
 
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/background_color_paint_definition_test.cc b/third_party/blink/renderer/modules/csspaint/nativepaint/background_color_paint_definition_test.cc
index accba71..6ebc0ad 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/background_color_paint_definition_test.cc
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/background_color_paint_definition_test.cc
@@ -462,9 +462,8 @@
   Element* element = GetElementById("target");
   StyleRecalcContext style_recalc_context;
   style_recalc_context.old_style = element->GetComputedStyle();
-  scoped_refptr<const ComputedStyle> style =
-      GetDocument().GetStyleResolver().ResolveStyle(element,
-                                                    style_recalc_context);
+  const ComputedStyle* style = GetDocument().GetStyleResolver().ResolveStyle(
+      element, style_recalc_context);
   EXPECT_FALSE(style->HasCurrentBackgroundColorAnimation());
 
   NonThrowableExceptionState exception_state;
@@ -537,9 +536,8 @@
   Element* element = GetElementById("target");
   StyleRecalcContext style_recalc_context;
   style_recalc_context.old_style = element->GetComputedStyle();
-  scoped_refptr<const ComputedStyle> style =
-      GetDocument().GetStyleResolver().ResolveStyle(element,
-                                                    style_recalc_context);
+  const ComputedStyle* style = GetDocument().GetStyleResolver().ResolveStyle(
+      element, style_recalc_context);
   EXPECT_FALSE(style->HasCurrentBackgroundColorAnimation());
 
   NonThrowableExceptionState exception_state;
diff --git a/third_party/blink/renderer/modules/formatted_text/formatted_text.cc b/third_party/blink/renderer/modules/formatted_text/formatted_text.cc
index 113aa6d..ba79702 100644
--- a/third_party/blink/renderer/modules/formatted_text/formatted_text.cc
+++ b/third_party/blink/renderer/modules/formatted_text/formatted_text.cc
@@ -53,8 +53,9 @@
 void FormattedText::UpdateComputedStylesIfNeeded(
     Document& document,
     const FontDescription& defaultFont) {
-  auto style = document.GetStyleResolver().StyleForFormattedText(
-      /*is_text_run*/ false, defaultFont, GetCssPropertySet());
+  const ComputedStyle* style =
+      document.GetStyleResolver().StyleForFormattedText(
+          /*is_text_run*/ false, defaultFont, GetCssPropertySet());
   block_->SetStyle(style, LayoutObject::ApplyStyleChanges::kNo);
   block_->SetHorizontalWritingMode(style->IsHorizontalWritingMode());
   for (auto& text_run : text_runs_)
diff --git a/third_party/blink/renderer/modules/formatted_text/formatted_text_run.cc b/third_party/blink/renderer/modules/formatted_text/formatted_text_run.cc
index 23b03b6..6b7151c 100644
--- a/third_party/blink/renderer/modules/formatted_text/formatted_text_run.cc
+++ b/third_party/blink/renderer/modules/formatted_text/formatted_text_run.cc
@@ -27,8 +27,9 @@
 
 void FormattedTextRunInternal::UpdateStyle(Document& document,
                                            const ComputedStyle& parent_style) {
-  auto style = document.GetStyleResolver().StyleForFormattedText(
-      /*is_text_run*/ true, parent_style, GetCssPropertySet());
+  const ComputedStyle* style =
+      document.GetStyleResolver().StyleForFormattedText(
+          /*is_text_run*/ true, parent_style, GetCssPropertySet());
   layout_text_->SetStyle(style, LayoutObject::ApplyStyleChanges::kNo);
 }
 
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder_test.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder_test.cc
index f1b3fa6..7a37f84 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder_test.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder_test.cc
@@ -33,52 +33,31 @@
 namespace {
 
 using testing::_;
+using testing::Invoke;
 using testing::Return;
-using testing::Unused;
+using testing::WithArgs;
 
-class FakeVideoEncoder : public VideoEncoder {
+class MockVideoEncoder : public VideoEncoder {
  public:
-  FakeVideoEncoder(ScriptState* script_state,
+  MockVideoEncoder(ScriptState* script_state,
                    const VideoEncoderInit* init,
                    ExceptionState& exception_state)
       : VideoEncoder(script_state, init, exception_state) {}
-  ~FakeVideoEncoder() override = default;
+  ~MockVideoEncoder() override = default;
 
-  void SetupMockEncoderCreation(bool is_hw_accelerated,
-                                base::RepeatingClosure quit_closure) {
-    next_mock_encoder_ = std::make_unique<media::MockVideoEncoder>();
-    mock_encoder_is_hw_ = is_hw_accelerated;
-    SetupExpectations(quit_closure);
+  MOCK_METHOD(std::unique_ptr<media::VideoEncoder>,
+              CreateMediaVideoEncoder,
+              (const ParsedConfig& config,
+               media::GpuVideoAcceleratorFactories* gpu_factories),
+              (override));
+
+  // CallOnMediaENcoderInfoChanged() is necessary for VideoEncoderTest to call
+  // VideoEncoder::OnMediaEncoderInfoChanged() because the function is a private
+  // and VideoEncoderTest is not a friend of VideoEncoder.
+  void CallOnMediaEncoderInfoChanged(
+      const media::VideoEncoderInfo& encoder_info) {
+    VideoEncoder::OnMediaEncoderInfoChanged(encoder_info);
   }
-
- private:
-  void SetupExpectations(base::RepeatingClosure quit_closure) {
-    EXPECT_CALL(*next_mock_encoder_, Initialize(_, _, _, _, _))
-        .WillOnce([quit_closure](Unused, Unused, Unused, Unused,
-                                 media::VideoEncoder::EncoderStatusCB done_cb) {
-          scheduler::GetSequencedTaskRunnerForTesting()->PostTask(
-              FROM_HERE, WTF::BindOnce(std::move(done_cb),
-                                       media::EncoderStatus::Codes::kOk));
-          scheduler::GetSequencedTaskRunnerForTesting()->PostTask(
-              FROM_HERE, std::move(quit_closure));
-        });
-  }
-
-  std::unique_ptr<media::VideoEncoder> CreateMediaVideoEncoder(
-      const ParsedConfig& config,
-      media::GpuVideoAcceleratorFactories* gpu_factories) override {
-    EXPECT_TRUE(next_mock_encoder_);
-
-    media::VideoEncoderInfo info;
-    info.implementation_name = "MockEncoderName";
-    info.is_hardware_accelerated = mock_encoder_is_hw_;
-    OnMediaEncoderInfoChanged(info);
-
-    return std::move(next_mock_encoder_);
-  }
-
-  bool mock_encoder_is_hw_;
-  std::unique_ptr<media::MockVideoEncoder> next_mock_encoder_;
 };
 
 class VideoEncoderTest : public testing::Test {
@@ -102,10 +81,10 @@
                                             exception_state);
 }
 
-FakeVideoEncoder* CreateFakeEncoder(ScriptState* script_state,
+MockVideoEncoder* CreateMockEncoder(ScriptState* script_state,
                                     VideoEncoderInit* init,
                                     ExceptionState& exception_state) {
-  return MakeGarbageCollected<FakeVideoEncoder>(script_state, init,
+  return MakeGarbageCollected<MockVideoEncoder>(script_state, init,
                                                 exception_state);
 }
 
@@ -201,7 +180,7 @@
   // Create a video encoder.
   auto* init =
       CreateInit(mock_function.ExpectNoCall(), mock_function.ExpectNoCall());
-  auto* encoder = CreateFakeEncoder(script_state, init, es);
+  auto* encoder = CreateMockEncoder(script_state, init, es);
   ASSERT_FALSE(es.HadException());
 
   // Simulate backgrounding to enable reclamation.
@@ -219,7 +198,29 @@
   auto* config = CreateConfig();
   {
     base::RunLoop run_loop;
-    encoder->SetupMockEncoderCreation(true, run_loop.QuitClosure());
+    auto media_encoder = std::make_unique<media::MockVideoEncoder>();
+    media::MockVideoEncoder* mock_media_encoder = media_encoder.get();
+
+    EXPECT_CALL(*encoder, CreateMediaVideoEncoder(_, _))
+        .WillOnce(::testing::DoAll(
+            ::testing::Invoke([encoder = encoder]() {
+              media::VideoEncoderInfo info;
+              info.implementation_name = "MockEncoderName";
+              info.is_hardware_accelerated = true;
+              encoder->CallOnMediaEncoderInfoChanged(info);
+            }),
+            ::testing::Return(::testing::ByMove(std::move(media_encoder)))));
+
+    EXPECT_CALL(*mock_media_encoder, Initialize(_, _, _, _, _))
+        .WillOnce(WithArgs<4>(
+            Invoke([quit_closure = run_loop.QuitClosure()](
+                       media::VideoEncoder::EncoderStatusCB done_cb) {
+              scheduler::GetSequencedTaskRunnerForTesting()->PostTask(
+                  FROM_HERE, WTF::BindOnce(std::move(done_cb),
+                                           media::EncoderStatus::Codes::kOk));
+              scheduler::GetSequencedTaskRunnerForTesting()->PostTask(
+                  FROM_HERE, std::move(quit_closure));
+            })));
 
     encoder->configure(config, es);
     ASSERT_FALSE(es.HadException());
@@ -235,7 +236,30 @@
   config->setCodec("avc1.42001E");
   {
     base::RunLoop run_loop;
-    encoder->SetupMockEncoderCreation(false, run_loop.QuitClosure());
+
+    auto media_encoder = std::make_unique<media::MockVideoEncoder>();
+    media::MockVideoEncoder* mock_media_encoder = media_encoder.get();
+
+    EXPECT_CALL(*encoder, CreateMediaVideoEncoder(_, _))
+        .WillOnce(::testing::DoAll(
+            ::testing::Invoke([encoder = encoder]() {
+              media::VideoEncoderInfo info;
+              info.implementation_name = "MockEncoderName";
+              info.is_hardware_accelerated = false;
+              encoder->CallOnMediaEncoderInfoChanged(info);
+            }),
+            ::testing::Return(::testing::ByMove(std::move(media_encoder)))));
+
+    EXPECT_CALL(*mock_media_encoder, Initialize(_, _, _, _, _))
+        .WillOnce(WithArgs<4>(
+            Invoke([quit_closure = run_loop.QuitClosure()](
+                       media::VideoEncoder::EncoderStatusCB done_cb) {
+              scheduler::GetSequencedTaskRunnerForTesting()->PostTask(
+                  FROM_HERE, WTF::BindOnce(std::move(done_cb),
+                                           media::EncoderStatus::Codes::kOk));
+              scheduler::GetSequencedTaskRunnerForTesting()->PostTask(
+                  FROM_HERE, std::move(quit_closure));
+            })));
 
     encoder->configure(config, es);
     ASSERT_FALSE(es.HadException());
diff --git a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc
index c9f1b18..809128c 100644
--- a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc
@@ -1326,10 +1326,8 @@
   out_gainmap_data = CreateGainmapSegmentReader(features, data_.get());
 
   // Parse gainmap image to get gainmap XMP.
-  AvifIOData gainmap_avif_io_data = {
-      .reader = out_gainmap_data.get(),
-      .all_data_received = IsAllDataReceived(),
-  };
+  AvifIOData gainmap_avif_io_data(out_gainmap_data.get(), IsAllDataReceived());
+
   avifIO gainmap_avif_io = {.destroy = nullptr,
                             .read = ReadFromSegmentReader,
                             .write = nullptr,
@@ -1372,4 +1370,10 @@
   return true;
 }
 
+AVIFImageDecoder::AvifIOData::AvifIOData() = default;
+AVIFImageDecoder::AvifIOData::AvifIOData(const SegmentReader* reader,
+                                         bool all_data_received)
+    : reader(reader), all_data_received(all_data_received) {}
+AVIFImageDecoder::AvifIOData::~AvifIOData() = default;
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h
index c99e73b..ab282e4 100644
--- a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h
@@ -75,6 +75,10 @@
   };
 
   struct AvifIOData {
+    AvifIOData();
+    AvifIOData(const SegmentReader* reader, bool all_data_received);
+    ~AvifIOData();
+
     const SegmentReader* reader = nullptr;
     std::vector<uint8_t> buffer ALLOW_DISCOURAGED_TYPE("Required by libavif");
     bool all_data_received = false;
diff --git a/third_party/blink/renderer/platform/image-decoders/segment_reader.cc b/third_party/blink/renderer/platform/image-decoders/segment_reader.cc
index 76df7d39..58ace0db6 100644
--- a/third_party/blink/renderer/platform/image-decoders/segment_reader.cc
+++ b/third_party/blink/renderer/platform/image-decoders/segment_reader.cc
@@ -72,6 +72,7 @@
   sk_sp<SkData> GetAsSkData() const override;
 
  private:
+  ~SharedBufferSegmentReader() override = default;
   scoped_refptr<SharedBuffer> shared_buffer_;
 };
 
@@ -119,6 +120,7 @@
   sk_sp<SkData> GetAsSkData() const override;
 
  private:
+  ~DataSegmentReader() override = default;
   sk_sp<SkData> data_;
 };
 
@@ -156,6 +158,7 @@
   sk_sp<SkData> GetAsSkData() const override;
 
  private:
+  ~ROBufferSegmentReader() override = default;
   scoped_refptr<ROBuffer> ro_buffer_;
   mutable base::Lock read_lock_;
   // Position of the first char in the current block of iter_.
@@ -226,7 +229,6 @@
 class ParkableImageSegmentReader : public SegmentReader {
  public:
   explicit ParkableImageSegmentReader(scoped_refptr<ParkableImage> image);
-  ~ParkableImageSegmentReader() override = default;
   size_t size() const override;
   size_t GetSomeData(const char*& data, size_t position) const override;
   sk_sp<SkData> GetAsSkData() const override;
@@ -234,6 +236,7 @@
   void UnlockData() override;
 
  private:
+  ~ParkableImageSegmentReader() override = default;
   scoped_refptr<ParkableImage> parkable_image_;
   size_t available_;
 };
diff --git a/third_party/blink/tools/blinkpy/wpt_tests/wpt_adapter.py b/third_party/blink/tools/blinkpy/wpt_tests/wpt_adapter.py
index 180bf34d..570f2dc 100644
--- a/third_party/blink/tools/blinkpy/wpt_tests/wpt_adapter.py
+++ b/third_party/blink/tools/blinkpy/wpt_tests/wpt_adapter.py
@@ -538,6 +538,8 @@
             'flag_specific': self.port.flag_specific_config_name() or '',
             'used_upstream': self.options.use_upstream_wpt,
             'sanitizer_enabled': self.options.enable_sanitizer,
+            # TODO(crbug.com/1152503): Fully support virtual suites.
+            'virtual_suite': '',
         }
         if self.options.use_upstream_wpt:
             # `run_wpt_tests` does not run in the upstream checkout's git
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 15130a81..c1d7c59 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6770,12 +6770,6 @@
 crbug.com/1472721 [ Linux ] virtual/scalefactor200/fast/hidpi/static/pointerevents/pointerevent_touch-adjustment_click_target.html [ Failure Pass ]
 
 # Gardener 2023-08-16
-crbug.com/1473373 [ Mac11 ] wpt_internal/scheduler/task-signal-any-memory-abort.any.worker.html [ Pass Timeout ]
-crbug.com/1473373 [ Mac11-arm64 ] wpt_internal/scheduler/task-signal-any-memory-abort.any.worker.html [ Pass Timeout ]
-crbug.com/1473373 [ Mac12 ] wpt_internal/scheduler/task-signal-any-memory-abort.any.worker.html [ Pass Timeout ]
-crbug.com/1473373 [ Mac12-arm64 ] wpt_internal/scheduler/task-signal-any-memory-abort.any.worker.html [ Pass Timeout ]
-crbug.com/1473373 [ Mac13 ] wpt_internal/scheduler/task-signal-any-memory-abort.any.worker.html [ Pass Timeout ]
-crbug.com/1473373 [ Mac13-arm64 ] wpt_internal/scheduler/task-signal-any-memory-abort.any.worker.html [ Pass Timeout ]
 crbug.com/1473474 [ Mac13 ] wpt_internal/mediastream/mediastreamtrackprocessor-transfer-to-worker.html [ Failure Pass ]
 
 # Disable the following tests to land and reenable after the land.
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index bc38835a..ab5ebf1 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -258396,7 +258396,7 @@
       },
       "text": {
        "2d.text.fontVariantCaps1.html": [
-        "b610c2240ffe96c7fe747a0db55c5bda51802e38",
+        "56acfc61f47c32092db1793eb2f4a9966fde04ef",
         [
          null,
          [
@@ -258408,21 +258408,8 @@
          {}
         ]
        ],
-       "2d.text.fontVariantCaps2.html": [
-        "f9d42ac3a60eb9f2a62ea2343c9f17a450713b71",
-        [
-         null,
-         [
-          [
-           "/html/canvas/element/text/2d.text.fontVariantCaps2-unexpected.html",
-           "!="
-          ]
-         ],
-         {}
-        ]
-       ],
        "2d.text.fontVariantCaps3.html": [
-        "a90e0c29b3dd1aa0176dabb653cd36d07abfadf4",
+        "c3d80d3e56caf84b9e5e1d7ab294300d722275cb",
         [
          null,
          [
@@ -258435,7 +258422,7 @@
         ]
        ],
        "2d.text.fontVariantCaps4.html": [
-        "b598fb60baf2d5126571eb020306cc57fd603464",
+        "1ee9053b4d9bc06343394cdae54950283873ed44",
         [
          null,
          [
@@ -258448,7 +258435,7 @@
         ]
        ],
        "2d.text.fontVariantCaps5.html": [
-        "b871f7c062409ffc0b263594c495bc0d5bde3896",
+        "d80de4ea31873274d14761cb9b1f171a4eb9b208",
         [
          null,
          [
@@ -258461,7 +258448,7 @@
         ]
        ],
        "2d.text.fontVariantCaps6.html": [
-        "e7bbd29341dcc6755848672047c3263cf4196fdd",
+        "c17fac18b773da2e581c5e55fb0d04dc64deafab",
         [
          null,
          [
@@ -259627,7 +259614,7 @@
       },
       "text": {
        "2d.text.fontVariantCaps1.html": [
-        "a2da7f557ce7c10d4b4dac0d9cd351fe11c062f1",
+        "3c216f07daac09924ae79221b05665ea0510000b",
         [
          null,
          [
@@ -259639,21 +259626,34 @@
          {}
         ]
        ],
-       "2d.text.fontVariantCaps2.html": [
-        "8a644fbb616bc42d223093b70a54fb6653c6b6d4",
+       "2d.text.fontVariantCaps1.w.html": [
+        "4bc1b36e17576a6ef35f75783e5ffd4fb16c0ffb",
         [
          null,
          [
           [
-           "/html/canvas/offscreen/text/2d.text.fontVariantCaps2-unexpected.html",
-           "!="
+           "/html/canvas/offscreen/text/2d.text.fontVariantCaps1-expected.html",
+           "=="
           ]
          ],
          {}
         ]
        ],
        "2d.text.fontVariantCaps3.html": [
-        "665a176087fba458e1b7708486d869ebd6862ce1",
+        "48699a640fe1f792ed275908b3b167e5e19aa01b",
+        [
+         null,
+         [
+          [
+           "/html/canvas/offscreen/text/2d.text.fontVariantCaps3-expected.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "2d.text.fontVariantCaps3.w.html": [
+        "cd5c1db818fcbf9c827cf3554d1ddd767ce2dac2",
         [
          null,
          [
@@ -259666,7 +259666,20 @@
         ]
        ],
        "2d.text.fontVariantCaps4.html": [
-        "84c5fbb4469f1ce6c844850dce34f79dbee62870",
+        "b1b81b81e28747f9ec671a63eefcc2cb13d3c5bd",
+        [
+         null,
+         [
+          [
+           "/html/canvas/offscreen/text/2d.text.fontVariantCaps4-expected.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "2d.text.fontVariantCaps4.w.html": [
+        "0bae66fcd46b3e2903a1ce2350f571224efeb591",
         [
          null,
          [
@@ -259679,7 +259692,20 @@
         ]
        ],
        "2d.text.fontVariantCaps5.html": [
-        "877d890ccc6d114fb70fa3df850366bd9a5bbe14",
+        "2a6f7b5f737ca8c549ae88d413241ada90543049",
+        [
+         null,
+         [
+          [
+           "/html/canvas/offscreen/text/2d.text.fontVariantCaps5-expected.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "2d.text.fontVariantCaps5.w.html": [
+        "8c59f5b517d4b8bd07b2d057a44792614eb55103",
         [
          null,
          [
@@ -259692,7 +259718,20 @@
         ]
        ],
        "2d.text.fontVariantCaps6.html": [
-        "08c70a3a2e2fd0b60020a21877575d10108a06c0",
+        "c33684d38869cd1fed409d44dc6bb1c6cfecf3e5",
+        [
+         null,
+         [
+          [
+           "/html/canvas/offscreen/text/2d.text.fontVariantCaps6-expected.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "2d.text.fontVariantCaps6.w.html": [
+        "47f70d812b6664c19fb424102df09d4960caad97",
         [
          null,
          [
@@ -305956,13 +305995,17 @@
        []
       ],
       "color-computed-relative-color-expected.txt": [
-       "be758f7252ef8c9d11323f1bdf07440132acb172",
+       "1e3f263447cecc562b28641a015d16762f79487a",
        []
       ],
       "color-computed-relative-color.html.ini": [
        "cd52a07975a7b0d3aaba0c37a1d2f8eef7b47142",
        []
       ],
+      "color-invalid-relative-color-expected.txt": [
+       "a518847d1a98c25f6fdb2ff807955d28e7d636d1",
+       []
+      ],
       "color-valid-color-function.html.ini": [
        "9f2446cc0e3668b8d01feaf7fe1f4db0c2ce2c0b",
        []
@@ -305980,7 +306023,7 @@
        []
       ],
       "color-valid-relative-color-expected.txt": [
-       "ff73eaaad050a55ba85ffbfe5b802b46f463710e",
+       "0e9c4e7240a216285748a5658fa2269de307c6b3",
        []
       ],
       "color-valid-relative-color.html.ini": [
@@ -311133,7 +311176,7 @@
       []
      ],
      "flexbox-align-self-baseline-horiz-006-ref.xhtml": [
-      "248ca88a2f2dfb1627bf99b06585f3e2c6986dae",
+      "9b38d0955b6cf2f70151268454f0753d5f219021",
       []
      ],
      "flexbox-align-self-baseline-horiz-006.xhtml.ini": [
@@ -367689,7 +367732,7 @@
       []
      ],
      "empty-elements-insertion-expected.txt": [
-      "6bff876fb8662b5106e6e1f5f71793df0bfe2c00",
+      "74501eab59da19551d8500949035f9ab32db747e",
       []
      ],
      "empty-elements-insertion.html.ini": [
@@ -381671,15 +381714,11 @@
         []
        ],
        "2d.text.fontVariantCaps1-expected.html": [
-        "8ea3c22be13dd3bf1421c3f80b121edcc8b2d3bc",
-        []
-       ],
-       "2d.text.fontVariantCaps2-unexpected.html": [
-        "c64f5d0ec2aea8307ea4ba5257498f2f236186e6",
+        "e2cef0d77a64b17657bdfe99194930c5328cc3e8",
         []
        ],
        "2d.text.fontVariantCaps3-expected.html": [
-        "069fbfba8823e3e0f5fcf7ada4bd600b6dce1bbd",
+        "cf2d5ae119b549803b48521003d394313159944a",
         []
        ],
        "2d.text.fontVariantCaps3.html.ini": [
@@ -381687,7 +381726,7 @@
         []
        ],
        "2d.text.fontVariantCaps4-expected.html": [
-        "069fbfba8823e3e0f5fcf7ada4bd600b6dce1bbd",
+        "3813fd3684e8c94887337a551727e068469a66c5",
         []
        ],
        "2d.text.fontVariantCaps4.html.ini": [
@@ -381695,11 +381734,11 @@
         []
        ],
        "2d.text.fontVariantCaps5-expected.html": [
-        "8ea3c22be13dd3bf1421c3f80b121edcc8b2d3bc",
+        "4bda4ec4b5dc522b400df462b8a13b2fc7a9be8a",
         []
        ],
        "2d.text.fontVariantCaps6-expected.html": [
-        "c64f5d0ec2aea8307ea4ba5257498f2f236186e6",
+        "af9c736aea7f9b20f4fd09522a8aa2dd25a11ef1",
         []
        ],
        "2d.text.measure.baselines-expected.txt": [
@@ -382269,7 +382308,7 @@
         []
        ],
        "2d.text.fontVariantCaps1-expected.html": [
-        "942bcdec9cb938536738ef1f71a60cd1c85c9086",
+        "e2cef0d77a64b17657bdfe99194930c5328cc3e8",
         []
        ],
        "2d.text.fontVariantCaps1.html.ini": [
@@ -382281,7 +382320,7 @@
         []
        ],
        "2d.text.fontVariantCaps3-expected.html": [
-        "8d96d0ab0320ea8412e0045f59b6a3ca18260242",
+        "cf2d5ae119b549803b48521003d394313159944a",
         []
        ],
        "2d.text.fontVariantCaps3.html.ini": [
@@ -382289,7 +382328,7 @@
         []
        ],
        "2d.text.fontVariantCaps4-expected.html": [
-        "8d96d0ab0320ea8412e0045f59b6a3ca18260242",
+        "3813fd3684e8c94887337a551727e068469a66c5",
         []
        ],
        "2d.text.fontVariantCaps4.html.ini": [
@@ -382297,7 +382336,7 @@
         []
        ],
        "2d.text.fontVariantCaps5-expected.html": [
-        "942bcdec9cb938536738ef1f71a60cd1c85c9086",
+        "4bda4ec4b5dc522b400df462b8a13b2fc7a9be8a",
         []
        ],
        "2d.text.fontVariantCaps5.html.ini": [
@@ -382305,7 +382344,7 @@
         []
        ],
        "2d.text.fontVariantCaps6-expected.html": [
-        "dbcb8abd76a544d8a5ab48b1f477fc54c7ba008f",
+        "af9c736aea7f9b20f4fd09522a8aa2dd25a11ef1",
         []
        ],
        "2d.text.fontVariantCaps6.html.ini": [
@@ -382551,7 +382590,7 @@
         []
        ],
        "text.yaml": [
-        "93c86b8b5e59e4c9817698d248e3b670c69c9528",
+        "0e69cf2ccb9b6501877bb92c88045245b2f970b7",
         []
        ],
        "the-canvas-state.yaml": [
@@ -392677,7 +392716,7 @@
         ]
        },
        "selection-pointer-expected.txt": [
-        "a46cb70594b81466ca0c856428b12ce23e940d36",
+        "92255d9932e6a679b84e2b8f9100dc6183f29e47",
         []
        ],
        "selection-pointer.html.ini": [
@@ -401425,7 +401464,7 @@
     ]
    },
    "lint.ignore": [
-    "489c717cd6a715ce07dea9421863d3b69ad42cc9",
+    "761380e5356657d20a76c31e0e18ab94e4527d38",
     []
    ],
    "loading": {
@@ -401699,6 +401738,10 @@
        "9d761b6de5ee65c9067a4c576c90eb9e7dd6ef05",
        []
       ],
+      "busy_in_promise.js": [
+       "2eab6b6b8fd1df45df14ab7972a8ff774c3f4ec9",
+       []
+      ],
       "utils.js": [
        "8781252e9411fcb3bf2423347e185e2633ef0140",
        []
@@ -474526,6 +474569,13 @@
         {}
        ]
       ],
+      "content-visibility-087.html": [
+       "f2faa45774cde805a295f3376b87444091500f47",
+       [
+        null,
+        {}
+       ]
+      ],
       "content-visibility-auto-first-observation-immediate.html": [
        "5a177d6ea98f15315db595d6bc7b0e8f2da5ac4e",
        [
@@ -560477,6 +560527,13 @@
          {}
         ]
        ],
+       "2d.text.fontVariantCaps2.html": [
+        "56efbb6fd3a990b04163889dcd0010538c714a5f",
+        [
+         null,
+         {}
+        ]
+       ],
        "2d.text.measure.actualBoundingBox.html": [
         "d0672b23dcd3f4902f1ca6375a3be62560f96902",
         [
@@ -572999,6 +573056,20 @@
          {}
         ]
        ],
+       "2d.text.fontVariantCaps2.html": [
+        "e5bcff1831689321a0bd23983780769cce4e0669",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.text.fontVariantCaps2.worker.js": [
+        "89f4f48c7371f119098789c44d46e7a611664519",
+        [
+         "html/canvas/offscreen/text/2d.text.fontVariantCaps2.worker.html",
+         {}
+        ]
+       ],
        "2d.text.measure.actualBoundingBox.html": [
         "105efc07948a4de537689bb8bbc7ee1548f187bf",
         [
@@ -606664,6 +606735,15 @@
        }
       ]
      ],
+     "loaf-source-location-promise-resolver.html": [
+      "353b4160751cb125e3b203f604405474c3715ec6",
+      [
+       null,
+       {
+        "timeout": "long"
+       }
+      ]
+     ],
      "loaf-source-location.html": [
       "1065564206fc151e9690aca9bf512f7d48016099",
       [
@@ -619534,9 +619614,9 @@
      ]
     ],
     "pointerevent_attributes_nohover_pointers.html": [
-     "d501ae0afd45612f5bad13d08cdd7cb2646a38d9",
+     "374279135d0c182e605cb7e661d89b1a8e27ca6a",
      [
-      null,
+      "pointerevents/pointerevent_attributes_nohover_pointers.html?touch",
       {
        "testdriver": true
       }
@@ -679398,6 +679478,15 @@
       }
      ]
     ],
+    "RTCEncodedAudioFrame-receive-cloned.https.html": [
+     "5a3bfeaf0aca51ae03f7244ff892035031720e74",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "RTCEncodedAudioFrame-serviceworker-failure.https.html": [
      "d6d8578dbdf5385f4f1ba85f68f610ce3727cd38",
      [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-087.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-087.html
new file mode 100644
index 0000000..f2faa45
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-087.html
@@ -0,0 +1,26 @@
+<!doctype HTML>
+<html>
+<meta charset="utf8">
+<title>Content visibility: focus does not target nested c-v: hidden/auto subtree"</title>
+<link rel="author" title="Rob Buis" href="mailto:rbuis@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<meta name="assert" content="focus does not target nested c-v: hidden/auto subtree">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div style="content-visibility: hidden">
+  <div style="content-visibility: auto">
+    <div id="focusable" tabIndex="0">
+      focusable thing
+    </div>
+  </div>
+</div>
+
+<script>
+test(() => {
+  focusable.focus();
+  assert_not_equals(document.activeElement, focusable);
+}, "Trying to focus on an element in a nested hidden/auto subtree will not work");
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flexbox-align-self-baseline-horiz-006-ref.xhtml b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flexbox-align-self-baseline-horiz-006-ref.xhtml
index 248ca88..9b38d095 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flexbox-align-self-baseline-horiz-006-ref.xhtml
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flexbox-align-self-baseline-horiz-006-ref.xhtml
@@ -11,16 +11,28 @@
     <title>CSS Reftest Reference</title>
     <link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
     <style>
-      .container {
+      .container,
+      .containerEndAlign {
         border: 1px dashed blue;
         font: 14px sans-serif;
         height: 50px;
       }
 
-      .container > div {
+      .container > div,
+      .wrapper > div{
         display: inline-block;
       }
 
+      .containerEndAlign {
+        display: flex;
+        align-items: end;
+      }
+      .wrapper {
+        /* This accounts for the 'margin-bottom: 3px' on the 'offset' element
+           in the last-baseline-aligned part of the testcase: */
+        margin-bottom: 3px;
+      }
+
       .ortho  {
         writing-mode: vertical-rl;
         width: 17px;
@@ -40,11 +52,21 @@
       ><div class="orange" style="display: inline-flex;">two<br/>lines</div
       ><div class="pink">offset</div>
     </div>
-    <div class="container">
-      <div class="lime ortho" style="margin-top: 4px;">ortho</div
-      ><div class="yellow">one line</div
-      ><div class="orange">two<br/>lines</div
-      ><div class="pink">offset</div>
+
+    <!-- Note: in the testcase, there's a flex container here, whose flex items
+         are 'last baseline'-aligned and collectively snapped to the end
+         (bottom) edge.  To mock that up, we use a simple flex container with a
+         single end-aligned 'display:block' flex item; and that item has
+         inline-block children, which are mockups of the testcase's flex items.
+         (These inline-blocks get automatically 'last-baseline' aligned to each
+         other, as part of regular inline-block layout behavior.) -->
+    <div class="containerEndAlign">
+      <div class="wrapper">
+        <div class="lime ortho">ortho</div
+        ><div class="yellow">one line</div
+        ><div class="orange">two<br/>lines</div
+        ><div class="pink">offset</div>
+      </div>
     </div>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/auto-direction-dynamic.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/auto-direction-dynamic.html
new file mode 100644
index 0000000..68ea511
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/auto-direction-dynamic.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<link rel="match" href="auto-direction-ref.html">
+<body>
+<script>
+const dirInput = document.createElement('input')
+dirInput.setAttribute('dir', 'auto')
+dirInput.setAttribute('value', 'شنينسنمس')
+document.body.appendChild(dirInput)
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/auto-direction-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/auto-direction-ref.html
new file mode 100644
index 0000000..675ba50
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/auto-direction-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<input dir="auto" value="شنينسنمس">
diff --git a/third_party/blink/web_tests/wpt_internal/dom/abort/abort-signal-memory-tests.https.any.js b/third_party/blink/web_tests/wpt_internal/dom/abort/abort-signal-memory-tests.https.any.js
index 9beb627c..3a7f8e69 100644
--- a/third_party/blink/web_tests/wpt_internal/dom/abort/abort-signal-memory-tests.https.any.js
+++ b/third_party/blink/web_tests/wpt_internal/dom/abort/abort-signal-memory-tests.https.any.js
@@ -1,15 +1,16 @@
+// META: script=./resources/run-async-gc.js
 // META: script=./resources/abort-signal-any-memory-tests.js
 
 abortSignalAnyMemoryTests(AbortSignal, AbortController);
 
-test(t => {
+promise_test(async t => {
   let count = 0;
   const controller = new AbortController();
   const signal = controller.signal;
   addEventListener('test', () => { ++count; }, {signal});
 
   // GC should not affect the event dispatch or listener removal below.
-  gc();
+  await runAsyncGC();
 
   dispatchEvent(new Event('test'));
   dispatchEvent(new Event('test'));
@@ -21,7 +22,7 @@
   assert_equals(count, 2);
 }, 'AbortSignalRegistry tracks algorithm handles for event listeners');
 
-test(t => {
+promise_test(async t => {
   let count = 0;
   const controller = new AbortController();
 
@@ -39,14 +40,14 @@
   // GC should not affect the listener removal below. The composite signal
   // above is not held onto by JS, so this test will fail if nothing is
   // holding a reference to it.
-  gc();
+  await runAsyncGC();
 
   controller.abort();
   dispatchEvent(new Event('test2'));
   assert_equals(count, 2);
 }, 'AbortSignalRegistry tracks algorithm handles for event listeners (composite signal)');
 
-promise_test(t => {
+promise_test(async t => {
   const controller = new AbortController();
   let promise;
 
@@ -58,7 +59,9 @@
 
   // Make sure the composite signal isn't GCed even though the lock request
   // doesn't hold onto it.
-  gc();
+  // Note: use high priority GC tasks to ensure they're scheduled before the
+  // locks request promise is resolved.
+  await runAsyncGC({priority: 'user-blocking'});
 
   controller.abort();
   return promise_rejects_dom(t, 'AbortError', promise);
diff --git a/third_party/blink/web_tests/wpt_internal/dom/abort/resources/abort-signal-any-memory-tests.js b/third_party/blink/web_tests/wpt_internal/dom/abort/resources/abort-signal-any-memory-tests.js
index 4b1e2f9..5814a5aa 100644
--- a/third_party/blink/web_tests/wpt_internal/dom/abort/resources/abort-signal-any-memory-tests.js
+++ b/third_party/blink/web_tests/wpt_internal/dom/abort/resources/abort-signal-any-memory-tests.js
@@ -1,5 +1,4 @@
 // Global state that should be prevented from being garbage collected.
-let gRegistry;
 let gController;
 let gController2;
 let gSignals = [];
@@ -7,356 +6,306 @@
 function abortSignalAnyMemoryTests(signalInterface, controllerInterface) {
   const suffix = `(using ${signalInterface.name} and ${controllerInterface.name})`;
 
-  // Schedules a GC to run before any pending finalization registry callbacks.
-  // This depends on user-blocking tasks running at a higher priority than
-  // main-thread V8 tasks.
-  const scheduleHighPriorityGC = () => scheduler.postTask(() => { gc(); }, {priority: 'user-blocking'});
-
   // Use promise tests so tests are not interleaved (to prevent global state
   // from getting clobbered).
-  promise_test(t => {
-    return new Promise((resolve) => {
-      let tokens = [];
-      gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-        tokens.push(token);
-        if (tokens.length == 2) {
-          assert_in_array(1, tokens);
-          assert_in_array(2, tokens);
-          resolve();
-        }
-      }));
+  promise_test(async t => {
+    let wr1;
+    let wr2;
 
-      (function() {
-        let controller1 = new controllerInterface();
-        let controller2 = new controllerInterface();
+    (function() {
+      let controller1 = new controllerInterface();
+      let controller2 = new controllerInterface();
 
-        gSignals.push(controller1.signal);
-        gSignals.push(controller2.signal);
+      gSignals.push(controller1.signal);
+      gSignals.push(controller2.signal);
 
-        signal = signalInterface.any(gSignals);
-        gSignals.push(signal);
+      signal = signalInterface.any(gSignals);
+      gSignals.push(signal);
 
-        gRegistry.register(controller1, 1);
-        gRegistry.register(controller2, 2);
-        controller1 = null;
-        controller2 = null;
-      })();
+      wr1 = new WeakRef(controller1);
+      wr2 = new WeakRef(controller2);
+      controller1 = null;
+      controller2 = null;
+    })();
 
-      gc();
-    });
+    await runAsyncGC();
+
+    assert_equals(wr1.deref(), undefined, 'controller1 should be GCed');
+    assert_equals(wr2.deref(), undefined, 'controller2 should be GCed');
   }, `Controllers can be GCed when their signals are being followed ${suffix}`);
 
-  promise_test(t => {
-    return new Promise((resolve) => {
-      let tokens = [];
-      gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-        tokens.push(token);
-        if (tokens.length == 3) {
-          assert_in_array(1, tokens);
-          assert_in_array(2, tokens);
-          assert_in_array(3, tokens);
-          resolve();
-        }
-      }));
+  promise_test(async t => {
+    let wr1;
+    let wr2;
+    let wr3;
 
-      (function() {
-        let controller1 = new controllerInterface();
-        let controller2 = new controllerInterface();
-        let signal = signalInterface.any([controller1.signal, controller2.signal]);
+    (function() {
+      let controller1 = new controllerInterface();
+      let controller2 = new controllerInterface();
+      let signal = signalInterface.any([controller1.signal, controller2.signal]);
 
-        gRegistry.register(controller1, 1);
-        gRegistry.register(controller2, 2);
-        gRegistry.register(signal, 3);
+      wr1 = new WeakRef(controller1);
+      wr2 = new WeakRef(controller2);
+      wr3 = new WeakRef(signal);
 
-        controller1 = null;
-        controller2 = null;
-        signal = null;
-      })();
+      controller1 = null;
+      controller2 = null;
+      signal = null;
+    })();
 
-      gc();
-    });
+    await runAsyncGC();
+
+    assert_equals(wr1.deref(), undefined, 'controller1 should be GCed');
+    assert_equals(wr2.deref(), undefined, 'controller2 should be GCed');
+    assert_equals(wr3.deref(), undefined, 'signal should be GCed');
   }, `Signals can be GCed when all abort sources have been GCed ${suffix}`);
 
-  promise_test(t => {
-    return new Promise((resolve) => {
-      let tokens = [];
-      gController = new controllerInterface();
-      gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-        tokens.push(token);
-        if (tokens.length == 2) {
-          assert_false(gController.signal.aborted);
-          assert_in_array(1, tokens);
-          assert_in_array(2, tokens);
-          resolve();
-        }
-      }));
+  promise_test(async t => {
+    let wr1;
+    let wr2;
 
-      (function() {
-        let signal1 = signalInterface.any([gController.signal]);
-        let signal2 = signalInterface.any([signal1]);
+    gController = new controllerInterface();
 
-        gRegistry.register(signal1, 1);
-        gRegistry.register(signal2, 2);
+    (function() {
+      let signal1 = signalInterface.any([gController.signal]);
+      let signal2 = signalInterface.any([signal1]);
 
-        signal1 = null;
-        signal2 = null;
-      })();
+      wr1 = new WeakRef(signal1);
+      wr2 = new WeakRef(signal2);
 
-      gc();
-    });
+      signal1 = null;
+      signal2 = null;
+    })();
+
+    await runAsyncGC();
+
+    assert_equals(wr1.deref(), undefined, 'signal1 should be GCed');
+    assert_equals(wr2.deref(), undefined, 'signal2 should be GCed');
   }, `Signals can be GCed when they have no references or event listeners ${suffix}`);
 
-  promise_test(t => {
-    return new Promise((resolve) => {
-      let tokens = [];
-      gController = new controllerInterface();
-      gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-        tokens.push(token);
-        if (tokens.length == 2) {
-          assert_false(gController.signal.aborted);
-          assert_in_array(1, tokens);
-          assert_in_array(2, tokens);
-          resolve();
-        }
-      }));
+  promise_test(async t => {
+    let wr1;
+    let wr2;
 
-      (function() {
-        let signal1 = signalInterface.any([gController.signal]);
-        signal1.addEventListener('event', () => {});
+    gController = new controllerInterface();
 
-        let signal2 = signalInterface.any([signal1]);
-        signal2.addEventListener('event', () => {});
+    (function() {
+      let signal1 = signalInterface.any([gController.signal]);
+      signal1.addEventListener('event', () => {});
 
-        gRegistry.register(signal1, 1);
-        gRegistry.register(signal2, 2);
+      let signal2 = signalInterface.any([signal1]);
+      signal2.addEventListener('event', () => {});
 
-        signal1 = null;
-        signal2 = null;
-      })();
+      wr1 = new WeakRef(signal1);
+      wr2 = new WeakRef(signal2);
 
-      gc();
-    });
+      signal1 = null;
+      signal2 = null;
+    })();
+
+    await runAsyncGC();
+
+    assert_equals(wr1.deref(), undefined, 'signal1 should be GCed');
+    assert_equals(wr2.deref(), undefined, 'signal2 should be GCed');
   }, `Signals can be GCed when they have no references or relevant event listeners ${suffix}`);
 
-  promise_test(t => {
-    return new Promise((resolve) => {
-      let tokens = [];
+  promise_test(async t => {
+    let wr1;
+    let wr2;
 
-      gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-        tokens.push(token);
-        if (tokens.length == 2) {
-          assert_in_array(1, tokens);
-          assert_in_array(2, tokens);
-          resolve();
-        }
-      }));
+    gController = new controllerInterface();
 
-      gController = new controllerInterface();
+    (function() {
+      let signal1 = signalInterface.any([gController.signal]);
+      let signal2 = signalInterface.any([signal1]);
 
-      (function() {
-        let signal1 = signalInterface.any([gController.signal]);
-        let signal2 = signalInterface.any([signal1]);
+      wr1 = new WeakRef(signal1);
+      wr2 = new WeakRef(signal2);
 
-        gRegistry.register(signal1, 1);
-        gRegistry.register(signal2, 2);
+      const abortCallback1 = () => {};
+      const abortCallback2 = () => {};
 
-        const abortCallback1 = () => {};
-        const abortCallback2 = () => {};
+      signal1.addEventListener('abort', abortCallback1);
+      signal1.addEventListener('abort', abortCallback2);
 
-        signal1.addEventListener('abort', abortCallback1);
-        signal1.addEventListener('abort', abortCallback2);
+      signal2.addEventListener('abort', abortCallback1);
+      signal2.addEventListener('abort', abortCallback2);
 
-        signal2.addEventListener('abort', abortCallback1);
-        signal2.addEventListener('abort', abortCallback2);
+      signal1.removeEventListener('abort', abortCallback1);
+      signal1.removeEventListener('abort', abortCallback2);
 
-        signal1.removeEventListener('abort', abortCallback1);
-        signal1.removeEventListener('abort', abortCallback2);
+      signal2.removeEventListener('abort', abortCallback1);
+      signal2.removeEventListener('abort', abortCallback2);
 
-        signal2.removeEventListener('abort', abortCallback1);
-        signal2.removeEventListener('abort', abortCallback2);
+      signal1 = null;
+      signal2 = null;
+    })();
 
-        signal1 = null;
-        signal2 = null;
-      })();
+    await runAsyncGC();
 
-      gc();
-    });
+    assert_equals(wr1.deref(), undefined, 'signal1 should be GCed');
+    assert_equals(wr2.deref(), undefined, 'signal2 should be GCed');
   }, `Signals can be GCed when all abort event listeners have been removed ${suffix}`);
 
-  promise_test(t => {
-    return new Promise((resolve) => {
-      let tokenCount = 0;
-      let fired = false;
+  promise_test(async t => {
+    let fired = false;
 
-      gController = new controllerInterface();
+    gController = new controllerInterface();
 
-      (function() {
-        let signal = signalInterface.any([gController.signal]);
-        signal.onabort = t.step_func((e) => {
-          assert_true(e.target.aborted);
-          resolve();
-        });
+    (function() {
+      let signal = signalInterface.any([gController.signal]);
+      signal.onabort = t.step_func((e) => {
+        fired = true;
+        assert_true(e.target.aborted);
+      });
 
-        signal = null;
-      })();
+      signal = null;
+    })();
 
-      gc();
-      gController.abort();
-    });
+    await runAsyncGC();
+
+    gController.abort();
+    assert_true(fired, 'signal should not be GCed before being aborted');
   }, `Signals are not GCed before being aborted by a controller when they have abort event listeners ${suffix}`);
 
-  promise_test(t => {
-    return new Promise((resolve) => {
-      gController = new controllerInterface();
-      gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-        assert_equals(token, 1);
-        assert_true(fired, 'The abort listener should not run before the signal is GCed');
-        resolve();
-      }));
+  promise_test(async t => {
+    let fired = false;
+    let wr;
 
-      (function() {
-        let signal = signalInterface.any([AbortSignal.timeout(20)]);
-        signal.onabort = t.step_func(() => {
-          fired = true;
-          // GC could also be triggered in this timeout task, so run GC at high
-          // priority to ensure the task finishes before the test.
-          scheduleHighPriorityGC();
-        });
-        gRegistry.register(signal, 1);
-        signal = null;
-      })();
+    gController = new controllerInterface();
 
-      gc();
-    });
+    (function() {
+      let signal = signalInterface.any([AbortSignal.timeout(20)]);
+      signal.onabort = t.step_func(() => {
+        fired = true;
+      });
+      wr = new WeakRef(signal);
+      signal = null;
+    })();
+
+    await runAsyncGC();
+    await t.step_wait(() => fired, 'The abort listener should run before the signal is GCed', 500, 20);
+    await runAsyncGC();
+    assert_equals(wr.deref(), undefined, 'signal should be GCed');
   }, `Composite signals are not GCed before being aborted by timeout when they have abort event listeners ${suffix}`);
 
-  promise_test(t => {
-    return new Promise((resolve) => {
-      let tokenCount = 0;
-      let fired = false;
+  promise_test(async t => {
+    let fired = false;
+    let wr1;
+    let wr2;
 
-      gController = new controllerInterface();
-      gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-        ++tokenCount;
-        if (tokenCount == 1) {
-          assert_equals(token, 1, 'tempCompositeSignal should be GCed first');
-          assert_false(fired, 'The abort listener should not run before tempCompositeSignal is GCed');
-          gController.abort();
-          gc();
-        }
+    gController = new controllerInterface();
 
-        if (tokenCount == 2) {
-          assert_equals(token, 2, 'compositeSignal should be GCed second');
-          assert_true(fired, 'The abort listener should run before compositeSignal is GCed');
-          resolve();
-        }
-      }));
+    (function() {
+      // `tempCompositeSignal` can be GCed after this function because it is
+      // only used to construct `compositeSignal`.
+      let tempCompositeSignal = signalInterface.any([gController.signal]);
+      wr1 = new WeakRef(tempCompositeSignal);
 
-      (function() {
-        // `tempCompositeSignal` can be GCed after this function because it is
-        // only used to construct `compositeSignal`.
-        let tempCompositeSignal = signalInterface.any([gController.signal]);
-        gRegistry.register(tempCompositeSignal, 1);
+      let compositeSignal = signalInterface.any([tempCompositeSignal]);
+      compositeSignal.onabort = t.step_func(() => {
+        fired = true;
+      });
+      wr2 = new WeakRef(compositeSignal);
 
-        let compositeSignal = signalInterface.any([tempCompositeSignal]);
-        compositeSignal.onabort = t.step_func(() => {
-          fired = true;
-        });
-        gRegistry.register(compositeSignal, 2);
+      tempCompositeSignal = null;
+      compositeSignal = null;
+    })();
 
-        tempCompositeSignal = null;
-        compositeSignal = null;
-      })();
+    await runAsyncGC();
 
-      gc();
-    });
+    assert_equals(wr1.deref(), undefined, 'tempCompositeSignal should be GCed');
+    assert_not_equals(wr2.deref(), undefined, 'compositeSignal shound not be GCed yet');
+    assert_false(fired, 'The abort listener should not run before tempCompositeSignal is GCed');
+
+    gController.abort();
+
+    await runAsyncGC();
+
+    assert_equals(wr2.deref(), undefined, 'compositeSignal should be GCed');
+    assert_true(fired, 'The abort listener should run before compositeSignal is GCed');
   }, `Temporary composite signals used for constructing other composite signals can be GCed ${suffix}`);
 
-  promise_test(t => {
-    return new Promise((resolve) => {
-      let tokenCount = 0;
-      let fired = false;
-      let tokens = [];
+  promise_test(async t => {
+    let fired = false;
+    let wr1;
+    let wr2;
+    let wr3;
+    let wr4;
+    let wr5;
 
-      gController = new controllerInterface();
-      gController2 = new controllerInterface();
-      gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-        ++tokenCount;
-        tokens.push(token);
+    gController = new controllerInterface();
+    gController2 = new controllerInterface();
 
-        if (tokenCount == 3) {
-          assert_array_equals(tokens.sort(), [1, 2, 3], 'The temporary signals should be GCed first');
-          assert_false(fired, 'The temporary signals should be GCed before the abort event listener fires');
-        }
+    (function() {
+      // These signals should be GCed after this function runs, before the
+      // timeout aborts `testSignal`.
+      let signal1 = signalInterface.any([gController.signal]);
+      let signal2 = signalInterface.any([gController2.signal]);
+      let signal3 = signalInterface.any([signal1, signal2]);
 
-        if (tokenCount == 5) {
-          assert_true(fired, 'The abort listener should run before compositeSignal is GCed');
-          resolve();
-        }
-      }));
+      wr1 = new WeakRef(signal1);
+      wr2 = new WeakRef(signal2);
+      wr3 = new WeakRef(signal3);
 
-      (function() {
-        // These signals should be GCed after this function runs, before the
-        // timeout aborts `testSignal`.
-        let signal1 = signalInterface.any([gController.signal]);
-        let signal2 = signalInterface.any([gController2.signal]);
-        let signal3 = signalInterface.any([signal1, signal2]);
+      let timeoutSignal = AbortSignal.timeout(20);
+      // This and `timeoutSignal` must remain alive until the timeout fires.
+      let testSignal = signalInterface.any([signal3, timeoutSignal]);
+      testSignal.onabort = t.step_func(() => {
+        fired = true;
+      });
 
-        let timeoutSignal = AbortSignal.timeout(20);
-        // This and `timeoutSignal` must remain alive until the timeout fires.
-        let testSignal = signalInterface.any([signal3, timeoutSignal]);
-        testSignal.onabort = t.step_func(() => {
-          fired = true;
-          scheduleHighPriorityGC();
-        });
+      wr4 = new WeakRef(timeoutSignal);
+      wr5 = new WeakRef(testSignal);
 
-        gRegistry.register(signal1, 1);
-        gRegistry.register(signal2, 2);
-        gRegistry.register(signal3, 3);
-        gRegistry.register(timeoutSignal, 4);
-        gRegistry.register(testSignal, 5);
+      signal1 = null;
+      signal2 = null;
+      signal3 = null;
+      timeoutSignal = null;
+      testSignal = null;
+    })();
 
-        signal1 = null;
-        signal2 = null;
-        signal3 = null;
-        timeoutSignal = null;
-        testSignal = null;
-      })();
+    // Running GC async in high priority tasks should complete before the timeout.
+    await runAsyncGC({priority: 'user-blocking'});
+    assert_false(fired, 'GC should complete before the timeout fires');
+    assert_equals(wr1.deref(), undefined, 'signal1 should be GCed');
+    assert_equals(wr2.deref(), undefined, 'signal2 should be GCed');
+    assert_equals(wr3.deref(), undefined, 'signal3 should be GCed');
+    assert_not_equals(wr4.deref(), undefined, 'timeoutSignal should not be GCed before the timeout');
+    assert_not_equals(wr5.deref(), undefined, 'testSignal should not be GCed before the timeout');
 
-      gc();
-    });
+    await t.step_wait(() => fired, 'The abort listener should run before the signal is GCed', 500, 20);
+
+    await runAsyncGC();
+    assert_equals(wr4.deref(), undefined, 'timeoutSignal should be GCed');
+    assert_equals(wr5.deref(), undefined, 'testSignal should be GCed');
   }, `Nested and intermediate composite signals can be GCed when expected ${suffix}`);
 
-  promise_test(t => {
-    return new Promise((resolve) => {
-      let tokenCount = 0;
-      gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-        ++tokenCount;
-        if (tokenCount == 2) {
-          resolve();
-        }
-      }));
+  promise_test(async t => {
+    let wr1;
+    let wr2;
 
-      (function() {
-        let signal1 = signalInterface.any([]);
-        signal1.addEventListener('abort', () => {});
-        // For plain AbortSignals, this should not be a no-op. For TaskSignals,
-        // this will test the settling logic.
-        signal1.addEventListener('prioritychange', () => {});
-        gRegistry.register(signal1, 1);
+    (function() {
+      let signal1 = signalInterface.any([]);
+      signal1.addEventListener('abort', () => {});
+      // For plain AbortSignals, this should not be a no-op. For TaskSignals,
+      // this will test the settling logic.
+      signal1.addEventListener('prioritychange', () => {});
+      wr1 = new WeakRef(signal1);
 
-        let controller = new controllerInterface();
-        let signal2 = signalInterface.any([controller.signal]);
-        signal2.addEventListener('abort', () => {});
-        signal2.addEventListener('prioritychange', () => {});
-        gRegistry.register(signal2, 2);
+      let controller = new controllerInterface();
+      let signal2 = signalInterface.any([controller.signal]);
+      signal2.addEventListener('abort', () => {});
+      signal2.addEventListener('prioritychange', () => {});
+      wr2 = new WeakRef(signal2);
 
-        signal1 = null;
-        signal2 = null;
-        controller = null;
-      })();
+      signal1 = null;
+      signal2 = null;
+      controller = null;
+    })();
 
-      gc();
-    });
+    await runAsyncGC();
+    assert_equals(wr1.deref(), undefined, 'signal1 should be GCed');
+    assert_equals(wr2.deref(), undefined, 'signal2 should be GCed');
   }, `Settled composite signals with event listeners can be GCed ${suffix}`);
 }
diff --git a/third_party/blink/web_tests/wpt_internal/dom/abort/resources/run-async-gc.js b/third_party/blink/web_tests/wpt_internal/dom/abort/resources/run-async-gc.js
new file mode 100644
index 0000000..548645da
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/dom/abort/resources/run-async-gc.js
@@ -0,0 +1,11 @@
+async function runAsyncGC(args = {}) {
+  // Run gc in a loop to ensure anything needing more than one cycle can be
+  // collected, e.g. due to dependencies. Note this is similar to
+  // ThreadState::CollectAllGarbageForTesting, but async and with 2 less
+  // iterations.
+  for (let i = 0; i < 3; i++) {
+    // crbug.com/1474629: invoking gc({execution: 'async'}) trips leak
+    // detection, so use postTask and run sync gc() to do async GC.
+    await scheduler.postTask(() => { gc(); }, args);
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort.any.js b/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort-1.any.js
similarity index 69%
rename from third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort.any.js
rename to third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort-1.any.js
index 09c5b39a..f7ab2148 100644
--- a/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort.any.js
+++ b/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort-1.any.js
@@ -1,4 +1,4 @@
+// META: script=../dom/abort/resources/run-async-gc.js
 // META: script=../dom/abort/resources/abort-signal-any-memory-tests.js
 
 abortSignalAnyMemoryTests(TaskSignal, AbortController);
-abortSignalAnyMemoryTests(TaskSignal, TaskController);
diff --git a/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort.any.js b/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort-2.any.js
similarity index 69%
copy from third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort.any.js
copy to third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort-2.any.js
index 09c5b39a..125b3d4 100644
--- a/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort.any.js
+++ b/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-abort-2.any.js
@@ -1,4 +1,4 @@
+// META: script=../dom/abort/resources/run-async-gc.js
 // META: script=../dom/abort/resources/abort-signal-any-memory-tests.js
 
-abortSignalAnyMemoryTests(TaskSignal, AbortController);
 abortSignalAnyMemoryTests(TaskSignal, TaskController);
diff --git a/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-priority.any.js b/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-priority.any.js
index ee28c3a..19b5237 100644
--- a/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-priority.any.js
+++ b/third_party/blink/web_tests/wpt_internal/scheduler/task-signal-any-memory-priority.any.js
@@ -1,157 +1,152 @@
+// META: script=../dom/abort/resources/run-async-gc.js
+
 // Global state that should be prevented from being garbage collected.
-let gRegistry;
 let gController;
 let gSignals = [];
 
 // The tests below rely on the same global state, which each test manipulates.
 // Use promise_tests so tests are not interleaved, otherwise the global state
 // can change unexpectedly.
-promise_test(t => {
-  return new Promise((resolve) => {
-    let tokens = [];
-    gController = new TaskController();
-    gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-      tokens.push(token);
-      if (tokens.length == 3) {
-        assert_in_array(1, tokens);
-        assert_in_array(2, tokens);
-        assert_in_array(3, tokens);
-        resolve();
-      }
-    }));
+promise_test(async t => {
+  let wr1;
+  let wr2;
+  let wr3;
 
-    (function() {
-      let signal1 = TaskSignal.any([], {priority: gController.signal});
-      let signal2 = TaskSignal.any([gController.signal], {priority: gController.signal});
-      let signal3 = TaskSignal.any([signal2]);
+  gController = new TaskController();
 
-      gRegistry.register(signal1, 1);
-      gRegistry.register(signal2, 2);
-      gRegistry.register(signal3, 3);
+  (function() {
+    let signal1 = TaskSignal.any([], {priority: gController.signal});
+    let signal2 = TaskSignal.any([gController.signal], {priority: gController.signal});
+    let signal3 = TaskSignal.any([signal2]);
 
-      signal1 = null;
-      signal2 = null;
-      signal3 = null;
-    })();
+     wr1 = new WeakRef(signal1);
+     wr2 = new WeakRef(signal2);
+     wr3 = new WeakRef(signal3);
 
-    gc();
-  });
+    signal1 = null;
+    signal2 = null;
+    signal3 = null;
+  })();
+
+  await runAsyncGC();
+
+  assert_equals(wr1.deref(), undefined, 'signal1 should be GCed');
+  assert_equals(wr2.deref(), undefined, 'signal2 should be GCed');
+  assert_equals(wr3.deref(), undefined, 'signal3 should be GCed');
 }, "TaskSignals can be GCed when they have no references or event listeners");
 
-promise_test(t => {
-  return new Promise((resolve) => {
-    let tokens = [];
-    gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-      tokens.push(token);
-      if (tokens.length == 2) {
-        assert_in_array(1, tokens);
-        assert_in_array(2, tokens);
-        resolve();
-      }
-    }));
+promise_test(async t => {
+  let wr1;
+  let wr2;
 
-    (function() {
-      let controller = new TaskController();
-      let signal = TaskSignal.any([], {priority: controller.signal});
-      signal.onprioritychange = () => {};
+  (function() {
+    let controller = new TaskController();
+    let signal = TaskSignal.any([], {priority: controller.signal});
+    signal.onprioritychange = () => {};
 
-      gRegistry.register(controller, 1);
-      gRegistry.register(signal, 2);
+    wr1 = new WeakRef(controller);
+    wr2 = new WeakRef(signal);
 
-      controller = null;
-      signal = null;
-    })();
+    controller = null;
+    signal = null;
+  })();
 
-    gc();
-  });
+  await runAsyncGC();
+  assert_equals(wr1.deref(), undefined, 'controller should be GCed');
+  assert_equals(wr2.deref(), undefined, 'signal should be GCed');
 }, "A TaskSignal with a prioritychange listener can be GCed when its priority source has been GCed");
 
-promise_test(t => {
-  return new Promise((resolve) => {
-    (function() {
-      gController = new TaskController();
-      let signal = TaskSignal.any([], {priority: gController.signal});
-      signal.onprioritychange = t.step_func((e) => {
-        assert_equals(e.target.priority, 'background');
-        resolve();
-      });
-      signal = null;
-    })();
+promise_test(async t => {
+  let fired = false;
 
-    gc();
-    gController.setPriority('background');
-  });
+  (function() {
+    gController = new TaskController();
+    let signal = TaskSignal.any([], {priority: gController.signal});
+    signal.onprioritychange = t.step_func((e) => {
+      assert_equals(e.target.priority, 'background', 'Priority should change to background');
+      fired = true;
+    });
+    signal = null;
+  })();
+
+  await runAsyncGC();
+  gController.setPriority('background');
+  assert_true(fired, 'prioritchange event should fire');
 }, "TaskSignals with prioritychange listeners are not GCed if their priority source is alive");
 
-promise_test(t => {
-  return new Promise((resolve) => {
-    (function() {
-      gController = new TaskController();
-      let controller = new AbortController();
-      let signal = TaskSignal.any([controller.signal], {priority: gController.signal});
-      signal.onprioritychange = t.step_func((e) => {
-        assert_equals(e.target.priority, 'background');
-        resolve();
-      });
-      signal = null;
-      controller = null;
-    })();
+promise_test(async t => {
+  (function() {
+    gController = new TaskController();
+    let controller = new AbortController();
+    let signal = TaskSignal.any([controller.signal], {priority: gController.signal});
+    signal.onprioritychange = t.step_func((e) => {
+      assert_equals(e.target.priority, 'background', 'Priority should change to background');
+      fired = true;
+    });
+    signal = null;
+    controller = null;
+  })();
 
-    gc();
-    gController.setPriority('background');
-  });
+  await runAsyncGC();
+  gController.setPriority('background');
+  assert_true(fired, 'prioritchange event should fire');
 }, "TaskSignals with prioritychange listeners are not GCed after their abort source is GCed if their priority source is alive");
 
-promise_test(t => {
-  return new Promise((resolve) => {
-    (function() {
-      gController = new TaskController();
-      let controller = new AbortController();
-      let signal = TaskSignal.any([controller.signal], {priority: gController.signal});
-      signal.onprioritychange = t.step_func((e) => {
-        assert_equals(e.target.priority, 'background');
-        resolve();
-      });
+promise_test(async t => {
+  let fired = true;
 
-      let abortFired = false;
-      signal.onabort = t.step_func(() => {
-        abortFired = true;
-      });
-      controller.abort();
-      assert_true(abortFired);
+  (function() {
+    gController = new TaskController();
+    let controller = new AbortController();
+    let signal = TaskSignal.any([controller.signal], {priority: gController.signal});
+    signal.onprioritychange = t.step_func((e) => {
+      assert_equals(e.target.priority, 'background');
+      fired = true;
+    });
 
-      signal = null;
-      controller = null;
-    })();
+    let abortFired = false;
+    signal.onabort = t.step_func(() => {
+      abortFired = true;
+    });
+    controller.abort();
+    assert_true(abortFired);
 
-    gc();
-    gController.setPriority('background');
-  });
+    signal = null;
+    controller = null;
+  })();
+
+  await runAsyncGC();
+  gController.setPriority('background');
+  assert_true(fired, 'prioritchange event should fire');
 }, "TaskSignals with prioritychange listeners are not GCed after they are aborted if their priority source is alive");
 
-promise_test(t => {
-  return new Promise((resolve) => {
-    let runCount = 0;
-    gRegistry = new FinalizationRegistry(t.step_func(function(token) {
-      assert_equals(token, 1);
-      assert_equals(runCount, 3);
-      resolve();
-    }));
-    gController = new TaskController({priority: 'background'});
+promise_test(async t => {
+  let runCount = 0;
+  gController = new TaskController({priority: 'background'});
+  const tasks = [];
 
-    (function() {
-      let signal = TaskSignal.any([], {priority: gController.signal});
-      scheduler.postTask(() => { ++runCount; }, {signal});
-      scheduler.postTask(() => { ++runCount; }, {signal});
-      scheduler.postTask(() => { ++runCount; }, {signal});
+  (function() {
+    let signal = TaskSignal.any([], {priority: gController.signal});
+    scheduler.postTask(() => { ++runCount; }, {signal});
+    scheduler.postTask(() => { ++runCount; }, {signal});
+    scheduler.postTask(() => { ++runCount; }, {signal});
 
-      // Finally, gc in a separate task so `signal` can be GCed.
-      scheduler.postTask(() => { gc(); }, {priority: 'background'});
+    wr = new WeakRef(signal);
+    signal = null;
+  })();
 
-      gRegistry.register(signal, 1);
-      signal = null;
-    })();
+  // Since this runs at higher than background priority, nothing should have
+  // happened yet.
+  await runAsyncGC();
+  assert_not_equals(wr.deref(), undefined, 'signal should not have been GCed yet');
 
-    gc();
-  });
+  // Let the background tasks run.
+  // NB: we don't use the task promises since the signal will be propagated for
+  // yield inheritance.
+  await scheduler.postTask(() => {}, {priority: 'background'});
+  assert_equals(runCount, 3, '3 tasks should have run');
+
+  // Finally, run gc so `signal` can be GCed.
+  await runAsyncGC();
+  assert_equals(wr.deref(), undefined, 'signal should have been GCed');
 }, "Composite TaskSignals with pending tasks are not GCed if their priority source is alive");
diff --git a/tools/clang/plugins/tests/bad_raw_ptr_cast_kinds.txt b/tools/clang/plugins/tests/bad_raw_ptr_cast_kinds.txt
index 43f9b2a2..3523478 100644
--- a/tools/clang/plugins/tests/bad_raw_ptr_cast_kinds.txt
+++ b/tools/clang/plugins/tests/bad_raw_ptr_cast_kinds.txt
@@ -6,8 +6,10 @@
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ./base/allocator/partition_allocator/pointers/raw_ptr.h:11:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'RawPtrWrapper' to 'const raw_ptr<int>' for 1st argument
 class raw_ptr {
-      ^
+      ^~~~~~~
 ./base/allocator/partition_allocator/pointers/raw_ptr.h:11:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'RawPtrWrapper' to 'raw_ptr<int>' for 1st argument
+class raw_ptr {
+      ^~~~~~~
 ./base/allocator/partition_allocator/pointers/raw_ptr.h:11:7: note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
 bad_raw_ptr_cast_kinds.cpp:57:9: error: cannot cast from type 'RawPtrWrapper' to pointer type 'int *'
   (void)static_cast<int*>(wrapped);
diff --git a/tools/licenses/licenses.py b/tools/licenses/licenses.py
index d2827cfc..ffc4f24 100755
--- a/tools/licenses/licenses.py
+++ b/tools/licenses/licenses.py
@@ -17,6 +17,8 @@
 
 import argparse
 import codecs
+import csv
+import io
 import json
 import logging
 import os
@@ -1073,16 +1075,90 @@
                                           args.spdx_doc_namespace)
   elif args.format == 'txt':
     license_txt = GenerateLicenseFilePlainText(metadatas)
+
+  elif args.format == 'csv':
+    license_txt = GenerateLicenseFileCsv(metadatas)
+
   else:
     raise ValueError(f'Unknown license format: {args.format}')
 
   if args.output_file:
     with open(args.output_file, 'w', encoding='utf-8') as f:
       f.write(license_txt)
+      print(f"\n ---- \nWrote license data to file {args.output_file}")
   else:
     print(license_txt)
 
 
+def GenerateLicenseFileCsv(
+    metadata: Dict[str, Dict[str, Any]],
+    repo_root: str = _REPOSITORY_ROOT,
+) -> str:
+  """Generates a CSV formatted file which contains license data to be used as
+    part of the submission to the Open Source Licensing Review process.
+  """
+  csv_content = io.StringIO()
+  csv_writer = csv.writer(csv_content, quoting=csv.QUOTE_NONNUMERIC)
+
+  # These values are applied statically to all dependencies which are included
+  # in the exported CSV.
+  # Static fields:
+  #   * Name of binary which uses dependency,
+  #   * License text for library included in product,
+  #   * Mirrored source for reciprocal licences.
+  #   * Signoff date.
+  static_data = ["Chromium", "Yes", "Yes", "N/A"]
+
+  # Add informative CSV header row to make it clear which columns represent
+  # which data in the review spreadsheet.
+  csv_writer.writerow([
+      "Library Name", "Link to LICENSE file", "License Name",
+      "Binary which uses library", "License text for library included?",
+      "Source code for library includes the mirrored source?",
+      "Authorization date"
+  ])
+
+  # Start with Chromium's LICENSE file
+  csv_writer.writerow([
+      "Chromium",
+      "https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/LICENSE",
+      "Chromium"
+  ] + static_data)
+
+  # Add necessary third_party.
+  for directory in sorted(metadata):
+    dir_metadata = metadata[directory]
+
+    # Only third party libraries which are shipped as part of a final product
+    # are in scope for license review.
+    if dir_metadata['Shipped'] == NO:
+      continue
+
+    data_row = [dir_metadata['Name'] or "UNKNOWN"]
+
+    urls = []
+    for lic in dir_metadata['License File']:
+      # The review process requires that a link is provided to each license
+      # which is included. We can achieve this by combining a static
+      # Chromium googlesource URL with the relative path to the license
+      # file from the top level Chromium src directory.
+      lic_url = (
+          "https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/"
+          + os.path.relpath(lic, repo_root))
+
+      # Since these are URLs and not paths, replace any Windows path `\`
+      # separators with a `/`
+      urls.append(lic_url.replace("\\", "/"))
+
+    data_row.append(", ".join(urls) or "UNKNOWN")
+    data_row.append(dir_metadata["License"] or "UNKNOWN")
+
+    # Join the default data which applies to each row
+    csv_writer.writerow(data_row + static_data)
+
+  return csv_content.getvalue()
+
+
 def GenerateLicenseFilePlainText(
     metadata: Dict[str, Dict[str, Any]],
     repo_root: str = _REPOSITORY_ROOT,
@@ -1175,7 +1251,7 @@
   parser.add_argument('--gn-target', help='GN target to scan for dependencies.')
   parser.add_argument('--format',
                       default='txt',
-                      choices=['txt', 'spdx'],
+                      choices=['txt', 'spdx', 'csv'],
                       help='What format to output in')
   parser.add_argument('--spdx-root',
                       default=_REPOSITORY_ROOT,
diff --git a/tools/licenses/licenses_test.py b/tools/licenses/licenses_test.py
index 77e900d..67d54a8 100755
--- a/tools/licenses/licenses_test.py
+++ b/tools/licenses/licenses_test.py
@@ -5,6 +5,8 @@
 """Unit tests for //tools/licenses/licenses.py.
 """
 
+import csv
+import io
 import os
 import pathlib
 import sys
@@ -28,6 +30,7 @@
         os.path.join('third_party', 'lib1'): {
             'Name': 'lib1',
             'Shipped': 'yes',
+            'License': 'MIT',
             'License File': [os.path.join('third_party', 'lib1', 'LICENSE')],
         },
         os.path.join('third_party', 'lib2'): {
@@ -35,6 +38,8 @@
             'lib2',
             'Shipped':
             'yes',
+            'License':
+            'MIT, Apache 2.0',
             'License File': [
                 os.path.join('third_party', 'lib2', 'LICENSE-A'),
                 os.path.join('third_party', 'lib2', 'LICENSE-B'),
@@ -50,6 +55,8 @@
             'lib_unshipped',
             'Shipped':
             'no',
+            'License':
+            '',
             'License File': [
                 os.path.join('third_party', 'lib_unshipped', 'LICENSE'),
             ],
@@ -57,18 +64,21 @@
         os.path.join('third_party', 'lib3'): {
             'Name': 'lib3',
             'Shipped': 'yes',
+            'License': '',
             'License File': [os.path.join('third_party', 'lib3', 'LICENSE')],
         },
         os.path.join('third_party', 'lib3-v1'): {
             # Test SPDX license file dedup. (different name, same license file)
             'Name': 'lib3-v1',
             'Shipped': 'yes',
+            'License': 'Apache 2.0',
             'License File': [os.path.join('third_party', 'lib3', 'LICENSE')],
         },
         os.path.join('third_party', 'lib3-v2'): {
             # Test SPDX id dedup. (same name, different license file)
             'Name': 'lib3',
             'Shipped': 'yes',
+            'License': 'BSD',
             'License File': [os.path.join('third_party', 'lib3-v2', 'LICENSE')],
         },
     }
@@ -128,6 +138,78 @@
             os.path.join('external', 'somelib'),
         ]))
 
+  def test_generate_license_file_csv(self):
+    # This is the same for all the links and prevents wildly long strings.
+    prefix = "https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/"
+
+    csv_file = io.StringIO(licenses.GenerateLicenseFileCsv(
+        self._get_metadata()))
+    csv_rows = [row for row in csv.DictReader(csv_file)]
+
+    expected = [{
+        'Library Name': 'Chromium',
+        'Link to LICENSE file': f'{prefix}LICENSE',
+        'License Name': 'Chromium',
+        'Binary which uses library': 'Chromium',
+        'License text for library included?': 'Yes',
+        'Source code for library includes the mirrored source?': 'Yes',
+        'Authorization date': 'N/A'
+    }, {
+        'Library Name': 'lib1',
+        'Link to LICENSE file':
+        f'{prefix}tools/licenses/third_party/lib1/LICENSE',
+        'License Name': 'MIT',
+        'Binary which uses library': 'Chromium',
+        'License text for library included?': 'Yes',
+        'Source code for library includes the mirrored source?': 'Yes',
+        'Authorization date': 'N/A'
+    }, {
+        'Library Name':
+        'lib2',
+        'Link to LICENSE file':
+        (f'{prefix}tools/licenses/third_party/lib2/LICENSE-A, '
+         f'{prefix}tools/licenses/third_party/lib2/LICENSE-B'),
+        'License Name':
+        'MIT, Apache 2.0',
+        'Binary which uses library':
+        'Chromium',
+        'License text for library included?':
+        'Yes',
+        'Source code for library includes the mirrored source?':
+        'Yes',
+        'Authorization date':
+        'N/A'
+    }, {
+        'Library Name': 'lib3',
+        'Link to LICENSE file':
+        f'{prefix}tools/licenses/third_party/lib3/LICENSE',
+        'License Name': 'UNKNOWN',
+        'Binary which uses library': 'Chromium',
+        'License text for library included?': 'Yes',
+        'Source code for library includes the mirrored source?': 'Yes',
+        'Authorization date': 'N/A'
+    }, {
+        'Library Name': 'lib3-v1',
+        'Link to LICENSE file':
+        f'{prefix}tools/licenses/third_party/lib3/LICENSE',
+        'License Name': 'Apache 2.0',
+        'Binary which uses library': 'Chromium',
+        'License text for library included?': 'Yes',
+        'Source code for library includes the mirrored source?': 'Yes',
+        'Authorization date': 'N/A'
+    }, {
+        'Library Name': 'lib3',
+        'Link to LICENSE file':
+        f'{prefix}tools/licenses/third_party/lib3-v2/LICENSE',
+        'License Name': 'BSD',
+        'Binary which uses library': 'Chromium',
+        'License text for library included?': 'Yes',
+        'Source code for library includes the mirrored source?': 'Yes',
+        'Authorization date': 'N/A'
+    }]
+
+    self.assertEqual(csv_rows, expected)
+
   def test_generate_license_file_txt(self):
     read_file_vals = [
         'root license text\n',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9ecbaf45..9f4110b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -64050,6 +64050,7 @@
   <int value="-180056644" label="HomeButtonWithText:disabled"/>
   <int value="-179580377" label="CrossOriginOpenerPolicy:enabled"/>
   <int value="-178364053" label="TerminalSystemAppLegacySettings:enabled"/>
+  <int value="-178359490" label="DrawImmediatelyWhenInteractive:enabled"/>
   <int value="-177974995" label="CrostiniShowMicSetting:disabled"/>
   <int value="-177085741"
       label="EnableEphemeralGuestProfilesOnDesktop:disabled"/>
@@ -64886,6 +64887,7 @@
       label="FriendlierSafeBrowsingSettingsStandardProtection:disabled"/>
   <int value="240856309" label="MimeHandlerViewInCrossProcessFrame:enabled"/>
   <int value="241187301" label="BrowserTouchBar:disabled"/>
+  <int value="244040049" label="DrawImmediatelyWhenInteractive:disabled"/>
   <int value="244697230" label="enable-theme-color-in-tabbed-mode"/>
   <int value="245100553" label="PcieBillboardNotification:enabled"/>
   <int value="245896533" label="SearchSuggestionsOnLocalNtp:enabled"/>
@@ -96663,6 +96665,7 @@
   <int value="1" label="ServiceWorker"/>
   <int value="2" label="Without ServiceWorker"/>
   <int value="3" label="SubresourceLoader is handling redirect"/>
+  <int value="4" label="AutoPreload is handling fallback"/>
 </enum>
 
 <enum name="ServiceWorkerInstalledScriptsManager.FinishedReason">
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 9f0c925..b6d0bed 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -4464,6 +4464,17 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.NotificationPopup.OnTopOfBubbleCount" units="popups"
+    expires_after="2024-08-22">
+  <owner>leandre@chromium.org</owner>
+  <owner>cros-status-area-eng@google.com</owner>
+  <summary>
+    Record the number of popups that show up on top of a tray bubble. Emitted
+    when a tray bubble is shown or change height, and when there's a new
+    notification popup added when a tray bubble is open.
+  </summary>
+</histogram>
+
 <histogram
     name="Ash.NotificationView.ConvertSingleToGroup.{Animation}.AnimationSmoothness"
     units="%" expires_after="2024-05-14">
diff --git a/tools/metrics/histograms/metadata/input/histograms.xml b/tools/metrics/histograms/metadata/input/histograms.xml
index 0681af2..e9dcd3e 100644
--- a/tools/metrics/histograms/metadata/input/histograms.xml
+++ b/tools/metrics/histograms/metadata/input/histograms.xml
@@ -1475,6 +1475,26 @@
   </summary>
 </histogram>
 
+<histogram
+    name="InputMethod.TouchSelection.{TouchSelectionResult}Session.TouchDownCount"
+    units="units" expires_after="2024-02-02">
+  <owner>michellegc@google.com</owner>
+  <owner>essential-inputs-team@google.com</owner>
+  <summary>
+    The number of touch down movements made by a user in a 'successful'
+    {TouchSelectionResult} session. A session starts from the first touch down
+    that activates touch selection and ends 'successfully' if an editing action
+    occurs after {TouchSelectionResult}, e.g. typing a character or using the
+    menu cut, copy or paste actions. The touch down count is recorded at the end
+    of a successful session (and is not recorded for sessions that end due to
+    the window closing, timing out after 10s of inactivity, etc.).
+  </summary>
+  <token key="TouchSelectionResult">
+    <variant name="Cursor" summary="cursor placement"/>
+    <variant name="Selection" summary="text selection"/>
+  </token>
+</histogram>
+
 <histogram name="InputMethod.VirtualKeyboard.BackspaceCount" units="units"
     expires_after="2023-12-24">
   <owner>shend@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/nearby/histograms.xml b/tools/metrics/histograms/metadata/nearby/histograms.xml
index cef83c0..280f2db 100644
--- a/tools/metrics/histograms/metadata/nearby/histograms.xml
+++ b/tools/metrics/histograms/metadata/nearby/histograms.xml
@@ -353,6 +353,18 @@
   </summary>
 </histogram>
 
+<histogram name="Nearby.Presence.Credentials.Download.ServerRequestDuration"
+    units="ms" expires_after="2024-01-05">
+  <owner>julietlevesque@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records time spent in milliseconds to receive a response from the Nearby
+    Presence Web Server after a download request for remote devices'
+    credentials. Emitted after a successful response from the server. Note that
+    there is a timeout at 5 seconds.
+  </summary>
+</histogram>
+
 <histogram name="Nearby.Presence.Credentials.FirstTimeRegistration.Result"
     enum="NearbyPresenceFirstTimeRegistrationResult" expires_after="2024-01-05">
   <owner>julietlevesque@google.com</owner>
@@ -428,6 +440,18 @@
   </summary>
 </histogram>
 
+<histogram name="Nearby.Presence.Credentials.Upload.ServerRequestDuration"
+    units="ms" expires_after="2024-01-05">
+  <owner>julietlevesque@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records time spent in milliseconds to receive a response from the Nearby
+    Presence Web Server after an upload request for the local device's
+    credentials. Emitted after a successful response from the server. Note that
+    there is a timeout at 5 seconds.
+  </summary>
+</histogram>
+
 <histogram
     name="Nearby.Share.BackgroundScanning.DeviceNearbySharing.Notification.Flow"
     enum="NearbyShareBackgroundScanningDeviceNearbySharingNotificationFlowEvent"
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index 5464fdf9..f776049 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -328,6 +328,14 @@
   return base::FeatureList::IsEnabled(::features::kReadAnythingWebUIToolbar);
 }
 
+BASE_FEATURE(kReadAnythingReadAloud,
+             "ReadAnythingReadAloud",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+bool IsReadAnythingReadAloudEnabled() {
+  return base::FeatureList::IsEnabled(::features::kReadAnythingReadAloud);
+}
+
 BASE_FEATURE(kPdfOcr, "PdfOcr", base::FEATURE_DISABLED_BY_DEFAULT);
 
 bool IsPdfOcrEnabled() {
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h
index 846fb8e..99a3ae3 100644
--- a/ui/accessibility/accessibility_features.h
+++ b/ui/accessibility/accessibility_features.h
@@ -240,6 +240,11 @@
 // If enabled, use the WebUI toolbar in Read Anything.
 AX_BASE_EXPORT bool IsReadAnythingWebUIToolbarEnabled();
 
+AX_BASE_EXPORT BASE_DECLARE_FEATURE(kReadAnythingReadAloud);
+
+// If enabled, show the Read Aloud feature in Read Anything.
+AX_BASE_EXPORT bool IsReadAnythingReadAloudEnabled();
+
 // Enables a feature whereby inaccessible (i.e. untagged) PDFs are made
 // accessible using an optical character recognition service. Due to the size of
 // the OCR component, this feature targets desktop versions of Chrome for now.
diff --git a/ui/file_manager/file_manager/foreground/js/crostini_controller.js b/ui/file_manager/file_manager/foreground/js/crostini_controller.js
index aa08ba24..e076b2b 100644
--- a/ui/file_manager/file_manager/foreground/js/crostini_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/crostini_controller.js
@@ -8,7 +8,7 @@
 import {str, strf, util} from '../../common/js/util.js';
 import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js';
 import {Crostini} from '../../externs/background/crostini.js';
-import {addUiEntry, removeUiEntry} from '../../state/actions/ui_entries.js';
+import {addUiEntry, removeUiEntry} from '../../state/ducks/ui_entries.js';
 import {crostiniPlaceHolderKey} from '../../state/ducks/volumes.js';
 import {getStore} from '../../state/store.js';
 
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 8f41eb3..0cf374c2 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -33,9 +33,9 @@
 import {PropStatus} from '../../externs/ts/state.js';
 import {Store} from '../../externs/ts/store.js';
 import {updatePreferences} from '../../state/actions/preferences.js';
-import {addUiEntry, removeUiEntry} from '../../state/actions/ui_entries.js';
 import {updateBulkPinProgress} from '../../state/ducks/bulk_pinning.js';
 import {updateSearch} from '../../state/ducks/search.js';
+import {addUiEntry, removeUiEntry} from '../../state/ducks/ui_entries.js';
 import {trashRootKey} from '../../state/ducks/volumes.js';
 import {getMyFiles} from '../../state/reducers/all_entries.js';
 import {getEmptyState, getStore} from '../../state/store.js';
diff --git a/ui/file_manager/file_manager/foreground/js/guest_os_controller.js b/ui/file_manager/file_manager/foreground/js/guest_os_controller.js
index ad8e7ca..070a09a 100644
--- a/ui/file_manager/file_manager/foreground/js/guest_os_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/guest_os_controller.js
@@ -7,7 +7,7 @@
 import {util} from '../../common/js/util.js';
 import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js';
 import {VolumeManager} from '../../externs/volume_manager.js';
-import {addUiEntry, removeUiEntry} from '../../state/actions/ui_entries.js';
+import {addUiEntry, removeUiEntry} from '../../state/ducks/ui_entries.js';
 import {getEntry, getStore} from '../../state/store.js';
 
 import {DirectoryModel} from './directory_model.js';
@@ -69,23 +69,20 @@
       }
     }
 
-    const newGuestOsPlaceholders =
-        guests.map(guest => {
-          const guestOsEntry =
-              new GuestOsPlaceholder(guest.displayName, guest.id, guest.vmType);
-          const navigationModelItem = new NavigationModelFakeItem(
-              guest.displayName, NavigationModelItemType.GUEST_OS,
-              guestOsEntry);
-          const volumeType =
-              guest.vmType == chrome.fileManagerPrivate.VmType.ARCVM ?
-              VolumeManagerCommon.VolumeType.ANDROID_FILES :
-              VolumeManagerCommon.VolumeType.GUEST_OS;
+    const newGuestOsPlaceholders = guests.map(guest => {
+      const guestOsEntry =
+          new GuestOsPlaceholder(guest.displayName, guest.id, guest.vmType);
+      const navigationModelItem = new NavigationModelFakeItem(
+          guest.displayName, NavigationModelItemType.GUEST_OS, guestOsEntry);
+      const volumeType =
+          guest.vmType == chrome.fileManagerPrivate.VmType.ARCVM ?
+          VolumeManagerCommon.VolumeType.ANDROID_FILES :
+          VolumeManagerCommon.VolumeType.GUEST_OS;
 
-          navigationModelItem.disabled =
-              this.volumeManager_.isDisabled(volumeType);
-          store.dispatch(addUiEntry({entry: guestOsEntry}));
-          return navigationModelItem;
-        });
+      navigationModelItem.disabled = this.volumeManager_.isDisabled(volumeType);
+      store.dispatch(addUiEntry({entry: guestOsEntry}));
+      return navigationModelItem;
+    });
 
     if (!util.isFilesAppExperimental()) {
       this.directoryTree_.dataModel.guestOsPlaceholders =
diff --git a/ui/file_manager/file_manager/state/actions.ts b/ui/file_manager/file_manager/state/actions.ts
index 74571c2..20e3526 100644
--- a/ui/file_manager/file_manager/state/actions.ts
+++ b/ui/file_manager/file_manager/state/actions.ts
@@ -8,9 +8,9 @@
 import {AddFolderShortcutAction, RefreshFolderShortcutAction, RemoveFolderShortcutAction} from './actions/folder_shortcuts.js';
 import {RefreshNavigationRootsAction, UpdateNavigationEntryAction} from './actions/navigation.js';
 import {UpdatePreferencesAction} from './actions/preferences.js';
-import {AddUiEntryAction, RemoveUiEntryAction} from './actions/ui_entries.js';
 import {UpdateBulkPinProgressAction} from './ducks/bulk_pinning.js';
 import {SearchAction} from './ducks/search.js';
+import {AddUiEntryAction, RemoveUiEntryAction} from './ducks/ui_entries.js';
 import {AddVolumeAction, RemoveVolumeAction, UpdateIsInteractiveVolumeAction} from './ducks/volumes.js';
 
 /**
diff --git a/ui/file_manager/file_manager/state/actions/ui_entries.ts b/ui/file_manager/file_manager/state/actions/ui_entries.ts
deleted file mode 100644
index 32b5f13a..0000000
--- a/ui/file_manager/file_manager/state/actions/ui_entries.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {FakeEntryImpl} from '../../common/js/files_app_entry_types.js';
-import {FileKey} from '../../externs/ts/state.js';
-import {BaseAction} from '../../lib/base_store.js';
-import {ActionType} from '../actions.js';
-
-/**
- * Actions for UI entries.
- *
- * UI entries represents entries shown on UI only (aka FakeEntry, e.g.
- * Recents/Trash/Google Drive wrapper), they don't have a real entry backup in
- * the file system.
- */
-
-
-/** Action add single UI entry into the store. */
-export interface AddUiEntryAction extends BaseAction {
-  type: ActionType.ADD_UI_ENTRY;
-  payload: {
-    entry: FakeEntryImpl,
-  };
-}
-
-/** Action remove single UI entry from the store. */
-export interface RemoveUiEntryAction extends BaseAction {
-  type: ActionType.REMOVE_UI_ENTRY;
-  payload: {
-    key: FileKey,
-  };
-}
-
-/** Action factory to add single UI entry into the store. */
-export function addUiEntry(payload: AddUiEntryAction['payload']):
-    AddUiEntryAction {
-  return {
-    type: ActionType.ADD_UI_ENTRY,
-    payload,
-  };
-}
-
-/** Action factory to remove single UI entry from the store. */
-export function removeUiEntry(payload: RemoveUiEntryAction['payload']):
-    RemoveUiEntryAction {
-  return {
-    type: ActionType.REMOVE_UI_ENTRY,
-    payload,
-  };
-}
diff --git a/ui/file_manager/file_manager/state/reducers/ui_entries.ts b/ui/file_manager/file_manager/state/ducks/ui_entries.ts
similarity index 67%
rename from ui/file_manager/file_manager/state/reducers/ui_entries.ts
rename to ui/file_manager/file_manager/state/ducks/ui_entries.ts
index 012ee48..0e795c7c 100644
--- a/ui/file_manager/file_manager/state/reducers/ui_entries.ts
+++ b/ui/file_manager/file_manager/state/ducks/ui_entries.ts
@@ -6,11 +6,23 @@
 import {FakeEntryImpl} from '../../common/js/files_app_entry_types.js';
 import {util} from '../../common/js/util.js';
 import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js';
-import {State} from '../../externs/ts/state.js';
-import {AddUiEntryAction, RemoveUiEntryAction} from '../actions/ui_entries.js';
+import {FileKey, State} from '../../externs/ts/state.js';
+import {addReducer, BaseAction, Reducer, ReducersMap} from '../../lib/base_store.js';
+import {Action, ActionType} from '../actions.js';
+import {getMyFiles} from '../reducers/all_entries.js';
 import {getEntry, getFileData} from '../store.js';
 
-import {getMyFiles} from './all_entries.js';
+/**
+ * Actions and reducers for UI entries.
+ *
+ * UI entries represents entries shown on UI only (aka FakeEntry, e.g.
+ * Recents/Trash/Google Drive wrapper), they don't have a real entry backup in
+ * the file system.
+ */
+
+
+/** Map of actions to reducers for the UI entries slice. */
+export const uiEntriesReducersMap: ReducersMap<State, Action> = new Map();
 
 const uiEntryRootTypesInMyFiles = new Set([
   VolumeManagerCommon.RootType.ANDROID_FILES,
@@ -18,9 +30,18 @@
   VolumeManagerCommon.RootType.GUEST_OS,
 ]);
 
-export function addUiEntry(
-    currentState: State, action: AddUiEntryAction): State {
-  const {entry} = action.payload;
+
+/** Action add single UI entry into the store. */
+export interface AddUiEntryAction extends BaseAction {
+  type: ActionType.ADD_UI_ENTRY;
+  payload: {
+    entry: FakeEntryImpl,
+  };
+}
+
+export function addUiEntryReducer(
+    currentState: State, payload: AddUiEntryAction['payload']): State {
+  const {entry} = payload;
   const key = entry.toURL();
 
   let isVolumeEntryExistedInMyFiles = false;
@@ -70,9 +91,22 @@
   };
 }
 
-export function removeUiEntry(
-    currentState: State, action: RemoveUiEntryAction): State {
-  const key = action.payload.key;
+/** Action factory to add single UI entry into the store. */
+export const addUiEntry = addReducer(
+    ActionType.ADD_UI_ENTRY, addUiEntryReducer as Reducer<State, Action>,
+    uiEntriesReducersMap);
+
+/** Action remove single UI entry from the store. */
+export interface RemoveUiEntryAction extends BaseAction {
+  type: ActionType.REMOVE_UI_ENTRY;
+  payload: {
+    key: FileKey,
+  };
+}
+
+export function removeUiEntryReducer(
+    currentState: State, payload: RemoveUiEntryAction['payload']): State {
+  const {key} = payload;
   const entry = getEntry(currentState, key) as FakeEntryImpl | null;
   if (currentState.uiEntries.find(k => k === key)) {
     // Shallow copy.
@@ -102,3 +136,8 @@
     ...currentState,
   };
 }
+
+/** Action factory to remove single UI entry from the store. */
+export const removeUiEntry = addReducer(
+    ActionType.REMOVE_UI_ENTRY, removeUiEntryReducer as Reducer<State, Action>,
+    uiEntriesReducersMap);
diff --git a/ui/file_manager/file_manager/state/reducers/ui_entries_unittest.ts b/ui/file_manager/file_manager/state/ducks/ui_entries_unittest.ts
similarity index 98%
rename from ui/file_manager/file_manager/state/reducers/ui_entries_unittest.ts
rename to ui/file_manager/file_manager/state/ducks/ui_entries_unittest.ts
index a36ef624..89ccd89f 100644
--- a/ui/file_manager/file_manager/state/reducers/ui_entries_unittest.ts
+++ b/ui/file_manager/file_manager/state/ducks/ui_entries_unittest.ts
@@ -13,12 +13,12 @@
 import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js';
 import {FileData, State} from '../../externs/ts/state.js';
 import {VolumeInfo} from '../../externs/volume_info.js';
-import {addUiEntry, removeUiEntry} from '../actions/ui_entries.js';
 import {createFakeVolumeMetadata, setUpFileManagerOnWindow, setupStore, waitDeepEquals} from '../for_tests.js';
+import {convertEntryToFileData} from '../reducers/all_entries.js';
 import {getEmptyState} from '../store.js';
 
-import {convertEntryToFileData} from './all_entries.js';
-import {convertVolumeInfoAndMetadataToVolume} from '../ducks/volumes.js';
+import {addUiEntry, removeUiEntry} from './ui_entries.js';
+import {convertVolumeInfoAndMetadataToVolume} from './volumes.js';
 
 export function setUp() {
   // sortEntries() from addUiEntry() reducer requires volumeManager and
diff --git a/ui/file_manager/file_manager/state/reducers/root.ts b/ui/file_manager/file_manager/state/reducers/root.ts
index 360198d..11a41218 100644
--- a/ui/file_manager/file_manager/state/reducers/root.ts
+++ b/ui/file_manager/file_manager/state/reducers/root.ts
@@ -6,6 +6,7 @@
 import {Action, ActionType} from '../actions.js';
 import {bulkPinningReducersMap} from '../ducks/bulk_pinning.js';
 import {searchReducersMap} from '../ducks/search.js';
+import {uiEntriesReducersMap} from '../ducks/ui_entries.js';
 import {volumesReducersMap} from '../ducks/volumes.js';
 
 import {addChildEntries, cacheEntries, clearCachedEntries, updateMetadata} from './all_entries.js';
@@ -14,11 +15,14 @@
 import {addFolderShortcut, refreshFolderShortcut, removeFolderShortcut} from './folder_shortcuts.js';
 import {refreshNavigationRoots, updateNavigationEntry} from './navigation.js';
 import {updatePreferences} from './preferences.js';
-import {addUiEntry, removeUiEntry} from './ui_entries.js';
 
 // Reducers map created from merging together each slice's exported reducersMap.
-const rootReducersMap = new Map(
-    [...searchReducersMap, ...volumesReducersMap, ...bulkPinningReducersMap]);
+const rootReducersMap = new Map([
+  ...searchReducersMap,
+  ...volumesReducersMap,
+  ...bulkPinningReducersMap,
+  ...uiEntriesReducersMap,
+]);
 
 /**
  * Root reducer for the State for Files app.
@@ -56,10 +60,6 @@
       return refreshNavigationRoots(currentState, action);
     case ActionType.UPDATE_NAVIGATION_ENTRY:
       return updateNavigationEntry(currentState, action);
-    case ActionType.ADD_UI_ENTRY:
-      return addUiEntry(currentState, action);
-    case ActionType.REMOVE_UI_ENTRY:
-      return removeUiEntry(currentState, action);
     case ActionType.REFRESH_FOLDER_SHORTCUT:
       return refreshFolderShortcut(currentState, action);
     case ActionType.ADD_FOLDER_SHORTCUT:
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni
index 2b2e7d81..4eacbe6 100644
--- a/ui/file_manager/file_names.gni
+++ b/ui/file_manager/file_names.gni
@@ -258,7 +258,6 @@
   "file_manager/state/actions/folder_shortcuts.ts",
   "file_manager/state/actions/navigation.ts",
   "file_manager/state/actions/preferences.ts",
-  "file_manager/state/actions/ui_entries.ts",
 
   # ActionsProducers.
   "file_manager/state/actions_producers/all_entries.ts",
@@ -272,11 +271,11 @@
   "file_manager/state/reducers/folder_shortcuts.ts",
   "file_manager/state/reducers/navigation.ts",
   "file_manager/state/reducers/preferences.ts",
-  "file_manager/state/reducers/ui_entries.ts",
 
   # Ducks.
   "file_manager/state/ducks/bulk_pinning.ts",
   "file_manager/state/ducks/search.ts",
+  "file_manager/state/ducks/ui_entries.ts",
   "file_manager/state/ducks/volumes.ts",
 
   # Containers.
@@ -406,12 +405,12 @@
   "file_manager/state/reducers/folder_shortcuts_unittest.ts",
   "file_manager/state/reducers/navigation_unittest.ts",
   "file_manager/state/reducers/preferences_unittest.ts",
-  "file_manager/state/reducers/ui_entries_unittest.ts",
 
   # Ducks:
   "file_manager/state/ducks/bulk_pinning_unittest.ts",
   "file_manager/state/ducks/search_unittest.ts",
   "file_manager/state/ducks/volumes_unittest.ts",
+  "file_manager/state/ducks/ui_entries_unittest.ts",
 
   # Widgets:
   "file_manager/widgets/xf_breadcrumb_unittest.ts",
diff --git a/ui/gtk/gtk_util.cc b/ui/gtk/gtk_util.cc
index 1c23c0f..01f5411 100644
--- a/ui/gtk/gtk_util.cc
+++ b/ui/gtk/gtk_util.cc
@@ -31,6 +31,7 @@
 #include "ui/linux/linux_ui.h"
 #include "ui/native_theme/common_theme.h"
 #include "ui/ozone/public/ozone_platform.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
 
 namespace gtk {
 
@@ -174,6 +175,13 @@
   return GetOpacityFromRenderNode(GetRenderNodeChild(node));
 }
 
+// Runs DesktopWindowTreeHostLinux::EnableEventListening() when the dialog is
+// closed.
+void OnDialogDestroy(base::OnceClosure* callback_raw) {
+  std::unique_ptr<base::OnceClosure> callback = base::WrapUnique(callback_raw);
+  std::move(*callback).Run();
+}
+
 }  // namespace
 
 const char* GtkCssMenu() {
@@ -224,6 +232,30 @@
       parent->GetHost()->GetAcceleratedWidget());
 }
 
+void DisableHostInputHandling(GtkWidget* dialog, aura::Window* parent) {
+  if (!parent) {
+    return;
+  }
+  auto* host =
+      static_cast<views::DesktopWindowTreeHostLinux*>(parent->GetHost());
+  if (!host) {
+    return;
+  }
+
+  // In some circumstances the mouse has been captured and by turning off event
+  // listening, it is never released. So we manually ensure there is no current
+  // capture.
+  host->ReleaseCapture();
+  auto callback =
+      std::make_unique<base::OnceClosure>(host->DisableEventListening());
+  // OnDialogDestroy() is called when |dialog| destroyed, which allows
+  // to invoke the callback function to re-enable event handling on the
+  // owning window.
+  g_object_set_data_full(G_OBJECT(dialog), "callback", callback.release(),
+                         reinterpret_cast<GDestroyNotify>(OnDialogDestroy));
+  gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+}
+
 void ParseButtonLayout(const std::string& button_string,
                        std::vector<views::FrameButton>* leading_buttons,
                        std::vector<views::FrameButton>* trailing_buttons) {
diff --git a/ui/gtk/gtk_util.h b/ui/gtk/gtk_util.h
index 10487a2..0366678 100644
--- a/ui/gtk/gtk_util.h
+++ b/ui/gtk/gtk_util.h
@@ -42,6 +42,9 @@
 // Clears the transient parent for |dialog|.
 void ClearAuraTransientParent(GtkWidget* dialog, aura::Window* parent);
 
+// Disable input events handling on `parent` to make `dialog` modal.
+void DisableHostInputHandling(GtkWidget* dialog, aura::Window* parent);
+
 // Parses |button_string| into |leading_buttons| and
 // |trailing_buttons|.  The string is of the format
 // "<button>*:<button*>", for example, "close:minimize:maximize".
diff --git a/ui/gtk/printing/print_dialog_gtk.cc b/ui/gtk/printing/print_dialog_gtk.cc
index 4e2c27c..154082c8 100644
--- a/ui/gtk/printing/print_dialog_gtk.cc
+++ b/ui/gtk/printing/print_dialog_gtk.cc
@@ -391,8 +391,9 @@
       gtk_print_settings_set_print_pages(gtk_settings_, GTK_PRINT_PAGES_ALL);
   }
 
-  // Set modal so user cannot focus the same tab and press print again.
-  gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
+  // Disable input handling so the user cannot focus the same tab and press
+  // print again.
+  gtk::DisableHostInputHandling(dialog_, parent_view);
 
   // Since we only generate PDF, only show printers that support PDF.
   // TODO(thestig) Add more capabilities to support?
diff --git a/ui/gtk/select_file_dialog_linux_gtk.cc b/ui/gtk/select_file_dialog_linux_gtk.cc
index c1b1b1b3..a9ee144 100644
--- a/ui/gtk/select_file_dialog_linux_gtk.cc
+++ b/ui/gtk/select_file_dialog_linux_gtk.cc
@@ -74,13 +74,6 @@
   return save;
 }
 
-// Runs DesktopWindowTreeHostLinux::EnableEventListening() when the file-picker
-// is closed.
-void OnFilePickerDestroy(base::OnceClosure* callback_raw) {
-  std::unique_ptr<base::OnceClosure> callback = base::WrapUnique(callback_raw);
-  std::move(*callback).Run();
-}
-
 void GtkFileChooserSetFilename(GtkFileChooser* dialog,
                                const base::FilePath& path) {
   if (GtkCheckVersion(4)) {
@@ -271,27 +264,7 @@
 
   params_map_[dialog] = params;
 
-  // Disable input events handling in the host window to make this dialog modal.
-  if (owning_window) {
-    views::DesktopWindowTreeHostLinux* host =
-        static_cast<views::DesktopWindowTreeHostLinux*>(
-            owning_window->GetHost());
-    if (host) {
-      // In some circumstances (e.g. dialog from flash plugin) the mouse has
-      // been captured and by turning off event listening, it is never
-      // released. So we manually ensure there is no current capture.
-      host->ReleaseCapture();
-      std::unique_ptr<base::OnceClosure> callback =
-          std::make_unique<base::OnceClosure>(host->DisableEventListening());
-      // OnFilePickerDestroy() is called when |dialog| destroyed, which allows
-      // to invoke the callback function to re-enable event handling on the
-      // owning window.
-      g_object_set_data_full(
-          G_OBJECT(dialog), "callback", callback.release(),
-          reinterpret_cast<GDestroyNotify>(OnFilePickerDestroy));
-      gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
-    }
-  }
+  DisableHostInputHandling(dialog, owning_window);
 
   if (!GtkCheckVersion(4))
     gtk_widget_show_all(dialog);
diff --git a/ui/touch_selection/BUILD.gn b/ui/touch_selection/BUILD.gn
index 074bcc0..3e218b15 100644
--- a/ui/touch_selection/BUILD.gn
+++ b/ui/touch_selection/BUILD.gn
@@ -85,12 +85,14 @@
     "longpress_drag_selector_unittest.cc",
     "touch_handle_unittest.cc",
     "touch_selection_controller_unittest.cc",
+    "touch_selection_metrics_unittest.cc",
   ]
 
   deps = [
     ":test_support",
     ":touch_selection",
     "//base/test:run_all_unittests",
+    "//base/test:test_support",
     "//testing/gmock:gmock",
     "//testing/gtest:gtest",
     "//ui/base:base",
diff --git a/ui/touch_selection/touch_selection_controller.cc b/ui/touch_selection/touch_selection_controller.cc
index a2fcf10b..813000c 100644
--- a/ui/touch_selection/touch_selection_controller.cc
+++ b/ui/touch_selection/touch_selection_controller.cc
@@ -173,6 +173,8 @@
 }
 
 bool TouchSelectionController::WillHandleTouchEvent(const MotionEvent& event) {
+  const bool is_down_event = event.GetAction() == MotionEvent::Action::DOWN;
+  session_metrics_recorder_.OnTouchEvent(is_down_event);
   bool handled = WillHandleTouchEventImpl(event);
   // If Action::DOWN is consumed, the rest of touch sequence should be consumed,
   // too, regardless of value of |handled|.
@@ -180,8 +182,9 @@
   // Ideally we should consume until the final Action::UP/Action::CANCEL.
   // But, apparently, we can't reliably determine the final Action::CANCEL in a
   // multi-touch scenario. See https://crbug.com/653212.
-  if (event.GetAction() == MotionEvent::Action::DOWN)
+  if (is_down_event) {
     consume_touch_sequence_ = handled;
+  }
   return handled || consume_touch_sequence_;
 }
 
@@ -225,6 +228,18 @@
   response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
 }
 
+void TouchSelectionController::OnMenuCommand(bool should_dismiss_handles) {
+  session_metrics_recorder_.OnMenuCommand(should_dismiss_handles);
+  if (should_dismiss_handles) {
+    HideAndDisallowShowingAutomatically();
+  }
+}
+
+void TouchSelectionController::OnSessionEndEvent(const Event& event) {
+  session_metrics_recorder_.OnSessionEndEvent(event);
+  HideAndDisallowShowingAutomatically();
+}
+
 void TouchSelectionController::HideHandles() {
   response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
   DeactivateInsertion();
@@ -236,6 +251,7 @@
 }
 
 void TouchSelectionController::HideAndDisallowShowingAutomatically() {
+  session_metrics_recorder_.ResetMetrics();
   HideHandles();
   show_touch_handles_ = false;
 }
@@ -571,6 +587,7 @@
 
 bool TouchSelectionController::ActivateInsertionIfNecessary() {
   DCHECK_NE(SELECTION_ACTIVE, active_status_);
+  session_metrics_recorder_.OnCursorActivationEvent();
 
   if (!insertion_handle_) {
     insertion_handle_ = std::make_unique<TouchHandle>(
@@ -599,6 +616,7 @@
 
 bool TouchSelectionController::ActivateSelectionIfNecessary() {
   DCHECK_NE(INSERTION_ACTIVE, active_status_);
+  session_metrics_recorder_.OnSelectionActivationEvent();
 
   if (!start_selection_handle_) {
     start_selection_handle_ =
diff --git a/ui/touch_selection/touch_selection_controller.h b/ui/touch_selection/touch_selection_controller.h
index 4fb88a6c6..3333724 100644
--- a/ui/touch_selection/touch_selection_controller.h
+++ b/ui/touch_selection/touch_selection_controller.h
@@ -16,10 +16,12 @@
 #include "ui/touch_selection/selection_event_type.h"
 #include "ui/touch_selection/touch_handle.h"
 #include "ui/touch_selection/touch_handle_orientation.h"
+#include "ui/touch_selection/touch_selection_metrics.h"
 #include "ui/touch_selection/ui_touch_selection_export.h"
 
 namespace ui {
 class MotionEvent;
+class Event;
 
 // Interface through which |TouchSelectionController| issues selection-related
 // commands, notifications and requests.
@@ -111,6 +113,13 @@
   // long-press drag.
   void OnScrollBeginEvent();
 
+  // To be called when a menu command has been requested, to dismiss touch
+  // handles and record metrics if needed.
+  void OnMenuCommand(bool should_dismiss_handles);
+
+  // To be called when an event occurs to deactivate touch selection.
+  void OnSessionEndEvent(const Event& event);
+
   // Hide the handles and suppress bounds updates until the next explicit
   // showing allowance.
   void HideAndDisallowShowingAutomatically();
@@ -267,6 +276,8 @@
   bool consume_touch_sequence_;
 
   bool show_touch_handles_;
+
+  TouchSelectionSessionMetricsRecorder session_metrics_recorder_;
 };
 
 }  // namespace ui
diff --git a/ui/touch_selection/touch_selection_metrics.cc b/ui/touch_selection/touch_selection_metrics.cc
index cf8729d1..72ce3ae2 100644
--- a/ui/touch_selection/touch_selection_metrics.cc
+++ b/ui/touch_selection/touch_selection_metrics.cc
@@ -5,29 +5,52 @@
 #include "ui/touch_selection/touch_selection_metrics.h"
 
 #include "base/metrics/histogram_functions.h"
+#include "base/time/time.h"
 #include "ui/base/pointer/touch_editing_controller.h"
+#include "ui/events/event.h"
 
 namespace ui {
 
 namespace {
 
+constexpr int kSessionTouchDownCountMin = 1;
+constexpr int kSessionTouchDownCountMax = 20;
+constexpr int kSessionTouchDownCountBuckets = 20;
+
+// Duration of inactivity after which we consider a touch selection session to
+// have timed out for the purpose of determining session action count metrics.
+constexpr base::TimeDelta kSessionTimeoutDuration = base::Seconds(10);
+
 TouchSelectionMenuAction MapCommandIdToMenuAction(int command_id) {
   switch (command_id) {
-    case ui::TouchEditable::kCut:
+    case TouchEditable::kCut:
       return TouchSelectionMenuAction::kCut;
-    case ui::TouchEditable::kCopy:
+    case TouchEditable::kCopy:
       return TouchSelectionMenuAction::kCopy;
-    case ui::TouchEditable::kPaste:
+    case TouchEditable::kPaste:
       return TouchSelectionMenuAction::kPaste;
-    case ui::TouchEditable::kSelectAll:
+    case TouchEditable::kSelectAll:
       return TouchSelectionMenuAction::kSelectAll;
-    case ui::TouchEditable::kSelectWord:
+    case TouchEditable::kSelectWord:
       return TouchSelectionMenuAction::kSelectWord;
     default:
       NOTREACHED_NORETURN() << "Invalid command id: " << command_id;
   }
 }
 
+// We want to record the touch down count required to get to a successful cursor
+// placement or selection, but it's hard to know if this has happened. We'll
+// just consider a session to be successful if it ends in a character key event
+// or an IME fabricated key event (e.g. from the ChromeOS virtual keyboard).
+bool IsSuccessfulSessionEndEvent(const Event& session_end_event) {
+  if (!session_end_event.IsKeyEvent()) {
+    return false;
+  }
+
+  return session_end_event.AsKeyEvent()->GetDomKey().IsCharacter() ||
+         session_end_event.flags() & EF_IME_FABRICATED_KEY;
+}
+
 }  // namespace
 
 void RecordTouchSelectionDrag(TouchSelectionDragType drag_type) {
@@ -50,4 +73,109 @@
                                 TouchSelectionMenuAction::kSmartAction);
 }
 
+TouchSelectionSessionMetricsRecorder::TouchSelectionSessionMetricsRecorder() =
+    default;
+
+TouchSelectionSessionMetricsRecorder::~TouchSelectionSessionMetricsRecorder() =
+    default;
+
+void TouchSelectionSessionMetricsRecorder::OnCursorActivationEvent() {
+  if (!IsSessionActive()) {
+    // We assume that an initial activation event occurs after a single touch
+    // down movement (from a tap or long press). This is not always correct,
+    // e.g. if the user double taps quickly enough then the cursor event from
+    // the first tap might occur after the second tap was already detected. But
+    // it should be ok to assume that this won't be a problem most of the time.
+    session_touch_down_count_ = 1;
+  }
+
+  active_status_ = ActiveStatus::kActiveCursor;
+}
+
+void TouchSelectionSessionMetricsRecorder::OnSelectionActivationEvent() {
+  if (!IsSessionActive()) {
+    // We assume that an initial activation event occurs after a single touch
+    // down movement (from a long press), since a selection event from a
+    // repeated tap would usually only occur after a cursor event from the
+    // first tap has already started the session.
+    session_touch_down_count_ = 1;
+  }
+
+  active_status_ = ActiveStatus::kActiveSelection;
+}
+
+void TouchSelectionSessionMetricsRecorder::OnTouchEvent(bool is_down_event) {
+  RefreshSessionStatus();
+  if (!IsSessionActive()) {
+    return;
+  }
+
+  session_touch_down_count_ += is_down_event;
+}
+
+void TouchSelectionSessionMetricsRecorder::OnMenuCommand(
+    bool should_end_session) {
+  RefreshSessionStatus();
+  if (!IsSessionActive()) {
+    return;
+  }
+
+  // We assume that a menu button was tapped, but only include this in the touch
+  // down count if the session continues (since we want to know the touch down
+  // count required to get to a successful cursor placement or selection, which
+  // would have occurred before the menu button was tapped).
+  if (should_end_session) {
+    RecordSessionMetrics();
+    ResetMetrics();
+  } else {
+    session_touch_down_count_++;
+  }
+}
+
+void TouchSelectionSessionMetricsRecorder::OnSessionEndEvent(
+    const Event& session_end_event) {
+  RefreshSessionStatus();
+  if (!IsSessionActive()) {
+    return;
+  }
+
+  if (IsSuccessfulSessionEndEvent(session_end_event)) {
+    RecordSessionMetrics();
+  }
+  ResetMetrics();
+}
+
+void TouchSelectionSessionMetricsRecorder::ResetMetrics() {
+  active_status_ = ActiveStatus::kInactive;
+  last_activity_time_ = base::TimeTicks();
+  session_touch_down_count_ = 0;
+}
+
+void TouchSelectionSessionMetricsRecorder::RefreshSessionStatus() {
+  // After a period of inactivity, we consider a session to have timed out since
+  // the user intent has probably changed.
+  if (last_activity_time_ + kSessionTimeoutDuration < base::TimeTicks::Now()) {
+    ResetMetrics();
+  }
+
+  last_activity_time_ = base::TimeTicks::Now();
+}
+
+bool TouchSelectionSessionMetricsRecorder::IsSessionActive() const {
+  return active_status_ != ActiveStatus::kInactive;
+}
+
+void TouchSelectionSessionMetricsRecorder::RecordSessionMetrics() const {
+  if (!IsSessionActive()) {
+    return;
+  }
+
+  base::UmaHistogramCustomCounts(
+      active_status_ == ActiveStatus::kActiveCursor
+          ? kTouchCursorSessionTouchDownCountHistogramName
+          : kTouchSelectionSessionTouchDownCountHistogramName,
+      session_touch_down_count_, kSessionTouchDownCountMin,
+      kSessionTouchDownCountMax, kSessionTouchDownCountBuckets);
+}
+
 }  // namespace ui
diff --git a/ui/touch_selection/touch_selection_metrics.h b/ui/touch_selection/touch_selection_metrics.h
index fb99da2e..19d8a1f 100644
--- a/ui/touch_selection/touch_selection_metrics.h
+++ b/ui/touch_selection/touch_selection_metrics.h
@@ -5,9 +5,11 @@
 #ifndef UI_TOUCH_SELECTION_TOUCH_SELECTION_METRICS_H_
 #define UI_TOUCH_SELECTION_TOUCH_SELECTION_METRICS_H_
 
+#include "base/time/time.h"
 #include "ui/touch_selection/ui_touch_selection_export.h"
 
 namespace ui {
+class Event;
 
 inline constexpr char kTouchSelectionDragTypeHistogramName[] =
     "InputMethod.TouchSelection.DragType";
@@ -15,6 +17,12 @@
 inline constexpr char kTouchSelectionMenuActionHistogramName[] =
     "InputMethod.TouchSelection.MenuAction";
 
+inline constexpr char kTouchCursorSessionTouchDownCountHistogramName[] =
+    "InputMethod.TouchSelection.CursorSession.TouchDownCount";
+
+inline constexpr char kTouchSelectionSessionTouchDownCountHistogramName[] =
+    "InputMethod.TouchSelection.SelectionSession.TouchDownCount";
+
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
 enum class TouchSelectionDragType {
@@ -47,6 +55,69 @@
 UI_TOUCH_SELECTION_EXPORT void RecordTouchSelectionMenuEllipsisAction();
 UI_TOUCH_SELECTION_EXPORT void RecordTouchSelectionMenuSmartAction();
 
+// Helper class for tracking the state of touch selection sessions and recording
+// session related metrics.
+class UI_TOUCH_SELECTION_EXPORT TouchSelectionSessionMetricsRecorder {
+ public:
+  TouchSelectionSessionMetricsRecorder();
+
+  TouchSelectionSessionMetricsRecorder(
+      const TouchSelectionSessionMetricsRecorder&) = delete;
+  TouchSelectionSessionMetricsRecorder& operator=(
+      const TouchSelectionSessionMetricsRecorder&) = delete;
+
+  ~TouchSelectionSessionMetricsRecorder();
+
+  // Called when the cursor or selection handles are shown or moved. This starts
+  // the session if it is not yet active and updates the session type (cursor or
+  // selection) if needed.
+  void OnCursorActivationEvent();
+  void OnSelectionActivationEvent();
+
+  // Called when a touch event occurs, to update the session status and touch
+  // down count. We assume this is only called for touch events targeting the
+  // touch selection context window (e.g. for tapping on the text or dragging
+  // touch handles, but not for tapping popup menu buttons).
+  void OnTouchEvent(bool is_down_event);
+
+  // Called when a menu command has been requested. If `should_end_session` is
+  // true, the session ends and metrics are recorded. Otherwise, the touch down
+  // count is incremented (since we assume a menu button was tapped) and the
+  // session continues.
+  void OnMenuCommand(bool should_end_session);
+
+  // Called when an event occurs to deactivate touch selection. This ends the
+  // session and records metrics if the session is deemed successful.
+  void OnSessionEndEvent(const Event& session_end_event);
+
+  // Resets the session state, effectively ending the session without recording
+  // metrics.
+  void ResetMetrics();
+
+ private:
+  enum class ActiveStatus {
+    kInactive,
+    kActiveCursor,
+    kActiveSelection,
+  };
+
+  // Helper to be called when user activity is detected (e.g. touch event or
+  // menu action), to check whether the session should continue or be considered
+  // timed out.
+  void RefreshSessionStatus();
+
+  bool IsSessionActive() const;
+
+  void RecordSessionMetrics() const;
+
+  ActiveStatus active_status_ = ActiveStatus::kInactive;
+
+  // The time of the most recently detected user activity.
+  base::TimeTicks last_activity_time_ = base::TimeTicks();
+
+  int session_touch_down_count_ = 0;
+};
+
 }  // namespace ui
 
 #endif  // UI_TOUCH_SELECTION_TOUCH_SELECTION_METRICS_H_
diff --git a/ui/touch_selection/touch_selection_metrics_unittest.cc b/ui/touch_selection/touch_selection_metrics_unittest.cc
new file mode 100644
index 0000000..f9d5944
--- /dev/null
+++ b/ui/touch_selection/touch_selection_metrics_unittest.cc
@@ -0,0 +1,171 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/touch_selection/touch_selection_metrics.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/types/event_type.h"
+
+namespace ui {
+
+namespace {
+
+TEST(TouchSelectionSessionMetricsTest, RecordsSuccessfulCursorSession) {
+  base::HistogramTester histogram_tester;
+  TouchSelectionSessionMetricsRecorder session_metrics_recorder;
+
+  // Activate cursor, then end session successfully with a menu command.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnCursorActivationEvent();
+  session_metrics_recorder.OnMenuCommand(true);
+
+  histogram_tester.ExpectUniqueSample(
+      kTouchCursorSessionTouchDownCountHistogramName, 1, 1);
+}
+
+TEST(TouchSelectionSessionMetricsTest, RecordsSuccessfulSelectionSession) {
+  base::HistogramTester histogram_tester;
+  TouchSelectionSessionMetricsRecorder session_metrics_recorder;
+
+  // Activate selection, then end session successfully with a menu command.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnSelectionActivationEvent();
+  session_metrics_recorder.OnMenuCommand(true);
+
+  histogram_tester.ExpectUniqueSample(
+      kTouchSelectionSessionTouchDownCountHistogramName, 1, 1);
+}
+
+TEST(TouchSelectionSessionMetricsTest, DoesNotRecordDismissedSession) {
+  base::HistogramTester histogram_tester;
+  TouchSelectionSessionMetricsRecorder session_metrics_recorder;
+
+  // Activate selection, then dismiss session.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnSelectionActivationEvent();
+  session_metrics_recorder.ResetMetrics();
+
+  histogram_tester.ExpectTotalCount(
+      kTouchSelectionSessionTouchDownCountHistogramName, 0);
+}
+
+TEST(TouchSelectionSessionMetricsTest, MultipleSessions) {
+  base::HistogramTester histogram_tester;
+  TouchSelectionSessionMetricsRecorder session_metrics_recorder;
+
+  // Activate, then end session successfully with a menu command.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnSelectionActivationEvent();
+  session_metrics_recorder.OnMenuCommand(true);
+  // Activate, then dismiss session.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnSelectionActivationEvent();
+  session_metrics_recorder.ResetMetrics();
+  // Activate, then end another session successfully.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnSelectionActivationEvent();
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnMenuCommand(true);
+
+  histogram_tester.ExpectTotalCount(
+      kTouchSelectionSessionTouchDownCountHistogramName, 2);
+  // First session.
+  histogram_tester.ExpectBucketCount(
+      kTouchSelectionSessionTouchDownCountHistogramName, 1, 1);
+  // Third session.
+  histogram_tester.ExpectBucketCount(
+      kTouchSelectionSessionTouchDownCountHistogramName, 2, 1);
+}
+
+TEST(TouchSelectionSessionMetricsTest, MultipleActivationEvents) {
+  base::HistogramTester histogram_tester;
+  TouchSelectionSessionMetricsRecorder session_metrics_recorder;
+
+  // Activate cursor.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnCursorActivationEvent();
+  // Activate selection within the same session.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnSelectionActivationEvent();
+  // Perform some touch events.
+  session_metrics_recorder.OnTouchEvent(false);
+  session_metrics_recorder.OnTouchEvent(true);
+  // End session successfully with a menu command.
+  session_metrics_recorder.OnMenuCommand(true);
+
+  // Selection session metrics should be recorded, since there was an active
+  // selection when the session ended.
+  histogram_tester.ExpectUniqueSample(
+      kTouchSelectionSessionTouchDownCountHistogramName, 3, 1);
+}
+
+TEST(TouchSelectionSessionMetricsTest, RecordsAfterCharacterKeyEvent) {
+  base::HistogramTester histogram_tester;
+  TouchSelectionSessionMetricsRecorder session_metrics_recorder;
+
+  // Activate cursor.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnCursorActivationEvent();
+  // End session successfully by typing a character key.
+  const KeyEvent key_event(ET_KEY_PRESSED, VKEY_A, DomCode::US_A, EF_NONE,
+                           DomKey::FromCharacter('a'), EventTimeForNow());
+  session_metrics_recorder.OnSessionEndEvent(key_event);
+
+  histogram_tester.ExpectUniqueSample(
+      kTouchCursorSessionTouchDownCountHistogramName, 1, 1);
+}
+
+TEST(TouchSelectionSessionMetricsTest, DoesNotRecordTimedOutSession) {
+  base::HistogramTester histogram_tester;
+  TouchSelectionSessionMetricsRecorder session_metrics_recorder;
+  base::test::TaskEnvironment task_environment(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+
+  // Activate selection.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnSelectionActivationEvent();
+  // Time out the session.
+  task_environment.FastForwardBy(base::Seconds(50));
+  session_metrics_recorder.OnMenuCommand(true);
+
+  // The session timed out and wasn't activated again, so we don't record touch
+  // down count metrics.
+  histogram_tester.ExpectTotalCount(
+      kTouchSelectionSessionTouchDownCountHistogramName, 0);
+}
+
+TEST(TouchSelectionSessionMetricsTest, ActivationAfterTimeOut) {
+  base::HistogramTester histogram_tester;
+  TouchSelectionSessionMetricsRecorder session_metrics_recorder;
+  base::test::TaskEnvironment task_environment(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+
+  // Activate selection.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnSelectionActivationEvent();
+  // Time out the session.
+  task_environment.FastForwardBy(base::Seconds(50));
+  // Activate selection again.
+  session_metrics_recorder.OnTouchEvent(true);
+  session_metrics_recorder.OnSelectionActivationEvent();
+  session_metrics_recorder.OnMenuCommand(true);
+
+  // Metrics should be recorded for the selection session that started from the
+  // activation event after the timeout.
+  histogram_tester.ExpectUniqueSample(
+      kTouchSelectionSessionTouchDownCountHistogramName, 1, 1);
+}
+
+}  // namespace
+
+}  // namespace ui
diff --git a/weblayer/browser/reduce_accept_language_factory.cc b/weblayer/browser/reduce_accept_language_factory.cc
index c916c27a..827f34dd 100644
--- a/weblayer/browser/reduce_accept_language_factory.cc
+++ b/weblayer/browser/reduce_accept_language_factory.cc
@@ -34,9 +34,10 @@
 
 ReduceAcceptLanguageFactory::~ReduceAcceptLanguageFactory() = default;
 
-KeyedService* ReduceAcceptLanguageFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ReduceAcceptLanguageFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new reduce_accept_language::ReduceAcceptLanguageService(
+  return std::make_unique<reduce_accept_language::ReduceAcceptLanguageService>(
       HostContentSettingsMapFactory::GetForBrowserContext(context),
       static_cast<BrowserContextImpl*>(context)->pref_service(),
       context->IsOffTheRecord());
@@ -47,4 +48,4 @@
   return context;
 }
 
-}  // namespace weblayer
\ No newline at end of file
+}  // namespace weblayer
diff --git a/weblayer/browser/reduce_accept_language_factory.h b/weblayer/browser/reduce_accept_language_factory.h
index 264adb2e..9dedb359 100644
--- a/weblayer/browser/reduce_accept_language_factory.h
+++ b/weblayer/browser/reduce_accept_language_factory.h
@@ -31,7 +31,7 @@
   ~ReduceAcceptLanguageFactory() override;
 
   // BrowserContextKeyedServiceFactory methods:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
diff --git a/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.cc b/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.cc
index 64b200fe..5c7782e 100644
--- a/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.cc
+++ b/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.cc
@@ -42,7 +42,8 @@
           "RealTimeUrlLookupService",
           BrowserContextDependencyManager::GetInstance()) {}
 
-KeyedService* RealTimeUrlLookupServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+RealTimeUrlLookupServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   auto url_loader_factory =
       std::make_unique<network::CrossThreadPendingSharedURLLoaderFactory>(
@@ -50,7 +51,7 @@
               ->GetSafeBrowsingService()
               ->GetURLLoaderFactory());
 
-  return new safe_browsing::RealTimeUrlLookupService(
+  return std::make_unique<safe_browsing::RealTimeUrlLookupService>(
       network::SharedURLLoaderFactory::Create(std::move(url_loader_factory)),
       VerdictCacheManagerFactory::GetForBrowserContext(context),
       base::BindRepeating(&GetUserPopulationForBrowserContext, context),
diff --git a/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.h b/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.h
index d85d198..55a8d54 100644
--- a/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.h
+++ b/weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.h
@@ -50,7 +50,7 @@
       const RealTimeUrlLookupServiceFactory&) = delete;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 
   // TODO(crbug.com/1171215): Remove this once browsertests can enable this